| /** |
| * \file interrupt.c |
| * |
| * \brief Interrupt related APIs. |
| * |
| * This file contains the APIs for configuring AINTC |
| */ |
| |
| /* |
| * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ |
| */ |
| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 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. |
| * |
| * Neither the name of Texas Instruments Incorporated 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. |
| * |
| */ |
| |
| |
| #include "hw_intc.h" |
| #include "interrupt.h" |
| #include "hw_types.h" |
| #include "soc_AM335x.h" |
| #include "cpu.h" |
| |
| /****************************************************************************** |
| ** INTERNAL MACRO DEFINITIONS |
| ******************************************************************************/ |
| #define REG_IDX_SHIFT (0x05) |
| #define REG_BIT_MASK (0x1F) |
| #define NUM_INTERRUPTS (128u) |
| |
| /**************** ************************************************************* |
| ** STATIC VARIABLE DEFINITIONS |
| ******************************************************************************/ |
| void (*fnRAMVectors[NUM_INTERRUPTS])(void); |
| |
| /****************************************************************************** |
| ** STATIC FUNCTION DECLARATIONS |
| ******************************************************************************/ |
| static void IntDefaultHandler(void); |
| |
| /****************************************************************************** |
| ** API FUNCTION DEFINITIONS |
| ******************************************************************************/ |
| |
| /** |
| * |
| * The Default Interrupt Handler. |
| * |
| * This is the default interrupt handler for all interrupts. It simply loops |
| * forever so that the system state is preserved for observation by a |
| * debugger. Since interrupts should be disabled before unregistering the |
| * corresponding handler, this should never be called. |
| * |
| * |
| **/ |
| static void IntDefaultHandler(void) |
| { |
| /* Go into an infinite loop.*/ |
| while(1) |
| { |
| ; |
| } |
| } |
| |
| /** |
| * \brief Registers an interrupt Handler in the interrupt vector table for |
| * system interrupts. |
| * |
| * \param intrNum - Interrupt Number |
| * \param fnHandler - Function pointer to the ISR |
| * |
| * Note: When the interrupt occurs for the sytem interrupt number indicated, |
| * the control goes to the ISR given as the parameter. |
| * |
| * \return None. |
| **/ |
| void IntRegister(unsigned int intrNum, void (*fnHandler)(void)) |
| { |
| /* Assign ISR */ |
| fnRAMVectors[intrNum] = fnHandler; |
| } |
| |
| /** |
| * \brief Unregisters an interrupt |
| * |
| * \param intrNum - Interrupt Number |
| * |
| * Note: Once an interrupt is unregistered it will enter infinite loop once |
| * an interrupt occurs |
| * |
| * \return None. |
| **/ |
| void IntUnRegister(unsigned int intrNum) |
| { |
| /* Assign default ISR */ |
| fnRAMVectors[intrNum] = IntDefaultHandler; |
| } |
| |
| /** |
| * \brief This API is used to initialize the interrupt controller. This API |
| * shall be called before using the interrupt controller. |
| * |
| * \param None |
| * |
| * \return None. |
| * |
| **/ |
| void IntAINTCInit(void) |
| { |
| /* Reset the ARM interrupt controller */ |
| HWREG(SOC_AINTC_REGS + INTC_SYSCONFIG) = INTC_SYSCONFIG_SOFTRESET; |
| |
| /* Wait for the reset to complete */ |
| while((HWREG(SOC_AINTC_REGS + INTC_SYSSTATUS) |
| & INTC_SYSSTATUS_RESETDONE) != INTC_SYSSTATUS_RESETDONE); |
| |
| /* Enable any interrupt generation by setting priority threshold */ |
| HWREG(SOC_AINTC_REGS + INTC_THRESHOLD) = |
| INTC_THRESHOLD_PRIORITYTHRESHOLD; |
| } |
| |
| /** |
| * \brief This API assigns a priority to an interrupt and routes it to |
| * either IRQ or to FIQ. Priority 0 is the highest priority level |
| * Among the host interrupts, FIQ has more priority than IRQ. |
| * |
| * \param intrNum - Interrupt number |
| * \param priority - Interrupt priority level |
| * \param hostIntRoute - The host interrupt IRQ/FIQ to which the interrupt |
| * is to be routed. |
| * 'priority' can take any value from 0 to 127, 0 being the highest and |
| * 127 being the lowest priority. |
| * |
| * 'hostIntRoute' can take one of the following values \n |
| * AINTC_HOSTINT_ROUTE_IRQ - To route the interrupt to IRQ \n |
| * AINTC_HOSTINT_ROUTE_FIQ - To route the interrupt to FIQ |
| * |
| * \return None. |
| * |
| **/ |
| void IntPrioritySet(unsigned int intrNum, unsigned int priority, |
| unsigned int hostIntRoute) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_ILR(intrNum)) = |
| ((priority << INTC_ILR_PRIORITY_SHIFT) |
| & INTC_ILR_PRIORITY) |
| | hostIntRoute ; |
| } |
| |
| /** |
| * \brief This API enables the system interrupt in AINTC. However, for |
| * the interrupt generation, make sure that the interrupt is |
| * enabled at the peripheral level also. |
| * |
| * \param intrNum - Interrupt number |
| * |
| * \return None. |
| * |
| **/ |
| void IntSystemEnable(unsigned int intrNum) |
| { |
| /* Disable the system interrupt in the corresponding MIR_CLEAR register */ |
| HWREG(SOC_AINTC_REGS + INTC_MIR_CLEAR(intrNum >> REG_IDX_SHIFT)) |
| = (0x01 << (intrNum & REG_BIT_MASK)); |
| } |
| |
| /** |
| * \brief This API disables the system interrupt in AINTC. |
| * |
| * \param intrNum - Interrupt number |
| * |
| * \return None. |
| * |
| **/ |
| void IntSystemDisable(unsigned int intrNum) |
| { |
| /* Enable the system interrupt in the corresponding MIR_SET register */ |
| HWREG(SOC_AINTC_REGS + INTC_MIR_SET(intrNum >> REG_IDX_SHIFT)) |
| = (0x01 << (intrNum & REG_BIT_MASK)); |
| } |
| |
| /** |
| * \brief Sets the interface clock to be free running |
| * |
| * \param None. |
| * |
| * \return None. |
| * |
| **/ |
| void IntIfClkFreeRunSet(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_SYSCONFIG)&= ~INTC_SYSCONFIG_AUTOIDLE; |
| } |
| |
| /** |
| * \brief When this API is called, automatic clock gating strategy is applied |
| * based on the interface bus activity. |
| * |
| * \param None. |
| * |
| * \return None. |
| * |
| **/ |
| void IntIfClkAutoGateSet(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_SYSCONFIG)|= INTC_SYSCONFIG_AUTOIDLE; |
| } |
| |
| /** |
| * \brief Reads the active IRQ number. |
| * |
| * \param None |
| * |
| * \return Active IRQ number. |
| * |
| **/ |
| unsigned int IntActiveIrqNumGet(void) |
| { |
| return (HWREG(SOC_AINTC_REGS + INTC_SIR_IRQ) & INTC_SIR_IRQ_ACTIVEIRQ); |
| } |
| |
| /** |
| * \brief Reads the active FIQ number. |
| * |
| * \param None |
| * |
| * \return Active FIQ number. |
| * |
| **/ |
| unsigned int IntActiveFiqNumGet(void) |
| { |
| return (HWREG(SOC_AINTC_REGS + INTC_SIR_FIQ) & INTC_SIR_FIQ_ACTIVEFIQ); |
| } |
| |
| /** |
| * \brief Reads the spurious IRQ Flag. Spurious IRQ flag is reflected in both |
| * SIR_IRQ and IRQ_PRIORITY registers of the interrupt controller. |
| * |
| * \param None |
| * |
| * \return Spurious IRQ Flag. |
| * |
| **/ |
| unsigned int IntSpurIrqFlagGet(void) |
| { |
| return ((HWREG(SOC_AINTC_REGS + INTC_SIR_IRQ) |
| & INTC_SIR_IRQ_SPURIOUSIRQ) |
| >> INTC_SIR_IRQ_SPURIOUSIRQ_SHIFT); |
| } |
| |
| /** |
| * \brief Reads the spurious FIQ Flag. Spurious FIQ flag is reflected in both |
| * SIR_FIQ and FIQ_PRIORITY registers of the interrupt controller. |
| * |
| * \param None |
| * |
| * \return Spurious IRQ Flag. |
| * |
| **/ |
| unsigned int IntSpurFiqFlagGet(void) |
| { |
| return ((HWREG(SOC_AINTC_REGS + INTC_SIR_FIQ) |
| & INTC_SIR_FIQ_SPURIOUSFIQ) |
| >> INTC_SIR_FIQ_SPURIOUSFIQ_SHIFT); |
| } |
| |
| /** |
| * \brief Enables protection mode for the interrupt controller register access. |
| * When the protection is enabled, the registers will be accessible only |
| * in privileged mode of the CPU. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| **/ |
| void IntProtectionEnable(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_PROTECTION) = INTC_PROTECTION_PROTECTION; |
| } |
| |
| /** |
| * \brief Disables protection mode for the interrupt controller register access. |
| * When the protection is disabled, the registers will be accessible |
| * in both unprivileged and privileged mode of the CPU. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| **/ |
| void IntProtectionDisable(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_PROTECTION) &= ~INTC_PROTECTION_PROTECTION; |
| } |
| |
| /** |
| * \brief Enables the free running of input synchronizer clock |
| * |
| * \param None |
| * |
| * \return None |
| * |
| **/ |
| void IntSyncClkFreeRunSet(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_IDLE) &= ~INTC_IDLE_TURBO; |
| } |
| |
| /** |
| * \brief When this API is called, Input synchronizer clock is auto-gated |
| * based on interrupt input activity |
| * |
| * \param None |
| * |
| * \return None |
| * |
| **/ |
| void IntSyncClkAutoGateSet(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_IDLE) |= INTC_IDLE_TURBO; |
| } |
| |
| /** |
| * \brief Enables the free running of functional clock |
| * |
| * \param None |
| * |
| * \return None |
| * |
| **/ |
| void IntFuncClkFreeRunSet(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_IDLE) |= INTC_IDLE_FUNCIDLE; |
| } |
| |
| /** |
| * \brief When this API is called, functional clock gating strategy |
| * is applied. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| **/ |
| void IntFuncClkAutoGateSet(void) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_IDLE) &= ~INTC_IDLE_FUNCIDLE; |
| } |
| |
| /** |
| * \brief Returns the currently active IRQ priority level. |
| * |
| * \param None |
| * |
| * \return Current IRQ priority |
| * |
| **/ |
| unsigned int IntCurrIrqPriorityGet(void) |
| { |
| return (HWREG(SOC_AINTC_REGS + INTC_IRQ_PRIORITY) |
| & INTC_IRQ_PRIORITY_IRQPRIORITY); |
| } |
| |
| /** |
| * \brief Returns the currently active FIQ priority level. |
| * |
| * \param None |
| * |
| * \return Current FIQ priority |
| * |
| **/ |
| unsigned int IntCurrFiqPriorityGet(void) |
| { |
| return (HWREG(SOC_AINTC_REGS + INTC_FIQ_PRIORITY) |
| & INTC_FIQ_PRIORITY_FIQPRIORITY); |
| } |
| |
| /** |
| * \brief Returns the priority threshold. |
| * |
| * \param None |
| * |
| * \return Priority threshold value. |
| * |
| **/ |
| unsigned int IntPriorityThresholdGet(void) |
| { |
| return (HWREG(SOC_AINTC_REGS + INTC_THRESHOLD) |
| & INTC_THRESHOLD_PRIORITYTHRESHOLD); |
| } |
| |
| /** |
| * \brief Sets the given priority threshold value. |
| * |
| * \param threshold - Priority threshold value |
| * |
| * 'threshold' can take any value from 0x00 to 0x7F. To disable |
| * priority threshold, write 0xFF. |
| * |
| * \return None. |
| * |
| **/ |
| void IntPriorityThresholdSet(unsigned int threshold) |
| { |
| HWREG(SOC_AINTC_REGS + INTC_THRESHOLD) = |
| threshold & INTC_THRESHOLD_PRIORITYTHRESHOLD; |
| } |
| |
| /** |
| * \brief Returns the raw interrupt status before masking. |
| * |
| * \param intrNum - the system interrupt number. |
| * |
| * \return TRUE - if the raw status is set \n |
| * FALSE - if the raw status is not set. |
| * |
| **/ |
| unsigned int IntRawStatusGet(unsigned int intrNum) |
| { |
| return ((0 == ((HWREG(SOC_AINTC_REGS + INTC_ITR(intrNum >> REG_IDX_SHIFT)) |
| >> (intrNum & REG_BIT_MASK))& 0x01)) ? FALSE : TRUE); |
| } |
| |
| /** |
| * \brief Sets software interrupt for the given interrupt number. |
| * |
| * \param intrNum - the system interrupt number, for which software interrupt |
| * to be generated |
| * |
| * \return None |
| * |
| **/ |
| void IntSoftwareIntSet(unsigned int intrNum) |
| { |
| /* Enable the software interrupt in the corresponding ISR_SET register */ |
| HWREG(SOC_AINTC_REGS + INTC_ISR_SET(intrNum >> REG_IDX_SHIFT)) |
| = (0x01 << (intrNum & REG_BIT_MASK)); |
| |
| } |
| |
| /** |
| * \brief Clears the software interrupt for the given interrupt number. |
| * |
| * \param intrNum - the system interrupt number, for which software interrupt |
| * to be cleared. |
| * |
| * \return None |
| * |
| **/ |
| void IntSoftwareIntClear(unsigned int intrNum) |
| { |
| /* Disable the software interrupt in the corresponding ISR_CLEAR register */ |
| HWREG(SOC_AINTC_REGS + INTC_ISR_CLEAR(intrNum >> REG_IDX_SHIFT)) |
| = (0x01 << (intrNum & REG_BIT_MASK)); |
| |
| } |
| |
| /** |
| * \brief Returns the IRQ status after masking. |
| * |
| * \param intrNum - the system interrupt number |
| * |
| * \return TRUE - if interrupt is pending \n |
| * FALSE - in no interrupt is pending |
| * |
| **/ |
| unsigned int IntPendingIrqMaskedStatusGet(unsigned int intrNum) |
| { |
| return ((0 ==(HWREG(SOC_AINTC_REGS + INTC_PENDING_IRQ(intrNum >> REG_IDX_SHIFT)) |
| >> (((intrNum & REG_BIT_MASK)) & 0x01))) ? FALSE : TRUE); |
| } |
| |
| /** |
| * \brief Returns the FIQ status after masking. |
| * |
| * \param intrNum - the system interrupt number |
| * |
| * \return TRUE - if interrupt is pending \n |
| * FALSE - in no interrupt is pending |
| * |
| **/ |
| unsigned int IntPendingFiqMaskedStatusGet(unsigned int intrNum) |
| { |
| return ((0 ==(HWREG(SOC_AINTC_REGS + INTC_PENDING_FIQ(intrNum >> REG_IDX_SHIFT)) |
| >> (((intrNum & REG_BIT_MASK)) & 0x01))) ? FALSE : TRUE); |
| } |
| |
| /** |
| * \brief Enables the processor IRQ only in CPSR. Makes the processor to |
| * respond to IRQs. This does not affect the set of interrupts |
| * enabled/disabled in the AINTC. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| void IntMasterIRQEnable(void) |
| { |
| /* Enable IRQ in CPSR.*/ |
| CPUirqe(); |
| |
| } |
| |
| /** |
| * \brief Disables the processor IRQ only in CPSR.Prevents the processor to |
| * respond to IRQs. This does not affect the set of interrupts |
| * enabled/disabled in the AINTC. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| void IntMasterIRQDisable(void) |
| { |
| /* Disable IRQ in CPSR.*/ |
| CPUirqd(); |
| } |
| |
| /** |
| * \brief Enables the processor FIQ only in CPSR. Makes the processor to |
| * respond to FIQs. This does not affect the set of interrupts |
| * enabled/disabled in the AINTC. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| void IntMasterFIQEnable(void) |
| { |
| /* Enable FIQ in CPSR.*/ |
| CPUfiqe(); |
| } |
| |
| /** |
| * \brief Disables the processor FIQ only in CPSR.Prevents the processor to |
| * respond to FIQs. This does not affect the set of interrupts |
| * enabled/disabled in the AINTC. |
| * |
| * \param None |
| * |
| * \return None |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| void IntMasterFIQDisable(void) |
| { |
| /* Disable FIQ in CPSR.*/ |
| CPUfiqd(); |
| } |
| |
| /** |
| * \brief Returns the status of the interrupts FIQ and IRQ. |
| * |
| * \param None |
| * |
| * \return Status of interrupt as in CPSR. |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| unsigned int IntMasterStatusGet(void) |
| { |
| return CPUIntStatus(); |
| } |
| |
| /** |
| * \brief Read and save the stasus and Disables the processor IRQ . |
| * Prevents the processor to respond to IRQs. |
| * |
| * \param None |
| * |
| * \return Current status of IRQ |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| unsigned char IntDisable(void) |
| { |
| unsigned char status; |
| |
| /* Reads the current status.*/ |
| status = (IntMasterStatusGet() & 0xFF); |
| |
| /* Disable the Interrupts.*/ |
| IntMasterIRQDisable(); |
| |
| return status; |
| } |
| |
| /** |
| * \brief Restore the processor IRQ only status. This does not affect |
| * the set of interrupts enabled/disabled in the AINTC. |
| * |
| * \param The status returned by the IntDisable fundtion. |
| * |
| * \return None |
| * |
| * Note: This function call shall be done only in previleged mode of ARM |
| **/ |
| void IntEnable(unsigned char status) |
| { |
| if((status & 0x80) == 0) |
| { |
| IntMasterIRQEnable(); |
| } |
| } |
| |
| /********************************** End Of File ******************************/ |
| |
| |