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