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 20 enum 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 */ 28 volatile 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 getActiveIRQ(void)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 */ isIRQPending(void)75static inline bool_t isIRQPending(void) 76 { 77 return getActiveIRQ() != irqInvalid; 78 } 79 80 /* Enable or disable irq according to the 'disable' flag. */ maskInterrupt(bool_t disable,irq_t irq)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 ackInterrupt(irq_t irq)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 handleSpuriousIRQ(void)100static inline void handleSpuriousIRQ(void) 101 { 102 /* Reset and re-enable IRQs. */ 103 intc->intcps_control = 1; 104 dsb(); 105 } 106 107