Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* * BK Id: %F% %I% %G% %U% %#% */ #include <linux/stddef.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/signal.h> #include <asm/irq.h> #include <asm/immap_8260.h> #include <asm/mpc8260.h> #include "ppc8260_pic.h" /* The 8260 internal interrupt controller. It is usually * the only interrupt controller. * There are two 32-bit registers (high/low) for up to 64 * possible interrupts. * * Now, the fun starts.....Interrupt Numbers DO NOT MAP * in a simple arithmetic fashion to mask or pending registers. * That is, interrupt 4 does not map to bit position 4. * We create two tables, indexed by vector number, to indicate * which register to use and which bit in the register to use. */ static u_char irq_to_siureg[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static u_char irq_to_siubit[] = { 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 30, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; static void m8260_mask_irq(unsigned int irq_nr) { int bit, word; volatile uint *simr; bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; simr = &(immr->im_intctl.ic_simrh); ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); simr[word] = ppc_cached_irq_mask[word]; } static void m8260_unmask_irq(unsigned int irq_nr) { int bit, word; volatile uint *simr; bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; simr = &(immr->im_intctl.ic_simrh); ppc_cached_irq_mask[word] |= (1 << (31 - bit)); simr[word] = ppc_cached_irq_mask[word]; } static void m8260_mask_and_ack(unsigned int irq_nr) { int bit, word; volatile uint *simr, *sipnr; bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; simr = &(immr->im_intctl.ic_simrh); sipnr = &(immr->im_intctl.ic_sipnrh); ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); simr[word] = ppc_cached_irq_mask[word]; sipnr[word] = 1 << (31 - bit); } static void m8260_end_irq(unsigned int irq_nr) { int bit, word; volatile uint *simr; if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { bit = irq_to_siubit[irq_nr]; word = irq_to_siureg[irq_nr]; simr = &(immr->im_intctl.ic_simrh); ppc_cached_irq_mask[word] |= (1 << (31 - bit)); simr[word] = ppc_cached_irq_mask[word]; } } struct hw_interrupt_type ppc8260_pic = { " 8260 SIU ", NULL, NULL, m8260_unmask_irq, m8260_mask_irq, m8260_mask_and_ack, m8260_end_irq, 0 }; int m8260_get_irq(struct pt_regs *regs) { int irq; unsigned long bits; /* For MPC8260, read the SIVEC register and shift the bits down * to get the irq number. */ bits = immr->im_intctl.ic_sivec; irq = bits >> 26; if (irq == 0) return(-1); #if 0 irq += ppc8260_pic.irq_offset; #endif return irq; } |