aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sgi-ip32
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/sgi-ip32
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/sgi-ip32')
-rw-r--r--arch/mips/sgi-ip32/Makefile9
-rw-r--r--arch/mips/sgi-ip32/crime.c103
-rw-r--r--arch/mips/sgi-ip32/ip32-berr.c36
-rw-r--r--arch/mips/sgi-ip32/ip32-irq-glue.S86
-rw-r--r--arch/mips/sgi-ip32/ip32-irq.c590
-rw-r--r--arch/mips/sgi-ip32/ip32-memory.c49
-rw-r--r--arch/mips/sgi-ip32/ip32-reset.c202
-rw-r--r--arch/mips/sgi-ip32/ip32-setup.c159
8 files changed, 1234 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile
new file mode 100644
index 000000000000..470898f4afe1
--- /dev/null
+++ b/arch/mips/sgi-ip32/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for the SGI specific kernel interface routines
3# under Linux.
4#
5
6obj-y += ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \
7 crime.o ip32-memory.o
8
9EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c
new file mode 100644
index 000000000000..eb3a16a04fee
--- /dev/null
+++ b/arch/mips/sgi-ip32/crime.c
@@ -0,0 +1,103 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2001, 2003 Keith M Wesolowski
7 * Copyright (C) 2005 Ilya A. Volynets <ilya@total-knowledge.com>
8 */
9#include <linux/types.h>
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/interrupt.h>
13#include <asm/bootinfo.h>
14#include <asm/io.h>
15#include <asm/mipsregs.h>
16#include <asm/ptrace.h>
17#include <asm/page.h>
18#include <asm/ip32/crime.h>
19#include <asm/ip32/mace.h>
20
21struct sgi_crime *crime;
22struct sgi_mace *mace;
23
24void __init crime_init(void)
25{
26 unsigned int id, rev;
27 const int field = 2 * sizeof(unsigned long);
28
29 set_io_port_base((unsigned long) ioremap(MACEPCI_LOW_IO, 0x2000000));
30 crime = ioremap(CRIME_BASE, sizeof(struct sgi_crime));
31 mace = ioremap(MACE_BASE, sizeof(struct sgi_mace));
32
33 id = crime->id;
34 rev = id & CRIME_ID_REV;
35 id = (id & CRIME_ID_IDBITS) >> 4;
36 printk (KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n",
37 id, rev, field, (unsigned long) CRIME_BASE);
38}
39
40irqreturn_t
41crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
42{
43 unsigned long stat, addr;
44 int fatal = 0;
45
46 stat = crime->mem_error_stat & CRIME_MEM_ERROR_STAT_MASK;
47 addr = crime->mem_error_addr & CRIME_MEM_ERROR_ADDR_MASK;
48
49 printk("CRIME memory error at 0x%08lx ST 0x%08lx<", addr, stat);
50
51 if (stat & CRIME_MEM_ERROR_INV)
52 printk("INV,");
53 if (stat & CRIME_MEM_ERROR_ECC) {
54 unsigned long ecc_syn =
55 crime->mem_ecc_syn & CRIME_MEM_ERROR_ECC_SYN_MASK;
56 unsigned long ecc_gen =
57 crime->mem_ecc_chk & CRIME_MEM_ERROR_ECC_CHK_MASK;
58 printk("ECC,SYN=0x%08lx,GEN=0x%08lx,", ecc_syn, ecc_gen);
59 }
60 if (stat & CRIME_MEM_ERROR_MULTIPLE) {
61 fatal = 1;
62 printk("MULTIPLE,");
63 }
64 if (stat & CRIME_MEM_ERROR_HARD_ERR) {
65 fatal = 1;
66 printk("HARD,");
67 }
68 if (stat & CRIME_MEM_ERROR_SOFT_ERR)
69 printk("SOFT,");
70 if (stat & CRIME_MEM_ERROR_CPU_ACCESS)
71 printk("CPU,");
72 if (stat & CRIME_MEM_ERROR_VICE_ACCESS)
73 printk("VICE,");
74 if (stat & CRIME_MEM_ERROR_GBE_ACCESS)
75 printk("GBE,");
76 if (stat & CRIME_MEM_ERROR_RE_ACCESS)
77 printk("RE,REID=0x%02lx,", (stat & CRIME_MEM_ERROR_RE_ID)>>8);
78 if (stat & CRIME_MEM_ERROR_MACE_ACCESS)
79 printk("MACE,MACEID=0x%02lx,", stat & CRIME_MEM_ERROR_MACE_ID);
80
81 crime->mem_error_stat = 0;
82
83 if (fatal) {
84 printk("FATAL>\n");
85 panic("Fatal memory error.");
86 } else
87 printk("NONFATAL>\n");
88
89 return IRQ_HANDLED;
90}
91
92irqreturn_t
93crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
94{
95 unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
96 unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
97
98 addr <<= 2;
99 printk ("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat);
100 crime->cpu_error_stat = 0;
101
102 return IRQ_HANDLED;
103}
diff --git a/arch/mips/sgi-ip32/ip32-berr.c b/arch/mips/sgi-ip32/ip32-berr.c
new file mode 100644
index 000000000000..a278e918a019
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-berr.c
@@ -0,0 +1,36 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
7 * Copyright (C) 1999, 2000 by Silicon Graphics
8 * Copyright (C) 2002 Maciej W. Rozycki
9 */
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <asm/traps.h>
14#include <asm/uaccess.h>
15#include <asm/addrspace.h>
16#include <asm/ptrace.h>
17#include <asm/tlbdebug.h>
18
19int ip32_be_handler(struct pt_regs *regs, int is_fixup)
20{
21 int data = regs->cp0_cause & 4;
22
23 if (is_fixup)
24 return MIPS_BE_FIXUP;
25
26 printk("Got %cbe at 0x%lx\n", data ? 'd' : 'i', regs->cp0_epc);
27 show_regs(regs);
28 dump_tlb_all();
29 while(1);
30 force_sig(SIGBUS, current);
31}
32
33void __init ip32_be_init(void)
34{
35 board_be_handler = ip32_be_handler;
36}
diff --git a/arch/mips/sgi-ip32/ip32-irq-glue.S b/arch/mips/sgi-ip32/ip32-irq-glue.S
new file mode 100644
index 000000000000..200924e1c4f5
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-irq-glue.S
@@ -0,0 +1,86 @@
1/*
2 * Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
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) 2000 Harald Koerfgen
9 * Copyright (C) 2001 Keith M Wesolowski
10 */
11#include <asm/asm.h>
12#include <asm/regdef.h>
13#include <asm/mipsregs.h>
14#include <asm/stackframe.h>
15#include <asm/addrspace.h>
16
17 .text
18 .set noreorder
19 .set noat
20 .align 5
21 NESTED(ip32_handle_int, PT_SIZE, ra)
22 .set noat
23 SAVE_ALL
24 CLI # TEST: interrupts should be off
25 .set at
26 .set noreorder
27
28 mfc0 s0,CP0_CAUSE
29
30 andi t1, s0, IE_IRQ0
31 bnez t1, handle_irq0
32 andi t1, s0, IE_IRQ1
33 bnez t1, handle_irq1
34 andi t1, s0, IE_IRQ2
35 bnez t1, handle_irq2
36 andi t1, s0, IE_IRQ3
37 bnez t1, handle_irq3
38 andi t1, s0, IE_IRQ4
39 bnez t1, handle_irq4
40 andi t1, s0, IE_IRQ5
41 bnez t1, handle_irq5
42 nop
43
44 /* Either someone has triggered the "software interrupts"
45 * or we lost an interrupt somehow. Ignore it.
46 */
47 j ret_from_irq
48 nop
49
50handle_irq0:
51 jal ip32_irq0
52 move a0, sp
53 j ret_from_irq
54 nop
55
56handle_irq1:
57 jal ip32_irq1
58 move a0, sp
59 j ret_from_irq
60 nop
61
62handle_irq2:
63 jal ip32_irq2
64 move a0, sp
65 j ret_from_irq
66 nop
67
68handle_irq3:
69 jal ip32_irq3
70 move a0, sp
71 j ret_from_irq
72 nop
73
74handle_irq4:
75 jal ip32_irq4
76 move a0, sp
77 j ret_from_irq
78 nop
79
80handle_irq5:
81 jal ip32_irq5
82 move a0, sp
83 j ret_from_irq
84 nop
85
86 END(ip32_handle_int)
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
new file mode 100644
index 000000000000..fc3a8e90d763
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -0,0 +1,590 @@
1/*
2 * Code to handle IP32 IRQs
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) 2000 Harald Koerfgen
9 * Copyright (C) 2001 Keith M Wesolowski
10 */
11#include <linux/init.h>
12#include <linux/kernel_stat.h>
13#include <linux/types.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/bitops.h>
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/mm.h>
20#include <linux/random.h>
21#include <linux/sched.h>
22
23#include <asm/mipsregs.h>
24#include <asm/signal.h>
25#include <asm/system.h>
26#include <asm/time.h>
27#include <asm/ip32/crime.h>
28#include <asm/ip32/mace.h>
29#include <asm/ip32/ip32_ints.h>
30
31/* issue a PIO read to make sure no PIO writes are pending */
32static void inline flush_crime_bus(void)
33{
34 volatile unsigned long junk = crime->control;
35}
36
37static void inline flush_mace_bus(void)
38{
39 volatile unsigned long junk = mace->perif.ctrl.misc;
40}
41
42#undef DEBUG_IRQ
43#ifdef DEBUG_IRQ
44#define DBG(x...) printk(x)
45#else
46#define DBG(x...)
47#endif
48
49/* O2 irq map
50 *
51 * IP0 -> software (ignored)
52 * IP1 -> software (ignored)
53 * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
54 * IP3 -> (irq1) X unknown
55 * IP4 -> (irq2) X unknown
56 * IP5 -> (irq3) X unknown
57 * IP6 -> (irq4) X unknown
58 * IP7 -> (irq5) 0 CPU count/compare timer (system timer)
59 *
60 * crime: (C)
61 *
62 * CRIME_INT_STAT 31:0:
63 *
64 * 0 -> 1 Video in 1
65 * 1 -> 2 Video in 2
66 * 2 -> 3 Video out
67 * 3 -> 4 Mace ethernet
68 * 4 -> S SuperIO sub-interrupt
69 * 5 -> M Miscellaneous sub-interrupt
70 * 6 -> A Audio sub-interrupt
71 * 7 -> 8 PCI bridge errors
72 * 8 -> 9 PCI SCSI aic7xxx 0
73 * 9 -> 10 PCI SCSI aic7xxx 1
74 * 10 -> 11 PCI slot 0
75 * 11 -> 12 unused (PCI slot 1)
76 * 12 -> 13 unused (PCI slot 2)
77 * 13 -> 14 unused (PCI shared 0)
78 * 14 -> 15 unused (PCI shared 1)
79 * 15 -> 16 unused (PCI shared 2)
80 * 16 -> 17 GBE0 (E)
81 * 17 -> 18 GBE1 (E)
82 * 18 -> 19 GBE2 (E)
83 * 19 -> 20 GBE3 (E)
84 * 20 -> 21 CPU errors
85 * 21 -> 22 Memory errors
86 * 22 -> 23 RE empty edge (E)
87 * 23 -> 24 RE full edge (E)
88 * 24 -> 25 RE idle edge (E)
89 * 25 -> 26 RE empty level
90 * 26 -> 27 RE full level
91 * 27 -> 28 RE idle level
92 * 28 -> 29 unused (software 0) (E)
93 * 29 -> 30 unused (software 1) (E)
94 * 30 -> 31 unused (software 2) - crime 1.5 CPU SysCorError (E)
95 * 31 -> 32 VICE
96 *
97 * S, M, A: Use the MACE ISA interrupt register
98 * MACE_ISA_INT_STAT 31:0
99 *
100 * 0-7 -> 33-40 Audio
101 * 8 -> 41 RTC
102 * 9 -> 42 Keyboard
103 * 10 -> X Keyboard polled
104 * 11 -> 44 Mouse
105 * 12 -> X Mouse polled
106 * 13-15 -> 46-48 Count/compare timers
107 * 16-19 -> 49-52 Parallel (16 E)
108 * 20-25 -> 53-58 Serial 1 (22 E)
109 * 26-31 -> 59-64 Serial 2 (28 E)
110 *
111 * Note that this means IRQs 5-7, 43, and 45 do not exist. This is a
112 * different IRQ map than IRIX uses, but that's OK as Linux irq handling
113 * is quite different anyway.
114 */
115
116/*
117 * IRQ spinlock - Ralf says not to disable CPU interrupts,
118 * and I think he knows better.
119 */
120static DEFINE_SPINLOCK(ip32_irq_lock);
121
122/* Some initial interrupts to set up */
123extern irqreturn_t crime_memerr_intr (int irq, void *dev_id,
124 struct pt_regs *regs);
125extern irqreturn_t crime_cpuerr_intr (int irq, void *dev_id,
126 struct pt_regs *regs);
127
128struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
129 CPU_MASK_NONE, "CRIME memory error", NULL, NULL };
130struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
131 CPU_MASK_NONE, "CRIME CPU error", NULL, NULL };
132
133extern void ip32_handle_int(void);
134
135/*
136 * For interrupts wired from a single device to the CPU. Only the clock
137 * uses this it seems, which is IRQ 0 and IP7.
138 */
139
140static void enable_cpu_irq(unsigned int irq)
141{
142 set_c0_status(STATUSF_IP7);
143}
144
145static unsigned int startup_cpu_irq(unsigned int irq)
146{
147 enable_cpu_irq(irq);
148 return 0;
149}
150
151static void disable_cpu_irq(unsigned int irq)
152{
153 clear_c0_status(STATUSF_IP7);
154}
155
156static void end_cpu_irq(unsigned int irq)
157{
158 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
159 enable_cpu_irq (irq);
160}
161
162#define shutdown_cpu_irq disable_cpu_irq
163#define mask_and_ack_cpu_irq disable_cpu_irq
164
165static struct hw_interrupt_type ip32_cpu_interrupt = {
166 "IP32 CPU",
167 startup_cpu_irq,
168 shutdown_cpu_irq,
169 enable_cpu_irq,
170 disable_cpu_irq,
171 mask_and_ack_cpu_irq,
172 end_cpu_irq,
173 NULL
174};
175
176/*
177 * This is for pure CRIME interrupts - ie not MACE. The advantage?
178 * We get to split the register in half and do faster lookups.
179 */
180
181static uint64_t crime_mask;
182
183static void enable_crime_irq(unsigned int irq)
184{
185 unsigned long flags;
186
187 spin_lock_irqsave(&ip32_irq_lock, flags);
188 crime_mask |= 1 << (irq - 1);
189 crime->imask = crime_mask;
190 spin_unlock_irqrestore(&ip32_irq_lock, flags);
191}
192
193static unsigned int startup_crime_irq(unsigned int irq)
194{
195 enable_crime_irq(irq);
196 return 0; /* This is probably not right; we could have pending irqs */
197}
198
199static void disable_crime_irq(unsigned int irq)
200{
201 unsigned long flags;
202
203 spin_lock_irqsave(&ip32_irq_lock, flags);
204 crime_mask &= ~(1 << (irq - 1));
205 crime->imask = crime_mask;
206 flush_crime_bus();
207 spin_unlock_irqrestore(&ip32_irq_lock, flags);
208}
209
210static void mask_and_ack_crime_irq(unsigned int irq)
211{
212 unsigned long flags;
213
214 /* Edge triggered interrupts must be cleared. */
215 if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ)
216 || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ)
217 || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) {
218 uint64_t crime_int;
219 spin_lock_irqsave(&ip32_irq_lock, flags);
220 crime_int = crime->hard_int;
221 crime_int &= ~(1 << (irq - 1));
222 crime->hard_int = crime_int;
223 spin_unlock_irqrestore(&ip32_irq_lock, flags);
224 }
225 disable_crime_irq(irq);
226}
227
228static void end_crime_irq(unsigned int irq)
229{
230 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
231 enable_crime_irq(irq);
232}
233
234#define shutdown_crime_irq disable_crime_irq
235
236static struct hw_interrupt_type ip32_crime_interrupt = {
237 "IP32 CRIME",
238 startup_crime_irq,
239 shutdown_crime_irq,
240 enable_crime_irq,
241 disable_crime_irq,
242 mask_and_ack_crime_irq,
243 end_crime_irq,
244 NULL
245};
246
247/*
248 * This is for MACE PCI interrupts. We can decrease bus traffic by masking
249 * as close to the source as possible. This also means we can take the
250 * next chunk of the CRIME register in one piece.
251 */
252
253static unsigned long macepci_mask;
254
255static void enable_macepci_irq(unsigned int irq)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&ip32_irq_lock, flags);
260 macepci_mask |= MACEPCI_CONTROL_INT(irq - 9);
261 mace->pci.control = macepci_mask;
262 crime_mask |= 1 << (irq - 1);
263 crime->imask = crime_mask;
264 spin_unlock_irqrestore(&ip32_irq_lock, flags);
265}
266
267static unsigned int startup_macepci_irq(unsigned int irq)
268{
269 enable_macepci_irq (irq);
270 return 0;
271}
272
273static void disable_macepci_irq(unsigned int irq)
274{
275 unsigned long flags;
276
277 spin_lock_irqsave(&ip32_irq_lock, flags);
278 crime_mask &= ~(1 << (irq - 1));
279 crime->imask = crime_mask;
280 flush_crime_bus();
281 macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
282 mace->pci.control = macepci_mask;
283 flush_mace_bus();
284 spin_unlock_irqrestore(&ip32_irq_lock, flags);
285}
286
287static void end_macepci_irq(unsigned int irq)
288{
289 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
290 enable_macepci_irq(irq);
291}
292
293#define shutdown_macepci_irq disable_macepci_irq
294#define mask_and_ack_macepci_irq disable_macepci_irq
295
296static struct hw_interrupt_type ip32_macepci_interrupt = {
297 "IP32 MACE PCI",
298 startup_macepci_irq,
299 shutdown_macepci_irq,
300 enable_macepci_irq,
301 disable_macepci_irq,
302 mask_and_ack_macepci_irq,
303 end_macepci_irq,
304 NULL
305};
306
307/* This is used for MACE ISA interrupts. That means bits 4-6 in the
308 * CRIME register.
309 */
310
311#define MACEISA_AUDIO_INT (MACEISA_AUDIO_SW_INT | \
312 MACEISA_AUDIO_SC_INT | \
313 MACEISA_AUDIO1_DMAT_INT | \
314 MACEISA_AUDIO1_OF_INT | \
315 MACEISA_AUDIO2_DMAT_INT | \
316 MACEISA_AUDIO2_MERR_INT | \
317 MACEISA_AUDIO3_DMAT_INT | \
318 MACEISA_AUDIO3_MERR_INT)
319#define MACEISA_MISC_INT (MACEISA_RTC_INT | \
320 MACEISA_KEYB_INT | \
321 MACEISA_KEYB_POLL_INT | \
322 MACEISA_MOUSE_INT | \
323 MACEISA_MOUSE_POLL_INT | \
324 MACEISA_TIMER0_INT | \
325 MACEISA_TIMER1_INT | \
326 MACEISA_TIMER2_INT)
327#define MACEISA_SUPERIO_INT (MACEISA_PARALLEL_INT | \
328 MACEISA_PAR_CTXA_INT | \
329 MACEISA_PAR_CTXB_INT | \
330 MACEISA_PAR_MERR_INT | \
331 MACEISA_SERIAL1_INT | \
332 MACEISA_SERIAL1_TDMAT_INT | \
333 MACEISA_SERIAL1_TDMAPR_INT | \
334 MACEISA_SERIAL1_TDMAME_INT | \
335 MACEISA_SERIAL1_RDMAT_INT | \
336 MACEISA_SERIAL1_RDMAOR_INT | \
337 MACEISA_SERIAL2_INT | \
338 MACEISA_SERIAL2_TDMAT_INT | \
339 MACEISA_SERIAL2_TDMAPR_INT | \
340 MACEISA_SERIAL2_TDMAME_INT | \
341 MACEISA_SERIAL2_RDMAT_INT | \
342 MACEISA_SERIAL2_RDMAOR_INT)
343
344static unsigned long maceisa_mask;
345
346static void enable_maceisa_irq (unsigned int irq)
347{
348 unsigned int crime_int = 0;
349 unsigned long flags;
350
351 DBG ("maceisa enable: %u\n", irq);
352
353 switch (irq) {
354 case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
355 crime_int = MACE_AUDIO_INT;
356 break;
357 case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
358 crime_int = MACE_MISC_INT;
359 break;
360 case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
361 crime_int = MACE_SUPERIO_INT;
362 break;
363 }
364 DBG ("crime_int %08x enabled\n", crime_int);
365 spin_lock_irqsave(&ip32_irq_lock, flags);
366 crime_mask |= crime_int;
367 crime->imask = crime_mask;
368 maceisa_mask |= 1 << (irq - 33);
369 mace->perif.ctrl.imask = maceisa_mask;
370 spin_unlock_irqrestore(&ip32_irq_lock, flags);
371}
372
373static unsigned int startup_maceisa_irq(unsigned int irq)
374{
375 enable_maceisa_irq(irq);
376 return 0;
377}
378
379static void disable_maceisa_irq(unsigned int irq)
380{
381 unsigned int crime_int = 0;
382 unsigned long flags;
383
384 spin_lock_irqsave(&ip32_irq_lock, flags);
385 maceisa_mask &= ~(1 << (irq - 33));
386 if(!(maceisa_mask & MACEISA_AUDIO_INT))
387 crime_int |= MACE_AUDIO_INT;
388 if(!(maceisa_mask & MACEISA_MISC_INT))
389 crime_int |= MACE_MISC_INT;
390 if(!(maceisa_mask & MACEISA_SUPERIO_INT))
391 crime_int |= MACE_SUPERIO_INT;
392 crime_mask &= ~crime_int;
393 crime->imask = crime_mask;
394 flush_crime_bus();
395 mace->perif.ctrl.imask = maceisa_mask;
396 flush_mace_bus();
397 spin_unlock_irqrestore(&ip32_irq_lock, flags);
398}
399
400static void mask_and_ack_maceisa_irq(unsigned int irq)
401{
402 unsigned long mace_int, flags;
403
404 switch (irq) {
405 case MACEISA_PARALLEL_IRQ:
406 case MACEISA_SERIAL1_TDMAPR_IRQ:
407 case MACEISA_SERIAL2_TDMAPR_IRQ:
408 /* edge triggered */
409 spin_lock_irqsave(&ip32_irq_lock, flags);
410 mace_int = mace->perif.ctrl.istat;
411 mace_int &= ~(1 << (irq - 33));
412 mace->perif.ctrl.istat = mace_int;
413 spin_unlock_irqrestore(&ip32_irq_lock, flags);
414 break;
415 }
416 disable_maceisa_irq(irq);
417}
418
419static void end_maceisa_irq(unsigned irq)
420{
421 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
422 enable_maceisa_irq(irq);
423}
424
425#define shutdown_maceisa_irq disable_maceisa_irq
426
427static struct hw_interrupt_type ip32_maceisa_interrupt = {
428 "IP32 MACE ISA",
429 startup_maceisa_irq,
430 shutdown_maceisa_irq,
431 enable_maceisa_irq,
432 disable_maceisa_irq,
433 mask_and_ack_maceisa_irq,
434 end_maceisa_irq,
435 NULL
436};
437
438/* This is used for regular non-ISA, non-PCI MACE interrupts. That means
439 * bits 0-3 and 7 in the CRIME register.
440 */
441
442static void enable_mace_irq(unsigned int irq)
443{
444 unsigned long flags;
445
446 spin_lock_irqsave(&ip32_irq_lock, flags);
447 crime_mask |= 1 << (irq - 1);
448 crime->imask = crime_mask;
449 spin_unlock_irqrestore(&ip32_irq_lock, flags);
450}
451
452static unsigned int startup_mace_irq(unsigned int irq)
453{
454 enable_mace_irq(irq);
455 return 0;
456}
457
458static void disable_mace_irq(unsigned int irq)
459{
460 unsigned long flags;
461
462 spin_lock_irqsave(&ip32_irq_lock, flags);
463 crime_mask &= ~(1 << (irq - 1));
464 crime->imask = crime_mask;
465 flush_crime_bus();
466 spin_unlock_irqrestore(&ip32_irq_lock, flags);
467}
468
469static void end_mace_irq(unsigned int irq)
470{
471 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
472 enable_mace_irq(irq);
473}
474
475#define shutdown_mace_irq disable_mace_irq
476#define mask_and_ack_mace_irq disable_mace_irq
477
478static struct hw_interrupt_type ip32_mace_interrupt = {
479 "IP32 MACE",
480 startup_mace_irq,
481 shutdown_mace_irq,
482 enable_mace_irq,
483 disable_mace_irq,
484 mask_and_ack_mace_irq,
485 end_mace_irq,
486 NULL
487};
488
489static void ip32_unknown_interrupt(struct pt_regs *regs)
490{
491 printk ("Unknown interrupt occurred!\n");
492 printk ("cp0_status: %08x\n", read_c0_status());
493 printk ("cp0_cause: %08x\n", read_c0_cause());
494 printk ("CRIME intr mask: %016lx\n", crime->imask);
495 printk ("CRIME intr status: %016lx\n", crime->istat);
496 printk ("CRIME hardware intr register: %016lx\n", crime->hard_int);
497 printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask);
498 printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat);
499 printk ("MACE PCI control register: %08x\n", mace->pci.control);
500
501 printk("Register dump:\n");
502 show_regs(regs);
503
504 printk("Please mail this report to linux-mips@linux-mips.org\n");
505 printk("Spinning...");
506 while(1) ;
507}
508
509/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
510/* change this to loop over all edge-triggered irqs, exception masked out ones */
511void ip32_irq0(struct pt_regs *regs)
512{
513 uint64_t crime_int;
514 int irq = 0;
515
516 crime_int = crime->istat & crime_mask;
517 irq = ffs(crime_int);
518 crime_int = 1 << (irq - 1);
519
520 if (crime_int & CRIME_MACEISA_INT_MASK) {
521 unsigned long mace_int = mace->perif.ctrl.istat;
522 irq = ffs(mace_int & maceisa_mask) + 32;
523 }
524 DBG("*irq %u*\n", irq);
525 do_IRQ(irq, regs);
526}
527
528void ip32_irq1(struct pt_regs *regs)
529{
530 ip32_unknown_interrupt(regs);
531}
532
533void ip32_irq2(struct pt_regs *regs)
534{
535 ip32_unknown_interrupt(regs);
536}
537
538void ip32_irq3(struct pt_regs *regs)
539{
540 ip32_unknown_interrupt(regs);
541}
542
543void ip32_irq4(struct pt_regs *regs)
544{
545 ip32_unknown_interrupt(regs);
546}
547
548void ip32_irq5(struct pt_regs *regs)
549{
550 ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
551}
552
553void __init arch_init_irq(void)
554{
555 unsigned int irq;
556
557 /* Install our interrupt handler, then clear and disable all
558 * CRIME and MACE interrupts. */
559 crime->imask = 0;
560 crime->hard_int = 0;
561 crime->soft_int = 0;
562 mace->perif.ctrl.istat = 0;
563 mace->perif.ctrl.imask = 0;
564 set_except_vector(0, ip32_handle_int);
565
566 for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
567 hw_irq_controller *controller;
568
569 if (irq == IP32_R4K_TIMER_IRQ)
570 controller = &ip32_cpu_interrupt;
571 else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ)
572 controller = &ip32_mace_interrupt;
573 else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ)
574 controller = &ip32_macepci_interrupt;
575 else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ)
576 controller = &ip32_crime_interrupt;
577 else
578 controller = &ip32_maceisa_interrupt;
579
580 irq_desc[irq].status = IRQ_DISABLED;
581 irq_desc[irq].action = 0;
582 irq_desc[irq].depth = 0;
583 irq_desc[irq].handler = controller;
584 }
585 setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
586 setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
587
588#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
589 change_c0_status(ST0_IM, ALLINTS);
590}
diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c
new file mode 100644
index 000000000000..fc76ca92bab9
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-memory.c
@@ -0,0 +1,49 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2003 Keith M Wesolowski
7 * Copyright (C) 2005 Ilya A. Volynets (Total Knowledge)
8 */
9#include <linux/types.h>
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/mm.h>
13
14#include <asm/ip32/crime.h>
15#include <asm/bootinfo.h>
16#include <asm/page.h>
17#include <asm/pgtable.h>
18#include <asm/pgalloc.h>
19
20extern void crime_init(void);
21
22void __init prom_meminit (void)
23{
24 u64 base, size;
25 int bank;
26
27 crime_init();
28
29 for (bank=0; bank < CRIME_MAXBANKS; bank++) {
30 u64 bankctl = crime->bank_ctrl[bank];
31 base = (bankctl & CRIME_MEM_BANK_CONTROL_ADDR) << 25;
32 if (bank != 0 && base == 0)
33 continue;
34 size = (bankctl & CRIME_MEM_BANK_CONTROL_SDRAM_SIZE) ? 128 : 32;
35 size <<= 20;
36 if (base + size > (256 << 20))
37 base += CRIME_HI_MEM_BASE;
38
39 printk("CRIME MC: bank %u base 0x%016lx size %luMB\n",
40 bank, base, size);
41 add_memory_region (base, size, BOOT_MEM_RAM);
42 }
43}
44
45
46unsigned long __init prom_free_prom_memory (void)
47{
48 return 0;
49}
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
new file mode 100644
index 000000000000..281f090e48a4
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -0,0 +1,202 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2001 Keith M Wesolowski
7 * Copyright (C) 2001 Paul Mundt
8 * Copyright (C) 2003 Guido Guenther <agx@sigxcpu.org>
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/notifier.h>
15#include <linux/delay.h>
16#include <linux/ds17287rtc.h>
17#include <linux/interrupt.h>
18
19#include <asm/addrspace.h>
20#include <asm/irq.h>
21#include <asm/reboot.h>
22#include <asm/system.h>
23#include <asm/wbflush.h>
24#include <asm/ip32/mace.h>
25#include <asm/ip32/crime.h>
26#include <asm/ip32/ip32_ints.h>
27
28#define POWERDOWN_TIMEOUT 120
29/*
30 * Blink frequency during reboot grace period and when paniced.
31 */
32#define POWERDOWN_FREQ (HZ / 4)
33#define PANIC_FREQ (HZ / 8)
34
35static struct timer_list power_timer, blink_timer, debounce_timer;
36static int has_paniced, shuting_down;
37
38static void ip32_machine_restart(char *command) __attribute__((noreturn));
39static void ip32_machine_halt(void) __attribute__((noreturn));
40static void ip32_machine_power_off(void) __attribute__((noreturn));
41
42static void ip32_machine_restart(char *cmd)
43{
44 crime->control = CRIME_CONTROL_HARD_RESET;
45 while (1);
46}
47
48static inline void ip32_machine_halt(void)
49{
50 ip32_machine_power_off();
51}
52
53static void ip32_machine_power_off(void)
54{
55 volatile unsigned char reg_a, xctrl_a, xctrl_b;
56
57 disable_irq(MACEISA_RTC_IRQ);
58 reg_a = CMOS_READ(RTC_REG_A);
59
60 /* setup for kickstart & wake-up (DS12287 Ref. Man. p. 19) */
61 reg_a &= ~DS_REGA_DV2;
62 reg_a |= DS_REGA_DV1;
63
64 CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A);
65 wbflush();
66 xctrl_b = CMOS_READ(DS_B1_XCTRL4B)
67 | DS_XCTRL4B_ABE | DS_XCTRL4B_KFE;
68 CMOS_WRITE(xctrl_b, DS_B1_XCTRL4B);
69 xctrl_a = CMOS_READ(DS_B1_XCTRL4A) & ~DS_XCTRL4A_IFS;
70 CMOS_WRITE(xctrl_a, DS_B1_XCTRL4A);
71 wbflush();
72 /* adios amigos... */
73 CMOS_WRITE(xctrl_a | DS_XCTRL4A_PAB, DS_B1_XCTRL4A);
74 CMOS_WRITE(reg_a, RTC_REG_A);
75 wbflush();
76 while (1);
77}
78
79static void power_timeout(unsigned long data)
80{
81 ip32_machine_power_off();
82}
83
84static void blink_timeout(unsigned long data)
85{
86 unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED;
87 mace->perif.ctrl.misc = led;
88 mod_timer(&blink_timer, jiffies + data);
89}
90
91static void debounce(unsigned long data)
92{
93 volatile unsigned char reg_a, reg_c, xctrl_a;
94
95 reg_c = CMOS_READ(RTC_INTR_FLAGS);
96 CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A);
97 wbflush();
98 xctrl_a = CMOS_READ(DS_B1_XCTRL4A);
99 if ((xctrl_a & DS_XCTRL4A_IFS) || (reg_c & RTC_IRQF )) {
100 /* Interrupt still being sent. */
101 debounce_timer.expires = jiffies + 50;
102 add_timer(&debounce_timer);
103
104 /* clear interrupt source */
105 CMOS_WRITE(xctrl_a & ~DS_XCTRL4A_IFS, DS_B1_XCTRL4A);
106 CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A);
107 return;
108 }
109 CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A);
110
111 if (has_paniced)
112 ip32_machine_restart(NULL);
113
114 enable_irq(MACEISA_RTC_IRQ);
115}
116
117static inline void ip32_power_button(void)
118{
119 if (has_paniced)
120 return;
121
122 if (shuting_down || kill_proc(1, SIGINT, 1)) {
123 /* No init process or button pressed twice. */
124 ip32_machine_power_off();
125 }
126
127 shuting_down = 1;
128 blink_timer.data = POWERDOWN_FREQ;
129 blink_timeout(POWERDOWN_FREQ);
130
131 init_timer(&power_timer);
132 power_timer.function = power_timeout;
133 power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
134 add_timer(&power_timer);
135}
136
137static irqreturn_t ip32_rtc_int(int irq, void *dev_id, struct pt_regs *regs)
138{
139 volatile unsigned char reg_c;
140
141 reg_c = CMOS_READ(RTC_INTR_FLAGS);
142 if (!(reg_c & RTC_IRQF)) {
143 printk(KERN_WARNING
144 "%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__);
145 }
146 /* Wait until interrupt goes away */
147 disable_irq(MACEISA_RTC_IRQ);
148 init_timer(&debounce_timer);
149 debounce_timer.function = debounce;
150 debounce_timer.expires = jiffies + 50;
151 add_timer(&debounce_timer);
152
153 printk(KERN_DEBUG "Power button pressed\n");
154 ip32_power_button();
155 return IRQ_HANDLED;
156}
157
158static int panic_event(struct notifier_block *this, unsigned long event,
159 void *ptr)
160{
161 unsigned long led;
162
163 if (has_paniced)
164 return NOTIFY_DONE;
165 has_paniced = 1;
166
167 /* turn off the green LED */
168 led = mace->perif.ctrl.misc | MACEISA_LED_GREEN;
169 mace->perif.ctrl.misc = led;
170
171 blink_timer.data = PANIC_FREQ;
172 blink_timeout(PANIC_FREQ);
173
174 return NOTIFY_DONE;
175}
176
177static struct notifier_block panic_block = {
178 .notifier_call = panic_event,
179};
180
181static __init int ip32_reboot_setup(void)
182{
183 /* turn on the green led only */
184 unsigned long led = mace->perif.ctrl.misc;
185 led |= MACEISA_LED_RED;
186 led &= ~MACEISA_LED_GREEN;
187 mace->perif.ctrl.misc = led;
188
189 _machine_restart = ip32_machine_restart;
190 _machine_halt = ip32_machine_halt;
191 _machine_power_off = ip32_machine_power_off;
192
193 init_timer(&blink_timer);
194 blink_timer.function = blink_timeout;
195 notifier_chain_register(&panic_notifier_list, &panic_block);
196
197 request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL);
198
199 return 0;
200}
201
202subsys_initcall(ip32_reboot_setup);
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
new file mode 100644
index 000000000000..8d270be58224
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-setup.c
@@ -0,0 +1,159 @@
1/*
2 * IP32 basic setup
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) 2000 Harald Koerfgen
9 * Copyright (C) 2002, 2003, 2005 Ilya A. Volynets
10 */
11#include <linux/config.h>
12#include <linux/console.h>
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/mc146818rtc.h>
16#include <linux/param.h>
17#include <linux/sched.h>
18
19#include <asm/bootinfo.h>
20#include <asm/mc146818-time.h>
21#include <asm/mipsregs.h>
22#include <asm/mmu_context.h>
23#include <asm/sgialib.h>
24#include <asm/time.h>
25#include <asm/traps.h>
26#include <asm/io.h>
27#include <asm/ip32/crime.h>
28#include <asm/ip32/mace.h>
29#include <asm/ip32/ip32_ints.h>
30
31extern void ip32_be_init(void);
32extern void crime_init(void);
33
34#ifdef CONFIG_SGI_O2MACE_ETH
35/*
36 * This is taken care of in here 'cause they say using Arc later on is
37 * problematic
38 */
39extern char o2meth_eaddr[8];
40static inline unsigned char str2hexnum(unsigned char c)
41{
42 if (c >= '0' && c <= '9')
43 return c - '0';
44 if (c >= 'a' && c <= 'f')
45 return c - 'a' + 10;
46 return 0; /* foo */
47}
48
49static inline void str2eaddr(unsigned char *ea, unsigned char *str)
50{
51 int i;
52
53 for (i = 0; i < 6; i++) {
54 unsigned char num;
55
56 if(*str == ':')
57 str++;
58 num = str2hexnum(*str++) << 4;
59 num |= (str2hexnum(*str++));
60 ea[i] = num;
61 }
62}
63#endif
64
65#ifdef CONFIG_SERIAL_8250
66#include <linux/tty.h>
67#include <linux/serial.h>
68#include <linux/serial_core.h>
69extern int early_serial_setup(struct uart_port *port);
70
71#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
72#define BASE_BAUD (1843200 / 16)
73
74#endif /* CONFIG_SERIAL_8250 */
75
76/* An arbitrary time; this can be decreased if reliability looks good */
77#define WAIT_MS 10
78
79void __init ip32_time_init(void)
80{
81 printk(KERN_INFO "Calibrating system timer... ");
82 write_c0_count(0);
83 crime->timer = 0;
84 while (crime->timer < CRIME_MASTER_FREQ * WAIT_MS / 1000) ;
85 mips_hpt_frequency = read_c0_count() * 1000 / WAIT_MS;
86 printk("%d MHz CPU detected\n", mips_hpt_frequency * 2 / 1000000);
87}
88
89void __init ip32_timer_setup(struct irqaction *irq)
90{
91 irq->handler = no_action;
92 setup_irq(IP32_R4K_TIMER_IRQ, irq);
93}
94
95static int __init ip32_setup(void)
96{
97 board_be_init = ip32_be_init;
98
99 rtc_get_time = mc146818_get_cmos_time;
100 rtc_set_mmss = mc146818_set_rtc_mmss;
101
102 board_time_init = ip32_time_init;
103 board_timer_setup = ip32_timer_setup;
104
105#ifdef CONFIG_SERIAL_8250
106 {
107 static struct uart_port o2_serial[2];
108
109 memset(o2_serial, 0, sizeof(o2_serial));
110 o2_serial[0].type = PORT_16550A;
111 o2_serial[0].line = 0;
112 o2_serial[0].irq = MACEISA_SERIAL1_IRQ;
113 o2_serial[0].flags = STD_COM_FLAGS;
114 o2_serial[0].uartclk = BASE_BAUD * 16;
115 o2_serial[0].iotype = UPIO_MEM;
116 o2_serial[0].membase = (char *)&mace->isa.serial1;
117 o2_serial[0].fifosize = 14;
118 /* How much to shift register offset by. Each UART register
119 * is replicated over 256 byte space */
120 o2_serial[0].regshift = 8;
121 o2_serial[1].type = PORT_16550A;
122 o2_serial[1].line = 1;
123 o2_serial[1].irq = MACEISA_SERIAL2_IRQ;
124 o2_serial[1].flags = STD_COM_FLAGS;
125 o2_serial[1].uartclk = BASE_BAUD * 16;
126 o2_serial[1].iotype = UPIO_MEM;
127 o2_serial[1].membase = (char *)&mace->isa.serial2;
128 o2_serial[1].fifosize = 14;
129 o2_serial[1].regshift = 8;
130
131 early_serial_setup(&o2_serial[0]);
132 early_serial_setup(&o2_serial[1]);
133 }
134#endif
135#ifdef CONFIG_SGI_O2MACE_ETH
136 {
137 char *mac = ArcGetEnvironmentVariable("eaddr");
138 str2eaddr(o2meth_eaddr, mac);
139 }
140#endif
141
142#if defined(CONFIG_SERIAL_CORE_CONSOLE)
143 {
144 char* con = ArcGetEnvironmentVariable("console");
145 if (con && *con == 'd') {
146 static char options[8];
147 char *baud = ArcGetEnvironmentVariable("dbaud");
148 if (baud)
149 strcpy(options, baud);
150 add_preferred_console("ttyS", *(con + 1) == '2' ? 1 : 0,
151 baud ? options : NULL);
152 }
153 }
154#endif
155
156 return 0;
157}
158
159early_initcall(ip32_setup);