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/ppc/platforms/pmac_pic.c |
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/ppc/platforms/pmac_pic.c')
-rw-r--r-- | arch/ppc/platforms/pmac_pic.c | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c new file mode 100644 index 000000000000..9f92e1bb7f34 --- /dev/null +++ b/arch/ppc/platforms/pmac_pic.c | |||
@@ -0,0 +1,689 @@ | |||
1 | /* | ||
2 | * Support for the interrupt controllers found on Power Macintosh, | ||
3 | * currently Apple's "Grand Central" interrupt controller in all | ||
4 | * it's incarnations. OpenPIC support used on newer machines is | ||
5 | * in a separate file | ||
6 | * | ||
7 | * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au) | ||
8 | * | ||
9 | * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
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 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/stddef.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/signal.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | #include <linux/adb.h> | ||
27 | #include <linux/pmu.h> | ||
28 | |||
29 | #include <asm/sections.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/smp.h> | ||
32 | #include <asm/prom.h> | ||
33 | #include <asm/pci-bridge.h> | ||
34 | #include <asm/time.h> | ||
35 | #include <asm/open_pic.h> | ||
36 | #include <asm/xmon.h> | ||
37 | #include <asm/pmac_feature.h> | ||
38 | |||
39 | #include "pmac_pic.h" | ||
40 | |||
41 | /* | ||
42 | * XXX this should be in xmon.h, but putting it there means xmon.h | ||
43 | * has to include <linux/interrupt.h> (to get irqreturn_t), which | ||
44 | * causes all sorts of problems. -- paulus | ||
45 | */ | ||
46 | extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); | ||
47 | |||
48 | struct pmac_irq_hw { | ||
49 | unsigned int event; | ||
50 | unsigned int enable; | ||
51 | unsigned int ack; | ||
52 | unsigned int level; | ||
53 | }; | ||
54 | |||
55 | /* Default addresses */ | ||
56 | static volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmacdata = { | ||
57 | (struct pmac_irq_hw *) 0xf3000020, | ||
58 | (struct pmac_irq_hw *) 0xf3000010, | ||
59 | (struct pmac_irq_hw *) 0xf4000020, | ||
60 | (struct pmac_irq_hw *) 0xf4000010, | ||
61 | }; | ||
62 | |||
63 | #define GC_LEVEL_MASK 0x3ff00000 | ||
64 | #define OHARE_LEVEL_MASK 0x1ff00000 | ||
65 | #define HEATHROW_LEVEL_MASK 0x1ff00000 | ||
66 | |||
67 | static int max_irqs __pmacdata; | ||
68 | static int max_real_irqs __pmacdata; | ||
69 | static u32 level_mask[4] __pmacdata; | ||
70 | |||
71 | static DEFINE_SPINLOCK(pmac_pic_lock __pmacdata); | ||
72 | |||
73 | |||
74 | #define GATWICK_IRQ_POOL_SIZE 10 | ||
75 | static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE] __pmacdata; | ||
76 | |||
77 | /* | ||
78 | * Mark an irq as "lost". This is only used on the pmac | ||
79 | * since it can lose interrupts (see pmac_set_irq_mask). | ||
80 | * -- Cort | ||
81 | */ | ||
82 | void __pmac | ||
83 | __set_lost(unsigned long irq_nr, int nokick) | ||
84 | { | ||
85 | if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { | ||
86 | atomic_inc(&ppc_n_lost_interrupts); | ||
87 | if (!nokick) | ||
88 | set_dec(1); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void __pmac | ||
93 | pmac_mask_and_ack_irq(unsigned int irq_nr) | ||
94 | { | ||
95 | unsigned long bit = 1UL << (irq_nr & 0x1f); | ||
96 | int i = irq_nr >> 5; | ||
97 | unsigned long flags; | ||
98 | |||
99 | if ((unsigned)irq_nr >= max_irqs) | ||
100 | return; | ||
101 | |||
102 | clear_bit(irq_nr, ppc_cached_irq_mask); | ||
103 | if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
104 | atomic_dec(&ppc_n_lost_interrupts); | ||
105 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
106 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); | ||
107 | out_le32(&pmac_irq_hw[i]->ack, bit); | ||
108 | do { | ||
109 | /* make sure ack gets to controller before we enable | ||
110 | interrupts */ | ||
111 | mb(); | ||
112 | } while((in_le32(&pmac_irq_hw[i]->enable) & bit) | ||
113 | != (ppc_cached_irq_mask[i] & bit)); | ||
114 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
115 | } | ||
116 | |||
117 | static void __pmac pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | ||
118 | { | ||
119 | unsigned long bit = 1UL << (irq_nr & 0x1f); | ||
120 | int i = irq_nr >> 5; | ||
121 | unsigned long flags; | ||
122 | |||
123 | if ((unsigned)irq_nr >= max_irqs) | ||
124 | return; | ||
125 | |||
126 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
127 | /* enable unmasked interrupts */ | ||
128 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); | ||
129 | |||
130 | do { | ||
131 | /* make sure mask gets to controller before we | ||
132 | return to user */ | ||
133 | mb(); | ||
134 | } while((in_le32(&pmac_irq_hw[i]->enable) & bit) | ||
135 | != (ppc_cached_irq_mask[i] & bit)); | ||
136 | |||
137 | /* | ||
138 | * Unfortunately, setting the bit in the enable register | ||
139 | * when the device interrupt is already on *doesn't* set | ||
140 | * the bit in the flag register or request another interrupt. | ||
141 | */ | ||
142 | if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) | ||
143 | __set_lost((ulong)irq_nr, nokicklost); | ||
144 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
145 | } | ||
146 | |||
147 | /* When an irq gets requested for the first client, if it's an | ||
148 | * edge interrupt, we clear any previous one on the controller | ||
149 | */ | ||
150 | static unsigned int __pmac pmac_startup_irq(unsigned int irq_nr) | ||
151 | { | ||
152 | unsigned long bit = 1UL << (irq_nr & 0x1f); | ||
153 | int i = irq_nr >> 5; | ||
154 | |||
155 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) | ||
156 | out_le32(&pmac_irq_hw[i]->ack, bit); | ||
157 | set_bit(irq_nr, ppc_cached_irq_mask); | ||
158 | pmac_set_irq_mask(irq_nr, 0); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void __pmac pmac_mask_irq(unsigned int irq_nr) | ||
164 | { | ||
165 | clear_bit(irq_nr, ppc_cached_irq_mask); | ||
166 | pmac_set_irq_mask(irq_nr, 0); | ||
167 | mb(); | ||
168 | } | ||
169 | |||
170 | static void __pmac pmac_unmask_irq(unsigned int irq_nr) | ||
171 | { | ||
172 | set_bit(irq_nr, ppc_cached_irq_mask); | ||
173 | pmac_set_irq_mask(irq_nr, 0); | ||
174 | } | ||
175 | |||
176 | static void __pmac pmac_end_irq(unsigned int irq_nr) | ||
177 | { | ||
178 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | ||
179 | && irq_desc[irq_nr].action) { | ||
180 | set_bit(irq_nr, ppc_cached_irq_mask); | ||
181 | pmac_set_irq_mask(irq_nr, 1); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | |||
186 | struct hw_interrupt_type pmac_pic = { | ||
187 | .typename = " PMAC-PIC ", | ||
188 | .startup = pmac_startup_irq, | ||
189 | .enable = pmac_unmask_irq, | ||
190 | .disable = pmac_mask_irq, | ||
191 | .ack = pmac_mask_and_ack_irq, | ||
192 | .end = pmac_end_irq, | ||
193 | }; | ||
194 | |||
195 | struct hw_interrupt_type gatwick_pic = { | ||
196 | .typename = " GATWICK ", | ||
197 | .startup = pmac_startup_irq, | ||
198 | .enable = pmac_unmask_irq, | ||
199 | .disable = pmac_mask_irq, | ||
200 | .ack = pmac_mask_and_ack_irq, | ||
201 | .end = pmac_end_irq, | ||
202 | }; | ||
203 | |||
204 | static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) | ||
205 | { | ||
206 | int irq, bits; | ||
207 | |||
208 | for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { | ||
209 | int i = irq >> 5; | ||
210 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; | ||
211 | /* We must read level interrupts from the level register */ | ||
212 | bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); | ||
213 | bits &= ppc_cached_irq_mask[i]; | ||
214 | if (bits == 0) | ||
215 | continue; | ||
216 | irq += __ilog2(bits); | ||
217 | __do_IRQ(irq, regs); | ||
218 | return IRQ_HANDLED; | ||
219 | } | ||
220 | printk("gatwick irq not from gatwick pic\n"); | ||
221 | return IRQ_NONE; | ||
222 | } | ||
223 | |||
224 | int | ||
225 | pmac_get_irq(struct pt_regs *regs) | ||
226 | { | ||
227 | int irq; | ||
228 | unsigned long bits = 0; | ||
229 | |||
230 | #ifdef CONFIG_SMP | ||
231 | void psurge_smp_message_recv(struct pt_regs *); | ||
232 | |||
233 | /* IPI's are a hack on the powersurge -- Cort */ | ||
234 | if ( smp_processor_id() != 0 ) { | ||
235 | psurge_smp_message_recv(regs); | ||
236 | return -2; /* ignore, already handled */ | ||
237 | } | ||
238 | #endif /* CONFIG_SMP */ | ||
239 | for (irq = max_real_irqs; (irq -= 32) >= 0; ) { | ||
240 | int i = irq >> 5; | ||
241 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; | ||
242 | /* We must read level interrupts from the level register */ | ||
243 | bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]); | ||
244 | bits &= ppc_cached_irq_mask[i]; | ||
245 | if (bits == 0) | ||
246 | continue; | ||
247 | irq += __ilog2(bits); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | return irq; | ||
252 | } | ||
253 | |||
254 | /* This routine will fix some missing interrupt values in the device tree | ||
255 | * on the gatwick mac-io controller used by some PowerBooks | ||
256 | */ | ||
257 | static void __init | ||
258 | pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) | ||
259 | { | ||
260 | struct device_node *node; | ||
261 | int count; | ||
262 | |||
263 | memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool)); | ||
264 | node = gw->child; | ||
265 | count = 0; | ||
266 | while(node) | ||
267 | { | ||
268 | /* Fix SCC */ | ||
269 | if (strcasecmp(node->name, "escc") == 0) | ||
270 | if (node->child) { | ||
271 | if (node->child->n_intrs < 3) { | ||
272 | node->child->intrs = &gatwick_int_pool[count]; | ||
273 | count += 3; | ||
274 | } | ||
275 | node->child->n_intrs = 3; | ||
276 | node->child->intrs[0].line = 15+irq_base; | ||
277 | node->child->intrs[1].line = 4+irq_base; | ||
278 | node->child->intrs[2].line = 5+irq_base; | ||
279 | printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n", | ||
280 | node->child->intrs[0].line, | ||
281 | node->child->intrs[1].line, | ||
282 | node->child->intrs[2].line); | ||
283 | } | ||
284 | /* Fix media-bay & left SWIM */ | ||
285 | if (strcasecmp(node->name, "media-bay") == 0) { | ||
286 | struct device_node* ya_node; | ||
287 | |||
288 | if (node->n_intrs == 0) | ||
289 | node->intrs = &gatwick_int_pool[count++]; | ||
290 | node->n_intrs = 1; | ||
291 | node->intrs[0].line = 29+irq_base; | ||
292 | printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", | ||
293 | node->intrs[0].line); | ||
294 | |||
295 | ya_node = node->child; | ||
296 | while(ya_node) | ||
297 | { | ||
298 | if (strcasecmp(ya_node->name, "floppy") == 0) { | ||
299 | if (ya_node->n_intrs < 2) { | ||
300 | ya_node->intrs = &gatwick_int_pool[count]; | ||
301 | count += 2; | ||
302 | } | ||
303 | ya_node->n_intrs = 2; | ||
304 | ya_node->intrs[0].line = 19+irq_base; | ||
305 | ya_node->intrs[1].line = 1+irq_base; | ||
306 | printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", | ||
307 | ya_node->intrs[0].line, ya_node->intrs[1].line); | ||
308 | } | ||
309 | if (strcasecmp(ya_node->name, "ata4") == 0) { | ||
310 | if (ya_node->n_intrs < 2) { | ||
311 | ya_node->intrs = &gatwick_int_pool[count]; | ||
312 | count += 2; | ||
313 | } | ||
314 | ya_node->n_intrs = 2; | ||
315 | ya_node->intrs[0].line = 14+irq_base; | ||
316 | ya_node->intrs[1].line = 3+irq_base; | ||
317 | printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n", | ||
318 | ya_node->intrs[0].line, ya_node->intrs[1].line); | ||
319 | } | ||
320 | ya_node = ya_node->sibling; | ||
321 | } | ||
322 | } | ||
323 | node = node->sibling; | ||
324 | } | ||
325 | if (count > 10) { | ||
326 | printk("WARNING !! Gatwick interrupt pool overflow\n"); | ||
327 | printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE); | ||
328 | printk(" requested = %d\n", count); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * The PowerBook 3400/2400/3500 can have a combo ethernet/modem | ||
334 | * card which includes an ohare chip that acts as a second interrupt | ||
335 | * controller. If we find this second ohare, set it up and fix the | ||
336 | * interrupt value in the device tree for the ethernet chip. | ||
337 | */ | ||
338 | static int __init enable_second_ohare(void) | ||
339 | { | ||
340 | unsigned char bus, devfn; | ||
341 | unsigned short cmd; | ||
342 | unsigned long addr; | ||
343 | struct device_node *irqctrler = find_devices("pci106b,7"); | ||
344 | struct device_node *ether; | ||
345 | |||
346 | if (irqctrler == NULL || irqctrler->n_addrs <= 0) | ||
347 | return -1; | ||
348 | addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); | ||
349 | pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); | ||
350 | max_irqs = 64; | ||
351 | if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) { | ||
352 | struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler); | ||
353 | if (!hose) | ||
354 | printk(KERN_ERR "Can't find PCI hose for OHare2 !\n"); | ||
355 | else { | ||
356 | early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd); | ||
357 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | ||
358 | cmd &= ~PCI_COMMAND_IO; | ||
359 | early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | /* Fix interrupt for the modem/ethernet combo controller. The number | ||
364 | in the device tree (27) is bogus (correct for the ethernet-only | ||
365 | board but not the combo ethernet/modem board). | ||
366 | The real interrupt is 28 on the second controller -> 28+32 = 60. | ||
367 | */ | ||
368 | ether = find_devices("pci1011,14"); | ||
369 | if (ether && ether->n_intrs > 0) { | ||
370 | ether->intrs[0].line = 60; | ||
371 | printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", | ||
372 | ether->intrs[0].line); | ||
373 | } | ||
374 | |||
375 | /* Return the interrupt number of the cascade */ | ||
376 | return irqctrler->intrs[0].line; | ||
377 | } | ||
378 | |||
379 | #ifdef CONFIG_POWER4 | ||
380 | static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs) | ||
381 | { | ||
382 | int irq; | ||
383 | |||
384 | irq = openpic2_get_irq(regs); | ||
385 | if (irq != -1) | ||
386 | __do_IRQ(irq, regs); | ||
387 | return IRQ_HANDLED; | ||
388 | } | ||
389 | |||
390 | static struct irqaction k2u3_cascade_action = { | ||
391 | .handler = k2u3_action, | ||
392 | .flags = 0, | ||
393 | .mask = CPU_MASK_NONE, | ||
394 | .name = "U3->K2 Cascade", | ||
395 | }; | ||
396 | #endif /* CONFIG_POWER4 */ | ||
397 | |||
398 | #ifdef CONFIG_XMON | ||
399 | static struct irqaction xmon_action = { | ||
400 | .handler = xmon_irq, | ||
401 | .flags = 0, | ||
402 | .mask = CPU_MASK_NONE, | ||
403 | .name = "NMI - XMON" | ||
404 | }; | ||
405 | #endif | ||
406 | |||
407 | static struct irqaction gatwick_cascade_action = { | ||
408 | .handler = gatwick_action, | ||
409 | .flags = SA_INTERRUPT, | ||
410 | .mask = CPU_MASK_NONE, | ||
411 | .name = "cascade", | ||
412 | }; | ||
413 | |||
414 | void __init pmac_pic_init(void) | ||
415 | { | ||
416 | int i; | ||
417 | struct device_node *irqctrler = NULL; | ||
418 | struct device_node *irqctrler2 = NULL; | ||
419 | struct device_node *np; | ||
420 | unsigned long addr; | ||
421 | int irq_cascade = -1; | ||
422 | |||
423 | /* We first try to detect Apple's new Core99 chipset, since mac-io | ||
424 | * is quite different on those machines and contains an IBM MPIC2. | ||
425 | */ | ||
426 | np = find_type_devices("open-pic"); | ||
427 | while(np) { | ||
428 | if (np->parent && !strcmp(np->parent->name, "u3")) | ||
429 | irqctrler2 = np; | ||
430 | else | ||
431 | irqctrler = np; | ||
432 | np = np->next; | ||
433 | } | ||
434 | if (irqctrler != NULL) | ||
435 | { | ||
436 | if (irqctrler->n_addrs > 0) | ||
437 | { | ||
438 | unsigned char senses[128]; | ||
439 | |||
440 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", | ||
441 | irqctrler->addrs[0].address); | ||
442 | |||
443 | prom_get_irq_senses(senses, 0, 128); | ||
444 | OpenPIC_InitSenses = senses; | ||
445 | OpenPIC_NumInitSenses = 128; | ||
446 | ppc_md.get_irq = openpic_get_irq; | ||
447 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0); | ||
448 | OpenPIC_Addr = ioremap(irqctrler->addrs[0].address, | ||
449 | irqctrler->addrs[0].size); | ||
450 | openpic_init(0); | ||
451 | |||
452 | #ifdef CONFIG_POWER4 | ||
453 | if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && | ||
454 | irqctrler2->n_addrs > 0) { | ||
455 | printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", | ||
456 | irqctrler2->addrs[0].address, | ||
457 | irqctrler2->intrs[0].line); | ||
458 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); | ||
459 | OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address, | ||
460 | irqctrler2->addrs[0].size); | ||
461 | prom_get_irq_senses(senses, PMAC_OPENPIC2_OFFSET, | ||
462 | PMAC_OPENPIC2_OFFSET+128); | ||
463 | OpenPIC_InitSenses = senses; | ||
464 | OpenPIC_NumInitSenses = 128; | ||
465 | openpic2_init(PMAC_OPENPIC2_OFFSET); | ||
466 | |||
467 | if (setup_irq(irqctrler2->intrs[0].line, | ||
468 | &k2u3_cascade_action)) | ||
469 | printk("Unable to get OpenPIC IRQ for cascade\n"); | ||
470 | } | ||
471 | #endif /* CONFIG_POWER4 */ | ||
472 | |||
473 | #ifdef CONFIG_XMON | ||
474 | { | ||
475 | struct device_node* pswitch; | ||
476 | int nmi_irq; | ||
477 | |||
478 | pswitch = find_devices("programmer-switch"); | ||
479 | if (pswitch && pswitch->n_intrs) { | ||
480 | nmi_irq = pswitch->intrs[0].line; | ||
481 | openpic_init_nmi_irq(nmi_irq); | ||
482 | setup_irq(nmi_irq, &xmon_action); | ||
483 | } | ||
484 | } | ||
485 | #endif /* CONFIG_XMON */ | ||
486 | return; | ||
487 | } | ||
488 | irqctrler = NULL; | ||
489 | } | ||
490 | |||
491 | /* Get the level/edge settings, assume if it's not | ||
492 | * a Grand Central nor an OHare, then it's an Heathrow | ||
493 | * (or Paddington). | ||
494 | */ | ||
495 | if (find_devices("gc")) | ||
496 | level_mask[0] = GC_LEVEL_MASK; | ||
497 | else if (find_devices("ohare")) { | ||
498 | level_mask[0] = OHARE_LEVEL_MASK; | ||
499 | /* We might have a second cascaded ohare */ | ||
500 | level_mask[1] = OHARE_LEVEL_MASK; | ||
501 | } else { | ||
502 | level_mask[0] = HEATHROW_LEVEL_MASK; | ||
503 | level_mask[1] = 0; | ||
504 | /* We might have a second cascaded heathrow */ | ||
505 | level_mask[2] = HEATHROW_LEVEL_MASK; | ||
506 | level_mask[3] = 0; | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, | ||
511 | * 1998 G3 Series PowerBooks have 128, | ||
512 | * other powermacs have 32. | ||
513 | * The combo ethernet/modem card for the Powerstar powerbooks | ||
514 | * (2400/3400/3500, ohare based) has a second ohare chip | ||
515 | * effectively making a total of 64. | ||
516 | */ | ||
517 | max_irqs = max_real_irqs = 32; | ||
518 | irqctrler = find_devices("mac-io"); | ||
519 | if (irqctrler) | ||
520 | { | ||
521 | max_real_irqs = 64; | ||
522 | if (irqctrler->next) | ||
523 | max_irqs = 128; | ||
524 | else | ||
525 | max_irqs = 64; | ||
526 | } | ||
527 | for ( i = 0; i < max_real_irqs ; i++ ) | ||
528 | irq_desc[i].handler = &pmac_pic; | ||
529 | |||
530 | /* get addresses of first controller */ | ||
531 | if (irqctrler) { | ||
532 | if (irqctrler->n_addrs > 0) { | ||
533 | addr = (unsigned long) | ||
534 | ioremap(irqctrler->addrs[0].address, 0x40); | ||
535 | for (i = 0; i < 2; ++i) | ||
536 | pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) | ||
537 | (addr + (2 - i) * 0x10); | ||
538 | } | ||
539 | |||
540 | /* get addresses of second controller */ | ||
541 | irqctrler = irqctrler->next; | ||
542 | if (irqctrler && irqctrler->n_addrs > 0) { | ||
543 | addr = (unsigned long) | ||
544 | ioremap(irqctrler->addrs[0].address, 0x40); | ||
545 | for (i = 2; i < 4; ++i) | ||
546 | pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) | ||
547 | (addr + (4 - i) * 0x10); | ||
548 | irq_cascade = irqctrler->intrs[0].line; | ||
549 | if (device_is_compatible(irqctrler, "gatwick")) | ||
550 | pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); | ||
551 | } | ||
552 | } else { | ||
553 | /* older powermacs have a GC (grand central) or ohare at | ||
554 | f3000000, with interrupt control registers at f3000020. */ | ||
555 | addr = (unsigned long) ioremap(0xf3000000, 0x40); | ||
556 | pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); | ||
557 | } | ||
558 | |||
559 | /* PowerBooks 3400 and 3500 can have a second controller in a second | ||
560 | ohare chip, on the combo ethernet/modem card */ | ||
561 | if (machine_is_compatible("AAPL,3400/2400") | ||
562 | || machine_is_compatible("AAPL,3500")) | ||
563 | irq_cascade = enable_second_ohare(); | ||
564 | |||
565 | /* disable all interrupts in all controllers */ | ||
566 | for (i = 0; i * 32 < max_irqs; ++i) | ||
567 | out_le32(&pmac_irq_hw[i]->enable, 0); | ||
568 | /* mark level interrupts */ | ||
569 | for (i = 0; i < max_irqs; i++) | ||
570 | if (level_mask[i >> 5] & (1UL << (i & 0x1f))) | ||
571 | irq_desc[i].status = IRQ_LEVEL; | ||
572 | |||
573 | /* get interrupt line of secondary interrupt controller */ | ||
574 | if (irq_cascade >= 0) { | ||
575 | printk(KERN_INFO "irq: secondary controller on irq %d\n", | ||
576 | (int)irq_cascade); | ||
577 | for ( i = max_real_irqs ; i < max_irqs ; i++ ) | ||
578 | irq_desc[i].handler = &gatwick_pic; | ||
579 | setup_irq(irq_cascade, &gatwick_cascade_action); | ||
580 | } | ||
581 | printk("System has %d possible interrupts\n", max_irqs); | ||
582 | if (max_irqs != max_real_irqs) | ||
583 | printk(KERN_DEBUG "%d interrupts on main controller\n", | ||
584 | max_real_irqs); | ||
585 | |||
586 | #ifdef CONFIG_XMON | ||
587 | setup_irq(20, &xmon_action); | ||
588 | #endif /* CONFIG_XMON */ | ||
589 | } | ||
590 | |||
591 | #ifdef CONFIG_PM | ||
592 | /* | ||
593 | * These procedures are used in implementing sleep on the powerbooks. | ||
594 | * sleep_save_intrs() saves the states of all interrupt enables | ||
595 | * and disables all interrupts except for the nominated one. | ||
596 | * sleep_restore_intrs() restores the states of all interrupt enables. | ||
597 | */ | ||
598 | unsigned long sleep_save_mask[2]; | ||
599 | |||
600 | /* This used to be passed by the PMU driver but that link got | ||
601 | * broken with the new driver model. We use this tweak for now... | ||
602 | */ | ||
603 | static int pmacpic_find_viaint(void) | ||
604 | { | ||
605 | int viaint = -1; | ||
606 | |||
607 | #ifdef CONFIG_ADB_PMU | ||
608 | struct device_node *np; | ||
609 | |||
610 | if (pmu_get_model() != PMU_OHARE_BASED) | ||
611 | goto not_found; | ||
612 | np = of_find_node_by_name(NULL, "via-pmu"); | ||
613 | if (np == NULL) | ||
614 | goto not_found; | ||
615 | viaint = np->intrs[0].line; | ||
616 | #endif /* CONFIG_ADB_PMU */ | ||
617 | |||
618 | not_found: | ||
619 | return viaint; | ||
620 | } | ||
621 | |||
622 | static int pmacpic_suspend(struct sys_device *sysdev, u32 state) | ||
623 | { | ||
624 | int viaint = pmacpic_find_viaint(); | ||
625 | |||
626 | sleep_save_mask[0] = ppc_cached_irq_mask[0]; | ||
627 | sleep_save_mask[1] = ppc_cached_irq_mask[1]; | ||
628 | ppc_cached_irq_mask[0] = 0; | ||
629 | ppc_cached_irq_mask[1] = 0; | ||
630 | if (viaint > 0) | ||
631 | set_bit(viaint, ppc_cached_irq_mask); | ||
632 | out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); | ||
633 | if (max_real_irqs > 32) | ||
634 | out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); | ||
635 | (void)in_le32(&pmac_irq_hw[0]->event); | ||
636 | /* make sure mask gets to controller before we return to caller */ | ||
637 | mb(); | ||
638 | (void)in_le32(&pmac_irq_hw[0]->enable); | ||
639 | |||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static int pmacpic_resume(struct sys_device *sysdev) | ||
644 | { | ||
645 | int i; | ||
646 | |||
647 | out_le32(&pmac_irq_hw[0]->enable, 0); | ||
648 | if (max_real_irqs > 32) | ||
649 | out_le32(&pmac_irq_hw[1]->enable, 0); | ||
650 | mb(); | ||
651 | for (i = 0; i < max_real_irqs; ++i) | ||
652 | if (test_bit(i, sleep_save_mask)) | ||
653 | pmac_unmask_irq(i); | ||
654 | |||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | #endif /* CONFIG_PM */ | ||
659 | |||
660 | static struct sysdev_class pmacpic_sysclass = { | ||
661 | set_kset_name("pmac_pic"), | ||
662 | }; | ||
663 | |||
664 | static struct sys_device device_pmacpic = { | ||
665 | .id = 0, | ||
666 | .cls = &pmacpic_sysclass, | ||
667 | }; | ||
668 | |||
669 | static struct sysdev_driver driver_pmacpic = { | ||
670 | #ifdef CONFIG_PM | ||
671 | .suspend = &pmacpic_suspend, | ||
672 | .resume = &pmacpic_resume, | ||
673 | #endif /* CONFIG_PM */ | ||
674 | }; | ||
675 | |||
676 | static int __init init_pmacpic_sysfs(void) | ||
677 | { | ||
678 | if (max_irqs == 0) | ||
679 | return -ENODEV; | ||
680 | |||
681 | printk(KERN_DEBUG "Registering pmac pic with sysfs...\n"); | ||
682 | sysdev_class_register(&pmacpic_sysclass); | ||
683 | sysdev_register(&device_pmacpic); | ||
684 | sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | subsys_initcall(init_pmacpic_sysfs); | ||
689 | |||