1327952Sdim/*
2317017Sdim * Copyright 2019, DornerWorks
3353358Sdim * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
4353358Sdim *
5353358Sdim * SPDX-License-Identifier: GPL-2.0-only
6317017Sdim */
7317017Sdim
8317017Sdim/*
9317017Sdim * Arm Generic Interrupt Controller v3
10317017Sdim */
11317017Sdim
12317017Sdim#pragma once
13327952Sdim
14327952Sdim/* tell the kernel we have the set trigger feature */
15317017Sdim#define HAVE_SET_TRIGGER 1
16327952Sdim
17327952Sdim#include <stdint.h>
18327952Sdim#include <util.h>
19327952Sdim#include <linker.h>
20317017Sdim#include <mode/smp/smp.h>
21317017Sdim#include <model/statedata.h>
22317017Sdim#include <armv/machine.h>
23327952Sdim
24327952Sdim#include "gic_common.h"
25327952Sdim
26327952Sdim#define GIC_PRI_LOWEST     0xf0
27317017Sdim#define GIC_PRI_IRQ        0xa0
28327952Sdim#define GIC_PRI_HIGHEST    0x80 /* Higher priorities belong to Secure-World */
29327952Sdim
30317017Sdim#define IRQ_MASK MASK(16u)
31317017Sdim
32317017Sdim/* Register bits */
33317017Sdim#define GICD_CTL_ENABLE 0x1
34327952Sdim#define GICD_CTLR_RWP                BIT(31)
35327952Sdim#define GICD_CTLR_ARE_NS             BIT(4)
36317017Sdim#define GICD_CTLR_ENABLE_G1NS         BIT(1)
37317017Sdim#define GICD_CTLR_ENABLE_G0          BIT(0)
38317017Sdim#define GICD_IROUTER_SPI_MODE_ANY    BIT(31)
39317017Sdim
40317017Sdim#define GICD_TYPE_LINESNR 0x01f
41317017Sdim
42317017Sdim#define GICC_SRE_EL1_SRE             BIT(0)
43317017Sdim
44317017Sdim#define GICR_WAKER_ProcessorSleep    BIT(1)
45317017Sdim#define GICR_WAKER_ChildrenAsleep    BIT(2)
46317017Sdim
47317017Sdim#define GICC_CTLR_EL1_EOImode_drop   BIT(1)
48317017Sdim
49317017Sdim#define DEFAULT_PMR_VALUE            0xff
50317017Sdim
51327952Sdim/* System registers for GIC CPU interface */
52317017Sdim#ifdef CONFIG_ARCH_AARCH64
53317017Sdim#define ICC_IAR1_EL1    "S3_0_C12_C12_0"
54327952Sdim#define ICC_EOIR1_EL1   "S3_0_C12_C12_1"
55317017Sdim#define ICC_HPPIR1_EL1  "S3_0_C12_C12_2"
56317017Sdim#define ICC_BPR1_EL1    "S3_0_C12_C12_3"
57317017Sdim#define ICC_DIR_EL1     "S3_0_C12_C11_1"
58317017Sdim#define ICC_PMR_EL1     "S3_0_C4_C6_0"
59317017Sdim#define ICC_CTLR_EL1    "S3_0_C12_C12_4"
60317017Sdim#define ICC_IGRPEN1_EL1 "S3_0_C12_C12_7"
61317017Sdim#define ICC_SRE_EL1     "S3_0_C12_C12_5"
62317017Sdim#define MPIDR           "mpidr_el1"
63317017Sdim#else
64317017Sdim#define ICC_IAR1_EL1    " p15, 0,  %0, c12,  c12, 0"
65317017Sdim#define ICC_EOIR1_EL1   " p15, 0,  %0, c12,  c12, 1"
66317017Sdim#define ICC_HPPIR1_EL1  " p15, 0,  %0, c12,  c12, 2"
67317017Sdim#define ICC_BPR1_EL1    " p15, 0,  %0, c12,  c12, 3"
68317017Sdim#define ICC_DIR_EL1     " p15, 0,  %0, c12,  c11, 1"
69317017Sdim#define ICC_PMR_EL1     " p15, 0,  %0, c4,  c6, 0"
70317017Sdim#define ICC_CTLR_EL1    " p15, 0,  %0, c12,  c12, 4"
71317017Sdim#define ICC_IGRPEN1_EL1 " p15, 0,  %0, c12,  c12, 7"
72317017Sdim#define ICC_SRE_EL1     " p15, 0,  %0, c12,  c12, 5"
73317017Sdim#define MPIDR           " p15, 0,  %0, c0,  c0, 5"
74317017Sdim#endif
75317017Sdim
76317017Sdim/* Memory map for GIC distributor */
77317017Sdimstruct gic_dist_map {
78317017Sdim    uint32_t ctlr;                /* 0x0000 */
79317017Sdim    uint32_t typer;               /* 0x0004 */
80317017Sdim    uint32_t iidr;                /* 0x0008 */
81317017Sdim    uint32_t res0;                /* 0x000C */
82317017Sdim    uint32_t statusr;             /* 0x0010 */
83317017Sdim    uint32_t res1[11];            /* [0x0014, 0x0040) */
84317017Sdim    uint32_t setspi_nsr;          /* 0x0040 */
85317017Sdim    uint32_t res2;                /* 0x0044 */
86317017Sdim    uint32_t clrspi_nsr;          /* 0x0048 */
87317017Sdim    uint32_t res3;                /* 0x004C */
88317017Sdim    uint32_t setspi_sr;           /* 0x0050 */
89317017Sdim    uint32_t res4;                /* 0x0054 */
90317017Sdim    uint32_t clrspi_sr;           /* 0x0058 */
91317017Sdim    uint32_t res5[9];             /* [0x005C, 0x0080) */
92317017Sdim    uint32_t igrouprn[32];        /* [0x0080, 0x0100) */
93317017Sdim
94317017Sdim    uint32_t isenablern[32];        /* [0x100, 0x180) */
95317017Sdim    uint32_t icenablern[32];        /* [0x180, 0x200) */
96317017Sdim    uint32_t ispendrn[32];          /* [0x200, 0x280) */
97317017Sdim    uint32_t icpendrn[32];          /* [0x280, 0x300) */
98317017Sdim    uint32_t isactivern[32];        /* [0x300, 0x380) */
99317017Sdim    uint32_t icactivern[32];        /* [0x380, 0x400) */
100317017Sdim
101317017Sdim    uint32_t ipriorityrn[255];      /* [0x400, 0x7FC) */
102317017Sdim    uint32_t res6;                  /* 0x7FC */
103317017Sdim
104317017Sdim    uint32_t itargetsrn[254];       /* [0x800, 0xBF8) */
105317017Sdim    uint32_t res7[2];               /* 0xBF8 */
106317017Sdim
107317017Sdim    uint32_t icfgrn[64];            /* [0xC00, 0xD00) */
108317017Sdim    uint32_t igrpmodrn[64];         /* [0xD00, 0xE00) */
109317017Sdim    uint32_t nsacrn[64];            /* [0xE00, 0xF00) */
110317017Sdim    uint32_t sgir;                  /* 0xF00 */
111327952Sdim    uint32_t res8[3];               /* [0xF04, 0xF10) */
112317017Sdim    uint32_t cpendsgirn[4];         /* [0xF10, 0xF20) */
113317017Sdim    uint32_t spendsgirn[4];         /* [0xF20, 0xF30) */
114317017Sdim    uint32_t res9[5235];            /* [0x0F30, 0x6100) */
115317017Sdim
116317017Sdim    uint64_t iroutern[960];         /* [0x6100, 0x7F00) */
117317017Sdim};
118317017Sdim
119317017Sdim/* Memory map for GIC Redistributor Registers for control and physical LPI's */
120317017Sdimstruct gic_rdist_map {          /* Starting */
121317017Sdim    uint32_t    ctlr;           /* 0x0000 */
122327952Sdim    uint32_t    iidr;           /* 0x0004 */
123317017Sdim    uint64_t    typer;          /* 0x0008 */
124317017Sdim    uint32_t    statusr;        /* 0x0010 */
125    uint32_t    waker;          /* 0x0014 */
126    uint32_t    res0[10];       /* 0x0018 */
127    uint64_t    setlpir;        /* 0x0040 */
128    uint64_t    clrlpir;        /* 0x0048 */
129    uint32_t    res1[8];        /* 0x0050 */
130    uint64_t    propbaser;      /* 0x0070 */
131    uint64_t    pendbaser;      /* 0x0078 */
132    uint32_t    res2[8];        /* 0x0080 */
133    uint64_t    invlpir;        /* 0x00a0 */
134    uint32_t    res3[2];        /* 0x00a8 */
135    uint64_t    invallr;        /* 0x00b0 */
136    uint32_t    res4[2];        /* 0x00b8 */
137    uint32_t    syncr;          /* 0x00c0 */
138};
139
140/* Memory map for the GIC Redistributor Registers for the SGI and PPI's */
141struct gic_rdist_sgi_ppi_map {  /* Starting */
142    uint32_t    res0[32];       /* 0x0000 */
143    uint32_t    igroupr0;       /* 0x0080 */
144    uint32_t    res1[31];       /* 0x0084 */
145    uint32_t    isenabler0;     /* 0x0100 */
146    uint32_t    res2[31];       /* 0x0104 */
147    uint32_t    icenabler0;     /* 0x0180 */
148    uint32_t    res3[31];       /* 0x0184 */
149    uint32_t    ispendr0;       /* 0x0200 */
150    uint32_t    res4[31];       /* 0x0204 */
151    uint32_t    icpendr0;       /* 0x0280 */
152    uint32_t    res5[31];       /* 0x0284 */
153    uint32_t    isactiver0;     /* 0x0300 */
154    uint32_t    res6[31];       /* 0x0304 */
155    uint32_t    icactiver0;     /* 0x0380 */
156    uint32_t    res7[31];       /* 0x0384 */
157    uint32_t    ipriorityrn[8]; /* 0x0400 */
158    uint32_t    res8[504];      /* 0x0420 */
159    uint32_t    icfgr0;         /* 0x0C00 */
160    uint32_t    icfgr1;         /* 0x0C04 */
161    uint32_t    res9[62];       /* 0x0C08 */
162    uint32_t    igrpmodr0;      /* 0x0D00*/
163    uint32_t    res10[63];      /* 0x0D04 */
164    uint32_t    nsacr;          /* 0x0E00 */
165};
166
167extern volatile struct gic_dist_map *const gic_dist;
168extern volatile struct gic_rdist_map *gic_rdist_map[CONFIG_MAX_NUM_NODES];
169extern volatile struct gic_rdist_sgi_ppi_map *gic_rdist_sgi_ppi_map[CONFIG_MAX_NUM_NODES];
170
171/* Helpers */
172static inline int is_irq_edge_triggered(word_t irq)
173{
174    uint32_t icfgr = 0;
175    int word = irq >> 4;
176    int bit = ((irq & 0xf) * 2);
177
178    if (HW_IRQ_IS_SGI(irq)) {
179        return 0;
180    }
181    if (HW_IRQ_IS_PPI(irq)) {
182        icfgr = gic_rdist_sgi_ppi_map[CURRENT_CPU_INDEX()]->icfgr1;
183    } else {
184        icfgr = gic_dist->icfgrn[word];
185    }
186
187    return !!(icfgr & BIT(bit + 1));
188}
189
190static inline void gic_pending_clr(word_t irq)
191{
192    int word = IRQ_REG(irq);
193    int bit = IRQ_BIT(irq);
194    /* Using |= here is detrimental to your health */
195    /* Applicable for SPI and PPIs */
196    if (irq < SPI_START) {
197        gic_rdist_sgi_ppi_map[CURRENT_CPU_INDEX()]->icpendr0 = BIT(bit);
198    } else {
199        gic_dist->icpendrn[word] = BIT(bit);
200    }
201}
202
203static inline void gic_enable_clr(word_t irq)
204{
205    int word = IRQ_REG(irq);
206    int bit = IRQ_BIT(irq);
207    /* Using |= here is detrimental to your health */
208    if (irq < SPI_START) {
209        gic_rdist_sgi_ppi_map[CURRENT_CPU_INDEX()]->icenabler0 = BIT(bit);
210    } else {
211        gic_dist->icenablern[word] = BIT(bit);
212    }
213
214}
215
216static inline void gic_enable_set(word_t irq)
217{
218    int word = IRQ_REG(irq);
219    int bit = IRQ_BIT(irq);
220
221    if (irq < SPI_START) {
222        gic_rdist_sgi_ppi_map[CURRENT_CPU_INDEX()]->isenabler0 = BIT(bit);
223    } else {
224        gic_dist->isenablern[word] = BIT(bit);
225    }
226
227}
228
229static inline irq_t getActiveIRQ(void)
230{
231    irq_t irq;
232
233    if (!IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])) {
234        uint32_t val = 0;
235        SYSTEM_READ_WORD(ICC_IAR1_EL1, val);
236        active_irq[CURRENT_CPU_INDEX()] = val;
237    }
238
239    if (IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])) {
240        irq = CORE_IRQ_TO_IRQT(CURRENT_CPU_INDEX(), active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK);
241    } else {
242        irq = irqInvalid;
243    }
244
245    return irq;
246}
247
248/*
249 * GIC has 4 states:
250 * seL4 expects two states: active->inactive.
251 * We ignore the active state in GIC to conform
252 */
253/** MODIFIES: phantom_machine_state */
254/** DONT_TRANSLATE */
255static inline bool_t isIRQPending(void)
256{
257    uint32_t val = 0;
258    /* Check for pending IRQs in group 1: ICC_HPPIR1_EL1 */
259    SYSTEM_READ_WORD(ICC_HPPIR1_EL1, val);
260    return IS_IRQ_VALID(val);
261}
262
263static inline void maskInterrupt(bool_t disable, irq_t irq)
264{
265#if defined ENABLE_SMP_SUPPORT
266    assert(!(IRQ_IS_PPI(irq)) || (IRQT_TO_CORE(irq) == getCurrentCPUIndex()));
267#endif
268
269    if (disable) {
270        gic_enable_clr(IRQT_TO_IRQ(irq));
271    } else {
272        gic_enable_set(IRQT_TO_IRQ(irq));
273    }
274}
275
276static inline void ackInterrupt(irq_t irq)
277{
278    word_t hw_irq = IRQT_TO_IRQ(irq);
279    assert(IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()]) && (active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK) == hw_irq);
280
281    if (is_irq_edge_triggered(hw_irq)) {
282        gic_pending_clr(hw_irq);
283    }
284
285    /* Set End of Interrupt for active IRQ: ICC_EOIR1_EL1 */
286    SYSTEM_WRITE_WORD(ICC_EOIR1_EL1, active_irq[CURRENT_CPU_INDEX()]);
287    active_irq[CURRENT_CPU_INDEX()] = IRQ_NONE;
288
289}
290
291