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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | /* * arch/ppc/syslib/gt64260_pic.c * * Interrupt controller support for Galileo's GT64260. * * Author: Chris Zankel <chris@mvista.com> * Modified by: Mark A. Greer <mgreer@mvista.com> * * Based on sources from Rabeeh Khoury / Galileo Technology * * 2001 (c) MontaVista, Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */ /* * This file contains the specific functions to support the GT64260 * interrupt controller. * * The GT64260 has two main interrupt registers (high and low) that * summarizes the interrupts generated by the units of the GT64260. * Each bit is assigned to an interrupt number, where the low register * are assigned from IRQ0 to IRQ31 and the high cause register * from IRQ32 to IRQ63 * The GPP (General Purpose Port) interrupts are assigned from IRQ64 (GPP0) * to IRQ95 (GPP31). * get_irq() returns the lowest interrupt number that is currently asserted. * * Note: * - This driver does not initialize the GPP when used as an interrupt * input. */ #include <linux/stddef.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/signal.h> #include <linux/stddef.h> #include <linux/delay.h> #include <linux/irq.h> #include <asm/io.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/irq.h> #include <asm/gt64260.h> /* ========================== forward declaration ========================== */ static void gt64260_unmask_irq(unsigned int); static void gt64260_mask_irq(unsigned int); /* ========================== local declarations =========================== */ struct hw_interrupt_type gt64260_pic = { " GT64260_PIC ", /* typename */ NULL, /* startup */ NULL, /* shutdown */ gt64260_unmask_irq, /* enable */ gt64260_mask_irq, /* disable */ gt64260_mask_irq, /* ack */ NULL, /* end */ NULL /* set_affinity */ }; u32 gt64260_irq_base = 0; /* GT64260 handles the next 96 IRQs from here */ /* gt64260_init_irq() * * This function initializes the interrupt controller. It assigns * all interrupts from IRQ0 to IRQ95 to the gt64260 interrupt controller. * * Input Variable(s): * None. * * Outpu. Variable(s): * None. * * Returns: * void * * Note: * We register all GPP inputs as interrupt source, but disable them. */ __init void gt64260_init_irq(void) { int i; if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: enter", 0x0); ppc_cached_irq_mask[0] = 0; ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */ ppc_cached_irq_mask[2] = 0; /* disable all interrupts and clear current interrupts */ gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2]); gt_write(GT64260_GPP_INTR_CAUSE,0); gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]); gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]); /* use the gt64260 for all (possible) interrupt sources */ for( i = gt64260_irq_base; i < (gt64260_irq_base + 96); i++ ) { irq_desc[i].handler = >64260_pic; } if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: exit", 0x0); } /* gt64260_get_irq() * * This function returns the lowest interrupt number of all interrupts that * are currently asserted. * * Input Variable(s): * struct pt_regs* not used * * Output Variable(s): * None. * * Returns: * int <interrupt number> or -2 (bogus interrupt) * */ int gt64260_get_irq(struct pt_regs *regs) { int irq; int irq_gpp; irq = gt_read(GT64260_IC_MAIN_CAUSE_LO); irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]); if (irq == -1) { irq = gt_read(GT64260_IC_MAIN_CAUSE_HI); irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]); if (irq == -1) { irq = -2; /* bogus interrupt, should never happen */ } else { if (irq >= 24) { irq_gpp = gt_read(GT64260_GPP_INTR_CAUSE); irq_gpp = __ilog2(irq_gpp & ppc_cached_irq_mask[2]); if (irq_gpp == -1) { irq = -2; } else { irq = irq_gpp + 64; gt_write(GT64260_GPP_INTR_CAUSE, ~(1<<(irq-64))); } } else { irq += 32; } } } if( irq < 0 ) { return( irq ); } else { return( gt64260_irq_base + irq ); } } /* gt64260_unmask_irq() * * This function enables an interrupt. * * Input Variable(s): * unsigned int interrupt number (IRQ0...IRQ95). * * Output Variable(s): * None. * * Returns: * void */ static void gt64260_unmask_irq(unsigned int irq) { irq -= gt64260_irq_base; if (irq > 31) { if (irq > 63) { /* unmask GPP irq */ gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2] |= (1<<(irq-64))); } else { /* mask high interrupt register */ gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1] |= (1<<(irq-32))); } } else { /* mask low interrupt register */ gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0] |= (1<<irq)); } } /* gt64260_mask_irq() * * This funktion disables the requested interrupt. * * Input Variable(s): * unsigned int interrupt number (IRQ0...IRQ95). * * Output Variable(s): * None. * * Returns: * void */ static void gt64260_mask_irq(unsigned int irq) { irq -= gt64260_irq_base; if (irq > 31) { if (irq > 63) { /* mask GPP irq */ gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2] &= ~(1<<(irq-64))); } else { /* mask high interrupt register */ gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1] &= ~(1<<(irq-32))); } } else { /* mask low interrupt register */ gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0] &= ~(1<<irq)); } if (irq == 36) { /* Seems necessary for SDMA interrupts */ udelay(1); } } |