aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sgi-ip22
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/sgi-ip22
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/sgi-ip22')
-rw-r--r--arch/mips/sgi-ip22/Makefile12
-rw-r--r--arch/mips/sgi-ip22/Platform32
-rw-r--r--arch/mips/sgi-ip22/ip22-berr.c116
-rw-r--r--arch/mips/sgi-ip22/ip22-eisa.c139
-rw-r--r--arch/mips/sgi-ip22/ip22-gio.c431
-rw-r--r--arch/mips/sgi-ip22/ip22-hpc.c64
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c320
-rw-r--r--arch/mips/sgi-ip22/ip22-mc.c203
-rw-r--r--arch/mips/sgi-ip22/ip22-nvram.c122
-rw-r--r--arch/mips/sgi-ip22/ip22-platform.c223
-rw-r--r--arch/mips/sgi-ip22/ip22-reset.c203
-rw-r--r--arch/mips/sgi-ip22/ip22-setup.c78
-rw-r--r--arch/mips/sgi-ip22/ip22-time.c131
-rw-r--r--arch/mips/sgi-ip22/ip28-berr.c488
14 files changed, 2562 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
new file mode 100644
index 000000000..45f42fa08
--- /dev/null
+++ b/arch/mips/sgi-ip22/Makefile
@@ -0,0 +1,12 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Makefile for the SGI specific kernel interface routines
4# under Linux.
5#
6
7obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
8 ip22-platform.o ip22-reset.o ip22-setup.o ip22-gio.o
9
10obj-$(CONFIG_SGI_IP22) += ip22-berr.o
11obj-$(CONFIG_SGI_IP28) += ip28-berr.o
12obj-$(CONFIG_EISA) += ip22-eisa.o
diff --git a/arch/mips/sgi-ip22/Platform b/arch/mips/sgi-ip22/Platform
new file mode 100644
index 000000000..62fa30bb9
--- /dev/null
+++ b/arch/mips/sgi-ip22/Platform
@@ -0,0 +1,32 @@
1#
2# SGI IP22 (Indy/Indigo2)
3#
4# Set the load address to >= 0xffffffff88069000 if you want to leave space for
5# symmon, 0xffffffff80002000 for production kernels. Note that the value must
6# be aligned to a multiple of the kernel stack size or the handling of the
7# current variable will break so for 64-bit kernels we have to raise the start
8# address by 8kb.
9#
10cflags-$(CONFIG_SGI_IP22) += -I$(srctree)/arch/mips/include/asm/mach-ip22
11ifdef CONFIG_32BIT
12load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
13endif
14ifdef CONFIG_64BIT
15load-$(CONFIG_SGI_IP22) += 0xffffffff88004000
16endif
17
18#
19# SGI IP28 (Indigo2 R10k)
20#
21# Set the load address to >= 0xa800000020080000 if you want to leave space for
22# symmon, 0xa800000020004000 for production kernels ? Note that the value must
23# be 16kb aligned or the handling of the current variable will break.
24# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
25#
26ifdef CONFIG_SGI_IP28
27 ifeq ($(call cc-option-yn,-march=r10000 -mr10k-cache-barrier=store), n)
28 $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
29 endif
30endif
31cflags-$(CONFIG_SGI_IP28) += -mr10k-cache-barrier=store -I$(srctree)/arch/mips/include/asm/mach-ip28
32load-$(CONFIG_SGI_IP28) += 0xa800000020004000
diff --git a/arch/mips/sgi-ip22/ip22-berr.c b/arch/mips/sgi-ip22/ip22-berr.c
new file mode 100644
index 000000000..dc0110a60
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-berr.c
@@ -0,0 +1,116 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip22-berr.c: Bus error handling.
4 *
5 * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org)
6 */
7
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/sched/signal.h>
11
12#include <asm/addrspace.h>
13#include <asm/traps.h>
14#include <asm/branch.h>
15#include <asm/irq_regs.h>
16#include <asm/sgi/mc.h>
17#include <asm/sgi/hpc3.h>
18#include <asm/sgi/ioc.h>
19#include <asm/sgi/ip22.h>
20
21
22static unsigned int cpu_err_stat; /* Status reg for CPU */
23static unsigned int gio_err_stat; /* Status reg for GIO */
24static unsigned int cpu_err_addr; /* Error address reg for CPU */
25static unsigned int gio_err_addr; /* Error address reg for GIO */
26static unsigned int extio_stat;
27static unsigned int hpc3_berr_stat; /* Bus error interrupt status */
28
29static void save_and_clear_buserr(void)
30{
31 /* save status registers */
32 cpu_err_addr = sgimc->cerr;
33 cpu_err_stat = sgimc->cstat;
34 gio_err_addr = sgimc->gerr;
35 gio_err_stat = sgimc->gstat;
36 extio_stat = ip22_is_fullhouse() ? sgioc->extio : (sgint->errstat << 4);
37 hpc3_berr_stat = hpc3c0->bestat;
38
39 sgimc->cstat = sgimc->gstat = 0;
40}
41
42#define GIO_ERRMASK 0xff00
43#define CPU_ERRMASK 0x3f00
44
45static void print_buserr(void)
46{
47 if (extio_stat & EXTIO_MC_BUSERR)
48 printk(KERN_ERR "MC Bus Error\n");
49 if (extio_stat & EXTIO_HPC3_BUSERR)
50 printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n",
51 hpc3_berr_stat,
52 (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >>
53 HPC3_BESTAT_PIDSHIFT,
54 (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA",
55 hpc3_berr_stat & HPC3_BESTAT_BLMASK);
56 if (extio_stat & EXTIO_EISA_BUSERR)
57 printk(KERN_ERR "EISA Bus Error\n");
58 if (cpu_err_stat & CPU_ERRMASK)
59 printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n",
60 cpu_err_stat,
61 cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "",
62 cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "",
63 cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "",
64 cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "",
65 cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "",
66 cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "",
67 cpu_err_addr);
68 if (gio_err_stat & GIO_ERRMASK)
69 printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n",
70 gio_err_stat,
71 gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "",
72 gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "",
73 gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "",
74 gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "",
75 gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "",
76 gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "",
77 gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "",
78 gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "",
79 gio_err_addr);
80}
81
82/*
83 * MC sends an interrupt whenever bus or parity errors occur. In addition,
84 * if the error happened during a CPU read, it also asserts the bus error
85 * pin on the R4K. Code in bus error handler save the MC bus error registers
86 * and then clear the interrupt when this happens.
87 */
88
89void ip22_be_interrupt(int irq)
90{
91 const int field = 2 * sizeof(unsigned long);
92 struct pt_regs *regs = get_irq_regs();
93
94 save_and_clear_buserr();
95 print_buserr();
96 printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
97 (regs->cp0_cause & 4) ? "Data" : "Instruction",
98 field, regs->cp0_epc, field, regs->regs[31]);
99 /* Assume it would be too dangerous to continue ... */
100 die_if_kernel("Oops", regs);
101 force_sig(SIGBUS);
102}
103
104static int ip22_be_handler(struct pt_regs *regs, int is_fixup)
105{
106 save_and_clear_buserr();
107 if (is_fixup)
108 return MIPS_BE_FIXUP;
109 print_buserr();
110 return MIPS_BE_FATAL;
111}
112
113void __init ip22_be_init(void)
114{
115 board_be_handler = ip22_be_handler;
116}
diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c
new file mode 100644
index 000000000..f3b0e90e0
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-eisa.c
@@ -0,0 +1,139 @@
1/*
2 * Basic EISA bus support for the SGI Indigo-2.
3 *
4 * (C) 2002 Pascal Dameme <netinet@freesurf.fr>
5 * and Marc Zyngier <mzyngier@freesurf.fr>
6 *
7 * This code is released under both the GPL version 2 and BSD
8 * licenses. Either license may be used.
9 *
10 * This code offers a very basic support for this EISA bus present in
11 * the SGI Indigo-2. It currently only supports PIO (forget about DMA
12 * for the time being). This is enough for a low-end ethernet card,
13 * but forget about your favorite SCSI card...
14 *
15 * TODO :
16 * - Fix bugs...
17 * - Add ISA support
18 * - Add DMA (yeah, right...).
19 * - Fix more bugs.
20 */
21
22#include <linux/eisa.h>
23#include <linux/types.h>
24#include <linux/init.h>
25#include <linux/irq.h>
26#include <linux/kernel_stat.h>
27#include <linux/signal.h>
28#include <linux/sched.h>
29#include <linux/interrupt.h>
30#include <linux/delay.h>
31#include <asm/io.h>
32#include <asm/irq.h>
33#include <asm/mipsregs.h>
34#include <asm/addrspace.h>
35#include <asm/processor.h>
36#include <asm/sgi/ioc.h>
37#include <asm/sgi/mc.h>
38#include <asm/sgi/ip22.h>
39#include <asm/i8259.h>
40
41/* I2 has four EISA slots. */
42#define IP22_EISA_MAX_SLOTS 4
43#define EISA_MAX_IRQ 16
44
45#define EIU_MODE_REG 0x0001ffc0
46#define EIU_STAT_REG 0x0001ffc4
47#define EIU_PREMPT_REG 0x0001ffc8
48#define EIU_QUIET_REG 0x0001ffcc
49#define EIU_INTRPT_ACK 0x00010004
50
51static char __init *decode_eisa_sig(unsigned long addr)
52{
53 static char sig_str[EISA_SIG_LEN] __initdata;
54 u8 sig[4];
55 u16 rev;
56 int i;
57
58 for (i = 0; i < 4; i++) {
59 sig[i] = inb(addr + i);
60
61 if (!i && (sig[0] & 0x80))
62 return NULL;
63 }
64
65 sig_str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1);
66 sig_str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1);
67 sig_str[2] = (sig[1] & 0x1f) + ('A' - 1);
68 rev = (sig[2] << 8) | sig[3];
69 sprintf(sig_str + 3, "%04X", rev);
70
71 return sig_str;
72}
73
74static irqreturn_t ip22_eisa_intr(int irq, void *dev_id)
75{
76 u8 eisa_irq = inb(EIU_INTRPT_ACK);
77
78 inb(EISA_DMA1_STATUS);
79 inb(EISA_DMA2_STATUS);
80
81 if (eisa_irq < EISA_MAX_IRQ) {
82 do_IRQ(eisa_irq);
83 return IRQ_HANDLED;
84 }
85
86 /* Oops, Bad Stuff Happened... */
87 printk(KERN_ERR "eisa_irq %d out of bound\n", eisa_irq);
88
89 outb(0x20, EISA_INT2_CTRL);
90 outb(0x20, EISA_INT1_CTRL);
91
92 return IRQ_NONE;
93}
94
95int __init ip22_eisa_init(void)
96{
97 int i, c;
98 char *str;
99
100 if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
101 printk(KERN_INFO "EISA: bus not present.\n");
102 return 1;
103 }
104
105 printk(KERN_INFO "EISA: Probing bus...\n");
106 for (c = 0, i = 1; i <= IP22_EISA_MAX_SLOTS; i++) {
107 if ((str = decode_eisa_sig(0x1000 * i + EISA_VENDOR_ID_OFFSET))) {
108 printk(KERN_INFO "EISA: slot %d : %s detected.\n",
109 i, str);
110 c++;
111 }
112 }
113 printk(KERN_INFO "EISA: Detected %d card%s.\n", c, c < 2 ? "" : "s");
114#ifdef CONFIG_ISA
115 printk(KERN_INFO "ISA support compiled in.\n");
116#endif
117
118 /* Warning : BlackMagicAhead(tm).
119 Please wave your favorite dead chicken over the busses */
120
121 /* First say hello to the EIU */
122 outl(0x0000FFFF, EIU_PREMPT_REG);
123 outl(1, EIU_QUIET_REG);
124 outl(0x40f3c07F, EIU_MODE_REG);
125
126 /* Now be nice to the EISA chipset */
127 outb(1, EISA_EXT_NMI_RESET_CTRL);
128 udelay(50); /* Wait long enough for the dust to settle */
129 outb(0, EISA_EXT_NMI_RESET_CTRL);
130 outb(0, EISA_DMA2_WRITE_SINGLE);
131
132 init_i8259_irqs();
133
134 if (request_irq(SGI_EISA_IRQ, ip22_eisa_intr, 0, "EISA", NULL))
135 pr_err("Failed to request irq %d (EISA)\n", SGI_EISA_IRQ);
136
137 EISA_bus = 1;
138 return 0;
139}
diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c
new file mode 100644
index 000000000..de0768a49
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-gio.c
@@ -0,0 +1,431 @@
1// SPDX-License-Identifier: GPL-2.0-only
2#include <linux/export.h>
3#include <linux/kernel.h>
4#include <linux/init.h>
5#include <linux/slab.h>
6
7#include <asm/addrspace.h>
8#include <asm/paccess.h>
9#include <asm/gio_device.h>
10#include <asm/sgi/gio.h>
11#include <asm/sgi/hpc3.h>
12#include <asm/sgi/mc.h>
13#include <asm/sgi/ip22.h>
14
15static struct bus_type gio_bus_type;
16
17static struct {
18 const char *name;
19 __u8 id;
20} gio_name_table[] = {
21 { .name = "SGI Impact", .id = 0x10 },
22 { .name = "Phobos G160", .id = 0x35 },
23 { .name = "Phobos G130", .id = 0x36 },
24 { .name = "Phobos G100", .id = 0x37 },
25 { .name = "Set Engineering GFE", .id = 0x38 },
26 /* fake IDs */
27 { .name = "SGI Newport", .id = 0x7e },
28 { .name = "SGI GR2/GR3", .id = 0x7f },
29};
30
31static void gio_bus_release(struct device *dev)
32{
33 kfree(dev);
34}
35
36static struct device gio_bus = {
37 .init_name = "gio",
38 .release = &gio_bus_release,
39};
40
41/**
42 * gio_match_device - Tell if an of_device structure has a matching
43 * gio_match structure
44 * @ids: array of of device match structures to search in
45 * @dev: the of device structure to match against
46 *
47 * Used by a driver to check whether an of_device present in the
48 * system is in its list of supported devices.
49 */
50static const struct gio_device_id *
51gio_match_device(const struct gio_device_id *match,
52 const struct gio_device *dev)
53{
54 const struct gio_device_id *ids;
55
56 for (ids = match; ids->id != 0xff; ids++)
57 if (ids->id == dev->id.id)
58 return ids;
59
60 return NULL;
61}
62
63struct gio_device *gio_dev_get(struct gio_device *dev)
64{
65 struct device *tmp;
66
67 if (!dev)
68 return NULL;
69 tmp = get_device(&dev->dev);
70 if (tmp)
71 return to_gio_device(tmp);
72 else
73 return NULL;
74}
75EXPORT_SYMBOL_GPL(gio_dev_get);
76
77void gio_dev_put(struct gio_device *dev)
78{
79 if (dev)
80 put_device(&dev->dev);
81}
82EXPORT_SYMBOL_GPL(gio_dev_put);
83
84/**
85 * gio_release_dev - free an gio device structure when all users of it are finished.
86 * @dev: device that's been disconnected
87 *
88 * Will be called only by the device core when all users of this gio device are
89 * done.
90 */
91void gio_release_dev(struct device *dev)
92{
93 struct gio_device *giodev;
94
95 giodev = to_gio_device(dev);
96 kfree(giodev);
97}
98EXPORT_SYMBOL_GPL(gio_release_dev);
99
100int gio_device_register(struct gio_device *giodev)
101{
102 giodev->dev.bus = &gio_bus_type;
103 giodev->dev.parent = &gio_bus;
104 return device_register(&giodev->dev);
105}
106EXPORT_SYMBOL_GPL(gio_device_register);
107
108void gio_device_unregister(struct gio_device *giodev)
109{
110 device_unregister(&giodev->dev);
111}
112EXPORT_SYMBOL_GPL(gio_device_unregister);
113
114static int gio_bus_match(struct device *dev, struct device_driver *drv)
115{
116 struct gio_device *gio_dev = to_gio_device(dev);
117 struct gio_driver *gio_drv = to_gio_driver(drv);
118
119 return gio_match_device(gio_drv->id_table, gio_dev) != NULL;
120}
121
122static int gio_device_probe(struct device *dev)
123{
124 int error = -ENODEV;
125 struct gio_driver *drv;
126 struct gio_device *gio_dev;
127 const struct gio_device_id *match;
128
129 drv = to_gio_driver(dev->driver);
130 gio_dev = to_gio_device(dev);
131
132 if (!drv->probe)
133 return error;
134
135 gio_dev_get(gio_dev);
136
137 match = gio_match_device(drv->id_table, gio_dev);
138 if (match)
139 error = drv->probe(gio_dev, match);
140 if (error)
141 gio_dev_put(gio_dev);
142
143 return error;
144}
145
146static int gio_device_remove(struct device *dev)
147{
148 struct gio_device *gio_dev = to_gio_device(dev);
149 struct gio_driver *drv = to_gio_driver(dev->driver);
150
151 if (dev->driver && drv->remove)
152 drv->remove(gio_dev);
153 return 0;
154}
155
156static void gio_device_shutdown(struct device *dev)
157{
158 struct gio_device *gio_dev = to_gio_device(dev);
159 struct gio_driver *drv = to_gio_driver(dev->driver);
160
161 if (dev->driver && drv->shutdown)
162 drv->shutdown(gio_dev);
163}
164
165static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
166 char *buf)
167{
168 struct gio_device *gio_dev = to_gio_device(dev);
169 int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id);
170
171 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
172}
173static DEVICE_ATTR_RO(modalias);
174
175static ssize_t name_show(struct device *dev,
176 struct device_attribute *attr, char *buf)
177{
178 struct gio_device *giodev;
179
180 giodev = to_gio_device(dev);
181 return sprintf(buf, "%s", giodev->name);
182}
183static DEVICE_ATTR_RO(name);
184
185static ssize_t id_show(struct device *dev,
186 struct device_attribute *attr, char *buf)
187{
188 struct gio_device *giodev;
189
190 giodev = to_gio_device(dev);
191 return sprintf(buf, "%x", giodev->id.id);
192}
193static DEVICE_ATTR_RO(id);
194
195static struct attribute *gio_dev_attrs[] = {
196 &dev_attr_modalias.attr,
197 &dev_attr_name.attr,
198 &dev_attr_id.attr,
199 NULL,
200};
201ATTRIBUTE_GROUPS(gio_dev);
202
203static int gio_device_uevent(struct device *dev, struct kobj_uevent_env *env)
204{
205 struct gio_device *gio_dev = to_gio_device(dev);
206
207 add_uevent_var(env, "MODALIAS=gio:%x", gio_dev->id.id);
208 return 0;
209}
210
211int gio_register_driver(struct gio_driver *drv)
212{
213 /* initialize common driver fields */
214 if (!drv->driver.name)
215 drv->driver.name = drv->name;
216 if (!drv->driver.owner)
217 drv->driver.owner = drv->owner;
218 drv->driver.bus = &gio_bus_type;
219
220 /* register with core */
221 return driver_register(&drv->driver);
222}
223EXPORT_SYMBOL_GPL(gio_register_driver);
224
225void gio_unregister_driver(struct gio_driver *drv)
226{
227 driver_unregister(&drv->driver);
228}
229EXPORT_SYMBOL_GPL(gio_unregister_driver);
230
231void gio_set_master(struct gio_device *dev)
232{
233 u32 tmp = sgimc->giopar;
234
235 switch (dev->slotno) {
236 case 0:
237 tmp |= SGIMC_GIOPAR_MASTERGFX;
238 break;
239 case 1:
240 tmp |= SGIMC_GIOPAR_MASTEREXP0;
241 break;
242 case 2:
243 tmp |= SGIMC_GIOPAR_MASTEREXP1;
244 break;
245 }
246 sgimc->giopar = tmp;
247}
248EXPORT_SYMBOL_GPL(gio_set_master);
249
250void ip22_gio_set_64bit(int slotno)
251{
252 u32 tmp = sgimc->giopar;
253
254 switch (slotno) {
255 case 0:
256 tmp |= SGIMC_GIOPAR_GFX64;
257 break;
258 case 1:
259 tmp |= SGIMC_GIOPAR_EXP064;
260 break;
261 case 2:
262 tmp |= SGIMC_GIOPAR_EXP164;
263 break;
264 }
265 sgimc->giopar = tmp;
266}
267
268static int ip22_gio_id(unsigned long addr, u32 *res)
269{
270 u8 tmp8;
271 u8 tmp16;
272 u32 tmp32;
273 u8 *ptr8;
274 u16 *ptr16;
275 u32 *ptr32;
276
277 ptr32 = (void *)CKSEG1ADDR(addr);
278 if (!get_dbe(tmp32, ptr32)) {
279 /*
280 * We got no DBE, but this doesn't mean anything.
281 * If GIO is pipelined (which can't be disabled
282 * for GFX slot) we don't get a DBE, but we see
283 * the transfer size as data. So we do an 8bit
284 * and a 16bit access and check whether the common
285 * data matches
286 */
287 ptr8 = (void *)CKSEG1ADDR(addr + 3);
288 if (get_dbe(tmp8, ptr8)) {
289 /*
290 * 32bit access worked, but 8bit doesn't
291 * so we don't see phantom reads on
292 * a pipelined bus, but a real card which
293 * doesn't support 8 bit reads
294 */
295 *res = tmp32;
296 return 1;
297 }
298 ptr16 = (void *)CKSEG1ADDR(addr + 2);
299 get_dbe(tmp16, ptr16);
300 if (tmp8 == (tmp16 & 0xff) &&
301 tmp8 == (tmp32 & 0xff) &&
302 tmp16 == (tmp32 & 0xffff)) {
303 *res = tmp32;
304 return 1;
305 }
306 }
307 return 0; /* nothing here */
308}
309
310#define HQ2_MYSTERY_OFFS 0x6A07C
311#define NEWPORT_USTATUS_OFFS 0xF133C
312
313static int ip22_is_gr2(unsigned long addr)
314{
315 u32 tmp;
316 u32 *ptr;
317
318 /* HQ2 only allows 32bit accesses */
319 ptr = (void *)CKSEG1ADDR(addr + HQ2_MYSTERY_OFFS);
320 if (!get_dbe(tmp, ptr)) {
321 if (tmp == 0xdeadbeef)
322 return 1;
323 }
324 return 0;
325}
326
327
328static void ip22_check_gio(int slotno, unsigned long addr, int irq)
329{
330 const char *name = "Unknown";
331 struct gio_device *gio_dev;
332 u32 tmp;
333 __u8 id;
334 int i;
335
336 /* first look for GR2/GR3 by checking mystery register */
337 if (ip22_is_gr2(addr))
338 tmp = 0x7f;
339 else {
340 if (!ip22_gio_id(addr, &tmp)) {
341 /*
342 * no GIO signature at start address of slot
343 * since Newport doesn't have one, we check if
344 * user status register is readable
345 */
346 if (ip22_gio_id(addr + NEWPORT_USTATUS_OFFS, &tmp))
347 tmp = 0x7e;
348 else
349 tmp = 0;
350 }
351 }
352 if (tmp) {
353 id = GIO_ID(tmp);
354 if (tmp & GIO_32BIT_ID) {
355 if (tmp & GIO_64BIT_IFACE)
356 ip22_gio_set_64bit(slotno);
357 }
358 for (i = 0; i < ARRAY_SIZE(gio_name_table); i++) {
359 if (id == gio_name_table[i].id) {
360 name = gio_name_table[i].name;
361 break;
362 }
363 }
364 printk(KERN_INFO "GIO: slot %d : %s (id %x)\n",
365 slotno, name, id);
366 gio_dev = kzalloc(sizeof *gio_dev, GFP_KERNEL);
367 gio_dev->name = name;
368 gio_dev->slotno = slotno;
369 gio_dev->id.id = id;
370 gio_dev->resource.start = addr;
371 gio_dev->resource.end = addr + 0x3fffff;
372 gio_dev->resource.flags = IORESOURCE_MEM;
373 gio_dev->irq = irq;
374 dev_set_name(&gio_dev->dev, "%d", slotno);
375 gio_device_register(gio_dev);
376 } else
377 printk(KERN_INFO "GIO: slot %d : Empty\n", slotno);
378}
379
380static struct bus_type gio_bus_type = {
381 .name = "gio",
382 .dev_groups = gio_dev_groups,
383 .match = gio_bus_match,
384 .probe = gio_device_probe,
385 .remove = gio_device_remove,
386 .shutdown = gio_device_shutdown,
387 .uevent = gio_device_uevent,
388};
389
390static struct resource gio_bus_resource = {
391 .start = GIO_SLOT_GFX_BASE,
392 .end = GIO_SLOT_GFX_BASE + 0x9fffff,
393 .name = "GIO Bus",
394 .flags = IORESOURCE_MEM,
395};
396
397int __init ip22_gio_init(void)
398{
399 unsigned int pbdma __maybe_unused;
400 int ret;
401
402 ret = device_register(&gio_bus);
403 if (ret) {
404 put_device(&gio_bus);
405 return ret;
406 }
407
408 ret = bus_register(&gio_bus_type);
409 if (!ret) {
410 request_resource(&iomem_resource, &gio_bus_resource);
411 printk(KERN_INFO "GIO: Probing bus...\n");
412
413 if (ip22_is_fullhouse()) {
414 /* Indigo2 */
415 ip22_check_gio(0, GIO_SLOT_GFX_BASE, SGI_GIO_1_IRQ);
416 ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIO_1_IRQ);
417 } else {
418 /* Indy/Challenge S */
419 if (get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
420 ip22_check_gio(0, GIO_SLOT_GFX_BASE,
421 SGI_GIO_0_IRQ);
422 ip22_check_gio(1, GIO_SLOT_EXP0_BASE, SGI_GIOEXP0_IRQ);
423 ip22_check_gio(2, GIO_SLOT_EXP1_BASE, SGI_GIOEXP1_IRQ);
424 }
425 } else
426 device_unregister(&gio_bus);
427
428 return ret;
429}
430
431subsys_initcall(ip22_gio_init);
diff --git a/arch/mips/sgi-ip22/ip22-hpc.c b/arch/mips/sgi-ip22/ip22-hpc.c
new file mode 100644
index 000000000..49922e86c
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-hpc.c
@@ -0,0 +1,64 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip22-hpc.c: Routines for generic manipulation of the HPC controllers.
4 *
5 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
6 * Copyright (C) 1998 Ralf Baechle
7 */
8
9#include <linux/export.h>
10#include <linux/init.h>
11#include <linux/types.h>
12
13#include <asm/io.h>
14#include <asm/sgi/hpc3.h>
15#include <asm/sgi/ioc.h>
16#include <asm/sgi/ip22.h>
17
18struct hpc3_regs *hpc3c0, *hpc3c1;
19
20EXPORT_SYMBOL(hpc3c0);
21EXPORT_SYMBOL(hpc3c1);
22
23struct sgioc_regs *sgioc;
24
25EXPORT_SYMBOL(sgioc);
26
27/* We need software copies of these because they are write only. */
28u8 sgi_ioc_reset, sgi_ioc_write;
29
30extern char *system_type;
31
32void __init sgihpc_init(void)
33{
34 /* ioremap can't fail */
35 hpc3c0 = (struct hpc3_regs *)
36 ioremap(HPC3_CHIP0_BASE, sizeof(struct hpc3_regs));
37 hpc3c1 = (struct hpc3_regs *)
38 ioremap(HPC3_CHIP1_BASE, sizeof(struct hpc3_regs));
39 /* IOC lives in PBUS PIO channel 6 */
40 sgioc = (struct sgioc_regs *)hpc3c0->pbus_extregs[6];
41
42 hpc3c0->pbus_piocfg[6][0] |= HPC3_PIOCFG_DS16;
43 if (ip22_is_fullhouse()) {
44 /* Full House comes with INT2 which lives in PBUS PIO
45 * channel 4 */
46 sgint = (struct sgint_regs *)hpc3c0->pbus_extregs[4];
47 system_type = "SGI Indigo2";
48 } else {
49 /* Guiness comes with INT3 which is part of IOC */
50 sgint = &sgioc->int3;
51 system_type = "SGI Indy";
52 }
53
54 sgi_ioc_reset = (SGIOC_RESET_PPORT | SGIOC_RESET_KBDMOUSE |
55 SGIOC_RESET_EISA | SGIOC_RESET_ISDN |
56 SGIOC_RESET_LC0OFF);
57
58 sgi_ioc_write = (SGIOC_WRITE_EASEL | SGIOC_WRITE_NTHRESH |
59 SGIOC_WRITE_TPSPEED | SGIOC_WRITE_EPSEL |
60 SGIOC_WRITE_U0AMODE | SGIOC_WRITE_U1AMODE);
61
62 sgioc->reset = sgi_ioc_reset;
63 sgioc->write = sgi_ioc_write;
64}
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
new file mode 100644
index 000000000..96798a4ab
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -0,0 +1,320 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip22-int.c: Routines for generic manipulation of the INT[23] ASIC
4 * found on INDY and Indigo2 workstations.
5 *
6 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
7 * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
8 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
9 * - Indigo2 changes
10 * - Interrupt handling fixes
11 * Copyright (C) 2001, 2003 Ladislav Michl (ladis@linux-mips.org)
12 */
13#include <linux/types.h>
14#include <linux/init.h>
15#include <linux/kernel_stat.h>
16#include <linux/interrupt.h>
17#include <linux/ftrace.h>
18
19#include <asm/irq_cpu.h>
20#include <asm/sgi/hpc3.h>
21#include <asm/sgi/ip22.h>
22
23/* So far nothing hangs here */
24#undef USE_LIO3_IRQ
25
26struct sgint_regs *sgint;
27
28static char lc0msk_to_irqnr[256];
29static char lc1msk_to_irqnr[256];
30static char lc2msk_to_irqnr[256];
31static char lc3msk_to_irqnr[256];
32
33extern int ip22_eisa_init(void);
34
35static void enable_local0_irq(struct irq_data *d)
36{
37 /* don't allow mappable interrupt to be enabled from setup_irq,
38 * we have our own way to do so */
39 if (d->irq != SGI_MAP_0_IRQ)
40 sgint->imask0 |= (1 << (d->irq - SGINT_LOCAL0));
41}
42
43static void disable_local0_irq(struct irq_data *d)
44{
45 sgint->imask0 &= ~(1 << (d->irq - SGINT_LOCAL0));
46}
47
48static struct irq_chip ip22_local0_irq_type = {
49 .name = "IP22 local 0",
50 .irq_mask = disable_local0_irq,
51 .irq_unmask = enable_local0_irq,
52};
53
54static void enable_local1_irq(struct irq_data *d)
55{
56 /* don't allow mappable interrupt to be enabled from setup_irq,
57 * we have our own way to do so */
58 if (d->irq != SGI_MAP_1_IRQ)
59 sgint->imask1 |= (1 << (d->irq - SGINT_LOCAL1));
60}
61
62static void disable_local1_irq(struct irq_data *d)
63{
64 sgint->imask1 &= ~(1 << (d->irq - SGINT_LOCAL1));
65}
66
67static struct irq_chip ip22_local1_irq_type = {
68 .name = "IP22 local 1",
69 .irq_mask = disable_local1_irq,
70 .irq_unmask = enable_local1_irq,
71};
72
73static void enable_local2_irq(struct irq_data *d)
74{
75 sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
76 sgint->cmeimask0 |= (1 << (d->irq - SGINT_LOCAL2));
77}
78
79static void disable_local2_irq(struct irq_data *d)
80{
81 sgint->cmeimask0 &= ~(1 << (d->irq - SGINT_LOCAL2));
82 if (!sgint->cmeimask0)
83 sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
84}
85
86static struct irq_chip ip22_local2_irq_type = {
87 .name = "IP22 local 2",
88 .irq_mask = disable_local2_irq,
89 .irq_unmask = enable_local2_irq,
90};
91
92static void enable_local3_irq(struct irq_data *d)
93{
94 sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
95 sgint->cmeimask1 |= (1 << (d->irq - SGINT_LOCAL3));
96}
97
98static void disable_local3_irq(struct irq_data *d)
99{
100 sgint->cmeimask1 &= ~(1 << (d->irq - SGINT_LOCAL3));
101 if (!sgint->cmeimask1)
102 sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
103}
104
105static struct irq_chip ip22_local3_irq_type = {
106 .name = "IP22 local 3",
107 .irq_mask = disable_local3_irq,
108 .irq_unmask = enable_local3_irq,
109};
110
111static void indy_local0_irqdispatch(void)
112{
113 u8 mask = sgint->istat0 & sgint->imask0;
114 u8 mask2;
115 int irq;
116
117 if (mask & SGINT_ISTAT0_LIO2) {
118 mask2 = sgint->vmeistat & sgint->cmeimask0;
119 irq = lc2msk_to_irqnr[mask2];
120 } else
121 irq = lc0msk_to_irqnr[mask];
122
123 /*
124 * workaround for INT2 bug; if irq == 0, INT2 has seen a fifo full
125 * irq, but failed to latch it into status register
126 */
127 if (irq)
128 do_IRQ(irq);
129 else
130 do_IRQ(SGINT_LOCAL0 + 0);
131}
132
133static void indy_local1_irqdispatch(void)
134{
135 u8 mask = sgint->istat1 & sgint->imask1;
136 u8 mask2;
137 int irq;
138
139 if (mask & SGINT_ISTAT1_LIO3) {
140 mask2 = sgint->vmeistat & sgint->cmeimask1;
141 irq = lc3msk_to_irqnr[mask2];
142 } else
143 irq = lc1msk_to_irqnr[mask];
144
145 /* if irq == 0, then the interrupt has already been cleared */
146 if (irq)
147 do_IRQ(irq);
148}
149
150extern void ip22_be_interrupt(int irq);
151
152static void __irq_entry indy_buserror_irq(void)
153{
154 int irq = SGI_BUSERR_IRQ;
155
156 irq_enter();
157 kstat_incr_irq_this_cpu(irq);
158 ip22_be_interrupt(irq);
159 irq_exit();
160}
161
162#ifdef USE_LIO3_IRQ
163#define SGI_INTERRUPTS SGINT_END
164#else
165#define SGI_INTERRUPTS SGINT_LOCAL3
166#endif
167
168extern void indy_8254timer_irq(void);
169
170/*
171 * IRQs on the INDY look basically (barring software IRQs which we don't use
172 * at all) like:
173 *
174 * MIPS IRQ Source
175 * -------- ------
176 * 0 Software (ignored)
177 * 1 Software (ignored)
178 * 2 Local IRQ level zero
179 * 3 Local IRQ level one
180 * 4 8254 Timer zero
181 * 5 8254 Timer one
182 * 6 Bus Error
183 * 7 R4k timer (what we use)
184 *
185 * We handle the IRQ according to _our_ priority which is:
186 *
187 * Highest ---- R4k Timer
188 * Local IRQ zero
189 * Local IRQ one
190 * Bus Error
191 * 8254 Timer zero
192 * Lowest ---- 8254 Timer one
193 *
194 * then we just return, if multiple IRQs are pending then we will just take
195 * another exception, big deal.
196 */
197
198asmlinkage void plat_irq_dispatch(void)
199{
200 unsigned int pending = read_c0_status() & read_c0_cause();
201
202 /*
203 * First we check for r4k counter/timer IRQ.
204 */
205 if (pending & CAUSEF_IP7)
206 do_IRQ(SGI_TIMER_IRQ);
207 else if (pending & CAUSEF_IP2)
208 indy_local0_irqdispatch();
209 else if (pending & CAUSEF_IP3)
210 indy_local1_irqdispatch();
211 else if (pending & CAUSEF_IP6)
212 indy_buserror_irq();
213 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
214 indy_8254timer_irq();
215}
216
217void __init arch_init_irq(void)
218{
219 int i;
220
221 /* Init local mask --> irq tables. */
222 for (i = 0; i < 256; i++) {
223 if (i & 0x80) {
224 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7;
225 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7;
226 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7;
227 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7;
228 } else if (i & 0x40) {
229 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6;
230 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6;
231 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6;
232 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6;
233 } else if (i & 0x20) {
234 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5;
235 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5;
236 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5;
237 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5;
238 } else if (i & 0x10) {
239 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4;
240 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4;
241 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4;
242 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4;
243 } else if (i & 0x08) {
244 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3;
245 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3;
246 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3;
247 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3;
248 } else if (i & 0x04) {
249 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2;
250 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2;
251 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2;
252 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2;
253 } else if (i & 0x02) {
254 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1;
255 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1;
256 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1;
257 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1;
258 } else if (i & 0x01) {
259 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0;
260 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0;
261 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0;
262 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0;
263 } else {
264 lc0msk_to_irqnr[i] = 0;
265 lc1msk_to_irqnr[i] = 0;
266 lc2msk_to_irqnr[i] = 0;
267 lc3msk_to_irqnr[i] = 0;
268 }
269 }
270
271 /* Mask out all interrupts. */
272 sgint->imask0 = 0;
273 sgint->imask1 = 0;
274 sgint->cmeimask0 = 0;
275 sgint->cmeimask1 = 0;
276
277 /* init CPU irqs */
278 mips_cpu_irq_init();
279
280 for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
281 struct irq_chip *handler;
282
283 if (i < SGINT_LOCAL1)
284 handler = &ip22_local0_irq_type;
285 else if (i < SGINT_LOCAL2)
286 handler = &ip22_local1_irq_type;
287 else if (i < SGINT_LOCAL3)
288 handler = &ip22_local2_irq_type;
289 else
290 handler = &ip22_local3_irq_type;
291
292 irq_set_chip_and_handler(i, handler, handle_level_irq);
293 }
294
295 /* vector handler. this register the IRQ as non-sharable */
296 if (request_irq(SGI_LOCAL_0_IRQ, no_action, IRQF_NO_THREAD,
297 "local0 cascade", NULL))
298 pr_err("Failed to register local0 cascade interrupt\n");
299 if (request_irq(SGI_LOCAL_1_IRQ, no_action, IRQF_NO_THREAD,
300 "local1 cascade", NULL))
301 pr_err("Failed to register local1 cascade interrupt\n");
302 if (request_irq(SGI_BUSERR_IRQ, no_action, IRQF_NO_THREAD,
303 "Bus Error", NULL))
304 pr_err("Failed to register Bus Error interrupt\n");
305
306 /* cascade in cascade. i love Indy ;-) */
307 if (request_irq(SGI_MAP_0_IRQ, no_action, IRQF_NO_THREAD,
308 "mapable0 cascade", NULL))
309 pr_err("Failed to register mapable0 cascade interrupt\n");
310#ifdef USE_LIO3_IRQ
311 if (request_irq(SGI_MAP_1_IRQ, no_action, IRQF_NO_THREAD,
312 "mapable1 cascade", NULL))
313 pr_err("Failed to register mapable1 cascade interrupt\n");
314#endif
315
316#ifdef CONFIG_EISA
317 if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */
318 ip22_eisa_init();
319#endif
320}
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
new file mode 100644
index 000000000..74e5b9e27
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -0,0 +1,203 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip22-mc.c: Routines for manipulating SGI Memory Controller.
4 *
5 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
6 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
7 * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org)
8 * Copyright (C) 2004 Peter Fuerst (pf@net.alphadv.de) - IP28
9 */
10
11#include <linux/init.h>
12#include <linux/export.h>
13#include <linux/kernel.h>
14#include <linux/memblock.h>
15#include <linux/spinlock.h>
16
17#include <asm/io.h>
18#include <asm/bootinfo.h>
19#include <asm/sgialib.h>
20#include <asm/sgi/mc.h>
21#include <asm/sgi/hpc3.h>
22#include <asm/sgi/ip22.h>
23
24struct sgimc_regs *sgimc;
25
26EXPORT_SYMBOL(sgimc);
27
28static inline unsigned long get_bank_addr(unsigned int memconfig)
29{
30 return (memconfig & SGIMC_MCONFIG_BASEADDR) << ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 24 : 22);
31}
32
33static inline unsigned long get_bank_size(unsigned int memconfig)
34{
35 return ((memconfig & SGIMC_MCONFIG_RMASK) + 0x0100) << ((sgimc->systemid & SGIMC_SYSID_MASKREV) >= 5 ? 16 : 14);
36}
37
38static inline unsigned int get_bank_config(int bank)
39{
40 unsigned int res = bank > 1 ? sgimc->mconfig1 : sgimc->mconfig0;
41 return bank % 2 ? res & 0xffff : res >> 16;
42}
43
44#if defined(CONFIG_SGI_IP28) || defined(CONFIG_32BIT)
45static void __init probe_memory(void)
46{
47 /* prom detects all usable memory */
48}
49#else
50/*
51 * Detect installed memory, which PROM misses
52 */
53static void __init probe_memory(void)
54{
55 unsigned long addr, size;
56 int i;
57
58 printk(KERN_INFO "MC: Probing memory configuration:\n");
59 for (i = 0; i < 4; i++) {
60 unsigned int tmp = get_bank_config(i);
61 if (!(tmp & SGIMC_MCONFIG_BVALID))
62 continue;
63
64 size = get_bank_size(tmp);
65 addr = get_bank_addr(tmp);
66 printk(KERN_INFO " bank%d: %3ldM @ %08lx\n",
67 i, size / 1024 / 1024, addr);
68
69 if (addr >= SGIMC_SEG1_BADDR)
70 memblock_add(addr, size);
71 }
72}
73#endif
74
75void __init sgimc_init(void)
76{
77 u32 tmp;
78
79 /* ioremap can't fail */
80 sgimc = (struct sgimc_regs *)
81 ioremap(SGIMC_BASE, sizeof(struct sgimc_regs));
82
83 printk(KERN_INFO "MC: SGI memory controller Revision %d\n",
84 (int) sgimc->systemid & SGIMC_SYSID_MASKREV);
85
86 /* Place the MC into a known state. This must be done before
87 * interrupts are first enabled etc.
88 */
89
90 /* Step 0: Make sure we turn off the watchdog in case it's
91 * still running (which might be the case after a
92 * soft reboot).
93 */
94 tmp = sgimc->cpuctrl0;
95 tmp &= ~SGIMC_CCTRL0_WDOG;
96 sgimc->cpuctrl0 = tmp;
97
98 /* Step 1: The CPU/GIO error status registers will not latch
99 * up a new error status until the register has been
100 * cleared by the cpu. These status registers are
101 * cleared by writing any value to them.
102 */
103 sgimc->cstat = sgimc->gstat = 0;
104
105 /* Step 2: Enable all parity checking in cpu control register
106 * zero.
107 */
108 /* don't touch parity settings for IP28 */
109 tmp = sgimc->cpuctrl0;
110#ifndef CONFIG_SGI_IP28
111 tmp |= SGIMC_CCTRL0_EPERRGIO | SGIMC_CCTRL0_EPERRMEM;
112#endif
113 tmp |= SGIMC_CCTRL0_R4KNOCHKPARR;
114 sgimc->cpuctrl0 = tmp;
115
116 /* Step 3: Setup the MC write buffer depth, this is controlled
117 * in cpu control register 1 in the lower 4 bits.
118 */
119 tmp = sgimc->cpuctrl1;
120 tmp &= ~0xf;
121 tmp |= 0xd;
122 sgimc->cpuctrl1 = tmp;
123
124 /* Step 4: Initialize the RPSS divider register to run as fast
125 * as it can correctly operate. The register is laid
126 * out as follows:
127 *
128 * ----------------------------------------
129 * | RESERVED | INCREMENT | DIVIDER |
130 * ----------------------------------------
131 * 31 16 15 8 7 0
132 *
133 * DIVIDER determines how often a 'tick' happens,
134 * INCREMENT determines by how the RPSS increment
135 * registers value increases at each 'tick'. Thus,
136 * for IP22 we get INCREMENT=1, DIVIDER=1 == 0x101
137 */
138 sgimc->divider = 0x101;
139
140 /* Step 5: Initialize GIO64 arbitrator configuration register.
141 *
142 * NOTE: HPC init code in sgihpc_init() must run before us because
143 * we need to know Guiness vs. FullHouse and the board
144 * revision on this machine. You have been warned.
145 */
146
147 /* First the basic invariants across all GIO64 implementations. */
148 tmp = sgimc->giopar & SGIMC_GIOPAR_GFX64; /* keep gfx 64bit settings */
149 tmp |= SGIMC_GIOPAR_HPC64; /* All 1st HPC's interface at 64bits */
150 tmp |= SGIMC_GIOPAR_ONEBUS; /* Only one physical GIO bus exists */
151
152 if (ip22_is_fullhouse()) {
153 /* Fullhouse specific settings. */
154 if (SGIOC_SYSID_BOARDREV(sgioc->sysid) < 2) {
155 tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC at 64bits */
156 tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp0 pipelines */
157 tmp |= SGIMC_GIOPAR_MASTEREXP1; /* exp1 masters */
158 tmp |= SGIMC_GIOPAR_RTIMEEXP0; /* exp0 is realtime */
159 } else {
160 tmp |= SGIMC_GIOPAR_HPC264; /* 2nd HPC 64bits */
161 tmp |= SGIMC_GIOPAR_PLINEEXP0; /* exp[01] pipelined */
162 tmp |= SGIMC_GIOPAR_PLINEEXP1;
163 tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA masters */
164 }
165 } else {
166 /* Guiness specific settings. */
167 tmp |= SGIMC_GIOPAR_EISA64; /* MC talks to EISA at 64bits */
168 tmp |= SGIMC_GIOPAR_MASTEREISA; /* EISA bus can act as master */
169 }
170 sgimc->giopar = tmp; /* poof */
171
172 probe_memory();
173}
174
175#ifdef CONFIG_SGI_IP28
176void __init prom_cleanup(void)
177{
178 u32 mconfig1;
179 unsigned long flags;
180 spinlock_t lock;
181
182 /*
183 * because ARCS accesses memory uncached we wait until ARCS
184 * isn't needed any longer, before we switch from slow to
185 * normal mode
186 */
187 spin_lock_irqsave(&lock, flags);
188 mconfig1 = sgimc->mconfig1;
189 /* map ECC register */
190 sgimc->mconfig1 = (mconfig1 & 0xffff0000) | 0x2060;
191 iob();
192 /* switch to normal mode */
193 *(unsigned long *)PHYS_TO_XKSEG_UNCACHED(0x60000000) = 0;
194 iob();
195 /* reduce WR_COL */
196 sgimc->cmacc = (sgimc->cmacc & ~0xf) | 4;
197 iob();
198 /* restore old config */
199 sgimc->mconfig1 = mconfig1;
200 iob();
201 spin_unlock_irqrestore(&lock, flags);
202}
203#endif
diff --git a/arch/mips/sgi-ip22/ip22-nvram.c b/arch/mips/sgi-ip22/ip22-nvram.c
new file mode 100644
index 000000000..e727ef519
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-nvram.c
@@ -0,0 +1,122 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip22-nvram.c: NVRAM and serial EEPROM handling.
4 *
5 * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org)
6 */
7#include <linux/export.h>
8
9#include <asm/sgi/hpc3.h>
10#include <asm/sgi/ip22.h>
11
12/* Control opcode for serial eeprom */
13#define EEPROM_READ 0xc000 /* serial memory read */
14#define EEPROM_WEN 0x9800 /* write enable before prog modes */
15#define EEPROM_WRITE 0xa000 /* serial memory write */
16#define EEPROM_WRALL 0x8800 /* write all registers */
17#define EEPROM_WDS 0x8000 /* disable all programming */
18#define EEPROM_PRREAD 0xc000 /* read protect register */
19#define EEPROM_PREN 0x9800 /* enable protect register mode */
20#define EEPROM_PRCLEAR 0xffff /* clear protect register */
21#define EEPROM_PRWRITE 0xa000 /* write protect register */
22#define EEPROM_PRDS 0x8000 /* disable protect register, forever */
23
24#define EEPROM_EPROT 0x01 /* Protect register enable */
25#define EEPROM_CSEL 0x02 /* Chip select */
26#define EEPROM_ECLK 0x04 /* EEPROM clock */
27#define EEPROM_DATO 0x08 /* Data out */
28#define EEPROM_DATI 0x10 /* Data in */
29
30/* We need to use these functions early... */
31#define delay() ({ \
32 int x; \
33 for (x=0; x<100000; x++) __asm__ __volatile__(""); })
34
35#define eeprom_cs_on(ptr) ({ \
36 __raw_writel(__raw_readl(ptr) & ~EEPROM_DATO, ptr); \
37 __raw_writel(__raw_readl(ptr) & ~EEPROM_ECLK, ptr); \
38 __raw_writel(__raw_readl(ptr) & ~EEPROM_EPROT, ptr); \
39 delay(); \
40 __raw_writel(__raw_readl(ptr) | EEPROM_CSEL, ptr); \
41 __raw_writel(__raw_readl(ptr) | EEPROM_ECLK, ptr); })
42
43
44#define eeprom_cs_off(ptr) ({ \
45 __raw_writel(__raw_readl(ptr) & ~EEPROM_ECLK, ptr); \
46 __raw_writel(__raw_readl(ptr) & ~EEPROM_CSEL, ptr); \
47 __raw_writel(__raw_readl(ptr) | EEPROM_EPROT, ptr); \
48 __raw_writel(__raw_readl(ptr) | EEPROM_ECLK, ptr); })
49
50#define BITS_IN_COMMAND 11
51/*
52 * clock in the nvram command and the register number. For the
53 * national semiconductor nv ram chip the op code is 3 bits and
54 * the address is 6/8 bits.
55 */
56static inline void eeprom_cmd(unsigned int *ctrl, unsigned cmd, unsigned reg)
57{
58 unsigned short ser_cmd;
59 int i;
60
61 ser_cmd = cmd | (reg << (16 - BITS_IN_COMMAND));
62 for (i = 0; i < BITS_IN_COMMAND; i++) {
63 if (ser_cmd & (1<<15)) /* if high order bit set */
64 __raw_writel(__raw_readl(ctrl) | EEPROM_DATO, ctrl);
65 else
66 __raw_writel(__raw_readl(ctrl) & ~EEPROM_DATO, ctrl);
67 __raw_writel(__raw_readl(ctrl) & ~EEPROM_ECLK, ctrl);
68 delay();
69 __raw_writel(__raw_readl(ctrl) | EEPROM_ECLK, ctrl);
70 delay();
71 ser_cmd <<= 1;
72 }
73 /* see data sheet timing diagram */
74 __raw_writel(__raw_readl(ctrl) & ~EEPROM_DATO, ctrl);
75}
76
77unsigned short ip22_eeprom_read(unsigned int *ctrl, int reg)
78{
79 unsigned short res = 0;
80 int i;
81
82 __raw_writel(__raw_readl(ctrl) & ~EEPROM_EPROT, ctrl);
83 eeprom_cs_on(ctrl);
84 eeprom_cmd(ctrl, EEPROM_READ, reg);
85
86 /* clock the data ouf of serial mem */
87 for (i = 0; i < 16; i++) {
88 __raw_writel(__raw_readl(ctrl) & ~EEPROM_ECLK, ctrl);
89 delay();
90 __raw_writel(__raw_readl(ctrl) | EEPROM_ECLK, ctrl);
91 delay();
92 res <<= 1;
93 if (__raw_readl(ctrl) & EEPROM_DATI)
94 res |= 1;
95 }
96
97 eeprom_cs_off(ctrl);
98
99 return res;
100}
101
102EXPORT_SYMBOL(ip22_eeprom_read);
103
104/*
105 * Read specified register from main NVRAM
106 */
107unsigned short ip22_nvram_read(int reg)
108{
109 if (ip22_is_fullhouse())
110 /* IP22 (Indigo2 aka FullHouse) stores env variables into
111 * 93CS56 Microwire Bus EEPROM 2048 Bit (128x16) */
112 return ip22_eeprom_read(&hpc3c0->eeprom, reg);
113 else {
114 unsigned short tmp;
115 /* IP24 (Indy aka Guiness) uses DS1386 8K version */
116 reg <<= 1;
117 tmp = hpc3c0->bbram[reg++] & 0xff;
118 return (tmp << 8) | (hpc3c0->bbram[reg] & 0xff);
119 }
120}
121
122EXPORT_SYMBOL(ip22_nvram_read);
diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c
new file mode 100644
index 000000000..0b2002e02
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-platform.c
@@ -0,0 +1,223 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <linux/init.h>
3#include <linux/if_ether.h>
4#include <linux/kernel.h>
5#include <linux/platform_device.h>
6#include <linux/dma-mapping.h>
7
8#include <asm/paccess.h>
9#include <asm/sgi/ip22.h>
10#include <asm/sgi/hpc3.h>
11#include <asm/sgi/mc.h>
12#include <asm/sgi/seeq.h>
13#include <asm/sgi/wd.h>
14
15static struct resource sgiwd93_0_resources[] = {
16 {
17 .name = "eth0 irq",
18 .start = SGI_WD93_0_IRQ,
19 .end = SGI_WD93_0_IRQ,
20 .flags = IORESOURCE_IRQ
21 }
22};
23
24static struct sgiwd93_platform_data sgiwd93_0_pd = {
25 .unit = 0,
26 .irq = SGI_WD93_0_IRQ,
27};
28
29static u64 sgiwd93_0_dma_mask = DMA_BIT_MASK(32);
30
31static struct platform_device sgiwd93_0_device = {
32 .name = "sgiwd93",
33 .id = 0,
34 .num_resources = ARRAY_SIZE(sgiwd93_0_resources),
35 .resource = sgiwd93_0_resources,
36 .dev = {
37 .platform_data = &sgiwd93_0_pd,
38 .dma_mask = &sgiwd93_0_dma_mask,
39 .coherent_dma_mask = DMA_BIT_MASK(32),
40 },
41};
42
43static struct resource sgiwd93_1_resources[] = {
44 {
45 .name = "eth0 irq",
46 .start = SGI_WD93_1_IRQ,
47 .end = SGI_WD93_1_IRQ,
48 .flags = IORESOURCE_IRQ
49 }
50};
51
52static struct sgiwd93_platform_data sgiwd93_1_pd = {
53 .unit = 1,
54 .irq = SGI_WD93_1_IRQ,
55};
56
57static u64 sgiwd93_1_dma_mask = DMA_BIT_MASK(32);
58
59static struct platform_device sgiwd93_1_device = {
60 .name = "sgiwd93",
61 .id = 1,
62 .num_resources = ARRAY_SIZE(sgiwd93_1_resources),
63 .resource = sgiwd93_1_resources,
64 .dev = {
65 .platform_data = &sgiwd93_1_pd,
66 .dma_mask = &sgiwd93_1_dma_mask,
67 .coherent_dma_mask = DMA_BIT_MASK(32),
68 },
69};
70
71/*
72 * Create a platform device for the GPI port that receives the
73 * image data from the embedded camera.
74 */
75static int __init sgiwd93_devinit(void)
76{
77 int res;
78
79 sgiwd93_0_pd.hregs = &hpc3c0->scsi_chan0;
80 sgiwd93_0_pd.wdregs = (unsigned char *) hpc3c0->scsi0_ext;
81
82 res = platform_device_register(&sgiwd93_0_device);
83 if (res)
84 return res;
85
86 if (!ip22_is_fullhouse())
87 return 0;
88
89 sgiwd93_1_pd.hregs = &hpc3c0->scsi_chan1;
90 sgiwd93_1_pd.wdregs = (unsigned char *) hpc3c0->scsi1_ext;
91
92 return platform_device_register(&sgiwd93_1_device);
93}
94
95device_initcall(sgiwd93_devinit);
96
97static struct resource sgiseeq_0_resources[] = {
98 {
99 .name = "eth0 irq",
100 .start = SGI_ENET_IRQ,
101 .end = SGI_ENET_IRQ,
102 .flags = IORESOURCE_IRQ
103 }
104};
105
106static struct sgiseeq_platform_data eth0_pd;
107
108static u64 sgiseeq_dma_mask = DMA_BIT_MASK(32);
109
110static struct platform_device eth0_device = {
111 .name = "sgiseeq",
112 .id = 0,
113 .num_resources = ARRAY_SIZE(sgiseeq_0_resources),
114 .resource = sgiseeq_0_resources,
115 .dev = {
116 .platform_data = &eth0_pd,
117 .dma_mask = &sgiseeq_dma_mask,
118 .coherent_dma_mask = DMA_BIT_MASK(32),
119 },
120};
121
122static struct resource sgiseeq_1_resources[] = {
123 {
124 .name = "eth1 irq",
125 .start = SGI_GIO_0_IRQ,
126 .end = SGI_GIO_0_IRQ,
127 .flags = IORESOURCE_IRQ
128 }
129};
130
131static struct sgiseeq_platform_data eth1_pd;
132
133static struct platform_device eth1_device = {
134 .name = "sgiseeq",
135 .id = 1,
136 .num_resources = ARRAY_SIZE(sgiseeq_1_resources),
137 .resource = sgiseeq_1_resources,
138 .dev = {
139 .platform_data = &eth1_pd,
140 },
141};
142
143/*
144 * Create a platform device for the GPI port that receives the
145 * image data from the embedded camera.
146 */
147static int __init sgiseeq_devinit(void)
148{
149 unsigned int pbdma __maybe_unused;
150 int res, i;
151
152 eth0_pd.hpc = hpc3c0;
153 eth0_pd.irq = SGI_ENET_IRQ;
154#define EADDR_NVOFS 250
155 for (i = 0; i < 3; i++) {
156 unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
157
158 eth0_pd.mac[2 * i] = tmp >> 8;
159 eth0_pd.mac[2 * i + 1] = tmp & 0xff;
160 }
161
162 res = platform_device_register(&eth0_device);
163 if (res)
164 return res;
165
166 /* Second HPC is missing? */
167 if (ip22_is_fullhouse() ||
168 get_dbe(pbdma, (unsigned int *)&hpc3c1->pbdma[1]))
169 return 0;
170
171 sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | SGIMC_GIOPAR_EXP164 |
172 SGIMC_GIOPAR_HPC264;
173 hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
174 /* interrupt/config register on Challenge S Mezz board */
175 hpc3c1->pbus_extregs[0][0] = 0x30;
176
177 eth1_pd.hpc = hpc3c1;
178 eth1_pd.irq = SGI_GIO_0_IRQ;
179#define EADDR_NVOFS 250
180 for (i = 0; i < 3; i++) {
181 unsigned short tmp = ip22_eeprom_read(&hpc3c1->eeprom,
182 EADDR_NVOFS / 2 + i);
183
184 eth1_pd.mac[2 * i] = tmp >> 8;
185 eth1_pd.mac[2 * i + 1] = tmp & 0xff;
186 }
187
188 return platform_device_register(&eth1_device);
189}
190
191device_initcall(sgiseeq_devinit);
192
193static int __init sgi_hal2_devinit(void)
194{
195 return IS_ERR(platform_device_register_simple("sgihal2", 0, NULL, 0));
196}
197
198device_initcall(sgi_hal2_devinit);
199
200static int __init sgi_button_devinit(void)
201{
202 if (ip22_is_fullhouse())
203 return 0; /* full house has no volume buttons */
204
205 return IS_ERR(platform_device_register_simple("sgibtns", -1, NULL, 0));
206}
207
208device_initcall(sgi_button_devinit);
209
210static int __init sgi_ds1286_devinit(void)
211{
212 struct resource res;
213
214 memset(&res, 0, sizeof(res));
215 res.start = HPC3_CHIP0_BASE + offsetof(struct hpc3_regs, rtcregs);
216 res.end = res.start + sizeof(hpc3c0->rtcregs) - 1;
217 res.flags = IORESOURCE_MEM;
218
219 return IS_ERR(platform_device_register_simple("rtc-ds1286", -1,
220 &res, 1));
221}
222
223device_initcall(sgi_ds1286_devinit);
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
new file mode 100644
index 000000000..c374f3cee
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-reset.c
@@ -0,0 +1,203 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1997, 1998, 2001, 03, 05, 06 by Ralf Baechle
7 */
8#include <linux/linkage.h>
9#include <linux/init.h>
10#include <linux/rtc/ds1286.h>
11#include <linux/interrupt.h>
12#include <linux/kernel.h>
13#include <linux/sched/signal.h>
14#include <linux/notifier.h>
15#include <linux/pm.h>
16#include <linux/timer.h>
17
18#include <asm/io.h>
19#include <asm/irq.h>
20#include <asm/reboot.h>
21#include <asm/sgialib.h>
22#include <asm/sgi/ioc.h>
23#include <asm/sgi/hpc3.h>
24#include <asm/sgi/mc.h>
25#include <asm/sgi/ip22.h>
26
27/*
28 * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds.
29 * I'm not sure if this feature is a good idea, for now it's here just to
30 * make the power button make behave just like under IRIX.
31 */
32#define POWERDOWN_TIMEOUT 120
33
34/*
35 * Blink frequency during reboot grace period and when panicked.
36 */
37#define POWERDOWN_FREQ (HZ / 4)
38#define PANIC_FREQ (HZ / 8)
39
40static struct timer_list power_timer, blink_timer, debounce_timer;
41static unsigned long blink_timer_timeout;
42
43#define MACHINE_PANICED 1
44#define MACHINE_SHUTTING_DOWN 2
45
46static int machine_state;
47
48static void __noreturn sgi_machine_power_off(void)
49{
50 unsigned int tmp;
51
52 local_irq_disable();
53
54 /* Disable watchdog */
55 tmp = hpc3c0->rtcregs[RTC_CMD] & 0xff;
56 hpc3c0->rtcregs[RTC_CMD] = tmp | RTC_WAM;
57 hpc3c0->rtcregs[RTC_WSEC] = 0;
58 hpc3c0->rtcregs[RTC_WHSEC] = 0;
59
60 while (1) {
61 sgioc->panel = ~SGIOC_PANEL_POWERON;
62 /* Good bye cruel world ... */
63
64 /* If we're still running, we probably got sent an alarm
65 interrupt. Read the flag to clear it. */
66 tmp = hpc3c0->rtcregs[RTC_HOURS_ALARM];
67 }
68}
69
70static void __noreturn sgi_machine_restart(char *command)
71{
72 if (machine_state & MACHINE_SHUTTING_DOWN)
73 sgi_machine_power_off();
74 sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
75 while (1);
76}
77
78static void __noreturn sgi_machine_halt(void)
79{
80 if (machine_state & MACHINE_SHUTTING_DOWN)
81 sgi_machine_power_off();
82 ArcEnterInteractiveMode();
83}
84
85static void power_timeout(struct timer_list *unused)
86{
87 sgi_machine_power_off();
88}
89
90static void blink_timeout(struct timer_list *unused)
91{
92 /* XXX fix this for fullhouse */
93 sgi_ioc_reset ^= (SGIOC_RESET_LC0OFF|SGIOC_RESET_LC1OFF);
94 sgioc->reset = sgi_ioc_reset;
95
96 mod_timer(&blink_timer, jiffies + blink_timer_timeout);
97}
98
99static void debounce(struct timer_list *unused)
100{
101 del_timer(&debounce_timer);
102 if (sgint->istat1 & SGINT_ISTAT1_PWR) {
103 /* Interrupt still being sent. */
104 debounce_timer.expires = jiffies + (HZ / 20); /* 0.05s */
105 add_timer(&debounce_timer);
106
107 sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR |
108 SGIOC_PANEL_VOLDNINTR | SGIOC_PANEL_VOLDNHOLD |
109 SGIOC_PANEL_VOLUPINTR | SGIOC_PANEL_VOLUPHOLD;
110
111 return;
112 }
113
114 if (machine_state & MACHINE_PANICED)
115 sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
116
117 enable_irq(SGI_PANEL_IRQ);
118}
119
120static inline void power_button(void)
121{
122 if (machine_state & MACHINE_PANICED)
123 return;
124
125 if ((machine_state & MACHINE_SHUTTING_DOWN) ||
126 kill_cad_pid(SIGINT, 1)) {
127 /* No init process or button pressed twice. */
128 sgi_machine_power_off();
129 }
130
131 machine_state |= MACHINE_SHUTTING_DOWN;
132 blink_timer_timeout = POWERDOWN_FREQ;
133 blink_timeout(&blink_timer);
134
135 timer_setup(&power_timer, power_timeout, 0);
136 power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
137 add_timer(&power_timer);
138}
139
140static irqreturn_t panel_int(int irq, void *dev_id)
141{
142 unsigned int buttons;
143
144 buttons = sgioc->panel;
145 sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR;
146
147 if (sgint->istat1 & SGINT_ISTAT1_PWR) {
148 /* Wait until interrupt goes away */
149 disable_irq_nosync(SGI_PANEL_IRQ);
150 timer_setup(&debounce_timer, debounce, 0);
151 debounce_timer.expires = jiffies + 5;
152 add_timer(&debounce_timer);
153 }
154
155 /* Power button was pressed
156 * ioc.ps page 22: "The Panel Register is called Power Control by Full
157 * House. Only lowest 2 bits are used. Guiness uses upper four bits
158 * for volume control". This is not true, all bits are pulled high
159 * on fullhouse */
160 if (!(buttons & SGIOC_PANEL_POWERINTR))
161 power_button();
162
163 return IRQ_HANDLED;
164}
165
166static int panic_event(struct notifier_block *this, unsigned long event,
167 void *ptr)
168{
169 if (machine_state & MACHINE_PANICED)
170 return NOTIFY_DONE;
171 machine_state |= MACHINE_PANICED;
172
173 blink_timer_timeout = PANIC_FREQ;
174 blink_timeout(&blink_timer);
175
176 return NOTIFY_DONE;
177}
178
179static struct notifier_block panic_block = {
180 .notifier_call = panic_event,
181};
182
183static int __init reboot_setup(void)
184{
185 int res;
186
187 _machine_restart = sgi_machine_restart;
188 _machine_halt = sgi_machine_halt;
189 pm_power_off = sgi_machine_power_off;
190
191 res = request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL);
192 if (res) {
193 printk(KERN_ERR "Allocation of front panel IRQ failed\n");
194 return res;
195 }
196
197 timer_setup(&blink_timer, blink_timeout, 0);
198 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
199
200 return 0;
201}
202
203subsys_initcall(reboot_setup);
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
new file mode 100644
index 000000000..b69daa024
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -0,0 +1,78 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip22-setup.c: SGI specific setup, including init of the feature struct.
4 *
5 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
6 * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
7 */
8#include <linux/init.h>
9#include <linux/kernel.h>
10#include <linux/kdev_t.h>
11#include <linux/types.h>
12#include <linux/console.h>
13#include <linux/sched.h>
14#include <linux/tty.h>
15
16#include <asm/addrspace.h>
17#include <asm/bcache.h>
18#include <asm/bootinfo.h>
19#include <asm/irq.h>
20#include <asm/reboot.h>
21#include <asm/time.h>
22#include <asm/io.h>
23#include <asm/traps.h>
24#include <asm/sgialib.h>
25#include <asm/sgi/mc.h>
26#include <asm/sgi/hpc3.h>
27#include <asm/sgi/ip22.h>
28
29extern void ip22_be_init(void) __init;
30
31void __init plat_mem_setup(void)
32{
33 char *ctype;
34 char *cserial;
35
36 board_be_init = ip22_be_init;
37
38 /* Init the INDY HPC I/O controller. Need to call this before
39 * fucking with the memory controller because it needs to know the
40 * boardID and whether this is a Guiness or a FullHouse machine.
41 */
42 sgihpc_init();
43
44 /* Init INDY memory controller. */
45 sgimc_init();
46
47#ifdef CONFIG_BOARD_SCACHE
48 /* Now enable boardcaches, if any. */
49 indy_sc_init();
50#endif
51
52 /* Set EISA IO port base for Indigo2
53 * ioremap cannot fail */
54 set_io_port_base((unsigned long)ioremap(0x00080000,
55 0x1fffffff - 0x00080000));
56 /* ARCS console environment variable is set to "g?" for
57 * graphics console, it is set to "d" for the first serial
58 * line and "d2" for the second serial line.
59 *
60 * Need to check if the case is 'g' but no keyboard:
61 * (ConsoleIn/Out = serial)
62 */
63 ctype = ArcGetEnvironmentVariable("console");
64 cserial = ArcGetEnvironmentVariable("ConsoleOut");
65
66 if ((ctype && *ctype == 'd') || (cserial && *cserial == 's')) {
67 static char options[8] __initdata;
68 char *baud = ArcGetEnvironmentVariable("dbaud");
69 if (baud)
70 strcpy(options, baud);
71 add_preferred_console("ttyS", *(ctype + 1) == '2' ? 1 : 0,
72 baud ? options : NULL);
73 } else if (!ctype || *ctype != 'g') {
74 /* Use ARC if we don't want serial ('d') or graphics ('g'). */
75 prom_flags |= PROM_FLAG_USE_AS_CONSOLE;
76 add_preferred_console("arc", 0, NULL);
77 }
78}
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
new file mode 100644
index 000000000..045aa89f2
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -0,0 +1,131 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Time operations for IP22 machines. Original code may come from
7 * Ralf Baechle or David S. Miller (sorry guys, i'm really not sure)
8 *
9 * Copyright (C) 2001 by Ladislav Michl
10 * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org)
11 */
12#include <linux/bcd.h>
13#include <linux/i8253.h>
14#include <linux/init.h>
15#include <linux/irq.h>
16#include <linux/kernel.h>
17#include <linux/interrupt.h>
18#include <linux/kernel_stat.h>
19#include <linux/time.h>
20#include <linux/ftrace.h>
21
22#include <asm/cpu.h>
23#include <asm/mipsregs.h>
24#include <asm/io.h>
25#include <asm/irq.h>
26#include <asm/time.h>
27#include <asm/sgialib.h>
28#include <asm/sgi/ioc.h>
29#include <asm/sgi/hpc3.h>
30#include <asm/sgi/ip22.h>
31
32static unsigned long dosample(void)
33{
34 u32 ct0, ct1;
35 u8 msb;
36
37 /* Start the counter. */
38 sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
39 SGINT_TCWORD_MRGEN);
40 sgint->tcnt2 = SGINT_TCSAMP_COUNTER & 0xff;
41 sgint->tcnt2 = SGINT_TCSAMP_COUNTER >> 8;
42
43 /* Get initial counter invariant */
44 ct0 = read_c0_count();
45
46 /* Latch and spin until top byte of counter2 is zero */
47 do {
48 writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword);
49 (void) readb(&sgint->tcnt2);
50 msb = readb(&sgint->tcnt2);
51 ct1 = read_c0_count();
52 } while (msb);
53
54 /* Stop the counter. */
55 writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST,
56 &sgint->tcword);
57 /*
58 * Return the difference, this is how far the r4k counter increments
59 * for every 1/HZ seconds. We round off the nearest 1 MHz of master
60 * clock (= 1000000 / HZ / 2).
61 */
62
63 return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
64}
65
66/*
67 * Here we need to calibrate the cycle counter to at least be close.
68 */
69__init void plat_time_init(void)
70{
71 unsigned long r4k_ticks[3];
72 unsigned long r4k_tick;
73
74 /*
75 * Figure out the r4k offset, the algorithm is very simple and works in
76 * _all_ cases as long as the 8254 counter register itself works ok (as
77 * an interrupt driving timer it does not because of bug, this is why
78 * we are using the onchip r4k counter/compare register to serve this
79 * purpose, but for r4k_offset calculation it will work ok for us).
80 * There are other very complicated ways of performing this calculation
81 * but this one works just fine so I am not going to futz around. ;-)
82 */
83 printk(KERN_INFO "Calibrating system timer... ");
84 dosample(); /* Prime cache. */
85 dosample(); /* Prime cache. */
86 /* Zero is NOT an option. */
87 do {
88 r4k_ticks[0] = dosample();
89 } while (!r4k_ticks[0]);
90 do {
91 r4k_ticks[1] = dosample();
92 } while (!r4k_ticks[1]);
93
94 if (r4k_ticks[0] != r4k_ticks[1]) {
95 printk("warning: timer counts differ, retrying... ");
96 r4k_ticks[2] = dosample();
97 if (r4k_ticks[2] == r4k_ticks[0]
98 || r4k_ticks[2] == r4k_ticks[1])
99 r4k_tick = r4k_ticks[2];
100 else {
101 printk("disagreement, using average... ");
102 r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
103 + r4k_ticks[2]) / 3;
104 }
105 } else
106 r4k_tick = r4k_ticks[0];
107
108 printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
109 (int) (r4k_tick / (500000 / HZ)),
110 (int) (r4k_tick % (500000 / HZ)));
111
112 mips_hpt_frequency = r4k_tick * HZ;
113
114 if (ip22_is_fullhouse())
115 setup_pit_timer();
116}
117
118/* Generic SGI handler for (spurious) 8254 interrupts */
119void __irq_entry indy_8254timer_irq(void)
120{
121 int irq = SGI_8254_0_IRQ;
122 ULONG cnt;
123 char c;
124
125 irq_enter();
126 kstat_incr_irq_this_cpu(irq);
127 printk(KERN_ALERT "Oops, got 8254 interrupt.\n");
128 ArcRead(0, &c, 1, &cnt);
129 ArcEnterInteractiveMode();
130 irq_exit();
131}
diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c
new file mode 100644
index 000000000..c61362d9e
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip28-berr.c
@@ -0,0 +1,488 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ip28-berr.c: Bus error handling.
4 *
5 * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org)
6 * Copyright (C) 2005 Peter Fuerst (pf@net.alphadv.de) - IP28
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/mm.h>
12#include <linux/sched.h>
13#include <linux/sched/debug.h>
14#include <linux/sched/signal.h>
15#include <linux/seq_file.h>
16
17#include <asm/addrspace.h>
18#include <asm/traps.h>
19#include <asm/branch.h>
20#include <asm/irq_regs.h>
21#include <asm/sgi/mc.h>
22#include <asm/sgi/hpc3.h>
23#include <asm/sgi/ioc.h>
24#include <asm/sgi/ip22.h>
25#include <asm/r4kcache.h>
26#include <linux/uaccess.h>
27#include <asm/bootinfo.h>
28
29static unsigned int count_be_is_fixup;
30static unsigned int count_be_handler;
31static unsigned int count_be_interrupt;
32static int debug_be_interrupt;
33
34static unsigned int cpu_err_stat; /* Status reg for CPU */
35static unsigned int gio_err_stat; /* Status reg for GIO */
36static unsigned int cpu_err_addr; /* Error address reg for CPU */
37static unsigned int gio_err_addr; /* Error address reg for GIO */
38static unsigned int extio_stat;
39static unsigned int hpc3_berr_stat; /* Bus error interrupt status */
40
41struct hpc3_stat {
42 unsigned long addr;
43 unsigned int ctrl;
44 unsigned int cbp;
45 unsigned int ndptr;
46};
47
48static struct {
49 struct hpc3_stat pbdma[8];
50 struct hpc3_stat scsi[2];
51 struct hpc3_stat ethrx, ethtx;
52} hpc3;
53
54static struct {
55 unsigned long err_addr;
56 struct {
57 u32 lo;
58 u32 hi;
59 } tags[1][2], tagd[4][2], tagi[4][2]; /* Way 0/1 */
60} cache_tags;
61
62static inline void save_cache_tags(unsigned busaddr)
63{
64 unsigned long addr = CAC_BASE | busaddr;
65 int i;
66 cache_tags.err_addr = addr;
67
68 /*
69 * Starting with a bus-address, save secondary cache (indexed by
70 * PA[23..18:7..6]) tags first.
71 */
72 addr &= ~1L;
73#define tag cache_tags.tags[0]
74 cache_op(Index_Load_Tag_S, addr);
75 tag[0].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */
76 tag[0].hi = read_c0_taghi(); /* PA[39:36] */
77 cache_op(Index_Load_Tag_S, addr | 1L);
78 tag[1].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */
79 tag[1].hi = read_c0_taghi(); /* PA[39:36] */
80#undef tag
81
82 /*
83 * Save all primary data cache (indexed by VA[13:5]) tags which
84 * might fit to this bus-address, knowing that VA[11:0] == PA[11:0].
85 * Saving all tags and evaluating them later is easier and safer
86 * than relying on VA[13:12] from the secondary cache tags to pick
87 * matching primary tags here already.
88 */
89 addr &= (0xffL << 56) | ((1 << 12) - 1);
90#define tag cache_tags.tagd[i]
91 for (i = 0; i < 4; ++i, addr += (1 << 12)) {
92 cache_op(Index_Load_Tag_D, addr);
93 tag[0].lo = read_c0_taglo(); /* PA[35:12] */
94 tag[0].hi = read_c0_taghi(); /* PA[39:36] */
95 cache_op(Index_Load_Tag_D, addr | 1L);
96 tag[1].lo = read_c0_taglo(); /* PA[35:12] */
97 tag[1].hi = read_c0_taghi(); /* PA[39:36] */
98 }
99#undef tag
100
101 /*
102 * Save primary instruction cache (indexed by VA[13:6]) tags
103 * the same way.
104 */
105 addr &= (0xffL << 56) | ((1 << 12) - 1);
106#define tag cache_tags.tagi[i]
107 for (i = 0; i < 4; ++i, addr += (1 << 12)) {
108 cache_op(Index_Load_Tag_I, addr);
109 tag[0].lo = read_c0_taglo(); /* PA[35:12] */
110 tag[0].hi = read_c0_taghi(); /* PA[39:36] */
111 cache_op(Index_Load_Tag_I, addr | 1L);
112 tag[1].lo = read_c0_taglo(); /* PA[35:12] */
113 tag[1].hi = read_c0_taghi(); /* PA[39:36] */
114 }
115#undef tag
116}
117
118#define GIO_ERRMASK 0xff00
119#define CPU_ERRMASK 0x3f00
120
121static void save_and_clear_buserr(void)
122{
123 int i;
124
125 /* save status registers */
126 cpu_err_addr = sgimc->cerr;
127 cpu_err_stat = sgimc->cstat;
128 gio_err_addr = sgimc->gerr;
129 gio_err_stat = sgimc->gstat;
130 extio_stat = sgioc->extio;
131 hpc3_berr_stat = hpc3c0->bestat;
132
133 hpc3.scsi[0].addr = (unsigned long)&hpc3c0->scsi_chan0;
134 hpc3.scsi[0].ctrl = hpc3c0->scsi_chan0.ctrl; /* HPC3_SCTRL_ACTIVE ? */
135 hpc3.scsi[0].cbp = hpc3c0->scsi_chan0.cbptr;
136 hpc3.scsi[0].ndptr = hpc3c0->scsi_chan0.ndptr;
137
138 hpc3.scsi[1].addr = (unsigned long)&hpc3c0->scsi_chan1;
139 hpc3.scsi[1].ctrl = hpc3c0->scsi_chan1.ctrl; /* HPC3_SCTRL_ACTIVE ? */
140 hpc3.scsi[1].cbp = hpc3c0->scsi_chan1.cbptr;
141 hpc3.scsi[1].ndptr = hpc3c0->scsi_chan1.ndptr;
142
143 hpc3.ethrx.addr = (unsigned long)&hpc3c0->ethregs.rx_cbptr;
144 hpc3.ethrx.ctrl = hpc3c0->ethregs.rx_ctrl; /* HPC3_ERXCTRL_ACTIVE ? */
145 hpc3.ethrx.cbp = hpc3c0->ethregs.rx_cbptr;
146 hpc3.ethrx.ndptr = hpc3c0->ethregs.rx_ndptr;
147
148 hpc3.ethtx.addr = (unsigned long)&hpc3c0->ethregs.tx_cbptr;
149 hpc3.ethtx.ctrl = hpc3c0->ethregs.tx_ctrl; /* HPC3_ETXCTRL_ACTIVE ? */
150 hpc3.ethtx.cbp = hpc3c0->ethregs.tx_cbptr;
151 hpc3.ethtx.ndptr = hpc3c0->ethregs.tx_ndptr;
152
153 for (i = 0; i < 8; ++i) {
154 /* HPC3_PDMACTRL_ISACT ? */
155 hpc3.pbdma[i].addr = (unsigned long)&hpc3c0->pbdma[i];
156 hpc3.pbdma[i].ctrl = hpc3c0->pbdma[i].pbdma_ctrl;
157 hpc3.pbdma[i].cbp = hpc3c0->pbdma[i].pbdma_bptr;
158 hpc3.pbdma[i].ndptr = hpc3c0->pbdma[i].pbdma_dptr;
159 }
160 i = 0;
161 if (gio_err_stat & CPU_ERRMASK)
162 i = gio_err_addr;
163 if (cpu_err_stat & CPU_ERRMASK)
164 i = cpu_err_addr;
165 save_cache_tags(i);
166
167 sgimc->cstat = sgimc->gstat = 0;
168}
169
170static void print_cache_tags(void)
171{
172 u32 scb, scw;
173 int i;
174
175 printk(KERN_ERR "Cache tags @ %08x:\n", (unsigned)cache_tags.err_addr);
176
177 /* PA[31:12] shifted to PTag0 (PA[35:12]) format */
178 scw = (cache_tags.err_addr >> 4) & 0x0fffff00;
179
180 scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 5) - 1);
181 for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */
182 if ((cache_tags.tagd[i][0].lo & 0x0fffff00) != scw &&
183 (cache_tags.tagd[i][1].lo & 0x0fffff00) != scw)
184 continue;
185 printk(KERN_ERR
186 "D: 0: %08x %08x, 1: %08x %08x (VA[13:5] %04x)\n",
187 cache_tags.tagd[i][0].hi, cache_tags.tagd[i][0].lo,
188 cache_tags.tagd[i][1].hi, cache_tags.tagd[i][1].lo,
189 scb | (1 << 12)*i);
190 }
191 scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 6) - 1);
192 for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */
193 if ((cache_tags.tagi[i][0].lo & 0x0fffff00) != scw &&
194 (cache_tags.tagi[i][1].lo & 0x0fffff00) != scw)
195 continue;
196 printk(KERN_ERR
197 "I: 0: %08x %08x, 1: %08x %08x (VA[13:6] %04x)\n",
198 cache_tags.tagi[i][0].hi, cache_tags.tagi[i][0].lo,
199 cache_tags.tagi[i][1].hi, cache_tags.tagi[i][1].lo,
200 scb | (1 << 12)*i);
201 }
202 i = read_c0_config();
203 scb = i & (1 << 13) ? 7:6; /* scblksize = 2^[7..6] */
204 scw = ((i >> 16) & 7) + 19 - 1; /* scwaysize = 2^[24..19] / 2 */
205
206 i = ((1 << scw) - 1) & ~((1 << scb) - 1);
207 printk(KERN_ERR "S: 0: %08x %08x, 1: %08x %08x (PA[%u:%u] %05x)\n",
208 cache_tags.tags[0][0].hi, cache_tags.tags[0][0].lo,
209 cache_tags.tags[0][1].hi, cache_tags.tags[0][1].lo,
210 scw-1, scb, i & (unsigned)cache_tags.err_addr);
211}
212
213static inline const char *cause_excode_text(int cause)
214{
215 static const char *txt[32] =
216 { "Interrupt",
217 "TLB modification",
218 "TLB (load or instruction fetch)",
219 "TLB (store)",
220 "Address error (load or instruction fetch)",
221 "Address error (store)",
222 "Bus error (instruction fetch)",
223 "Bus error (data: load or store)",
224 "Syscall",
225 "Breakpoint",
226 "Reserved instruction",
227 "Coprocessor unusable",
228 "Arithmetic Overflow",
229 "Trap",
230 "14",
231 "Floating-Point",
232 "16", "17", "18", "19", "20", "21", "22",
233 "Watch Hi/Lo",
234 "24", "25", "26", "27", "28", "29", "30", "31",
235 };
236 return txt[(cause & 0x7c) >> 2];
237}
238
239static void print_buserr(const struct pt_regs *regs)
240{
241 const int field = 2 * sizeof(unsigned long);
242 int error = 0;
243
244 if (extio_stat & EXTIO_MC_BUSERR) {
245 printk(KERN_ERR "MC Bus Error\n");
246 error |= 1;
247 }
248 if (extio_stat & EXTIO_HPC3_BUSERR) {
249 printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n",
250 hpc3_berr_stat,
251 (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >>
252 HPC3_BESTAT_PIDSHIFT,
253 (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA",
254 hpc3_berr_stat & HPC3_BESTAT_BLMASK);
255 error |= 2;
256 }
257 if (extio_stat & EXTIO_EISA_BUSERR) {
258 printk(KERN_ERR "EISA Bus Error\n");
259 error |= 4;
260 }
261 if (cpu_err_stat & CPU_ERRMASK) {
262 printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n",
263 cpu_err_stat,
264 cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "",
265 cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "",
266 cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "",
267 cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "",
268 cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "",
269 cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "",
270 cpu_err_addr);
271 error |= 8;
272 }
273 if (gio_err_stat & GIO_ERRMASK) {
274 printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n",
275 gio_err_stat,
276 gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "",
277 gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "",
278 gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "",
279 gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "",
280 gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "",
281 gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "",
282 gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "",
283 gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "",
284 gio_err_addr);
285 error |= 16;
286 }
287 if (!error)
288 printk(KERN_ERR "MC: Hmm, didn't find any error condition.\n");
289 else {
290 printk(KERN_ERR "CP0: config %08x, "
291 "MC: cpuctrl0/1: %08x/%05x, giopar: %04x\n"
292 "MC: cpu/gio_memacc: %08x/%05x, memcfg0/1: %08x/%08x\n",
293 read_c0_config(),
294 sgimc->cpuctrl0, sgimc->cpuctrl0, sgimc->giopar,
295 sgimc->cmacc, sgimc->gmacc,
296 sgimc->mconfig0, sgimc->mconfig1);
297 print_cache_tags();
298 }
299 printk(KERN_ALERT "%s, epc == %0*lx, ra == %0*lx\n",
300 cause_excode_text(regs->cp0_cause),
301 field, regs->cp0_epc, field, regs->regs[31]);
302}
303
304static int check_microtlb(u32 hi, u32 lo, unsigned long vaddr)
305{
306 /* This is likely rather similar to correct code ;-) */
307
308 vaddr &= 0x7fffffff; /* Doc. states that top bit is ignored */
309
310 /* If tlb-entry is valid and VPN-high (bits [30:21] ?) matches... */
311 if ((lo & 2) && (vaddr >> 21) == ((hi<<1) >> 22)) {
312 u32 ctl = sgimc->dma_ctrl;
313 if (ctl & 1) {
314 unsigned int pgsz = (ctl & 2) ? 14:12; /* 16k:4k */
315 /* PTEIndex is VPN-low (bits [22:14]/[20:12] ?) */
316 unsigned long pte = (lo >> 6) << 12; /* PTEBase */
317 pte += 8*((vaddr >> pgsz) & 0x1ff);
318 if (page_is_ram(PFN_DOWN(pte))) {
319 /*
320 * Note: Since DMA hardware does look up
321 * translation on its own, this PTE *must*
322 * match the TLB/EntryLo-register format !
323 */
324 unsigned long a = *(unsigned long *)
325 PHYS_TO_XKSEG_UNCACHED(pte);
326 a = (a & 0x3f) << 6; /* PFN */
327 a += vaddr & ((1 << pgsz) - 1);
328 return cpu_err_addr == a;
329 }
330 }
331 }
332 return 0;
333}
334
335static int check_vdma_memaddr(void)
336{
337 if (cpu_err_stat & CPU_ERRMASK) {
338 u32 a = sgimc->maddronly;
339
340 if (!(sgimc->dma_ctrl & 0x100)) /* Xlate-bit clear ? */
341 return cpu_err_addr == a;
342
343 if (check_microtlb(sgimc->dtlb_hi0, sgimc->dtlb_lo0, a) ||
344 check_microtlb(sgimc->dtlb_hi1, sgimc->dtlb_lo1, a) ||
345 check_microtlb(sgimc->dtlb_hi2, sgimc->dtlb_lo2, a) ||
346 check_microtlb(sgimc->dtlb_hi3, sgimc->dtlb_lo3, a))
347 return 1;
348 }
349 return 0;
350}
351
352static int check_vdma_gioaddr(void)
353{
354 if (gio_err_stat & GIO_ERRMASK) {
355 u32 a = sgimc->gio_dma_trans;
356 a = (sgimc->gmaddronly & ~a) | (sgimc->gio_dma_sbits & a);
357 return gio_err_addr == a;
358 }
359 return 0;
360}
361
362/*
363 * MC sends an interrupt whenever bus or parity errors occur. In addition,
364 * if the error happened during a CPU read, it also asserts the bus error
365 * pin on the R4K. Code in bus error handler save the MC bus error registers
366 * and then clear the interrupt when this happens.
367 */
368
369static int ip28_be_interrupt(const struct pt_regs *regs)
370{
371 int i;
372
373 save_and_clear_buserr();
374 /*
375 * Try to find out, whether we got here by a mispredicted speculative
376 * load/store operation. If so, it's not fatal, we can go on.
377 */
378 /* Any cause other than "Interrupt" (ExcCode 0) is fatal. */
379 if (regs->cp0_cause & CAUSEF_EXCCODE)
380 goto mips_be_fatal;
381
382 /* Any cause other than "Bus error interrupt" (IP6) is weird. */
383 if ((regs->cp0_cause & CAUSEF_IP6) != CAUSEF_IP6)
384 goto mips_be_fatal;
385
386 if (extio_stat & (EXTIO_HPC3_BUSERR | EXTIO_EISA_BUSERR))
387 goto mips_be_fatal;
388
389 /* Any state other than "Memory bus error" is fatal. */
390 if (cpu_err_stat & CPU_ERRMASK & ~SGIMC_CSTAT_ADDR)
391 goto mips_be_fatal;
392
393 /* GIO errors other than timeouts are fatal */
394 if (gio_err_stat & GIO_ERRMASK & ~SGIMC_GSTAT_TIME)
395 goto mips_be_fatal;
396
397 /*
398 * Now we have an asynchronous bus error, speculatively or DMA caused.
399 * Need to search all DMA descriptors for the error address.
400 */
401 for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) {
402 struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
403 if ((cpu_err_stat & CPU_ERRMASK) &&
404 (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp))
405 break;
406 if ((gio_err_stat & GIO_ERRMASK) &&
407 (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp))
408 break;
409 }
410 if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) {
411 struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i;
412 printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:"
413 " ctl %08x, ndp %08x, cbp %08x\n",
414 CPHYSADDR(hp->addr), hp->ctrl, hp->ndptr, hp->cbp);
415 goto mips_be_fatal;
416 }
417 /* Check MC's virtual DMA stuff. */
418 if (check_vdma_memaddr()) {
419 printk(KERN_ERR "at GIO DMA: mem address 0x%08x.\n",
420 sgimc->maddronly);
421 goto mips_be_fatal;
422 }
423 if (check_vdma_gioaddr()) {
424 printk(KERN_ERR "at GIO DMA: gio address 0x%08x.\n",
425 sgimc->gmaddronly);
426 goto mips_be_fatal;
427 }
428 /* A speculative bus error... */
429 if (debug_be_interrupt) {
430 print_buserr(regs);
431 printk(KERN_ERR "discarded!\n");
432 }
433 return MIPS_BE_DISCARD;
434
435mips_be_fatal:
436 print_buserr(regs);
437 return MIPS_BE_FATAL;
438}
439
440void ip22_be_interrupt(int irq)
441{
442 struct pt_regs *regs = get_irq_regs();
443
444 count_be_interrupt++;
445
446 if (ip28_be_interrupt(regs) != MIPS_BE_DISCARD) {
447 /* Assume it would be too dangerous to continue ... */
448 die_if_kernel("Oops", regs);
449 force_sig(SIGBUS);
450 } else if (debug_be_interrupt)
451 show_regs(regs);
452}
453
454static int ip28_be_handler(struct pt_regs *regs, int is_fixup)
455{
456 /*
457 * We arrive here only in the unusual case of do_be() invocation,
458 * i.e. by a bus error exception without a bus error interrupt.
459 */
460 if (is_fixup) {
461 count_be_is_fixup++;
462 save_and_clear_buserr();
463 return MIPS_BE_FIXUP;
464 }
465 count_be_handler++;
466 return ip28_be_interrupt(regs);
467}
468
469void __init ip22_be_init(void)
470{
471 board_be_handler = ip28_be_handler;
472}
473
474int ip28_show_be_info(struct seq_file *m)
475{
476 seq_printf(m, "IP28 be fixups\t\t: %u\n", count_be_is_fixup);
477 seq_printf(m, "IP28 be interrupts\t: %u\n", count_be_interrupt);
478 seq_printf(m, "IP28 be handler\t\t: %u\n", count_be_handler);
479
480 return 0;
481}
482
483static int __init debug_be_setup(char *str)
484{
485 debug_be_interrupt++;
486 return 1;
487}
488__setup("ip28_debug_be", debug_be_setup);