diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/dec |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/mips/dec')
-rw-r--r-- | arch/mips/dec/Makefile | 11 | ||||
-rw-r--r-- | arch/mips/dec/boot/Makefile | 12 | ||||
-rw-r--r-- | arch/mips/dec/boot/decstation.c | 83 | ||||
-rw-r--r-- | arch/mips/dec/boot/ld.ecoff | 43 | ||||
-rw-r--r-- | arch/mips/dec/ecc-berr.c | 280 | ||||
-rw-r--r-- | arch/mips/dec/int-handler.S | 297 | ||||
-rw-r--r-- | arch/mips/dec/ioasic-irq.c | 157 | ||||
-rw-r--r-- | arch/mips/dec/kn02-irq.c | 127 | ||||
-rw-r--r-- | arch/mips/dec/prom/Makefile | 11 | ||||
-rw-r--r-- | arch/mips/dec/prom/call_o32.S | 91 | ||||
-rw-r--r-- | arch/mips/dec/prom/cmdline.c | 39 | ||||
-rw-r--r-- | arch/mips/dec/prom/console.c | 55 | ||||
-rw-r--r-- | arch/mips/dec/prom/dectypes.h | 14 | ||||
-rw-r--r-- | arch/mips/dec/prom/identify.c | 177 | ||||
-rw-r--r-- | arch/mips/dec/prom/init.c | 134 | ||||
-rw-r--r-- | arch/mips/dec/prom/locore.S | 30 | ||||
-rw-r--r-- | arch/mips/dec/prom/memory.c | 130 | ||||
-rw-r--r-- | arch/mips/dec/promcon.c | 55 | ||||
-rw-r--r-- | arch/mips/dec/reset.c | 41 | ||||
-rw-r--r-- | arch/mips/dec/setup.c | 750 | ||||
-rw-r--r-- | arch/mips/dec/time.c | 200 | ||||
-rw-r--r-- | arch/mips/dec/wbflush.c | 94 |
22 files changed, 2831 insertions, 0 deletions
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile new file mode 100644 index 000000000000..688757a97cb8 --- /dev/null +++ b/arch/mips/dec/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for the DECstation family specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn02-irq.o reset.o \ | ||
6 | setup.o time.o | ||
7 | |||
8 | obj-$(CONFIG_PROM_CONSOLE) += promcon.o | ||
9 | obj-$(CONFIG_CPU_HAS_WB) += wbflush.o | ||
10 | |||
11 | EXTRA_AFLAGS := $(CFLAGS) | ||
diff --git a/arch/mips/dec/boot/Makefile b/arch/mips/dec/boot/Makefile new file mode 100644 index 000000000000..bcea41698ef5 --- /dev/null +++ b/arch/mips/dec/boot/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for the DECstation family specific parts of the kernel | ||
3 | # | ||
4 | |||
5 | netboot: all | ||
6 | $(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \ | ||
7 | dec_boot.o ramdisk.img -o nbImage | ||
8 | |||
9 | obj-y := decstation.o | ||
10 | |||
11 | clean: | ||
12 | rm -f nbImage | ||
diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c new file mode 100644 index 000000000000..56fd4277555e --- /dev/null +++ b/arch/mips/dec/boot/decstation.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * arch/mips/dec/decstation.c | ||
3 | */ | ||
4 | |||
5 | #define RELOC | ||
6 | #define INITRD | ||
7 | #define DEBUG_BOOT | ||
8 | |||
9 | /* | ||
10 | * Magic number indicating REX PROM available on DECSTATION. | ||
11 | */ | ||
12 | #define REX_PROM_MAGIC 0x30464354 | ||
13 | |||
14 | #define REX_PROM_CLEARCACHE 0x7c/4 | ||
15 | #define REX_PROM_PRINTF 0x30/4 | ||
16 | |||
17 | #define VEC_RESET 0xBFC00000 /* Prom base address */ | ||
18 | #define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */ | ||
19 | #define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17) | ||
20 | |||
21 | #define PARAM (k_start + 0x2000) | ||
22 | |||
23 | #define LOADER_TYPE (*(unsigned char *) (PARAM+0x210)) | ||
24 | #define INITRD_START (*(unsigned long *) (PARAM+0x218)) | ||
25 | #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) | ||
26 | |||
27 | extern int _ftext, _end; /* begin and end of kernel image */ | ||
28 | extern void kernel_entry(int, char **, unsigned long, int *); | ||
29 | |||
30 | void * memcpy(void * dest, const void *src, unsigned int count) | ||
31 | { | ||
32 | unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src; | ||
33 | |||
34 | count >>= 2; | ||
35 | while (count--) | ||
36 | *tmp++ = *s++; | ||
37 | |||
38 | return dest; | ||
39 | } | ||
40 | |||
41 | void dec_entry(int argc, char **argv, | ||
42 | unsigned long magic, int *prom_vec) | ||
43 | { | ||
44 | void (*rex_clear_cache)(void); | ||
45 | int (*prom_printf)(char *, ...); | ||
46 | unsigned long k_start, len; | ||
47 | |||
48 | /* | ||
49 | * The DS5100 leaves cpu with BEV enabled, clear it. | ||
50 | */ | ||
51 | asm( "lui\t$8,0x3000\n\t" | ||
52 | "mtc0\t$8,$12\n\t" | ||
53 | ".section\t.sdata\n\t" | ||
54 | ".section\t.sbss\n\t" | ||
55 | ".section\t.text" | ||
56 | : : : "$8"); | ||
57 | |||
58 | #ifdef DEBUG_BOOT | ||
59 | if (magic == REX_PROM_MAGIC) { | ||
60 | prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF); | ||
61 | } else { | ||
62 | prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF; | ||
63 | } | ||
64 | prom_printf("Launching kernel...\n"); | ||
65 | #endif | ||
66 | |||
67 | k_start = (unsigned long) (&kernel_entry) & 0xffff0000; | ||
68 | |||
69 | #ifdef RELOC | ||
70 | /* | ||
71 | * Now copy kernel image to its destination. | ||
72 | */ | ||
73 | len = ((unsigned long) (&_end) - k_start); | ||
74 | memcpy((void *)k_start, &_ftext, len); | ||
75 | #endif | ||
76 | |||
77 | if (magic == REX_PROM_MAGIC) { | ||
78 | rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE); | ||
79 | rex_clear_cache(); | ||
80 | } | ||
81 | |||
82 | kernel_entry(argc, argv, magic, prom_vec); | ||
83 | } | ||
diff --git a/arch/mips/dec/boot/ld.ecoff b/arch/mips/dec/boot/ld.ecoff new file mode 100644 index 000000000000..aaa633dfb5f7 --- /dev/null +++ b/arch/mips/dec/boot/ld.ecoff | |||
@@ -0,0 +1,43 @@ | |||
1 | OUTPUT_FORMAT("ecoff-littlemips") | ||
2 | OUTPUT_ARCH(mips) | ||
3 | ENTRY(dec_entry) | ||
4 | SECTIONS | ||
5 | { | ||
6 | . = 0x80200000; | ||
7 | |||
8 | .text : | ||
9 | { | ||
10 | _ftext = .; | ||
11 | *(.text) | ||
12 | *(.fixup) | ||
13 | } | ||
14 | .rdata : | ||
15 | { | ||
16 | *(.rodata .rodata.* .rdata) | ||
17 | } | ||
18 | .data : | ||
19 | { | ||
20 | . = ALIGN(0x1000); | ||
21 | ramdisk.img (.data) | ||
22 | *(.data) | ||
23 | } | ||
24 | .sdata : | ||
25 | { | ||
26 | *(.sdata) | ||
27 | } | ||
28 | _gp = .; | ||
29 | .sbss : | ||
30 | { | ||
31 | *(.sbss) | ||
32 | *(.scommon) | ||
33 | } | ||
34 | .bss : | ||
35 | { | ||
36 | *(.dynbss) | ||
37 | *(.bss) | ||
38 | *(COMMON) | ||
39 | } | ||
40 | /DISCARD/ : { | ||
41 | *(.reginfo .mdebug .note) | ||
42 | } | ||
43 | } | ||
diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c new file mode 100644 index 000000000000..133fb7c48e6c --- /dev/null +++ b/arch/mips/dec/ecc-berr.c | |||
@@ -0,0 +1,280 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/dec/ecc-berr.c | ||
3 | * | ||
4 | * Bus error event handling code for systems equipped with ECC | ||
5 | * handling logic, i.e. DECstation/DECsystem 5000/200 (KN02), | ||
6 | * 5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03), | ||
7 | * 5900/260 (KN05) systems. | ||
8 | * | ||
9 | * Copyright (c) 2003 Maciej W. Rozycki | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/types.h> | ||
22 | |||
23 | #include <asm/addrspace.h> | ||
24 | #include <asm/bootinfo.h> | ||
25 | #include <asm/cpu.h> | ||
26 | #include <asm/processor.h> | ||
27 | #include <asm/system.h> | ||
28 | #include <asm/traps.h> | ||
29 | |||
30 | #include <asm/dec/ecc.h> | ||
31 | #include <asm/dec/kn02.h> | ||
32 | #include <asm/dec/kn03.h> | ||
33 | #include <asm/dec/kn05.h> | ||
34 | |||
35 | static volatile u32 *kn0x_erraddr; | ||
36 | static volatile u32 *kn0x_chksyn; | ||
37 | |||
38 | static inline void dec_ecc_be_ack(void) | ||
39 | { | ||
40 | *kn0x_erraddr = 0; /* any write clears the IRQ */ | ||
41 | iob(); | ||
42 | } | ||
43 | |||
44 | static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker) | ||
45 | { | ||
46 | static const char excstr[] = "exception"; | ||
47 | static const char intstr[] = "interrupt"; | ||
48 | static const char cpustr[] = "CPU"; | ||
49 | static const char dmastr[] = "DMA"; | ||
50 | static const char readstr[] = "read"; | ||
51 | static const char mreadstr[] = "memory read"; | ||
52 | static const char writestr[] = "write"; | ||
53 | static const char mwritstr[] = "partial memory write"; | ||
54 | static const char timestr[] = "timeout"; | ||
55 | static const char overstr[] = "overrun"; | ||
56 | static const char eccstr[] = "ECC error"; | ||
57 | |||
58 | const char *kind, *agent, *cycle, *event; | ||
59 | const char *status = "", *xbit = "", *fmt = ""; | ||
60 | dma_addr_t address; | ||
61 | u16 syn = 0, sngl; | ||
62 | |||
63 | int i = 0; | ||
64 | |||
65 | u32 erraddr = *kn0x_erraddr; | ||
66 | u32 chksyn = *kn0x_chksyn; | ||
67 | int action = MIPS_BE_FATAL; | ||
68 | |||
69 | /* For non-ECC ack ASAP, so any subsequent errors get caught. */ | ||
70 | if ((erraddr & (KN0X_EAR_VALID | KN0X_EAR_ECCERR)) == KN0X_EAR_VALID) | ||
71 | dec_ecc_be_ack(); | ||
72 | |||
73 | kind = invoker ? intstr : excstr; | ||
74 | |||
75 | if (!(erraddr & KN0X_EAR_VALID)) { | ||
76 | /* No idea what happened. */ | ||
77 | printk(KERN_ALERT "Unidentified bus error %s.\n", kind); | ||
78 | return action; | ||
79 | } | ||
80 | |||
81 | agent = (erraddr & KN0X_EAR_CPU) ? cpustr : dmastr; | ||
82 | |||
83 | if (erraddr & KN0X_EAR_ECCERR) { | ||
84 | /* An ECC error on a CPU or DMA transaction. */ | ||
85 | cycle = (erraddr & KN0X_EAR_WRITE) ? mwritstr : mreadstr; | ||
86 | event = eccstr; | ||
87 | } else { | ||
88 | /* A CPU timeout or a DMA overrun. */ | ||
89 | cycle = (erraddr & KN0X_EAR_WRITE) ? writestr : readstr; | ||
90 | event = (erraddr & KN0X_EAR_CPU) ? timestr : overstr; | ||
91 | } | ||
92 | |||
93 | address = erraddr & KN0X_EAR_ADDRESS; | ||
94 | /* For ECC errors on reads adjust for MT pipelining. */ | ||
95 | if ((erraddr & (KN0X_EAR_WRITE | KN0X_EAR_ECCERR)) == KN0X_EAR_ECCERR) | ||
96 | address = (address & ~0xfffLL) | ((address - 5) & 0xfffLL); | ||
97 | address <<= 2; | ||
98 | |||
99 | /* Only CPU errors are fixable. */ | ||
100 | if (erraddr & KN0X_EAR_CPU && is_fixup) | ||
101 | action = MIPS_BE_FIXUP; | ||
102 | |||
103 | if (erraddr & KN0X_EAR_ECCERR) { | ||
104 | static const u8 data_sbit[32] = { | ||
105 | 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, | ||
106 | 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34, | ||
107 | 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, | ||
108 | 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75, | ||
109 | }; | ||
110 | static const u8 data_mbit[25] = { | ||
111 | 0x07, 0x0d, 0x1f, | ||
112 | 0x2f, 0x32, 0x37, 0x38, 0x3b, 0x3d, 0x3e, | ||
113 | 0x43, 0x45, 0x46, 0x49, 0x4c, 0x51, 0x5e, | ||
114 | 0x61, 0x6e, 0x73, 0x76, 0x79, 0x7a, 0x7c, 0x7f, | ||
115 | }; | ||
116 | static const char sbestr[] = "corrected single"; | ||
117 | static const char dbestr[] = "uncorrectable double"; | ||
118 | static const char mbestr[] = "uncorrectable multiple"; | ||
119 | |||
120 | if (!(address & 0x4)) | ||
121 | syn = chksyn; /* Low bank. */ | ||
122 | else | ||
123 | syn = chksyn >> 16; /* High bank. */ | ||
124 | |||
125 | if (!(syn & KN0X_ESR_VLDLO)) { | ||
126 | /* Ack now, no rewrite will happen. */ | ||
127 | dec_ecc_be_ack(); | ||
128 | |||
129 | fmt = KERN_ALERT "%s" "invalid.\n"; | ||
130 | } else { | ||
131 | sngl = syn & KN0X_ESR_SNGLO; | ||
132 | syn &= KN0X_ESR_SYNLO; | ||
133 | |||
134 | /* | ||
135 | * Multibit errors may be tagged incorrectly; | ||
136 | * check the syndrome explicitly. | ||
137 | */ | ||
138 | for (i = 0; i < 25; i++) | ||
139 | if (syn == data_mbit[i]) | ||
140 | break; | ||
141 | |||
142 | if (i < 25) { | ||
143 | status = mbestr; | ||
144 | } else if (!sngl) { | ||
145 | status = dbestr; | ||
146 | } else { | ||
147 | volatile u32 *ptr = (void *)KSEG1ADDR(address); | ||
148 | |||
149 | *ptr = *ptr; /* Rewrite. */ | ||
150 | iob(); | ||
151 | |||
152 | status = sbestr; | ||
153 | action = MIPS_BE_DISCARD; | ||
154 | } | ||
155 | |||
156 | /* Ack now, now we've rewritten (or not). */ | ||
157 | dec_ecc_be_ack(); | ||
158 | |||
159 | if (syn && syn == (syn & -syn)) { | ||
160 | if (syn == 0x01) { | ||
161 | fmt = KERN_ALERT "%s" | ||
162 | "%#04x -- %s bit error " | ||
163 | "at check bit C%s.\n"; | ||
164 | xbit = "X"; | ||
165 | } else { | ||
166 | fmt = KERN_ALERT "%s" | ||
167 | "%#04x -- %s bit error " | ||
168 | "at check bit C%s%u.\n"; | ||
169 | } | ||
170 | i = syn >> 2; | ||
171 | } else { | ||
172 | for (i = 0; i < 32; i++) | ||
173 | if (syn == data_sbit[i]) | ||
174 | break; | ||
175 | if (i < 32) | ||
176 | fmt = KERN_ALERT "%s" | ||
177 | "%#04x -- %s bit error " | ||
178 | "at data bit D%s%u.\n"; | ||
179 | else | ||
180 | fmt = KERN_ALERT "%s" | ||
181 | "%#04x -- %s bit error.\n"; | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | if (action != MIPS_BE_FIXUP) | ||
187 | printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx.\n", | ||
188 | kind, agent, cycle, event, address); | ||
189 | |||
190 | if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR) | ||
191 | printk(fmt, " ECC syndrome ", syn, status, xbit, i); | ||
192 | |||
193 | return action; | ||
194 | } | ||
195 | |||
196 | int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup) | ||
197 | { | ||
198 | return dec_ecc_be_backend(regs, is_fixup, 0); | ||
199 | } | ||
200 | |||
201 | irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
202 | { | ||
203 | int action = dec_ecc_be_backend(regs, 0, 1); | ||
204 | |||
205 | if (action == MIPS_BE_DISCARD) | ||
206 | return IRQ_NONE; | ||
207 | |||
208 | /* | ||
209 | * FIXME: Find affected processes and kill them, otherwise we | ||
210 | * must die. | ||
211 | * | ||
212 | * The interrupt is asynchronously delivered thus EPC and RA | ||
213 | * may be irrelevant, but are printed for a reference. | ||
214 | */ | ||
215 | printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n", | ||
216 | regs->cp0_epc, regs->regs[31]); | ||
217 | die("Unrecoverable bus error", regs); | ||
218 | } | ||
219 | |||
220 | |||
221 | /* | ||
222 | * Initialization differs a bit between KN02 and KN03/KN05, so we | ||
223 | * need two variants. Once set up, all systems can be handled the | ||
224 | * same way. | ||
225 | */ | ||
226 | static inline void dec_kn02_be_init(void) | ||
227 | { | ||
228 | volatile u32 *csr = (void *)KN02_CSR_BASE; | ||
229 | unsigned long flags; | ||
230 | |||
231 | kn0x_erraddr = (void *)(KN02_SLOT_BASE + KN02_ERRADDR); | ||
232 | kn0x_chksyn = (void *)(KN02_SLOT_BASE + KN02_CHKSYN); | ||
233 | |||
234 | spin_lock_irqsave(&kn02_lock, flags); | ||
235 | |||
236 | /* Preset write-only bits of the Control Register cache. */ | ||
237 | cached_kn02_csr = *csr | KN03_CSR_LEDS; | ||
238 | |||
239 | /* Set normal ECC detection and generation. */ | ||
240 | cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN); | ||
241 | /* Enable ECC correction. */ | ||
242 | cached_kn02_csr |= KN02_CSR_CORRECT; | ||
243 | *csr = cached_kn02_csr; | ||
244 | iob(); | ||
245 | |||
246 | spin_unlock_irqrestore(&kn02_lock, flags); | ||
247 | } | ||
248 | |||
249 | static inline void dec_kn03_be_init(void) | ||
250 | { | ||
251 | volatile u32 *mcr = (void *)(KN03_SLOT_BASE + IOASIC_MCR); | ||
252 | volatile u32 *mbcs = (void *)(KN03_SLOT_BASE + KN05_MB_CSR); | ||
253 | |||
254 | kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR); | ||
255 | kn0x_chksyn = (void *)(KN03_SLOT_BASE + IOASIC_CHKSYN); | ||
256 | |||
257 | /* | ||
258 | * Set normal ECC detection and generation, enable ECC correction. | ||
259 | * For KN05 we also need to make sure EE (?) is enabled in the MB. | ||
260 | * Otherwise DBE/IBE exceptions would be masked but bus error | ||
261 | * interrupts would still arrive, resulting in an inevitable crash | ||
262 | * if get_dbe() triggers one. | ||
263 | */ | ||
264 | *mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) | | ||
265 | KN03_MCR_CORRECT; | ||
266 | if (current_cpu_data.cputype == CPU_R4400SC) | ||
267 | *mbcs |= KN05_MB_CSR_EE; | ||
268 | fast_iob(); | ||
269 | } | ||
270 | |||
271 | void __init dec_ecc_be_init(void) | ||
272 | { | ||
273 | if (mips_machtype == MACH_DS5000_200) | ||
274 | dec_kn02_be_init(); | ||
275 | else | ||
276 | dec_kn03_be_init(); | ||
277 | |||
278 | /* Clear any leftover errors from the firmware. */ | ||
279 | dec_ecc_be_ack(); | ||
280 | } | ||
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S new file mode 100644 index 000000000000..3b3790993219 --- /dev/null +++ b/arch/mips/dec/int-handler.S | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * arch/mips/dec/int-handler.S | ||
3 | * | ||
4 | * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen | ||
5 | * Copyright (C) 2000, 2001, 2002, 2003 Maciej W. Rozycki | ||
6 | * | ||
7 | * Written by Ralf Baechle and Andreas Busse, modified for DECStation | ||
8 | * support by Paul Antoine and Harald Koerfgen. | ||
9 | * | ||
10 | * completly rewritten: | ||
11 | * Copyright (C) 1998 Harald Koerfgen | ||
12 | * | ||
13 | * Rewritten extensively for controller-driven IRQ support | ||
14 | * by Maciej W. Rozycki. | ||
15 | */ | ||
16 | #include <linux/config.h> | ||
17 | #include <asm/asm.h> | ||
18 | #include <asm/regdef.h> | ||
19 | #include <asm/mipsregs.h> | ||
20 | #include <asm/stackframe.h> | ||
21 | #include <asm/addrspace.h> | ||
22 | |||
23 | #include <asm/dec/interrupts.h> | ||
24 | #include <asm/dec/ioasic_addrs.h> | ||
25 | #include <asm/dec/ioasic_ints.h> | ||
26 | #include <asm/dec/kn01.h> | ||
27 | #include <asm/dec/kn02.h> | ||
28 | #include <asm/dec/kn02xa.h> | ||
29 | #include <asm/dec/kn03.h> | ||
30 | |||
31 | |||
32 | .text | ||
33 | .set noreorder | ||
34 | /* | ||
35 | * decstation_handle_int: Interrupt handler for DECStations | ||
36 | * | ||
37 | * We follow the model in the Indy interrupt code by David Miller, where he | ||
38 | * says: a lot of complication here is taken away because: | ||
39 | * | ||
40 | * 1) We handle one interrupt and return, sitting in a loop | ||
41 | * and moving across all the pending IRQ bits in the cause | ||
42 | * register is _NOT_ the answer, the common case is one | ||
43 | * pending IRQ so optimize in that direction. | ||
44 | * | ||
45 | * 2) We need not check against bits in the status register | ||
46 | * IRQ mask, that would make this routine slow as hell. | ||
47 | * | ||
48 | * 3) Linux only thinks in terms of all IRQs on or all IRQs | ||
49 | * off, nothing in between like BSD spl() brain-damage. | ||
50 | * | ||
51 | * Furthermore, the IRQs on the DECStations look basically (barring | ||
52 | * software IRQs which we don't use at all) like... | ||
53 | * | ||
54 | * DS2100/3100's, aka kn01, aka Pmax: | ||
55 | * | ||
56 | * MIPS IRQ Source | ||
57 | * -------- ------ | ||
58 | * 0 Software (ignored) | ||
59 | * 1 Software (ignored) | ||
60 | * 2 SCSI | ||
61 | * 3 Lance Ethernet | ||
62 | * 4 DZ11 serial | ||
63 | * 5 RTC | ||
64 | * 6 Memory Controller | ||
65 | * 7 FPU | ||
66 | * | ||
67 | * DS5000/200, aka kn02, aka 3max: | ||
68 | * | ||
69 | * MIPS IRQ Source | ||
70 | * -------- ------ | ||
71 | * 0 Software (ignored) | ||
72 | * 1 Software (ignored) | ||
73 | * 2 TurboChannel | ||
74 | * 3 RTC | ||
75 | * 4 Reserved | ||
76 | * 5 Memory Controller | ||
77 | * 6 Reserved | ||
78 | * 7 FPU | ||
79 | * | ||
80 | * DS5000/1xx's, aka kn02ba, aka 3min: | ||
81 | * | ||
82 | * MIPS IRQ Source | ||
83 | * -------- ------ | ||
84 | * 0 Software (ignored) | ||
85 | * 1 Software (ignored) | ||
86 | * 2 TurboChannel Slot 0 | ||
87 | * 3 TurboChannel Slot 1 | ||
88 | * 4 TurboChannel Slot 2 | ||
89 | * 5 TurboChannel Slot 3 (ASIC) | ||
90 | * 6 Halt button | ||
91 | * 7 FPU/R4k timer | ||
92 | * | ||
93 | * DS5000/2x's, aka kn02ca, aka maxine: | ||
94 | * | ||
95 | * MIPS IRQ Source | ||
96 | * -------- ------ | ||
97 | * 0 Software (ignored) | ||
98 | * 1 Software (ignored) | ||
99 | * 2 Periodic Interrupt (100usec) | ||
100 | * 3 RTC | ||
101 | * 4 I/O write timeout | ||
102 | * 5 TurboChannel (ASIC) | ||
103 | * 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER) | ||
104 | * 7 FPU/R4k timer | ||
105 | * | ||
106 | * DS5000/2xx's, aka kn03, aka 3maxplus: | ||
107 | * | ||
108 | * MIPS IRQ Source | ||
109 | * -------- ------ | ||
110 | * 0 Software (ignored) | ||
111 | * 1 Software (ignored) | ||
112 | * 2 System Board (ASIC) | ||
113 | * 3 RTC | ||
114 | * 4 Reserved | ||
115 | * 5 Memory | ||
116 | * 6 Halt Button | ||
117 | * 7 FPU/R4k timer | ||
118 | * | ||
119 | * We handle the IRQ according to _our_ priority (see setup.c), | ||
120 | * then we just return. If multiple IRQs are pending then we will | ||
121 | * just take another exception, big deal. | ||
122 | */ | ||
123 | .align 5 | ||
124 | NESTED(decstation_handle_int, PT_SIZE, ra) | ||
125 | .set noat | ||
126 | SAVE_ALL | ||
127 | CLI # TEST: interrupts should be off | ||
128 | .set at | ||
129 | .set noreorder | ||
130 | |||
131 | /* | ||
132 | * Get pending Interrupts | ||
133 | */ | ||
134 | mfc0 t0,CP0_CAUSE # get pending interrupts | ||
135 | mfc0 t1,CP0_STATUS | ||
136 | #ifdef CONFIG_MIPS32 | ||
137 | lw t2,cpu_fpu_mask | ||
138 | #endif | ||
139 | andi t0,ST0_IM # CAUSE.CE may be non-zero! | ||
140 | and t0,t1 # isolate allowed ones | ||
141 | |||
142 | beqz t0,spurious | ||
143 | |||
144 | #ifdef CONFIG_MIPS32 | ||
145 | and t2,t0 | ||
146 | bnez t2,fpu # handle FPU immediately | ||
147 | #endif | ||
148 | |||
149 | /* | ||
150 | * Find irq with highest priority | ||
151 | */ | ||
152 | PTR_LA t1,cpu_mask_nr_tbl | ||
153 | 1: lw t2,(t1) | ||
154 | nop | ||
155 | and t2,t0 | ||
156 | beqz t2,1b | ||
157 | addu t1,2*PTRSIZE # delay slot | ||
158 | |||
159 | /* | ||
160 | * Do the low-level stuff | ||
161 | */ | ||
162 | lw a0,(-PTRSIZE)(t1) | ||
163 | nop | ||
164 | bgez a0,handle_it # irq_nr >= 0? | ||
165 | # irq_nr < 0: it is an address | ||
166 | nop | ||
167 | jr a0 | ||
168 | # a trick to save a branch: | ||
169 | lui t2,(KN03_IOASIC_BASE>>16)&0xffff | ||
170 | # upper part of IOASIC Address | ||
171 | |||
172 | /* | ||
173 | * Handle "IRQ Controller" Interrupts | ||
174 | * Masked Interrupts are still visible and have to be masked "by hand". | ||
175 | */ | ||
176 | FEXPORT(kn02_io_int) # 3max | ||
177 | lui t0,(KN02_CSR_BASE>>16)&0xffff | ||
178 | # get interrupt status and mask | ||
179 | lw t0,(t0) | ||
180 | nop | ||
181 | andi t1,t0,KN02_IRQ_ALL | ||
182 | b 1f | ||
183 | srl t0,16 # shift interrupt mask | ||
184 | |||
185 | FEXPORT(kn02xa_io_int) # 3min/maxine | ||
186 | lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff | ||
187 | # upper part of IOASIC Address | ||
188 | |||
189 | FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier) | ||
190 | lw t0,IO_REG_SIR(t2) # get status: IOASIC sir | ||
191 | lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr | ||
192 | nop | ||
193 | |||
194 | 1: and t0,t1 # mask out allowed ones | ||
195 | |||
196 | beqz t0,spurious | ||
197 | |||
198 | /* | ||
199 | * Find irq with highest priority | ||
200 | */ | ||
201 | PTR_LA t1,asic_mask_nr_tbl | ||
202 | 2: lw t2,(t1) | ||
203 | nop | ||
204 | and t2,t0 | ||
205 | beq zero,t2,2b | ||
206 | addu t1,2*PTRSIZE # delay slot | ||
207 | |||
208 | /* | ||
209 | * Do the low-level stuff | ||
210 | */ | ||
211 | lw a0,%lo(-PTRSIZE)(t1) | ||
212 | nop | ||
213 | bgez a0,handle_it # irq_nr >= 0? | ||
214 | # irq_nr < 0: it is an address | ||
215 | nop | ||
216 | jr a0 | ||
217 | nop # delay slot | ||
218 | |||
219 | /* | ||
220 | * Dispatch low-priority interrupts. We reconsider all status | ||
221 | * bits again, which looks like a lose, but it makes the code | ||
222 | * simple and O(log n), so it gets compensated. | ||
223 | */ | ||
224 | FEXPORT(cpu_all_int) # HALT, timers, software junk | ||
225 | li a0,DEC_CPU_IRQ_BASE | ||
226 | srl t0,CAUSEB_IP | ||
227 | li t1,CAUSEF_IP>>CAUSEB_IP # mask | ||
228 | b 1f | ||
229 | li t2,4 # nr of bits / 2 | ||
230 | |||
231 | FEXPORT(kn02_all_int) # impossible ? | ||
232 | li a0,KN02_IRQ_BASE | ||
233 | li t1,KN02_IRQ_ALL # mask | ||
234 | b 1f | ||
235 | li t2,4 # nr of bits / 2 | ||
236 | |||
237 | FEXPORT(asic_all_int) # various I/O ASIC junk | ||
238 | li a0,IO_IRQ_BASE | ||
239 | li t1,IO_IRQ_ALL # mask | ||
240 | b 1f | ||
241 | li t2,8 # nr of bits / 2 | ||
242 | |||
243 | /* | ||
244 | * Dispatch DMA interrupts -- O(log n). | ||
245 | */ | ||
246 | FEXPORT(asic_dma_int) # I/O ASIC DMA events | ||
247 | li a0,IO_IRQ_BASE+IO_INR_DMA | ||
248 | srl t0,IO_INR_DMA | ||
249 | li t1,IO_IRQ_DMA>>IO_INR_DMA # mask | ||
250 | li t2,8 # nr of bits / 2 | ||
251 | |||
252 | /* | ||
253 | * Find irq with highest priority. | ||
254 | * Highest irq number takes precedence. | ||
255 | */ | ||
256 | 1: srlv t3,t1,t2 | ||
257 | 2: xor t1,t3 | ||
258 | and t3,t0,t1 | ||
259 | beqz t3,3f | ||
260 | nop | ||
261 | move t0,t3 | ||
262 | addu a0,t2 | ||
263 | 3: srl t2,1 | ||
264 | bnez t2,2b | ||
265 | srlv t3,t1,t2 | ||
266 | |||
267 | handle_it: | ||
268 | jal do_IRQ | ||
269 | move a1,sp | ||
270 | |||
271 | j ret_from_irq | ||
272 | nop | ||
273 | |||
274 | #ifdef CONFIG_MIPS32 | ||
275 | fpu: | ||
276 | j handle_fpe_int | ||
277 | nop | ||
278 | #endif | ||
279 | |||
280 | spurious: | ||
281 | j spurious_interrupt | ||
282 | nop | ||
283 | END(decstation_handle_int) | ||
284 | |||
285 | /* | ||
286 | * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl | ||
287 | * and asic_mask_nr_tbl are initialized to point all interrupts here. | ||
288 | * The tables are then filled in by machine-specific initialisation | ||
289 | * in dec_setup(). | ||
290 | */ | ||
291 | FEXPORT(dec_intr_unimplemented) | ||
292 | move a1,t0 # cheats way of printing an arg! | ||
293 | PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x"); | ||
294 | |||
295 | FEXPORT(asic_intr_unimplemented) | ||
296 | move a1,t0 # cheats way of printing an arg! | ||
297 | 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 000000000000..d5bca5d233b6 --- /dev/null +++ b/arch/mips/dec/ioasic-irq.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/dec/ioasic-irq.c | ||
3 | * | ||
4 | * DEC I/O ASIC interrupts. | ||
5 | * | ||
6 | * Copyright (c) 2002, 2003 Maciej W. Rozycki | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/types.h> | ||
18 | |||
19 | #include <asm/dec/ioasic.h> | ||
20 | #include <asm/dec/ioasic_addrs.h> | ||
21 | #include <asm/dec/ioasic_ints.h> | ||
22 | |||
23 | |||
24 | static DEFINE_SPINLOCK(ioasic_lock); | ||
25 | |||
26 | static int ioasic_irq_base; | ||
27 | |||
28 | |||
29 | static inline void unmask_ioasic_irq(unsigned int irq) | ||
30 | { | ||
31 | u32 simr; | ||
32 | |||
33 | simr = ioasic_read(IO_REG_SIMR); | ||
34 | simr |= (1 << (irq - ioasic_irq_base)); | ||
35 | ioasic_write(IO_REG_SIMR, simr); | ||
36 | } | ||
37 | |||
38 | static inline void mask_ioasic_irq(unsigned int irq) | ||
39 | { | ||
40 | u32 simr; | ||
41 | |||
42 | simr = ioasic_read(IO_REG_SIMR); | ||
43 | simr &= ~(1 << (irq - ioasic_irq_base)); | ||
44 | ioasic_write(IO_REG_SIMR, simr); | ||
45 | } | ||
46 | |||
47 | static inline void clear_ioasic_irq(unsigned int irq) | ||
48 | { | ||
49 | u32 sir; | ||
50 | |||
51 | sir = ~(1 << (irq - ioasic_irq_base)); | ||
52 | ioasic_write(IO_REG_SIR, sir); | ||
53 | } | ||
54 | |||
55 | static inline void enable_ioasic_irq(unsigned int irq) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | |||
59 | spin_lock_irqsave(&ioasic_lock, flags); | ||
60 | unmask_ioasic_irq(irq); | ||
61 | spin_unlock_irqrestore(&ioasic_lock, flags); | ||
62 | } | ||
63 | |||
64 | static inline void disable_ioasic_irq(unsigned int irq) | ||
65 | { | ||
66 | unsigned long flags; | ||
67 | |||
68 | spin_lock_irqsave(&ioasic_lock, flags); | ||
69 | mask_ioasic_irq(irq); | ||
70 | spin_unlock_irqrestore(&ioasic_lock, flags); | ||
71 | } | ||
72 | |||
73 | |||
74 | static inline unsigned int startup_ioasic_irq(unsigned int irq) | ||
75 | { | ||
76 | enable_ioasic_irq(irq); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | #define shutdown_ioasic_irq disable_ioasic_irq | ||
81 | |||
82 | static inline void ack_ioasic_irq(unsigned int irq) | ||
83 | { | ||
84 | spin_lock(&ioasic_lock); | ||
85 | mask_ioasic_irq(irq); | ||
86 | spin_unlock(&ioasic_lock); | ||
87 | fast_iob(); | ||
88 | } | ||
89 | |||
90 | static inline void end_ioasic_irq(unsigned int irq) | ||
91 | { | ||
92 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
93 | enable_ioasic_irq(irq); | ||
94 | } | ||
95 | |||
96 | static struct hw_interrupt_type ioasic_irq_type = { | ||
97 | .typename = "IO-ASIC", | ||
98 | .startup = startup_ioasic_irq, | ||
99 | .shutdown = shutdown_ioasic_irq, | ||
100 | .enable = enable_ioasic_irq, | ||
101 | .disable = disable_ioasic_irq, | ||
102 | .ack = ack_ioasic_irq, | ||
103 | .end = end_ioasic_irq, | ||
104 | }; | ||
105 | |||
106 | |||
107 | #define startup_ioasic_dma_irq startup_ioasic_irq | ||
108 | |||
109 | #define shutdown_ioasic_dma_irq shutdown_ioasic_irq | ||
110 | |||
111 | #define enable_ioasic_dma_irq enable_ioasic_irq | ||
112 | |||
113 | #define disable_ioasic_dma_irq disable_ioasic_irq | ||
114 | |||
115 | #define ack_ioasic_dma_irq ack_ioasic_irq | ||
116 | |||
117 | static inline void end_ioasic_dma_irq(unsigned int irq) | ||
118 | { | ||
119 | clear_ioasic_irq(irq); | ||
120 | fast_iob(); | ||
121 | end_ioasic_irq(irq); | ||
122 | } | ||
123 | |||
124 | static struct hw_interrupt_type ioasic_dma_irq_type = { | ||
125 | .typename = "IO-ASIC-DMA", | ||
126 | .startup = startup_ioasic_dma_irq, | ||
127 | .shutdown = shutdown_ioasic_dma_irq, | ||
128 | .enable = enable_ioasic_dma_irq, | ||
129 | .disable = disable_ioasic_dma_irq, | ||
130 | .ack = ack_ioasic_dma_irq, | ||
131 | .end = end_ioasic_dma_irq, | ||
132 | }; | ||
133 | |||
134 | |||
135 | void __init init_ioasic_irqs(int base) | ||
136 | { | ||
137 | int i; | ||
138 | |||
139 | /* Mask interrupts. */ | ||
140 | ioasic_write(IO_REG_SIMR, 0); | ||
141 | fast_iob(); | ||
142 | |||
143 | for (i = base; i < base + IO_INR_DMA; i++) { | ||
144 | irq_desc[i].status = IRQ_DISABLED; | ||
145 | irq_desc[i].action = 0; | ||
146 | irq_desc[i].depth = 1; | ||
147 | irq_desc[i].handler = &ioasic_irq_type; | ||
148 | } | ||
149 | for (; i < base + IO_IRQ_LINES; i++) { | ||
150 | irq_desc[i].status = IRQ_DISABLED; | ||
151 | irq_desc[i].action = 0; | ||
152 | irq_desc[i].depth = 1; | ||
153 | irq_desc[i].handler = &ioasic_dma_irq_type; | ||
154 | } | ||
155 | |||
156 | ioasic_irq_base = base; | ||
157 | } | ||
diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c new file mode 100644 index 000000000000..e0bfcd1521e2 --- /dev/null +++ b/arch/mips/dec/kn02-irq.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/dec/kn02-irq.c | ||
3 | * | ||
4 | * DECstation 5000/200 (KN02) Control and Status Register | ||
5 | * interrupts. | ||
6 | * | ||
7 | * Copyright (c) 2002, 2003 Maciej W. Rozycki | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/types.h> | ||
19 | |||
20 | #include <asm/dec/kn02.h> | ||
21 | |||
22 | |||
23 | /* | ||
24 | * Bits 7:0 of the Control Register are write-only -- the | ||
25 | * corresponding bits of the Status Register have a different | ||
26 | * meaning. Hence we use a cache. It speeds up things a bit | ||
27 | * as well. | ||
28 | * | ||
29 | * There is no default value -- it has to be initialized. | ||
30 | */ | ||
31 | u32 cached_kn02_csr; | ||
32 | DEFINE_SPINLOCK(kn02_lock); | ||
33 | |||
34 | |||
35 | static int kn02_irq_base; | ||
36 | |||
37 | |||
38 | static inline void unmask_kn02_irq(unsigned int irq) | ||
39 | { | ||
40 | volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE; | ||
41 | |||
42 | cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16)); | ||
43 | *csr = cached_kn02_csr; | ||
44 | } | ||
45 | |||
46 | static inline void mask_kn02_irq(unsigned int irq) | ||
47 | { | ||
48 | volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE; | ||
49 | |||
50 | cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16)); | ||
51 | *csr = cached_kn02_csr; | ||
52 | } | ||
53 | |||
54 | static inline void enable_kn02_irq(unsigned int irq) | ||
55 | { | ||
56 | unsigned long flags; | ||
57 | |||
58 | spin_lock_irqsave(&kn02_lock, flags); | ||
59 | unmask_kn02_irq(irq); | ||
60 | spin_unlock_irqrestore(&kn02_lock, flags); | ||
61 | } | ||
62 | |||
63 | static inline void disable_kn02_irq(unsigned int irq) | ||
64 | { | ||
65 | unsigned long flags; | ||
66 | |||
67 | spin_lock_irqsave(&kn02_lock, flags); | ||
68 | mask_kn02_irq(irq); | ||
69 | spin_unlock_irqrestore(&kn02_lock, flags); | ||
70 | } | ||
71 | |||
72 | |||
73 | static unsigned int startup_kn02_irq(unsigned int irq) | ||
74 | { | ||
75 | enable_kn02_irq(irq); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | #define shutdown_kn02_irq disable_kn02_irq | ||
80 | |||
81 | static void ack_kn02_irq(unsigned int irq) | ||
82 | { | ||
83 | spin_lock(&kn02_lock); | ||
84 | mask_kn02_irq(irq); | ||
85 | spin_unlock(&kn02_lock); | ||
86 | iob(); | ||
87 | } | ||
88 | |||
89 | static void end_kn02_irq(unsigned int irq) | ||
90 | { | ||
91 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
92 | enable_kn02_irq(irq); | ||
93 | } | ||
94 | |||
95 | static struct hw_interrupt_type kn02_irq_type = { | ||
96 | .typename = "KN02-CSR", | ||
97 | .startup = startup_kn02_irq, | ||
98 | .shutdown = shutdown_kn02_irq, | ||
99 | .enable = enable_kn02_irq, | ||
100 | .disable = disable_kn02_irq, | ||
101 | .ack = ack_kn02_irq, | ||
102 | .end = end_kn02_irq, | ||
103 | }; | ||
104 | |||
105 | |||
106 | void __init init_kn02_irqs(int base) | ||
107 | { | ||
108 | volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE; | ||
109 | unsigned long flags; | ||
110 | int i; | ||
111 | |||
112 | /* Mask interrupts. */ | ||
113 | spin_lock_irqsave(&kn02_lock, flags); | ||
114 | cached_kn02_csr &= ~KN03_CSR_IOINTEN; | ||
115 | *csr = cached_kn02_csr; | ||
116 | iob(); | ||
117 | spin_unlock_irqrestore(&kn02_lock, flags); | ||
118 | |||
119 | for (i = base; i < base + KN02_IRQ_LINES; i++) { | ||
120 | irq_desc[i].status = IRQ_DISABLED; | ||
121 | irq_desc[i].action = 0; | ||
122 | irq_desc[i].depth = 1; | ||
123 | irq_desc[i].handler = &kn02_irq_type; | ||
124 | } | ||
125 | |||
126 | kn02_irq_base = base; | ||
127 | } | ||
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile new file mode 100644 index 000000000000..373822ec2d8c --- /dev/null +++ b/arch/mips/dec/prom/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for the DECstation prom monitor library routines | ||
3 | # under Linux. | ||
4 | # | ||
5 | |||
6 | lib-y += init.o memory.o cmdline.o identify.o console.o | ||
7 | |||
8 | lib-$(CONFIG_MIPS32) += locore.o | ||
9 | lib-$(CONFIG_MIPS64) += call_o32.o | ||
10 | |||
11 | EXTRA_AFLAGS := $(CFLAGS) | ||
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S new file mode 100644 index 000000000000..0dd56db9b3d0 --- /dev/null +++ b/arch/mips/dec/prom/call_o32.S | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * arch/mips/dec/call_o32.S | ||
3 | * | ||
4 | * O32 interface for the 64 (or N32) ABI. | ||
5 | * | ||
6 | * Copyright (C) 2002 Maciej W. Rozycki | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <asm/asm.h> | ||
15 | #include <asm/regdef.h> | ||
16 | |||
17 | /* Maximum number of arguments supported. Must be even! */ | ||
18 | #define O32_ARGC 32 | ||
19 | /* Number of static registers we save. */ | ||
20 | #define O32_STATC 11 | ||
21 | /* Frame size for both of the above. */ | ||
22 | #define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC) | ||
23 | |||
24 | .text | ||
25 | |||
26 | /* | ||
27 | * O32 function call dispatcher, for interfacing 32-bit ROM routines. | ||
28 | * | ||
29 | * The standard 64 (N32) calling sequence is supported, with a0 | ||
30 | * holding a function pointer, a1-a7 -- its first seven arguments | ||
31 | * and the stack -- remaining ones (up to O32_ARGC, including a1-a7). | ||
32 | * Static registers, gp and fp are preserved, v0 holds a result. | ||
33 | * This code relies on the called o32 function for sp and ra | ||
34 | * restoration and thus both this dispatcher and the current stack | ||
35 | * have to be placed in a KSEGx (or KUSEG) address space. Any | ||
36 | * pointers passed have to point to addresses within one of these | ||
37 | * spaces as well. | ||
38 | */ | ||
39 | NESTED(call_o32, O32_FRAMESZ, ra) | ||
40 | REG_SUBU sp,O32_FRAMESZ | ||
41 | |||
42 | REG_S ra,O32_FRAMESZ-1*SZREG(sp) | ||
43 | REG_S fp,O32_FRAMESZ-2*SZREG(sp) | ||
44 | REG_S gp,O32_FRAMESZ-3*SZREG(sp) | ||
45 | REG_S s7,O32_FRAMESZ-4*SZREG(sp) | ||
46 | REG_S s6,O32_FRAMESZ-5*SZREG(sp) | ||
47 | REG_S s5,O32_FRAMESZ-6*SZREG(sp) | ||
48 | REG_S s4,O32_FRAMESZ-7*SZREG(sp) | ||
49 | REG_S s3,O32_FRAMESZ-8*SZREG(sp) | ||
50 | REG_S s2,O32_FRAMESZ-9*SZREG(sp) | ||
51 | REG_S s1,O32_FRAMESZ-10*SZREG(sp) | ||
52 | REG_S s0,O32_FRAMESZ-11*SZREG(sp) | ||
53 | |||
54 | move jp,a0 | ||
55 | |||
56 | sll a0,a1,zero | ||
57 | sll a1,a2,zero | ||
58 | sll a2,a3,zero | ||
59 | sll a3,a4,zero | ||
60 | sw a5,0x10(sp) | ||
61 | sw a6,0x14(sp) | ||
62 | sw a7,0x18(sp) | ||
63 | |||
64 | PTR_LA t0,O32_FRAMESZ(sp) | ||
65 | PTR_LA t1,0x1c(sp) | ||
66 | li t2,O32_ARGC-7 | ||
67 | 1: | ||
68 | lw t3,(t0) | ||
69 | REG_ADDU t0,SZREG | ||
70 | sw t3,(t1) | ||
71 | REG_SUBU t2,1 | ||
72 | REG_ADDU t1,4 | ||
73 | bnez t2,1b | ||
74 | |||
75 | jalr jp | ||
76 | |||
77 | REG_L s0,O32_FRAMESZ-11*SZREG(sp) | ||
78 | REG_L s1,O32_FRAMESZ-10*SZREG(sp) | ||
79 | REG_L s2,O32_FRAMESZ-9*SZREG(sp) | ||
80 | REG_L s3,O32_FRAMESZ-8*SZREG(sp) | ||
81 | REG_L s4,O32_FRAMESZ-7*SZREG(sp) | ||
82 | REG_L s5,O32_FRAMESZ-6*SZREG(sp) | ||
83 | REG_L s6,O32_FRAMESZ-5*SZREG(sp) | ||
84 | REG_L s7,O32_FRAMESZ-4*SZREG(sp) | ||
85 | REG_L gp,O32_FRAMESZ-3*SZREG(sp) | ||
86 | REG_L fp,O32_FRAMESZ-2*SZREG(sp) | ||
87 | REG_L ra,O32_FRAMESZ-1*SZREG(sp) | ||
88 | |||
89 | REG_ADDU sp,O32_FRAMESZ | ||
90 | jr ra | ||
91 | END(call_o32) | ||
diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c new file mode 100644 index 000000000000..c3490bebbc5d --- /dev/null +++ b/arch/mips/dec/prom/cmdline.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * cmdline.c: read the command line passed to us by the PROM. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen | ||
5 | * Copyright (C) 2002, 2004 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/string.h> | ||
10 | #include <linux/types.h> | ||
11 | |||
12 | #include <asm/bootinfo.h> | ||
13 | #include <asm/dec/prom.h> | ||
14 | |||
15 | #undef PROM_DEBUG | ||
16 | |||
17 | void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic) | ||
18 | { | ||
19 | char *arg; | ||
20 | int start_arg, i; | ||
21 | |||
22 | /* | ||
23 | * collect args and prepare cmd_line | ||
24 | */ | ||
25 | if (!prom_is_rex(magic)) | ||
26 | start_arg = 1; | ||
27 | else | ||
28 | start_arg = 2; | ||
29 | for (i = start_arg; i < argc; i++) { | ||
30 | arg = (void *)(long)(argv[i]); | ||
31 | strcat(arcs_cmdline, arg); | ||
32 | if (i < (argc - 1)) | ||
33 | strcat(arcs_cmdline, " "); | ||
34 | } | ||
35 | |||
36 | #ifdef PROM_DEBUG | ||
37 | printk("arcs_cmdline: %s\n", &(arcs_cmdline[0])); | ||
38 | #endif | ||
39 | } | ||
diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c new file mode 100644 index 000000000000..cade16ec7e5a --- /dev/null +++ b/arch/mips/dec/prom/console.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * arch/mips/dec/prom/console.c | ||
3 | * | ||
4 | * DECstation PROM-based early console support. | ||
5 | * | ||
6 | * Copyright (C) 2004 Maciej W. Rozycki | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | #include <linux/console.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | #include <asm/dec/prom.h> | ||
18 | |||
19 | static void __init prom_console_write(struct console *con, const char *s, | ||
20 | unsigned int c) | ||
21 | { | ||
22 | static char sfmt[] __initdata = "%%%us"; | ||
23 | char fmt[13]; | ||
24 | |||
25 | snprintf(fmt, sizeof(fmt), sfmt, c); | ||
26 | prom_printf(fmt, s); | ||
27 | } | ||
28 | |||
29 | static struct console promcons __initdata = { | ||
30 | .name = "prom", | ||
31 | .write = prom_console_write, | ||
32 | .flags = CON_PRINTBUFFER, | ||
33 | .index = -1, | ||
34 | }; | ||
35 | |||
36 | static int promcons_output __initdata = 0; | ||
37 | |||
38 | void __init register_prom_console(void) | ||
39 | { | ||
40 | if (!promcons_output) { | ||
41 | promcons_output = 1; | ||
42 | register_console(&promcons); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | void __init unregister_prom_console(void) | ||
47 | { | ||
48 | if (promcons_output) { | ||
49 | unregister_console(&promcons); | ||
50 | promcons_output = 0; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | void disable_early_printk(void) | ||
55 | __attribute__((alias("unregister_prom_console"))); | ||
diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h new file mode 100644 index 000000000000..707b6f1f5a9d --- /dev/null +++ b/arch/mips/dec/prom/dectypes.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef DECTYPES | ||
2 | #define DECTYPES | ||
3 | |||
4 | #define DS2100_3100 1 /* DS2100/3100 Pmax */ | ||
5 | #define DS5000_200 2 /* DS5000/200 3max */ | ||
6 | #define DS5000_1XX 3 /* DS5000/1xx kmin */ | ||
7 | #define DS5000_2X0 4 /* DS5000/2x0 3max+ */ | ||
8 | #define DS5800 5 /* DS5800 Isis */ | ||
9 | #define DS5400 6 /* DS5400 MIPSfair */ | ||
10 | #define DS5000_XX 7 /* DS5000/xx maxine */ | ||
11 | #define DS5500 11 /* DS5500 MIPSfair-2 */ | ||
12 | #define DS5100 12 /* DS5100 MIPSmate */ | ||
13 | |||
14 | #endif | ||
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c new file mode 100644 index 000000000000..9380588cb15c --- /dev/null +++ b/arch/mips/dec/prom/identify.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * identify.c: machine identification code. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine | ||
5 | * Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/mc146818rtc.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/types.h> | ||
13 | |||
14 | #include <asm/bootinfo.h> | ||
15 | #include <asm/dec/ioasic.h> | ||
16 | #include <asm/dec/ioasic_addrs.h> | ||
17 | #include <asm/dec/kn01.h> | ||
18 | #include <asm/dec/kn02.h> | ||
19 | #include <asm/dec/kn02ba.h> | ||
20 | #include <asm/dec/kn02ca.h> | ||
21 | #include <asm/dec/kn03.h> | ||
22 | #include <asm/dec/kn230.h> | ||
23 | #include <asm/dec/prom.h> | ||
24 | |||
25 | #include "dectypes.h" | ||
26 | |||
27 | extern unsigned long mips_machgroup; | ||
28 | extern unsigned long mips_machtype; | ||
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_rtc_base = (void *)KN01_RTC_BASE; | ||
72 | dec_kn_slot_size = KN01_SLOT_SIZE; | ||
73 | } | ||
74 | |||
75 | static inline void prom_init_kn230(void) | ||
76 | { | ||
77 | dec_rtc_base = (void *)KN01_RTC_BASE; | ||
78 | dec_kn_slot_size = KN01_SLOT_SIZE; | ||
79 | } | ||
80 | |||
81 | static inline void prom_init_kn02(void) | ||
82 | { | ||
83 | dec_rtc_base = (void *)KN02_RTC_BASE; | ||
84 | dec_kn_slot_size = KN02_SLOT_SIZE; | ||
85 | } | ||
86 | |||
87 | static inline void prom_init_kn02xa(void) | ||
88 | { | ||
89 | ioasic_base = (void *)KN02XA_IOASIC_BASE; | ||
90 | dec_rtc_base = (void *)KN02XA_RTC_BASE; | ||
91 | dec_kn_slot_size = IOASIC_SLOT_SIZE; | ||
92 | } | ||
93 | |||
94 | static inline void prom_init_kn03(void) | ||
95 | { | ||
96 | ioasic_base = (void *)KN03_IOASIC_BASE; | ||
97 | dec_rtc_base = (void *)KN03_RTC_BASE; | ||
98 | dec_kn_slot_size = IOASIC_SLOT_SIZE; | ||
99 | } | ||
100 | |||
101 | |||
102 | void __init prom_identify_arch(u32 magic) | ||
103 | { | ||
104 | unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype; | ||
105 | u32 dec_sysid; | ||
106 | |||
107 | if (!prom_is_rex(magic)) { | ||
108 | dec_sysid = simple_strtoul(prom_getenv("systype"), | ||
109 | (char **)0, 0); | ||
110 | } else { | ||
111 | dec_sysid = rex_getsysid(); | ||
112 | if (dec_sysid == 0) { | ||
113 | printk("Zero sysid returned from PROM! " | ||
114 | "Assuming a PMAX-like machine.\n"); | ||
115 | dec_sysid = 1; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | dec_cpunum = (dec_sysid & 0xff000000) >> 24; | ||
120 | dec_systype = (dec_sysid & 0xff0000) >> 16; | ||
121 | dec_firmrev = (dec_sysid & 0xff00) >> 8; | ||
122 | dec_etc = dec_sysid & 0xff; | ||
123 | |||
124 | /* We're obviously one of the DEC machines */ | ||
125 | mips_machgroup = MACH_GROUP_DEC; | ||
126 | |||
127 | /* | ||
128 | * FIXME: This may not be an exhaustive list of DECStations/Servers! | ||
129 | * Put all model-specific initialisation calls here. | ||
130 | */ | ||
131 | switch (dec_systype) { | ||
132 | case DS2100_3100: | ||
133 | mips_machtype = MACH_DS23100; | ||
134 | prom_init_kn01(); | ||
135 | break; | ||
136 | case DS5100: /* DS5100 MIPSMATE */ | ||
137 | mips_machtype = MACH_DS5100; | ||
138 | prom_init_kn230(); | ||
139 | break; | ||
140 | case DS5000_200: /* DS5000 3max */ | ||
141 | mips_machtype = MACH_DS5000_200; | ||
142 | prom_init_kn02(); | ||
143 | break; | ||
144 | case DS5000_1XX: /* DS5000/100 3min */ | ||
145 | mips_machtype = MACH_DS5000_1XX; | ||
146 | prom_init_kn02xa(); | ||
147 | break; | ||
148 | case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */ | ||
149 | mips_machtype = MACH_DS5000_2X0; | ||
150 | prom_init_kn03(); | ||
151 | if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP)) | ||
152 | mips_machtype = MACH_DS5900; | ||
153 | break; | ||
154 | case DS5000_XX: /* Personal DS5000/xx maxine */ | ||
155 | mips_machtype = MACH_DS5000_XX; | ||
156 | prom_init_kn02xa(); | ||
157 | break; | ||
158 | case DS5800: /* DS5800 Isis */ | ||
159 | mips_machtype = MACH_DS5800; | ||
160 | break; | ||
161 | case DS5400: /* DS5400 MIPSfair */ | ||
162 | mips_machtype = MACH_DS5400; | ||
163 | break; | ||
164 | case DS5500: /* DS5500 MIPSfair-2 */ | ||
165 | mips_machtype = MACH_DS5500; | ||
166 | break; | ||
167 | default: | ||
168 | mips_machtype = MACH_DSUNKNOWN; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | if (mips_machtype == MACH_DSUNKNOWN) | ||
173 | printk("This is an %s, id is %x\n", | ||
174 | dec_system_strings[mips_machtype], dec_systype); | ||
175 | else | ||
176 | printk("This is a %s\n", dec_system_strings[mips_machtype]); | ||
177 | } | ||
diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c new file mode 100644 index 000000000000..60f74256e689 --- /dev/null +++ b/arch/mips/dec/prom/init.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * init.c: PROM library initialisation code. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen | ||
5 | * Copyright (C) 2002, 2004 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/config.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/smp.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/types.h> | ||
12 | |||
13 | #include <asm/bootinfo.h> | ||
14 | #include <asm/cpu.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | #include <asm/dec/prom.h> | ||
18 | |||
19 | |||
20 | int (*__rex_bootinit)(void); | ||
21 | int (*__rex_bootread)(void); | ||
22 | int (*__rex_getbitmap)(memmap *); | ||
23 | unsigned long *(*__rex_slot_address)(int); | ||
24 | void *(*__rex_gettcinfo)(void); | ||
25 | int (*__rex_getsysid)(void); | ||
26 | void (*__rex_clear_cache)(void); | ||
27 | |||
28 | int (*__prom_getchar)(void); | ||
29 | char *(*__prom_getenv)(char *); | ||
30 | int (*__prom_printf)(char *, ...); | ||
31 | |||
32 | int (*__pmax_open)(char*, int); | ||
33 | int (*__pmax_lseek)(int, long, int); | ||
34 | int (*__pmax_read)(int, void *, int); | ||
35 | int (*__pmax_close)(int); | ||
36 | |||
37 | |||
38 | /* | ||
39 | * Detect which PROM the DECSTATION has, and set the callback vectors | ||
40 | * appropriately. | ||
41 | */ | ||
42 | void __init which_prom(s32 magic, s32 *prom_vec) | ||
43 | { | ||
44 | /* | ||
45 | * No sign of the REX PROM's magic number means we assume a non-REX | ||
46 | * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx) | ||
47 | */ | ||
48 | if (prom_is_rex(magic)) { | ||
49 | /* | ||
50 | * Set up prom abstraction structure with REX entry points. | ||
51 | */ | ||
52 | __rex_bootinit = | ||
53 | (void *)(long)*(prom_vec + REX_PROM_BOOTINIT); | ||
54 | __rex_bootread = | ||
55 | (void *)(long)*(prom_vec + REX_PROM_BOOTREAD); | ||
56 | __rex_getbitmap = | ||
57 | (void *)(long)*(prom_vec + REX_PROM_GETBITMAP); | ||
58 | __prom_getchar = | ||
59 | (void *)(long)*(prom_vec + REX_PROM_GETCHAR); | ||
60 | __prom_getenv = | ||
61 | (void *)(long)*(prom_vec + REX_PROM_GETENV); | ||
62 | __rex_getsysid = | ||
63 | (void *)(long)*(prom_vec + REX_PROM_GETSYSID); | ||
64 | __rex_gettcinfo = | ||
65 | (void *)(long)*(prom_vec + REX_PROM_GETTCINFO); | ||
66 | __prom_printf = | ||
67 | (void *)(long)*(prom_vec + REX_PROM_PRINTF); | ||
68 | __rex_slot_address = | ||
69 | (void *)(long)*(prom_vec + REX_PROM_SLOTADDR); | ||
70 | __rex_clear_cache = | ||
71 | (void *)(long)*(prom_vec + REX_PROM_CLEARCACHE); | ||
72 | } else { | ||
73 | /* | ||
74 | * Set up prom abstraction structure with non-REX entry points. | ||
75 | */ | ||
76 | __prom_getchar = (void *)PMAX_PROM_GETCHAR; | ||
77 | __prom_getenv = (void *)PMAX_PROM_GETENV; | ||
78 | __prom_printf = (void *)PMAX_PROM_PRINTF; | ||
79 | __pmax_open = (void *)PMAX_PROM_OPEN; | ||
80 | __pmax_lseek = (void *)PMAX_PROM_LSEEK; | ||
81 | __pmax_read = (void *)PMAX_PROM_READ; | ||
82 | __pmax_close = (void *)PMAX_PROM_CLOSE; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | void __init prom_init(void) | ||
87 | { | ||
88 | extern void dec_machine_halt(void); | ||
89 | static char cpu_msg[] __initdata = | ||
90 | "Sorry, this kernel is compiled for a wrong CPU type!\n"; | ||
91 | static char r3k_msg[] __initdata = | ||
92 | "Please recompile with \"CONFIG_CPU_R3000 = y\".\n"; | ||
93 | static char r4k_msg[] __initdata = | ||
94 | "Please recompile with \"CONFIG_CPU_R4x00 = y\".\n"; | ||
95 | s32 argc = fw_arg0; | ||
96 | s32 argv = fw_arg1; | ||
97 | u32 magic = fw_arg2; | ||
98 | s32 prom_vec = fw_arg3; | ||
99 | |||
100 | /* | ||
101 | * Determine which PROM we have | ||
102 | * (and therefore which machine we're on!) | ||
103 | */ | ||
104 | which_prom(magic, prom_vec); | ||
105 | |||
106 | if (prom_is_rex(magic)) | ||
107 | rex_clear_cache(); | ||
108 | |||
109 | /* Register the early console. */ | ||
110 | register_prom_console(); | ||
111 | |||
112 | /* Were we compiled with the right CPU option? */ | ||
113 | #if defined(CONFIG_CPU_R3000) | ||
114 | if ((current_cpu_data.cputype == CPU_R4000SC) || | ||
115 | (current_cpu_data.cputype == CPU_R4400SC)) { | ||
116 | printk(cpu_msg); | ||
117 | printk(r4k_msg); | ||
118 | dec_machine_halt(); | ||
119 | } | ||
120 | #endif | ||
121 | |||
122 | #if defined(CONFIG_CPU_R4X00) | ||
123 | if ((current_cpu_data.cputype == CPU_R3000) || | ||
124 | (current_cpu_data.cputype == CPU_R3000A)) { | ||
125 | printk(cpu_msg); | ||
126 | printk(r3k_msg); | ||
127 | dec_machine_halt(); | ||
128 | } | ||
129 | #endif | ||
130 | |||
131 | prom_meminit(magic); | ||
132 | prom_identify_arch(magic); | ||
133 | prom_init_cmdline(argc, argv, magic); | ||
134 | } | ||
diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S new file mode 100644 index 000000000000..d9acdcefee81 --- /dev/null +++ b/arch/mips/dec/prom/locore.S | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * locore.S | ||
3 | */ | ||
4 | #include <asm/asm.h> | ||
5 | #include <asm/regdef.h> | ||
6 | #include <asm/mipsregs.h> | ||
7 | |||
8 | .text | ||
9 | |||
10 | /* | ||
11 | * Simple general exception handling routine. This one is used for the | ||
12 | * Memory sizing routine for pmax machines. HK | ||
13 | */ | ||
14 | |||
15 | NESTED(genexcept_early, 0, sp) | ||
16 | .set noat | ||
17 | .set noreorder | ||
18 | |||
19 | mfc0 k0, CP0_STATUS | ||
20 | la k1, mem_err | ||
21 | |||
22 | sw k0, 0(k1) | ||
23 | |||
24 | mfc0 k0, CP0_EPC | ||
25 | nop | ||
26 | addiu k0, 4 # skip the causing instruction | ||
27 | jr k0 | ||
28 | rfe | ||
29 | END(genexcept_early) | ||
30 | |||
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c new file mode 100644 index 000000000000..e4f6f26425ea --- /dev/null +++ b/arch/mips/dec/prom/memory.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * memory.c: memory initialisation code. | ||
3 | * | ||
4 | * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine | ||
5 | * Copyright (C) 2000, 2002 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/config.h> | ||
8 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/bootmem.h> | ||
12 | #include <linux/types.h> | ||
13 | |||
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/bootinfo.h> | ||
16 | #include <asm/dec/machtype.h> | ||
17 | #include <asm/dec/prom.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/sections.h> | ||
20 | |||
21 | |||
22 | volatile unsigned long mem_err = 0; /* So we know an error occurred */ | ||
23 | |||
24 | /* | ||
25 | * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen | ||
26 | * off the end of real memory. Only suitable for the 2100/3100's (PMAX). | ||
27 | */ | ||
28 | |||
29 | #define CHUNK_SIZE 0x400000 | ||
30 | |||
31 | static inline void pmax_setup_memory_region(void) | ||
32 | { | ||
33 | volatile unsigned char *memory_page, dummy; | ||
34 | char old_handler[0x80]; | ||
35 | extern char genexcept_early; | ||
36 | |||
37 | /* Install exception handler */ | ||
38 | memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80); | ||
39 | memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80); | ||
40 | |||
41 | /* read unmapped and uncached (KSEG1) | ||
42 | * DECstations have at least 4MB RAM | ||
43 | * Assume less than 480MB of RAM, as this is max for 5000/2xx | ||
44 | * FIXME this should be replaced by the first free page! | ||
45 | */ | ||
46 | for (memory_page = (unsigned char *) KSEG1 + CHUNK_SIZE; | ||
47 | (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000)); | ||
48 | memory_page += CHUNK_SIZE) { | ||
49 | dummy = *memory_page; | ||
50 | } | ||
51 | memcpy((void *)(KSEG0 + 0x80), &old_handler, 0x80); | ||
52 | |||
53 | add_memory_region(0, (unsigned long)memory_page - KSEG1 - CHUNK_SIZE, | ||
54 | BOOT_MEM_RAM); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * Use the REX prom calls to get hold of the memory bitmap, and thence | ||
59 | * determine memory size. | ||
60 | */ | ||
61 | static inline void rex_setup_memory_region(void) | ||
62 | { | ||
63 | int i, bitmap_size; | ||
64 | unsigned long mem_start = 0, mem_size = 0; | ||
65 | memmap *bm; | ||
66 | |||
67 | /* some free 64k */ | ||
68 | bm = (memmap *)KSEG0ADDR(0x28000); | ||
69 | |||
70 | bitmap_size = rex_getbitmap(bm); | ||
71 | |||
72 | for (i = 0; i < bitmap_size; i++) { | ||
73 | /* FIXME: very simplistically only add full sets of pages */ | ||
74 | if (bm->bitmap[i] == 0xff) | ||
75 | mem_size += (8 * bm->pagesize); | ||
76 | else if (!mem_size) | ||
77 | mem_start += (8 * bm->pagesize); | ||
78 | else { | ||
79 | add_memory_region(mem_start, mem_size, BOOT_MEM_RAM); | ||
80 | mem_start += mem_size + (8 * bm->pagesize); | ||
81 | mem_size = 0; | ||
82 | } | ||
83 | } | ||
84 | if (mem_size) | ||
85 | add_memory_region(mem_start, mem_size, BOOT_MEM_RAM); | ||
86 | } | ||
87 | |||
88 | void __init prom_meminit(u32 magic) | ||
89 | { | ||
90 | if (!prom_is_rex(magic)) | ||
91 | pmax_setup_memory_region(); | ||
92 | else | ||
93 | rex_setup_memory_region(); | ||
94 | } | ||
95 | |||
96 | unsigned long __init prom_free_prom_memory(void) | ||
97 | { | ||
98 | unsigned long addr, end; | ||
99 | |||
100 | /* | ||
101 | * Free everything below the kernel itself but leave | ||
102 | * the first page reserved for the exception handlers. | ||
103 | */ | ||
104 | |||
105 | #if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE) | ||
106 | /* | ||
107 | * Leave 128 KB reserved for Lance memory for | ||
108 | * IOASIC DECstations. | ||
109 | * | ||
110 | * XXX: save this address for use in dec_lance.c? | ||
111 | */ | ||
112 | if (IOASIC) | ||
113 | end = __pa(&_text) - 0x00020000; | ||
114 | else | ||
115 | #endif | ||
116 | end = __pa(&_text); | ||
117 | |||
118 | addr = PAGE_SIZE; | ||
119 | while (addr < end) { | ||
120 | ClearPageReserved(virt_to_page(__va(addr))); | ||
121 | set_page_count(virt_to_page(__va(addr)), 1); | ||
122 | free_page((unsigned long)__va(addr)); | ||
123 | addr += PAGE_SIZE; | ||
124 | } | ||
125 | |||
126 | printk("Freeing unused PROM memory: %ldk freed\n", | ||
127 | (end - PAGE_SIZE) >> 10); | ||
128 | |||
129 | return end - PAGE_SIZE; | ||
130 | } | ||
diff --git a/arch/mips/dec/promcon.c b/arch/mips/dec/promcon.c new file mode 100644 index 000000000000..9f0972f5a702 --- /dev/null +++ b/arch/mips/dec/promcon.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Wrap-around code for a console using the | ||
3 | * DECstation PROM io-routines. | ||
4 | * | ||
5 | * Copyright (c) 1998 Harald Koerfgen | ||
6 | */ | ||
7 | |||
8 | #include <linux/tty.h> | ||
9 | #include <linux/ptrace.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/console.h> | ||
12 | #include <linux/fs.h> | ||
13 | |||
14 | #include <asm/dec/prom.h> | ||
15 | |||
16 | static void prom_console_write(struct console *co, const char *s, | ||
17 | unsigned count) | ||
18 | { | ||
19 | unsigned i; | ||
20 | |||
21 | /* | ||
22 | * Now, do each character | ||
23 | */ | ||
24 | for (i = 0; i < count; i++) { | ||
25 | if (*s == 10) | ||
26 | prom_printf("%c", 13); | ||
27 | prom_printf("%c", *s++); | ||
28 | } | ||
29 | } | ||
30 | |||
31 | static int __init prom_console_setup(struct console *co, char *options) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static struct console sercons = | ||
37 | { | ||
38 | .name = "ttyS", | ||
39 | .write = prom_console_write, | ||
40 | .setup = prom_console_setup, | ||
41 | .flags = CON_PRINTBUFFER, | ||
42 | .index = -1, | ||
43 | }; | ||
44 | |||
45 | /* | ||
46 | * Register console. | ||
47 | */ | ||
48 | |||
49 | static int __init prom_console_init(void) | ||
50 | { | ||
51 | register_console(&sercons); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | console_initcall(prom_console_init); | ||
diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c new file mode 100644 index 000000000000..7e4d34d0573d --- /dev/null +++ b/arch/mips/dec/reset.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Reset a DECstation machine. | ||
3 | * | ||
4 | * Copyright (C) 199x the Anonymous | ||
5 | * Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki | ||
6 | */ | ||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/linkage.h> | ||
9 | |||
10 | #include <asm/addrspace.h> | ||
11 | #include <asm/ptrace.h> | ||
12 | |||
13 | typedef void ATTRIB_NORET (* noret_func_t)(void); | ||
14 | |||
15 | static inline void ATTRIB_NORET back_to_prom(void) | ||
16 | { | ||
17 | noret_func_t func = (void *) KSEG1ADDR(0x1fc00000); | ||
18 | |||
19 | func(); | ||
20 | } | ||
21 | |||
22 | void ATTRIB_NORET dec_machine_restart(char *command) | ||
23 | { | ||
24 | back_to_prom(); | ||
25 | } | ||
26 | |||
27 | void ATTRIB_NORET dec_machine_halt(void) | ||
28 | { | ||
29 | back_to_prom(); | ||
30 | } | ||
31 | |||
32 | void ATTRIB_NORET 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, struct pt_regs *regs) | ||
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 000000000000..6a69309baf40 --- /dev/null +++ b/arch/mips/dec/setup.c | |||
@@ -0,0 +1,750 @@ | |||
1 | /* | ||
2 | * Setup the interrupt stuff. | ||
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 Maciej W. Rozycki | ||
10 | */ | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/param.h> | ||
14 | #include <linux/console.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/types.h> | ||
19 | |||
20 | #include <asm/bootinfo.h> | ||
21 | #include <asm/cpu.h> | ||
22 | #include <asm/cpu-features.h> | ||
23 | #include <asm/irq.h> | ||
24 | #include <asm/irq_cpu.h> | ||
25 | #include <asm/mipsregs.h> | ||
26 | #include <asm/reboot.h> | ||
27 | #include <asm/time.h> | ||
28 | #include <asm/traps.h> | ||
29 | #include <asm/wbflush.h> | ||
30 | |||
31 | #include <asm/dec/interrupts.h> | ||
32 | #include <asm/dec/ioasic.h> | ||
33 | #include <asm/dec/ioasic_addrs.h> | ||
34 | #include <asm/dec/ioasic_ints.h> | ||
35 | #include <asm/dec/kn01.h> | ||
36 | #include <asm/dec/kn02.h> | ||
37 | #include <asm/dec/kn02ba.h> | ||
38 | #include <asm/dec/kn02ca.h> | ||
39 | #include <asm/dec/kn03.h> | ||
40 | #include <asm/dec/kn230.h> | ||
41 | |||
42 | |||
43 | extern void dec_machine_restart(char *command); | ||
44 | extern void dec_machine_halt(void); | ||
45 | extern void dec_machine_power_off(void); | ||
46 | extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs); | ||
47 | |||
48 | extern asmlinkage void decstation_handle_int(void); | ||
49 | |||
50 | spinlock_t ioasic_ssr_lock; | ||
51 | |||
52 | volatile u32 *ioasic_base; | ||
53 | unsigned long dec_kn_slot_size; | ||
54 | |||
55 | /* | ||
56 | * IRQ routing and priority tables. Priorites are set as follows: | ||
57 | * | ||
58 | * KN01 KN230 KN02 KN02-BA KN02-CA KN03 | ||
59 | * | ||
60 | * MEMORY CPU CPU CPU ASIC CPU CPU | ||
61 | * RTC CPU CPU CPU ASIC CPU CPU | ||
62 | * DMA - - - ASIC ASIC ASIC | ||
63 | * SERIAL0 CPU CPU CSR ASIC ASIC ASIC | ||
64 | * SERIAL1 - - - ASIC - ASIC | ||
65 | * SCSI CPU CPU CSR ASIC ASIC ASIC | ||
66 | * ETHERNET CPU * CSR ASIC ASIC ASIC | ||
67 | * other - - - ASIC - - | ||
68 | * TC2 - - CSR CPU ASIC ASIC | ||
69 | * TC1 - - CSR CPU ASIC ASIC | ||
70 | * TC0 - - CSR CPU ASIC ASIC | ||
71 | * other - CPU - CPU ASIC ASIC | ||
72 | * other - - - - CPU CPU | ||
73 | * | ||
74 | * * -- shared with SCSI | ||
75 | */ | ||
76 | |||
77 | int dec_interrupt[DEC_NR_INTS] = { | ||
78 | [0 ... DEC_NR_INTS - 1] = -1 | ||
79 | }; | ||
80 | int_ptr cpu_mask_nr_tbl[DEC_MAX_CPU_INTS][2] = { | ||
81 | { { .i = ~0 }, { .p = dec_intr_unimplemented } }, | ||
82 | }; | ||
83 | int_ptr asic_mask_nr_tbl[DEC_MAX_ASIC_INTS][2] = { | ||
84 | { { .i = ~0 }, { .p = asic_intr_unimplemented } }, | ||
85 | }; | ||
86 | int cpu_fpu_mask = DEC_CPU_IRQ_MASK(DEC_CPU_INR_FPU); | ||
87 | |||
88 | static struct irqaction ioirq = { | ||
89 | .handler = no_action, | ||
90 | .name = "cascade", | ||
91 | }; | ||
92 | static struct irqaction fpuirq = { | ||
93 | .handler = no_action, | ||
94 | .name = "fpu", | ||
95 | }; | ||
96 | |||
97 | static struct irqaction busirq = { | ||
98 | .flags = SA_INTERRUPT, | ||
99 | .name = "bus error", | ||
100 | }; | ||
101 | |||
102 | static struct irqaction haltirq = { | ||
103 | .handler = dec_intr_halt, | ||
104 | .name = "halt", | ||
105 | }; | ||
106 | |||
107 | |||
108 | /* | ||
109 | * Bus error (DBE/IBE exceptions and bus interrupts) handling setup. | ||
110 | */ | ||
111 | void __init dec_be_init(void) | ||
112 | { | ||
113 | switch (mips_machtype) { | ||
114 | case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */ | ||
115 | busirq.flags |= SA_SHIRQ; | ||
116 | break; | ||
117 | case MACH_DS5000_200: /* DS5000/200 3max */ | ||
118 | case MACH_DS5000_2X0: /* DS5000/240 3max+ */ | ||
119 | case MACH_DS5900: /* DS5900 bigmax */ | ||
120 | board_be_handler = dec_ecc_be_handler; | ||
121 | busirq.handler = dec_ecc_be_interrupt; | ||
122 | dec_ecc_be_init(); | ||
123 | break; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | |||
128 | extern void dec_time_init(void); | ||
129 | extern void dec_timer_setup(struct irqaction *); | ||
130 | |||
131 | static void __init decstation_setup(void) | ||
132 | { | ||
133 | board_be_init = dec_be_init; | ||
134 | board_time_init = dec_time_init; | ||
135 | board_timer_setup = dec_timer_setup; | ||
136 | |||
137 | wbflush_setup(); | ||
138 | |||
139 | _machine_restart = dec_machine_restart; | ||
140 | _machine_halt = dec_machine_halt; | ||
141 | _machine_power_off = dec_machine_power_off; | ||
142 | } | ||
143 | |||
144 | early_initcall(decstation_setup); | ||
145 | |||
146 | /* | ||
147 | * Machine-specific initialisation for KN01, aka DS2100 (aka Pmin) | ||
148 | * or DS3100 (aka Pmax). | ||
149 | */ | ||
150 | static int kn01_interrupt[DEC_NR_INTS] __initdata = { | ||
151 | [DEC_IRQ_CASCADE] = -1, | ||
152 | [DEC_IRQ_AB_RECV] = -1, | ||
153 | [DEC_IRQ_AB_XMIT] = -1, | ||
154 | [DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11), | ||
155 | [DEC_IRQ_ASC] = -1, | ||
156 | [DEC_IRQ_FLOPPY] = -1, | ||
157 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
158 | [DEC_IRQ_HALT] = -1, | ||
159 | [DEC_IRQ_ISDN] = -1, | ||
160 | [DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE), | ||
161 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS), | ||
162 | [DEC_IRQ_PSU] = -1, | ||
163 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC), | ||
164 | [DEC_IRQ_SCC0] = -1, | ||
165 | [DEC_IRQ_SCC1] = -1, | ||
166 | [DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII), | ||
167 | [DEC_IRQ_TC0] = -1, | ||
168 | [DEC_IRQ_TC1] = -1, | ||
169 | [DEC_IRQ_TC2] = -1, | ||
170 | [DEC_IRQ_TIMER] = -1, | ||
171 | [DEC_IRQ_VIDEO] = DEC_CPU_IRQ_NR(KN01_CPU_INR_VIDEO), | ||
172 | [DEC_IRQ_ASC_MERR] = -1, | ||
173 | [DEC_IRQ_ASC_ERR] = -1, | ||
174 | [DEC_IRQ_ASC_DMA] = -1, | ||
175 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
176 | [DEC_IRQ_ISDN_ERR] = -1, | ||
177 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
178 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
179 | [DEC_IRQ_LANCE_MERR] = -1, | ||
180 | [DEC_IRQ_SCC0A_RXERR] = -1, | ||
181 | [DEC_IRQ_SCC0A_RXDMA] = -1, | ||
182 | [DEC_IRQ_SCC0A_TXERR] = -1, | ||
183 | [DEC_IRQ_SCC0A_TXDMA] = -1, | ||
184 | [DEC_IRQ_AB_RXERR] = -1, | ||
185 | [DEC_IRQ_AB_RXDMA] = -1, | ||
186 | [DEC_IRQ_AB_TXERR] = -1, | ||
187 | [DEC_IRQ_AB_TXDMA] = -1, | ||
188 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
189 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
190 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
191 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
192 | }; | ||
193 | |||
194 | static int_ptr kn01_cpu_mask_nr_tbl[][2] __initdata = { | ||
195 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_BUS) }, | ||
196 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_BUS) } }, | ||
197 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_RTC) }, | ||
198 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_RTC) } }, | ||
199 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_DZ11) }, | ||
200 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_DZ11) } }, | ||
201 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_SII) }, | ||
202 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_SII) } }, | ||
203 | { { .i = DEC_CPU_IRQ_MASK(KN01_CPU_INR_LANCE) }, | ||
204 | { .i = DEC_CPU_IRQ_NR(KN01_CPU_INR_LANCE) } }, | ||
205 | { { .i = DEC_CPU_IRQ_ALL }, | ||
206 | { .p = cpu_all_int } }, | ||
207 | }; | ||
208 | |||
209 | void __init dec_init_kn01(void) | ||
210 | { | ||
211 | /* IRQ routing. */ | ||
212 | memcpy(&dec_interrupt, &kn01_interrupt, | ||
213 | sizeof(kn01_interrupt)); | ||
214 | |||
215 | /* CPU IRQ priorities. */ | ||
216 | memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl, | ||
217 | sizeof(kn01_cpu_mask_nr_tbl)); | ||
218 | |||
219 | mips_cpu_irq_init(DEC_CPU_IRQ_BASE); | ||
220 | |||
221 | } /* dec_init_kn01 */ | ||
222 | |||
223 | |||
224 | /* | ||
225 | * Machine-specific initialisation for KN230, aka DS5100, aka MIPSmate. | ||
226 | */ | ||
227 | static int kn230_interrupt[DEC_NR_INTS] __initdata = { | ||
228 | [DEC_IRQ_CASCADE] = -1, | ||
229 | [DEC_IRQ_AB_RECV] = -1, | ||
230 | [DEC_IRQ_AB_XMIT] = -1, | ||
231 | [DEC_IRQ_DZ11] = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11), | ||
232 | [DEC_IRQ_ASC] = -1, | ||
233 | [DEC_IRQ_FLOPPY] = -1, | ||
234 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
235 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN230_CPU_INR_HALT), | ||
236 | [DEC_IRQ_ISDN] = -1, | ||
237 | [DEC_IRQ_LANCE] = DEC_CPU_IRQ_NR(KN230_CPU_INR_LANCE), | ||
238 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS), | ||
239 | [DEC_IRQ_PSU] = -1, | ||
240 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC), | ||
241 | [DEC_IRQ_SCC0] = -1, | ||
242 | [DEC_IRQ_SCC1] = -1, | ||
243 | [DEC_IRQ_SII] = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII), | ||
244 | [DEC_IRQ_TC0] = -1, | ||
245 | [DEC_IRQ_TC1] = -1, | ||
246 | [DEC_IRQ_TC2] = -1, | ||
247 | [DEC_IRQ_TIMER] = -1, | ||
248 | [DEC_IRQ_VIDEO] = -1, | ||
249 | [DEC_IRQ_ASC_MERR] = -1, | ||
250 | [DEC_IRQ_ASC_ERR] = -1, | ||
251 | [DEC_IRQ_ASC_DMA] = -1, | ||
252 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
253 | [DEC_IRQ_ISDN_ERR] = -1, | ||
254 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
255 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
256 | [DEC_IRQ_LANCE_MERR] = -1, | ||
257 | [DEC_IRQ_SCC0A_RXERR] = -1, | ||
258 | [DEC_IRQ_SCC0A_RXDMA] = -1, | ||
259 | [DEC_IRQ_SCC0A_TXERR] = -1, | ||
260 | [DEC_IRQ_SCC0A_TXDMA] = -1, | ||
261 | [DEC_IRQ_AB_RXERR] = -1, | ||
262 | [DEC_IRQ_AB_RXDMA] = -1, | ||
263 | [DEC_IRQ_AB_TXERR] = -1, | ||
264 | [DEC_IRQ_AB_TXDMA] = -1, | ||
265 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
266 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
267 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
268 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
269 | }; | ||
270 | |||
271 | static int_ptr kn230_cpu_mask_nr_tbl[][2] __initdata = { | ||
272 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_BUS) }, | ||
273 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_BUS) } }, | ||
274 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_RTC) }, | ||
275 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_RTC) } }, | ||
276 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_DZ11) }, | ||
277 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_DZ11) } }, | ||
278 | { { .i = DEC_CPU_IRQ_MASK(KN230_CPU_INR_SII) }, | ||
279 | { .i = DEC_CPU_IRQ_NR(KN230_CPU_INR_SII) } }, | ||
280 | { { .i = DEC_CPU_IRQ_ALL }, | ||
281 | { .p = cpu_all_int } }, | ||
282 | }; | ||
283 | |||
284 | void __init dec_init_kn230(void) | ||
285 | { | ||
286 | /* IRQ routing. */ | ||
287 | memcpy(&dec_interrupt, &kn230_interrupt, | ||
288 | sizeof(kn230_interrupt)); | ||
289 | |||
290 | /* CPU IRQ priorities. */ | ||
291 | memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl, | ||
292 | sizeof(kn230_cpu_mask_nr_tbl)); | ||
293 | |||
294 | mips_cpu_irq_init(DEC_CPU_IRQ_BASE); | ||
295 | |||
296 | } /* dec_init_kn230 */ | ||
297 | |||
298 | |||
299 | /* | ||
300 | * Machine-specific initialisation for KN02, aka DS5000/200, aka 3max. | ||
301 | */ | ||
302 | static int kn02_interrupt[DEC_NR_INTS] __initdata = { | ||
303 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02_CPU_INR_CASCADE), | ||
304 | [DEC_IRQ_AB_RECV] = -1, | ||
305 | [DEC_IRQ_AB_XMIT] = -1, | ||
306 | [DEC_IRQ_DZ11] = KN02_IRQ_NR(KN02_CSR_INR_DZ11), | ||
307 | [DEC_IRQ_ASC] = KN02_IRQ_NR(KN02_CSR_INR_ASC), | ||
308 | [DEC_IRQ_FLOPPY] = -1, | ||
309 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
310 | [DEC_IRQ_HALT] = -1, | ||
311 | [DEC_IRQ_ISDN] = -1, | ||
312 | [DEC_IRQ_LANCE] = KN02_IRQ_NR(KN02_CSR_INR_LANCE), | ||
313 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS), | ||
314 | [DEC_IRQ_PSU] = -1, | ||
315 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC), | ||
316 | [DEC_IRQ_SCC0] = -1, | ||
317 | [DEC_IRQ_SCC1] = -1, | ||
318 | [DEC_IRQ_SII] = -1, | ||
319 | [DEC_IRQ_TC0] = KN02_IRQ_NR(KN02_CSR_INR_TC0), | ||
320 | [DEC_IRQ_TC1] = KN02_IRQ_NR(KN02_CSR_INR_TC1), | ||
321 | [DEC_IRQ_TC2] = KN02_IRQ_NR(KN02_CSR_INR_TC2), | ||
322 | [DEC_IRQ_TIMER] = -1, | ||
323 | [DEC_IRQ_VIDEO] = -1, | ||
324 | [DEC_IRQ_ASC_MERR] = -1, | ||
325 | [DEC_IRQ_ASC_ERR] = -1, | ||
326 | [DEC_IRQ_ASC_DMA] = -1, | ||
327 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
328 | [DEC_IRQ_ISDN_ERR] = -1, | ||
329 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
330 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
331 | [DEC_IRQ_LANCE_MERR] = -1, | ||
332 | [DEC_IRQ_SCC0A_RXERR] = -1, | ||
333 | [DEC_IRQ_SCC0A_RXDMA] = -1, | ||
334 | [DEC_IRQ_SCC0A_TXERR] = -1, | ||
335 | [DEC_IRQ_SCC0A_TXDMA] = -1, | ||
336 | [DEC_IRQ_AB_RXERR] = -1, | ||
337 | [DEC_IRQ_AB_RXDMA] = -1, | ||
338 | [DEC_IRQ_AB_TXERR] = -1, | ||
339 | [DEC_IRQ_AB_TXDMA] = -1, | ||
340 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
341 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
342 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
343 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
344 | }; | ||
345 | |||
346 | static int_ptr kn02_cpu_mask_nr_tbl[][2] __initdata = { | ||
347 | { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_BUS) }, | ||
348 | { .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_BUS) } }, | ||
349 | { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_RTC) }, | ||
350 | { .i = DEC_CPU_IRQ_NR(KN02_CPU_INR_RTC) } }, | ||
351 | { { .i = DEC_CPU_IRQ_MASK(KN02_CPU_INR_CASCADE) }, | ||
352 | { .p = kn02_io_int } }, | ||
353 | { { .i = DEC_CPU_IRQ_ALL }, | ||
354 | { .p = cpu_all_int } }, | ||
355 | }; | ||
356 | |||
357 | static int_ptr kn02_asic_mask_nr_tbl[][2] __initdata = { | ||
358 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_DZ11) }, | ||
359 | { .i = KN02_IRQ_NR(KN02_CSR_INR_DZ11) } }, | ||
360 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_ASC) }, | ||
361 | { .i = KN02_IRQ_NR(KN02_CSR_INR_ASC) } }, | ||
362 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_LANCE) }, | ||
363 | { .i = KN02_IRQ_NR(KN02_CSR_INR_LANCE) } }, | ||
364 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC2) }, | ||
365 | { .i = KN02_IRQ_NR(KN02_CSR_INR_TC2) } }, | ||
366 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC1) }, | ||
367 | { .i = KN02_IRQ_NR(KN02_CSR_INR_TC1) } }, | ||
368 | { { .i = KN02_IRQ_MASK(KN02_CSR_INR_TC0) }, | ||
369 | { .i = KN02_IRQ_NR(KN02_CSR_INR_TC0) } }, | ||
370 | { { .i = KN02_IRQ_ALL }, | ||
371 | { .p = kn02_all_int } }, | ||
372 | }; | ||
373 | |||
374 | void __init dec_init_kn02(void) | ||
375 | { | ||
376 | /* IRQ routing. */ | ||
377 | memcpy(&dec_interrupt, &kn02_interrupt, | ||
378 | sizeof(kn02_interrupt)); | ||
379 | |||
380 | /* CPU IRQ priorities. */ | ||
381 | memcpy(&cpu_mask_nr_tbl, &kn02_cpu_mask_nr_tbl, | ||
382 | sizeof(kn02_cpu_mask_nr_tbl)); | ||
383 | |||
384 | /* KN02 CSR IRQ priorities. */ | ||
385 | memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl, | ||
386 | sizeof(kn02_asic_mask_nr_tbl)); | ||
387 | |||
388 | mips_cpu_irq_init(DEC_CPU_IRQ_BASE); | ||
389 | init_kn02_irqs(KN02_IRQ_BASE); | ||
390 | |||
391 | } /* dec_init_kn02 */ | ||
392 | |||
393 | |||
394 | /* | ||
395 | * Machine-specific initialisation for KN02-BA, aka DS5000/1xx | ||
396 | * (xx = 20, 25, 33), aka 3min. Also applies to KN04(-BA), aka | ||
397 | * DS5000/150, aka 4min. | ||
398 | */ | ||
399 | static int kn02ba_interrupt[DEC_NR_INTS] __initdata = { | ||
400 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_CASCADE), | ||
401 | [DEC_IRQ_AB_RECV] = -1, | ||
402 | [DEC_IRQ_AB_XMIT] = -1, | ||
403 | [DEC_IRQ_DZ11] = -1, | ||
404 | [DEC_IRQ_ASC] = IO_IRQ_NR(KN02BA_IO_INR_ASC), | ||
405 | [DEC_IRQ_FLOPPY] = -1, | ||
406 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
407 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_HALT), | ||
408 | [DEC_IRQ_ISDN] = -1, | ||
409 | [DEC_IRQ_LANCE] = IO_IRQ_NR(KN02BA_IO_INR_LANCE), | ||
410 | [DEC_IRQ_BUS] = IO_IRQ_NR(KN02BA_IO_INR_BUS), | ||
411 | [DEC_IRQ_PSU] = IO_IRQ_NR(KN02BA_IO_INR_PSU), | ||
412 | [DEC_IRQ_RTC] = IO_IRQ_NR(KN02BA_IO_INR_RTC), | ||
413 | [DEC_IRQ_SCC0] = IO_IRQ_NR(KN02BA_IO_INR_SCC0), | ||
414 | [DEC_IRQ_SCC1] = IO_IRQ_NR(KN02BA_IO_INR_SCC1), | ||
415 | [DEC_IRQ_SII] = -1, | ||
416 | [DEC_IRQ_TC0] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0), | ||
417 | [DEC_IRQ_TC1] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1), | ||
418 | [DEC_IRQ_TC2] = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2), | ||
419 | [DEC_IRQ_TIMER] = -1, | ||
420 | [DEC_IRQ_VIDEO] = -1, | ||
421 | [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR), | ||
422 | [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR), | ||
423 | [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA), | ||
424 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
425 | [DEC_IRQ_ISDN_ERR] = -1, | ||
426 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
427 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
428 | [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR), | ||
429 | [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR), | ||
430 | [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA), | ||
431 | [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR), | ||
432 | [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA), | ||
433 | [DEC_IRQ_AB_RXERR] = -1, | ||
434 | [DEC_IRQ_AB_RXDMA] = -1, | ||
435 | [DEC_IRQ_AB_TXERR] = -1, | ||
436 | [DEC_IRQ_AB_TXDMA] = -1, | ||
437 | [DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR), | ||
438 | [DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA), | ||
439 | [DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR), | ||
440 | [DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA), | ||
441 | }; | ||
442 | |||
443 | static int_ptr kn02ba_cpu_mask_nr_tbl[][2] __initdata = { | ||
444 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_CASCADE) }, | ||
445 | { .p = kn02xa_io_int } }, | ||
446 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC2) }, | ||
447 | { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC2) } }, | ||
448 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC1) }, | ||
449 | { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC1) } }, | ||
450 | { { .i = DEC_CPU_IRQ_MASK(KN02BA_CPU_INR_TC0) }, | ||
451 | { .i = DEC_CPU_IRQ_NR(KN02BA_CPU_INR_TC0) } }, | ||
452 | { { .i = DEC_CPU_IRQ_ALL }, | ||
453 | { .p = cpu_all_int } }, | ||
454 | }; | ||
455 | |||
456 | static int_ptr kn02ba_asic_mask_nr_tbl[][2] __initdata = { | ||
457 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_BUS) }, | ||
458 | { .i = IO_IRQ_NR(KN02BA_IO_INR_BUS) } }, | ||
459 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_RTC) }, | ||
460 | { .i = IO_IRQ_NR(KN02BA_IO_INR_RTC) } }, | ||
461 | { { .i = IO_IRQ_DMA }, | ||
462 | { .p = asic_dma_int } }, | ||
463 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC0) }, | ||
464 | { .i = IO_IRQ_NR(KN02BA_IO_INR_SCC0) } }, | ||
465 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_SCC1) }, | ||
466 | { .i = IO_IRQ_NR(KN02BA_IO_INR_SCC1) } }, | ||
467 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_ASC) }, | ||
468 | { .i = IO_IRQ_NR(KN02BA_IO_INR_ASC) } }, | ||
469 | { { .i = IO_IRQ_MASK(KN02BA_IO_INR_LANCE) }, | ||
470 | { .i = IO_IRQ_NR(KN02BA_IO_INR_LANCE) } }, | ||
471 | { { .i = IO_IRQ_ALL }, | ||
472 | { .p = asic_all_int } }, | ||
473 | }; | ||
474 | |||
475 | void __init dec_init_kn02ba(void) | ||
476 | { | ||
477 | /* IRQ routing. */ | ||
478 | memcpy(&dec_interrupt, &kn02ba_interrupt, | ||
479 | sizeof(kn02ba_interrupt)); | ||
480 | |||
481 | /* CPU IRQ priorities. */ | ||
482 | memcpy(&cpu_mask_nr_tbl, &kn02ba_cpu_mask_nr_tbl, | ||
483 | sizeof(kn02ba_cpu_mask_nr_tbl)); | ||
484 | |||
485 | /* I/O ASIC IRQ priorities. */ | ||
486 | memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl, | ||
487 | sizeof(kn02ba_asic_mask_nr_tbl)); | ||
488 | |||
489 | mips_cpu_irq_init(DEC_CPU_IRQ_BASE); | ||
490 | init_ioasic_irqs(IO_IRQ_BASE); | ||
491 | |||
492 | } /* dec_init_kn02ba */ | ||
493 | |||
494 | |||
495 | /* | ||
496 | * Machine-specific initialisation for KN02-CA, aka DS5000/xx, | ||
497 | * (xx = 20, 25, 33), aka MAXine. Also applies to KN04(-CA), aka | ||
498 | * DS5000/50, aka 4MAXine. | ||
499 | */ | ||
500 | static int kn02ca_interrupt[DEC_NR_INTS] __initdata = { | ||
501 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_CASCADE), | ||
502 | [DEC_IRQ_AB_RECV] = IO_IRQ_NR(KN02CA_IO_INR_AB_RECV), | ||
503 | [DEC_IRQ_AB_XMIT] = IO_IRQ_NR(KN02CA_IO_INR_AB_XMIT), | ||
504 | [DEC_IRQ_DZ11] = -1, | ||
505 | [DEC_IRQ_ASC] = IO_IRQ_NR(KN02CA_IO_INR_ASC), | ||
506 | [DEC_IRQ_FLOPPY] = IO_IRQ_NR(KN02CA_IO_INR_FLOPPY), | ||
507 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
508 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_HALT), | ||
509 | [DEC_IRQ_ISDN] = IO_IRQ_NR(KN02CA_IO_INR_ISDN), | ||
510 | [DEC_IRQ_LANCE] = IO_IRQ_NR(KN02CA_IO_INR_LANCE), | ||
511 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS), | ||
512 | [DEC_IRQ_PSU] = -1, | ||
513 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC), | ||
514 | [DEC_IRQ_SCC0] = IO_IRQ_NR(KN02CA_IO_INR_SCC0), | ||
515 | [DEC_IRQ_SCC1] = -1, | ||
516 | [DEC_IRQ_SII] = -1, | ||
517 | [DEC_IRQ_TC0] = IO_IRQ_NR(KN02CA_IO_INR_TC0), | ||
518 | [DEC_IRQ_TC1] = IO_IRQ_NR(KN02CA_IO_INR_TC1), | ||
519 | [DEC_IRQ_TC2] = -1, | ||
520 | [DEC_IRQ_TIMER] = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_TIMER), | ||
521 | [DEC_IRQ_VIDEO] = IO_IRQ_NR(KN02CA_IO_INR_VIDEO), | ||
522 | [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR), | ||
523 | [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR), | ||
524 | [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA), | ||
525 | [DEC_IRQ_FLOPPY_ERR] = IO_IRQ_NR(IO_INR_FLOPPY_ERR), | ||
526 | [DEC_IRQ_ISDN_ERR] = IO_IRQ_NR(IO_INR_ISDN_ERR), | ||
527 | [DEC_IRQ_ISDN_RXDMA] = IO_IRQ_NR(IO_INR_ISDN_RXDMA), | ||
528 | [DEC_IRQ_ISDN_TXDMA] = IO_IRQ_NR(IO_INR_ISDN_TXDMA), | ||
529 | [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR), | ||
530 | [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR), | ||
531 | [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA), | ||
532 | [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR), | ||
533 | [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA), | ||
534 | [DEC_IRQ_AB_RXERR] = IO_IRQ_NR(IO_INR_AB_RXERR), | ||
535 | [DEC_IRQ_AB_RXDMA] = IO_IRQ_NR(IO_INR_AB_RXDMA), | ||
536 | [DEC_IRQ_AB_TXERR] = IO_IRQ_NR(IO_INR_AB_TXERR), | ||
537 | [DEC_IRQ_AB_TXDMA] = IO_IRQ_NR(IO_INR_AB_TXDMA), | ||
538 | [DEC_IRQ_SCC1A_RXERR] = -1, | ||
539 | [DEC_IRQ_SCC1A_RXDMA] = -1, | ||
540 | [DEC_IRQ_SCC1A_TXERR] = -1, | ||
541 | [DEC_IRQ_SCC1A_TXDMA] = -1, | ||
542 | }; | ||
543 | |||
544 | static int_ptr kn02ca_cpu_mask_nr_tbl[][2] __initdata = { | ||
545 | { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_BUS) }, | ||
546 | { .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_BUS) } }, | ||
547 | { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_RTC) }, | ||
548 | { .i = DEC_CPU_IRQ_NR(KN02CA_CPU_INR_RTC) } }, | ||
549 | { { .i = DEC_CPU_IRQ_MASK(KN02CA_CPU_INR_CASCADE) }, | ||
550 | { .p = kn02xa_io_int } }, | ||
551 | { { .i = DEC_CPU_IRQ_ALL }, | ||
552 | { .p = cpu_all_int } }, | ||
553 | }; | ||
554 | |||
555 | static int_ptr kn02ca_asic_mask_nr_tbl[][2] __initdata = { | ||
556 | { { .i = IO_IRQ_DMA }, | ||
557 | { .p = asic_dma_int } }, | ||
558 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_SCC0) }, | ||
559 | { .i = IO_IRQ_NR(KN02CA_IO_INR_SCC0) } }, | ||
560 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_ASC) }, | ||
561 | { .i = IO_IRQ_NR(KN02CA_IO_INR_ASC) } }, | ||
562 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_LANCE) }, | ||
563 | { .i = IO_IRQ_NR(KN02CA_IO_INR_LANCE) } }, | ||
564 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC1) }, | ||
565 | { .i = IO_IRQ_NR(KN02CA_IO_INR_TC1) } }, | ||
566 | { { .i = IO_IRQ_MASK(KN02CA_IO_INR_TC0) }, | ||
567 | { .i = IO_IRQ_NR(KN02CA_IO_INR_TC0) } }, | ||
568 | { { .i = IO_IRQ_ALL }, | ||
569 | { .p = asic_all_int } }, | ||
570 | }; | ||
571 | |||
572 | void __init dec_init_kn02ca(void) | ||
573 | { | ||
574 | /* IRQ routing. */ | ||
575 | memcpy(&dec_interrupt, &kn02ca_interrupt, | ||
576 | sizeof(kn02ca_interrupt)); | ||
577 | |||
578 | /* CPU IRQ priorities. */ | ||
579 | memcpy(&cpu_mask_nr_tbl, &kn02ca_cpu_mask_nr_tbl, | ||
580 | sizeof(kn02ca_cpu_mask_nr_tbl)); | ||
581 | |||
582 | /* I/O ASIC IRQ priorities. */ | ||
583 | memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl, | ||
584 | sizeof(kn02ca_asic_mask_nr_tbl)); | ||
585 | |||
586 | mips_cpu_irq_init(DEC_CPU_IRQ_BASE); | ||
587 | init_ioasic_irqs(IO_IRQ_BASE); | ||
588 | |||
589 | } /* dec_init_kn02ca */ | ||
590 | |||
591 | |||
592 | /* | ||
593 | * Machine-specific initialisation for KN03, aka DS5000/240, | ||
594 | * aka 3max+ and DS5900, aka BIGmax. Also applies to KN05, aka | ||
595 | * DS5000/260, aka 4max+ and DS5900/260. | ||
596 | */ | ||
597 | static int kn03_interrupt[DEC_NR_INTS] __initdata = { | ||
598 | [DEC_IRQ_CASCADE] = DEC_CPU_IRQ_NR(KN03_CPU_INR_CASCADE), | ||
599 | [DEC_IRQ_AB_RECV] = -1, | ||
600 | [DEC_IRQ_AB_XMIT] = -1, | ||
601 | [DEC_IRQ_DZ11] = -1, | ||
602 | [DEC_IRQ_ASC] = IO_IRQ_NR(KN03_IO_INR_ASC), | ||
603 | [DEC_IRQ_FLOPPY] = -1, | ||
604 | [DEC_IRQ_FPU] = DEC_CPU_IRQ_NR(DEC_CPU_INR_FPU), | ||
605 | [DEC_IRQ_HALT] = DEC_CPU_IRQ_NR(KN03_CPU_INR_HALT), | ||
606 | [DEC_IRQ_ISDN] = -1, | ||
607 | [DEC_IRQ_LANCE] = IO_IRQ_NR(KN03_IO_INR_LANCE), | ||
608 | [DEC_IRQ_BUS] = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS), | ||
609 | [DEC_IRQ_PSU] = IO_IRQ_NR(KN03_IO_INR_PSU), | ||
610 | [DEC_IRQ_RTC] = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC), | ||
611 | [DEC_IRQ_SCC0] = IO_IRQ_NR(KN03_IO_INR_SCC0), | ||
612 | [DEC_IRQ_SCC1] = IO_IRQ_NR(KN03_IO_INR_SCC1), | ||
613 | [DEC_IRQ_SII] = -1, | ||
614 | [DEC_IRQ_TC0] = IO_IRQ_NR(KN03_IO_INR_TC0), | ||
615 | [DEC_IRQ_TC1] = IO_IRQ_NR(KN03_IO_INR_TC1), | ||
616 | [DEC_IRQ_TC2] = IO_IRQ_NR(KN03_IO_INR_TC2), | ||
617 | [DEC_IRQ_TIMER] = -1, | ||
618 | [DEC_IRQ_VIDEO] = -1, | ||
619 | [DEC_IRQ_ASC_MERR] = IO_IRQ_NR(IO_INR_ASC_MERR), | ||
620 | [DEC_IRQ_ASC_ERR] = IO_IRQ_NR(IO_INR_ASC_ERR), | ||
621 | [DEC_IRQ_ASC_DMA] = IO_IRQ_NR(IO_INR_ASC_DMA), | ||
622 | [DEC_IRQ_FLOPPY_ERR] = -1, | ||
623 | [DEC_IRQ_ISDN_ERR] = -1, | ||
624 | [DEC_IRQ_ISDN_RXDMA] = -1, | ||
625 | [DEC_IRQ_ISDN_TXDMA] = -1, | ||
626 | [DEC_IRQ_LANCE_MERR] = IO_IRQ_NR(IO_INR_LANCE_MERR), | ||
627 | [DEC_IRQ_SCC0A_RXERR] = IO_IRQ_NR(IO_INR_SCC0A_RXERR), | ||
628 | [DEC_IRQ_SCC0A_RXDMA] = IO_IRQ_NR(IO_INR_SCC0A_RXDMA), | ||
629 | [DEC_IRQ_SCC0A_TXERR] = IO_IRQ_NR(IO_INR_SCC0A_TXERR), | ||
630 | [DEC_IRQ_SCC0A_TXDMA] = IO_IRQ_NR(IO_INR_SCC0A_TXDMA), | ||
631 | [DEC_IRQ_AB_RXERR] = -1, | ||
632 | [DEC_IRQ_AB_RXDMA] = -1, | ||
633 | [DEC_IRQ_AB_TXERR] = -1, | ||
634 | [DEC_IRQ_AB_TXDMA] = -1, | ||
635 | [DEC_IRQ_SCC1A_RXERR] = IO_IRQ_NR(IO_INR_SCC1A_RXERR), | ||
636 | [DEC_IRQ_SCC1A_RXDMA] = IO_IRQ_NR(IO_INR_SCC1A_RXDMA), | ||
637 | [DEC_IRQ_SCC1A_TXERR] = IO_IRQ_NR(IO_INR_SCC1A_TXERR), | ||
638 | [DEC_IRQ_SCC1A_TXDMA] = IO_IRQ_NR(IO_INR_SCC1A_TXDMA), | ||
639 | }; | ||
640 | |||
641 | static int_ptr kn03_cpu_mask_nr_tbl[][2] __initdata = { | ||
642 | { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_BUS) }, | ||
643 | { .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_BUS) } }, | ||
644 | { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_RTC) }, | ||
645 | { .i = DEC_CPU_IRQ_NR(KN03_CPU_INR_RTC) } }, | ||
646 | { { .i = DEC_CPU_IRQ_MASK(KN03_CPU_INR_CASCADE) }, | ||
647 | { .p = kn03_io_int } }, | ||
648 | { { .i = DEC_CPU_IRQ_ALL }, | ||
649 | { .p = cpu_all_int } }, | ||
650 | }; | ||
651 | |||
652 | static int_ptr kn03_asic_mask_nr_tbl[][2] __initdata = { | ||
653 | { { .i = IO_IRQ_DMA }, | ||
654 | { .p = asic_dma_int } }, | ||
655 | { { .i = IO_IRQ_MASK(KN03_IO_INR_SCC0) }, | ||
656 | { .i = IO_IRQ_NR(KN03_IO_INR_SCC0) } }, | ||
657 | { { .i = IO_IRQ_MASK(KN03_IO_INR_SCC1) }, | ||
658 | { .i = IO_IRQ_NR(KN03_IO_INR_SCC1) } }, | ||
659 | { { .i = IO_IRQ_MASK(KN03_IO_INR_ASC) }, | ||
660 | { .i = IO_IRQ_NR(KN03_IO_INR_ASC) } }, | ||
661 | { { .i = IO_IRQ_MASK(KN03_IO_INR_LANCE) }, | ||
662 | { .i = IO_IRQ_NR(KN03_IO_INR_LANCE) } }, | ||
663 | { { .i = IO_IRQ_MASK(KN03_IO_INR_TC2) }, | ||
664 | { .i = IO_IRQ_NR(KN03_IO_INR_TC2) } }, | ||
665 | { { .i = IO_IRQ_MASK(KN03_IO_INR_TC1) }, | ||
666 | { .i = IO_IRQ_NR(KN03_IO_INR_TC1) } }, | ||
667 | { { .i = IO_IRQ_MASK(KN03_IO_INR_TC0) }, | ||
668 | { .i = IO_IRQ_NR(KN03_IO_INR_TC0) } }, | ||
669 | { { .i = IO_IRQ_ALL }, | ||
670 | { .p = asic_all_int } }, | ||
671 | }; | ||
672 | |||
673 | void __init dec_init_kn03(void) | ||
674 | { | ||
675 | /* IRQ routing. */ | ||
676 | memcpy(&dec_interrupt, &kn03_interrupt, | ||
677 | sizeof(kn03_interrupt)); | ||
678 | |||
679 | /* CPU IRQ priorities. */ | ||
680 | memcpy(&cpu_mask_nr_tbl, &kn03_cpu_mask_nr_tbl, | ||
681 | sizeof(kn03_cpu_mask_nr_tbl)); | ||
682 | |||
683 | /* I/O ASIC IRQ priorities. */ | ||
684 | memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl, | ||
685 | sizeof(kn03_asic_mask_nr_tbl)); | ||
686 | |||
687 | mips_cpu_irq_init(DEC_CPU_IRQ_BASE); | ||
688 | init_ioasic_irqs(IO_IRQ_BASE); | ||
689 | |||
690 | } /* dec_init_kn03 */ | ||
691 | |||
692 | |||
693 | void __init arch_init_irq(void) | ||
694 | { | ||
695 | switch (mips_machtype) { | ||
696 | case MACH_DS23100: /* DS2100/DS3100 Pmin/Pmax */ | ||
697 | dec_init_kn01(); | ||
698 | break; | ||
699 | case MACH_DS5100: /* DS5100 MIPSmate */ | ||
700 | dec_init_kn230(); | ||
701 | break; | ||
702 | case MACH_DS5000_200: /* DS5000/200 3max */ | ||
703 | dec_init_kn02(); | ||
704 | break; | ||
705 | case MACH_DS5000_1XX: /* DS5000/1xx 3min */ | ||
706 | dec_init_kn02ba(); | ||
707 | break; | ||
708 | case MACH_DS5000_2X0: /* DS5000/240 3max+ */ | ||
709 | case MACH_DS5900: /* DS5900 bigmax */ | ||
710 | dec_init_kn03(); | ||
711 | break; | ||
712 | case MACH_DS5000_XX: /* Personal DS5000/xx */ | ||
713 | dec_init_kn02ca(); | ||
714 | break; | ||
715 | case MACH_DS5800: /* DS5800 Isis */ | ||
716 | panic("Don't know how to set this up!"); | ||
717 | break; | ||
718 | case MACH_DS5400: /* DS5400 MIPSfair */ | ||
719 | panic("Don't know how to set this up!"); | ||
720 | break; | ||
721 | case MACH_DS5500: /* DS5500 MIPSfair-2 */ | ||
722 | panic("Don't know how to set this up!"); | ||
723 | break; | ||
724 | } | ||
725 | set_except_vector(0, decstation_handle_int); | ||
726 | |||
727 | /* Free the FPU interrupt if the exception is present. */ | ||
728 | if (!cpu_has_nofpuex) { | ||
729 | cpu_fpu_mask = 0; | ||
730 | dec_interrupt[DEC_IRQ_FPU] = -1; | ||
731 | } | ||
732 | |||
733 | /* Register board interrupts: FPU and cascade. */ | ||
734 | if (dec_interrupt[DEC_IRQ_FPU] >= 0) | ||
735 | setup_irq(dec_interrupt[DEC_IRQ_FPU], &fpuirq); | ||
736 | if (dec_interrupt[DEC_IRQ_CASCADE] >= 0) | ||
737 | setup_irq(dec_interrupt[DEC_IRQ_CASCADE], &ioirq); | ||
738 | |||
739 | /* Register the bus error interrupt. */ | ||
740 | if (dec_interrupt[DEC_IRQ_BUS] >= 0 && busirq.handler) | ||
741 | setup_irq(dec_interrupt[DEC_IRQ_BUS], &busirq); | ||
742 | |||
743 | /* Register the HALT interrupt. */ | ||
744 | if (dec_interrupt[DEC_IRQ_HALT] >= 0) | ||
745 | setup_irq(dec_interrupt[DEC_IRQ_HALT], &haltirq); | ||
746 | } | ||
747 | |||
748 | EXPORT_SYMBOL(ioasic_base); | ||
749 | EXPORT_SYMBOL(dec_kn_slot_size); | ||
750 | EXPORT_SYMBOL(dec_interrupt); | ||
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c new file mode 100644 index 000000000000..dc7091caa7aa --- /dev/null +++ b/arch/mips/dec/time.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * linux/arch/mips/dec/time.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
5 | * Copyright (C) 2000, 2003 Maciej W. Rozycki | ||
6 | * | ||
7 | * This file contains the time handling details for PC-style clocks as | ||
8 | * found in some MIPS systems. | ||
9 | * | ||
10 | */ | ||
11 | #include <linux/bcd.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/mc146818rtc.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/param.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | #include <asm/bootinfo.h> | ||
26 | #include <asm/cpu.h> | ||
27 | #include <asm/div64.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/mipsregs.h> | ||
31 | #include <asm/sections.h> | ||
32 | #include <asm/time.h> | ||
33 | |||
34 | #include <asm/dec/interrupts.h> | ||
35 | #include <asm/dec/ioasic.h> | ||
36 | #include <asm/dec/ioasic_addrs.h> | ||
37 | #include <asm/dec/machtype.h> | ||
38 | |||
39 | |||
40 | static unsigned long dec_rtc_get_time(void) | ||
41 | { | ||
42 | unsigned int year, mon, day, hour, min, sec, real_year; | ||
43 | int i; | ||
44 | |||
45 | /* The Linux interpretation of the DS1287 clock register contents: | ||
46 | * When the Update-In-Progress (UIP) flag goes from 1 to 0, the | ||
47 | * RTC registers show the second which has precisely just started. | ||
48 | * Let's hope other operating systems interpret the RTC the same way. | ||
49 | */ | ||
50 | /* read RTC exactly on falling edge of update flag */ | ||
51 | for (i = 0; i < 1000000; i++) /* may take up to 1 second... */ | ||
52 | if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) | ||
53 | break; | ||
54 | for (i = 0; i < 1000000; i++) /* must try at least 2.228 ms */ | ||
55 | if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) | ||
56 | break; | ||
57 | /* Isn't this overkill? UIP above should guarantee consistency */ | ||
58 | do { | ||
59 | sec = CMOS_READ(RTC_SECONDS); | ||
60 | min = CMOS_READ(RTC_MINUTES); | ||
61 | hour = CMOS_READ(RTC_HOURS); | ||
62 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
63 | mon = CMOS_READ(RTC_MONTH); | ||
64 | year = CMOS_READ(RTC_YEAR); | ||
65 | } while (sec != CMOS_READ(RTC_SECONDS)); | ||
66 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
67 | sec = BCD2BIN(sec); | ||
68 | min = BCD2BIN(min); | ||
69 | hour = BCD2BIN(hour); | ||
70 | day = BCD2BIN(day); | ||
71 | mon = BCD2BIN(mon); | ||
72 | year = BCD2BIN(year); | ||
73 | } | ||
74 | /* | ||
75 | * The PROM will reset the year to either '72 or '73. | ||
76 | * Therefore we store the real year separately, in one | ||
77 | * of unused BBU RAM locations. | ||
78 | */ | ||
79 | real_year = CMOS_READ(RTC_DEC_YEAR); | ||
80 | year += real_year - 72 + 2000; | ||
81 | |||
82 | return mktime(year, mon, day, hour, min, sec); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * In order to set the CMOS clock precisely, dec_rtc_set_mmss has to | ||
87 | * be called 500 ms after the second nowtime has started, because when | ||
88 | * nowtime is written into the registers of the CMOS clock, it will | ||
89 | * jump to the next second precisely 500 ms later. Check the Dallas | ||
90 | * DS1287 data sheet for details. | ||
91 | */ | ||
92 | static int dec_rtc_set_mmss(unsigned long nowtime) | ||
93 | { | ||
94 | int retval = 0; | ||
95 | int real_seconds, real_minutes, cmos_minutes; | ||
96 | unsigned char save_control, save_freq_select; | ||
97 | |||
98 | /* tell the clock it's being set */ | ||
99 | save_control = CMOS_READ(RTC_CONTROL); | ||
100 | CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL); | ||
101 | |||
102 | /* stop and reset prescaler */ | ||
103 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
104 | CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
105 | |||
106 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
107 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
108 | cmos_minutes = BCD2BIN(cmos_minutes); | ||
109 | |||
110 | /* | ||
111 | * since we're only adjusting minutes and seconds, | ||
112 | * don't interfere with hour overflow. This avoids | ||
113 | * messing with unknown time zones but requires your | ||
114 | * RTC not to be off by more than 15 minutes | ||
115 | */ | ||
116 | real_seconds = nowtime % 60; | ||
117 | real_minutes = nowtime / 60; | ||
118 | if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) | ||
119 | real_minutes += 30; /* correct for half hour time zone */ | ||
120 | real_minutes %= 60; | ||
121 | |||
122 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
123 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
124 | real_seconds = BIN2BCD(real_seconds); | ||
125 | real_minutes = BIN2BCD(real_minutes); | ||
126 | } | ||
127 | CMOS_WRITE(real_seconds, RTC_SECONDS); | ||
128 | CMOS_WRITE(real_minutes, RTC_MINUTES); | ||
129 | } else { | ||
130 | printk(KERN_WARNING | ||
131 | "set_rtc_mmss: can't update from %d to %d\n", | ||
132 | cmos_minutes, real_minutes); | ||
133 | retval = -1; | ||
134 | } | ||
135 | |||
136 | /* The following flags have to be released exactly in this order, | ||
137 | * otherwise the DS1287 will not reset the oscillator and will not | ||
138 | * update precisely 500 ms later. You won't find this mentioned | ||
139 | * in the Dallas Semiconductor data sheets, but who believes data | ||
140 | * sheets anyway ... -- Markus Kuhn | ||
141 | */ | ||
142 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
143 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
144 | |||
145 | return retval; | ||
146 | } | ||
147 | |||
148 | |||
149 | static int dec_timer_state(void) | ||
150 | { | ||
151 | return (CMOS_READ(RTC_REG_C) & RTC_PF) != 0; | ||
152 | } | ||
153 | |||
154 | static void dec_timer_ack(void) | ||
155 | { | ||
156 | CMOS_READ(RTC_REG_C); /* Ack the RTC interrupt. */ | ||
157 | } | ||
158 | |||
159 | static unsigned int dec_ioasic_hpt_read(void) | ||
160 | { | ||
161 | /* | ||
162 | * The free-running counter is 32-bit which is good for about | ||
163 | * 2 minutes, 50 seconds at possible count rates of up to 25MHz. | ||
164 | */ | ||
165 | return ioasic_read(IO_REG_FCTR); | ||
166 | } | ||
167 | |||
168 | static void dec_ioasic_hpt_init(unsigned int count) | ||
169 | { | ||
170 | ioasic_write(IO_REG_FCTR, ioasic_read(IO_REG_FCTR) - count); | ||
171 | } | ||
172 | |||
173 | |||
174 | void __init dec_time_init(void) | ||
175 | { | ||
176 | rtc_get_time = dec_rtc_get_time; | ||
177 | rtc_set_mmss = dec_rtc_set_mmss; | ||
178 | |||
179 | mips_timer_state = dec_timer_state; | ||
180 | mips_timer_ack = dec_timer_ack; | ||
181 | |||
182 | if (!cpu_has_counter && IOASIC) { | ||
183 | /* For pre-R4k systems we use the I/O ASIC's counter. */ | ||
184 | mips_hpt_read = dec_ioasic_hpt_read; | ||
185 | mips_hpt_init = dec_ioasic_hpt_init; | ||
186 | } | ||
187 | |||
188 | /* Set up the rate of periodic DS1287 interrupts. */ | ||
189 | CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - LOG_2_HZ), RTC_REG_A); | ||
190 | } | ||
191 | |||
192 | EXPORT_SYMBOL(do_settimeofday); | ||
193 | |||
194 | void __init dec_timer_setup(struct irqaction *irq) | ||
195 | { | ||
196 | setup_irq(dec_interrupt[DEC_IRQ_RTC], irq); | ||
197 | |||
198 | /* Enable periodic DS1287 interrupts. */ | ||
199 | CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B); | ||
200 | } | ||
diff --git a/arch/mips/dec/wbflush.c b/arch/mips/dec/wbflush.c new file mode 100644 index 000000000000..925c0525344b --- /dev/null +++ b/arch/mips/dec/wbflush.c | |||
@@ -0,0 +1,94 @@ | |||
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/init.h> | ||
18 | |||
19 | #include <asm/bootinfo.h> | ||
20 | #include <asm/system.h> | ||
21 | #include <asm/wbflush.h> | ||
22 | |||
23 | static void wbflush_kn01(void); | ||
24 | static void wbflush_kn210(void); | ||
25 | static void wbflush_mips(void); | ||
26 | |||
27 | void (*__wbflush) (void); | ||
28 | |||
29 | void __init wbflush_setup(void) | ||
30 | { | ||
31 | switch (mips_machtype) { | ||
32 | case MACH_DS23100: | ||
33 | case MACH_DS5000_200: /* DS5000 3max */ | ||
34 | __wbflush = wbflush_kn01; | ||
35 | break; | ||
36 | case MACH_DS5100: /* DS5100 MIPSMATE */ | ||
37 | __wbflush = wbflush_kn210; | ||
38 | break; | ||
39 | case MACH_DS5000_1XX: /* DS5000/100 3min */ | ||
40 | case MACH_DS5000_XX: /* Personal DS5000/2x */ | ||
41 | case MACH_DS5000_2X0: /* DS5000/240 3max+ */ | ||
42 | case MACH_DS5900: /* DS5900 bigmax */ | ||
43 | default: | ||
44 | __wbflush = wbflush_mips; | ||
45 | break; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions | ||
51 | * as part of Coprocessor 0. | ||
52 | */ | ||
53 | static void wbflush_kn01(void) | ||
54 | { | ||
55 | asm(".set\tpush\n\t" | ||
56 | ".set\tnoreorder\n\t" | ||
57 | "1:\tbc0f\t1b\n\t" | ||
58 | "nop\n\t" | ||
59 | ".set\tpop"); | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * For the DS5100 the writeback buffer seems to be a part of Coprocessor 3. | ||
64 | * But CP3 has to enabled first. | ||
65 | */ | ||
66 | static void wbflush_kn210(void) | ||
67 | { | ||
68 | asm(".set\tpush\n\t" | ||
69 | ".set\tnoreorder\n\t" | ||
70 | "mfc0\t$2,$12\n\t" | ||
71 | "lui\t$3,0x8000\n\t" | ||
72 | "or\t$3,$2,$3\n\t" | ||
73 | "mtc0\t$3,$12\n\t" | ||
74 | "nop\n" | ||
75 | "1:\tbc3f\t1b\n\t" | ||
76 | "nop\n\t" | ||
77 | "mtc0\t$2,$12\n\t" | ||
78 | "nop\n\t" | ||
79 | ".set\tpop" | ||
80 | : : : "$2", "$3"); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * I/O ASIC systems use a standard writeback buffer that gets flushed | ||
85 | * upon an uncached read. | ||
86 | */ | ||
87 | static void wbflush_mips(void) | ||
88 | { | ||
89 | __fast_iob(); | ||
90 | } | ||
91 | |||
92 | #include <linux/module.h> | ||
93 | |||
94 | EXPORT_SYMBOL(__wbflush); | ||