| /**************************************************************************** |
| * arch/arm/src/tms570/tms570_irq.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdint.h> |
| #include <errno.h> |
| #include <assert.h> |
| #include <debug.h> |
| |
| #include <nuttx/irq.h> |
| #include <nuttx/arch.h> |
| #include <arch/irq.h> |
| |
| #include "arm_internal.h" |
| #include "hardware/tms570_vim.h" |
| #include "tms570_gio.h" |
| #include "tms570_esm.h" |
| #include "tms570_irq.h" |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: tms570_error_handler |
| ****************************************************************************/ |
| |
| static void tms570_error_handler(void) |
| { |
| PANIC(); |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: up_irqinitialize |
| |
| * The device supports three different possibilities for software to handle |
| * interrupts: |
| * |
| * 1. Index interrupts mode (compatible with TMS470R1x legacy code), |
| * 2. Register vectored interrupts (automatically provide vector address |
| * to application) |
| * 3. Hardware vectored interrupts (automatically dispatch to ISR, IRQ |
| * only) |
| * |
| * Only the indexed mode is supported here: After the interrupt is received |
| * by the CPU, the CPU branches to 0x18 (IRQ) or 0x1C (FIQ) to execute the |
| * main ISR. The main ISR routine reads the offset register (IRQINDEX, |
| * FIQINDEX) to determine the source of the interrupt. |
| * |
| * To use mode 2), it would only be necessary to initialize the VIM_RAM. |
| * To use mode 3), it would be necessary to initialize the VIM_RAM and also |
| * to set the vector enable (VE) bit in the CP15 R1 register. This bit is |
| * zero on reset so that the default state after reset is backward |
| * compatible to earlier ARM CPU. |
| * |
| ****************************************************************************/ |
| |
| #define TMS570_VIM_FIRQPR3 (TMS570_VIM_BASE+0x001c) |
| #define TMS570_VIM_REQENASET3 (TMS570_VIM_BASE+0x003c) |
| #define TMS570_VIM_REQENACLR3 (TMS570_VIM_BASE+0x004c) |
| |
| void up_irqinitialize(void) |
| { |
| uintptr_t *vimram; |
| int i; |
| |
| /* Initialize VIM RAM vectors. These vectors are not used in the current |
| * interrupt handler logic. |
| */ |
| |
| vimram = (uintptr_t *)TMS570_VIMRAM_BASE; |
| for (i = 0; i < (TMS570_IRQ_NCHANNELS + 1); i++) |
| { |
| *vimram++ = (uintptr_t)tms570_error_handler; |
| } |
| |
| /* Set Fall-Back Address Parity Error Register (also not used) */ |
| |
| putreg32((uint32_t)tms570_error_handler, TMS570_VIM_FBPARERR); |
| |
| /* Assign all interrupt requests to the VIM channel of the same value. |
| * NOTE: Nothing need be done. That is the power-on default mapping. |
| */ |
| |
| /* Assign all channels to IRQs */ |
| |
| putreg32(0, TMS570_VIM_FIRQPR0); |
| putreg32(0, TMS570_VIM_FIRQPR1); |
| putreg32(0, TMS570_VIM_FIRQPR2); |
| #ifdef TMS570_VIM_FIRQPR3 |
| putreg32(0, TMS570_VIM_FIRQPR3); |
| #endif |
| |
| /* Disable all interrupts */ |
| |
| putreg32(0xfffffffc, TMS570_VIM_REQENACLR0); |
| putreg32(0xffffffff, TMS570_VIM_REQENACLR1); |
| putreg32(0xffffffff, TMS570_VIM_REQENACLR2); |
| #ifdef TMS570_VIM_REQENACLR3 |
| putreg32(0xffffffff, TMS570_VIM_REQENACLR3); |
| #endif |
| |
| #ifdef CONFIG_ARMV7R_HAVE_DECODEFIQ |
| /* By default, interrupt CHAN0 is mapped to ESM (Error Signal Module) |
| * high level interrupt and CHAN1 is reserved for other NMI. For safety |
| * reasons, these two channels are mapped to FIQ only and can NOT be |
| * disabled through ENABLE registers. |
| */ |
| |
| #endif |
| |
| #ifndef CONFIG_SUPPRESS_INTERRUPTS |
| #ifdef CONFIG_TMS570_GIO_IRQ |
| /* Initialize logic to support a second level of interrupt decoding for |
| * GIO pins. |
| */ |
| |
| tms570_gioirq_initialize(); |
| #endif |
| |
| /* Attach and enable ESM interrupts. The high level interrupt is really |
| * an NMI. |
| */ |
| |
| irq_attach(TMS570_REQ_ESMHIGH, tms570_esm_interrupt, NULL); |
| irq_attach(TMS570_REQ_ESMLO, tms570_esm_interrupt, NULL); |
| up_enable_irq(TMS570_REQ_ESMHIGH); |
| up_enable_irq(TMS570_REQ_ESMLO); |
| |
| /* And finally, enable interrupts globally */ |
| |
| up_irq_enable(); |
| #endif |
| } |
| |
| /**************************************************************************** |
| * Name: arm_decodeirq |
| * |
| * Description: |
| * This function is called from the IRQ vector handler in arm_vectors.S. |
| * At this point, the interrupt has been taken and the registers have |
| * been saved on the stack. This function simply needs to determine the |
| * the irq number of the interrupt and then to call arm_doirq to dispatch |
| * the interrupt. |
| * |
| * Input Parameters: |
| * regs - A pointer to the register save area on the stack. |
| * |
| ****************************************************************************/ |
| |
| uint32_t *arm_decodeirq(uint32_t *regs) |
| { |
| int vector; |
| |
| /* Check for a VRAM parity error. |
| * |
| * REVISIT: This is not to critical in this implementation since VIM RAM |
| * is not used. |
| */ |
| |
| /* Get the interrupting vector number from the IRQINDEX register. Zero, |
| * the "phantom" vector will returned. |
| */ |
| |
| vector = getreg32(TMS570_VIM_IRQINDEX) & VIM_IRQINDEX_MASK; |
| if (vector > 0) |
| { |
| /* Dispatch the interrupt. NOTE that the IRQ number is the vector |
| * number offset by one to skip over the "phantom" vector. |
| */ |
| |
| regs = arm_doirq(vector - 1, regs); |
| } |
| |
| return regs; |
| } |
| |
| /**************************************************************************** |
| * Name: arm_decodefiq |
| * |
| * Description: |
| * This function is called from the FIQ vector handler in arm_vectors.S. |
| * At this point, the interrupt has been taken and the registers have |
| * been saved on the stack. This function simply needs to determine the |
| * the irq number of the interrupt and then to call arm_doirq to dispatch |
| * the interrupt. |
| * |
| * Input Parameters: |
| * regs - A pointer to the register save area on the stack. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_ARMV7R_HAVE_DECODEFIQ |
| uint32_t *arm_decodefiq(uint32_t *regs) |
| { |
| int vector; |
| |
| /* Check for a VRAM parity error. |
| * |
| * REVISIT: This is not to critical in this implementation since VIM RAM |
| * is not used. |
| */ |
| |
| /* Get the interrupting vector number from the FIQINDEX register. Zero, |
| * the "phantom" vector will returned. |
| */ |
| |
| vector = getreg32(TMS570_VIM_FIQINDEX) & VIM_FIQINDEX_MASK; |
| if (vector > 0) |
| { |
| /* Dispatch the interrupt. NOTE that the IRQ number is the vector |
| * number offset by one to skip over the "phantom" vector. |
| */ |
| |
| regs = arm_doirq(vector - 1, regs); |
| } |
| |
| return regs; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: up_disable_irq |
| * |
| * Description: |
| * Disable the IRQ or FIQ specified by 'channel' |
| * |
| ****************************************************************************/ |
| |
| void up_disable_irq(int channel) |
| { |
| uintptr_t regaddr; |
| uint32_t regval; |
| uint32_t bitmask; |
| unsigned int regndx; |
| |
| DEBUGASSERT(channel >= 0 && channel < TMS570_IRQ_NCHANNELS); |
| |
| /* Offset to account for the "phantom" vector */ |
| |
| regndx = VIM_REGNDX(channel); |
| channel = VIM_REGBIT(channel); |
| bitmask = (1 << channel); |
| |
| /* Disable the IRQ/FIQ by setting the corresponding REQENACLR bit. */ |
| |
| regaddr = TMS570_VIM_REQENACLR(regndx); |
| regval = getreg32(regaddr); |
| regval |= bitmask; |
| putreg32(regval, regaddr); |
| } |
| |
| /**************************************************************************** |
| * Name: up_enable_irq |
| * |
| * Description: |
| * Enable the IRQ specified by 'channel' |
| * |
| ****************************************************************************/ |
| |
| void up_enable_irq(int channel) |
| { |
| uintptr_t regaddr; |
| uint32_t regval; |
| uint32_t bitmask; |
| unsigned int regndx; |
| |
| DEBUGASSERT(channel >= 0 && channel < TMS570_IRQ_NCHANNELS); |
| |
| /* Offset to account for the "phantom" vector */ |
| |
| regndx = VIM_REGNDX(channel); |
| channel = VIM_REGBIT(channel); |
| bitmask = (1 << channel); |
| |
| #ifdef CONFIG_ARMV7R_HAVE_DECODEFIQ |
| /* Select IRQ (vs FIQ) by clearing the corresponding FIRQPR bit */ |
| |
| regaddr = TMS570_VIM_FIRQPR(regndx); |
| regval = getreg32(regaddr); |
| regval &= ~bitmask; |
| putreg32(regval, regaddr); |
| #endif |
| |
| /* Enable the IRQ by setting the corresponding REQENASET bit. */ |
| |
| regaddr = TMS570_VIM_REQENASET(regndx); |
| regval = getreg32(regaddr); |
| regval |= bitmask; |
| putreg32(regval, regaddr); |
| } |
| |
| /**************************************************************************** |
| * Name: up_enable_fiq |
| * |
| * Description: |
| * Enable the FIQ specified by 'channel' |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_ARMV7R_HAVE_DECODEFIQ |
| void up_enable_fiq(int channel) |
| { |
| uintptr_t regaddr; |
| uint32_t regval; |
| uint32_t bitmask; |
| unsigned int regndx; |
| |
| DEBUGASSERT(channel >= 0 && channel < TMS570_IRQ_NCHANNELS); |
| |
| /* Offset to account for the "phantom" vector */ |
| |
| regndx = VIM_REGNDX(channel); |
| channel = VIM_REGBIT(channel); |
| bitmask = (1 << channel); |
| |
| /* Select FIQ (vs IRQ) by setting the corresponding FIRQPR bit */ |
| |
| regaddr = TMS570_VIM_FIRQPR(regndx); |
| regval = getreg32(regaddr); |
| regval &= ~bitmask; |
| putreg32(regval, regaddr); |
| |
| /* Enable the FIQ by setting the corresponding REQENASET bit. */ |
| |
| regaddr = TMS570_VIM_REQENASET(regndx); |
| regval = getreg32(regaddr); |
| regval |= bitmask; |
| putreg32(regval, regaddr); |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: arm_ack_irq |
| * |
| * Description: |
| * Acknowledge the IRQ |
| * |
| ****************************************************************************/ |
| |
| void arm_ack_irq(int irq) |
| { |
| } |