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