1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7/*
8 * ARM Generic Interrupt Controller PL-390
9 */
10#pragma once
11
12/* tell the kernel we have the set trigger feature */
13#define HAVE_SET_TRIGGER 1
14
15#include <stdint.h>
16#include <util.h>
17#include <linker.h>
18#include <mode/smp/smp.h>
19#include <model/statedata.h>
20
21#include "gic_common.h"
22
23#define IRQ_MASK MASK(10u)
24
25/* Helpers for VGIC */
26#define VGIC_HCR_EOI_INVALID_COUNT(hcr) (((hcr) >> 27) & 0x1f)
27#define VGIC_HCR_VGRP1DIE               (1U << 7)
28#define VGIC_HCR_VGRP1EIE               (1U << 6)
29#define VGIC_HCR_VGRP0DIE               (1U << 5)
30#define VGIC_HCR_VGRP0EIE               (1U << 4)
31#define VGIC_HCR_NPIE                   (1U << 3)
32#define VGIC_HCR_LRENPIE                (1U << 2)
33#define VGIC_HCR_UIE                    (1U << 1)
34#define VGIC_HCR_EN                     (1U << 0)
35#define VGIC_MISR_VGRP1D                VGIC_HCR_VGRP1DIE
36#define VGIC_MISR_VGRP1E                VGIC_HCR_VGRP1EIE
37#define VGIC_MISR_VGRP0D                VGIC_HCR_VGRP0DIE
38#define VGIC_MISR_VGRP0E                VGIC_HCR_VGRP0EIE
39#define VGIC_MISR_NP                    VGIC_HCR_NPIE
40#define VGIC_MISR_LRENP                 VGIC_HCR_LRENPIE
41#define VGIC_MISR_U                     VGIC_HCR_UIE
42#define VGIC_MISR_EOI                   VGIC_HCR_EN
43#define VGIC_VTR_NLISTREGS(vtr)         ((((vtr) >>  0) & 0x3f) + 1)
44#define VGIC_VTR_NPRIOBITS(vtr)         ((((vtr) >> 29) & 0x07) + 1)
45#define VGIC_VTR_NPREBITS(vtr)          ((((vtr) >> 26) & 0x07) + 1)
46
47/* Memory map for GIC distributor */
48struct gic_dist_map {
49    uint32_t enable;                /* 0x000 */
50    uint32_t ic_type;               /* 0x004 */
51    uint32_t dist_ident;            /* 0x008 */
52    uint32_t res1[29];              /* [0x00C, 0x080) */
53
54    uint32_t security[32];          /* [0x080, 0x100) */
55
56    uint32_t enable_set[32];        /* [0x100, 0x180) */
57    uint32_t enable_clr[32];        /* [0x180, 0x200) */
58    uint32_t pending_set[32];       /* [0x200, 0x280) */
59    uint32_t pending_clr[32];       /* [0x280, 0x300) */
60    uint32_t active[32];            /* [0x300, 0x380) */
61    uint32_t res2[32];              /* [0x380, 0x400) */
62
63    uint32_t priority[255];         /* [0x400, 0x7FC) */
64    uint32_t res3;                  /* 0x7FC */
65
66    uint32_t targets[255];            /* [0x800, 0xBFC) */
67    uint32_t res4;                  /* 0xBFC */
68
69    uint32_t config[64];             /* [0xC00, 0xD00) */
70
71    uint32_t spi[32];               /* [0xD00, 0xD80) */
72    uint32_t res5[20];              /* [0xD80, 0xDD0) */
73    uint32_t res6;                  /* 0xDD0 */
74    uint32_t legacy_int;            /* 0xDD4 */
75    uint32_t res7[2];               /* [0xDD8, 0xDE0) */
76    uint32_t match_d;               /* 0xDE0 */
77    uint32_t enable_d;              /* 0xDE4 */
78    uint32_t res8[70];               /* [0xDE8, 0xF00) */
79
80    uint32_t sgi_control;           /* 0xF00 */
81    uint32_t res9[3];               /* [0xF04, 0xF10) */
82    uint32_t sgi_pending_clr[4];    /* [0xF10, 0xF20) */
83    uint32_t res10[40];             /* [0xF20, 0xFC0) */
84
85    uint32_t periph_id[12];         /* [0xFC0, 0xFF0) */
86    uint32_t component_id[4];       /* [0xFF0, 0xFFF] */
87};
88
89/* Memory map for GIC  cpu interface */
90struct gic_cpu_iface_map {
91    uint32_t icontrol;              /*  0x000         */
92    uint32_t pri_msk_c;             /*  0x004         */
93    uint32_t pb_c;                  /*  0x008         */
94    uint32_t int_ack;               /*  0x00C         */
95    uint32_t eoi;                   /*  0x010         */
96    uint32_t run_priority;          /*  0x014         */
97    uint32_t hi_pend;               /*  0x018         */
98    uint32_t ns_alias_bp_c;         /*  0x01C         */
99    uint32_t ns_alias_ack;          /*  0x020 GIC400 only */
100    uint32_t ns_alias_eoi;          /*  0x024 GIC400 only */
101    uint32_t ns_alias_hi_pend;      /*  0x028 GIC400 only */
102
103    uint32_t res1[5];               /* [0x02C, 0x040) */
104
105    uint32_t integ_en_c;            /*  0x040 PL390 only */
106    uint32_t interrupt_out;         /*  0x044 PL390 only */
107    uint32_t res2[2];               /* [0x048, 0x050)    */
108
109    uint32_t match_c;               /*  0x050 PL390 only */
110    uint32_t enable_c;              /*  0x054 PL390 only */
111
112    uint32_t res3[30];              /* [0x058, 0x0FC)  */
113    uint32_t active_priority[4];    /* [0x0D0, 0xDC] GIC400 only */
114    uint32_t ns_active_priority[4]; /* [0xE0,0xEC] GIC400 only */
115    uint32_t res4[3];
116
117    uint32_t cpu_if_ident;          /*  0x0FC         */
118    uint32_t res5[948];             /* [0x100. 0xFC0) */
119
120    uint32_t periph_id[8];          /* [0xFC0, 9xFF0) PL390 only */
121    uint32_t component_id[4];       /* [0xFF0, 0xFFF] PL390 only */
122};
123
124extern volatile struct gic_dist_map *const gic_dist;
125extern volatile struct gic_cpu_iface_map *const gic_cpuiface;
126
127/* Helpers */
128static inline int is_irq_edge_triggered(word_t irq)
129{
130    int word = irq >> 4;
131    int bit = ((irq & 0xf) * 2);
132    return !!(gic_dist->config[word] & BIT(bit + 1));
133}
134
135static inline void dist_pending_clr(word_t irq)
136{
137    int word = IRQ_REG(irq);
138    int bit = IRQ_BIT(irq);
139    /* Using |= here is detrimental to your health */
140    gic_dist->pending_clr[word] = BIT(bit);
141}
142
143static inline void dist_enable_clr(word_t irq)
144{
145    int word = IRQ_REG(irq);
146    int bit = IRQ_BIT(irq);
147    /* Using |= here is detrimental to your health */
148    gic_dist->enable_clr[word] = BIT(bit);
149}
150
151static inline void dist_enable_set(word_t irq)
152{
153    int word = IRQ_REG(irq);
154    int bit = IRQ_BIT(irq);
155    gic_dist->enable_set[word] = BIT(bit);
156}
157
158static inline irq_t getActiveIRQ(void)
159{
160    irq_t irq;
161    if (!IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])) {
162        active_irq[CURRENT_CPU_INDEX()] = gic_cpuiface->int_ack;
163    }
164
165    if (IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])) {
166        irq = CORE_IRQ_TO_IRQT(CURRENT_CPU_INDEX(), active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK);
167    } else {
168        irq = irqInvalid;
169    }
170
171    return irq;
172}
173
174/*
175 * GIC has 4 states: pending->active(+pending)->inactive
176 * seL4 expects two states: active->inactive.
177 * We ignore the active state in GIC to conform
178 */
179static inline bool_t isIRQPending(void)
180{
181    return IS_IRQ_VALID(gic_cpuiface->hi_pend);
182}
183
184static inline void maskInterrupt(bool_t disable, irq_t irq)
185{
186#if defined ENABLE_SMP_SUPPORT && defined CONFIG_ARCH_ARM
187    assert(!(IRQ_IS_PPI(irq)) || (IRQT_TO_CORE(irq) == getCurrentCPUIndex()));
188#endif
189    if (disable) {
190        dist_enable_clr(IRQT_TO_IRQ(irq));
191    } else {
192        dist_enable_set(IRQT_TO_IRQ(irq));
193    }
194}
195
196static inline void ackInterrupt(irq_t irq)
197{
198    assert(IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])
199           && (active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK) == IRQT_TO_IRQ(irq));
200    if (is_irq_edge_triggered(IRQT_TO_IRQ(irq))) {
201        dist_pending_clr(IRQT_TO_IRQ(irq));
202    }
203    gic_cpuiface->eoi = active_irq[CURRENT_CPU_INDEX()];
204    active_irq[CURRENT_CPU_INDEX()] = IRQ_NONE;
205
206}
207
208
209#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
210
211/* GIC VCPU Control Interface */
212struct gich_vcpu_ctrl_map {
213    uint32_t hcr;    /* 0x000 RW 0x00000000 Hypervisor Control Register */
214    uint32_t vtr;    /* 0x004 RO IMPLEMENTATION DEFINED VGIC Type Register */
215    /* Save restore on VCPU switch */
216    uint32_t vmcr;   /* 0x008 RW IMPLEMENTATION DEFINED Virtual Machine Control Register */
217    uint32_t res1[1];
218    /* IRQ pending flags */
219    uint32_t misr;   /* 0x010 RO 0x00000000 Maintenance Interrupt Status Register */
220    uint32_t res2[3];
221    /* Bitfield of list registers that have EOI */
222    uint32_t eisr0;  /* 0x020 RO 0x00000000 End of Interrupt Status Registers 0 and 1, see EISRn */
223    uint32_t eisr1;  /* 0x024 RO 0x00000000 */
224    uint32_t res3[2];
225    /* Bitfield of list registers that are empty */
226    uint32_t elsr0;  /* 0x030 RO IMPLEMENTATION DEFINED a */
227    uint32_t elsr1;  /* 0x034 RO IMPLEMENTATION DEFINED a Empty List Register Status Registers 0 and 1, see ELRSRn */
228    uint32_t res4[46];
229    /* Active priority: bitfield of active priorities */
230    uint32_t apr;    /* 0x0F0 RW 0x00000000 Active Priorities Register */
231    uint32_t res5[3];
232    uint32_t lr[64]; /* 0x100 RW 0x00000000 List Registers 0-63, see LRn */
233};
234
235extern volatile struct gich_vcpu_ctrl_map *gic_vcpu_ctrl;
236extern unsigned int gic_vcpu_num_list_regs;
237
238static inline uint32_t get_gic_vcpu_ctrl_hcr(void)
239{
240    return gic_vcpu_ctrl->hcr;
241}
242
243static inline void set_gic_vcpu_ctrl_hcr(uint32_t hcr)
244{
245    gic_vcpu_ctrl->hcr = hcr;
246}
247
248static inline uint32_t get_gic_vcpu_ctrl_vmcr(void)
249{
250    return gic_vcpu_ctrl->vmcr;
251}
252
253static inline void set_gic_vcpu_ctrl_vmcr(uint32_t vmcr)
254{
255    gic_vcpu_ctrl->vmcr = vmcr;
256}
257
258static inline uint32_t get_gic_vcpu_ctrl_apr(void)
259{
260    return gic_vcpu_ctrl->apr;
261}
262
263static inline void set_gic_vcpu_ctrl_apr(uint32_t apr)
264{
265    gic_vcpu_ctrl->apr = apr;
266}
267
268static inline uint32_t get_gic_vcpu_ctrl_vtr(void)
269{
270    return gic_vcpu_ctrl->vtr;
271}
272
273static inline uint32_t get_gic_vcpu_ctrl_eisr0(void)
274{
275    return gic_vcpu_ctrl->eisr0;
276}
277
278static inline uint32_t get_gic_vcpu_ctrl_eisr1(void)
279{
280    return gic_vcpu_ctrl->eisr1;
281}
282
283static inline uint32_t get_gic_vcpu_ctrl_misr(void)
284{
285    return gic_vcpu_ctrl->misr;
286}
287
288static inline virq_t get_gic_vcpu_ctrl_lr(int num)
289{
290    virq_t virq;
291    virq.words[0] = gic_vcpu_ctrl->lr[num];
292    return virq;
293}
294
295static inline void set_gic_vcpu_ctrl_lr(int num, virq_t lr)
296{
297    gic_vcpu_ctrl->lr[num] = lr.words[0];
298}
299
300#endif /* End of CONFIG_ARM_HYPERVISOR_SUPPORT */
301