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