/* $NetBSD: omap2430_intr.c,v 1.7 2016/05/31 02:26:00 dholland Exp $ */ /* * Define the SDP2430 specific information and then include the generic OMAP * interrupt header. */ /* * Copyright (c) 2007 Microsoft * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Microsoft * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTERS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_omap.h" #include __KERNEL_RCSID(0, "$NetBSD: omap2430_intr.c,v 1.7 2016/05/31 02:26:00 dholland Exp $"); #include #include #include #include #include #include #include #include #include #ifdef OMAP_2430 #define NIGROUPS 8 #define GPIO1_BASE GPIO1_BASE_2430 #define GPIO2_BASE GPIO2_BASE_2430 #define GPIO3_BASE GPIO3_BASE_2430 #define GPIO4_BASE GPIO4_BASE_2430 #define GPIO5_BASE GPIO5_BASE_2430 #elif defined(OMAP_2420) #define NIGROUPS 7 #define GPIO1_BASE GPIO1_BASE_2420 #define GPIO2_BASE GPIO2_BASE_2420 #define GPIO3_BASE GPIO3_BASE_2420 #define GPIO4_BASE GPIO4_BASE_2420 #endif struct intrsource { struct evcnt is_ev; uint8_t is_ipl; uint8_t is_group; int (*is_func)(void *); void *is_arg; uint64_t is_marked; }; static struct intrgroup { uint32_t ig_irqsbyipl[NIPL]; uint32_t ig_irqs; volatile uint32_t ig_pending_irqs; uint32_t ig_enabled_irqs; uint32_t ig_edge_rising; uint32_t ig_edge_falling; uint32_t ig_level_low; uint32_t ig_level_high; struct intrsource ig_sources[32]; bus_space_tag_t ig_memt; bus_space_handle_t ig_memh; } intrgroups[NIGROUPS] = { [0].ig_sources[ 0 ... 31 ].is_group = 0, [1].ig_sources[ 0 ... 31 ].is_group = 1, [2].ig_sources[ 0 ... 31 ].is_group = 2, [3].ig_sources[ 0 ... 31 ].is_group = 3, [4].ig_sources[ 0 ... 31 ].is_group = 4, [5].ig_sources[ 0 ... 31 ].is_group = 5, [6].ig_sources[ 0 ... 31 ].is_group = 6, #ifdef OMAP_2430 [7].ig_sources[ 0 ... 31 ].is_group = 7, #endif }; volatile uint32_t pending_ipls; volatile uint32_t pending_igroupsbyipl[NIPL]; void omap2430_intr_init(bus_space_tag_t); #define INTC_READ(ig, o) \ bus_space_read_4((ig)->ig_memt, (ig)->ig_memh, o) #define INTC_WRITE(ig, o, v) \ bus_space_write_4((ig)->ig_memt, (ig)->ig_memh, o, v) #define GPIO_READ(ig, o) \ bus_space_read_4((ig)->ig_memt, (ig)->ig_memh, o) #define GPIO_WRITE(ig, o, v) \ bus_space_write_4((ig)->ig_memt, (ig)->ig_memh, o, v) static void unblock_irq(unsigned int group, int irq_mask) { struct intrgroup * const ig = &intrgroups[group]; KASSERT((irq_mask & ig->ig_enabled_irqs) == 0); ig->ig_enabled_irqs |= irq_mask; if (group < 3) { INTC_WRITE(ig, INTC_MIR_CLEAR, irq_mask); } else { GPIO_WRITE(ig, GPIO_SETIRQENABLE1, irq_mask); /* * Clear IRQSTATUS of level interrupts, if they are still * asserted, IRQSTATUS will become set again and they will * refire. This avoids one spurious interrupt for every * real interrupt. */ if (irq_mask & (ig->ig_level_low|ig->ig_level_high)) GPIO_WRITE(ig, GPIO_IRQSTATUS1, irq_mask & (ig->ig_level_low|ig->ig_level_high)); } /* Force INTC to recompute IRQ availability */ INTC_WRITE(&intrgroups[0], INTC_CONTROL, INTC_CONTROL_NEWIRQAGR); } static void block_irq(unsigned int group, int irq_mask) { struct intrgroup * const ig = &intrgroups[group]; ig->ig_enabled_irqs &= ~irq_mask; if (group < 3) { INTC_WRITE(ig, INTC_MIR_SET, irq_mask); return; } GPIO_WRITE(ig, GPIO_CLEARIRQENABLE1, irq_mask); /* * Only clear(reenable) edge interrupts. */ if (irq_mask & (ig->ig_edge_falling|ig->ig_edge_rising)) GPIO_WRITE(ig, GPIO_IRQSTATUS1, /* reset int bits */ irq_mask & (ig->ig_edge_falling|ig->ig_edge_rising)); } static void init_irq(int irq, int spl, int type) { struct intrgroup * const ig = &intrgroups[irq / 32]; uint32_t irq_mask = __BIT(irq & 31); uint32_t v; KASSERT(irq >= 0 && irq < 256); ig->ig_sources[irq & 31].is_ipl = spl; if (irq < 96) { KASSERT(type == IST_LEVEL); return; } ig->ig_enabled_irqs &= ~irq_mask; GPIO_WRITE(ig, GPIO_CLEARIRQENABLE1, irq_mask); v = GPIO_READ(ig, GPIO_OE); GPIO_WRITE(ig, GPIO_OE, v | irq_mask); /* set as input */ ig->ig_edge_rising &= ~irq_mask; ig->ig_edge_falling &= ~irq_mask; ig->ig_level_low &= ~irq_mask; ig->ig_level_high &= ~irq_mask; switch (type) { case IST_EDGE_BOTH: ig->ig_edge_rising |= irq_mask; ig->ig_edge_falling |= irq_mask; break; case IST_EDGE_RISING: ig->ig_edge_rising |= irq_mask; break; case IST_EDGE_FALLING: ig->ig_edge_falling |= irq_mask; break; case IST_LEVEL_LOW: ig->ig_level_low |= irq_mask; break; case IST_LEVEL_HIGH: ig->ig_level_high |= irq_mask; break; } GPIO_WRITE(ig, GPIO_LEVELDETECT0, ig->ig_level_low); GPIO_WRITE(ig, GPIO_LEVELDETECT1, ig->ig_level_high); GPIO_WRITE(ig, GPIO_RISINGDETECT, ig->ig_edge_rising); GPIO_WRITE(ig, GPIO_FALLINGDETECT, ig->ig_edge_falling); } /* * Called with interrupt disabled */ static void calculate_irq_masks(struct intrgroup *ig) { u_int irq; int ipl; uint32_t irq_mask; memset(ig->ig_irqsbyipl, 0, sizeof(ig->ig_irqsbyipl)); ig->ig_irqs = 0; for (irq_mask = 1, irq = 0; irq < 32; irq_mask <<= 1, irq++) { if ((ipl = ig->ig_sources[irq].is_ipl) == IPL_NONE) continue; ig->ig_irqsbyipl[ipl] |= irq_mask; ig->ig_irqs |= irq_mask; } } /* * Called with interrupts disabled */ static uint32_t mark_pending_irqs(int group, uint32_t pending) { struct intrgroup * const ig = &intrgroups[group]; struct intrsource *is; int n; int ipl_mask = 0; if (pending == 0) return ipl_mask; KASSERT((ig->ig_enabled_irqs & pending) == pending); KASSERT((ig->ig_pending_irqs & pending) == 0); ig->ig_pending_irqs |= pending; block_irq(group, pending); for (;;) { n = ffs(pending); if (n-- == 0) break; is = &ig->ig_sources[n]; KASSERT(ig->ig_irqsbyipl[is->is_ipl] & pending); pending &= ~ig->ig_irqsbyipl[is->is_ipl]; ipl_mask |= __BIT(is->is_ipl); KASSERT(ipl_mask < __BIT(NIPL)); pending_igroupsbyipl[is->is_ipl] |= __BIT(group); is->is_marked++; } KASSERT(ipl_mask < __BIT(NIPL)); return ipl_mask; } /* * Called with interrupts disabled */ static uint32_t get_pending_irqs(void) { uint32_t pending[3]; uint32_t ipl_mask = 0; uint32_t xpending; pending[0] = INTC_READ(&intrgroups[0], INTC_PENDING_IRQ); pending[1] = INTC_READ(&intrgroups[1], INTC_PENDING_IRQ); pending[2] = INTC_READ(&intrgroups[2], INTC_PENDING_IRQ); /* Get interrupt status of GPIO1 */ if (pending[GPIO1_MPU_IRQ / 32] & __BIT(GPIO1_MPU_IRQ & 31)) { KASSERT(intrgroups[3].ig_enabled_irqs); xpending = GPIO_READ(&intrgroups[3], GPIO_IRQSTATUS1); xpending &= intrgroups[3].ig_enabled_irqs; ipl_mask |= mark_pending_irqs(3, xpending); } /* Get interrupt status of GPIO2 */ if (pending[GPIO2_MPU_IRQ / 32] & __BIT(GPIO2_MPU_IRQ & 31)) { KASSERT(intrgroups[4].ig_enabled_irqs); xpending = GPIO_READ(&intrgroups[4], GPIO_IRQSTATUS1); xpending &= intrgroups[4].ig_enabled_irqs; ipl_mask |= mark_pending_irqs(4, xpending); } /* Get interrupt status of GPIO3 */ if (pending[GPIO3_MPU_IRQ / 32] & __BIT(GPIO3_MPU_IRQ & 31)) { KASSERT(intrgroups[5].ig_enabled_irqs); xpending = GPIO_READ(&intrgroups[5], GPIO_IRQSTATUS1); xpending &= intrgroups[5].ig_enabled_irqs; ipl_mask |= mark_pending_irqs(5, xpending); } /* Get interrupt status of GPIO4 */ if (pending[GPIO4_MPU_IRQ / 32] & __BIT(GPIO4_MPU_IRQ & 31)) { KASSERT(intrgroups[6].ig_enabled_irqs); xpending = GPIO_READ(&intrgroups[6], GPIO_IRQSTATUS1); xpending &= intrgroups[6].ig_enabled_irqs; ipl_mask |= mark_pending_irqs(6, xpending); } #ifdef OMAP_2430 /* Get interrupt status of GPIO5 */ if (pending[GPIO5_MPU_IRQ / 32] & __BIT(GPIO5_MPU_IRQ & 31)) { KASSERT(intrgroups[7].ig_enabled_irqs); xpending = GPIO_READ(&intrgroups[7], GPIO_IRQSTATUS1); xpending = GPIO_READ(&intrgroups[7], GPIO_IRQSTATUS1); xpending &= intrgroups[7].ig_enabled_irqs; ipl_mask |= mark_pending_irqs(7, xpending); } #endif /* Clear GPIO indication from summaries */ pending[GPIO1_MPU_IRQ / 32] &= ~__BIT(GPIO1_MPU_IRQ & 31); pending[GPIO2_MPU_IRQ / 32] &= ~__BIT(GPIO2_MPU_IRQ & 31); pending[GPIO3_MPU_IRQ / 32] &= ~__BIT(GPIO3_MPU_IRQ & 31); pending[GPIO4_MPU_IRQ / 32] &= ~__BIT(GPIO4_MPU_IRQ & 31); #ifdef OMAP_2430 pending[GPIO5_MPU_IRQ / 32] &= ~__BIT(GPIO5_MPU_IRQ & 31); #endif /* Now handle the primaries interrupt summaries */ ipl_mask |= mark_pending_irqs(0, pending[0]); ipl_mask |= mark_pending_irqs(1, pending[1]); ipl_mask |= mark_pending_irqs(2, pending[2]); /* Force INTC to recompute IRQ availability */ INTC_WRITE(&intrgroups[0], INTC_CONTROL, INTC_CONTROL_NEWIRQAGR); return ipl_mask; } static int last_delivered_ipl; static u_long no_pending_irqs[NIPL][NIGROUPS]; static void deliver_irqs(register_t psw, int ipl, void *frame) { struct intrgroup *ig; struct intrsource *is; uint32_t pending_irqs; uint32_t irq_mask; uint32_t blocked_irqs; volatile uint32_t * const pending_igroups = &pending_igroupsbyipl[ipl]; const uint32_t ipl_mask = __BIT(ipl); int n; int saved_ipl = IPL_NONE; /* XXX stupid GCC */ unsigned int group; int rv; if (frame == NULL) { saved_ipl = last_delivered_ipl; KASSERT(saved_ipl < ipl); last_delivered_ipl = ipl; } /* * We only must be called is there is this IPL has pending interrupts * and therefore there must be at least one intrgroup with a pending * interrupt. */ KASSERT(pending_ipls & ipl_mask); KASSERT(*pending_igroups); /* * We loop until there are no more intrgroups with pending interrupts. */ do { group = 31 - __builtin_clz(*pending_igroups); KASSERT(group < NIGROUPS); ig = &intrgroups[group]; irq_mask = ig->ig_irqsbyipl[ipl]; pending_irqs = ig->ig_pending_irqs & irq_mask; blocked_irqs = pending_irqs; if ((*pending_igroups &= ~__BIT(group)) == 0) pending_ipls &= ~ipl_mask; #if 0 KASSERT(group < 3 || (GPIO_READ(ig, GPIO_IRQSTATUS1) & blocked_irqs) == 0); #endif /* * We couldn't gotten here unless there was at least one * pending interrupt in this intrgroup. */ if (pending_irqs == 0) { no_pending_irqs[ipl][group]++; continue; } #if 0 KASSERT(pending_irqs != 0); #endif do { n = 31 - __builtin_clz(pending_irqs); KASSERT(ig->ig_irqs & __BIT(n)); KASSERT(irq_mask & __BIT(n)); /* * If this was the last bit cleared for this IRQ, * we need to clear this group's bit in * pending_igroupsbyipl[ipl]. Now if that's now 0, * we need to clear pending_ipls for this IPL. */ ig->ig_pending_irqs &= ~__BIT(n); if (irq_mask == __BIT(n)) KASSERT((ig->ig_pending_irqs & irq_mask) == 0); is = &ig->ig_sources[n]; if (__predict_false(frame != NULL)) { (*is->is_func)(frame); } else { restore_interrupts(psw); rv = (*is->is_func)(is->is_arg); disable_interrupts(I32_bit); } #if 0 if (rv && group >= 3) /* XXX */ GPIO_WRITE(ig, GPIO_IRQSTATUS1, __BIT(n)); #endif #if 0 if (ig->ig_irqsbyipl[ipl] == __BIT(n)) KASSERT((ig->ig_pending_irqs & irq_mask) == 0); #endif is->is_ev.ev_count++; pending_irqs = ig->ig_pending_irqs & irq_mask; } while (pending_irqs); /* * We don't block the interrupts individually because even if * one was unblocked it couldn't be delivered since our * current IPL would prevent it. So we wait until we can do * them all at once. */ #if 0 KASSERT(group < 3 || (GPIO_READ(ig, GPIO_IRQSTATUS1) & blocked_irqs) == 0); #endif unblock_irq(group, blocked_irqs); } while (*pending_igroups); /* * Since there are no more pending interrupts for this IPL, * this IPL must not be present in the pending IPLs. */ KASSERT((pending_ipls & ipl_mask) == 0); KASSERT((intrgroups[0].ig_pending_irqs & intrgroups[0].ig_irqsbyipl[ipl]) == 0); KASSERT((intrgroups[1].ig_pending_irqs & intrgroups[1].ig_irqsbyipl[ipl]) == 0); KASSERT((intrgroups[2].ig_pending_irqs & intrgroups[2].ig_irqsbyipl[ipl]) == 0); KASSERT((intrgroups[3].ig_pending_irqs & intrgroups[3].ig_irqsbyipl[ipl]) == 0); KASSERT((intrgroups[4].ig_pending_irqs & intrgroups[4].ig_irqsbyipl[ipl]) == 0); KASSERT((intrgroups[5].ig_pending_irqs & intrgroups[5].ig_irqsbyipl[ipl]) == 0); KASSERT((intrgroups[6].ig_pending_irqs & intrgroups[6].ig_irqsbyipl[ipl]) == 0); #ifdef OMAP_2430 KASSERT((intrgroups[7].ig_pending_irqs & intrgroups[7].ig_irqsbyipl[ipl]) == 0); #endif if (frame == NULL) last_delivered_ipl = saved_ipl; } static inline void do_pending_ints(register_t psw, int newipl) { while ((pending_ipls & ~__BIT(newipl)) > __BIT(newipl)) { KASSERT(pending_ipls < __BIT(NIPL)); for (;;) { int ipl = 31 - __builtin_clz(pending_ipls); KASSERT(ipl < NIPL); if (ipl <= newipl) break; curcpu()->ci_cpl = ipl; deliver_irqs(psw, ipl, NULL); } } curcpu()->ci_cpl = newipl; } int _splraise(int newipl) { const int oldipl = curcpu()->ci_cpl; KASSERT(newipl < NIPL); if (newipl > curcpu()->ci_cpl) curcpu()->ci_cpl = newipl; return oldipl; } int _spllower(int newipl) { const int oldipl = curcpu()->ci_cpl; KASSERT(panicstr || newipl <= curcpu()->ci_cpl); if (newipl < curcpu()->ci_cpl) { register_t psw = disable_interrupts(I32_bit); do_pending_ints(psw, newipl); restore_interrupts(psw); } return oldipl; } void splx(int savedipl) { KASSERT(savedipl < NIPL); if (savedipl < curcpu()->ci_cpl) { register_t psw = disable_interrupts(I32_bit); do_pending_ints(psw, savedipl); restore_interrupts(psw); } curcpu()->ci_cpl = savedipl; } void omap_irq_handler(void *frame) { const int oldipl = curcpu()->ci_cpl; const uint32_t oldipl_mask = __BIT(oldipl); /* * When we enter there must be no pending IRQs for IPL greater than * the current IPL. There might be pending IRQs for the current IPL * if we are servicing interrupts. */ KASSERT((pending_ipls & ~oldipl_mask) < oldipl_mask); pending_ipls |= get_pending_irqs(); curcpu()->ci_data.cpu_nintr++; /* * We assume this isn't a clock intr. But if it is, deliver it * unconditionally so it will always have the interrupted frame. * The clock intr will handle being called at IPLs != IPL_CLOCK. */ if (__predict_false(pending_ipls & __BIT(IPL_STATCLOCK))) { deliver_irqs(0, IPL_STATCLOCK, frame); pending_ipls &= ~__BIT(IPL_STATCLOCK); } if (__predict_false(pending_ipls & __BIT(IPL_CLOCK))) { deliver_irqs(0, IPL_CLOCK, frame); pending_ipls &= ~__BIT(IPL_CLOCK); } /* * Record the pending_ipls and deliver them if we can. */ if ((pending_ipls & ~oldipl_mask) > oldipl_mask) do_pending_ints(I32_bit, oldipl); } void * omap_intr_establish(int irq, int ipl, const char *name, int (*func)(void *), void *arg) { struct intrgroup *ig = &intrgroups[irq / 32]; struct intrsource *is; register_t psw; KASSERT(irq >= 0 && irq < 256); is = &ig->ig_sources[irq & 0x1f]; KASSERT(irq != GPIO1_MPU_IRQ); KASSERT(irq != GPIO2_MPU_IRQ); KASSERT(irq != GPIO3_MPU_IRQ); KASSERT(irq != GPIO4_MPU_IRQ); KASSERT(irq != GPIO5_MPU_IRQ); KASSERT(is->is_ipl == IPL_NONE); is->is_func = func; is->is_arg = arg; psw = disable_interrupts(I32_bit); evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL, name, "intr"); init_irq(irq, ipl, IST_LEVEL); calculate_irq_masks(ig); unblock_irq(is->is_group, __BIT(irq & 31)); restore_interrupts(psw); return is; } void omap_intr_disestablish(void *ih) { struct intrsource * const is = ih; struct intrgroup *ig; register_t psw; uint32_t mask; KASSERT(ih != NULL); ig = &intrgroups[is->is_group]; psw = disable_interrupts(I32_bit); mask = __BIT(is - ig->ig_sources); block_irq(is->is_group, mask); ig->ig_pending_irqs &= ~mask; calculate_irq_masks(ig); evcnt_detach(&is->is_ev); restore_interrupts(psw); } #ifdef GPIO5_BASE static void gpio5_clkinit(bus_space_tag_t memt) { bus_space_handle_t memh; uint32_t r; int error; error = bus_space_map(memt, OMAP2430_CM_BASE, OMAP2430_CM_SIZE, 0, &memh); if (error != 0) panic("%s: cannot map OMAP2430_CM_BASE at %#x: %d\n", __func__, OMAP2430_CM_BASE, error); r = bus_space_read_4(memt, memh, OMAP2430_CM_FCLKEN2_CORE); r |= OMAP2430_CM_FCLKEN2_CORE_EN_GPIO5; bus_space_write_4(memt, memh, OMAP2430_CM_FCLKEN2_CORE, r); r = bus_space_read_4(memt, memh, OMAP2430_CM_ICLKEN2_CORE); r |= OMAP2430_CM_ICLKEN2_CORE_EN_GPIO5; bus_space_write_4(memt, memh, OMAP2430_CM_ICLKEN2_CORE, r); bus_space_unmap(memt, memh, OMAP2430_CM_SIZE); } #endif void omap2430_intr_init(bus_space_tag_t memt) { int error; int group; for (group = 0; group < NIGROUPS; group++) intrgroups[group].ig_memt = memt; error = bus_space_map(memt, INTC_BASE, 0x1000, 0, &intrgroups[0].ig_memh); if (error) panic("failed to map interrupt registers: %d", error); error = bus_space_subregion(memt, intrgroups[0].ig_memh, 0x20, 0x20, &intrgroups[1].ig_memh); if (error) panic("failed to region interrupt registers: %d", error); error = bus_space_subregion(memt, intrgroups[0].ig_memh, 0x40, 0x20, &intrgroups[2].ig_memh); if (error) panic("failed to subregion interrupt registers: %d", error); error = bus_space_map(memt, GPIO1_BASE, 0x400, 0, &intrgroups[3].ig_memh); if (error) panic("failed to map gpio #1 registers: %d", error); error = bus_space_map(memt, GPIO2_BASE, 0x400, 0, &intrgroups[4].ig_memh); if (error) panic("failed to map gpio #2 registers: %d", error); error = bus_space_map(memt, GPIO3_BASE, 0x400, 0, &intrgroups[5].ig_memh); if (error) panic("failed to map gpio #3 registers: %d", error); error = bus_space_map(memt, GPIO4_BASE, 0x400, 0, &intrgroups[6].ig_memh); if (error) panic("failed to map gpio #4 registers: %d", error); #ifdef GPIO5_BASE gpio5_clkinit(memt); error = bus_space_map(memt, GPIO5_BASE, 0x400, 0, &intrgroups[7].ig_memh); if (error) panic("failed to map gpio #5 registers: %d", error); #endif INTC_WRITE(&intrgroups[0], INTC_MIR_SET, 0xffffffff); INTC_WRITE(&intrgroups[1], INTC_MIR_SET, 0xffffffff); INTC_WRITE(&intrgroups[2], INTC_MIR_SET, 0xffffffff); INTC_WRITE(&intrgroups[GPIO1_MPU_IRQ / 32], INTC_MIR_CLEAR, __BIT(GPIO1_MPU_IRQ & 31)); INTC_WRITE(&intrgroups[GPIO2_MPU_IRQ / 32], INTC_MIR_CLEAR, __BIT(GPIO2_MPU_IRQ & 31)); INTC_WRITE(&intrgroups[GPIO3_MPU_IRQ / 32], INTC_MIR_CLEAR, __BIT(GPIO3_MPU_IRQ & 31)); INTC_WRITE(&intrgroups[GPIO4_MPU_IRQ / 32], INTC_MIR_CLEAR, __BIT(GPIO4_MPU_IRQ & 31)); #ifdef GPIO5_BASE INTC_WRITE(&intrgroups[GPIO5_MPU_IRQ / 32], INTC_MIR_CLEAR, __BIT(GPIO5_MPU_IRQ & 31)); #endif /* * Setup the primary intrgroups. */ calculate_irq_masks(&intrgroups[0]); calculate_irq_masks(&intrgroups[1]); calculate_irq_masks(&intrgroups[2]); }