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