1178476Sjb/* 2178476Sjb * Copyright 2014, General Dynamics C4 Systems 3178476Sjb * 4178476Sjb * SPDX-License-Identifier: GPL-2.0-only 5178476Sjb */ 6178476Sjb 7178476Sjb#pragma once 8178476Sjb 9178476Sjb#include <config.h> 10178476Sjb#include <basic_types.h> 11178476Sjb#include <machine/interrupt.h> 12178476Sjb 13178476Sjbenum irqNumbers { 14178476Sjb irqInvalid = 255 15178476Sjb}; 16178476Sjb 17178476Sjb/* Memory map for AVIC (Advanced Vectored Interrupt Controller). */ 18178476Sjbvolatile struct avic_map { 19178476Sjb uint32_t intctl; 20178476Sjb uint32_t nimask; 21178476Sjb uint32_t intennum; 22178476Sjb uint32_t intdisnum; 23178476Sjb uint32_t intenableh; 24178476Sjb uint32_t intenablel; 25178476Sjb uint32_t inttypeh; 26178476Sjb uint32_t inttypel; 27178476Sjb uint32_t nipriority[8]; 28178476Sjb uint32_t nivecsr; 29178476Sjb uint32_t fivecsr; 30178476Sjb uint32_t intsrch; 31178476Sjb uint32_t intsrcl; 32178476Sjb uint32_t intfrch; 33178476Sjb uint32_t intfrcl; 34178476Sjb uint32_t nipndh; 35178476Sjb uint32_t nipndl; 36178476Sjb uint32_t fipndh; 37178476Sjb uint32_t fipndl; 38178476Sjb 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