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