1/* 2 * BK Id: SCCS/s.ppc8xx_pic.c 1.13 12/01/01 17:19:48 trini 3 */ 4#include <linux/config.h> 5#include <linux/stddef.h> 6#include <linux/init.h> 7#include <linux/sched.h> 8#include <linux/signal.h> 9#include <asm/irq.h> 10#include <asm/8xx_immap.h> 11#include <asm/mpc8xx.h> 12#include "ppc8xx_pic.h" 13 14/* The 8xx internal interrupt controller. It is usually 15 * the only interrupt controller. Some boards, like the MBX and 16 * Sandpoint have the 8259 as a secondary controller. Depending 17 * upon the processor type, the internal controller can have as 18 * few as 16 interrups or as many as 64. We could use the 19 * "clear_bit()" and "set_bit()" functions like other platforms, 20 * but they are overkill for us. 21 */ 22 23static void m8xx_mask_irq(unsigned int irq_nr) 24{ 25 int bit, word; 26 27 bit = irq_nr & 0x1f; 28 word = irq_nr >> 5; 29 30 ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); 31 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 32 ppc_cached_irq_mask[word]; 33} 34 35static void m8xx_unmask_irq(unsigned int irq_nr) 36{ 37 int bit, word; 38 39 bit = irq_nr & 0x1f; 40 word = irq_nr >> 5; 41 42 ppc_cached_irq_mask[word] |= (1 << (31-bit)); 43 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 44 ppc_cached_irq_mask[word]; 45} 46 47static void m8xx_end_irq(unsigned int irq_nr) 48{ 49 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { 50 int bit, word; 51 52 bit = irq_nr & 0x1f; 53 word = irq_nr >> 5; 54 55 ppc_cached_irq_mask[word] |= (1 << (31-bit)); 56 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 57 ppc_cached_irq_mask[word]; 58 } 59} 60 61 62static void m8xx_mask_and_ack(unsigned int irq_nr) 63{ 64 int bit, word; 65 66 bit = irq_nr & 0x1f; 67 word = irq_nr >> 5; 68 69 ppc_cached_irq_mask[word] &= ~(1 << (31-bit)); 70 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 71 ppc_cached_irq_mask[word]; 72 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit); 73} 74 75struct hw_interrupt_type ppc8xx_pic = { 76 " 8xx SIU ", 77 NULL, 78 NULL, 79 m8xx_unmask_irq, 80 m8xx_mask_irq, 81 m8xx_mask_and_ack, 82 m8xx_end_irq, 83 0 84}; 85 86 87 88/* 89 * We either return a valid interrupt or -1 if there is nothing pending 90 */ 91int 92m8xx_get_irq(struct pt_regs *regs) 93{ 94 int irq; 95 96 /* For MPC8xx, read the SIVEC register and shift the bits down 97 * to get the irq number. 98 */ 99 irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26; 100 101 /* 102 * When we read the sivec without an interrupt to process, we will 103 * get back SIU_LEVEL7. In this case, return -1 104 */ 105 if (irq == SIU_LEVEL7) 106 return -1; 107 108 return irq; 109} 110 111/* The MBX is the only 8xx board that uses the 8259. 112*/ 113#if defined(CONFIG_MBX) && defined(CONFIG_PCI) 114void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs) 115{ 116 int bits, irq; 117 118 /* A bug in the QSpan chip causes it to give us 0xff always 119 * when doing a character read. So read 32 bits and shift. 120 * This doesn't seem to return useful values anyway, but 121 * read it to make sure things are acked. 122 * -- Cort 123 */ 124 irq = (inl(0x508) >> 24)&0xff; 125 if ( irq != 0xff ) printk("iack %d\n", irq); 126 127 outb(0x0C, 0x20); 128 irq = inb(0x20) & 7; 129 if (irq == 2) 130 { 131 outb(0x0C, 0xA0); 132 irq = inb(0xA0); 133 irq = (irq&7) + 8; 134 } 135 bits = 1UL << irq; 136 irq += i8259_pic.irq_offset; 137 ppc_irq_dispatch_handler( regs, irq ); 138} 139#endif 140 141/* Only the MBX uses the external 8259. This allows us to catch standard 142 * drivers that may mess up the internal interrupt controllers, and also 143 * allow them to run without modification on the MBX. 144 */ 145int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), 146 unsigned long irqflags, const char * devname, void *dev_id) 147{ 148 149#if defined(CONFIG_MBX) && defined(CONFIG_PCI) 150 irq += i8259_pic.irq_offset; 151 return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); 152#else 153 /* 154 * Handle other "well-known" interrupts, but panic on unknown ones. 155 */ 156 switch (irq) { 157#ifdef IDE0_INTERRUPT 158 case IDE0_INTERRUPT: /* IDE0 */ 159 return (request_8xxirq(irq, handler, irqflags, devname, 160 dev_id)); 161#endif 162#ifdef IDE1_INTERRUPT 163 case IDE1_INTERRUPT: /* IDE1 */ 164 return (request_8xxirq(irq, handler, irqflags, devname, 165 dev_id)); 166#endif 167 default: /* unknown IRQ -> panic */ 168 panic("request_irq"); 169 } 170#endif 171} 172