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 <types.h> 11#include <machine/io.h> 12#include <kernel/vspace.h> 13#include <arch/kernel/vspace.h> 14#include <linker.h> 15#include <armv/machine.h> 16#include <machine/interrupt.h> 17 18#define INTCPS_SIR_IRQ_SPURIOUSIRQFLAG 0xFF0000 19 20enum irqNumbers { 21 irqInvalid = 255 22}; 23 24/* 25 * The struct below is used to discourage the compiler from generating literals 26 * for every single address we might access. 27 */ 28volatile struct INTC_map { 29 uint32_t padding[4]; 30 uint32_t intcps_sysconfig; 31 uint32_t intcps_sysstatus; 32 uint32_t padding2[10]; 33 uint32_t intcps_sir_irq; 34 uint32_t intcps_sir_fiq; 35 uint32_t intcps_control; 36 uint32_t intcps_protection; 37 uint32_t intcps_idle; 38 uint32_t padding3[3]; 39 uint32_t intcps_irq_priority; 40 uint32_t intcps_fiq_priority; 41 uint32_t intcps_threshold; 42 uint32_t padding4[5]; 43 struct { 44 uint32_t intcps_itr; 45 uint32_t intcps_mir; 46 uint32_t intcps_mir_clear; 47 uint32_t intcps_mir_set; 48 uint32_t intcps_isr_set; 49 uint32_t intcps_isr_clear; 50 uint32_t intcps_pending_irq; 51 uint32_t intcps_pending_fiq; 52 } intcps_n[3]; 53 uint32_t padding5[8]; 54 uint32_t intcps_ilr[96]; 55} *intc = (volatile void *)INTC_PPTR; 56 57static inline irq_t getActiveIRQ(void) 58{ 59 uint32_t intcps_sir_irq = intc->intcps_sir_irq; 60 irq_t irq = (irq_t)(intcps_sir_irq & 0x7f); 61 62 /* Ignore spurious interrupts. */ 63 if ((intcps_sir_irq & INTCPS_SIR_IRQ_SPURIOUSIRQFLAG) == 0) { 64 assert(irq <= maxIRQ); 65 if (intc->intcps_n[irq / 32].intcps_pending_irq & (1 << (irq & 31))) { 66 return irq; 67 } 68 } 69 70 /* No interrupt. */ 71 return irqInvalid; 72} 73 74/* Check for pending IRQ */ 75static inline bool_t isIRQPending(void) 76{ 77 return getActiveIRQ() != irqInvalid; 78} 79 80/* Enable or disable irq according to the 'disable' flag. */ 81static inline void maskInterrupt(bool_t disable, irq_t irq) 82{ 83 if (likely(irq < maxIRQ)) { 84 if (disable) { 85 intc->intcps_n[irq / 32].intcps_mir_set = 1 << (irq & 31); 86 } else { 87 intc->intcps_n[irq / 32].intcps_mir_clear = 1 << (irq & 31); 88 } 89 } 90} 91 92static inline void ackInterrupt(irq_t irq) 93{ 94 intc->intcps_control = 1; 95 /* Ensure the ack has hit the interrupt controller before potentially 96 * re-enabling interrupts. */ 97 dsb(); 98} 99 100static inline void handleSpuriousIRQ(void) 101{ 102 /* Reset and re-enable IRQs. */ 103 intc->intcps_control = 1; 104 dsb(); 105} 106 107