11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2b0104773SPascal Brand /* 305089e5fSJens Wiklander * Copyright (c) 2016-2017, 2023 Linaro Limited 4b0104773SPascal Brand * Copyright (c) 2014, STMicroelectronics International N.V. 5b0104773SPascal Brand */ 6b0104773SPascal Brand 718901324SDavid Wang #include <arm.h> 88ddf5a4eSEtienne Carriere #include <assert.h> 98c7282beSEtienne Carriere #include <dt-bindings/interrupt-controller/arm-gic.h> 1067e55c51SEtienne Carriere #include <compiler.h> 1105089e5fSJens Wiklander #include <config.h> 12b0104773SPascal Brand #include <drivers/gic.h> 1305089e5fSJens Wiklander #include <io.h> 140f93de74SEtienne Carriere #include <keep.h> 1567729d8dSLudovic Barre #include <kernel/dt.h> 1614885eb1SEtienne Carriere #include <kernel/dt_driver.h> 177315b7b4SJens Wiklander #include <kernel/interrupt.h> 1805089e5fSJens Wiklander #include <kernel/misc.h> 19d13278b8SEtienne Carriere #include <kernel/panic.h> 2005089e5fSJens Wiklander #include <libfdt.h> 2160801696SVolodymyr Babchuk #include <mm/core_memprot.h> 2260801696SVolodymyr Babchuk #include <mm/core_mmu.h> 234de4bebcSJens Wiklander #include <trace.h> 2405089e5fSJens Wiklander #include <util.h> 25b0104773SPascal Brand 26b0104773SPascal Brand /* Offsets from gic.gicc_base */ 27b0104773SPascal Brand #define GICC_CTLR (0x000) 2830a673e3SPeter Maydell #define GICC_PMR (0x004) 29b0104773SPascal Brand #define GICC_IAR (0x00C) 30b0104773SPascal Brand #define GICC_EOIR (0x010) 31b0104773SPascal Brand 32b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0) 33b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1) 34b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3) 35b0104773SPascal Brand 36b0104773SPascal Brand /* Offsets from gic.gicd_base */ 37b0104773SPascal Brand #define GICD_CTLR (0x000) 38b0104773SPascal Brand #define GICD_TYPER (0x004) 39b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4) 40b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4) 41b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4) 4226ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4) 43b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4) 44b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) 45b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4) 461fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 4726ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 48b0104773SPascal Brand 4969171becSJens Wiklander #ifdef CFG_ARM_GICV3 5069171becSJens Wiklander #define GICD_PIDR2 (0xFFE8) 5169171becSJens Wiklander #else 5269171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */ 5369171becSJens Wiklander #define GICD_PIDR2 (0xFE8) 5469171becSJens Wiklander #endif 5569171becSJens Wiklander 5605089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0 BIT32(0) 5705089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS BIT32(1) 5805089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S BIT32(2) 5905089e5fSJens Wiklander #define GICD_CTLR_ARE_S BIT32(4) 6005089e5fSJens Wiklander #define GICD_CTLR_ARE_NS BIT32(5) 6105089e5fSJens Wiklander 6205089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */ 6305089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE (2 * 64 * 1024) 6405089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET (64 * 1024) 6505089e5fSJens Wiklander #define GICR_CTLR (0x00) 6605089e5fSJens Wiklander #define GICR_TYPER (0x08) 6705089e5fSJens Wiklander 6805089e5fSJens Wiklander #define GICR_IGROUPR0 (GICR_SGI_BASE_OFFSET + 0x080) 6905089e5fSJens Wiklander #define GICR_IGRPMODR0 (GICR_SGI_BASE_OFFSET + 0xD00) 70*84603456SJens Wiklander #define GICR_ICENABLER0 (GICR_SGI_BASE_OFFSET + 0x180) 71*84603456SJens Wiklander #define GICR_ICPENDR0 (GICR_SGI_BASE_OFFSET + 0x280) 7205089e5fSJens Wiklander 7305089e5fSJens Wiklander #define GICR_TYPER_LAST BIT64(4) 7405089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT 56 7505089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT 48 7605089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT 40 7705089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT 32 78b0104773SPascal Brand 7969171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */ 8069171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT 4 8169171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK 0xF 8269171becSJens Wiklander 8353bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 8453bd332aSSY Chiu #define NUM_PPI 32 8553bd332aSSY Chiu 8626ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 8726ed70ecSGuanchao Liang #define NUM_SGI 16 8826ed70ecSGuanchao Liang 8926ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 9026ed70ecSGuanchao Liang #define NUM_NS_SGI 8 9126ed70ecSGuanchao Liang 9253bd332aSSY Chiu /* Number of interrupts in one register */ 9353bd332aSSY Chiu #define NUM_INTS_PER_REG 32 9453bd332aSSY Chiu 9553bd332aSSY Chiu /* Number of targets in one register */ 9653bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 9753bd332aSSY Chiu 9853bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 9953bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 10053bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 10153bd332aSSY Chiu 1021b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f 1037315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 1047315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 1057315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 106b0104773SPascal Brand 107ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40 108ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16 109ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32 110ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48 111ec740b9fSJens Wiklander 112ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf 113ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1 114ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2 115ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24 116ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15 117ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16 118ec740b9fSJens Wiklander 11967e55c51SEtienne Carriere struct gic_data { 12067e55c51SEtienne Carriere vaddr_t gicc_base; 12167e55c51SEtienne Carriere vaddr_t gicd_base; 12205089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 12305089e5fSJens Wiklander vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE]; 12405089e5fSJens Wiklander #endif 12567e55c51SEtienne Carriere size_t max_it; 12605089e5fSJens Wiklander uint32_t per_cpu_group_status; 12705089e5fSJens Wiklander uint32_t per_cpu_group_modifier; 12867e55c51SEtienne Carriere struct itr_chip chip; 12967e55c51SEtienne Carriere }; 13067e55c51SEtienne Carriere 13167e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss; 13267e55c51SEtienne Carriere 133702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type, 134702fe5a7SClément Léger uint32_t prio); 1357315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 1367315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 13726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 13826ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 139ec740b9fSJens Wiklander uint32_t cpu_mask); 14026ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 14126ed70ecSGuanchao Liang uint8_t cpu_mask); 1427315b7b4SJens Wiklander 1437315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 1447315b7b4SJens Wiklander .add = gic_op_add, 14508ded0e1SEtienne Carriere .mask = gic_op_disable, 14608ded0e1SEtienne Carriere .unmask = gic_op_enable, 1477315b7b4SJens Wiklander .enable = gic_op_enable, 1487315b7b4SJens Wiklander .disable = gic_op_disable, 14926ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 15026ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 15126ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 1527315b7b4SJens Wiklander }; 1533639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 1547315b7b4SJens Wiklander 15505089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused) 15605089e5fSJens Wiklander { 15705089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 15805089e5fSJens Wiklander return gd->gicr_base[get_core_pos()]; 15905089e5fSJens Wiklander #else 16005089e5fSJens Wiklander return 0; 16105089e5fSJens Wiklander #endif 16205089e5fSJens Wiklander } 16305089e5fSJens Wiklander 16418901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 165b0104773SPascal Brand { 166b0104773SPascal Brand int i; 167b0104773SPascal Brand uint32_t old_ctlr; 168b0104773SPascal Brand size_t ret = 0; 1691b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) & 1701b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK; 171b0104773SPascal Brand 172b0104773SPascal Brand /* 173b0104773SPascal Brand * Probe which interrupt number is the largest. 174b0104773SPascal Brand */ 17518901324SDavid Wang #if defined(CFG_ARM_GICV3) 17618901324SDavid Wang old_ctlr = read_icc_ctlr(); 17718901324SDavid Wang write_icc_ctlr(0); 17818901324SDavid Wang #else 179918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 180918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 18118901324SDavid Wang #endif 18279f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 183b0104773SPascal Brand uint32_t old_reg; 184b0104773SPascal Brand uint32_t reg; 185b0104773SPascal Brand int b; 186b0104773SPascal Brand 187918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 188918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 189918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 190918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 19179f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 192007a97a2SJens Wiklander if (BIT32(b) & reg) { 19353bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 194b0104773SPascal Brand goto out; 195b0104773SPascal Brand } 196b0104773SPascal Brand } 197b0104773SPascal Brand } 198b0104773SPascal Brand out: 19918901324SDavid Wang #if defined(CFG_ARM_GICV3) 20018901324SDavid Wang write_icc_ctlr(old_ctlr); 20118901324SDavid Wang #else 202918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 20318901324SDavid Wang #endif 204b0104773SPascal Brand return ret; 205b0104773SPascal Brand } 206b0104773SPascal Brand 207*84603456SJens Wiklander static void gicv3_sync_sgi_config(struct gic_data *gd) 208*84603456SJens Wiklander { 209*84603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 210*84603456SJens Wiklander bool need_sync = false; 211*84603456SJens Wiklander uint32_t gmod0 = 0; 212*84603456SJens Wiklander uint32_t grp0 = 0; 213*84603456SJens Wiklander size_t n = 0; 214*84603456SJens Wiklander 215*84603456SJens Wiklander if (!gicr_base) 216*84603456SJens Wiklander panic("GICR_BASE missing for affinity routing"); 217*84603456SJens Wiklander 218*84603456SJens Wiklander grp0 = io_read32(gicr_base + GICR_IGROUPR0); 219*84603456SJens Wiklander gmod0 = io_read32(gicr_base + GICR_IGRPMODR0); 220*84603456SJens Wiklander for (n = GIC_SGI_SEC_BASE; n <= GIC_SGI_SEC_MAX; n++) { 221*84603456SJens Wiklander /* Ignore matching bits */ 222*84603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) && 223*84603456SJens Wiklander !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier))) 224*84603456SJens Wiklander continue; 225*84603456SJens Wiklander /* 226*84603456SJens Wiklander * SGI-n differs from primary CPU configuration, 227*84603456SJens Wiklander * let's sync up. 228*84603456SJens Wiklander */ 229*84603456SJens Wiklander need_sync = true; 230*84603456SJens Wiklander 231*84603456SJens Wiklander /* Disable interrupt */ 232*84603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(n)); 233*84603456SJens Wiklander 234*84603456SJens Wiklander /* Make interrupt non-pending */ 235*84603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(n)); 236*84603456SJens Wiklander 237*84603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status) 238*84603456SJens Wiklander grp0 |= BIT32(n); 239*84603456SJens Wiklander else 240*84603456SJens Wiklander grp0 &= ~BIT32(n); 241*84603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_modifier) 242*84603456SJens Wiklander gmod0 |= BIT32(n); 243*84603456SJens Wiklander else 244*84603456SJens Wiklander gmod0 &= ~BIT32(n); 245*84603456SJens Wiklander } 246*84603456SJens Wiklander 247*84603456SJens Wiklander if (need_sync) { 248*84603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, grp0); 249*84603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, gmod0); 250*84603456SJens Wiklander } 251*84603456SJens Wiklander } 252*84603456SJens Wiklander 253*84603456SJens Wiklander static void gic_legacy_sync_sgi_config(struct gic_data *gd) 254*84603456SJens Wiklander { 255*84603456SJens Wiklander bool need_sync = false; 256*84603456SJens Wiklander uint32_t grp0 = 0; 257*84603456SJens Wiklander size_t n = 0; 258*84603456SJens Wiklander 259*84603456SJens Wiklander grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0)); 260*84603456SJens Wiklander for (n = GIC_SGI_SEC_BASE; n <= GIC_SGI_SEC_MAX; n++) { 261*84603456SJens Wiklander /* Ignore matching bits */ 262*84603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status))) 263*84603456SJens Wiklander continue; 264*84603456SJens Wiklander /* 265*84603456SJens Wiklander * SGI-n differs from primary CPU configuration, 266*84603456SJens Wiklander * let's sync up. 267*84603456SJens Wiklander */ 268*84603456SJens Wiklander need_sync = true; 269*84603456SJens Wiklander 270*84603456SJens Wiklander /* Disable interrupt */ 271*84603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n)); 272*84603456SJens Wiklander 273*84603456SJens Wiklander /* Make interrupt non-pending */ 274*84603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n)); 275*84603456SJens Wiklander 276*84603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status) 277*84603456SJens Wiklander grp0 |= BIT32(n); 278*84603456SJens Wiklander else 279*84603456SJens Wiklander grp0 &= ~BIT32(n); 280*84603456SJens Wiklander } 281*84603456SJens Wiklander 282*84603456SJens Wiklander if (need_sync) 283*84603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0); 284*84603456SJens Wiklander } 285*84603456SJens Wiklander 2865da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd) 287bedc2b9fSsunny { 28805089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status); 289bedc2b9fSsunny 29005089e5fSJens Wiklander /* 29105089e5fSJens Wiklander * Set the priority mask to permit Non-secure interrupts, and to 29230a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 29330a673e3SPeter Maydell */ 29418901324SDavid Wang #if defined(CFG_ARM_GICV3) 29518901324SDavid Wang write_icc_pmr(0x80); 2961fcac774SSandeep Tripathy write_icc_igrpen1(1); 29718901324SDavid Wang #else 298918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 29930a673e3SPeter Maydell 300bedc2b9fSsunny /* Enable GIC */ 301918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 302918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 303918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 30418901324SDavid Wang #endif 305bedc2b9fSsunny } 306bedc2b9fSsunny 3075da157f5SJens Wiklander void gic_init_per_cpu(void) 3085da157f5SJens Wiklander { 3095da157f5SJens Wiklander struct gic_data *gd = &gic_data; 3105da157f5SJens Wiklander 3115da157f5SJens Wiklander #if defined(CFG_ARM_GICV3) 3125da157f5SJens Wiklander assert(gd->gicd_base); 3135da157f5SJens Wiklander #else 3145da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base); 3155da157f5SJens Wiklander #endif 3165da157f5SJens Wiklander 317*84603456SJens Wiklander if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) { 318*84603456SJens Wiklander /* 319*84603456SJens Wiklander * GIC is already initialized by TF-A, we only need to 320*84603456SJens Wiklander * handle eventual SGI configuration changes. 321*84603456SJens Wiklander */ 322*84603456SJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3) && 323*84603456SJens Wiklander io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S) 324*84603456SJens Wiklander gicv3_sync_sgi_config(gd); 325*84603456SJens Wiklander else 326*84603456SJens Wiklander gic_legacy_sync_sgi_config(gd); 327*84603456SJens Wiklander } else { 328*84603456SJens Wiklander /* 329*84603456SJens Wiklander * Non-TF-A case where all CPU specific configuration 330*84603456SJens Wiklander * of GIC must be done here. 331*84603456SJens Wiklander */ 3325da157f5SJens Wiklander init_gic_per_cpu(gd); 3335da157f5SJens Wiklander } 334*84603456SJens Wiklander } 3355da157f5SJens Wiklander 3365da157f5SJens Wiklander void gic_cpu_init(void) 3375da157f5SJens Wiklander { 3385da157f5SJens Wiklander struct gic_data *gd = &gic_data; 3395da157f5SJens Wiklander 3405da157f5SJens Wiklander #if defined(CFG_ARM_GICV3) 3415da157f5SJens Wiklander assert(gd->gicd_base); 3425da157f5SJens Wiklander #else 3435da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base); 3445da157f5SJens Wiklander #endif 3455da157f5SJens Wiklander IMSG("%s is deprecated, please use gic_init_per_cpu()", __func__); 3465da157f5SJens Wiklander 3475da157f5SJens Wiklander init_gic_per_cpu(gd); 3485da157f5SJens Wiklander } 3495da157f5SJens Wiklander 350*84603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it) 351*84603456SJens Wiklander { 352*84603456SJens Wiklander struct gic_data *gd = &gic_data; 353*84603456SJens Wiklander 354*84603456SJens Wiklander assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX); 355*84603456SJens Wiklander 356*84603456SJens Wiklander /* Assert it's secure to start with. */ 357*84603456SJens Wiklander assert(!(gd->per_cpu_group_status & BIT32(it)) && 358*84603456SJens Wiklander (gd->per_cpu_group_modifier & BIT32(it))); 359*84603456SJens Wiklander 360*84603456SJens Wiklander gd->per_cpu_group_modifier &= ~BIT32(it); 361*84603456SJens Wiklander gd->per_cpu_group_status |= BIT32(it); 362*84603456SJens Wiklander 363*84603456SJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3) && 364*84603456SJens Wiklander (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S)) { 365*84603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 366*84603456SJens Wiklander 367*84603456SJens Wiklander /* Disable interrupt */ 368*84603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it)); 369*84603456SJens Wiklander 370*84603456SJens Wiklander /* Make interrupt non-pending */ 371*84603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it)); 372*84603456SJens Wiklander 373*84603456SJens Wiklander /* Make it to non-secure */ 374*84603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status); 375*84603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, 376*84603456SJens Wiklander gd->per_cpu_group_modifier); 377*84603456SJens Wiklander } else { 378*84603456SJens Wiklander /* Disable interrupt */ 379*84603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it)); 380*84603456SJens Wiklander 381*84603456SJens Wiklander /* Make interrupt non-pending */ 382*84603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it)); 383*84603456SJens Wiklander 384*84603456SJens Wiklander /* Make it to non-secure */ 385*84603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), 386*84603456SJens Wiklander gd->per_cpu_group_status); 387*84603456SJens Wiklander } 388*84603456SJens Wiklander } 389*84603456SJens Wiklander 3900ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 3910ee3f52eSEtienne Carriere uint32_t *prio) 3920ee3f52eSEtienne Carriere { 3930ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT; 3940ee3f52eSEtienne Carriere 3950ee3f52eSEtienne Carriere if (type) 3960ee3f52eSEtienne Carriere *type = IRQ_TYPE_NONE; 3970ee3f52eSEtienne Carriere 3980ee3f52eSEtienne Carriere if (prio) 3990ee3f52eSEtienne Carriere *prio = 0; 4000ee3f52eSEtienne Carriere 4010ee3f52eSEtienne Carriere if (!properties || count < 2) 4020ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 4030ee3f52eSEtienne Carriere 4040ee3f52eSEtienne Carriere it_num = fdt32_to_cpu(properties[1]); 4050ee3f52eSEtienne Carriere 4060ee3f52eSEtienne Carriere switch (fdt32_to_cpu(properties[0])) { 4078c7282beSEtienne Carriere case GIC_PPI: 4080ee3f52eSEtienne Carriere it_num += 16; 4090ee3f52eSEtienne Carriere break; 4108c7282beSEtienne Carriere case GIC_SPI: 4110ee3f52eSEtienne Carriere it_num += 32; 4120ee3f52eSEtienne Carriere break; 4130ee3f52eSEtienne Carriere default: 4140ee3f52eSEtienne Carriere it_num = DT_INFO_INVALID_INTERRUPT; 4150ee3f52eSEtienne Carriere } 4160ee3f52eSEtienne Carriere 4170ee3f52eSEtienne Carriere return it_num; 4180ee3f52eSEtienne Carriere } 4190ee3f52eSEtienne Carriere 42005089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs, 42105089e5fSJens Wiklander paddr_t gicr_base_pa) 42205089e5fSJens Wiklander { 42305089e5fSJens Wiklander size_t sz = GICR_V3_PCPUBASE_SIZE; 42405089e5fSJens Wiklander paddr_t pa = gicr_base_pa; 42505089e5fSJens Wiklander size_t core_pos = 0; 42605089e5fSJens Wiklander uint64_t mt_bit = 0; 42705089e5fSJens Wiklander uint64_t mpidr = 0; 42805089e5fSJens Wiklander uint64_t tv = 0; 42905089e5fSJens Wiklander vaddr_t va = 0; 43005089e5fSJens Wiklander 43105089e5fSJens Wiklander #ifdef ARM64 43205089e5fSJens Wiklander mt_bit = read_mpidr_el1() & MPIDR_MT_MASK; 43305089e5fSJens Wiklander #endif 43405089e5fSJens Wiklander do { 43505089e5fSJens Wiklander va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz); 43605089e5fSJens Wiklander if (!va) 43705089e5fSJens Wiklander panic(); 43805089e5fSJens Wiklander tv = io_read64(va + GICR_TYPER); 43905089e5fSJens Wiklander 44005089e5fSJens Wiklander /* 44105089e5fSJens Wiklander * Extract an mpidr from the Type register to calculate the 44205089e5fSJens Wiklander * core position of this redistributer instance. 44305089e5fSJens Wiklander */ 44405089e5fSJens Wiklander mpidr = mt_bit; 44505089e5fSJens Wiklander mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) & 44605089e5fSJens Wiklander MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT); 44705089e5fSJens Wiklander mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) & 44805089e5fSJens Wiklander (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK); 44905089e5fSJens Wiklander core_pos = get_core_pos_mpidr(mpidr); 45005089e5fSJens Wiklander if (core_pos < CFG_TEE_CORE_NB_CORE) { 45105089e5fSJens Wiklander DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va); 45205089e5fSJens Wiklander gicr_base_addrs[core_pos] = va; 45305089e5fSJens Wiklander } else { 45405089e5fSJens Wiklander EMSG("Skipping too large core_pos %zu from GICR_TYPER", 45505089e5fSJens Wiklander core_pos); 45605089e5fSJens Wiklander } 45705089e5fSJens Wiklander pa += sz; 45805089e5fSJens Wiklander } while (!(tv & GICR_TYPER_LAST)); 45905089e5fSJens Wiklander } 46005089e5fSJens Wiklander 46105089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 46205089e5fSJens Wiklander paddr_t gicr_base_pa __maybe_unused) 463b0104773SPascal Brand { 46467e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 4650ee3f52eSEtienne Carriere vaddr_t gicc_base = 0; 4660ee3f52eSEtienne Carriere vaddr_t gicd_base = 0; 46769171becSJens Wiklander uint32_t vers __maybe_unused = 0; 4680ee3f52eSEtienne Carriere 4690ee3f52eSEtienne Carriere assert(cpu_mmu_enabled()); 4700ee3f52eSEtienne Carriere 4710ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 4720ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE); 4730ee3f52eSEtienne Carriere if (!gicd_base) 4740ee3f52eSEtienne Carriere panic(); 4750ee3f52eSEtienne Carriere 47669171becSJens Wiklander vers = io_read32(gicd_base + GICD_PIDR2); 47769171becSJens Wiklander vers >>= GICD_PIDR2_ARCHREV_SHIFT; 47869171becSJens Wiklander vers &= GICD_PIDR2_ARCHREV_MASK; 47969171becSJens Wiklander 48069171becSJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3)) { 48169171becSJens Wiklander assert(vers == 3); 48269171becSJens Wiklander } else { 48369171becSJens Wiklander assert(vers == 2); 4840ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 4850ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE); 4860ee3f52eSEtienne Carriere if (!gicc_base) 4870ee3f52eSEtienne Carriere panic(); 4880ee3f52eSEtienne Carriere } 4890ee3f52eSEtienne Carriere 4900ee3f52eSEtienne Carriere gd->gicc_base = gicc_base; 4910ee3f52eSEtienne Carriere gd->gicd_base = gicd_base; 4920ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base); 49305089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 49405089e5fSJens Wiklander probe_redist_base_addrs(gd->gicr_base, gicr_base_pa); 49505089e5fSJens Wiklander #endif 4960ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops; 4970ee3f52eSEtienne Carriere 4980ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT)) 4990ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq; 5000ee3f52eSEtienne Carriere } 5010ee3f52eSEtienne Carriere 50205089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 50305089e5fSJens Wiklander paddr_t gicr_base_pa) 5040ee3f52eSEtienne Carriere { 5050ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data; 5060ee3f52eSEtienne Carriere size_t __maybe_unused n = 0; 507b0104773SPascal Brand 50805089e5fSJens Wiklander gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa); 509b0104773SPascal Brand 51005089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW) 5110ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */ 51205089e5fSJens Wiklander if (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S) { 51305089e5fSJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 51405089e5fSJens Wiklander 51505089e5fSJens Wiklander if (!gicr_base) 51605089e5fSJens Wiklander panic("GICR_BASE missing for affinity routing"); 51705089e5fSJens Wiklander /* Secure affinity routing enabled */ 51805089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gicr_base + GICR_IGROUPR0); 51905089e5fSJens Wiklander gd->per_cpu_group_modifier = io_read32(gicr_base + 52005089e5fSJens Wiklander GICR_IGRPMODR0); 52105089e5fSJens Wiklander } else { 52205089e5fSJens Wiklander /* Legacy operation with secure affinity routing disabled */ 52305089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gd->gicd_base + 52405089e5fSJens Wiklander GICD_IGROUPR(0)); 52505089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 52605089e5fSJens Wiklander } 52705089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/ 52805089e5fSJens Wiklander /* 52905089e5fSJens Wiklander * Without TF-A, GIC is always configured in for legacy operation 53005089e5fSJens Wiklander * with secure affinity routing disabled. 53105089e5fSJens Wiklander */ 5327315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 533b0104773SPascal Brand /* Disable interrupts */ 534918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 535b0104773SPascal Brand 536b0104773SPascal Brand /* Make interrupts non-pending */ 537918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 538b0104773SPascal Brand 539b0104773SPascal Brand /* Mark interrupts non-secure */ 540bedc2b9fSsunny if (n == 0) { 541bedc2b9fSsunny /* per-CPU inerrupts config: 542bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 543bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 544bedc2b9fSsunny * All PPI config as Non-secure interrupts. 545bedc2b9fSsunny */ 54605089e5fSJens Wiklander gd->per_cpu_group_status = 0xffff00ff; 54705089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 54805089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(n), 54905089e5fSJens Wiklander gd->per_cpu_group_status); 550bedc2b9fSsunny } else { 551918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 552b0104773SPascal Brand } 553bedc2b9fSsunny } 554b0104773SPascal Brand 55530a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 55630a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 55730a673e3SPeter Maydell */ 55818901324SDavid Wang #if defined(CFG_ARM_GICV3) 55918901324SDavid Wang write_icc_pmr(0x80); 5601fcac774SSandeep Tripathy write_icc_igrpen1(1); 5611fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 56218901324SDavid Wang #else 563918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 56430a673e3SPeter Maydell 565b0104773SPascal Brand /* Enable GIC */ 566918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 567918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 568918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 56905089e5fSJens Wiklander GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS); 5701fcac774SSandeep Tripathy #endif 57105089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/ 57267e55c51SEtienne Carriere 57301980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip); 574b0104773SPascal Brand } 575b0104773SPascal Brand 5767315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 577b0104773SPascal Brand { 57853bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 57953bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 580b0104773SPascal Brand 58167e55c51SEtienne Carriere assert(gd == &gic_data); 58267e55c51SEtienne Carriere 583b0104773SPascal Brand /* Disable the interrupt */ 584918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 585b0104773SPascal Brand /* Make it non-pending */ 586918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 587b0104773SPascal Brand /* Assign it to group0 */ 588918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 5891fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 5901fcac774SSandeep Tripathy /* Assign it to group1S */ 5911fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 5921fcac774SSandeep Tripathy #endif 593b0104773SPascal Brand } 594b0104773SPascal Brand 5957315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 5967315b7b4SJens Wiklander uint8_t cpu_mask) 597b0104773SPascal Brand { 5988ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 5998ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 60053bd332aSSY Chiu uint32_t target, target_shift; 601918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 602918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 603b0104773SPascal Brand 60467e55c51SEtienne Carriere assert(gd == &gic_data); 60567e55c51SEtienne Carriere 606b0104773SPascal Brand /* Assigned to group0 */ 607918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 608b0104773SPascal Brand 609b0104773SPascal Brand /* Route it to selected CPUs */ 610918bb3a5SEtienne Carriere target = io_read32(itargetsr); 61153bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 61253bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 61353bd332aSSY Chiu target |= cpu_mask << target_shift; 614918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 615918bb3a5SEtienne Carriere io_write32(itargetsr, target); 616918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 617b0104773SPascal Brand } 618b0104773SPascal Brand 6197315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 620b0104773SPascal Brand { 6218ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 6228ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 623b0104773SPascal Brand 62467e55c51SEtienne Carriere assert(gd == &gic_data); 62567e55c51SEtienne Carriere 626b0104773SPascal Brand /* Assigned to group0 */ 627918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 628b0104773SPascal Brand 629b0104773SPascal Brand /* Set prio it to selected CPUs */ 6301f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 6317315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 632918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 633b0104773SPascal Brand } 634b0104773SPascal Brand 6357315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 636b0104773SPascal Brand { 63753bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 63853bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 639918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 640b0104773SPascal Brand 64167e55c51SEtienne Carriere assert(gd == &gic_data); 64267e55c51SEtienne Carriere 643b0104773SPascal Brand /* Assigned to group0 */ 644918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 645b0104773SPascal Brand 646b0104773SPascal Brand /* Enable the interrupt */ 647918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 648b0104773SPascal Brand } 649b0104773SPascal Brand 6507315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 651b0104773SPascal Brand { 65253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 65353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 654b0104773SPascal Brand 65567e55c51SEtienne Carriere assert(gd == &gic_data); 65667e55c51SEtienne Carriere 657b0104773SPascal Brand /* Assigned to group0 */ 658918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 659b0104773SPascal Brand 660b0104773SPascal Brand /* Disable the interrupt */ 661918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 662b0104773SPascal Brand } 663b0104773SPascal Brand 66426ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 66526ed70ecSGuanchao Liang { 66626ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 66726ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 66826ed70ecSGuanchao Liang 66967e55c51SEtienne Carriere assert(gd == &gic_data); 67067e55c51SEtienne Carriere 67126ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 67226ed70ecSGuanchao Liang assert(it >= NUM_SGI); 67326ed70ecSGuanchao Liang 67426ed70ecSGuanchao Liang /* Raise the interrupt */ 675918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 67626ed70ecSGuanchao Liang } 67726ed70ecSGuanchao Liang 678ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask) 679ec740b9fSJens Wiklander { 680ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS; 681ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU; 682ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff; 683ec740b9fSJens Wiklander 684ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */ 685ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1); 686ec740b9fSJens Wiklander } 687ec740b9fSJens Wiklander 68854739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it, 689*84603456SJens Wiklander uint32_t cpu_mask, bool ns) 69026ed70ecSGuanchao Liang { 69154739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3) 69254739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf; 693ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24); 694ec740b9fSJens Wiklander 695ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 696ec740b9fSJens Wiklander 697ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 698ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT); 699ec740b9fSJens Wiklander } else { 70054739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr(); 701ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >> 702ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT; 703ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >> 704ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT; 705ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >> 706ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT; 707ec740b9fSJens Wiklander 708ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT); 709ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT); 710ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT); 711ec740b9fSJens Wiklander 712ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 713ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf); 714ec740b9fSJens Wiklander } else { 715ec740b9fSJens Wiklander /* 716ec740b9fSJens Wiklander * Only support sending SGI to the cores in the 717ec740b9fSJens Wiklander * same cluster now. 718ec740b9fSJens Wiklander */ 719ec740b9fSJens Wiklander mask |= cpu_mask & 0xff; 720ec740b9fSJens Wiklander } 721ec740b9fSJens Wiklander } 72254739cb4SMark-PK Tsai 72354739cb4SMark-PK Tsai /* Raise the interrupt */ 724*84603456SJens Wiklander if (ns) 72554739cb4SMark-PK Tsai write_icc_asgi1r(mask); 72654739cb4SMark-PK Tsai else 72754739cb4SMark-PK Tsai write_icc_sgi1r(mask); 72854739cb4SMark-PK Tsai #else 729ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK; 730*84603456SJens Wiklander uint32_t mask_group = ns; 731ec740b9fSJens Wiklander uint32_t mask = mask_id; 732ec740b9fSJens Wiklander 733ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 734ec740b9fSJens Wiklander 735ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT); 736ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 737ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS, 738ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 739ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 740ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU, 741ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 742ec740b9fSJens Wiklander } else { 743ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff, 744ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT); 745ec740b9fSJens Wiklander } 74626ed70ecSGuanchao Liang 74726ed70ecSGuanchao Liang /* Raise the interrupt */ 748918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 74954739cb4SMark-PK Tsai #endif 75026ed70ecSGuanchao Liang } 75126ed70ecSGuanchao Liang 75218901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 753b0104773SPascal Brand { 75467e55c51SEtienne Carriere assert(gd == &gic_data); 75567e55c51SEtienne Carriere 75618901324SDavid Wang #if defined(CFG_ARM_GICV3) 7571de462e1SSumit Garg return read_icc_iar1(); 75818901324SDavid Wang #else 759918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 76018901324SDavid Wang #endif 761b0104773SPascal Brand } 762b0104773SPascal Brand 76318901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 764b0104773SPascal Brand { 76567e55c51SEtienne Carriere assert(gd == &gic_data); 76667e55c51SEtienne Carriere 76718901324SDavid Wang #if defined(CFG_ARM_GICV3) 7681de462e1SSumit Garg write_icc_eoir1(eoir); 76918901324SDavid Wang #else 770918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 77118901324SDavid Wang #endif 772b0104773SPascal Brand } 773b0104773SPascal Brand 7747315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 7757315b7b4SJens Wiklander { 77653bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 77753bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 77867e55c51SEtienne Carriere 77967e55c51SEtienne Carriere assert(gd == &gic_data); 780918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 78153bd332aSSY Chiu } 78253bd332aSSY Chiu 7837315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 7847315b7b4SJens Wiklander { 78553bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 78653bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 78767e55c51SEtienne Carriere 78867e55c51SEtienne Carriere assert(gd == &gic_data); 789918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 79053bd332aSSY Chiu } 79153bd332aSSY Chiu 7927315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 7937315b7b4SJens Wiklander { 79453bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 7957315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 7967315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 79753bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 798918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 7997315b7b4SJens Wiklander 80067e55c51SEtienne Carriere assert(gd == &gic_data); 801918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 80253bd332aSSY Chiu } 80353bd332aSSY Chiu 80467e55c51SEtienne Carriere void gic_dump_state(void) 80553bd332aSSY Chiu { 80667e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 80767e55c51SEtienne Carriere int i = 0; 80853bd332aSSY Chiu 80918901324SDavid Wang #if defined(CFG_ARM_GICV3) 81018901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 81118901324SDavid Wang #else 812918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 81318901324SDavid Wang #endif 814918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 8157315b7b4SJens Wiklander 8164a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 8177315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 81853bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 8197315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 82053bd332aSSY Chiu } 82153bd332aSSY Chiu } 82253bd332aSSY Chiu } 8237315b7b4SJens Wiklander 82467e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void) 8257315b7b4SJens Wiklander { 82667e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 82767e55c51SEtienne Carriere uint32_t iar = 0; 82867e55c51SEtienne Carriere uint32_t id = 0; 8297315b7b4SJens Wiklander 8307315b7b4SJens Wiklander iar = gic_read_iar(gd); 8317315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 8327315b7b4SJens Wiklander 8334a9ea08cSFangsuo Wu if (id <= gd->max_it) 83499e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id); 8353b3a4611SMathieu Briand else 8363b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 8377315b7b4SJens Wiklander 8387315b7b4SJens Wiklander gic_write_eoir(gd, iar); 8397315b7b4SJens Wiklander } 8407315b7b4SJens Wiklander 84167e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI 842358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */ 843358bf47cSEtienne Carriere void interrupt_main_handler(void) 84467e55c51SEtienne Carriere { 84567e55c51SEtienne Carriere gic_native_itr_handler(); 84667e55c51SEtienne Carriere } 84767e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/ 84867e55c51SEtienne Carriere 8497315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 850702fe5a7SClément Léger uint32_t type __unused, 851702fe5a7SClément Léger uint32_t prio __unused) 8527315b7b4SJens Wiklander { 8537315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 8547315b7b4SJens Wiklander 85567e55c51SEtienne Carriere assert(gd == &gic_data); 85667e55c51SEtienne Carriere 8574a9ea08cSFangsuo Wu if (it > gd->max_it) 858d13278b8SEtienne Carriere panic(); 859d13278b8SEtienne Carriere 8607315b7b4SJens Wiklander gic_it_add(gd, it); 8617315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 8627315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 8637315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 8647315b7b4SJens Wiklander } 8657315b7b4SJens Wiklander 8667315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 8677315b7b4SJens Wiklander { 8687315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 8697315b7b4SJens Wiklander 87067e55c51SEtienne Carriere assert(gd == &gic_data); 87167e55c51SEtienne Carriere 8724a9ea08cSFangsuo Wu if (it > gd->max_it) 873d13278b8SEtienne Carriere panic(); 874d13278b8SEtienne Carriere 8757315b7b4SJens Wiklander gic_it_enable(gd, it); 8767315b7b4SJens Wiklander } 8777315b7b4SJens Wiklander 8787315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 8797315b7b4SJens Wiklander { 8807315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 8817315b7b4SJens Wiklander 88267e55c51SEtienne Carriere assert(gd == &gic_data); 88367e55c51SEtienne Carriere 8844a9ea08cSFangsuo Wu if (it > gd->max_it) 885d13278b8SEtienne Carriere panic(); 886d13278b8SEtienne Carriere 8877315b7b4SJens Wiklander gic_it_disable(gd, it); 8887315b7b4SJens Wiklander } 88926ed70ecSGuanchao Liang 89026ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 89126ed70ecSGuanchao Liang { 89226ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 89326ed70ecSGuanchao Liang 89467e55c51SEtienne Carriere assert(gd == &gic_data); 89567e55c51SEtienne Carriere 8964a9ea08cSFangsuo Wu if (it > gd->max_it) 89726ed70ecSGuanchao Liang panic(); 89826ed70ecSGuanchao Liang 89926ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 90026ed70ecSGuanchao Liang } 90126ed70ecSGuanchao Liang 90226ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 903ec740b9fSJens Wiklander uint32_t cpu_mask) 90426ed70ecSGuanchao Liang { 90526ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 906*84603456SJens Wiklander bool ns = false; 90726ed70ecSGuanchao Liang 90867e55c51SEtienne Carriere assert(gd == &gic_data); 90967e55c51SEtienne Carriere 91054739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */ 91154739cb4SMark-PK Tsai assert(it < NUM_SGI); 91254739cb4SMark-PK Tsai 913*84603456SJens Wiklander ns = BIT32(it) & gd->per_cpu_group_status; 914*84603456SJens Wiklander gic_it_raise_sgi(gd, it, cpu_mask, ns); 91526ed70ecSGuanchao Liang } 91667e55c51SEtienne Carriere 91726ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 91826ed70ecSGuanchao Liang uint8_t cpu_mask) 91926ed70ecSGuanchao Liang { 92026ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 92126ed70ecSGuanchao Liang 92267e55c51SEtienne Carriere assert(gd == &gic_data); 92367e55c51SEtienne Carriere 9244a9ea08cSFangsuo Wu if (it > gd->max_it) 92526ed70ecSGuanchao Liang panic(); 92626ed70ecSGuanchao Liang 92726ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 92826ed70ecSGuanchao Liang } 92914885eb1SEtienne Carriere 93014885eb1SEtienne Carriere #ifdef CFG_DT 93114885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */ 93214885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data, 93314885eb1SEtienne Carriere struct itr_desc *itr_desc) 93414885eb1SEtienne Carriere { 93514885eb1SEtienne Carriere int itr_num = DT_INFO_INVALID_INTERRUPT; 93614885eb1SEtienne Carriere struct itr_chip *chip = priv_data; 93714885eb1SEtienne Carriere uint32_t phandle_args[2] = { }; 93814885eb1SEtienne Carriere uint32_t type = 0; 93914885eb1SEtienne Carriere uint32_t prio = 0; 94014885eb1SEtienne Carriere 94114885eb1SEtienne Carriere assert(arg && itr_desc); 94214885eb1SEtienne Carriere 94314885eb1SEtienne Carriere /* 94414885eb1SEtienne Carriere * gic_dt_get_irq() expects phandle arguments passed are still in DT 94514885eb1SEtienne Carriere * format (big-endian) whereas struct dt_pargs carries converted 94614885eb1SEtienne Carriere * formats. Therefore swap again phandle arguments. gic_dt_get_irq() 94714885eb1SEtienne Carriere * consumes only the 2 first arguments. 94814885eb1SEtienne Carriere */ 94914885eb1SEtienne Carriere if (arg->args_count < 2) 95014885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 95114885eb1SEtienne Carriere phandle_args[0] = cpu_to_fdt32(arg->args[0]); 95214885eb1SEtienne Carriere phandle_args[1] = cpu_to_fdt32(arg->args[1]); 95314885eb1SEtienne Carriere 95414885eb1SEtienne Carriere itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio); 95514885eb1SEtienne Carriere if (itr_num == DT_INFO_INVALID_INTERRUPT) 95614885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 95714885eb1SEtienne Carriere 95814885eb1SEtienne Carriere gic_op_add(chip, itr_num, type, prio); 95914885eb1SEtienne Carriere 96014885eb1SEtienne Carriere itr_desc->chip = chip; 96114885eb1SEtienne Carriere itr_desc->itr_num = itr_num; 96214885eb1SEtienne Carriere 96314885eb1SEtienne Carriere return TEE_SUCCESS; 96414885eb1SEtienne Carriere } 96514885eb1SEtienne Carriere 96614885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused) 96714885eb1SEtienne Carriere { 96814885eb1SEtienne Carriere if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb, 96914885eb1SEtienne Carriere &gic_data.chip)) 97014885eb1SEtienne Carriere panic(); 97114885eb1SEtienne Carriere 97214885eb1SEtienne Carriere return TEE_SUCCESS; 97314885eb1SEtienne Carriere } 97414885eb1SEtienne Carriere 97514885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = { 97614885eb1SEtienne Carriere { .compatible = "arm,cortex-a15-gic" }, 97714885eb1SEtienne Carriere { .compatible = "arm,cortex-a7-gic" }, 97814885eb1SEtienne Carriere { .compatible = "arm,cortex-a5-gic" }, 97914885eb1SEtienne Carriere { .compatible = "arm,cortex-a9-gic" }, 98014885eb1SEtienne Carriere { .compatible = "arm,gic-400" }, 98114885eb1SEtienne Carriere { } 98214885eb1SEtienne Carriere }; 98314885eb1SEtienne Carriere 98414885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = { 98514885eb1SEtienne Carriere .name = "gic", 98614885eb1SEtienne Carriere .match_table = gic_match_table, 98714885eb1SEtienne Carriere .probe = gic_probe, 98814885eb1SEtienne Carriere }; 98914885eb1SEtienne Carriere #endif /*CFG_DT*/ 990