11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2b0104773SPascal Brand /* 39e935234SJens Wiklander * Copyright (c) 2016-2017, 2023-2024 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> 967e55c51SEtienne Carriere #include <compiler.h> 1005089e5fSJens Wiklander #include <config.h> 11b0104773SPascal Brand #include <drivers/gic.h> 129e935234SJens Wiklander #include <dt-bindings/interrupt-controller/arm-gic.h> 139e935234SJens Wiklander #include <initcall.h> 1405089e5fSJens Wiklander #include <io.h> 150f93de74SEtienne Carriere #include <keep.h> 1667729d8dSLudovic Barre #include <kernel/dt.h> 1714885eb1SEtienne Carriere #include <kernel/dt_driver.h> 187315b7b4SJens Wiklander #include <kernel/interrupt.h> 1905089e5fSJens Wiklander #include <kernel/misc.h> 20*10cc5912SRunyang Chen #include <kernel/mutex.h> 21d13278b8SEtienne Carriere #include <kernel/panic.h> 2205089e5fSJens Wiklander #include <libfdt.h> 2360801696SVolodymyr Babchuk #include <mm/core_memprot.h> 2460801696SVolodymyr Babchuk #include <mm/core_mmu.h> 254de4bebcSJens Wiklander #include <trace.h> 2605089e5fSJens Wiklander #include <util.h> 27b0104773SPascal Brand 28b0104773SPascal Brand /* Offsets from gic.gicc_base */ 29b0104773SPascal Brand #define GICC_CTLR (0x000) 3030a673e3SPeter Maydell #define GICC_PMR (0x004) 31b0104773SPascal Brand #define GICC_IAR (0x00C) 32b0104773SPascal Brand #define GICC_EOIR (0x010) 33b0104773SPascal Brand 34b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0) 35b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1) 36b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3) 37b0104773SPascal Brand 38b0104773SPascal Brand /* Offsets from gic.gicd_base */ 39b0104773SPascal Brand #define GICD_CTLR (0x000) 40b0104773SPascal Brand #define GICD_TYPER (0x004) 41b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4) 42b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4) 43b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4) 4426ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4) 45b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4) 46b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) 47b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4) 481fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 4926ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 50b0104773SPascal Brand 5169171becSJens Wiklander #ifdef CFG_ARM_GICV3 5269171becSJens Wiklander #define GICD_PIDR2 (0xFFE8) 5369171becSJens Wiklander #else 5469171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */ 5569171becSJens Wiklander #define GICD_PIDR2 (0xFE8) 5669171becSJens Wiklander #endif 5769171becSJens Wiklander 5805089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0 BIT32(0) 5905089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS BIT32(1) 6005089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S BIT32(2) 6105089e5fSJens Wiklander #define GICD_CTLR_ARE_S BIT32(4) 6205089e5fSJens Wiklander #define GICD_CTLR_ARE_NS BIT32(5) 6305089e5fSJens Wiklander 6405089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */ 6505089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE (2 * 64 * 1024) 6605089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET (64 * 1024) 6705089e5fSJens Wiklander #define GICR_CTLR (0x00) 6805089e5fSJens Wiklander #define GICR_TYPER (0x08) 6905089e5fSJens Wiklander 7005089e5fSJens Wiklander #define GICR_IGROUPR0 (GICR_SGI_BASE_OFFSET + 0x080) 7105089e5fSJens Wiklander #define GICR_IGRPMODR0 (GICR_SGI_BASE_OFFSET + 0xD00) 7284603456SJens Wiklander #define GICR_ICENABLER0 (GICR_SGI_BASE_OFFSET + 0x180) 7384603456SJens Wiklander #define GICR_ICPENDR0 (GICR_SGI_BASE_OFFSET + 0x280) 749e935234SJens Wiklander #define GICR_ISENABLER0 (GICR_SGI_BASE_OFFSET + 0x100) 759e935234SJens Wiklander #define GICR_ICFGR0 (GICR_SGI_BASE_OFFSET + 0xC00) 769e935234SJens Wiklander #define GICR_ICFGR1 (GICR_SGI_BASE_OFFSET + 0xC04) 779e935234SJens Wiklander #define GICR_IPRIORITYR(n) (GICR_SGI_BASE_OFFSET + 0x400 + (n) * 4) 789e935234SJens Wiklander 796c2d2e8aSJens Wiklander #define GICR_CTLR_RWP BIT32(3) 8005089e5fSJens Wiklander 8105089e5fSJens Wiklander #define GICR_TYPER_LAST BIT64(4) 8205089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT 56 8305089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT 48 8405089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT 40 8505089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT 32 86b0104773SPascal Brand 8769171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */ 8869171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT 4 8969171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK 0xF 9069171becSJens Wiklander 9153bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 9253bd332aSSY Chiu #define NUM_PPI 32 9353bd332aSSY Chiu 9426ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 9526ed70ecSGuanchao Liang #define NUM_SGI 16 9626ed70ecSGuanchao Liang 9726ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 9826ed70ecSGuanchao Liang #define NUM_NS_SGI 8 9926ed70ecSGuanchao Liang 10053bd332aSSY Chiu /* Number of interrupts in one register */ 10153bd332aSSY Chiu #define NUM_INTS_PER_REG 32 10253bd332aSSY Chiu 10353bd332aSSY Chiu /* Number of targets in one register */ 10453bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 10553bd332aSSY Chiu 10653bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 10753bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 10853bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 10953bd332aSSY Chiu 1101b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f 1117315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 1127315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 1137315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 114b0104773SPascal Brand 115ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40 116ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16 117ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32 118ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48 119ec740b9fSJens Wiklander 120ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf 121ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1 122ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2 123ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24 124ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15 125ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16 126ec740b9fSJens Wiklander 12767e55c51SEtienne Carriere struct gic_data { 12867e55c51SEtienne Carriere vaddr_t gicc_base; 12967e55c51SEtienne Carriere vaddr_t gicd_base; 13005089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 13105089e5fSJens Wiklander vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE]; 13205089e5fSJens Wiklander #endif 13367e55c51SEtienne Carriere size_t max_it; 13405089e5fSJens Wiklander uint32_t per_cpu_group_status; 13505089e5fSJens Wiklander uint32_t per_cpu_group_modifier; 1369e935234SJens Wiklander uint32_t per_cpu_enable; 13767e55c51SEtienne Carriere struct itr_chip chip; 13867e55c51SEtienne Carriere }; 13967e55c51SEtienne Carriere 1409e935234SJens Wiklander static bool gic_primary_done __nex_bss; 14167e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss; 142*10cc5912SRunyang Chen static struct mutex gic_mutex = MUTEX_INITIALIZER; 14367e55c51SEtienne Carriere 144702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type, 145702fe5a7SClément Léger uint32_t prio); 1467315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 1477315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 14826ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 14926ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 150ec740b9fSJens Wiklander uint32_t cpu_mask); 15126ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 15226ed70ecSGuanchao Liang uint8_t cpu_mask); 1537315b7b4SJens Wiklander 1547315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 1557315b7b4SJens Wiklander .add = gic_op_add, 15608ded0e1SEtienne Carriere .mask = gic_op_disable, 15708ded0e1SEtienne Carriere .unmask = gic_op_enable, 1587315b7b4SJens Wiklander .enable = gic_op_enable, 1597315b7b4SJens Wiklander .disable = gic_op_disable, 16026ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 16126ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 16226ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 1637315b7b4SJens Wiklander }; 1643639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 1657315b7b4SJens Wiklander 16605089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused) 16705089e5fSJens Wiklander { 16805089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 16905089e5fSJens Wiklander return gd->gicr_base[get_core_pos()]; 17005089e5fSJens Wiklander #else 17105089e5fSJens Wiklander return 0; 17205089e5fSJens Wiklander #endif 17305089e5fSJens Wiklander } 17405089e5fSJens Wiklander 1757c4883aeSJens Wiklander static bool affinity_routing_is_enabled(struct gic_data *gd) 1767c4883aeSJens Wiklander { 1777c4883aeSJens Wiklander return IS_ENABLED(CFG_ARM_GICV3) && 1787c4883aeSJens Wiklander io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S; 1797c4883aeSJens Wiklander } 1807c4883aeSJens Wiklander 18118901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 182b0104773SPascal Brand { 183b0104773SPascal Brand int i; 184b0104773SPascal Brand uint32_t old_ctlr; 185b0104773SPascal Brand size_t ret = 0; 1861b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) & 1871b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK; 188b0104773SPascal Brand 189b0104773SPascal Brand /* 190b0104773SPascal Brand * Probe which interrupt number is the largest. 191b0104773SPascal Brand */ 19218901324SDavid Wang #if defined(CFG_ARM_GICV3) 19318901324SDavid Wang old_ctlr = read_icc_ctlr(); 19418901324SDavid Wang write_icc_ctlr(0); 19518901324SDavid Wang #else 196918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 197918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 19818901324SDavid Wang #endif 19979f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 200b0104773SPascal Brand uint32_t old_reg; 201b0104773SPascal Brand uint32_t reg; 202b0104773SPascal Brand int b; 203b0104773SPascal Brand 204918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 205918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 206918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 207918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 20879f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 209007a97a2SJens Wiklander if (BIT32(b) & reg) { 21053bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 211b0104773SPascal Brand goto out; 212b0104773SPascal Brand } 213b0104773SPascal Brand } 214b0104773SPascal Brand } 215b0104773SPascal Brand out: 21618901324SDavid Wang #if defined(CFG_ARM_GICV3) 21718901324SDavid Wang write_icc_ctlr(old_ctlr); 21818901324SDavid Wang #else 219918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 22018901324SDavid Wang #endif 221b0104773SPascal Brand return ret; 222b0104773SPascal Brand } 223b0104773SPascal Brand 2246c2d2e8aSJens Wiklander static void gicr_wait_for_pending_write(vaddr_t gicr_base) 2256c2d2e8aSJens Wiklander { 2266c2d2e8aSJens Wiklander /* 2276c2d2e8aSJens Wiklander * Wait for changes to 2286c2d2e8aSJens Wiklander * - GICR_ICENABLER0 2296c2d2e8aSJens Wiklander * - GICR_CTLR.DPG1S 2306c2d2e8aSJens Wiklander * - GICR_CTLR.DPG1NS 2316c2d2e8aSJens Wiklander * - GICR_CTLR.DPG0 2326c2d2e8aSJens Wiklander * to be visible to all agents in the system. 2336c2d2e8aSJens Wiklander */ 2346c2d2e8aSJens Wiklander while (io_read32(gicr_base + GICR_CTLR) & GICR_CTLR_RWP) 2356c2d2e8aSJens Wiklander ; 2366c2d2e8aSJens Wiklander } 2376c2d2e8aSJens Wiklander 2389e935234SJens Wiklander static void gicv3_sync_redist_config(struct gic_data *gd) 23984603456SJens Wiklander { 24084603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 24184603456SJens Wiklander bool need_sync = false; 24284603456SJens Wiklander uint32_t gmod0 = 0; 24384603456SJens Wiklander uint32_t grp0 = 0; 24484603456SJens Wiklander size_t n = 0; 24584603456SJens Wiklander 2467c4883aeSJens Wiklander /* 2477c4883aeSJens Wiklander * If gicr_base isn't available there's no need to synchronize SGI 2487c4883aeSJens Wiklander * configuration since gic_init_donate_sgi_to_ns() would panic. 2497c4883aeSJens Wiklander */ 25084603456SJens Wiklander if (!gicr_base) 2517c4883aeSJens Wiklander return; 25284603456SJens Wiklander 25384603456SJens Wiklander grp0 = io_read32(gicr_base + GICR_IGROUPR0); 25484603456SJens Wiklander gmod0 = io_read32(gicr_base + GICR_IGRPMODR0); 2559e935234SJens Wiklander for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) { 25684603456SJens Wiklander /* Ignore matching bits */ 25784603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) && 25884603456SJens Wiklander !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier))) 25984603456SJens Wiklander continue; 26084603456SJens Wiklander /* 2619e935234SJens Wiklander * SGI/PPI-n differs from primary CPU configuration, 26284603456SJens Wiklander * let's sync up. 26384603456SJens Wiklander */ 26484603456SJens Wiklander need_sync = true; 26584603456SJens Wiklander 26684603456SJens Wiklander /* Disable interrupt */ 26784603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(n)); 26884603456SJens Wiklander 2696c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */ 2706c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base); 2716c2d2e8aSJens Wiklander 27284603456SJens Wiklander /* Make interrupt non-pending */ 27384603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(n)); 27484603456SJens Wiklander 27584603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status) 27684603456SJens Wiklander grp0 |= BIT32(n); 27784603456SJens Wiklander else 27884603456SJens Wiklander grp0 &= ~BIT32(n); 27984603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_modifier) 28084603456SJens Wiklander gmod0 |= BIT32(n); 28184603456SJens Wiklander else 28284603456SJens Wiklander gmod0 &= ~BIT32(n); 28384603456SJens Wiklander } 28484603456SJens Wiklander 28584603456SJens Wiklander if (need_sync) { 28684603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, grp0); 28784603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, gmod0); 2889e935234SJens Wiklander io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable); 28984603456SJens Wiklander } 29084603456SJens Wiklander } 29184603456SJens Wiklander 2929e935234SJens Wiklander static void gic_legacy_sync_dist_config(struct gic_data *gd) 29384603456SJens Wiklander { 29484603456SJens Wiklander bool need_sync = false; 29584603456SJens Wiklander uint32_t grp0 = 0; 29684603456SJens Wiklander size_t n = 0; 29784603456SJens Wiklander 29884603456SJens Wiklander grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0)); 2999e935234SJens Wiklander for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) { 30084603456SJens Wiklander /* Ignore matching bits */ 30184603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status))) 30284603456SJens Wiklander continue; 30384603456SJens Wiklander /* 3049e935234SJens Wiklander * SGI/PPI-n differs from primary CPU configuration, 30584603456SJens Wiklander * let's sync up. 30684603456SJens Wiklander */ 30784603456SJens Wiklander need_sync = true; 30884603456SJens Wiklander 30984603456SJens Wiklander /* Disable interrupt */ 31084603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n)); 31184603456SJens Wiklander 31284603456SJens Wiklander /* Make interrupt non-pending */ 31384603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n)); 31484603456SJens Wiklander 31584603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status) 31684603456SJens Wiklander grp0 |= BIT32(n); 31784603456SJens Wiklander else 31884603456SJens Wiklander grp0 &= ~BIT32(n); 31984603456SJens Wiklander } 32084603456SJens Wiklander 3219e935234SJens Wiklander if (need_sync) { 32284603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0); 3239e935234SJens Wiklander io_write32(gd->gicd_base + GICD_ISENABLER(0), 3249e935234SJens Wiklander gd->per_cpu_enable); 3259e935234SJens Wiklander } 32684603456SJens Wiklander } 32784603456SJens Wiklander 3285da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd) 329bedc2b9fSsunny { 33005089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status); 331bedc2b9fSsunny 33205089e5fSJens Wiklander /* 33305089e5fSJens Wiklander * Set the priority mask to permit Non-secure interrupts, and to 33430a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 33530a673e3SPeter Maydell */ 33618901324SDavid Wang #if defined(CFG_ARM_GICV3) 33718901324SDavid Wang write_icc_pmr(0x80); 3381fcac774SSandeep Tripathy write_icc_igrpen1(1); 33918901324SDavid Wang #else 340918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 34130a673e3SPeter Maydell 342bedc2b9fSsunny /* Enable GIC */ 343918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 344918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 345918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 34618901324SDavid Wang #endif 347bedc2b9fSsunny } 348bedc2b9fSsunny 3495da157f5SJens Wiklander void gic_init_per_cpu(void) 3505da157f5SJens Wiklander { 3515da157f5SJens Wiklander struct gic_data *gd = &gic_data; 3525da157f5SJens Wiklander 3535da157f5SJens Wiklander #if defined(CFG_ARM_GICV3) 3545da157f5SJens Wiklander assert(gd->gicd_base); 3555da157f5SJens Wiklander #else 3565da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base); 3575da157f5SJens Wiklander #endif 3585da157f5SJens Wiklander 35984603456SJens Wiklander if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) { 36084603456SJens Wiklander /* 36184603456SJens Wiklander * GIC is already initialized by TF-A, we only need to 3629e935234SJens Wiklander * handle eventual SGI or PPI configuration changes. 36384603456SJens Wiklander */ 3647c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) 3659e935234SJens Wiklander gicv3_sync_redist_config(gd); 36684603456SJens Wiklander else 3679e935234SJens Wiklander gic_legacy_sync_dist_config(gd); 36884603456SJens Wiklander } else { 36984603456SJens Wiklander /* 37084603456SJens Wiklander * Non-TF-A case where all CPU specific configuration 37184603456SJens Wiklander * of GIC must be done here. 37284603456SJens Wiklander */ 3735da157f5SJens Wiklander init_gic_per_cpu(gd); 3745da157f5SJens Wiklander } 37584603456SJens Wiklander } 3765da157f5SJens Wiklander 37784603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it) 37884603456SJens Wiklander { 37984603456SJens Wiklander struct gic_data *gd = &gic_data; 38084603456SJens Wiklander 38184603456SJens Wiklander assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX); 38284603456SJens Wiklander 38384603456SJens Wiklander /* Assert it's secure to start with. */ 38484603456SJens Wiklander assert(!(gd->per_cpu_group_status & BIT32(it)) && 38584603456SJens Wiklander (gd->per_cpu_group_modifier & BIT32(it))); 38684603456SJens Wiklander 38784603456SJens Wiklander gd->per_cpu_group_modifier &= ~BIT32(it); 38884603456SJens Wiklander gd->per_cpu_group_status |= BIT32(it); 38984603456SJens Wiklander 3907c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) { 39184603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 39284603456SJens Wiklander 3937c4883aeSJens Wiklander if (!gicr_base) 3947c4883aeSJens Wiklander panic("GICR_BASE missing"); 3957c4883aeSJens Wiklander 39684603456SJens Wiklander /* Disable interrupt */ 39784603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it)); 39884603456SJens Wiklander 3996c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */ 4006c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base); 4016c2d2e8aSJens Wiklander 40284603456SJens Wiklander /* Make interrupt non-pending */ 40384603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it)); 40484603456SJens Wiklander 40584603456SJens Wiklander /* Make it to non-secure */ 40684603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status); 40784603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, 40884603456SJens Wiklander gd->per_cpu_group_modifier); 40984603456SJens Wiklander } else { 41084603456SJens Wiklander /* Disable interrupt */ 41184603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it)); 41284603456SJens Wiklander 41384603456SJens Wiklander /* Make interrupt non-pending */ 41484603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it)); 41584603456SJens Wiklander 41684603456SJens Wiklander /* Make it to non-secure */ 41784603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), 41884603456SJens Wiklander gd->per_cpu_group_status); 41984603456SJens Wiklander } 42084603456SJens Wiklander } 42184603456SJens Wiklander 4220ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 4230ee3f52eSEtienne Carriere uint32_t *prio) 4240ee3f52eSEtienne Carriere { 4250ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT; 4260ee3f52eSEtienne Carriere 4270ee3f52eSEtienne Carriere if (type) 4280ee3f52eSEtienne Carriere *type = IRQ_TYPE_NONE; 4290ee3f52eSEtienne Carriere 4300ee3f52eSEtienne Carriere if (prio) 4310ee3f52eSEtienne Carriere *prio = 0; 4320ee3f52eSEtienne Carriere 4330ee3f52eSEtienne Carriere if (!properties || count < 2) 4340ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 4350ee3f52eSEtienne Carriere 4360ee3f52eSEtienne Carriere it_num = fdt32_to_cpu(properties[1]); 4370ee3f52eSEtienne Carriere 4380ee3f52eSEtienne Carriere switch (fdt32_to_cpu(properties[0])) { 4398c7282beSEtienne Carriere case GIC_PPI: 4400ee3f52eSEtienne Carriere it_num += 16; 4410ee3f52eSEtienne Carriere break; 4428c7282beSEtienne Carriere case GIC_SPI: 4430ee3f52eSEtienne Carriere it_num += 32; 4440ee3f52eSEtienne Carriere break; 4450ee3f52eSEtienne Carriere default: 4460ee3f52eSEtienne Carriere it_num = DT_INFO_INVALID_INTERRUPT; 4470ee3f52eSEtienne Carriere } 4480ee3f52eSEtienne Carriere 4490ee3f52eSEtienne Carriere return it_num; 4500ee3f52eSEtienne Carriere } 4510ee3f52eSEtienne Carriere 45205089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs, 45305089e5fSJens Wiklander paddr_t gicr_base_pa) 45405089e5fSJens Wiklander { 45505089e5fSJens Wiklander size_t sz = GICR_V3_PCPUBASE_SIZE; 45605089e5fSJens Wiklander paddr_t pa = gicr_base_pa; 45705089e5fSJens Wiklander size_t core_pos = 0; 45805089e5fSJens Wiklander uint64_t mt_bit = 0; 45905089e5fSJens Wiklander uint64_t mpidr = 0; 46005089e5fSJens Wiklander uint64_t tv = 0; 46105089e5fSJens Wiklander vaddr_t va = 0; 46205089e5fSJens Wiklander 46305089e5fSJens Wiklander #ifdef ARM64 46405089e5fSJens Wiklander mt_bit = read_mpidr_el1() & MPIDR_MT_MASK; 46505089e5fSJens Wiklander #endif 46605089e5fSJens Wiklander do { 46705089e5fSJens Wiklander va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz); 46805089e5fSJens Wiklander if (!va) 46905089e5fSJens Wiklander panic(); 47005089e5fSJens Wiklander tv = io_read64(va + GICR_TYPER); 47105089e5fSJens Wiklander 47205089e5fSJens Wiklander /* 47305089e5fSJens Wiklander * Extract an mpidr from the Type register to calculate the 47405089e5fSJens Wiklander * core position of this redistributer instance. 47505089e5fSJens Wiklander */ 47605089e5fSJens Wiklander mpidr = mt_bit; 47705089e5fSJens Wiklander mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) & 47805089e5fSJens Wiklander MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT); 47905089e5fSJens Wiklander mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) & 48005089e5fSJens Wiklander (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK); 48105089e5fSJens Wiklander core_pos = get_core_pos_mpidr(mpidr); 48205089e5fSJens Wiklander if (core_pos < CFG_TEE_CORE_NB_CORE) { 48305089e5fSJens Wiklander DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va); 48405089e5fSJens Wiklander gicr_base_addrs[core_pos] = va; 48505089e5fSJens Wiklander } else { 48605089e5fSJens Wiklander EMSG("Skipping too large core_pos %zu from GICR_TYPER", 48705089e5fSJens Wiklander core_pos); 48805089e5fSJens Wiklander } 48905089e5fSJens Wiklander pa += sz; 49005089e5fSJens Wiklander } while (!(tv & GICR_TYPER_LAST)); 49105089e5fSJens Wiklander } 49205089e5fSJens Wiklander 49305089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 49405089e5fSJens Wiklander paddr_t gicr_base_pa __maybe_unused) 495b0104773SPascal Brand { 49667e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 4970ee3f52eSEtienne Carriere vaddr_t gicc_base = 0; 4980ee3f52eSEtienne Carriere vaddr_t gicd_base = 0; 49969171becSJens Wiklander uint32_t vers __maybe_unused = 0; 5000ee3f52eSEtienne Carriere 5010ee3f52eSEtienne Carriere assert(cpu_mmu_enabled()); 5020ee3f52eSEtienne Carriere 5030ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 5040ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE); 5050ee3f52eSEtienne Carriere if (!gicd_base) 5060ee3f52eSEtienne Carriere panic(); 5070ee3f52eSEtienne Carriere 50869171becSJens Wiklander vers = io_read32(gicd_base + GICD_PIDR2); 50969171becSJens Wiklander vers >>= GICD_PIDR2_ARCHREV_SHIFT; 51069171becSJens Wiklander vers &= GICD_PIDR2_ARCHREV_MASK; 51169171becSJens Wiklander 51269171becSJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3)) { 513dd18bd87SZiad Elhanafy assert(vers == 4 || vers == 3); 51469171becSJens Wiklander } else { 515d3f6526eSJens Wiklander assert(vers == 2 || vers == 1); 5160ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 5170ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE); 5180ee3f52eSEtienne Carriere if (!gicc_base) 5190ee3f52eSEtienne Carriere panic(); 5200ee3f52eSEtienne Carriere } 5210ee3f52eSEtienne Carriere 5220ee3f52eSEtienne Carriere gd->gicc_base = gicc_base; 5230ee3f52eSEtienne Carriere gd->gicd_base = gicd_base; 5240ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base); 52505089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 5267c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd) && gicr_base_pa) 52705089e5fSJens Wiklander probe_redist_base_addrs(gd->gicr_base, gicr_base_pa); 52805089e5fSJens Wiklander #endif 5290ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops; 5300ee3f52eSEtienne Carriere 5310ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT)) 5320ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq; 5330ee3f52eSEtienne Carriere } 5340ee3f52eSEtienne Carriere 53505089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 53605089e5fSJens Wiklander paddr_t gicr_base_pa) 5370ee3f52eSEtienne Carriere { 5380ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data; 5390ee3f52eSEtienne Carriere size_t __maybe_unused n = 0; 540b0104773SPascal Brand 54105089e5fSJens Wiklander gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa); 542b0104773SPascal Brand 54305089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW) 5440ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */ 5457c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) { 5467c4883aeSJens Wiklander /* Secure affinity routing enabled */ 54705089e5fSJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 54805089e5fSJens Wiklander 5497c4883aeSJens Wiklander if (gicr_base) { 5507c4883aeSJens Wiklander gd->per_cpu_group_status = io_read32(gicr_base + 5517c4883aeSJens Wiklander GICR_IGROUPR0); 55205089e5fSJens Wiklander gd->per_cpu_group_modifier = io_read32(gicr_base + 55305089e5fSJens Wiklander GICR_IGRPMODR0); 55405089e5fSJens Wiklander } else { 5557c4883aeSJens Wiklander IMSG("GIC redistributor base address not provided"); 5567c4883aeSJens Wiklander IMSG("Assuming default GIC group status and modifier"); 5577c4883aeSJens Wiklander gd->per_cpu_group_status = 0xffff00ff; 5587c4883aeSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 5597c4883aeSJens Wiklander } 5607c4883aeSJens Wiklander } else { 56105089e5fSJens Wiklander /* Legacy operation with secure affinity routing disabled */ 56205089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gd->gicd_base + 56305089e5fSJens Wiklander GICD_IGROUPR(0)); 56405089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 56505089e5fSJens Wiklander } 56605089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/ 56705089e5fSJens Wiklander /* 56805089e5fSJens Wiklander * Without TF-A, GIC is always configured in for legacy operation 56905089e5fSJens Wiklander * with secure affinity routing disabled. 57005089e5fSJens Wiklander */ 5717315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 572b0104773SPascal Brand /* Disable interrupts */ 573918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 574b0104773SPascal Brand 575b0104773SPascal Brand /* Make interrupts non-pending */ 576918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 577b0104773SPascal Brand 578b0104773SPascal Brand /* Mark interrupts non-secure */ 579bedc2b9fSsunny if (n == 0) { 580bedc2b9fSsunny /* per-CPU inerrupts config: 581bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 582bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 583bedc2b9fSsunny * All PPI config as Non-secure interrupts. 584bedc2b9fSsunny */ 58505089e5fSJens Wiklander gd->per_cpu_group_status = 0xffff00ff; 58605089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 58705089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(n), 58805089e5fSJens Wiklander gd->per_cpu_group_status); 589bedc2b9fSsunny } else { 590918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 591b0104773SPascal Brand } 592bedc2b9fSsunny } 593b0104773SPascal Brand 59430a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 59530a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 59630a673e3SPeter Maydell */ 59718901324SDavid Wang #if defined(CFG_ARM_GICV3) 59818901324SDavid Wang write_icc_pmr(0x80); 5991fcac774SSandeep Tripathy write_icc_igrpen1(1); 6001fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 60118901324SDavid Wang #else 602918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 60330a673e3SPeter Maydell 604b0104773SPascal Brand /* Enable GIC */ 605918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 606918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 607918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 60805089e5fSJens Wiklander GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS); 6091fcac774SSandeep Tripathy #endif 61005089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/ 61167e55c51SEtienne Carriere 61201980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip); 613b0104773SPascal Brand } 614b0104773SPascal Brand 6157315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 616b0104773SPascal Brand { 61753bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 61853bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 619b0104773SPascal Brand 62067e55c51SEtienne Carriere assert(gd == &gic_data); 62167e55c51SEtienne Carriere 622b0104773SPascal Brand /* Disable the interrupt */ 623918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 624b0104773SPascal Brand /* Make it non-pending */ 625918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 626b0104773SPascal Brand /* Assign it to group0 */ 627918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 6281fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 6291fcac774SSandeep Tripathy /* Assign it to group1S */ 6301fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 6311fcac774SSandeep Tripathy #endif 632b0104773SPascal Brand } 633b0104773SPascal Brand 6347315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 6357315b7b4SJens Wiklander uint8_t cpu_mask) 636b0104773SPascal Brand { 6378ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 6388ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 63953bd332aSSY Chiu uint32_t target, target_shift; 640918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 641918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 642b0104773SPascal Brand 64367e55c51SEtienne Carriere assert(gd == &gic_data); 64467e55c51SEtienne Carriere 645b0104773SPascal Brand /* Assigned to group0 */ 646918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 647b0104773SPascal Brand 648b0104773SPascal Brand /* Route it to selected CPUs */ 649918bb3a5SEtienne Carriere target = io_read32(itargetsr); 65053bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 65153bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 65253bd332aSSY Chiu target |= cpu_mask << target_shift; 653918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 654918bb3a5SEtienne Carriere io_write32(itargetsr, target); 655918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 656b0104773SPascal Brand } 657b0104773SPascal Brand 6587315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 659b0104773SPascal Brand { 6608ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 6618ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 662b0104773SPascal Brand 66367e55c51SEtienne Carriere assert(gd == &gic_data); 66467e55c51SEtienne Carriere 665b0104773SPascal Brand /* Assigned to group0 */ 666918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 667b0104773SPascal Brand 668b0104773SPascal Brand /* Set prio it to selected CPUs */ 6691f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 6707315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 671918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 672b0104773SPascal Brand } 673b0104773SPascal Brand 6747315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 675b0104773SPascal Brand { 67653bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 67753bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 678918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 679b0104773SPascal Brand 68067e55c51SEtienne Carriere assert(gd == &gic_data); 68167e55c51SEtienne Carriere 682b0104773SPascal Brand /* Assigned to group0 */ 683918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 684b0104773SPascal Brand 685b0104773SPascal Brand /* Enable the interrupt */ 686918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 687b0104773SPascal Brand } 688b0104773SPascal Brand 6897315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 690b0104773SPascal Brand { 69153bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 69253bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 693b0104773SPascal Brand 69467e55c51SEtienne Carriere assert(gd == &gic_data); 69567e55c51SEtienne Carriere 696b0104773SPascal Brand /* Assigned to group0 */ 697918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 698b0104773SPascal Brand 699b0104773SPascal Brand /* Disable the interrupt */ 700918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 701b0104773SPascal Brand } 702b0104773SPascal Brand 70326ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 70426ed70ecSGuanchao Liang { 70526ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 70626ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 70726ed70ecSGuanchao Liang 70867e55c51SEtienne Carriere assert(gd == &gic_data); 70967e55c51SEtienne Carriere 71026ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 71126ed70ecSGuanchao Liang assert(it >= NUM_SGI); 71226ed70ecSGuanchao Liang 71326ed70ecSGuanchao Liang /* Raise the interrupt */ 714918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 71526ed70ecSGuanchao Liang } 71626ed70ecSGuanchao Liang 717ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask) 718ec740b9fSJens Wiklander { 719ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS; 720ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU; 721ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff; 722ec740b9fSJens Wiklander 723ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */ 724ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1); 725ec740b9fSJens Wiklander } 726ec740b9fSJens Wiklander 72754739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it, 72884603456SJens Wiklander uint32_t cpu_mask, bool ns) 72926ed70ecSGuanchao Liang { 73054739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3) 73154739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf; 732ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24); 733ec740b9fSJens Wiklander 734ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 735ec740b9fSJens Wiklander 736ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 737ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT); 738ec740b9fSJens Wiklander } else { 73954739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr(); 740ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >> 741ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT; 742ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >> 743ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT; 744ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >> 745ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT; 746ec740b9fSJens Wiklander 747ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT); 748ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT); 749ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT); 750ec740b9fSJens Wiklander 751ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 752ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf); 753ec740b9fSJens Wiklander } else { 754ec740b9fSJens Wiklander /* 755ec740b9fSJens Wiklander * Only support sending SGI to the cores in the 756ec740b9fSJens Wiklander * same cluster now. 757ec740b9fSJens Wiklander */ 758ec740b9fSJens Wiklander mask |= cpu_mask & 0xff; 759ec740b9fSJens Wiklander } 760ec740b9fSJens Wiklander } 76154739cb4SMark-PK Tsai 76254739cb4SMark-PK Tsai /* Raise the interrupt */ 76384603456SJens Wiklander if (ns) 76454739cb4SMark-PK Tsai write_icc_asgi1r(mask); 76554739cb4SMark-PK Tsai else 76654739cb4SMark-PK Tsai write_icc_sgi1r(mask); 76754739cb4SMark-PK Tsai #else 768ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK; 76984603456SJens Wiklander uint32_t mask_group = ns; 770ec740b9fSJens Wiklander uint32_t mask = mask_id; 771ec740b9fSJens Wiklander 772ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 773ec740b9fSJens Wiklander 774ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT); 775ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 776ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS, 777ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 778ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 779ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU, 780ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 781ec740b9fSJens Wiklander } else { 782ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff, 783ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT); 784ec740b9fSJens Wiklander } 78526ed70ecSGuanchao Liang 78626ed70ecSGuanchao Liang /* Raise the interrupt */ 787918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 78854739cb4SMark-PK Tsai #endif 78926ed70ecSGuanchao Liang } 79026ed70ecSGuanchao Liang 79118901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 792b0104773SPascal Brand { 79367e55c51SEtienne Carriere assert(gd == &gic_data); 79467e55c51SEtienne Carriere 79518901324SDavid Wang #if defined(CFG_ARM_GICV3) 7961de462e1SSumit Garg return read_icc_iar1(); 79718901324SDavid Wang #else 798918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 79918901324SDavid Wang #endif 800b0104773SPascal Brand } 801b0104773SPascal Brand 80218901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 803b0104773SPascal Brand { 80467e55c51SEtienne Carriere assert(gd == &gic_data); 80567e55c51SEtienne Carriere 80618901324SDavid Wang #if defined(CFG_ARM_GICV3) 8071de462e1SSumit Garg write_icc_eoir1(eoir); 80818901324SDavid Wang #else 809918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 81018901324SDavid Wang #endif 811b0104773SPascal Brand } 812b0104773SPascal Brand 8137315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 8147315b7b4SJens Wiklander { 81553bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 81653bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 81767e55c51SEtienne Carriere 81867e55c51SEtienne Carriere assert(gd == &gic_data); 819918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 82053bd332aSSY Chiu } 82153bd332aSSY Chiu 8227315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 8237315b7b4SJens Wiklander { 82453bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 82553bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 82667e55c51SEtienne Carriere 82767e55c51SEtienne Carriere assert(gd == &gic_data); 828918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 82953bd332aSSY Chiu } 83053bd332aSSY Chiu 8317315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 8327315b7b4SJens Wiklander { 83353bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 8347315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 8357315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 83653bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 837918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 8387315b7b4SJens Wiklander 83967e55c51SEtienne Carriere assert(gd == &gic_data); 840918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 84153bd332aSSY Chiu } 84253bd332aSSY Chiu 84367e55c51SEtienne Carriere void gic_dump_state(void) 84453bd332aSSY Chiu { 84567e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 84667e55c51SEtienne Carriere int i = 0; 84753bd332aSSY Chiu 84818901324SDavid Wang #if defined(CFG_ARM_GICV3) 84918901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 85018901324SDavid Wang #else 851918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 85218901324SDavid Wang #endif 853918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 8547315b7b4SJens Wiklander 8554a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 8567315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 85753bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 8587315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 85953bd332aSSY Chiu } 86053bd332aSSY Chiu } 86153bd332aSSY Chiu } 8627315b7b4SJens Wiklander 863*10cc5912SRunyang Chen TEE_Result gic_spi_release_to_ns(size_t it) 864*10cc5912SRunyang Chen { 865*10cc5912SRunyang Chen struct gic_data *gd = &gic_data; 866*10cc5912SRunyang Chen size_t idx = it / NUM_INTS_PER_REG; 867*10cc5912SRunyang Chen uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 868*10cc5912SRunyang Chen 869*10cc5912SRunyang Chen if (it >= gd->max_it || it < GIC_SPI_BASE) 870*10cc5912SRunyang Chen return TEE_ERROR_BAD_PARAMETERS; 871*10cc5912SRunyang Chen /* Make sure it's already disabled */ 872*10cc5912SRunyang Chen if (!gic_it_is_enabled(gd, it)) 873*10cc5912SRunyang Chen return TEE_ERROR_BAD_STATE; 874*10cc5912SRunyang Chen /* Assert it's secure to start with */ 875*10cc5912SRunyang Chen if (!gic_it_get_group(gd, it)) 876*10cc5912SRunyang Chen return TEE_ERROR_BAD_STATE; 877*10cc5912SRunyang Chen 878*10cc5912SRunyang Chen mutex_lock(&gic_mutex); 879*10cc5912SRunyang Chen gic_it_set_cpu_mask(gd, it, 0); 880*10cc5912SRunyang Chen gic_it_set_prio(gd, it, GIC_SPI_PRI_NS_EL1); 881*10cc5912SRunyang Chen 882*10cc5912SRunyang Chen /* Clear pending status */ 883*10cc5912SRunyang Chen io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 884*10cc5912SRunyang Chen /* Assign it to NS Group1 */ 885*10cc5912SRunyang Chen io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 886*10cc5912SRunyang Chen #if defined(CFG_ARM_GICV3) 887*10cc5912SRunyang Chen io_clrbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 888*10cc5912SRunyang Chen #endif 889*10cc5912SRunyang Chen mutex_unlock(&gic_mutex); 890*10cc5912SRunyang Chen return TEE_SUCCESS; 891*10cc5912SRunyang Chen } 892*10cc5912SRunyang Chen 89367e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void) 8947315b7b4SJens Wiklander { 89567e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 89667e55c51SEtienne Carriere uint32_t iar = 0; 89767e55c51SEtienne Carriere uint32_t id = 0; 8987315b7b4SJens Wiklander 8997315b7b4SJens Wiklander iar = gic_read_iar(gd); 9007315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 9017315b7b4SJens Wiklander 9024a9ea08cSFangsuo Wu if (id <= gd->max_it) 90399e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id); 9043b3a4611SMathieu Briand else 9053b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 9067315b7b4SJens Wiklander 9077315b7b4SJens Wiklander gic_write_eoir(gd, iar); 9087315b7b4SJens Wiklander } 9097315b7b4SJens Wiklander 91067e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI 911358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */ 912358bf47cSEtienne Carriere void interrupt_main_handler(void) 91367e55c51SEtienne Carriere { 91467e55c51SEtienne Carriere gic_native_itr_handler(); 91567e55c51SEtienne Carriere } 91667e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/ 91767e55c51SEtienne Carriere 9187315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 919702fe5a7SClément Léger uint32_t type __unused, 920702fe5a7SClément Léger uint32_t prio __unused) 9217315b7b4SJens Wiklander { 9227315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 9237315b7b4SJens Wiklander 92467e55c51SEtienne Carriere assert(gd == &gic_data); 92567e55c51SEtienne Carriere 9264a9ea08cSFangsuo Wu if (it > gd->max_it) 927d13278b8SEtienne Carriere panic(); 928d13278b8SEtienne Carriere 9299e935234SJens Wiklander if (it < GIC_SPI_BASE) { 9309e935234SJens Wiklander if (gic_primary_done) 9319e935234SJens Wiklander panic("Cannot add SGI or PPI after boot"); 9329e935234SJens Wiklander 9339e935234SJens Wiklander /* Assign it to Secure Group 1, G1S */ 9349e935234SJens Wiklander gd->per_cpu_group_modifier |= BIT32(it); 9359e935234SJens Wiklander gd->per_cpu_group_status &= ~BIT32(it); 9369e935234SJens Wiklander } 9379e935234SJens Wiklander 9389e935234SJens Wiklander if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) { 9399e935234SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 9409e935234SJens Wiklander 9419e935234SJens Wiklander if (!gicr_base) 9429e935234SJens Wiklander panic("GICR_BASE missing"); 9439e935234SJens Wiklander 9449e935234SJens Wiklander /* Disable interrupt */ 9459e935234SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it)); 9469e935234SJens Wiklander 9476c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */ 9486c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base); 9496c2d2e8aSJens Wiklander 9509e935234SJens Wiklander /* Make interrupt non-pending */ 9519e935234SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it)); 9529e935234SJens Wiklander 9539e935234SJens Wiklander /* Make it to Secure */ 9549e935234SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status); 9559e935234SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, 9569e935234SJens Wiklander gd->per_cpu_group_modifier); 9579e935234SJens Wiklander } else { 9587315b7b4SJens Wiklander gic_it_add(gd, it); 9597315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 9607315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 9617315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 9627315b7b4SJens Wiklander } 9639e935234SJens Wiklander } 9647315b7b4SJens Wiklander 9657315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 9667315b7b4SJens Wiklander { 9677315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 9687315b7b4SJens Wiklander 96967e55c51SEtienne Carriere assert(gd == &gic_data); 97067e55c51SEtienne Carriere 9714a9ea08cSFangsuo Wu if (it > gd->max_it) 972d13278b8SEtienne Carriere panic(); 973d13278b8SEtienne Carriere 9749e935234SJens Wiklander if (it < GIC_SPI_BASE) 9759e935234SJens Wiklander gd->per_cpu_enable |= BIT(it); 9769e935234SJens Wiklander 9779e935234SJens Wiklander if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) { 9789e935234SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 9799e935234SJens Wiklander 9809e935234SJens Wiklander if (!gicr_base) 9819e935234SJens Wiklander panic("GICR_BASE missing"); 9829e935234SJens Wiklander 9839e935234SJens Wiklander /* Assigned to G1S */ 9849e935234SJens Wiklander assert(gd->per_cpu_group_modifier & BIT(it) && 9859e935234SJens Wiklander !(gd->per_cpu_group_status & BIT(it))); 9869e935234SJens Wiklander io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable); 9879e935234SJens Wiklander } else { 9887315b7b4SJens Wiklander gic_it_enable(gd, it); 9897315b7b4SJens Wiklander } 9909e935234SJens Wiklander } 9917315b7b4SJens Wiklander 9927315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 9937315b7b4SJens Wiklander { 9947315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 9957315b7b4SJens Wiklander 99667e55c51SEtienne Carriere assert(gd == &gic_data); 99767e55c51SEtienne Carriere 9984a9ea08cSFangsuo Wu if (it > gd->max_it) 999d13278b8SEtienne Carriere panic(); 1000d13278b8SEtienne Carriere 10017315b7b4SJens Wiklander gic_it_disable(gd, it); 10027315b7b4SJens Wiklander } 100326ed70ecSGuanchao Liang 100426ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 100526ed70ecSGuanchao Liang { 100626ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 100726ed70ecSGuanchao Liang 100867e55c51SEtienne Carriere assert(gd == &gic_data); 100967e55c51SEtienne Carriere 10104a9ea08cSFangsuo Wu if (it > gd->max_it) 101126ed70ecSGuanchao Liang panic(); 101226ed70ecSGuanchao Liang 101326ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 101426ed70ecSGuanchao Liang } 101526ed70ecSGuanchao Liang 101626ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 1017ec740b9fSJens Wiklander uint32_t cpu_mask) 101826ed70ecSGuanchao Liang { 101926ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 102084603456SJens Wiklander bool ns = false; 102126ed70ecSGuanchao Liang 102267e55c51SEtienne Carriere assert(gd == &gic_data); 102367e55c51SEtienne Carriere 102454739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */ 102554739cb4SMark-PK Tsai assert(it < NUM_SGI); 102654739cb4SMark-PK Tsai 102784603456SJens Wiklander ns = BIT32(it) & gd->per_cpu_group_status; 102884603456SJens Wiklander gic_it_raise_sgi(gd, it, cpu_mask, ns); 102926ed70ecSGuanchao Liang } 103067e55c51SEtienne Carriere 103126ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 103226ed70ecSGuanchao Liang uint8_t cpu_mask) 103326ed70ecSGuanchao Liang { 103426ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 103526ed70ecSGuanchao Liang 103667e55c51SEtienne Carriere assert(gd == &gic_data); 103767e55c51SEtienne Carriere 10384a9ea08cSFangsuo Wu if (it > gd->max_it) 103926ed70ecSGuanchao Liang panic(); 104026ed70ecSGuanchao Liang 104126ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 104226ed70ecSGuanchao Liang } 104314885eb1SEtienne Carriere 104414885eb1SEtienne Carriere #ifdef CFG_DT 104514885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */ 104614885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data, 104714885eb1SEtienne Carriere struct itr_desc *itr_desc) 104814885eb1SEtienne Carriere { 104914885eb1SEtienne Carriere int itr_num = DT_INFO_INVALID_INTERRUPT; 105014885eb1SEtienne Carriere struct itr_chip *chip = priv_data; 105114885eb1SEtienne Carriere uint32_t phandle_args[2] = { }; 105214885eb1SEtienne Carriere uint32_t type = 0; 105314885eb1SEtienne Carriere uint32_t prio = 0; 105414885eb1SEtienne Carriere 105514885eb1SEtienne Carriere assert(arg && itr_desc); 105614885eb1SEtienne Carriere 105714885eb1SEtienne Carriere /* 105814885eb1SEtienne Carriere * gic_dt_get_irq() expects phandle arguments passed are still in DT 105914885eb1SEtienne Carriere * format (big-endian) whereas struct dt_pargs carries converted 106014885eb1SEtienne Carriere * formats. Therefore swap again phandle arguments. gic_dt_get_irq() 106114885eb1SEtienne Carriere * consumes only the 2 first arguments. 106214885eb1SEtienne Carriere */ 106314885eb1SEtienne Carriere if (arg->args_count < 2) 106414885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 106514885eb1SEtienne Carriere phandle_args[0] = cpu_to_fdt32(arg->args[0]); 106614885eb1SEtienne Carriere phandle_args[1] = cpu_to_fdt32(arg->args[1]); 106714885eb1SEtienne Carriere 106814885eb1SEtienne Carriere itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio); 106914885eb1SEtienne Carriere if (itr_num == DT_INFO_INVALID_INTERRUPT) 107014885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 107114885eb1SEtienne Carriere 107214885eb1SEtienne Carriere gic_op_add(chip, itr_num, type, prio); 107314885eb1SEtienne Carriere 107414885eb1SEtienne Carriere itr_desc->chip = chip; 107514885eb1SEtienne Carriere itr_desc->itr_num = itr_num; 107614885eb1SEtienne Carriere 107714885eb1SEtienne Carriere return TEE_SUCCESS; 107814885eb1SEtienne Carriere } 107914885eb1SEtienne Carriere 108014885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused) 108114885eb1SEtienne Carriere { 108214885eb1SEtienne Carriere if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb, 108314885eb1SEtienne Carriere &gic_data.chip)) 108414885eb1SEtienne Carriere panic(); 108514885eb1SEtienne Carriere 108614885eb1SEtienne Carriere return TEE_SUCCESS; 108714885eb1SEtienne Carriere } 108814885eb1SEtienne Carriere 108914885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = { 109014885eb1SEtienne Carriere { .compatible = "arm,cortex-a15-gic" }, 109114885eb1SEtienne Carriere { .compatible = "arm,cortex-a7-gic" }, 109214885eb1SEtienne Carriere { .compatible = "arm,cortex-a5-gic" }, 109314885eb1SEtienne Carriere { .compatible = "arm,cortex-a9-gic" }, 109414885eb1SEtienne Carriere { .compatible = "arm,gic-400" }, 109514885eb1SEtienne Carriere { } 109614885eb1SEtienne Carriere }; 109714885eb1SEtienne Carriere 109814885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = { 109914885eb1SEtienne Carriere .name = "gic", 110014885eb1SEtienne Carriere .match_table = gic_match_table, 110114885eb1SEtienne Carriere .probe = gic_probe, 110214885eb1SEtienne Carriere }; 110314885eb1SEtienne Carriere #endif /*CFG_DT*/ 11049e935234SJens Wiklander 11059e935234SJens Wiklander static TEE_Result gic_set_primary_done(void) 11069e935234SJens Wiklander { 11079e935234SJens Wiklander gic_primary_done = true; 11089e935234SJens Wiklander return TEE_SUCCESS; 11099e935234SJens Wiklander } 11109e935234SJens Wiklander 11119e935234SJens Wiklander nex_release_init_resource(gic_set_primary_done); 1112