/**************************************************************************** * arch/arm/src/calypso/calypso_irq.c * Driver for Calypso IRQ controller * * (C) 2010 by Harald Welte * (C) 2011 by Stefan Richter * * This source code is derivated from Osmocom-BB project and was * relicensed as BSD with permission from original authors. * * 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. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "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 * COPYRIGHT OWNER OR CONTRIBUTORS 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. * **************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include "arm.h" #include "up_arch.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define BASE_ADDR_IRQ 0xfffffa00 #define BASE_ADDR_IBOOT_EXC 0x0080001C enum irq_reg { IT_REG1 = 0x00, IT_REG2 = 0x02, MASK_IT_REG1 = 0x08, MASK_IT_REG2 = 0x0a, IRQ_NUM = 0x10, FIQ_NUM = 0x12, IRQ_CTRL = 0x14, }; #define ILR_IRQ(x) (0x20 + (x*2)) #define IRQ_REG(x) (BASE_ADDR_IRQ + (x)) #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif /**************************************************************************** * Public Data ****************************************************************************/ volatile uint32_t *current_regs; extern uint32_t _exceptions; /**************************************************************************** * Private Data ****************************************************************************/ static uint8_t default_irq_prio[] = { [IRQ_WATCHDOG] = 0xff, [IRQ_TIMER1] = 0xff, [IRQ_TIMER2] = 0xff, [IRQ_TSP_RX] = 0, [IRQ_TPU_FRAME] = 3, [IRQ_TPU_PAGE] = 0xff, [IRQ_SIMCARD] = 0xff, [IRQ_UART_MODEM] = 8, [IRQ_KEYPAD_GPIO] = 4, [IRQ_RTC_TIMER] = 9, [IRQ_RTC_ALARM_I2C] = 10, [IRQ_ULPD_GAUGING] = 2, [IRQ_EXTERNAL] = 12, [IRQ_SPI] = 0xff, [IRQ_DMA] = 0xff, [IRQ_API] = 0xff, [IRQ_SIM_DETECT] = 0, [IRQ_EXTERNAL_FIQ] = 7, [IRQ_UART_IRDA] = 2, [IRQ_ULPD_GSM_TIMER] = 1, [IRQ_GEA] = 0xff, }; /**************************************************************************** * Private Functions ****************************************************************************/ static void _irq_enable(enum irq_nr nr, int enable) { uintptr_t reg = IRQ_REG(MASK_IT_REG1); uint16_t val; if (nr > 15) { reg = IRQ_REG(MASK_IT_REG2); nr -= 16; } val = getreg16(reg); if (enable) { val &= ~(1 << nr); } else { val |= (1 << nr); } putreg16(val, reg); } static void set_default_priorities(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(default_irq_prio); i++) { uint16_t val; uint8_t prio = default_irq_prio[i]; if (prio > 31) { prio = 31; } val = getreg16(IRQ_REG(ILR_IRQ(i))); val &= ~(0x1f << 2); val |= prio << 2; /* Make edge mode default. Hopefully causes less trouble */ val |= 0x02; putreg16(val, IRQ_REG(ILR_IRQ(i))); } } /* Install the exception handlers to where the ROM loader jumps */ static void calypso_exceptions_install(void) { uint32_t *exceptions_dst = (uint32_t *) BASE_ADDR_IBOOT_EXC; uint32_t *exceptions_src = &_exceptions; int i; for (i = 0; i < 7; i++) { *exceptions_dst++ = *exceptions_src++; } } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: up_irqinitialize * * Description: * Setup the IRQ and FIQ controllers * ****************************************************************************/ void up_irqinitialize(void) { /* Prepare hardware */ calypso_exceptions_install(); current_regs = NULL; /* Switch to internal ROM */ calypso_bootrom(1); /* Set default priorities */ set_default_priorities(); /* Mask all interrupts off */ putreg16(0xffff, IRQ_REG(MASK_IT_REG1)); putreg16(0xffff, IRQ_REG(MASK_IT_REG2)); /* clear all pending interrupts */ putreg16(0, IRQ_REG(IT_REG1)); putreg16(0, IRQ_REG(IT_REG2)); /* Enable interrupts globally to the ARM core */ #ifndef CONFIG_SUPPRESS_INTERRUPTS irqrestore(SVC_MODE | PSR_F_BIT); #endif } /**************************************************************************** * Name: up_disable_irq * * Description: * Disable the IRQ specified by 'irq' * ****************************************************************************/ void up_disable_irq(int irq) { if ((unsigned)irq < NR_IRQS) { _irq_enable(irq, 0); } } /**************************************************************************** * Name: up_enable_irq * * Description: * Enable the IRQ specified by 'irq' * ****************************************************************************/ void up_enable_irq(int irq) { if((unsigned)irq < NR_IRQS) { _irq_enable(irq, 1); } } /**************************************************************************** * Name: up_prioritize_irq * * Description: * Set the priority of an IRQ. * ****************************************************************************/ #ifndef CONFIG_ARCH_IRQPRIO int up_prioritize_irq(int nr, int prio) { uint16_t val; if (prio == -1) { prio = default_irq_prio[nr]; } if (prio > 31) { prio = 31; } val = prio << 2; putreg16(val, IRQ_REG(ILR_IRQ(nr))); return 0; } #endif /**************************************************************************** * Entry point for interrupts ****************************************************************************/ void up_decodeirq(uint32_t *regs) { uint8_t num, tmp; uint32_t *saved_regs; /* XXX: What is this??? * Passed to but ignored in IRQ handlers * Only valid meaning is apparently non-NULL == IRQ context */ saved_regs = (uint32_t *)current_regs; current_regs = regs; /* Detect & deliver the IRQ */ num = getreg8(IRQ_REG(IRQ_NUM)) & 0x1f; irq_dispatch(num, regs); /* Start new IRQ agreement */ tmp = getreg8(IRQ_REG(IRQ_CTRL)); tmp |= 0x01; putreg8(tmp, IRQ_REG(IRQ_CTRL)); current_regs = saved_regs; } /**************************************************************************** * Entry point for FIQs ****************************************************************************/ void calypso_fiq(void) { uint8_t num, tmp; uint32_t *regs; /* XXX: What is this??? * Passed to but ignored in IRQ handlers * Only valid meaning is apparently non-NULL == IRQ context */ regs = (uint32_t *)current_regs; current_regs = (uint32_t *)# /* Detect & deliver like an IRQ but we are in FIQ context */ num = getreg8(IRQ_REG(FIQ_NUM)) & 0x1f; irq_dispatch(num, regs); /* Start new FIQ agreement */ tmp = getreg8(IRQ_REG(IRQ_CTRL)); tmp |= 0x02; putreg8(tmp, IRQ_REG(IRQ_CTRL)); current_regs = regs; }