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