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)57 static 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)75 static 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)81 static 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)92 static 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)100 static inline void handleSpuriousIRQ(void)
101 {
102     /* Reset and re-enable IRQs. */
103     intc->intcps_control = 1;
104     dsb();
105 }
106 
107