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) 7005089e5fSJens Wiklander 7105089e5fSJens Wiklander #define GICR_TYPER_LAST BIT64(4) 7205089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT 56 7305089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT 48 7405089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT 40 7505089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT 32 76b0104773SPascal Brand 7769171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */ 7869171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT 4 7969171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK 0xF 8069171becSJens Wiklander 8153bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 8253bd332aSSY Chiu #define NUM_PPI 32 8353bd332aSSY Chiu 8426ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 8526ed70ecSGuanchao Liang #define NUM_SGI 16 8626ed70ecSGuanchao Liang 8726ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 8826ed70ecSGuanchao Liang #define NUM_NS_SGI 8 8926ed70ecSGuanchao Liang 9053bd332aSSY Chiu /* Number of interrupts in one register */ 9153bd332aSSY Chiu #define NUM_INTS_PER_REG 32 9253bd332aSSY Chiu 9353bd332aSSY Chiu /* Number of targets in one register */ 9453bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 9553bd332aSSY Chiu 9653bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 9753bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 9853bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 9953bd332aSSY Chiu 1001b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f 1017315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 1027315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 1037315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 104b0104773SPascal Brand 105ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40 106ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16 107ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32 108ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48 109ec740b9fSJens Wiklander 110ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf 111ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1 112ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2 113ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24 114ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15 115ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16 116ec740b9fSJens Wiklander 11767e55c51SEtienne Carriere struct gic_data { 11867e55c51SEtienne Carriere vaddr_t gicc_base; 11967e55c51SEtienne Carriere vaddr_t gicd_base; 12005089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 12105089e5fSJens Wiklander vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE]; 12205089e5fSJens Wiklander #endif 12367e55c51SEtienne Carriere size_t max_it; 12405089e5fSJens Wiklander uint32_t per_cpu_group_status; 12505089e5fSJens Wiklander uint32_t per_cpu_group_modifier; 12667e55c51SEtienne Carriere struct itr_chip chip; 12767e55c51SEtienne Carriere }; 12867e55c51SEtienne Carriere 12967e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss; 13067e55c51SEtienne Carriere 131702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type, 132702fe5a7SClément Léger uint32_t prio); 1337315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 1347315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 13526ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 13626ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 137ec740b9fSJens Wiklander uint32_t cpu_mask); 13826ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 13926ed70ecSGuanchao Liang uint8_t cpu_mask); 1407315b7b4SJens Wiklander 1417315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 1427315b7b4SJens Wiklander .add = gic_op_add, 14308ded0e1SEtienne Carriere .mask = gic_op_disable, 14408ded0e1SEtienne Carriere .unmask = gic_op_enable, 1457315b7b4SJens Wiklander .enable = gic_op_enable, 1467315b7b4SJens Wiklander .disable = gic_op_disable, 14726ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 14826ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 14926ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 1507315b7b4SJens Wiklander }; 1513639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 1527315b7b4SJens Wiklander 15305089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused) 15405089e5fSJens Wiklander { 15505089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 15605089e5fSJens Wiklander return gd->gicr_base[get_core_pos()]; 15705089e5fSJens Wiklander #else 15805089e5fSJens Wiklander return 0; 15905089e5fSJens Wiklander #endif 16005089e5fSJens Wiklander } 16105089e5fSJens Wiklander 16218901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 163b0104773SPascal Brand { 164b0104773SPascal Brand int i; 165b0104773SPascal Brand uint32_t old_ctlr; 166b0104773SPascal Brand size_t ret = 0; 1671b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) & 1681b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK; 169b0104773SPascal Brand 170b0104773SPascal Brand /* 171b0104773SPascal Brand * Probe which interrupt number is the largest. 172b0104773SPascal Brand */ 17318901324SDavid Wang #if defined(CFG_ARM_GICV3) 17418901324SDavid Wang old_ctlr = read_icc_ctlr(); 17518901324SDavid Wang write_icc_ctlr(0); 17618901324SDavid Wang #else 177918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 178918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 17918901324SDavid Wang #endif 18079f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 181b0104773SPascal Brand uint32_t old_reg; 182b0104773SPascal Brand uint32_t reg; 183b0104773SPascal Brand int b; 184b0104773SPascal Brand 185918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 186918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 187918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 188918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 18979f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 190007a97a2SJens Wiklander if (BIT32(b) & reg) { 19153bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 192b0104773SPascal Brand goto out; 193b0104773SPascal Brand } 194b0104773SPascal Brand } 195b0104773SPascal Brand } 196b0104773SPascal Brand out: 19718901324SDavid Wang #if defined(CFG_ARM_GICV3) 19818901324SDavid Wang write_icc_ctlr(old_ctlr); 19918901324SDavid Wang #else 200918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 20118901324SDavid Wang #endif 202b0104773SPascal Brand return ret; 203b0104773SPascal Brand } 204b0104773SPascal Brand 205*5da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd) 206bedc2b9fSsunny { 20705089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status); 208bedc2b9fSsunny 20905089e5fSJens Wiklander /* 21005089e5fSJens Wiklander * Set the priority mask to permit Non-secure interrupts, and to 21130a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 21230a673e3SPeter Maydell */ 21318901324SDavid Wang #if defined(CFG_ARM_GICV3) 21418901324SDavid Wang write_icc_pmr(0x80); 2151fcac774SSandeep Tripathy write_icc_igrpen1(1); 21618901324SDavid Wang #else 217918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 21830a673e3SPeter Maydell 219bedc2b9fSsunny /* Enable GIC */ 220918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 221918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 222918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 22318901324SDavid Wang #endif 224bedc2b9fSsunny } 225bedc2b9fSsunny 226*5da157f5SJens Wiklander void gic_init_per_cpu(void) 227*5da157f5SJens Wiklander { 228*5da157f5SJens Wiklander struct gic_data *gd = &gic_data; 229*5da157f5SJens Wiklander 230*5da157f5SJens Wiklander #if defined(CFG_ARM_GICV3) 231*5da157f5SJens Wiklander assert(gd->gicd_base); 232*5da157f5SJens Wiklander #else 233*5da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base); 234*5da157f5SJens Wiklander #endif 235*5da157f5SJens Wiklander 236*5da157f5SJens Wiklander /* GIC is already configured in TF-A configurations */ 237*5da157f5SJens Wiklander if (!IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) 238*5da157f5SJens Wiklander init_gic_per_cpu(gd); 239*5da157f5SJens Wiklander } 240*5da157f5SJens Wiklander 241*5da157f5SJens Wiklander void gic_cpu_init(void) 242*5da157f5SJens Wiklander { 243*5da157f5SJens Wiklander struct gic_data *gd = &gic_data; 244*5da157f5SJens Wiklander 245*5da157f5SJens Wiklander #if defined(CFG_ARM_GICV3) 246*5da157f5SJens Wiklander assert(gd->gicd_base); 247*5da157f5SJens Wiklander #else 248*5da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base); 249*5da157f5SJens Wiklander #endif 250*5da157f5SJens Wiklander IMSG("%s is deprecated, please use gic_init_per_cpu()", __func__); 251*5da157f5SJens Wiklander 252*5da157f5SJens Wiklander init_gic_per_cpu(gd); 253*5da157f5SJens Wiklander } 254*5da157f5SJens Wiklander 2550ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 2560ee3f52eSEtienne Carriere uint32_t *prio) 2570ee3f52eSEtienne Carriere { 2580ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT; 2590ee3f52eSEtienne Carriere 2600ee3f52eSEtienne Carriere if (type) 2610ee3f52eSEtienne Carriere *type = IRQ_TYPE_NONE; 2620ee3f52eSEtienne Carriere 2630ee3f52eSEtienne Carriere if (prio) 2640ee3f52eSEtienne Carriere *prio = 0; 2650ee3f52eSEtienne Carriere 2660ee3f52eSEtienne Carriere if (!properties || count < 2) 2670ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 2680ee3f52eSEtienne Carriere 2690ee3f52eSEtienne Carriere it_num = fdt32_to_cpu(properties[1]); 2700ee3f52eSEtienne Carriere 2710ee3f52eSEtienne Carriere switch (fdt32_to_cpu(properties[0])) { 2728c7282beSEtienne Carriere case GIC_PPI: 2730ee3f52eSEtienne Carriere it_num += 16; 2740ee3f52eSEtienne Carriere break; 2758c7282beSEtienne Carriere case GIC_SPI: 2760ee3f52eSEtienne Carriere it_num += 32; 2770ee3f52eSEtienne Carriere break; 2780ee3f52eSEtienne Carriere default: 2790ee3f52eSEtienne Carriere it_num = DT_INFO_INVALID_INTERRUPT; 2800ee3f52eSEtienne Carriere } 2810ee3f52eSEtienne Carriere 2820ee3f52eSEtienne Carriere return it_num; 2830ee3f52eSEtienne Carriere } 2840ee3f52eSEtienne Carriere 28505089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs, 28605089e5fSJens Wiklander paddr_t gicr_base_pa) 28705089e5fSJens Wiklander { 28805089e5fSJens Wiklander size_t sz = GICR_V3_PCPUBASE_SIZE; 28905089e5fSJens Wiklander paddr_t pa = gicr_base_pa; 29005089e5fSJens Wiklander size_t core_pos = 0; 29105089e5fSJens Wiklander uint64_t mt_bit = 0; 29205089e5fSJens Wiklander uint64_t mpidr = 0; 29305089e5fSJens Wiklander uint64_t tv = 0; 29405089e5fSJens Wiklander vaddr_t va = 0; 29505089e5fSJens Wiklander 29605089e5fSJens Wiklander #ifdef ARM64 29705089e5fSJens Wiklander mt_bit = read_mpidr_el1() & MPIDR_MT_MASK; 29805089e5fSJens Wiklander #endif 29905089e5fSJens Wiklander do { 30005089e5fSJens Wiklander va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz); 30105089e5fSJens Wiklander if (!va) 30205089e5fSJens Wiklander panic(); 30305089e5fSJens Wiklander tv = io_read64(va + GICR_TYPER); 30405089e5fSJens Wiklander 30505089e5fSJens Wiklander /* 30605089e5fSJens Wiklander * Extract an mpidr from the Type register to calculate the 30705089e5fSJens Wiklander * core position of this redistributer instance. 30805089e5fSJens Wiklander */ 30905089e5fSJens Wiklander mpidr = mt_bit; 31005089e5fSJens Wiklander mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) & 31105089e5fSJens Wiklander MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT); 31205089e5fSJens Wiklander mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) & 31305089e5fSJens Wiklander (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK); 31405089e5fSJens Wiklander core_pos = get_core_pos_mpidr(mpidr); 31505089e5fSJens Wiklander if (core_pos < CFG_TEE_CORE_NB_CORE) { 31605089e5fSJens Wiklander DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va); 31705089e5fSJens Wiklander gicr_base_addrs[core_pos] = va; 31805089e5fSJens Wiklander } else { 31905089e5fSJens Wiklander EMSG("Skipping too large core_pos %zu from GICR_TYPER", 32005089e5fSJens Wiklander core_pos); 32105089e5fSJens Wiklander } 32205089e5fSJens Wiklander pa += sz; 32305089e5fSJens Wiklander } while (!(tv & GICR_TYPER_LAST)); 32405089e5fSJens Wiklander } 32505089e5fSJens Wiklander 32605089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 32705089e5fSJens Wiklander paddr_t gicr_base_pa __maybe_unused) 328b0104773SPascal Brand { 32967e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 3300ee3f52eSEtienne Carriere vaddr_t gicc_base = 0; 3310ee3f52eSEtienne Carriere vaddr_t gicd_base = 0; 33269171becSJens Wiklander uint32_t vers __maybe_unused = 0; 3330ee3f52eSEtienne Carriere 3340ee3f52eSEtienne Carriere assert(cpu_mmu_enabled()); 3350ee3f52eSEtienne Carriere 3360ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 3370ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE); 3380ee3f52eSEtienne Carriere if (!gicd_base) 3390ee3f52eSEtienne Carriere panic(); 3400ee3f52eSEtienne Carriere 34169171becSJens Wiklander vers = io_read32(gicd_base + GICD_PIDR2); 34269171becSJens Wiklander vers >>= GICD_PIDR2_ARCHREV_SHIFT; 34369171becSJens Wiklander vers &= GICD_PIDR2_ARCHREV_MASK; 34469171becSJens Wiklander 34569171becSJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3)) { 34669171becSJens Wiklander assert(vers == 3); 34769171becSJens Wiklander } else { 34869171becSJens Wiklander assert(vers == 2); 3490ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 3500ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE); 3510ee3f52eSEtienne Carriere if (!gicc_base) 3520ee3f52eSEtienne Carriere panic(); 3530ee3f52eSEtienne Carriere } 3540ee3f52eSEtienne Carriere 3550ee3f52eSEtienne Carriere gd->gicc_base = gicc_base; 3560ee3f52eSEtienne Carriere gd->gicd_base = gicd_base; 3570ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base); 35805089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 35905089e5fSJens Wiklander probe_redist_base_addrs(gd->gicr_base, gicr_base_pa); 36005089e5fSJens Wiklander #endif 3610ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops; 3620ee3f52eSEtienne Carriere 3630ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT)) 3640ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq; 3650ee3f52eSEtienne Carriere } 3660ee3f52eSEtienne Carriere 36705089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 36805089e5fSJens Wiklander paddr_t gicr_base_pa) 3690ee3f52eSEtienne Carriere { 3700ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data; 3710ee3f52eSEtienne Carriere size_t __maybe_unused n = 0; 372b0104773SPascal Brand 37305089e5fSJens Wiklander gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa); 374b0104773SPascal Brand 37505089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW) 3760ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */ 37705089e5fSJens Wiklander if (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S) { 37805089e5fSJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 37905089e5fSJens Wiklander 38005089e5fSJens Wiklander if (!gicr_base) 38105089e5fSJens Wiklander panic("GICR_BASE missing for affinity routing"); 38205089e5fSJens Wiklander /* Secure affinity routing enabled */ 38305089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gicr_base + GICR_IGROUPR0); 38405089e5fSJens Wiklander gd->per_cpu_group_modifier = io_read32(gicr_base + 38505089e5fSJens Wiklander GICR_IGRPMODR0); 38605089e5fSJens Wiklander } else { 38705089e5fSJens Wiklander /* Legacy operation with secure affinity routing disabled */ 38805089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gd->gicd_base + 38905089e5fSJens Wiklander GICD_IGROUPR(0)); 39005089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 39105089e5fSJens Wiklander } 39205089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/ 39305089e5fSJens Wiklander /* 39405089e5fSJens Wiklander * Without TF-A, GIC is always configured in for legacy operation 39505089e5fSJens Wiklander * with secure affinity routing disabled. 39605089e5fSJens Wiklander */ 3977315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 398b0104773SPascal Brand /* Disable interrupts */ 399918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 400b0104773SPascal Brand 401b0104773SPascal Brand /* Make interrupts non-pending */ 402918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 403b0104773SPascal Brand 404b0104773SPascal Brand /* Mark interrupts non-secure */ 405bedc2b9fSsunny if (n == 0) { 406bedc2b9fSsunny /* per-CPU inerrupts config: 407bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 408bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 409bedc2b9fSsunny * All PPI config as Non-secure interrupts. 410bedc2b9fSsunny */ 41105089e5fSJens Wiklander gd->per_cpu_group_status = 0xffff00ff; 41205089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 41305089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(n), 41405089e5fSJens Wiklander gd->per_cpu_group_status); 415bedc2b9fSsunny } else { 416918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 417b0104773SPascal Brand } 418bedc2b9fSsunny } 419b0104773SPascal Brand 42030a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 42130a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 42230a673e3SPeter Maydell */ 42318901324SDavid Wang #if defined(CFG_ARM_GICV3) 42418901324SDavid Wang write_icc_pmr(0x80); 4251fcac774SSandeep Tripathy write_icc_igrpen1(1); 4261fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 42718901324SDavid Wang #else 428918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 42930a673e3SPeter Maydell 430b0104773SPascal Brand /* Enable GIC */ 431918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 432918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 433918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 43405089e5fSJens Wiklander GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS); 4351fcac774SSandeep Tripathy #endif 43605089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/ 43767e55c51SEtienne Carriere 43801980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip); 439b0104773SPascal Brand } 440b0104773SPascal Brand 4417315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 442b0104773SPascal Brand { 44353bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 44453bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 445b0104773SPascal Brand 44667e55c51SEtienne Carriere assert(gd == &gic_data); 44767e55c51SEtienne Carriere 448b0104773SPascal Brand /* Disable the interrupt */ 449918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 450b0104773SPascal Brand /* Make it non-pending */ 451918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 452b0104773SPascal Brand /* Assign it to group0 */ 453918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 4541fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 4551fcac774SSandeep Tripathy /* Assign it to group1S */ 4561fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 4571fcac774SSandeep Tripathy #endif 458b0104773SPascal Brand } 459b0104773SPascal Brand 4607315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 4617315b7b4SJens Wiklander uint8_t cpu_mask) 462b0104773SPascal Brand { 4638ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 4648ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 46553bd332aSSY Chiu uint32_t target, target_shift; 466918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 467918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 468b0104773SPascal Brand 46967e55c51SEtienne Carriere assert(gd == &gic_data); 47067e55c51SEtienne Carriere 471b0104773SPascal Brand /* Assigned to group0 */ 472918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 473b0104773SPascal Brand 474b0104773SPascal Brand /* Route it to selected CPUs */ 475918bb3a5SEtienne Carriere target = io_read32(itargetsr); 47653bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 47753bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 47853bd332aSSY Chiu target |= cpu_mask << target_shift; 479918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 480918bb3a5SEtienne Carriere io_write32(itargetsr, target); 481918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 482b0104773SPascal Brand } 483b0104773SPascal Brand 4847315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 485b0104773SPascal Brand { 4868ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 4878ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 488b0104773SPascal Brand 48967e55c51SEtienne Carriere assert(gd == &gic_data); 49067e55c51SEtienne Carriere 491b0104773SPascal Brand /* Assigned to group0 */ 492918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 493b0104773SPascal Brand 494b0104773SPascal Brand /* Set prio it to selected CPUs */ 4951f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 4967315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 497918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 498b0104773SPascal Brand } 499b0104773SPascal Brand 5007315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 501b0104773SPascal Brand { 50253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 50353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 504918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 505b0104773SPascal Brand 50667e55c51SEtienne Carriere assert(gd == &gic_data); 50767e55c51SEtienne Carriere 508b0104773SPascal Brand /* Assigned to group0 */ 509918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 510b0104773SPascal Brand 511b0104773SPascal Brand /* Enable the interrupt */ 512918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 513b0104773SPascal Brand } 514b0104773SPascal Brand 5157315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 516b0104773SPascal Brand { 51753bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 51853bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 519b0104773SPascal Brand 52067e55c51SEtienne Carriere assert(gd == &gic_data); 52167e55c51SEtienne Carriere 522b0104773SPascal Brand /* Assigned to group0 */ 523918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 524b0104773SPascal Brand 525b0104773SPascal Brand /* Disable the interrupt */ 526918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 527b0104773SPascal Brand } 528b0104773SPascal Brand 52926ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 53026ed70ecSGuanchao Liang { 53126ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 53226ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 53326ed70ecSGuanchao Liang 53467e55c51SEtienne Carriere assert(gd == &gic_data); 53567e55c51SEtienne Carriere 53626ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 53726ed70ecSGuanchao Liang assert(it >= NUM_SGI); 53826ed70ecSGuanchao Liang 53926ed70ecSGuanchao Liang /* Raise the interrupt */ 540918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 54126ed70ecSGuanchao Liang } 54226ed70ecSGuanchao Liang 543ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask) 544ec740b9fSJens Wiklander { 545ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS; 546ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU; 547ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff; 548ec740b9fSJens Wiklander 549ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */ 550ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1); 551ec740b9fSJens Wiklander } 552ec740b9fSJens Wiklander 55354739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it, 554ec740b9fSJens Wiklander uint32_t cpu_mask, uint8_t group) 55526ed70ecSGuanchao Liang { 55654739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3) 55754739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf; 558ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24); 559ec740b9fSJens Wiklander 560ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 561ec740b9fSJens Wiklander 562ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 563ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT); 564ec740b9fSJens Wiklander } else { 56554739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr(); 566ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >> 567ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT; 568ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >> 569ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT; 570ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >> 571ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT; 572ec740b9fSJens Wiklander 573ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT); 574ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT); 575ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT); 576ec740b9fSJens Wiklander 577ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 578ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf); 579ec740b9fSJens Wiklander } else { 580ec740b9fSJens Wiklander /* 581ec740b9fSJens Wiklander * Only support sending SGI to the cores in the 582ec740b9fSJens Wiklander * same cluster now. 583ec740b9fSJens Wiklander */ 584ec740b9fSJens Wiklander mask |= cpu_mask & 0xff; 585ec740b9fSJens Wiklander } 586ec740b9fSJens Wiklander } 58754739cb4SMark-PK Tsai 58854739cb4SMark-PK Tsai /* Raise the interrupt */ 58954739cb4SMark-PK Tsai if (group) 59054739cb4SMark-PK Tsai write_icc_asgi1r(mask); 59154739cb4SMark-PK Tsai else 59254739cb4SMark-PK Tsai write_icc_sgi1r(mask); 59354739cb4SMark-PK Tsai #else 594ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK; 59526ed70ecSGuanchao Liang uint32_t mask_group = group & 0x1; 596ec740b9fSJens Wiklander uint32_t mask = mask_id; 597ec740b9fSJens Wiklander 598ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 599ec740b9fSJens Wiklander 600ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT); 601ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 602ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS, 603ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 604ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 605ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU, 606ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 607ec740b9fSJens Wiklander } else { 608ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff, 609ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT); 610ec740b9fSJens Wiklander } 61126ed70ecSGuanchao Liang 61226ed70ecSGuanchao Liang /* Raise the interrupt */ 613918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 61454739cb4SMark-PK Tsai #endif 61526ed70ecSGuanchao Liang } 61626ed70ecSGuanchao Liang 61718901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 618b0104773SPascal Brand { 61967e55c51SEtienne Carriere assert(gd == &gic_data); 62067e55c51SEtienne Carriere 62118901324SDavid Wang #if defined(CFG_ARM_GICV3) 6221de462e1SSumit Garg return read_icc_iar1(); 62318901324SDavid Wang #else 624918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 62518901324SDavid Wang #endif 626b0104773SPascal Brand } 627b0104773SPascal Brand 62818901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 629b0104773SPascal Brand { 63067e55c51SEtienne Carriere assert(gd == &gic_data); 63167e55c51SEtienne Carriere 63218901324SDavid Wang #if defined(CFG_ARM_GICV3) 6331de462e1SSumit Garg write_icc_eoir1(eoir); 63418901324SDavid Wang #else 635918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 63618901324SDavid Wang #endif 637b0104773SPascal Brand } 638b0104773SPascal Brand 6397315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 6407315b7b4SJens Wiklander { 64153bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 64253bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 64367e55c51SEtienne Carriere 64467e55c51SEtienne Carriere assert(gd == &gic_data); 645918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 64653bd332aSSY Chiu } 64753bd332aSSY Chiu 6487315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 6497315b7b4SJens Wiklander { 65053bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 65153bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 65267e55c51SEtienne Carriere 65367e55c51SEtienne Carriere assert(gd == &gic_data); 654918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 65553bd332aSSY Chiu } 65653bd332aSSY Chiu 6577315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 6587315b7b4SJens Wiklander { 65953bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 6607315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 6617315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 66253bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 663918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 6647315b7b4SJens Wiklander 66567e55c51SEtienne Carriere assert(gd == &gic_data); 666918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 66753bd332aSSY Chiu } 66853bd332aSSY Chiu 66967e55c51SEtienne Carriere void gic_dump_state(void) 67053bd332aSSY Chiu { 67167e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 67267e55c51SEtienne Carriere int i = 0; 67353bd332aSSY Chiu 67418901324SDavid Wang #if defined(CFG_ARM_GICV3) 67518901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 67618901324SDavid Wang #else 677918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 67818901324SDavid Wang #endif 679918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 6807315b7b4SJens Wiklander 6814a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 6827315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 68353bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 6847315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 68553bd332aSSY Chiu } 68653bd332aSSY Chiu } 68753bd332aSSY Chiu } 6887315b7b4SJens Wiklander 68967e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void) 6907315b7b4SJens Wiklander { 69167e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 69267e55c51SEtienne Carriere uint32_t iar = 0; 69367e55c51SEtienne Carriere uint32_t id = 0; 6947315b7b4SJens Wiklander 6957315b7b4SJens Wiklander iar = gic_read_iar(gd); 6967315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 6977315b7b4SJens Wiklander 6984a9ea08cSFangsuo Wu if (id <= gd->max_it) 69999e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id); 7003b3a4611SMathieu Briand else 7013b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 7027315b7b4SJens Wiklander 7037315b7b4SJens Wiklander gic_write_eoir(gd, iar); 7047315b7b4SJens Wiklander } 7057315b7b4SJens Wiklander 70667e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI 707358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */ 708358bf47cSEtienne Carriere void interrupt_main_handler(void) 70967e55c51SEtienne Carriere { 71067e55c51SEtienne Carriere gic_native_itr_handler(); 71167e55c51SEtienne Carriere } 71267e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/ 71367e55c51SEtienne Carriere 7147315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 715702fe5a7SClément Léger uint32_t type __unused, 716702fe5a7SClément Léger uint32_t prio __unused) 7177315b7b4SJens Wiklander { 7187315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 7197315b7b4SJens Wiklander 72067e55c51SEtienne Carriere assert(gd == &gic_data); 72167e55c51SEtienne Carriere 7224a9ea08cSFangsuo Wu if (it > gd->max_it) 723d13278b8SEtienne Carriere panic(); 724d13278b8SEtienne Carriere 7257315b7b4SJens Wiklander gic_it_add(gd, it); 7267315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 7277315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 7287315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 7297315b7b4SJens Wiklander } 7307315b7b4SJens Wiklander 7317315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 7327315b7b4SJens Wiklander { 7337315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 7347315b7b4SJens Wiklander 73567e55c51SEtienne Carriere assert(gd == &gic_data); 73667e55c51SEtienne Carriere 7374a9ea08cSFangsuo Wu if (it > gd->max_it) 738d13278b8SEtienne Carriere panic(); 739d13278b8SEtienne Carriere 7407315b7b4SJens Wiklander gic_it_enable(gd, it); 7417315b7b4SJens Wiklander } 7427315b7b4SJens Wiklander 7437315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 7447315b7b4SJens Wiklander { 7457315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 7467315b7b4SJens Wiklander 74767e55c51SEtienne Carriere assert(gd == &gic_data); 74867e55c51SEtienne Carriere 7494a9ea08cSFangsuo Wu if (it > gd->max_it) 750d13278b8SEtienne Carriere panic(); 751d13278b8SEtienne Carriere 7527315b7b4SJens Wiklander gic_it_disable(gd, it); 7537315b7b4SJens Wiklander } 75426ed70ecSGuanchao Liang 75526ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 75626ed70ecSGuanchao Liang { 75726ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 75826ed70ecSGuanchao Liang 75967e55c51SEtienne Carriere assert(gd == &gic_data); 76067e55c51SEtienne Carriere 7614a9ea08cSFangsuo Wu if (it > gd->max_it) 76226ed70ecSGuanchao Liang panic(); 76326ed70ecSGuanchao Liang 76426ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 76526ed70ecSGuanchao Liang } 76626ed70ecSGuanchao Liang 76726ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 768ec740b9fSJens Wiklander uint32_t cpu_mask) 76926ed70ecSGuanchao Liang { 77026ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 77126ed70ecSGuanchao Liang 77267e55c51SEtienne Carriere assert(gd == &gic_data); 77367e55c51SEtienne Carriere 77454739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */ 77554739cb4SMark-PK Tsai assert(it < NUM_SGI); 77654739cb4SMark-PK Tsai 77726ed70ecSGuanchao Liang if (it < NUM_NS_SGI) 77826ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 1); 77926ed70ecSGuanchao Liang else 78026ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 0); 78126ed70ecSGuanchao Liang } 78267e55c51SEtienne Carriere 78326ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 78426ed70ecSGuanchao Liang uint8_t cpu_mask) 78526ed70ecSGuanchao Liang { 78626ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 78726ed70ecSGuanchao Liang 78867e55c51SEtienne Carriere assert(gd == &gic_data); 78967e55c51SEtienne Carriere 7904a9ea08cSFangsuo Wu if (it > gd->max_it) 79126ed70ecSGuanchao Liang panic(); 79226ed70ecSGuanchao Liang 79326ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 79426ed70ecSGuanchao Liang } 79514885eb1SEtienne Carriere 79614885eb1SEtienne Carriere #ifdef CFG_DT 79714885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */ 79814885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data, 79914885eb1SEtienne Carriere struct itr_desc *itr_desc) 80014885eb1SEtienne Carriere { 80114885eb1SEtienne Carriere int itr_num = DT_INFO_INVALID_INTERRUPT; 80214885eb1SEtienne Carriere struct itr_chip *chip = priv_data; 80314885eb1SEtienne Carriere uint32_t phandle_args[2] = { }; 80414885eb1SEtienne Carriere uint32_t type = 0; 80514885eb1SEtienne Carriere uint32_t prio = 0; 80614885eb1SEtienne Carriere 80714885eb1SEtienne Carriere assert(arg && itr_desc); 80814885eb1SEtienne Carriere 80914885eb1SEtienne Carriere /* 81014885eb1SEtienne Carriere * gic_dt_get_irq() expects phandle arguments passed are still in DT 81114885eb1SEtienne Carriere * format (big-endian) whereas struct dt_pargs carries converted 81214885eb1SEtienne Carriere * formats. Therefore swap again phandle arguments. gic_dt_get_irq() 81314885eb1SEtienne Carriere * consumes only the 2 first arguments. 81414885eb1SEtienne Carriere */ 81514885eb1SEtienne Carriere if (arg->args_count < 2) 81614885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 81714885eb1SEtienne Carriere phandle_args[0] = cpu_to_fdt32(arg->args[0]); 81814885eb1SEtienne Carriere phandle_args[1] = cpu_to_fdt32(arg->args[1]); 81914885eb1SEtienne Carriere 82014885eb1SEtienne Carriere itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio); 82114885eb1SEtienne Carriere if (itr_num == DT_INFO_INVALID_INTERRUPT) 82214885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 82314885eb1SEtienne Carriere 82414885eb1SEtienne Carriere gic_op_add(chip, itr_num, type, prio); 82514885eb1SEtienne Carriere 82614885eb1SEtienne Carriere itr_desc->chip = chip; 82714885eb1SEtienne Carriere itr_desc->itr_num = itr_num; 82814885eb1SEtienne Carriere 82914885eb1SEtienne Carriere return TEE_SUCCESS; 83014885eb1SEtienne Carriere } 83114885eb1SEtienne Carriere 83214885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused) 83314885eb1SEtienne Carriere { 83414885eb1SEtienne Carriere if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb, 83514885eb1SEtienne Carriere &gic_data.chip)) 83614885eb1SEtienne Carriere panic(); 83714885eb1SEtienne Carriere 83814885eb1SEtienne Carriere return TEE_SUCCESS; 83914885eb1SEtienne Carriere } 84014885eb1SEtienne Carriere 84114885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = { 84214885eb1SEtienne Carriere { .compatible = "arm,cortex-a15-gic" }, 84314885eb1SEtienne Carriere { .compatible = "arm,cortex-a7-gic" }, 84414885eb1SEtienne Carriere { .compatible = "arm,cortex-a5-gic" }, 84514885eb1SEtienne Carriere { .compatible = "arm,cortex-a9-gic" }, 84614885eb1SEtienne Carriere { .compatible = "arm,gic-400" }, 84714885eb1SEtienne Carriere { } 84814885eb1SEtienne Carriere }; 84914885eb1SEtienne Carriere 85014885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = { 85114885eb1SEtienne Carriere .name = "gic", 85214885eb1SEtienne Carriere .match_table = gic_match_table, 85314885eb1SEtienne Carriere .probe = gic_probe, 85414885eb1SEtienne Carriere }; 85514885eb1SEtienne Carriere #endif /*CFG_DT*/ 856