| /**************************************************************************** |
| * arch/arm/src/lpc214x/lpc214x_decodeirq.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * 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 <nuttx/irq.h> |
| #include <nuttx/arch.h> |
| #include <assert.h> |
| #include <debug.h> |
| |
| #include "chip.h" |
| #include "arm_internal.h" |
| #include "lpc214x_vic.h" |
| #include "sched/sched.h" |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| /* This array maps 4 bits into the bit number of the lowest bit that it set */ |
| |
| #ifndef CONFIG_SUPPRESS_INTERRUPTS |
| static uint8_t g_nibblemap[16] = |
| { |
| 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 |
| }; |
| #endif |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * arm_decodeirq() and/or lpc214x_decodeirq() |
| * |
| * Description: |
| * The vectored interrupt controller (VIC) takes 32 interrupt request |
| * inputs and pro grammatically assigns them into 3 categories: FIQ, |
| * vectored IRQ, and non-vectored IRQ. |
| * |
| * - FIQs have the highest priority. There is a single FIQ vector, but |
| * multiple interrupt sources can be ORed to this FIQ vector. |
| * |
| * - Vectored IRQs have the middle priority. Any 16 of the 32 interrupt |
| * sources can be assigned to vectored IRQs. |
| * |
| * - Non-vectored IRQs have the lowest priority. |
| * |
| * The general flow of IRQ processing is to simply read the VIC vector |
| * address and jump to the address of the vector provided in the register. |
| * The VIC will provide the address of the highest priority vectored IRQ. |
| * If a non-vectored IRQ is requesting, the address of a default handler |
| * is provided. |
| * |
| ****************************************************************************/ |
| |
| #ifndef CONFIG_VECTORED_INTERRUPTS |
| uint32_t *arm_decodeirq(uint32_t *regs) |
| #else |
| static uint32_t *lpc214x_decodeirq(uint32_t *regs) |
| #endif |
| { |
| struct tcb_s *tcb = this_task(); |
| |
| #ifdef CONFIG_SUPPRESS_INTERRUPTS |
| tcb->xcp.regs = regs; |
| up_set_interrupt_context(true); |
| err("ERROR: Unexpected IRQ\n"); |
| PANIC(); |
| return NULL; |
| #else |
| |
| /* Decode the interrupt. We have to do this by search for the lowest |
| * numbered non-zero bit in the interrupt status register. |
| */ |
| |
| uint32_t pending = vic_getreg(LPC214X_VIC_IRQSTATUS_OFFSET) & 0x007fffff; |
| unsigned int nibble; |
| unsigned int irq_base; |
| unsigned int irq = NR_IRQS; |
| |
| /* Search in groups of four bits. For 22 sources, this is at most six |
| * times through the loop. |
| */ |
| |
| for (nibble = pending & 0x0f, irq_base = 0; |
| pending && irq_base < NR_IRQS; |
| pending >>= 4, nibble = pending & 0x0f, irq_base += 4) |
| { |
| if (nibble) |
| { |
| irq = irq_base + g_nibblemap[nibble]; |
| break; |
| } |
| } |
| |
| /* Verify that the resulting IRQ number is valid */ |
| |
| if (irq < NR_IRQS) |
| { |
| uint32_t *saveregs; |
| bool savestate; |
| |
| savestate = up_interrupt_context(); |
| saveregs = tcb->xcp.regs; |
| up_set_interrupt_context(true); |
| tcb->xcp.regs = regs; |
| |
| /* Deliver the IRQ */ |
| |
| irq_dispatch(irq, regs); |
| |
| /* Restore the previous value of saveregs. */ |
| |
| up_set_interrupt_context(savestate); |
| tcb->xcp.regs = saveregs; |
| } |
| |
| return NULL; /* Return not used in this architecture */ |
| #endif |
| } |
| |
| #ifdef CONFIG_VECTORED_INTERRUPTS |
| uint32_t *arm_decodeirq(uint32_t *regs) |
| { |
| vic_vector_t vector = |
| (vic_vector_t)vic_getreg(LPC214X_VIC_VECTADDR_OFFSET); |
| vector(regs); |
| return NULL; /* Return not used in this architecture */ |
| } |
| #endif |