diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/dec | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/dec')
-rw-r--r-- | arch/mips/dec/Makefile | 10 | ||||
-rw-r--r-- | arch/mips/dec/Platform | 7 | ||||
-rw-r--r-- | arch/mips/dec/ecc-berr.c | 274 | ||||
-rw-r--r-- | arch/mips/dec/int-handler.S | 311 | ||||
-rw-r--r-- | arch/mips/dec/ioasic-irq.c | 112 | ||||
-rw-r--r-- | arch/mips/dec/kn01-berr.c | 196 | ||||
-rw-r--r-- | arch/mips/dec/kn02-irq.c | 75 | ||||
-rw-r--r-- | arch/mips/dec/kn02xa-berr.c | 135 | ||||
-rw-r--r-- | arch/mips/dec/platform.c | 40 | ||||
-rw-r--r-- | arch/mips/dec/prom/Makefile | 9 | ||||
-rw-r--r-- | arch/mips/dec/prom/cmdline.c | 40 | ||||
-rw-r--r-- | arch/mips/dec/prom/console.c | 41 | ||||
-rw-r--r-- | arch/mips/dec/prom/dectypes.h | 15 | ||||
-rw-r--r-- | arch/mips/dec/prom/identify.c | 187 | ||||
-rw-r--r-- | arch/mips/dec/prom/init.c | 137 | ||||
-rw-r--r-- | arch/mips/dec/prom/locore.S | 30 | ||||
-rw-r--r-- | arch/mips/dec/prom/memory.c | 117 | ||||
-rw-r--r-- | arch/mips/dec/reset.c | 41 | ||||
-rw-r--r-- | arch/mips/dec/setup.c | 784 | ||||
-rw-r--r-- | arch/mips/dec/tc.c | 95 | ||||
-rw-r--r-- | arch/mips/dec/time.c | 172 | ||||
-rw-r--r-- | arch/mips/dec/wbflush.c | 92 |
22 files changed, 2920 insertions, 0 deletions
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile new file mode 100644 index 000000000..c9f62f1da --- /dev/null +++ b/arch/mips/dec/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # | ||
3 | # Makefile for the DECstation family specific parts of the kernel | ||
4 | # | ||
5 | |||
6 | obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \ | ||
7 | kn02-irq.o kn02xa-berr.o platform.o reset.o setup.o time.o | ||
8 | |||
9 | obj-$(CONFIG_TC) += tc.o | ||
10 | obj-$(CONFIG_CPU_HAS_WB) += wbflush.o | ||
diff --git a/arch/mips/dec/Platform b/arch/mips/dec/Platform new file mode 100644 index 000000000..c82391e83 --- /dev/null +++ b/arch/mips/dec/Platform | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # DECstation family | ||
3 | # | ||
4 | cflags-$(CONFIG_MACH_DECSTATION) += \ | ||
5 | -I$(srctree)/arch/mips/include/asm/mach-dec | ||
6 | libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/ | ||
7 | load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000 | ||
diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c new file mode 100644 index 000000000..1eb356fdd --- /dev/null +++ b/arch/mips/dec/ecc-berr.c | |||
@@ -0,0 +1,274 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Bus error event handling code for systems equipped with ECC | ||
4 | * handling logic, i.e. DECstation/DECsystem 5000/200 (KN02), | ||
5 | * 5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03), | ||
6 | * 5900/260 (KN05) systems. | ||
7 | * | ||
8 | * Copyright (c) 2003, 2005 Maciej W. Rozycki | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/types.h> | ||
16 | |||
17 | #include <asm/addrspace.h> | ||
18 | #include <asm/bootinfo.h> | ||
19 | #include <asm/cpu.h> | ||
20 | #include <asm/cpu-type.h> | ||
21 | #include <asm/irq_regs.h> | ||
22 | #include <asm/processor.h> | ||
23 | #include <asm/ptrace.h> | ||
24 | #include <asm/traps.h> | ||
25 | |||
26 | #include <asm/dec/ecc.h> | ||
27 | #include <asm/dec/kn02.h> | ||
28 | #include <asm/dec/kn03.h> | ||
29 | #include <asm/dec/kn05.h> | ||
30 | |||
31 | static volatile u32 *kn0x_erraddr; | ||
32 | static volatile u32 *kn0x_chksyn; | ||
33 | |||
34 | static inline void dec_ecc_be_ack(void) | ||
35 | { | ||
36 | *kn0x_erraddr = 0; /* any write clears the IRQ */ | ||
37 | iob(); | ||
38 | } | ||
39 | |||
40 | static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) | ||
41 | { | ||
42 | static const char excstr[] = "exception"; | ||
43 | static const char intstr[] = "interrupt"; | ||
44 | static const char cpustr[] = "CPU"; | ||
45 | static const char dmastr[] = "DMA"; | ||
46 | static const char readstr[] = "read"; | ||
47 | static const char mreadstr[] = "memory read"; | ||
48 | static const char writestr[] = "write"; | ||
49 | static const char mwritstr[] = "partial memory write"; | ||
50 | static const char timestr[] = "timeout"; | ||
51 | static const char overstr[] = "overrun"; | ||
52 | static const char eccstr[] = "ECC error"; | ||
53 | |||
54 | const char *kind, *agent, *cycle, *event; | ||
55 | const char *status = "", *xbit = "", *fmt = ""; | ||
56 | unsigned long address; | ||
57 | u16 syn = 0, sngl; | ||
58 | |||
59 | int i = 0; | ||
60 | |||
61 | u32 erraddr = *kn0x_erraddr; | ||
62 | u32 chksyn = *kn0x_chksyn; | ||
63 | int action = MIPS_BE_FATAL; | ||
64 | |||
65 | /* For non-ECC ack ASAP, so that any subsequent errors get caught. */ | ||
66 | if ((erraddr & (KN0X_EAR_VALID | KN0X_EAR_ECCERR)) == KN0X_EAR_VALID) | ||
67 | dec_ecc_be_ack(); | ||
68 | |||
69 | kind = invoker ? intstr : excstr; | ||
70 | |||
71 | if (!(erraddr & KN0X_EAR_VALID)) { | ||
72 | /* No idea what happened. */ | ||
73 | printk(KERN_ALERT "Unidentified bus error %s\n", kind); | ||
74 | return action; | ||
75 | } | ||
76 | |||
77 | agent = (erraddr & KN0X_EAR_CPU) ? cpustr : dmastr; | ||
78 | |||
79 | if (erraddr & KN0X_EAR_ECCERR) { | ||
80 | /* An ECC error on a CPU or DMA transaction. */ | ||
81 | cycle = (erraddr & KN0X_EAR_WRITE) ? mwritstr : mreadstr; | ||
82 | event = eccstr; | ||
83 | } else { | ||
84 | /* A CPU timeout or a DMA overrun. */ | ||
85 | cycle = (erraddr & KN0X_EAR_WRITE) ? writestr : readstr; | ||
86 | event = (erraddr & KN0X_EAR_CPU) ? timestr : overstr; | ||
87 | } | ||
88 | |||
89 | address = erraddr & KN0X_EAR_ADDRESS; | ||
90 | /* For ECC errors on reads adjust for MT pipelining. */ | ||
91 | if ((erraddr & (KN0X_EAR_WRITE | KN0X_EAR_ECCERR)) == KN0X_EAR_ECCERR) | ||
92 | address = (address & ~0xfffLL) | ((address - 5) & 0xfffLL); | ||
93 | address <<= 2; | ||
94 | |||
95 | /* Only CPU errors are fixable. */ | ||
96 | if (erraddr & KN0X_EAR_CPU && is_fixup) | ||
97 | action = MIPS_BE_FIXUP; | ||
98 | |||
99 | if (erraddr & KN0X_EAR_ECCERR) { | ||
100 | static const u8 data_sbit[32] = { | ||
101 | 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, | ||
102 | 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34, | ||
103 | 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, | ||
104 | 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75, | ||
105 | }; | ||
106 | static const u8 data_mbit[25] = { | ||
107 | 0x07, 0x0d, 0x1f, | ||
108 | 0x2f, 0x32, 0x37, 0x38, 0x3b, 0x3d, 0x3e, | ||
109 | 0x43, 0x45, 0x46, 0x49, 0x4c, 0x51, 0x5e, | ||
110 | 0x61, 0x6e, 0x73, 0x76, 0x79, 0x7a, 0x7c, 0x7f, | ||
111 | }; | ||
112 | static const char sbestr[] = "corrected single"; | ||
113 | static const char dbestr[] = "uncorrectable double"; | ||
114 | static const char mbestr[] = "uncorrectable multiple"; | ||
115 | |||
116 | if (!(address & 0x4)) | ||
117 | syn = chksyn; /* Low bank. */ | ||
118 | else | ||
119 | syn = chksyn >> 16; /* High bank. */ | ||
120 | |||
121 | if (!(syn & KN0X_ESR_VLDLO)) { | ||
122 | /* Ack now, no rewrite will happen. */ | ||
123 | dec_ecc_be_ack(); | ||
124 | |||
125 | fmt = KERN_ALERT "%s" "invalid\n"; | ||
126 | } else { | ||
127 | sngl = syn & KN0X_ESR_SNGLO; | ||
128 | syn &= KN0X_ESR_SYNLO; | ||
129 | |||
130 | /* | ||
131 | * Multibit errors may be tagged incorrectly; | ||
132 | * check the syndrome explicitly. | ||
133 | */ | ||
134 | for (i = 0; i < 25; i++) | ||
135 | if (syn == data_mbit[i]) | ||
136 | break; | ||
137 | |||
138 | if (i < 25) { | ||
139 | status = mbestr; | ||
140 | } else if (!sngl) { | ||
141 | status = dbestr; | ||
142 | } else { | ||
143 | volatile u32 *ptr = | ||
144 | (void *)CKSEG1ADDR(address); | ||
145 | |||
146 | *ptr = *ptr; /* Rewrite. */ | ||
147 | iob(); | ||
148 | |||
149 | status = sbestr; | ||
150 | action = MIPS_BE_DISCARD; | ||
151 | } | ||
152 | |||
153 | /* Ack now, now we've rewritten (or not). */ | ||
154 | dec_ecc_be_ack(); | ||
155 | |||
156 | if (syn && syn == (syn & -syn)) { | ||
157 | if (syn == 0x01) { | ||
158 | fmt = KERN_ALERT "%s" | ||
159 | "%#04x -- %s bit error " | ||
160 | "at check bit C%s\n"; | ||
161 | xbit = "X"; | ||
162 | } else { | ||
163 | fmt = KERN_ALERT "%s" | ||
164 | "%#04x -- %s bit error " | ||
165 | "at check bit C%s%u\n"; | ||
166 | } | ||
167 | i = syn >> 2; | ||
168 | } else { | ||
169 | for (i = 0; i < 32; i++) | ||
170 | if (syn == data_sbit[i]) | ||
171 | break; | ||
172 | if (i < 32) | ||
173 | fmt = KERN_ALERT "%s" | ||
174 | "%#04x -- %s bit error " | ||
175 | "at data bit D%s%u\n"; | ||
176 | else | ||
177 | fmt = KERN_ALERT "%s" | ||
178 | "%#04x -- %s bit error\n"; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | if (action != MIPS_BE_FIXUP) | ||
184 | printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", | ||
185 | kind, agent, cycle, event, address); | ||
186 | |||
187 | if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR) | ||
188 | printk(fmt, " ECC syndrome ", syn, status, xbit, i); | ||
189 | |||
190 | return action; | ||
191 | } | ||
192 | |||
193 | int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup) | ||
194 | { | ||
195 | return dec_ecc_be_backend(regs, is_fixup, 0); | ||
196 | } | ||
197 | |||
198 | irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id) | ||
199 | { | ||
200 | struct pt_regs *regs = get_irq_regs(); | ||
201 | |||
202 | int action = dec_ecc_be_backend(regs, 0, 1); | ||
203 | |||
204 | if (action == MIPS_BE_DISCARD) | ||
205 | return IRQ_HANDLED; | ||
206 | |||
207 | /* | ||
208 | * FIXME: Find the affected processes and kill them, otherwise | ||
209 | * we must die. | ||
210 | * | ||
211 | * The interrupt is asynchronously delivered thus EPC and RA | ||
212 | * may be irrelevant, but are printed for a reference. | ||
213 | */ | ||
214 | printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n", | ||
215 | regs->cp0_epc, regs->regs[31]); | ||
216 | die("Unrecoverable bus error", regs); | ||
217 | } | ||
218 | |||
219 | |||
220 | /* | ||
221 | * Initialization differs a bit between KN02 and KN03/KN05, so we | ||
222 | * need two variants. Once set up, all systems can be handled the | ||
223 | * same way. | ||
224 | */ | ||
225 | static inline void dec_kn02_be_init(void) | ||
226 | { | ||
227 | volatile u32 *csr = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR); | ||
228 | |||
229 | kn0x_erraddr = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_ERRADDR); | ||
230 | kn0x_chksyn = (void *)CKSEG1ADDR(KN02_SLOT_BASE + KN02_CHKSYN); | ||
231 | |||
232 | /* Preset write-only bits of the Control Register cache. */ | ||
233 | cached_kn02_csr = *csr | KN02_CSR_LEDS; | ||
234 | |||
235 | /* Set normal ECC detection and generation. */ | ||
236 | cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN); | ||
237 | /* Enable ECC correction. */ | ||
238 | cached_kn02_csr |= KN02_CSR_CORRECT; | ||
239 | *csr = cached_kn02_csr; | ||
240 | iob(); | ||
241 | } | ||
242 | |||
243 | static inline void dec_kn03_be_init(void) | ||
244 | { | ||
245 | volatile u32 *mcr = (void *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_MCR); | ||
246 | volatile u32 *mbcs = (void *)CKSEG1ADDR(KN4K_SLOT_BASE + KN4K_MB_CSR); | ||
247 | |||
248 | kn0x_erraddr = (void *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_ERRADDR); | ||
249 | kn0x_chksyn = (void *)CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_CHKSYN); | ||
250 | |||
251 | /* | ||
252 | * Set normal ECC detection and generation, enable ECC correction. | ||
253 | * For KN05 we also need to make sure EE (?) is enabled in the MB. | ||
254 | * Otherwise DBE/IBE exceptions would be masked but bus error | ||
255 | * interrupts would still arrive, resulting in an inevitable crash | ||
256 | * if get_dbe() triggers one. | ||
257 | */ | ||
258 | *mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) | | ||
259 | KN03_MCR_CORRECT; | ||
260 | if (current_cpu_type() == CPU_R4400SC) | ||
261 | *mbcs |= KN4K_MB_CSR_EE; | ||
262 | fast_iob(); | ||
263 | } | ||
264 | |||
265 | void __init dec_ecc_be_init(void) | ||
266 | { | ||
267 | if (mips_machtype == MACH_DS5000_200) | ||
268 | dec_kn02_be_init(); | ||
269 | else | ||
270 | dec_kn03_be_init(); | ||
271 | |||
272 | /* Clear any leftover errors from the firmware. */ | ||
273 | dec_ecc_be_ack(); | ||
274 | } | ||
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S new file mode 100644 index 000000000..011d1d678 --- /dev/null +++ b/arch/mips/dec/int-handler.S | |||
@@ -0,0 +1,311 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen | ||
4 | * Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki | ||
5 | * | ||
6 | * Written by Ralf Baechle and Andreas Busse, modified for DECstation | ||
7 | * support by Paul Antoine and Harald Koerfgen. | ||
8 | * | ||
9 | * completely rewritten: | ||
10 | * Copyright (C) 1998 Harald Koerfgen | ||
11 | * | ||
12 | * Rewritten extensively for controller-driven IRQ support | ||
13 | * by Maciej W. Rozycki. | ||
14 | */ | ||
15 | |||
16 | #include <asm/addrspace.h> | ||
17 | #include <asm/asm.h> | ||
18 | #include <asm/mipsregs.h> | ||
19 | #include <asm/regdef.h> | ||
20 | #include <asm/stackframe.h> | ||
21 | |||
22 | #include <asm/dec/interrupts.h> | ||
23 | #include <asm/dec/ioasic_addrs.h> | ||
24 | #include <asm/dec/ioasic_ints.h> | ||
25 | #include <asm/dec/kn01.h> | ||
26 | #include <asm/dec/kn02.h> | ||
27 | #include <asm/dec/kn02xa.h> | ||
28 | #include <asm/dec/kn03.h> | ||
29 | |||
30 | #define KN02_CSR_BASE CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR) | ||
31 | #define KN02XA_IOASIC_BASE CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL) | ||
32 | #define KN03_IOASIC_BASE CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL) | ||
33 | |||
34 | .text | ||
35 | .set noreorder | ||
36 | /* | ||
37 | * plat_irq_dispatch: Interrupt handler for DECstations | ||
38 | * | ||
39 | * We follow the model in the Indy interrupt code by David Miller, where he | ||
40 | * says: a lot of complication here is taken away because: | ||
41 | * | ||
42 | * 1) We handle one interrupt and return, sitting in a loop | ||
43 | * and moving across all the pending IRQ bits in the cause | ||
44 | * register is _NOT_ the answer, the common case is one | ||
45 | * pending IRQ so optimize in that direction. | ||
46 | * | ||
47 | * 2) We need not check against bits in the status register | ||
48 | * IRQ mask, that would make this routine slow as hell. | ||
49 | * | ||
50 | * 3) Linux only thinks in terms of all IRQs on or all IRQs | ||
51 | * off, nothing in between like BSD spl() brain-damage. | ||
52 | * | ||
53 | * Furthermore, the IRQs on the DECstations look basically (barring | ||
54 | * software IRQs which we don't use at all) like... | ||
55 | * | ||
56 | * DS2100/3100's, aka kn01, aka Pmax: | ||
57 | * | ||
58 | * MIPS IRQ Source | ||
59 | * -------- ------ | ||
60 | * 0 Software (ignored) | ||
61 | * 1 Software (ignored) | ||
62 | * 2 SCSI | ||
63 | * 3 Lance Ethernet | ||
64 | * 4 DZ11 serial | ||
65 | * 5 RTC | ||
66 | * 6 Memory Controller & Video | ||
67 | * 7 FPU | ||
68 | * | ||
69 | * DS5000/200, aka kn02, aka 3max: | ||
70 | * | ||
71 | * MIPS IRQ Source | ||
72 | * -------- ------ | ||
73 | * 0 Software (ignored) | ||
74 | * 1 Software (ignored) | ||
75 | * 2 TurboChannel | ||
76 | * 3 RTC | ||
77 | * 4 Reserved | ||
78 | * 5 Memory Controller | ||
79 | * 6 Reserved | ||
80 | * 7 FPU | ||
81 | * | ||
82 | * DS5000/1xx's, aka kn02ba, aka 3min: | ||
83 | * | ||
84 | * MIPS IRQ Source | ||
85 | * -------- ------ | ||
86 | * 0 Software (ignored) | ||
87 | * 1 Software (ignored) | ||
88 | * 2 TurboChannel Slot 0 | ||
89 | * 3 TurboChannel Slot 1 | ||
90 | * 4 TurboChannel Slot 2 | ||
91 | * 5 TurboChannel Slot 3 (ASIC) | ||
92 | * 6 Halt button | ||
93 | * 7 FPU/R4k timer | ||
94 | * | ||
95 | * DS5000/2x's, aka kn02ca, aka maxine: | ||
96 | * | ||
97 | * MIPS IRQ Source | ||
98 | * -------- ------ | ||
99 | * 0 Software (ignored) | ||
100 | * 1 Software (ignored) | ||
101 | * 2 Periodic Interrupt (100usec) | ||
102 | * 3 RTC | ||
103 | * 4 I/O write timeout | ||
104 | * 5 TurboChannel (ASIC) | ||
105 | * 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER) | ||
106 | * 7 FPU/R4k timer | ||
107 | * | ||
108 | * DS5000/2xx's, aka kn03, aka 3maxplus: | ||
109 | * | ||
110 | * MIPS IRQ Source | ||
111 | * -------- ------ | ||
112 | * 0 Software (ignored) | ||
113 | * 1 Software (ignored) | ||
114 | * 2 System Board (ASIC) | ||
115 | * 3 RTC | ||
116 | * 4 Reserved | ||
117 | * 5 Memory | ||
118 | * 6 Halt Button | ||
119 | * 7 FPU/R4k timer | ||
120 | * | ||
121 | * We handle the IRQ according to _our_ priority (see setup.c), | ||
122 | * then we just return. If multiple IRQs are pending then we will | ||
123 | * just take another exception, big deal. | ||
124 | */ | ||
125 | .align 5 | ||
126 | NESTED(plat_irq_dispatch, PT_SIZE, ra) | ||
127 | .set noreorder | ||
128 | |||
129 | /* | ||
130 | * Get pending Interrupts | ||
131 | */ | ||
132 | mfc0 t0,CP0_CAUSE # get pending interrupts | ||
133 | mfc0 t1,CP0_STATUS | ||
134 | #if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) | ||
135 | lw t2,cpu_fpu_mask | ||
136 | #endif | ||
137 | andi t0,ST0_IM # CAUSE.CE may be non-zero! | ||
138 | and t0,t1 # isolate allowed ones | ||
139 | |||
140 | beqz t0,spurious | ||
141 | |||
142 | #if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) | ||
143 | and t2,t0 | ||
144 | bnez t2,fpu # handle FPU immediately | ||
145 | #endif | ||
146 | |||
147 | /* | ||
148 | * Find irq with highest priority | ||
149 | */ | ||
150 | # open coded PTR_LA t1, cpu_mask_nr_tbl | ||
151 | #if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) | ||
152 | # open coded la t1, cpu_mask_nr_tbl | ||
153 | lui t1, %hi(cpu_mask_nr_tbl) | ||
154 | addiu t1, %lo(cpu_mask_nr_tbl) | ||
155 | #else | ||
156 | #error GCC `-msym32' option required for 64-bit DECstation builds | ||
157 | #endif | ||
158 | 1: lw t2,(t1) | ||
159 | nop | ||
160 | and t2,t0 | ||
161 | beqz t2,1b | ||
162 | addu t1,2*PTRSIZE # delay slot | ||
163 | |||
164 | /* | ||
165 | * Do the low-level stuff | ||
166 | */ | ||
167 | lw a0,(-PTRSIZE)(t1) | ||
168 | nop | ||
169 | bgez a0,handle_it # irq_nr >= 0? | ||
170 | # irq_nr < 0: it is an address | ||
171 | nop | ||
172 | jr a0 | ||
173 | # a trick to save a branch: | ||
174 | lui t2,(KN03_IOASIC_BASE>>16)&0xffff | ||
175 | # upper part of IOASIC Address | ||
176 | |||
177 | /* | ||
178 | * Handle "IRQ Controller" Interrupts | ||
179 | * Masked Interrupts are still visible and have to be masked "by hand". | ||
180 | */ | ||
181 | FEXPORT(kn02_io_int) # 3max | ||
182 | lui t0,(KN02_CSR_BASE>>16)&0xffff | ||
183 | # get interrupt status and mask | ||
184 | lw t0,(t0) | ||
185 | nop | ||
186 | andi t1,t0,KN02_IRQ_ALL | ||
187 | b 1f | ||
188 | srl t0,16 # shift interrupt mask | ||
189 | |||
190 | FEXPORT(kn02xa_io_int) # 3min/maxine | ||
191 | lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff | ||
192 | # upper part of IOASIC Address | ||
193 | |||
194 | FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier) | ||
195 | lw t0,IO_REG_SIR(t2) # get status: IOASIC sir | ||
196 | lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr | ||
197 | nop | ||
198 | |||
199 | 1: and t0,t1 # mask out allowed ones | ||
200 | |||
201 | beqz t0,spurious | ||
202 | |||
203 | /* | ||
204 | * Find irq with highest priority | ||
205 | */ | ||
206 | # open coded PTR_LA t1,asic_mask_nr_tbl | ||
207 | #if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) | ||
208 | # open coded la t1, asic_mask_nr_tbl | ||
209 | lui t1, %hi(asic_mask_nr_tbl) | ||
210 | addiu t1, %lo(asic_mask_nr_tbl) | ||
211 | #else | ||
212 | #error GCC `-msym32' option required for 64-bit DECstation builds | ||
213 | #endif | ||
214 | 2: lw t2,(t1) | ||
215 | nop | ||
216 | and t2,t0 | ||
217 | beq zero,t2,2b | ||
218 | addu t1,2*PTRSIZE # delay slot | ||
219 | |||
220 | /* | ||
221 | * Do the low-level stuff | ||
222 | */ | ||
223 | lw a0,%lo(-PTRSIZE)(t1) | ||
224 | nop | ||
225 | bgez a0,handle_it # irq_nr >= 0? | ||
226 | # irq_nr < 0: it is an address | ||
227 | nop | ||
228 | jr a0 | ||
229 | nop # delay slot | ||
230 | |||
231 | /* | ||
232 | * Dispatch low-priority interrupts. We reconsider all status | ||
233 | * bits again, which looks like a lose, but it makes the code | ||
234 | * simple and O(log n), so it gets compensated. | ||
235 | */ | ||
236 | FEXPORT(cpu_all_int) # HALT, timers, software junk | ||
237 | li a0,DEC_CPU_IRQ_BASE | ||
238 | srl t0,CAUSEB_IP | ||
239 | li t1,CAUSEF_IP>>CAUSEB_IP # mask | ||
240 | b 1f | ||
241 | li t2,4 # nr of bits / 2 | ||
242 | |||
243 | FEXPORT(kn02_all_int) # impossible ? | ||
244 | li a0,KN02_IRQ_BASE | ||
245 | li t1,KN02_IRQ_ALL # mask | ||
246 | b 1f | ||
247 | li t2,4 # nr of bits / 2 | ||
248 | |||
249 | FEXPORT(asic_all_int) # various I/O ASIC junk | ||
250 | li a0,IO_IRQ_BASE | ||
251 | li t1,IO_IRQ_ALL # mask | ||
252 | b 1f | ||
253 | li t2,8 # nr of bits / 2 | ||
254 | |||
255 | /* | ||
256 | * Dispatch DMA interrupts -- O(log n). | ||
257 | */ | ||
258 | FEXPORT(asic_dma_int) # I/O ASIC DMA events | ||
259 | li a0,IO_IRQ_BASE+IO_INR_DMA | ||
260 | srl t0,IO_INR_DMA | ||
261 | li t1,IO_IRQ_DMA>>IO_INR_DMA # mask | ||
262 | li t2,8 # nr of bits / 2 | ||
263 | |||
264 | /* | ||
265 | * Find irq with highest priority. | ||
266 | * Highest irq number takes precedence. | ||
267 | */ | ||
268 | 1: srlv t3,t1,t2 | ||
269 | 2: xor t1,t3 | ||
270 | and t3,t0,t1 | ||
271 | beqz t3,3f | ||
272 | nop | ||
273 | move t0,t3 | ||
274 | addu a0,t2 | ||
275 | 3: srl t2,1 | ||
276 | bnez t2,2b | ||
277 | srlv t3,t1,t2 | ||
278 | |||
279 | handle_it: | ||
280 | j dec_irq_dispatch | ||
281 | nop | ||
282 | |||
283 | #if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) | ||
284 | fpu: | ||
285 | lw t0,fpu_kstat_irq | ||
286 | nop | ||
287 | lw t1,(t0) | ||
288 | nop | ||
289 | addu t1,1 | ||
290 | j handle_fpe_int | ||
291 | sw t1,(t0) | ||
292 | #endif | ||
293 | |||
294 | spurious: | ||
295 | j spurious_interrupt | ||
296 | nop | ||
297 | END(plat_irq_dispatch) | ||
298 | |||
299 | /* | ||
300 | * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl | ||
301 | * and asic_mask_nr_tbl are initialized to point all interrupts here. | ||
302 | * The tables are then filled in by machine-specific initialisation | ||
303 | * in dec_setup(). | ||
304 | */ | ||
305 | FEXPORT(dec_intr_unimplemented) | ||
306 | move a1,t0 # cheats way of printing an arg! | ||
307 | ASM_PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x"); | ||
308 | |||
309 | FEXPORT(asic_intr_unimplemented) | ||
310 | move a1,t0 # cheats way of printing an arg! | ||
311 | ASM_PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x"); | ||
diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c new file mode 100644 index 000000000..130eb67bd --- /dev/null +++ b/arch/mips/dec/ioasic-irq.c | |||
@@ -0,0 +1,112 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * DEC I/O ASIC interrupts. | ||
4 | * | ||
5 | * Copyright (c) 2002, 2003, 2013 Maciej W. Rozycki | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/irq.h> | ||
10 | #include <linux/types.h> | ||
11 | |||
12 | #include <asm/dec/ioasic.h> | ||
13 | #include <asm/dec/ioasic_addrs.h> | ||
14 | #include <asm/dec/ioasic_ints.h> | ||
15 | |||
16 | static int ioasic_irq_base; | ||
17 | |||
18 | static void unmask_ioasic_irq(struct irq_data *d) | ||
19 | { | ||
20 | u32 simr; | ||
21 | |||
22 | simr = ioasic_read(IO_REG_SIMR); | ||
23 | simr |= (1 << (d->irq - ioasic_irq_base)); | ||
24 | ioasic_write(IO_REG_SIMR, simr); | ||
25 | } | ||
26 | |||
27 | static void mask_ioasic_irq(struct irq_data *d) | ||
28 | { | ||
29 | u32 simr; | ||
30 | |||
31 | simr = ioasic_read(IO_REG_SIMR); | ||
32 | simr &= ~(1 << (d->irq - ioasic_irq_base)); | ||
33 | ioasic_write(IO_REG_SIMR, simr); | ||
34 | } | ||
35 | |||
36 | static void ack_ioasic_irq(struct irq_data *d) | ||
37 | { | ||
38 | mask_ioasic_irq(d); | ||
39 | fast_iob(); | ||
40 | } | ||
41 | |||
42 | static struct irq_chip ioasic_irq_type = { | ||
43 | .name = "IO-ASIC", | ||
44 | .irq_ack = ack_ioasic_irq, | ||
45 | .irq_mask = mask_ioasic_irq, | ||
46 | .irq_mask_ack = ack_ioasic_irq, | ||
47 | .irq_unmask = unmask_ioasic_irq, | ||
48 | }; | ||
49 | |||
50 | static void clear_ioasic_dma_irq(struct irq_data *d) | ||
51 | { | ||
52 | u32 sir; | ||
53 | |||
54 | sir = ~(1 << (d->irq - ioasic_irq_base)); | ||
55 | ioasic_write(IO_REG_SIR, sir); | ||
56 | fast_iob(); | ||
57 | } | ||
58 | |||
59 | static struct irq_chip ioasic_dma_irq_type = { | ||
60 | .name = "IO-ASIC-DMA", | ||
61 | .irq_ack = clear_ioasic_dma_irq, | ||
62 | .irq_mask = mask_ioasic_irq, | ||
63 | .irq_unmask = unmask_ioasic_irq, | ||
64 | .irq_eoi = clear_ioasic_dma_irq, | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * I/O ASIC implements two kinds of DMA interrupts, informational and | ||
69 | * error interrupts. | ||
70 | * | ||
71 | * The formers do not stop DMA and should be cleared as soon as possible | ||
72 | * so that if they retrigger before the handler has completed, usually as | ||
73 | * a side effect of actions taken by the handler, then they are reissued. | ||
74 | * These use the `handle_edge_irq' handler that clears the request right | ||
75 | * away. | ||
76 | * | ||
77 | * The latters stop DMA and do not resume it until the interrupt has been | ||
78 | * cleared. This cannot be done until after a corrective action has been | ||
79 | * taken and this also means they will not retrigger. Therefore they use | ||
80 | * the `handle_fasteoi_irq' handler that only clears the request on the | ||
81 | * way out. Because MIPS processor interrupt inputs, one of which the I/O | ||
82 | * ASIC is cascaded to, are level-triggered it is recommended that error | ||
83 | * DMA interrupt action handlers are registered with the IRQF_ONESHOT flag | ||
84 | * set so that they are run with the interrupt line masked. | ||
85 | * | ||
86 | * This mask has `1' bits in the positions of informational interrupts. | ||
87 | */ | ||
88 | #define IO_IRQ_DMA_INFO \ | ||
89 | (IO_IRQ_MASK(IO_INR_SCC0A_RXDMA) | \ | ||
90 | IO_IRQ_MASK(IO_INR_SCC1A_RXDMA) | \ | ||
91 | IO_IRQ_MASK(IO_INR_ISDN_TXDMA) | \ | ||
92 | IO_IRQ_MASK(IO_INR_ISDN_RXDMA) | \ | ||
93 | IO_IRQ_MASK(IO_INR_ASC_DMA)) | ||
94 | |||
95 | void __init init_ioasic_irqs(int base) | ||
96 | { | ||
97 | int i; | ||
98 | |||
99 | /* Mask interrupts. */ | ||
100 | ioasic_write(IO_REG_SIMR, 0); | ||
101 | fast_iob(); | ||
102 | |||
103 | for (i = base; i < base + IO_INR_DMA; i++) | ||
104 | irq_set_chip_and_handler(i, &ioasic_irq_type, | ||
105 | handle_level_irq); | ||
106 | for (; i < base + IO_IRQ_LINES; i++) | ||
107 | irq_set_chip_and_handler(i, &ioasic_dma_irq_type, | ||
108 | 1 << (i - base) & IO_IRQ_DMA_INFO ? | ||
109 | handle_edge_irq : handle_fasteoi_irq); | ||
110 | |||
111 | ioasic_irq_base = base; | ||
112 | } | ||
diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c new file mode 100644 index 000000000..76efed7bc --- /dev/null +++ b/arch/mips/dec/kn01-berr.c | |||
@@ -0,0 +1,196 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Bus error event handling code for DECstation/DECsystem 3100 | ||
4 | * and 2100 (KN01) systems equipped with parity error detection | ||
5 | * logic. | ||
6 | * | ||
7 | * Copyright (c) 2005 Maciej W. Rozycki | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/types.h> | ||
15 | |||
16 | #include <asm/inst.h> | ||
17 | #include <asm/irq_regs.h> | ||
18 | #include <asm/mipsregs.h> | ||
19 | #include <asm/page.h> | ||
20 | #include <asm/ptrace.h> | ||
21 | #include <asm/traps.h> | ||
22 | #include <linux/uaccess.h> | ||
23 | |||
24 | #include <asm/dec/kn01.h> | ||
25 | |||
26 | |||
27 | /* CP0 hazard avoidance. */ | ||
28 | #define BARRIER \ | ||
29 | __asm__ __volatile__( \ | ||
30 | ".set push\n\t" \ | ||
31 | ".set noreorder\n\t" \ | ||
32 | "nop\n\t" \ | ||
33 | ".set pop\n\t") | ||
34 | |||
35 | /* | ||
36 | * Bits 7:0 of the Control Register are write-only -- the | ||
37 | * corresponding bits of the Status Register have a different | ||
38 | * meaning. Hence we use a cache. It speeds up things a bit | ||
39 | * as well. | ||
40 | * | ||
41 | * There is no default value -- it has to be initialized. | ||
42 | */ | ||
43 | u16 cached_kn01_csr; | ||
44 | static DEFINE_RAW_SPINLOCK(kn01_lock); | ||
45 | |||
46 | |||
47 | static inline void dec_kn01_be_ack(void) | ||
48 | { | ||
49 | volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR); | ||
50 | unsigned long flags; | ||
51 | |||
52 | raw_spin_lock_irqsave(&kn01_lock, flags); | ||
53 | |||
54 | *csr = cached_kn01_csr | KN01_CSR_MEMERR; /* Clear bus IRQ. */ | ||
55 | iob(); | ||
56 | |||
57 | raw_spin_unlock_irqrestore(&kn01_lock, flags); | ||
58 | } | ||
59 | |||
60 | static int dec_kn01_be_backend(struct pt_regs *regs, int is_fixup, int invoker) | ||
61 | { | ||
62 | volatile u32 *kn01_erraddr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + | ||
63 | KN01_ERRADDR); | ||
64 | |||
65 | static const char excstr[] = "exception"; | ||
66 | static const char intstr[] = "interrupt"; | ||
67 | static const char cpustr[] = "CPU"; | ||
68 | static const char mreadstr[] = "memory read"; | ||
69 | static const char readstr[] = "read"; | ||
70 | static const char writestr[] = "write"; | ||
71 | static const char timestr[] = "timeout"; | ||
72 | static const char paritystr[] = "parity error"; | ||
73 | |||
74 | int data = regs->cp0_cause & 4; | ||
75 | unsigned int __user *pc = (unsigned int __user *)regs->cp0_epc + | ||
76 | ((regs->cp0_cause & CAUSEF_BD) != 0); | ||
77 | union mips_instruction insn; | ||
78 | unsigned long entrylo, offset; | ||
79 | long asid, entryhi, vaddr; | ||
80 | |||
81 | const char *kind, *agent, *cycle, *event; | ||
82 | unsigned long address; | ||
83 | |||
84 | u32 erraddr = *kn01_erraddr; | ||
85 | int action = MIPS_BE_FATAL; | ||
86 | |||
87 | /* Ack ASAP, so that any subsequent errors get caught. */ | ||
88 | dec_kn01_be_ack(); | ||
89 | |||
90 | kind = invoker ? intstr : excstr; | ||
91 | |||
92 | agent = cpustr; | ||
93 | |||
94 | if (invoker) | ||
95 | address = erraddr; | ||
96 | else { | ||
97 | /* Bloody hardware doesn't record the address for reads... */ | ||
98 | if (data) { | ||
99 | /* This never faults. */ | ||
100 | __get_user(insn.word, pc); | ||
101 | vaddr = regs->regs[insn.i_format.rs] + | ||
102 | insn.i_format.simmediate; | ||
103 | } else | ||
104 | vaddr = (long)pc; | ||
105 | if (KSEGX(vaddr) == CKSEG0 || KSEGX(vaddr) == CKSEG1) | ||
106 | address = CPHYSADDR(vaddr); | ||
107 | else { | ||
108 | /* Peek at what physical address the CPU used. */ | ||
109 | asid = read_c0_entryhi(); | ||
110 | entryhi = asid & (PAGE_SIZE - 1); | ||
111 | entryhi |= vaddr & ~(PAGE_SIZE - 1); | ||
112 | write_c0_entryhi(entryhi); | ||
113 | BARRIER; | ||
114 | tlb_probe(); | ||
115 | /* No need to check for presence. */ | ||
116 | tlb_read(); | ||
117 | entrylo = read_c0_entrylo0(); | ||
118 | write_c0_entryhi(asid); | ||
119 | offset = vaddr & (PAGE_SIZE - 1); | ||
120 | address = (entrylo & ~(PAGE_SIZE - 1)) | offset; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | /* Treat low 256MB as memory, high -- as I/O. */ | ||
125 | if (address < 0x10000000) { | ||
126 | cycle = mreadstr; | ||
127 | event = paritystr; | ||
128 | } else { | ||
129 | cycle = invoker ? writestr : readstr; | ||
130 | event = timestr; | ||
131 | } | ||
132 | |||
133 | if (is_fixup) | ||
134 | action = MIPS_BE_FIXUP; | ||
135 | |||
136 | if (action != MIPS_BE_FIXUP) | ||
137 | printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", | ||
138 | kind, agent, cycle, event, address); | ||
139 | |||
140 | return action; | ||
141 | } | ||
142 | |||
143 | int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup) | ||
144 | { | ||
145 | return dec_kn01_be_backend(regs, is_fixup, 0); | ||
146 | } | ||
147 | |||
148 | irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id) | ||
149 | { | ||
150 | volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR); | ||
151 | struct pt_regs *regs = get_irq_regs(); | ||
152 | int action; | ||
153 | |||
154 | if (!(*csr & KN01_CSR_MEMERR)) | ||
155 | return IRQ_NONE; /* Must have been video. */ | ||
156 | |||
157 | action = dec_kn01_be_backend(regs, 0, 1); | ||
158 | |||
159 | if (action == MIPS_BE_DISCARD) | ||
160 | return IRQ_HANDLED; | ||
161 | |||
162 | /* | ||
163 | * FIXME: Find the affected processes and kill them, otherwise | ||
164 | * we must die. | ||
165 | * | ||
166 | * The interrupt is asynchronously delivered thus EPC and RA | ||
167 | * may be irrelevant, but are printed for a reference. | ||
168 | */ | ||
169 | printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n", | ||
170 | regs->cp0_epc, regs->regs[31]); | ||
171 | die("Unrecoverable bus error", regs); | ||
172 | } | ||
173 | |||
174 | |||
175 | void __init dec_kn01_be_init(void) | ||
176 | { | ||
177 | volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR); | ||
178 | unsigned long flags; | ||
179 | |||
180 | raw_spin_lock_irqsave(&kn01_lock, flags); | ||
181 | |||
182 | /* Preset write-only bits of the Control Register cache. */ | ||
183 | cached_kn01_csr = *csr; | ||
184 | cached_kn01_csr &= KN01_CSR_STATUS | KN01_CSR_PARDIS | KN01_CSR_TXDIS; | ||
185 | cached_kn01_csr |= KN01_CSR_LEDS; | ||
186 | |||
187 | /* Enable parity error detection. */ | ||
188 | cached_kn01_csr &= ~KN01_CSR_PARDIS; | ||
189 | *csr = cached_kn01_csr; | ||
190 | iob(); | ||
191 | |||
192 | raw_spin_unlock_irqrestore(&kn01_lock, flags); | ||
193 | |||
194 | /* Clear any leftover errors from the firmware. */ | ||
195 | dec_kn01_be_ack(); | ||
196 | } | ||
diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c new file mode 100644 index 000000000..7e18de574 --- /dev/null +++ b/arch/mips/dec/kn02-irq.c | |||
@@ -0,0 +1,75 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * DECstation 5000/200 (KN02) Control and Status Register | ||
4 | * interrupts. | ||
5 | * | ||
6 | * Copyright (c) 2002, 2003, 2005 Maciej W. Rozycki | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <linux/types.h> | ||
12 | |||
13 | #include <asm/dec/kn02.h> | ||
14 | |||
15 | |||
16 | /* | ||
17 | * Bits 7:0 of the Control Register are write-only -- the | ||
18 | * corresponding bits of the Status Register have a different | ||
19 | * meaning. Hence we use a cache. It speeds up things a bit | ||
20 | * as well. | ||
21 | * | ||
22 | * There is no default value -- it has to be initialized. | ||
23 | */ | ||
24 | u32 cached_kn02_csr; | ||
25 | |||
26 | static int kn02_irq_base; | ||
27 | |||
28 | static void unmask_kn02_irq(struct irq_data *d) | ||
29 | { | ||
30 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + | ||
31 | KN02_CSR); | ||
32 | |||
33 | cached_kn02_csr |= (1 << (d->irq - kn02_irq_base + 16)); | ||
34 | *csr = cached_kn02_csr; | ||
35 | } | ||
36 | |||
37 | static void mask_kn02_irq(struct irq_data *d) | ||
38 | { | ||
39 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + | ||
40 | KN02_CSR); | ||
41 | |||
42 | cached_kn02_csr &= ~(1 << (d->irq - kn02_irq_base + 16)); | ||
43 | *csr = cached_kn02_csr; | ||
44 | } | ||
45 | |||
46 | static void ack_kn02_irq(struct irq_data *d) | ||
47 | { | ||
48 | mask_kn02_irq(d); | ||
49 | iob(); | ||
50 | } | ||
51 | |||
52 | static struct irq_chip kn02_irq_type = { | ||
53 | .name = "KN02-CSR", | ||
54 | .irq_ack = ack_kn02_irq, | ||
55 | .irq_mask = mask_kn02_irq, | ||
56 | .irq_mask_ack = ack_kn02_irq, | ||
57 | .irq_unmask = unmask_kn02_irq, | ||
58 | }; | ||
59 | |||
60 | void __init init_kn02_irqs(int base) | ||
61 | { | ||
62 | volatile u32 *csr = (volatile u32 *)CKSEG1ADDR(KN02_SLOT_BASE + | ||
63 | KN02_CSR); | ||
64 | int i; | ||
65 | |||
66 | /* Mask interrupts. */ | ||
67 | cached_kn02_csr &= ~KN02_CSR_IOINTEN; | ||
68 | *csr = cached_kn02_csr; | ||
69 | iob(); | ||
70 | |||
71 | for (i = base; i < base + KN02_IRQ_LINES; i++) | ||
72 | irq_set_chip_and_handler(i, &kn02_irq_type, handle_level_irq); | ||
73 | |||
74 | kn02_irq_base = base; | ||
75 | } | ||
diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c new file mode 100644 index 000000000..9699fc4e6 --- /dev/null +++ b/arch/mips/dec/kn02xa-berr.c | |||
@@ -0,0 +1,135 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * Bus error event handling code for 5000-series systems equipped | ||
4 | * with parity error detection logic, i.e. DECstation/DECsystem | ||
5 | * 5000/120, /125, /133 (KN02-BA), 5000/150 (KN04-BA) and Personal | ||
6 | * DECstation/DECsystem 5000/20, /25, /33 (KN02-CA), 5000/50 | ||
7 | * (KN04-CA) systems. | ||
8 | * | ||
9 | * Copyright (c) 2005 Maciej W. Rozycki | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/types.h> | ||
16 | |||
17 | #include <asm/addrspace.h> | ||
18 | #include <asm/cpu-type.h> | ||
19 | #include <asm/irq_regs.h> | ||
20 | #include <asm/ptrace.h> | ||
21 | #include <asm/traps.h> | ||
22 | |||
23 | #include <asm/dec/kn02ca.h> | ||
24 | #include <asm/dec/kn02xa.h> | ||
25 | #include <asm/dec/kn05.h> | ||
26 | |||
27 | static inline void dec_kn02xa_be_ack(void) | ||
28 | { | ||
29 | volatile u32 *mer = (void *)CKSEG1ADDR(KN02XA_MER); | ||
30 | volatile u32 *mem_intr = (void *)CKSEG1ADDR(KN02XA_MEM_INTR); | ||
31 | |||
32 | *mer = KN02CA_MER_INTR; /* Clear errors; keep the ARC IRQ. */ | ||
33 | *mem_intr = 0; /* Any write clears the bus IRQ. */ | ||
34 | iob(); | ||
35 | } | ||
36 | |||
37 | static int dec_kn02xa_be_backend(struct pt_regs *regs, int is_fixup, | ||
38 | int invoker) | ||
39 | { | ||
40 | volatile u32 *kn02xa_mer = (void *)CKSEG1ADDR(KN02XA_MER); | ||
41 | volatile u32 *kn02xa_ear = (void *)CKSEG1ADDR(KN02XA_EAR); | ||
42 | |||
43 | static const char excstr[] = "exception"; | ||
44 | static const char intstr[] = "interrupt"; | ||
45 | static const char cpustr[] = "CPU"; | ||
46 | static const char mreadstr[] = "memory read"; | ||
47 | static const char readstr[] = "read"; | ||
48 | static const char writestr[] = "write"; | ||
49 | static const char timestr[] = "timeout"; | ||
50 | static const char paritystr[] = "parity error"; | ||
51 | static const char lanestat[][4] = { " OK", "BAD" }; | ||
52 | |||
53 | const char *kind, *agent, *cycle, *event; | ||
54 | unsigned long address; | ||
55 | |||
56 | u32 mer = *kn02xa_mer; | ||
57 | u32 ear = *kn02xa_ear; | ||
58 | int action = MIPS_BE_FATAL; | ||
59 | |||
60 | /* Ack ASAP, so that any subsequent errors get caught. */ | ||
61 | dec_kn02xa_be_ack(); | ||
62 | |||
63 | kind = invoker ? intstr : excstr; | ||
64 | |||
65 | /* No DMA errors? */ | ||
66 | agent = cpustr; | ||
67 | |||
68 | address = ear & KN02XA_EAR_ADDRESS; | ||
69 | |||
70 | /* Low 256MB is decoded as memory, high -- as TC. */ | ||
71 | if (address < 0x10000000) { | ||
72 | cycle = mreadstr; | ||
73 | event = paritystr; | ||
74 | } else { | ||
75 | cycle = invoker ? writestr : readstr; | ||
76 | event = timestr; | ||
77 | } | ||
78 | |||
79 | if (is_fixup) | ||
80 | action = MIPS_BE_FIXUP; | ||
81 | |||
82 | if (action != MIPS_BE_FIXUP) | ||
83 | printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx\n", | ||
84 | kind, agent, cycle, event, address); | ||
85 | |||
86 | if (action != MIPS_BE_FIXUP && address < 0x10000000) | ||
87 | printk(KERN_ALERT " Byte lane status %#3x -- " | ||
88 | "#3: %s, #2: %s, #1: %s, #0: %s\n", | ||
89 | (mer & KN02XA_MER_BYTERR) >> 8, | ||
90 | lanestat[(mer & KN02XA_MER_BYTERR_3) != 0], | ||
91 | lanestat[(mer & KN02XA_MER_BYTERR_2) != 0], | ||
92 | lanestat[(mer & KN02XA_MER_BYTERR_1) != 0], | ||
93 | lanestat[(mer & KN02XA_MER_BYTERR_0) != 0]); | ||
94 | |||
95 | return action; | ||
96 | } | ||
97 | |||
98 | int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup) | ||
99 | { | ||
100 | return dec_kn02xa_be_backend(regs, is_fixup, 0); | ||
101 | } | ||
102 | |||
103 | irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id) | ||
104 | { | ||
105 | struct pt_regs *regs = get_irq_regs(); | ||
106 | int action = dec_kn02xa_be_backend(regs, 0, 1); | ||
107 | |||
108 | if (action == MIPS_BE_DISCARD) | ||
109 | return IRQ_HANDLED; | ||
110 | |||
111 | /* | ||
112 | * FIXME: Find the affected processes and kill them, otherwise | ||
113 | * we must die. | ||
114 | * | ||
115 | * The interrupt is asynchronously delivered thus EPC and RA | ||
116 | * may be irrelevant, but are printed for a reference. | ||
117 | */ | ||
118 | printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n", | ||
119 | regs->cp0_epc, regs->regs[31]); | ||
120 | die("Unrecoverable bus error", regs); | ||
121 | } | ||
122 | |||
123 | |||
124 | void __init dec_kn02xa_be_init(void) | ||
125 | { | ||
126 | volatile u32 *mbcs = (void *)CKSEG1ADDR(KN4K_SLOT_BASE + KN4K_MB_CSR); | ||
127 | |||
128 | /* For KN04 we need to make sure EE (?) is enabled in the MB. */ | ||
129 | if (current_cpu_type() == CPU_R4000SC) | ||
130 | *mbcs |= KN4K_MB_CSR_EE; | ||
131 | fast_iob(); | ||
132 | |||
133 | /* Clear any leftover errors from the firmware. */ | ||
134 | dec_kn02xa_be_ack(); | ||
135 | } | ||
diff --git a/arch/mips/dec/platform.c b/arch/mips/dec/platform.c new file mode 100644 index 000000000..c4fcb8c58 --- /dev/null +++ b/arch/mips/dec/platform.c | |||
@@ -0,0 +1,40 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * DEC platform devices. | ||
4 | * | ||
5 | * Copyright (c) 2014 Maciej W. Rozycki | ||
6 | */ | ||
7 | |||
8 | #include <linux/ioport.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/mc146818rtc.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | |||
13 | static struct resource dec_rtc_resources[] = { | ||
14 | { | ||
15 | .name = "rtc", | ||
16 | .flags = IORESOURCE_MEM, | ||
17 | }, | ||
18 | }; | ||
19 | |||
20 | static struct cmos_rtc_board_info dec_rtc_info = { | ||
21 | .flags = CMOS_RTC_FLAGS_NOFREQ, | ||
22 | .address_space = 64, | ||
23 | }; | ||
24 | |||
25 | static struct platform_device dec_rtc_device = { | ||
26 | .name = "rtc_cmos", | ||
27 | .id = PLATFORM_DEVID_NONE, | ||
28 | .dev.platform_data = &dec_rtc_info, | ||
29 | .resource = dec_rtc_resources, | ||
30 | .num_resources = ARRAY_SIZE(dec_rtc_resources), | ||
31 | }; | ||
32 | |||
33 | static int __init dec_add_devices(void) | ||
34 | { | ||
35 | dec_rtc_resources[0].start = RTC_PORT(0); | ||
36 | dec_rtc_resources[0].end = RTC_PORT(0) + dec_kn_slot_size - 1; | ||
37 | return platform_device_register(&dec_rtc_device); | ||
38 | } | ||
39 | |||
40 | device_initcall(dec_add_devices); | ||
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile new file mode 100644 index 000000000..2bad87551 --- /dev/null +++ b/arch/mips/dec/prom/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # | ||
3 | # Makefile for the DECstation prom monitor library routines | ||
4 | # under Linux. | ||
5 | # | ||
6 | |||
7 | lib-y += init.o memory.o cmdline.o identify.o console.o | ||
8 | |||
9 | lib-$(CONFIG_CPU_R3000) += locore.o | ||
diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c new file mode 100644 index 000000000..3ed63280a --- /dev/null +++ b/arch/mips/dec/prom/cmdline.c | |||
@@ -0,0 +1,40 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * cmdline.c: read the command line passed to us by the PROM. | ||
4 | * | ||
5 | * Copyright (C) 1998 Harald Koerfgen | ||
6 | * Copyright (C) 2002, 2004 Maciej W. Rozycki | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/types.h> | ||
12 | |||
13 | #include <asm/bootinfo.h> | ||
14 | #include <asm/dec/prom.h> | ||
15 | |||
16 | #undef PROM_DEBUG | ||
17 | |||
18 | void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic) | ||
19 | { | ||
20 | char *arg; | ||
21 | int start_arg, i; | ||
22 | |||
23 | /* | ||
24 | * collect args and prepare cmd_line | ||
25 | */ | ||
26 | if (!prom_is_rex(magic)) | ||
27 | start_arg = 1; | ||
28 | else | ||
29 | start_arg = 2; | ||
30 | for (i = start_arg; i < argc; i++) { | ||
31 | arg = (void *)(long)(argv[i]); | ||
32 | strcat(arcs_cmdline, arg); | ||
33 | if (i < (argc - 1)) | ||
34 | strcat(arcs_cmdline, " "); | ||
35 | } | ||
36 | |||
37 | #ifdef PROM_DEBUG | ||
38 | printk("arcs_cmdline: %s\n", &(arcs_cmdline[0])); | ||
39 | #endif | ||
40 | } | ||
diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c new file mode 100644 index 000000000..31a8441d8 --- /dev/null +++ b/arch/mips/dec/prom/console.c | |||
@@ -0,0 +1,41 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
2 | /* | ||
3 | * DECstation PROM-based early console support. | ||
4 | * | ||
5 | * Copyright (C) 2004, 2007 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/console.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/string.h> | ||
11 | |||
12 | #include <asm/dec/prom.h> | ||
13 | |||
14 | static void __init prom_console_write(struct console *con, const char *s, | ||
15 | unsigned int c) | ||
16 | { | ||
17 | char buf[81]; | ||
18 | unsigned int chunk = sizeof(buf) - 1; | ||
19 | |||
20 | while (c > 0) { | ||
21 | if (chunk > c) | ||
22 | chunk = c; | ||
23 | memcpy(buf, s, chunk); | ||
24 | buf[chunk] = '\0'; | ||
25 | prom_printf("%s", buf); | ||
26 | s += chunk; | ||
27 | c -= chunk; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | static struct console promcons __initdata = { | ||
32 | .name = "prom", | ||
33 | .write = prom_console_write, | ||
34 | .flags = CON_BOOT | CON_PRINTBUFFER, | ||
35 | .index = -1, | ||
36 | }; | ||
37 | |||
38 | void __init register_prom_console(void) | ||
39 | { | ||
40 | register_console(&promcons); | ||
41 | } | ||
diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h new file mode 100644 index 000000000..9fcbcc7cd --- /dev/null +++ b/arch/mips/dec/prom/dectypes.h | |||
@@ -0,0 +1,15 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef DECTYPES | ||
3 | #define DECTYPES | ||
4 | |||
5 | #define DS2100_3100 1 /* DS2100/3100 Pmax */ | ||
6 | #define DS5000_200 2 /* DS5000/200 3max */ | ||
7 | #define DS5000_1XX 3 /* DS5000/1xx kmin */ | ||
8 | #define DS5000_2X0 4 /* DS5000/2x0 3max+ */ | ||
9 | #define DS5800 5 /* DS5800 Isis */ | ||
10 | #define DS5400 6 /* DS5400 MIPSfair */ | ||
11 | #define DS5000_XX 7 /* DS5000/xx maxine */ | ||
12 | #define DS5500 11 /* DS5500 MIPSfair-2 */ | ||
13 | #define DS5100 12 /* DS5100 MIPSmate */ | ||
14 | |||
15 | #endif | ||
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c new file mode 100644 index 000000000..80cd14cd1 --- /dev/null +++ b/arch/mips/dec/prom/identify.c | |||
@@ -0,0 +1,187 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * identify.c: machine identification code. | ||
4 | * | ||
5 | * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine | ||
6 | * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/mc146818rtc.h> | ||
11 | #include <linux/export.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/types.h> | ||
14 | |||
15 | #include <asm/bootinfo.h> | ||
16 | |||
17 | #include <asm/dec/ioasic.h> | ||
18 | #include <asm/dec/ioasic_addrs.h> | ||
19 | #include <asm/dec/kn01.h> | ||
20 | #include <asm/dec/kn02.h> | ||
21 | #include <asm/dec/kn02ba.h> | ||
22 | #include <asm/dec/kn02ca.h> | ||
23 | #include <asm/dec/kn03.h> | ||
24 | #include <asm/dec/kn230.h> | ||
25 | #include <asm/dec/prom.h> | ||
26 | #include <asm/dec/system.h> | ||
27 | |||
28 | #include "dectypes.h" | ||
29 | |||
30 | static const char *dec_system_strings[] = { | ||
31 | [MACH_DSUNKNOWN] "unknown DECstation", | ||
32 | [MACH_DS23100] "DECstation 2100/3100", | ||
33 | [MACH_DS5100] "DECsystem 5100", | ||
34 | [MACH_DS5000_200] "DECstation 5000/200", | ||
35 | [MACH_DS5000_1XX] "DECstation 5000/1xx", | ||
36 | [MACH_DS5000_XX] "Personal DECstation 5000/xx", | ||
37 | [MACH_DS5000_2X0] "DECstation 5000/2x0", | ||
38 | [MACH_DS5400] "DECsystem 5400", | ||
39 | [MACH_DS5500] "DECsystem 5500", | ||
40 | [MACH_DS5800] "DECsystem 5800", | ||
41 | [MACH_DS5900] "DECsystem 5900", | ||
42 | }; | ||
43 | |||
44 | const char *get_system_type(void) | ||
45 | { | ||
46 | #define STR_BUF_LEN 64 | ||
47 | static char system[STR_BUF_LEN]; | ||
48 | static int called = 0; | ||
49 | |||
50 | if (called == 0) { | ||
51 | called = 1; | ||
52 | snprintf(system, STR_BUF_LEN, "Digital %s", | ||
53 | dec_system_strings[mips_machtype]); | ||
54 | } | ||
55 | |||
56 | return system; | ||
57 | } | ||
58 | |||
59 | |||
60 | /* | ||
61 | * Setup essential system-specific memory addresses. We need them | ||
62 | * early. Semantically the functions belong to prom/init.c, but they | ||
63 | * are compact enough we want them inlined. --macro | ||
64 | */ | ||
65 | volatile u8 *dec_rtc_base; | ||
66 | |||
67 | EXPORT_SYMBOL(dec_rtc_base); | ||
68 | |||
69 | static inline void prom_init_kn01(void) | ||
70 | { | ||
71 | dec_kn_slot_base = KN01_SLOT_BASE; | ||
72 | dec_kn_slot_size = KN01_SLOT_SIZE; | ||
73 | |||
74 | dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN01_RTC); | ||
75 | } | ||
76 | |||
77 | static inline void prom_init_kn230(void) | ||
78 | { | ||
79 | dec_kn_slot_base = KN01_SLOT_BASE; | ||
80 | dec_kn_slot_size = KN01_SLOT_SIZE; | ||
81 | |||
82 | dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN01_RTC); | ||
83 | } | ||
84 | |||
85 | static inline void prom_init_kn02(void) | ||
86 | { | ||
87 | dec_kn_slot_base = KN02_SLOT_BASE; | ||
88 | dec_kn_slot_size = KN02_SLOT_SIZE; | ||
89 | dec_tc_bus = 1; | ||
90 | |||
91 | dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC); | ||
92 | } | ||
93 | |||
94 | static inline void prom_init_kn02xa(void) | ||
95 | { | ||
96 | dec_kn_slot_base = KN02XA_SLOT_BASE; | ||
97 | dec_kn_slot_size = IOASIC_SLOT_SIZE; | ||
98 | dec_tc_bus = 1; | ||
99 | |||
100 | ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); | ||
101 | dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); | ||
102 | } | ||
103 | |||
104 | static inline void prom_init_kn03(void) | ||
105 | { | ||
106 | dec_kn_slot_base = KN03_SLOT_BASE; | ||
107 | dec_kn_slot_size = IOASIC_SLOT_SIZE; | ||
108 | dec_tc_bus = 1; | ||
109 | |||
110 | ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); | ||
111 | dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); | ||
112 | } | ||
113 | |||
114 | |||
115 | void __init prom_identify_arch(u32 magic) | ||
116 | { | ||
117 | unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype; | ||
118 | u32 dec_sysid; | ||
119 | |||
120 | if (!prom_is_rex(magic)) { | ||
121 | dec_sysid = simple_strtoul(prom_getenv("systype"), | ||
122 | (char **)0, 0); | ||
123 | } else { | ||
124 | dec_sysid = rex_getsysid(); | ||
125 | if (dec_sysid == 0) { | ||
126 | printk("Zero sysid returned from PROM! " | ||
127 | "Assuming a PMAX-like machine.\n"); | ||
128 | dec_sysid = 1; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | dec_cpunum = (dec_sysid & 0xff000000) >> 24; | ||
133 | dec_systype = (dec_sysid & 0xff0000) >> 16; | ||
134 | dec_firmrev = (dec_sysid & 0xff00) >> 8; | ||
135 | dec_etc = dec_sysid & 0xff; | ||
136 | |||
137 | /* | ||
138 | * FIXME: This may not be an exhaustive list of DECStations/Servers! | ||
139 | * Put all model-specific initialisation calls here. | ||
140 | */ | ||
141 | switch (dec_systype) { | ||
142 | case DS2100_3100: | ||
143 | mips_machtype = MACH_DS23100; | ||
144 | prom_init_kn01(); | ||
145 | break; | ||
146 | case DS5100: /* DS5100 MIPSMATE */ | ||
147 | mips_machtype = MACH_DS5100; | ||
148 | prom_init_kn230(); | ||
149 | break; | ||
150 | case DS5000_200: /* DS5000 3max */ | ||
151 | mips_machtype = MACH_DS5000_200; | ||
152 | prom_init_kn02(); | ||
153 | break; | ||
154 | case DS5000_1XX: /* DS5000/100 3min */ | ||
155 | mips_machtype = MACH_DS5000_1XX; | ||
156 | prom_init_kn02xa(); | ||
157 | break; | ||
158 | case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */ | ||
159 | mips_machtype = MACH_DS5000_2X0; | ||
160 | prom_init_kn03(); | ||
161 | if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP)) | ||
162 | mips_machtype = MACH_DS5900; | ||
163 | break; | ||
164 | case DS5000_XX: /* Personal DS5000/xx maxine */ | ||
165 | mips_machtype = MACH_DS5000_XX; | ||
166 | prom_init_kn02xa(); | ||
167 | break; | ||
168 | case DS5800: /* DS5800 Isis */ | ||
169 | mips_machtype = MACH_DS5800; | ||
170 | break; | ||
171 | case DS5400: /* DS5400 MIPSfair */ | ||
172 | mips_machtype = MACH_DS5400; | ||
173 | break; | ||
174 | case DS5500: /* DS5500 MIPSfair-2 */ | ||
175 | mips_machtype = MACH_DS5500; | ||
176 | break; | ||
177 | default: | ||
178 | mips_machtype = MACH_DSUNKNOWN; | ||
179 | break; | ||
180 | } | ||
181 | |||
182 | if (mips_machtype == MACH_DSUNKNOWN) | ||
183 | printk("This is an %s, id is %x\n", | ||
184 | dec_system_strings[mips_machtype], dec_systype); | ||
185 | else | ||
186 | printk("This is a %s\n", dec_system_strings[mips_machtype]); | ||
187 | } | ||
diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c new file mode 100644 index 000000000..cc988bbd2 --- /dev/null +++ b/arch/mips/dec/prom/init.c | |||
@@ -0,0 +1,137 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * init.c: PROM library initialisation code. | ||
4 | * | ||
5 | * Copyright (C) 1998 Harald Koerfgen | ||
6 | * Copyright (C) 2002, 2004 Maciej W. Rozycki | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/linkage.h> | ||
11 | #include <linux/smp.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/types.h> | ||
14 | |||
15 | #include <asm/bootinfo.h> | ||
16 | #include <asm/cpu.h> | ||
17 | #include <asm/cpu-type.h> | ||
18 | #include <asm/processor.h> | ||
19 | |||
20 | #include <asm/dec/prom.h> | ||
21 | |||
22 | |||
23 | int (*__rex_bootinit)(void); | ||
24 | int (*__rex_bootread)(void); | ||
25 | int (*__rex_getbitmap)(memmap *); | ||
26 | unsigned long *(*__rex_slot_address)(int); | ||
27 | void *(*__rex_gettcinfo)(void); | ||
28 | int (*__rex_getsysid)(void); | ||
29 | void (*__rex_clear_cache)(void); | ||
30 | |||
31 | int (*__prom_getchar)(void); | ||
32 | char *(*__prom_getenv)(char *); | ||
33 | int (*__prom_printf)(char *, ...); | ||
34 | |||
35 | int (*__pmax_open)(char*, int); | ||
36 | int (*__pmax_lseek)(int, long, int); | ||
37 | int (*__pmax_read)(int, void *, int); | ||
38 | int (*__pmax_close)(int); | ||
39 | |||
40 | |||
41 | /* | ||
42 | * Detect which PROM the DECSTATION has, and set the callback vectors | ||
43 | * appropriately. | ||
44 | */ | ||
45 | void __init which_prom(s32 magic, s32 *prom_vec) | ||
46 | { | ||
47 | /* | ||
48 | * No sign of the REX PROM's magic number means we assume a non-REX | ||
49 | * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx) | ||
50 | */ | ||
51 | if (prom_is_rex(magic)) { | ||
52 | /* | ||
53 | * Set up prom abstraction structure with REX entry points. | ||
54 | */ | ||
55 | __rex_bootinit = | ||
56 | (void *)(long)*(prom_vec + REX_PROM_BOOTINIT); | ||
57 | __rex_bootread = | ||
58 | (void *)(long)*(prom_vec + REX_PROM_BOOTREAD); | ||
59 | __rex_getbitmap = | ||
60 | (void *)(long)*(prom_vec + REX_PROM_GETBITMAP); | ||
61 | __prom_getchar = | ||
62 | (void *)(long)*(prom_vec + REX_PROM_GETCHAR); | ||
63 | __prom_getenv = | ||
64 | (void *)(long)*(prom_vec + REX_PROM_GETENV); | ||
65 | __rex_getsysid = | ||
66 | (void *)(long)*(prom_vec + REX_PROM_GETSYSID); | ||
67 | __rex_gettcinfo = | ||
68 | (void *)(long)*(prom_vec + REX_PROM_GETTCINFO); | ||
69 | __prom_printf = | ||
70 | (void *)(long)*(prom_vec + REX_PROM_PRINTF); | ||
71 | __rex_slot_address = | ||
72 | (void *)(long)*(prom_vec + REX_PROM_SLOTADDR); | ||
73 | __rex_clear_cache = | ||
74 | (void *)(long)*(prom_vec + REX_PROM_CLEARCACHE); | ||
75 | } else { | ||
76 | /* | ||
77 | * Set up prom abstraction structure with non-REX entry points. | ||
78 | */ | ||
79 | __prom_getchar = (void *)PMAX_PROM_GETCHAR; | ||
80 | __prom_getenv = (void *)PMAX_PROM_GETENV; | ||
81 | __prom_printf = (void *)PMAX_PROM_PRINTF; | ||
82 | __pmax_open = (void *)PMAX_PROM_OPEN; | ||
83 | __pmax_lseek = (void *)PMAX_PROM_LSEEK; | ||
84 | __pmax_read = (void *)PMAX_PROM_READ; | ||
85 | __pmax_close = (void *)PMAX_PROM_CLOSE; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | void __init prom_init(void) | ||
90 | { | ||
91 | extern void dec_machine_halt(void); | ||
92 | static const char cpu_msg[] __initconst = | ||
93 | "Sorry, this kernel is compiled for a wrong CPU type!\n"; | ||
94 | s32 argc = fw_arg0; | ||
95 | s32 *argv = (void *)fw_arg1; | ||
96 | u32 magic = fw_arg2; | ||
97 | s32 *prom_vec = (void *)fw_arg3; | ||
98 | |||
99 | /* | ||
100 | * Determine which PROM we have | ||
101 | * (and therefore which machine we're on!) | ||
102 | */ | ||
103 | which_prom(magic, prom_vec); | ||
104 | |||
105 | if (prom_is_rex(magic)) | ||
106 | rex_clear_cache(); | ||
107 | |||
108 | /* Register the early console. */ | ||
109 | register_prom_console(); | ||
110 | |||
111 | /* Were we compiled with the right CPU option? */ | ||
112 | #if defined(CONFIG_CPU_R3000) | ||
113 | if ((current_cpu_type() == CPU_R4000SC) || | ||
114 | (current_cpu_type() == CPU_R4400SC)) { | ||
115 | static const char r4k_msg[] __initconst = | ||
116 | "Please recompile with \"CONFIG_CPU_R4x00 = y\".\n"; | ||
117 | printk(cpu_msg); | ||
118 | printk(r4k_msg); | ||
119 | dec_machine_halt(); | ||
120 | } | ||
121 | #endif | ||
122 | |||
123 | #if defined(CONFIG_CPU_R4X00) | ||
124 | if ((current_cpu_type() == CPU_R3000) || | ||
125 | (current_cpu_type() == CPU_R3000A)) { | ||
126 | static const char r3k_msg[] __initconst = | ||
127 | "Please recompile with \"CONFIG_CPU_R3000 = y\".\n"; | ||
128 | printk(cpu_msg); | ||
129 | printk(r3k_msg); | ||
130 | dec_machine_halt(); | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | prom_meminit(magic); | ||
135 | prom_identify_arch(magic); | ||
136 | prom_init_cmdline(argc, argv, magic); | ||
137 | } | ||
diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S new file mode 100644 index 000000000..0eb8fab62 --- /dev/null +++ b/arch/mips/dec/prom/locore.S | |||
@@ -0,0 +1,30 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * locore.S | ||
4 | */ | ||
5 | #include <asm/asm.h> | ||
6 | #include <asm/regdef.h> | ||
7 | #include <asm/mipsregs.h> | ||
8 | |||
9 | .text | ||
10 | |||
11 | /* | ||
12 | * Simple general exception handling routine. This one is used for the | ||
13 | * Memory sizing routine for pmax machines. HK | ||
14 | */ | ||
15 | |||
16 | NESTED(genexcept_early, 0, sp) | ||
17 | .set noat | ||
18 | .set noreorder | ||
19 | |||
20 | mfc0 k0, CP0_STATUS | ||
21 | la k1, mem_err | ||
22 | |||
23 | sw k0, 0(k1) | ||
24 | |||
25 | mfc0 k0, CP0_EPC | ||
26 | nop | ||
27 | addiu k0, 4 # skip the causing instruction | ||
28 | jr k0 | ||
29 | rfe | ||
30 | END(genexcept_early) | ||
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c new file mode 100644 index 000000000..44490c30d --- /dev/null +++ b/arch/mips/dec/prom/memory.c | |||
@@ -0,0 +1,117 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * memory.c: memory initialisation code. | ||
4 | * | ||
5 | * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine | ||
6 | * Copyright (C) 2000, 2002 Maciej W. Rozycki | ||
7 | */ | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/memblock.h> | ||
12 | #include <linux/types.h> | ||
13 | |||
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/dec/machtype.h> | ||
16 | #include <asm/dec/prom.h> | ||
17 | #include <asm/page.h> | ||
18 | #include <asm/sections.h> | ||
19 | |||
20 | |||
21 | volatile unsigned long mem_err; /* So we know an error occurred */ | ||
22 | |||
23 | /* | ||
24 | * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen | ||
25 | * off the end of real memory. Only suitable for the 2100/3100's (PMAX). | ||
26 | */ | ||
27 | |||
28 | #define CHUNK_SIZE 0x400000 | ||
29 | |||
30 | static __init void pmax_setup_memory_region(void) | ||
31 | { | ||
32 | volatile unsigned char *memory_page, dummy; | ||
33 | char old_handler[0x80]; | ||
34 | extern char genexcept_early; | ||
35 | |||
36 | /* Install exception handler */ | ||
37 | memcpy(&old_handler, (void *)(CKSEG0 + 0x80), 0x80); | ||
38 | memcpy((void *)(CKSEG0 + 0x80), &genexcept_early, 0x80); | ||
39 | |||
40 | /* read unmapped and uncached (KSEG1) | ||
41 | * DECstations have at least 4MB RAM | ||
42 | * Assume less than 480MB of RAM, as this is max for 5000/2xx | ||
43 | * FIXME this should be replaced by the first free page! | ||
44 | */ | ||
45 | for (memory_page = (unsigned char *)CKSEG1 + CHUNK_SIZE; | ||
46 | mem_err == 0 && memory_page < (unsigned char *)CKSEG1 + 0x1e00000; | ||
47 | memory_page += CHUNK_SIZE) { | ||
48 | dummy = *memory_page; | ||
49 | } | ||
50 | memcpy((void *)(CKSEG0 + 0x80), &old_handler, 0x80); | ||
51 | |||
52 | memblock_add(0, (unsigned long)memory_page - CKSEG1 - CHUNK_SIZE); | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Use the REX prom calls to get hold of the memory bitmap, and thence | ||
57 | * determine memory size. | ||
58 | */ | ||
59 | static __init void rex_setup_memory_region(void) | ||
60 | { | ||
61 | int i, bitmap_size; | ||
62 | unsigned long mem_start = 0, mem_size = 0; | ||
63 | memmap *bm; | ||
64 | |||
65 | /* some free 64k */ | ||
66 | bm = (memmap *)CKSEG0ADDR(0x28000); | ||
67 | |||
68 | bitmap_size = rex_getbitmap(bm); | ||
69 | |||
70 | for (i = 0; i < bitmap_size; i++) { | ||
71 | /* FIXME: very simplistically only add full sets of pages */ | ||
72 | if (bm->bitmap[i] == 0xff) | ||
73 | mem_size += (8 * bm->pagesize); | ||
74 | else if (!mem_size) | ||
75 | mem_start += (8 * bm->pagesize); | ||
76 | else { | ||
77 | memblock_add(mem_start, mem_size); | ||
78 | mem_start += mem_size + (8 * bm->pagesize); | ||
79 | mem_size = 0; | ||
80 | } | ||
81 | } | ||
82 | if (mem_size) | ||
83 | memblock_add(mem_start, mem_size); | ||
84 | } | ||
85 | |||
86 | void __init prom_meminit(u32 magic) | ||
87 | { | ||
88 | if (!prom_is_rex(magic)) | ||
89 | pmax_setup_memory_region(); | ||
90 | else | ||
91 | rex_setup_memory_region(); | ||
92 | } | ||
93 | |||
94 | void __init prom_free_prom_memory(void) | ||
95 | { | ||
96 | unsigned long end; | ||
97 | |||
98 | /* | ||
99 | * Free everything below the kernel itself but leave | ||
100 | * the first page reserved for the exception handlers. | ||
101 | */ | ||
102 | |||
103 | #if IS_ENABLED(CONFIG_DECLANCE) | ||
104 | /* | ||
105 | * Leave 128 KB reserved for Lance memory for | ||
106 | * IOASIC DECstations. | ||
107 | * | ||
108 | * XXX: save this address for use in dec_lance.c? | ||
109 | */ | ||
110 | if (IOASIC) | ||
111 | end = __pa(&_text) - 0x00020000; | ||
112 | else | ||
113 | #endif | ||
114 | end = __pa(&_text); | ||
115 | |||
116 | free_init_pages("unused PROM memory", PAGE_SIZE, end); | ||
117 | } | ||
diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c new file mode 100644 index 000000000..3df01f1da --- /dev/null +++ b/arch/mips/dec/reset.c | |||
@@ -0,0 +1,41 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Reset a DECstation machine. | ||
4 | * | ||
5 | * Copyright (C) 199x the Anonymous | ||
6 | * Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki | ||
7 | */ | ||
8 | #include <linux/interrupt.h> | ||
9 | #include <linux/linkage.h> | ||
10 | |||
11 | #include <asm/addrspace.h> | ||
12 | |||
13 | typedef void __noreturn (* noret_func_t)(void); | ||
14 | |||
15 | static inline void __noreturn back_to_prom(void) | ||
16 | { | ||
17 | noret_func_t func = (void *)CKSEG1ADDR(0x1fc00000); | ||
18 | |||
19 | func(); | ||
20 | } | ||
21 | |||
22 | void __noreturn dec_machine_restart(char *command) | ||
23 | { | ||
24 | back_to_prom(); | ||
25 | } | ||
26 | |||
27 | void __noreturn dec_machine_halt(void) | ||
28 | { | ||
29 | back_to_prom(); | ||
30 | } | ||
31 | |||
32 | void __noreturn dec_machine_power_off(void) | ||
33 | { | ||
34 | /* DECstations don't have a software power switch */ | ||
35 | back_to_prom(); | ||
36 | } | ||
37 | |||
38 | irqreturn_t dec_intr_halt(int irq, void *dev_id) | ||
39 | { | ||
40 | dec_machine_halt(); | ||
41 | } | ||
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c new file mode 100644 index 000000000..99b9b2975 --- /dev/null +++ b/arch/mips/dec/setup.c | |||
@@ -0,0 +1,784 @@ | |||
1 | /* | ||
2 | * System-specific setup, especially interrupts. | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 1998 Harald Koerfgen | ||
9 | * Copyright (C) 2000, 2001, 2002, 2003, 2005, 2020 Maciej W. Rozycki | ||
10 | */ | ||
11 | #include <linux/console.h> | ||
12 | #include <linux/export.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/irqnr.h> | ||
18 | #include <linux/memblock.h> | ||
19 | #include <linux/param.h> | ||
20 | #include <linux/percpu-defs.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/pm.h> | ||
25 | |||
26 | #include <asm/addrspace.h> | ||
27 | #include <asm/bootinfo.h> | ||
28 | #include <asm/cpu.h> | ||
29 | #include <asm/cpu-features.h> | ||
30 | #include <asm/cpu-type.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/irq_cpu.h> | ||
33 | #include <asm/mipsregs.h> | ||
34 | #include <asm/page.h> | ||
35 | #include <asm/reboot.h> | ||
36 | #include <asm/sections.h> | ||
37 | #include <asm/time.h> | ||
38 | #include <asm/traps.h> | ||
39 | #include <asm/wbflush.h> | ||
40 | |||
41 | #include <asm/dec/interrupts.h> | ||
42 | #include <asm/dec/ioasic.h> | ||
43 | #include <asm/dec/ioasic_addrs.h> | ||
44 | #include <asm/dec/ioasic_ints.h> | ||
45 | #include <asm/dec/kn01.h> | ||
46 | #include <asm/dec/kn02.h> | ||
47 | #include <asm/dec/kn02ba.h> | ||
48 | #include <asm/dec/kn02ca.h> | ||
49 | #include <asm/dec/kn03.h> | ||
50 | #include <asm/dec/kn230.h> | ||
51 | #include <asm/dec/system.h> | ||
52 | |||
53 | |||
54 | extern void dec_machine_restart(char *command); | ||
55 | extern void dec_machine_halt(void); | ||
56 | extern void dec_machine_power_off(void); | ||
57 | extern irqreturn_t dec_intr_halt(int irq, void *dev_id); | ||
58 | |||
59 | unsigned long dec_kn_slot_base, dec_kn_slot_size; | ||
60 | |||
61 | EXPORT_SYMBOL(dec_kn_slot_base); | ||
62 | EXPORT_SYMBOL(dec_kn_slot_size); | ||
63 | |||
64 | int dec_tc_bus; | ||
65 | |||
66 | DEFINE_SPINLOCK(ioasic_ssr_lock); | ||
67 | EXPORT_SYMBOL(ioasic_ssr_lock); | ||
68 | |||
69 | volatile u32 *ioasic_base; | ||
70 | |||
71 | EXPORT_SYMBOL(ioasic_base); | ||
72 | |||
73 | /* | ||
74 | * IRQ routing and priority tables. Priorites are set as follows: | ||
75 | * | ||
76 | * KN01 KN230 KN02 KN02-BA KN02-CA KN03 | ||
77 | * | ||
78 | * MEMORY CPU CPU CPU ASIC CPU CPU | ||
79 | * RTC CPU CPU CPU ASIC CPU CPU | ||
80 | * DMA - - - ASIC ASIC ASIC | ||
81 | * SERIAL0 CPU CPU CSR ASIC ASIC ASIC | ||
82 | * SERIAL1 - - - ASIC - ASIC | ||
83 | * SCSI CPU CPU CSR ASIC ASIC ASIC | ||
84 | * ETHERNET CPU * CSR ASIC ASIC ASIC | ||
85 | * other - - - ASIC - - | ||
86 | * TC2 - - CSR CPU ASIC ASIC | ||
87 | * TC1 - - CSR CPU ASIC ASIC | ||
88 | * TC0 - - CSR CPU ASIC ASIC | ||
89 | * other - CPU - CPU ASIC ASIC | ||
90 | * other - - - - CPU CPU | ||
91 | * | ||
92 | * * -- shared with SCSI | ||
93 | */ | ||
94 | |||
95 | int dec_interrupt[DEC_NR_INTS] = { | ||
96 | [0 ... DEC_NR_INTS - 1] = -1 | ||
97 | }; | ||
98 | |||
99 | EXPORT_SYMBOL(dec_interrupt); | ||
100 | |||
101 | int_ptr cpu_mask_nr_tbl[DEC_MAX_CPU_INTS][2] = { | ||
102 | { { .i = ~0 }, { .p = dec_intr_unimplemented } }, | ||
103 | }; | ||
104 | int_ptr asic_mask_nr_tbl[DEC_MAX_ASIC_INTS][2] = { | ||
105 | { { .i = ~0 }, { .p = asic_intr_unimplemented } }, | ||
106 | }; | ||
107 | int cpu_fpu_mask = DEC_CPU_IRQ_MASK(DEC_CPU_INR_FPU); | ||
108 | int *fpu_kstat_irq; | ||
109 | |||
110 | static irq_handler_t busirq_handler; | ||
111 | static unsigned int busirq_flags = IRQF_NO_THREAD; | ||
112 | |||
113 | /* | ||
114 | * Bus error (DBE/IBE exceptions and bus interrupts) handling setup. | ||
115 | */ | ||
116 | static void __init dec_be_init(void) | ||
117 | { | ||
118 | switch (mips_machtype) { | ||
119 | case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */ | ||
120 | board_be_handler = dec_kn01_be_handler; | ||
121 | busirq_handler = dec_kn01_be_interrupt; | ||
122 | busirq_flags |= IRQF_SHARED; | ||
123 | dec_kn01_be_init(); | ||
124 | break; | ||
125 | case MACH_DS5000_1XX: /* DS5000/1xx 3min */ | ||
126 | case MACH_DS5000_XX: /* DS5000/xx Maxine */ | ||
127 | board_be_handler = dec_kn02xa_be_handler; | ||
128 | busirq_handler = dec_kn02xa_be_interrupt; | ||
129 | dec_kn02xa_be_init(); | ||
130 | break; | ||
131 | case MACH_DS5000_200: /* DS5000/200 3max */ | ||
132 | case MACH_DS5000_2X0: /* DS5000/240 3max+ */ | ||
133 | case MACH_DS5900: /* DS5900 bigmax */ | ||
134 | board_be_handler = dec_ecc_be_handler; | ||
135 | busirq_handler = dec_ecc_be_interrupt; | ||
136 | dec_ecc_be_init(); | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | void __init plat_mem_setup(void) | ||
142 | { | ||
143 | board_be_init = dec_be_init; | ||
144 | |||
145 | wbflush_setup(); | ||
146 | |||
147 | _machine_restart = dec_machine_restart; | ||
148 | _machine_halt = dec_machine_halt; | ||
149 | pm_power_off = dec_machine_power_off; | ||
150 | |||
151 | ioport_resource.start = ~0UL; | ||
152 | ioport_resource.end = 0UL; | ||
153 | |||
154 | /* Stay away from the firmware working memory area for now. */ | ||
155 | memblock_reserve(PHYS_OFFSET, __pa_symbol(&_text) - PHYS_OFFSET); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Machine-specific initialisation for KN01, aka DS2100 (aka Pmin) | ||
160 | * or DS3100 (aka Pmax). | ||
161 | */ | ||
162 | static int kn01_interrupt[DEC_NR_INTS] __initdata = { | ||
163 | [DEC_IRQ_CASCADE] = -1, | ||
164 | [DEC_IRQ_AB_RECV] = -1, | ||
165 | [DEC_IRQ_AB_XMIT] = -1, | ||
166 | [DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11), | ||
167 | [DEC_IRQ_ASC] = -1, | ||
168 | [DEC_IRQ_FLOPPY] = -1, | ||
169 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
170 | [DEC_IRQ_HALT] = -1, | ||
171 | [DEC_IRQ_ISDN] = -1, | ||
172 | [DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE), | ||
173 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS), | ||
174 | [DEC_IRQ_PSU] = -1, | ||
175 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC), | ||
176 | [DEC_IRQ_SCC0] = -1, | ||
177 | [DEC_IRQ_SCC1] = -1, | ||
178 | [DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII), | ||
179 | [DEC_IRQ_TC0] = -1, | ||
180 | [DEC_IRQ_TC1] = -1, | ||
181 | [DEC_IRQ_TC2] = -1, | ||
182 | [DEC_IRQ_TIMER] = -1, | ||
183 | [DEC_IRQ_VIDEO] = DEC_CPU_IRQ_NR(KN01_CPU_INR_VIDEO), | ||
184 | [DEC_IRQ_ASC_MERR] = -1, | ||
185 | [DEC_IRQ_ASC_ERR] = -1, | ||
186 | [DEC_IRQ_ASC_DMA] = -1, | ||
187 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
188 | [DEC_IRQ_ISDN_ERR] = -1, | ||
189 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
190 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
191 | [DEC_IRQ_LANCE_MERR] = -1, | ||
192 | [DEC_IRQ_SCC0A_RXERR] = -1, | ||
193 | [DEC_IRQ_SCC0A_RXDMA] = -1, | ||
194 | [DEC_IRQ_SCC0A_TXERR] = -1, | ||
195 | [DEC_IRQ_SCC0A_TXDMA] = -1, | ||
196 | [DEC_IRQ_AB_RXERR] = -1, | ||
197 | [DEC_IRQ_AB_RXDMA] = -1, | ||
198 | [DEC_IRQ_AB_TXERR] = -1, | ||
199 | [DEC_IRQ_AB_TXDMA] = -1, | ||
200 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
201 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
202 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
203 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
204 | }; | ||
205 | |||
206 | static int_ptr kn01_cpu_mask_nr_tbl[][2] __initdata = { | ||
207 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_BUS) }, | ||
208 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS) } }, | ||
209 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_RTC) }, | ||
210 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC) } }, | ||
211 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_DZ11) }, | ||
212 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11) } }, | ||
213 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_SII) }, | ||
214 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII) } }, | ||
215 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_LANCE) }, | ||
216 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE) } }, | ||
217 | { { .i = DEC_CPU_IRQ_ALL }, | ||
218 | { .p = cpu_all_int } }, | ||
219 | }; | ||
220 | |||
221 | static void __init dec_init_kn01(void) | ||
222 | { | ||
223 | /* IRQ routing. */ | ||
224 | memcpy(&dec_interrupt, &kn01_interrupt, | ||
225 | sizeof(kn01_interrupt)); | ||
226 | |||
227 | /* CPU IRQ priorities. */ | ||
228 | memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl, | ||
229 | sizeof(kn01_cpu_mask_nr_tbl)); | ||
230 | |||
231 | mips_cpu_irq_init(); | ||
232 | |||
233 | } /* dec_init_kn01 */ | ||
234 | |||
235 | |||
236 | /* | ||
237 | * Machine-specific initialisation for KN230, aka DS5100, aka MIPSmate. | ||
238 | */ | ||
239 | static int kn230_interrupt[DEC_NR_INTS] __initdata = { | ||
240 | [DEC_IRQ_CASCADE] = -1, | ||
241 | [DEC_IRQ_AB_RECV] = -1, | ||
242 | [DEC_IRQ_AB_XMIT] = -1, | ||
243 | [DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11), | ||
244 | [DEC_IRQ_ASC] = -1, | ||
245 | [DEC_IRQ_FLOPPY] = -1, | ||
246 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
247 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN230_CPU_INR_HALT), | ||
248 | [DEC_IRQ_ISDN] = -1, | ||
249 | [DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN230_CPU_INR_LANCE), | ||
250 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS), | ||
251 | [DEC_IRQ_PSU] = -1, | ||
252 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC), | ||
253 | [DEC_IRQ_SCC0] = -1, | ||
254 | [DEC_IRQ_SCC1] = -1, | ||
255 | [DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII), | ||
256 | [DEC_IRQ_TC0] = -1, | ||
257 | [DEC_IRQ_TC1] = -1, | ||
258 | [DEC_IRQ_TC2] = -1, | ||
259 | [DEC_IRQ_TIMER] = -1, | ||
260 | [DEC_IRQ_VIDEO] = -1, | ||
261 | [DEC_IRQ_ASC_MERR] = -1, | ||
262 | [DEC_IRQ_ASC_ERR] = -1, | ||
263 | [DEC_IRQ_ASC_DMA] = -1, | ||
264 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
265 | [DEC_IRQ_ISDN_ERR] = -1, | ||
266 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
267 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
268 | [DEC_IRQ_LANCE_MERR] = -1, | ||
269 | [DEC_IRQ_SCC0A_RXERR] = -1, | ||
270 | [DEC_IRQ_SCC0A_RXDMA] = -1, | ||
271 | [DEC_IRQ_SCC0A_TXERR] = -1, | ||
272 | [DEC_IRQ_SCC0A_TXDMA] = -1, | ||
273 | [DEC_IRQ_AB_RXERR] = -1, | ||
274 | [DEC_IRQ_AB_RXDMA] = -1, | ||
275 | [DEC_IRQ_AB_TXERR] = -1, | ||
276 | [DEC_IRQ_AB_TXDMA] = -1, | ||
277 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
278 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
279 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
280 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
281 | }; | ||
282 | |||
283 | static int_ptr kn230_cpu_mask_nr_tbl[][2] __initdata = { | ||
284 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_BUS) }, | ||
285 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS) } }, | ||
286 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_RTC) }, | ||
287 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC) } }, | ||
288 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_DZ11) }, | ||
289 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11) } }, | ||
290 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_SII) }, | ||
291 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII) } }, | ||
292 | { { .i = DEC_CPU_IRQ_ALL }, | ||
293 | { .p = cpu_all_int } }, | ||
294 | }; | ||
295 | |||
296 | static void __init dec_init_kn230(void) | ||
297 | { | ||
298 | /* IRQ routing. */ | ||
299 | memcpy(&dec_interrupt, &kn230_interrupt, | ||
300 | sizeof(kn230_interrupt)); | ||
301 | |||
302 | /* CPU IRQ priorities. */ | ||
303 | memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl, | ||
304 | sizeof(kn230_cpu_mask_nr_tbl)); | ||
305 | |||
306 | mips_cpu_irq_init(); | ||
307 | |||
308 | } /* dec_init_kn230 */ | ||
309 | |||
310 | |||
311 | /* | ||
312 | * Machine-specific initialisation for KN02, aka DS5000/200, aka 3max. | ||
313 | */ | ||
314 | static int kn02_interrupt[DEC_NR_INTS] __initdata = { | ||
315 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02_CPU_INR_CASCADE), | ||
316 | [DEC_IRQ_AB_RECV] = -1, | ||
317 | [DEC_IRQ_AB_XMIT] = -1, | ||
318 | [DEC_IRQ_DZ11] = KN02_IRQ_NR(KN02_CSR_INR_DZ11), | ||
319 | [DEC_IRQ_ASC] = KN02_IRQ_NR(KN02_CSR_INR_ASC), | ||
320 | [DEC_IRQ_FLOPPY] = -1, | ||
321 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
322 | [DEC_IRQ_HALT] = -1, | ||
323 | [DEC_IRQ_ISDN] = -1, | ||
324 | [DEC_IRQ_LANCE] = KN02_IRQ_NR(KN02_CSR_INR_LANCE), | ||
325 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS), | ||
326 | [DEC_IRQ_PSU] = -1, | ||
327 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC), | ||
328 | [DEC_IRQ_SCC0] = -1, | ||
329 | [DEC_IRQ_SCC1] = -1, | ||
330 | [DEC_IRQ_SII] = -1, | ||
331 | [DEC_IRQ_TC0] = KN02_IRQ_NR(KN02_CSR_INR_TC0), | ||
332 | [DEC_IRQ_TC1] = KN02_IRQ_NR(KN02_CSR_INR_TC1), | ||
333 | [DEC_IRQ_TC2] = KN02_IRQ_NR(KN02_CSR_INR_TC2), | ||
334 | [DEC_IRQ_TIMER] = -1, | ||
335 | [DEC_IRQ_VIDEO] = -1, | ||
336 | [DEC_IRQ_ASC_MERR] = -1, | ||
337 | [DEC_IRQ_ASC_ERR] = -1, | ||
338 | [DEC_IRQ_ASC_DMA] = -1, | ||
339 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
340 | [DEC_IRQ_ISDN_ERR] = -1, | ||
341 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
342 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
343 | [DEC_IRQ_LANCE_MERR] = -1, | ||
344 | [DEC_IRQ_SCC0A_RXERR] = -1, | ||
345 | [DEC_IRQ_SCC0A_RXDMA] = -1, | ||
346 | [DEC_IRQ_SCC0A_TXERR] = -1, | ||
347 | [DEC_IRQ_SCC0A_TXDMA] = -1, | ||
348 | [DEC_IRQ_AB_RXERR] = -1, | ||
349 | [DEC_IRQ_AB_RXDMA] = -1, | ||
350 | [DEC_IRQ_AB_TXERR] = -1, | ||
351 | [DEC_IRQ_AB_TXDMA] = -1, | ||
352 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
353 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
354 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
355 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
356 | }; | ||
357 | |||
358 | static int_ptr kn02_cpu_mask_nr_tbl[][2] __initdata = { | ||
359 | { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_BUS) }, | ||
360 | { .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS) } }, | ||
361 | { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_RTC) }, | ||
362 | { .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC) } }, | ||
363 | { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_CASCADE) }, | ||
364 | { .p = kn02_io_int } }, | ||
365 | { { .i = DEC_CPU_IRQ_ALL }, | ||
366 | { .p = cpu_all_int } }, | ||
367 | }; | ||
368 | |||
369 | static int_ptr kn02_asic_mask_nr_tbl[][2] __initdata = { | ||
370 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_DZ11) }, | ||
371 | { .i = KN02_IRQ_NR(KN02_CSR_INR_DZ11) } }, | ||
372 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_ASC) }, | ||
373 | { .i = KN02_IRQ_NR(KN02_CSR_INR_ASC) } }, | ||
374 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_LANCE) }, | ||
375 | { .i = KN02_IRQ_NR(KN02_CSR_INR_LANCE) } }, | ||
376 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC2) }, | ||
377 | { .i = KN02_IRQ_NR(KN02_CSR_INR_TC2) } }, | ||
378 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC1) }, | ||
379 | { .i = KN02_IRQ_NR(KN02_CSR_INR_TC1) } }, | ||
380 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC0) }, | ||
381 | { .i = KN02_IRQ_NR(KN02_CSR_INR_TC0) } }, | ||
382 | { { .i = KN02_IRQ_ALL }, | ||
383 | { .p = kn02_all_int } }, | ||
384 | }; | ||
385 | |||
386 | static void __init dec_init_kn02(void) | ||
387 | { | ||
388 | /* IRQ routing. */ | ||
389 | memcpy(&dec_interrupt, &kn02_interrupt, | ||
390 | sizeof(kn02_interrupt)); | ||
391 | |||
392 | /* CPU IRQ priorities. */ | ||
393 | memcpy(&cpu_mask_nr_tbl, &kn02_cpu_mask_nr_tbl, | ||
394 | sizeof(kn02_cpu_mask_nr_tbl)); | ||
395 | |||
396 | /* KN02 CSR IRQ priorities. */ | ||
397 | memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl, | ||
398 | sizeof(kn02_asic_mask_nr_tbl)); | ||
399 | |||
400 | mips_cpu_irq_init(); | ||
401 | init_kn02_irqs(KN02_IRQ_BASE); | ||
402 | |||
403 | } /* dec_init_kn02 */ | ||
404 | |||
405 | |||
406 | /* | ||
407 | * Machine-specific initialisation for KN02-BA, aka DS5000/1xx | ||
408 | * (xx = 20, 25, 33), aka 3min. Also applies to KN04(-BA), aka | ||
409 | * DS5000/150, aka 4min. | ||
410 | */ | ||
411 | static int kn02ba_interrupt[DEC_NR_INTS] __initdata = { | ||
412 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_CASCADE), | ||
413 | [DEC_IRQ_AB_RECV] = -1, | ||
414 | [DEC_IRQ_AB_XMIT] = -1, | ||
415 | [DEC_IRQ_DZ11] = -1, | ||
416 | [DEC_IRQ_ASC] = IO_IRQ_NR(KN02BA_IO_INR_ASC), | ||
417 | [DEC_IRQ_FLOPPY] = -1, | ||
418 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
419 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_HALT), | ||
420 | [DEC_IRQ_ISDN] = -1, | ||
421 | [DEC_IRQ_LANCE] = IO_IRQ_NR(KN02BA_IO_INR_LANCE), | ||
422 | [DEC_IRQ_BUS] = IO_IRQ_NR(KN02BA_IO_INR_BUS), | ||
423 | [DEC_IRQ_PSU] = IO_IRQ_NR(KN02BA_IO_INR_PSU), | ||
424 | [DEC_IRQ_RTC] = IO_IRQ_NR(KN02BA_IO_INR_RTC), | ||
425 | [DEC_IRQ_SCC0] = IO_IRQ_NR(KN02BA_IO_INR_SCC0), | ||
426 | [DEC_IRQ_SCC1] = IO_IRQ_NR(KN02BA_IO_INR_SCC1), | ||
427 | [DEC_IRQ_SII] = -1, | ||
428 | [DEC_IRQ_TC0] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0), | ||
429 | [DEC_IRQ_TC1] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1), | ||
430 | [DEC_IRQ_TC2] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2), | ||
431 | [DEC_IRQ_TIMER] = -1, | ||
432 | [DEC_IRQ_VIDEO] = -1, | ||
433 | [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR), | ||
434 | [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR), | ||
435 | [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA), | ||
436 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
437 | [DEC_IRQ_ISDN_ERR] = -1, | ||
438 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
439 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
440 | [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR), | ||
441 | [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR), | ||
442 | [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA), | ||
443 | [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR), | ||
444 | [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA), | ||
445 | [DEC_IRQ_AB_RXERR] = -1, | ||
446 | [DEC_IRQ_AB_RXDMA] = -1, | ||
447 | [DEC_IRQ_AB_TXERR] = -1, | ||
448 | [DEC_IRQ_AB_TXDMA] = -1, | ||
449 | [DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR), | ||
450 | [DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA), | ||
451 | [DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR), | ||
452 | [DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA), | ||
453 | }; | ||
454 | |||
455 | static int_ptr kn02ba_cpu_mask_nr_tbl[][2] __initdata = { | ||
456 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_CASCADE) }, | ||
457 | { .p = kn02xa_io_int } }, | ||
458 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC2) }, | ||
459 | { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2) } }, | ||
460 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC1) }, | ||
461 | { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1) } }, | ||
462 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC0) }, | ||
463 | { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0) } }, | ||
464 | { { .i = DEC_CPU_IRQ_ALL }, | ||
465 | { .p = cpu_all_int } }, | ||
466 | }; | ||
467 | |||
468 | static int_ptr kn02ba_asic_mask_nr_tbl[][2] __initdata = { | ||
469 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_BUS) }, | ||
470 | { .i = IO_IRQ_NR(KN02BA_IO_INR_BUS) } }, | ||
471 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_RTC) }, | ||
472 | { .i = IO_IRQ_NR(KN02BA_IO_INR_RTC) } }, | ||
473 | { { .i = IO_IRQ_DMA }, | ||
474 | { .p = asic_dma_int } }, | ||
475 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC0) }, | ||
476 | { .i = IO_IRQ_NR(KN02BA_IO_INR_SCC0) } }, | ||
477 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC1) }, | ||
478 | { .i = IO_IRQ_NR(KN02BA_IO_INR_SCC1) } }, | ||
479 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_ASC) }, | ||
480 | { .i = IO_IRQ_NR(KN02BA_IO_INR_ASC) } }, | ||
481 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_LANCE) }, | ||
482 | { .i = IO_IRQ_NR(KN02BA_IO_INR_LANCE) } }, | ||
483 | { { .i = IO_IRQ_ALL }, | ||
484 | { .p = asic_all_int } }, | ||
485 | }; | ||
486 | |||
487 | static void __init dec_init_kn02ba(void) | ||
488 | { | ||
489 | /* IRQ routing. */ | ||
490 | memcpy(&dec_interrupt, &kn02ba_interrupt, | ||
491 | sizeof(kn02ba_interrupt)); | ||
492 | |||
493 | /* CPU IRQ priorities. */ | ||
494 | memcpy(&cpu_mask_nr_tbl, &kn02ba_cpu_mask_nr_tbl, | ||
495 | sizeof(kn02ba_cpu_mask_nr_tbl)); | ||
496 | |||
497 | /* I/O ASIC IRQ priorities. */ | ||
498 | memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl, | ||
499 | sizeof(kn02ba_asic_mask_nr_tbl)); | ||
500 | |||
501 | mips_cpu_irq_init(); | ||
502 | init_ioasic_irqs(IO_IRQ_BASE); | ||
503 | |||
504 | } /* dec_init_kn02ba */ | ||
505 | |||
506 | |||
507 | /* | ||
508 | * Machine-specific initialisation for KN02-CA, aka DS5000/xx, | ||
509 | * (xx = 20, 25, 33), aka MAXine. Also applies to KN04(-CA), aka | ||
510 | * DS5000/50, aka 4MAXine. | ||
511 | */ | ||
512 | static int kn02ca_interrupt[DEC_NR_INTS] __initdata = { | ||
513 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_CASCADE), | ||
514 | [DEC_IRQ_AB_RECV] = IO_IRQ_NR(KN02CA_IO_INR_AB_RECV), | ||
515 | [DEC_IRQ_AB_XMIT] = IO_IRQ_NR(KN02CA_IO_INR_AB_XMIT), | ||
516 | [DEC_IRQ_DZ11] = -1, | ||
517 | [DEC_IRQ_ASC] = IO_IRQ_NR(KN02CA_IO_INR_ASC), | ||
518 | [DEC_IRQ_FLOPPY] = IO_IRQ_NR(KN02CA_IO_INR_FLOPPY), | ||
519 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
520 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_HALT), | ||
521 | [DEC_IRQ_ISDN] = IO_IRQ_NR(KN02CA_IO_INR_ISDN), | ||
522 | [DEC_IRQ_LANCE] = IO_IRQ_NR(KN02CA_IO_INR_LANCE), | ||
523 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS), | ||
524 | [DEC_IRQ_PSU] = -1, | ||
525 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC), | ||
526 | [DEC_IRQ_SCC0] = IO_IRQ_NR(KN02CA_IO_INR_SCC0), | ||
527 | [DEC_IRQ_SCC1] = -1, | ||
528 | [DEC_IRQ_SII] = -1, | ||
529 | [DEC_IRQ_TC0] = IO_IRQ_NR(KN02CA_IO_INR_TC0), | ||
530 | [DEC_IRQ_TC1] = IO_IRQ_NR(KN02CA_IO_INR_TC1), | ||
531 | [DEC_IRQ_TC2] = -1, | ||
532 | [DEC_IRQ_TIMER] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_TIMER), | ||
533 | [DEC_IRQ_VIDEO] = IO_IRQ_NR(KN02CA_IO_INR_VIDEO), | ||
534 | [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR), | ||
535 | [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR), | ||
536 | [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA), | ||
537 | [DEC_IRQ_FLOPPY_ERR] = IO_IRQ_NR(IO_INR_FLOPPY_ERR), | ||
538 | [DEC_IRQ_ISDN_ERR] = IO_IRQ_NR(IO_INR_ISDN_ERR), | ||
539 | [DEC_IRQ_ISDN_RXDMA] = IO_IRQ_NR(IO_INR_ISDN_RXDMA), | ||
540 | [DEC_IRQ_ISDN_TXDMA] = IO_IRQ_NR(IO_INR_ISDN_TXDMA), | ||
541 | [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR), | ||
542 | [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR), | ||
543 | [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA), | ||
544 | [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR), | ||
545 | [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA), | ||
546 | [DEC_IRQ_AB_RXERR] = IO_IRQ_NR(IO_INR_AB_RXERR), | ||
547 | [DEC_IRQ_AB_RXDMA] = IO_IRQ_NR(IO_INR_AB_RXDMA), | ||
548 | [DEC_IRQ_AB_TXERR] = IO_IRQ_NR(IO_INR_AB_TXERR), | ||
549 | [DEC_IRQ_AB_TXDMA] = IO_IRQ_NR(IO_INR_AB_TXDMA), | ||
550 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
551 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
552 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
553 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
554 | }; | ||
555 | |||
556 | static int_ptr kn02ca_cpu_mask_nr_tbl[][2] __initdata = { | ||
557 | { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_BUS) }, | ||
558 | { .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS) } }, | ||
559 | { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_RTC) }, | ||
560 | { .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC) } }, | ||
561 | { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_CASCADE) }, | ||
562 | { .p = kn02xa_io_int } }, | ||
563 | { { .i = DEC_CPU_IRQ_ALL }, | ||
564 | { .p = cpu_all_int } }, | ||
565 | }; | ||
566 | |||
567 | static int_ptr kn02ca_asic_mask_nr_tbl[][2] __initdata = { | ||
568 | { { .i = IO_IRQ_DMA }, | ||
569 | { .p = asic_dma_int } }, | ||
570 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_SCC0) }, | ||
571 | { .i = IO_IRQ_NR(KN02CA_IO_INR_SCC0) } }, | ||
572 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_ASC) }, | ||
573 | { .i = IO_IRQ_NR(KN02CA_IO_INR_ASC) } }, | ||
574 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_LANCE) }, | ||
575 | { .i = IO_IRQ_NR(KN02CA_IO_INR_LANCE) } }, | ||
576 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC1) }, | ||
577 | { .i = IO_IRQ_NR(KN02CA_IO_INR_TC1) } }, | ||
578 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC0) }, | ||
579 | { .i = IO_IRQ_NR(KN02CA_IO_INR_TC0) } }, | ||
580 | { { .i = IO_IRQ_ALL }, | ||
581 | { .p = asic_all_int } }, | ||
582 | }; | ||
583 | |||
584 | static void __init dec_init_kn02ca(void) | ||
585 | { | ||
586 | /* IRQ routing. */ | ||
587 | memcpy(&dec_interrupt, &kn02ca_interrupt, | ||
588 | sizeof(kn02ca_interrupt)); | ||
589 | |||
590 | /* CPU IRQ priorities. */ | ||
591 | memcpy(&cpu_mask_nr_tbl, &kn02ca_cpu_mask_nr_tbl, | ||
592 | sizeof(kn02ca_cpu_mask_nr_tbl)); | ||
593 | |||
594 | /* I/O ASIC IRQ priorities. */ | ||
595 | memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl, | ||
596 | sizeof(kn02ca_asic_mask_nr_tbl)); | ||
597 | |||
598 | mips_cpu_irq_init(); | ||
599 | init_ioasic_irqs(IO_IRQ_BASE); | ||
600 | |||
601 | } /* dec_init_kn02ca */ | ||
602 | |||
603 | |||
604 | /* | ||
605 | * Machine-specific initialisation for KN03, aka DS5000/240, | ||
606 | * aka 3max+ and DS5900, aka BIGmax. Also applies to KN05, aka | ||
607 | * DS5000/260, aka 4max+ and DS5900/260. | ||
608 | */ | ||
609 | static int kn03_interrupt[DEC_NR_INTS] __initdata = { | ||
610 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN03_CPU_INR_CASCADE), | ||
611 | [DEC_IRQ_AB_RECV] = -1, | ||
612 | [DEC_IRQ_AB_XMIT] = -1, | ||
613 | [DEC_IRQ_DZ11] = -1, | ||
614 | [DEC_IRQ_ASC] = IO_IRQ_NR(KN03_IO_INR_ASC), | ||
615 | [DEC_IRQ_FLOPPY] = -1, | ||
616 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
617 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN03_CPU_INR_HALT), | ||
618 | [DEC_IRQ_ISDN] = -1, | ||
619 | [DEC_IRQ_LANCE] = IO_IRQ_NR(KN03_IO_INR_LANCE), | ||
620 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS), | ||
621 | [DEC_IRQ_PSU] = IO_IRQ_NR(KN03_IO_INR_PSU), | ||
622 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC), | ||
623 | [DEC_IRQ_SCC0] = IO_IRQ_NR(KN03_IO_INR_SCC0), | ||
624 | [DEC_IRQ_SCC1] = IO_IRQ_NR(KN03_IO_INR_SCC1), | ||
625 | [DEC_IRQ_SII] = -1, | ||
626 | [DEC_IRQ_TC0] = IO_IRQ_NR(KN03_IO_INR_TC0), | ||
627 | [DEC_IRQ_TC1] = IO_IRQ_NR(KN03_IO_INR_TC1), | ||
628 | [DEC_IRQ_TC2] = IO_IRQ_NR(KN03_IO_INR_TC2), | ||
629 | [DEC_IRQ_TIMER] = -1, | ||
630 | [DEC_IRQ_VIDEO] = -1, | ||
631 | [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR), | ||
632 | [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR), | ||
633 | [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA), | ||
634 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
635 | [DEC_IRQ_ISDN_ERR] = -1, | ||
636 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
637 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
638 | [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR), | ||
639 | [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR), | ||
640 | [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA), | ||
641 | [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR), | ||
642 | [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA), | ||
643 | [DEC_IRQ_AB_RXERR] = -1, | ||
644 | [DEC_IRQ_AB_RXDMA] = -1, | ||
645 | [DEC_IRQ_AB_TXERR] = -1, | ||
646 | [DEC_IRQ_AB_TXDMA] = -1, | ||
647 | [DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR), | ||
648 | [DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA), | ||
649 | [DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR), | ||
650 | [DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA), | ||
651 | }; | ||
652 | |||
653 | static int_ptr kn03_cpu_mask_nr_tbl[][2] __initdata = { | ||
654 | { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_BUS) }, | ||
655 | { .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS) } }, | ||
656 | { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_RTC) }, | ||
657 | { .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC) } }, | ||
658 | { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_CASCADE) }, | ||
659 | { .p = kn03_io_int } }, | ||
660 | { { .i = DEC_CPU_IRQ_ALL }, | ||
661 | { .p = cpu_all_int } }, | ||
662 | }; | ||
663 | |||
664 | static int_ptr kn03_asic_mask_nr_tbl[][2] __initdata = { | ||
665 | { { .i = IO_IRQ_DMA }, | ||
666 | { .p = asic_dma_int } }, | ||
667 | { { .i = IO_IRQ_MASK(KN03_IO_INR_SCC0) }, | ||
668 | { .i = IO_IRQ_NR(KN03_IO_INR_SCC0) } }, | ||
669 | { { .i = IO_IRQ_MASK(KN03_IO_INR_SCC1) }, | ||
670 | { .i = IO_IRQ_NR(KN03_IO_INR_SCC1) } }, | ||
671 | { { .i = IO_IRQ_MASK(KN03_IO_INR_ASC) }, | ||
672 | { .i = IO_IRQ_NR(KN03_IO_INR_ASC) } }, | ||
673 | { { .i = IO_IRQ_MASK(KN03_IO_INR_LANCE) }, | ||
674 | { .i = IO_IRQ_NR(KN03_IO_INR_LANCE) } }, | ||
675 | { { .i = IO_IRQ_MASK(KN03_IO_INR_TC2) }, | ||
676 | { .i = IO_IRQ_NR(KN03_IO_INR_TC2) } }, | ||
677 | { { .i = IO_IRQ_MASK(KN03_IO_INR_TC1) }, | ||
678 | { .i = IO_IRQ_NR(KN03_IO_INR_TC1) } }, | ||
679 | { { .i = IO_IRQ_MASK(KN03_IO_INR_TC0) }, | ||
680 | { .i = IO_IRQ_NR(KN03_IO_INR_TC0) } }, | ||
681 | { { .i = IO_IRQ_ALL }, | ||
682 | { .p = asic_all_int } }, | ||
683 | }; | ||
684 | |||
685 | static void __init dec_init_kn03(void) | ||
686 | { | ||
687 | /* IRQ routing. */ | ||
688 | memcpy(&dec_interrupt, &kn03_interrupt, | ||
689 | sizeof(kn03_interrupt)); | ||
690 | |||
691 | /* CPU IRQ priorities. */ | ||
692 | memcpy(&cpu_mask_nr_tbl, &kn03_cpu_mask_nr_tbl, | ||
693 | sizeof(kn03_cpu_mask_nr_tbl)); | ||
694 | |||
695 | /* I/O ASIC IRQ priorities. */ | ||
696 | memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl, | ||
697 | sizeof(kn03_asic_mask_nr_tbl)); | ||
698 | |||
699 | mips_cpu_irq_init(); | ||
700 | init_ioasic_irqs(IO_IRQ_BASE); | ||
701 | |||
702 | } /* dec_init_kn03 */ | ||
703 | |||
704 | |||
705 | void __init arch_init_irq(void) | ||
706 | { | ||
707 | switch (mips_machtype) { | ||
708 | case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */ | ||
709 | dec_init_kn01(); | ||
710 | break; | ||
711 | case MACH_DS5100: /* DS5100 MIPSmate */ | ||
712 | dec_init_kn230(); | ||
713 | break; | ||
714 | case MACH_DS5000_200: /* DS5000/200 3max */ | ||
715 | dec_init_kn02(); | ||
716 | break; | ||
717 | case MACH_DS5000_1XX: /* DS5000/1xx 3min */ | ||
718 | dec_init_kn02ba(); | ||
719 | break; | ||
720 | case MACH_DS5000_2X0: /* DS5000/240 3max+ */ | ||
721 | case MACH_DS5900: /* DS5900 bigmax */ | ||
722 | dec_init_kn03(); | ||
723 | break; | ||
724 | case MACH_DS5000_XX: /* Personal DS5000/xx */ | ||
725 | dec_init_kn02ca(); | ||
726 | break; | ||
727 | case MACH_DS5800: /* DS5800 Isis */ | ||
728 | panic("Don't know how to set this up!"); | ||
729 | break; | ||
730 | case MACH_DS5400: /* DS5400 MIPSfair */ | ||
731 | panic("Don't know how to set this up!"); | ||
732 | break; | ||
733 | case MACH_DS5500: /* DS5500 MIPSfair-2 */ | ||
734 | panic("Don't know how to set this up!"); | ||
735 | break; | ||
736 | } | ||
737 | |||
738 | /* Free the FPU interrupt if the exception is present. */ | ||
739 | if (!cpu_has_nofpuex) { | ||
740 | cpu_fpu_mask = 0; | ||
741 | dec_interrupt[DEC_IRQ_FPU] = -1; | ||
742 | } | ||
743 | /* Free the halt interrupt unused on R4k systems. */ | ||
744 | if (current_cpu_type() == CPU_R4000SC || | ||
745 | current_cpu_type() == CPU_R4400SC) | ||
746 | dec_interrupt[DEC_IRQ_HALT] = -1; | ||
747 | |||
748 | /* Register board interrupts: FPU and cascade. */ | ||
749 | if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT) && | ||
750 | dec_interrupt[DEC_IRQ_FPU] >= 0 && cpu_has_fpu) { | ||
751 | struct irq_desc *desc_fpu; | ||
752 | int irq_fpu; | ||
753 | |||
754 | irq_fpu = dec_interrupt[DEC_IRQ_FPU]; | ||
755 | if (request_irq(irq_fpu, no_action, IRQF_NO_THREAD, "fpu", | ||
756 | NULL)) | ||
757 | pr_err("Failed to register fpu interrupt\n"); | ||
758 | desc_fpu = irq_to_desc(irq_fpu); | ||
759 | fpu_kstat_irq = this_cpu_ptr(desc_fpu->kstat_irqs); | ||
760 | } | ||
761 | if (dec_interrupt[DEC_IRQ_CASCADE] >= 0) { | ||
762 | if (request_irq(dec_interrupt[DEC_IRQ_CASCADE], no_action, | ||
763 | IRQF_NO_THREAD, "cascade", NULL)) | ||
764 | pr_err("Failed to register cascade interrupt\n"); | ||
765 | } | ||
766 | /* Register the bus error interrupt. */ | ||
767 | if (dec_interrupt[DEC_IRQ_BUS] >= 0 && busirq_handler) { | ||
768 | if (request_irq(dec_interrupt[DEC_IRQ_BUS], busirq_handler, | ||
769 | busirq_flags, "bus error", busirq_handler)) | ||
770 | pr_err("Failed to register bus error interrupt\n"); | ||
771 | } | ||
772 | /* Register the HALT interrupt. */ | ||
773 | if (dec_interrupt[DEC_IRQ_HALT] >= 0) { | ||
774 | if (request_irq(dec_interrupt[DEC_IRQ_HALT], dec_intr_halt, | ||
775 | IRQF_NO_THREAD, "halt", NULL)) | ||
776 | pr_err("Failed to register halt interrupt\n"); | ||
777 | } | ||
778 | } | ||
779 | |||
780 | asmlinkage unsigned int dec_irq_dispatch(unsigned int irq) | ||
781 | { | ||
782 | do_IRQ(irq); | ||
783 | return 0; | ||
784 | } | ||
diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c new file mode 100644 index 000000000..dba583976 --- /dev/null +++ b/arch/mips/dec/tc.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * TURBOchannel architecture calls. | ||
3 | * | ||
4 | * Copyright (c) Harald Koerfgen, 1998 | ||
5 | * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki | ||
6 | * Copyright (c) 2005 James Simmons | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU | ||
9 | * General Public License. See the file "COPYING" in the main | ||
10 | * directory of this archive for more details. | ||
11 | */ | ||
12 | #include <linux/compiler.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/tc.h> | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #include <asm/addrspace.h> | ||
20 | #include <asm/bootinfo.h> | ||
21 | #include <asm/paccess.h> | ||
22 | |||
23 | #include <asm/dec/interrupts.h> | ||
24 | #include <asm/dec/prom.h> | ||
25 | #include <asm/dec/system.h> | ||
26 | |||
27 | /* | ||
28 | * Protected read byte from TURBOchannel slot space. | ||
29 | */ | ||
30 | int tc_preadb(u8 *valp, void __iomem *addr) | ||
31 | { | ||
32 | return get_dbe(*valp, (u8 *)addr); | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * Get TURBOchannel bus information as specified by the spec, plus | ||
37 | * the slot space base address and the number of slots. | ||
38 | */ | ||
39 | int __init tc_bus_get_info(struct tc_bus *tbus) | ||
40 | { | ||
41 | if (!dec_tc_bus) | ||
42 | return -ENXIO; | ||
43 | |||
44 | memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info)); | ||
45 | tbus->slot_base = CPHYSADDR((long)rex_slot_address(0)); | ||
46 | |||
47 | switch (mips_machtype) { | ||
48 | case MACH_DS5000_200: | ||
49 | tbus->num_tcslots = 7; | ||
50 | break; | ||
51 | case MACH_DS5000_2X0: | ||
52 | case MACH_DS5900: | ||
53 | tbus->ext_slot_base = 0x20000000; | ||
54 | tbus->ext_slot_size = 0x20000000; | ||
55 | fallthrough; | ||
56 | case MACH_DS5000_1XX: | ||
57 | tbus->num_tcslots = 3; | ||
58 | break; | ||
59 | case MACH_DS5000_XX: | ||
60 | tbus->num_tcslots = 2; | ||
61 | default: | ||
62 | break; | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Get the IRQ for the specified slot. | ||
69 | */ | ||
70 | void __init tc_device_get_irq(struct tc_dev *tdev) | ||
71 | { | ||
72 | switch (tdev->slot) { | ||
73 | case 0: | ||
74 | tdev->interrupt = dec_interrupt[DEC_IRQ_TC0]; | ||
75 | break; | ||
76 | case 1: | ||
77 | tdev->interrupt = dec_interrupt[DEC_IRQ_TC1]; | ||
78 | break; | ||
79 | case 2: | ||
80 | tdev->interrupt = dec_interrupt[DEC_IRQ_TC2]; | ||
81 | break; | ||
82 | /* | ||
83 | * Yuck! DS5000/200 onboard devices | ||
84 | */ | ||
85 | case 5: | ||
86 | tdev->interrupt = dec_interrupt[DEC_IRQ_TC5]; | ||
87 | break; | ||
88 | case 6: | ||
89 | tdev->interrupt = dec_interrupt[DEC_IRQ_TC6]; | ||
90 | break; | ||
91 | default: | ||
92 | tdev->interrupt = -1; | ||
93 | break; | ||
94 | } | ||
95 | } | ||
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c new file mode 100644 index 000000000..c38686f89 --- /dev/null +++ b/arch/mips/dec/time.c | |||
@@ -0,0 +1,172 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
4 | * Copyright (C) 2000, 2003 Maciej W. Rozycki | ||
5 | * | ||
6 | * This file contains the time handling details for PC-style clocks as | ||
7 | * found in some MIPS systems. | ||
8 | * | ||
9 | */ | ||
10 | #include <linux/bcd.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/mc146818rtc.h> | ||
13 | #include <linux/param.h> | ||
14 | |||
15 | #include <asm/cpu-features.h> | ||
16 | #include <asm/ds1287.h> | ||
17 | #include <asm/time.h> | ||
18 | #include <asm/dec/interrupts.h> | ||
19 | #include <asm/dec/ioasic.h> | ||
20 | #include <asm/dec/machtype.h> | ||
21 | |||
22 | void read_persistent_clock64(struct timespec64 *ts) | ||
23 | { | ||
24 | unsigned int year, mon, day, hour, min, sec, real_year; | ||
25 | unsigned long flags; | ||
26 | |||
27 | spin_lock_irqsave(&rtc_lock, flags); | ||
28 | |||
29 | do { | ||
30 | sec = CMOS_READ(RTC_SECONDS); | ||
31 | min = CMOS_READ(RTC_MINUTES); | ||
32 | hour = CMOS_READ(RTC_HOURS); | ||
33 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
34 | mon = CMOS_READ(RTC_MONTH); | ||
35 | year = CMOS_READ(RTC_YEAR); | ||
36 | /* | ||
37 | * The PROM will reset the year to either '72 or '73. | ||
38 | * Therefore we store the real year separately, in one | ||
39 | * of unused BBU RAM locations. | ||
40 | */ | ||
41 | real_year = CMOS_READ(RTC_DEC_YEAR); | ||
42 | } while (sec != CMOS_READ(RTC_SECONDS)); | ||
43 | |||
44 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
45 | |||
46 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
47 | sec = bcd2bin(sec); | ||
48 | min = bcd2bin(min); | ||
49 | hour = bcd2bin(hour); | ||
50 | day = bcd2bin(day); | ||
51 | mon = bcd2bin(mon); | ||
52 | year = bcd2bin(year); | ||
53 | } | ||
54 | |||
55 | year += real_year - 72 + 2000; | ||
56 | |||
57 | ts->tv_sec = mktime64(year, mon, day, hour, min, sec); | ||
58 | ts->tv_nsec = 0; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * In order to set the CMOS clock precisely, update_persistent_clock64 has to | ||
63 | * be called 500 ms after the second nowtime has started, because when | ||
64 | * nowtime is written into the registers of the CMOS clock, it will | ||
65 | * jump to the next second precisely 500 ms later. Check the Dallas | ||
66 | * DS1287 data sheet for details. | ||
67 | */ | ||
68 | int update_persistent_clock64(struct timespec64 now) | ||
69 | { | ||
70 | time64_t nowtime = now.tv_sec; | ||
71 | int retval = 0; | ||
72 | int real_seconds, real_minutes, cmos_minutes; | ||
73 | unsigned char save_control, save_freq_select; | ||
74 | |||
75 | /* irq are locally disabled here */ | ||
76 | spin_lock(&rtc_lock); | ||
77 | /* tell the clock it's being set */ | ||
78 | save_control = CMOS_READ(RTC_CONTROL); | ||
79 | CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL); | ||
80 | |||
81 | /* stop and reset prescaler */ | ||
82 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
83 | CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
84 | |||
85 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
86 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
87 | cmos_minutes = bcd2bin(cmos_minutes); | ||
88 | |||
89 | /* | ||
90 | * since we're only adjusting minutes and seconds, | ||
91 | * don't interfere with hour overflow. This avoids | ||
92 | * messing with unknown time zones but requires your | ||
93 | * RTC not to be off by more than 15 minutes | ||
94 | */ | ||
95 | real_minutes = div_s64_rem(nowtime, 60, &real_seconds); | ||
96 | if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) | ||
97 | real_minutes += 30; /* correct for half hour time zone */ | ||
98 | real_minutes %= 60; | ||
99 | |||
100 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
101 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
102 | real_seconds = bin2bcd(real_seconds); | ||
103 | real_minutes = bin2bcd(real_minutes); | ||
104 | } | ||
105 | CMOS_WRITE(real_seconds, RTC_SECONDS); | ||
106 | CMOS_WRITE(real_minutes, RTC_MINUTES); | ||
107 | } else { | ||
108 | printk_once(KERN_NOTICE | ||
109 | "set_rtc_mmss: can't update from %d to %d\n", | ||
110 | cmos_minutes, real_minutes); | ||
111 | retval = -1; | ||
112 | } | ||
113 | |||
114 | /* The following flags have to be released exactly in this order, | ||
115 | * otherwise the DS1287 will not reset the oscillator and will not | ||
116 | * update precisely 500 ms later. You won't find this mentioned | ||
117 | * in the Dallas Semiconductor data sheets, but who believes data | ||
118 | * sheets anyway ... -- Markus Kuhn | ||
119 | */ | ||
120 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
121 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
122 | spin_unlock(&rtc_lock); | ||
123 | |||
124 | return retval; | ||
125 | } | ||
126 | |||
127 | void __init plat_time_init(void) | ||
128 | { | ||
129 | int ioasic_clock = 0; | ||
130 | u32 start, end; | ||
131 | int i = HZ / 8; | ||
132 | |||
133 | /* Set up the rate of periodic DS1287 interrupts. */ | ||
134 | ds1287_set_base_clock(HZ); | ||
135 | |||
136 | /* On some I/O ASIC systems we have the I/O ASIC's counter. */ | ||
137 | if (IOASIC) | ||
138 | ioasic_clock = dec_ioasic_clocksource_init() == 0; | ||
139 | if (cpu_has_counter) { | ||
140 | ds1287_timer_state(); | ||
141 | while (!ds1287_timer_state()) | ||
142 | ; | ||
143 | |||
144 | start = read_c0_count(); | ||
145 | |||
146 | while (i--) | ||
147 | while (!ds1287_timer_state()) | ||
148 | ; | ||
149 | |||
150 | end = read_c0_count(); | ||
151 | |||
152 | mips_hpt_frequency = (end - start) * 8; | ||
153 | printk(KERN_INFO "MIPS counter frequency %dHz\n", | ||
154 | mips_hpt_frequency); | ||
155 | |||
156 | /* | ||
157 | * All R4k DECstations suffer from the CP0 Count erratum, | ||
158 | * so we can't use the timer as a clock source, and a clock | ||
159 | * event both at a time. An accurate wall clock is more | ||
160 | * important than a high-precision interval timer so only | ||
161 | * use the timer as a clock source, and not a clock event | ||
162 | * if there's no I/O ASIC counter available to serve as a | ||
163 | * clock source. | ||
164 | */ | ||
165 | if (!ioasic_clock) { | ||
166 | init_r4k_clocksource(); | ||
167 | mips_hpt_frequency = 0; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); | ||
172 | } | ||
diff --git a/arch/mips/dec/wbflush.c b/arch/mips/dec/wbflush.c new file mode 100644 index 000000000..dad64d178 --- /dev/null +++ b/arch/mips/dec/wbflush.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * Setup the right wbflush routine for the different DECstations. | ||
3 | * | ||
4 | * Created with information from: | ||
5 | * DECstation 3100 Desktop Workstation Functional Specification | ||
6 | * DECstation 5000/200 KN02 System Module Functional Specification | ||
7 | * mipsel-linux-objdump --disassemble vmunix | grep "wbflush" :-) | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | * | ||
13 | * Copyright (C) 1998 Harald Koerfgen | ||
14 | * Copyright (C) 2002 Maciej W. Rozycki | ||
15 | */ | ||
16 | |||
17 | #include <linux/export.h> | ||
18 | #include <linux/init.h> | ||
19 | |||
20 | #include <asm/bootinfo.h> | ||
21 | #include <asm/wbflush.h> | ||
22 | #include <asm/barrier.h> | ||
23 | |||
24 | static void wbflush_kn01(void); | ||
25 | static void wbflush_kn210(void); | ||
26 | static void wbflush_mips(void); | ||
27 | |||
28 | void (*__wbflush) (void); | ||
29 | |||
30 | void __init wbflush_setup(void) | ||
31 | { | ||
32 | switch (mips_machtype) { | ||
33 | case MACH_DS23100: | ||
34 | case MACH_DS5000_200: /* DS5000 3max */ | ||
35 | __wbflush = wbflush_kn01; | ||
36 | break; | ||
37 | case MACH_DS5100: /* DS5100 MIPSMATE */ | ||
38 | __wbflush = wbflush_kn210; | ||
39 | break; | ||
40 | case MACH_DS5000_1XX: /* DS5000/100 3min */ | ||
41 | case MACH_DS5000_XX: /* Personal DS5000/2x */ | ||
42 | case MACH_DS5000_2X0: /* DS5000/240 3max+ */ | ||
43 | case MACH_DS5900: /* DS5900 bigmax */ | ||
44 | default: | ||
45 | __wbflush = wbflush_mips; | ||
46 | break; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions | ||
52 | * as part of Coprocessor 0. | ||
53 | */ | ||
54 | static void wbflush_kn01(void) | ||
55 | { | ||
56 | asm(".set\tpush\n\t" | ||
57 | ".set\tnoreorder\n\t" | ||
58 | "1:\tbc0f\t1b\n\t" | ||
59 | "nop\n\t" | ||
60 | ".set\tpop"); | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * For the DS5100 the writeback buffer seems to be a part of Coprocessor 3. | ||
65 | * But CP3 has to enabled first. | ||
66 | */ | ||
67 | static void wbflush_kn210(void) | ||
68 | { | ||
69 | asm(".set\tpush\n\t" | ||
70 | ".set\tnoreorder\n\t" | ||
71 | "mfc0\t$2,$12\n\t" | ||
72 | "lui\t$3,0x8000\n\t" | ||
73 | "or\t$3,$2,$3\n\t" | ||
74 | "mtc0\t$3,$12\n\t" | ||
75 | "nop\n" | ||
76 | "1:\tbc3f\t1b\n\t" | ||
77 | "nop\n\t" | ||
78 | "mtc0\t$2,$12\n\t" | ||
79 | "nop\n\t" | ||
80 | ".set\tpop" | ||
81 | : : : "$2", "$3"); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * I/O ASIC systems use a standard writeback buffer that gets flushed | ||
86 | * upon an uncached read. | ||
87 | */ | ||
88 | static void wbflush_mips(void) | ||
89 | { | ||
90 | __fast_iob(); | ||
91 | } | ||
92 | EXPORT_SYMBOL(__wbflush); | ||