1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#pragma once 8 9#include <config.h> 10#include <basic_types.h> 11#include <machine/interrupt.h> 12 13enum irqNumbers { 14 irqInvalid = 255 15}; 16 17/* Memory map for AVIC (Advanced Vectored Interrupt Controller). */ 18volatile struct avic_map { 19 uint32_t intctl; 20 uint32_t nimask; 21 uint32_t intennum; 22 uint32_t intdisnum; 23 uint32_t intenableh; 24 uint32_t intenablel; 25 uint32_t inttypeh; 26 uint32_t inttypel; 27 uint32_t nipriority[8]; 28 uint32_t nivecsr; 29 uint32_t fivecsr; 30 uint32_t intsrch; 31 uint32_t intsrcl; 32 uint32_t intfrch; 33 uint32_t intfrcl; 34 uint32_t nipndh; 35 uint32_t nipndl; 36 uint32_t fipndh; 37 uint32_t fipndl; 38 uint32_t vector[64]; 39} *avic = (volatile void *)AVIC_PPTR; 40 41/* Reading the IRQ number from the nivecsr register also 42 * acks the interrupt. To allow the active irq to be read 43 * multiple times per interrupt received, we store the 44 * current active IRQ in a global variable. 45 */ 46extern irq_t active_irq; 47 48/* Get the active IRQ number from the AVIC. Returns 0xff if 49 * there isn't one. Note this is also known as irqInvalid */ 50static inline irq_t getActiveIRQ(void) 51{ 52 if (active_irq == irqInvalid) { 53 /* Read the IRQ number from the IRQ controller. 54 * This has the side-effect of acking the interrupt. 55 * Reading from this register after acking the 56 * interrupt will yield an invalid IRQ number, so 57 * we save the IRQ number in a global variable to 58 * allow multiple successive calls to this function. 59 */ 60 active_irq = (avic->nivecsr >> 16) & 0xff; 61 } 62 63 return active_irq; 64} 65 66/* Check for pending IRQ */ 67static inline bool_t isIRQPending(void) 68{ 69 return getActiveIRQ() != irqInvalid; 70} 71 72/* Enable or disable irq according to the 'disable' flag. */ 73static inline void maskInterrupt(bool_t disable, irq_t irq) 74{ 75 if (disable) { 76 avic->intdisnum = irq; 77 } else { 78 avic->intennum = irq; 79 } 80} 81 82static inline void ackInterrupt(irq_t irq) 83{ 84 /* The interrupt was acked when the IRQ number was read from 85 * the IRQ controller in getActiveIRQ. Here we reset the 86 * global active IRQ number so the next call to getActiveIRQ 87 * will read the IRQ number from the IRQ controller. 88 */ 89 active_irq = irqInvalid; 90} 91 92static inline void handleSpuriousIRQ(void) 93{ 94 /* do nothing */ 95} 96 97