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> 2010cc5912SRunyang 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) 48141876e4SEtienne Carriere #define GICD_ICFGR(n) (0xc00 + (n) * 4) 491fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 5026ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 51b0104773SPascal Brand 5269171becSJens Wiklander #ifdef CFG_ARM_GICV3 5369171becSJens Wiklander #define GICD_PIDR2 (0xFFE8) 5469171becSJens Wiklander #else 5569171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */ 5669171becSJens Wiklander #define GICD_PIDR2 (0xFE8) 5769171becSJens Wiklander #endif 5869171becSJens Wiklander 5905089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0 BIT32(0) 6005089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS BIT32(1) 6105089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S BIT32(2) 6205089e5fSJens Wiklander #define GICD_CTLR_ARE_S BIT32(4) 6305089e5fSJens Wiklander #define GICD_CTLR_ARE_NS BIT32(5) 6405089e5fSJens Wiklander 6505089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */ 6605089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE (2 * 64 * 1024) 6705089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET (64 * 1024) 6805089e5fSJens Wiklander #define GICR_CTLR (0x00) 6905089e5fSJens Wiklander #define GICR_TYPER (0x08) 7005089e5fSJens Wiklander 7105089e5fSJens Wiklander #define GICR_IGROUPR0 (GICR_SGI_BASE_OFFSET + 0x080) 7205089e5fSJens Wiklander #define GICR_IGRPMODR0 (GICR_SGI_BASE_OFFSET + 0xD00) 7384603456SJens Wiklander #define GICR_ICENABLER0 (GICR_SGI_BASE_OFFSET + 0x180) 7484603456SJens Wiklander #define GICR_ICPENDR0 (GICR_SGI_BASE_OFFSET + 0x280) 759e935234SJens Wiklander #define GICR_ISENABLER0 (GICR_SGI_BASE_OFFSET + 0x100) 769e935234SJens Wiklander #define GICR_ICFGR0 (GICR_SGI_BASE_OFFSET + 0xC00) 779e935234SJens Wiklander #define GICR_ICFGR1 (GICR_SGI_BASE_OFFSET + 0xC04) 789e935234SJens Wiklander #define GICR_IPRIORITYR(n) (GICR_SGI_BASE_OFFSET + 0x400 + (n) * 4) 799e935234SJens Wiklander 806c2d2e8aSJens Wiklander #define GICR_CTLR_RWP BIT32(3) 8105089e5fSJens Wiklander 8205089e5fSJens Wiklander #define GICR_TYPER_LAST BIT64(4) 8305089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT 56 8405089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT 48 8505089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT 40 8605089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT 32 87b0104773SPascal Brand 8869171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */ 8969171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT 4 9069171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK 0xF 9169171becSJens Wiklander 9253bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 9353bd332aSSY Chiu #define NUM_PPI 32 9453bd332aSSY Chiu 9526ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 9626ed70ecSGuanchao Liang #define NUM_SGI 16 9726ed70ecSGuanchao Liang 9826ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 9926ed70ecSGuanchao Liang #define NUM_NS_SGI 8 10026ed70ecSGuanchao Liang 10153bd332aSSY Chiu /* Number of interrupts in one register */ 10253bd332aSSY Chiu #define NUM_INTS_PER_REG 32 10353bd332aSSY Chiu 10453bd332aSSY Chiu /* Number of targets in one register */ 10553bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 10653bd332aSSY Chiu 10753bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 10853bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 10953bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 11053bd332aSSY Chiu 1111b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f 1127315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 1137315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 1147315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 115b0104773SPascal Brand 116ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40 117ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16 118ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32 119ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48 120ec740b9fSJens Wiklander 121ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf 122ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1 123ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2 124ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24 125ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15 126ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16 127ec740b9fSJens Wiklander 128141876e4SEtienne Carriere /* GICD ICFGR bit fields */ 129141876e4SEtienne Carriere #define GICD_ICFGR_TYPE_EDGE 2 130141876e4SEtienne Carriere #define GICD_ICFGR_TYPE_LEVEL 0 131141876e4SEtienne Carriere #define GICD_ICFGR_FIELD_BITS 2 132141876e4SEtienne Carriere #define GICD_ICFGR_FIELD_MASK 0x3 133141876e4SEtienne Carriere #define GICD_ICFGR_NUM_INTS_PER_REG (NUM_INTS_PER_REG / \ 134141876e4SEtienne Carriere GICD_ICFGR_FIELD_BITS) 135141876e4SEtienne Carriere 13667e55c51SEtienne Carriere struct gic_data { 13767e55c51SEtienne Carriere vaddr_t gicc_base; 13867e55c51SEtienne Carriere vaddr_t gicd_base; 13905089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 14005089e5fSJens Wiklander vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE]; 14105089e5fSJens Wiklander #endif 14267e55c51SEtienne Carriere size_t max_it; 14305089e5fSJens Wiklander uint32_t per_cpu_group_status; 14405089e5fSJens Wiklander uint32_t per_cpu_group_modifier; 1459e935234SJens Wiklander uint32_t per_cpu_enable; 14667e55c51SEtienne Carriere struct itr_chip chip; 14767e55c51SEtienne Carriere }; 14867e55c51SEtienne Carriere 1499e935234SJens Wiklander static bool gic_primary_done __nex_bss; 15067e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss; 15110cc5912SRunyang Chen static struct mutex gic_mutex = MUTEX_INITIALIZER; 15267e55c51SEtienne Carriere 153*2a50ce7dSEtienne Carriere static void gic_op_configure(struct itr_chip *chip, size_t it, uint32_t type, 154702fe5a7SClément Léger uint32_t prio); 1557315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 1567315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 15726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 15826ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 159ec740b9fSJens Wiklander uint32_t cpu_mask); 16026ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 16126ed70ecSGuanchao Liang uint8_t cpu_mask); 1627315b7b4SJens Wiklander 1637315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 164*2a50ce7dSEtienne Carriere .configure = gic_op_configure, 16508ded0e1SEtienne Carriere .mask = gic_op_disable, 16608ded0e1SEtienne Carriere .unmask = gic_op_enable, 1677315b7b4SJens Wiklander .enable = gic_op_enable, 1687315b7b4SJens Wiklander .disable = gic_op_disable, 16926ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 17026ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 17126ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 1727315b7b4SJens Wiklander }; 1733639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 1747315b7b4SJens Wiklander 17505089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused) 17605089e5fSJens Wiklander { 17705089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 17805089e5fSJens Wiklander return gd->gicr_base[get_core_pos()]; 17905089e5fSJens Wiklander #else 18005089e5fSJens Wiklander return 0; 18105089e5fSJens Wiklander #endif 18205089e5fSJens Wiklander } 18305089e5fSJens Wiklander 1847c4883aeSJens Wiklander static bool affinity_routing_is_enabled(struct gic_data *gd) 1857c4883aeSJens Wiklander { 1867c4883aeSJens Wiklander return IS_ENABLED(CFG_ARM_GICV3) && 1877c4883aeSJens Wiklander io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S; 1887c4883aeSJens Wiklander } 1897c4883aeSJens Wiklander 19018901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 191b0104773SPascal Brand { 192b012d115SEtienne Carriere int i = 0; 193b012d115SEtienne Carriere uint32_t old_ctlr = 0; 194b0104773SPascal Brand size_t ret = 0; 1951b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) & 1961b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK; 197b0104773SPascal Brand 198b0104773SPascal Brand /* 199b0104773SPascal Brand * Probe which interrupt number is the largest. 200b0104773SPascal Brand */ 20118901324SDavid Wang #if defined(CFG_ARM_GICV3) 20218901324SDavid Wang old_ctlr = read_icc_ctlr(); 20318901324SDavid Wang write_icc_ctlr(0); 20418901324SDavid Wang #else 205918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 206918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 20718901324SDavid Wang #endif 20879f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 209b012d115SEtienne Carriere uint32_t old_reg = 0; 210b012d115SEtienne Carriere uint32_t reg = 0; 211b012d115SEtienne Carriere int b = 0; 212b0104773SPascal Brand 213918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 214918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 215918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 216918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 21779f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 218007a97a2SJens Wiklander if (BIT32(b) & reg) { 21953bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 220b0104773SPascal Brand goto out; 221b0104773SPascal Brand } 222b0104773SPascal Brand } 223b0104773SPascal Brand } 224b0104773SPascal Brand out: 22518901324SDavid Wang #if defined(CFG_ARM_GICV3) 22618901324SDavid Wang write_icc_ctlr(old_ctlr); 22718901324SDavid Wang #else 228918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 22918901324SDavid Wang #endif 230b0104773SPascal Brand return ret; 231b0104773SPascal Brand } 232b0104773SPascal Brand 2336c2d2e8aSJens Wiklander static void gicr_wait_for_pending_write(vaddr_t gicr_base) 2346c2d2e8aSJens Wiklander { 2356c2d2e8aSJens Wiklander /* 2366c2d2e8aSJens Wiklander * Wait for changes to 2376c2d2e8aSJens Wiklander * - GICR_ICENABLER0 2386c2d2e8aSJens Wiklander * - GICR_CTLR.DPG1S 2396c2d2e8aSJens Wiklander * - GICR_CTLR.DPG1NS 2406c2d2e8aSJens Wiklander * - GICR_CTLR.DPG0 2416c2d2e8aSJens Wiklander * to be visible to all agents in the system. 2426c2d2e8aSJens Wiklander */ 2436c2d2e8aSJens Wiklander while (io_read32(gicr_base + GICR_CTLR) & GICR_CTLR_RWP) 2446c2d2e8aSJens Wiklander ; 2456c2d2e8aSJens Wiklander } 2466c2d2e8aSJens Wiklander 2479e935234SJens Wiklander static void gicv3_sync_redist_config(struct gic_data *gd) 24884603456SJens Wiklander { 24984603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 25084603456SJens Wiklander bool need_sync = false; 25184603456SJens Wiklander uint32_t gmod0 = 0; 25284603456SJens Wiklander uint32_t grp0 = 0; 25384603456SJens Wiklander size_t n = 0; 25484603456SJens Wiklander 2557c4883aeSJens Wiklander /* 2567c4883aeSJens Wiklander * If gicr_base isn't available there's no need to synchronize SGI 2577c4883aeSJens Wiklander * configuration since gic_init_donate_sgi_to_ns() would panic. 2587c4883aeSJens Wiklander */ 25984603456SJens Wiklander if (!gicr_base) 2607c4883aeSJens Wiklander return; 26184603456SJens Wiklander 26284603456SJens Wiklander grp0 = io_read32(gicr_base + GICR_IGROUPR0); 26384603456SJens Wiklander gmod0 = io_read32(gicr_base + GICR_IGRPMODR0); 2649e935234SJens Wiklander for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) { 26584603456SJens Wiklander /* Ignore matching bits */ 26684603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) && 26784603456SJens Wiklander !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier))) 26884603456SJens Wiklander continue; 26984603456SJens Wiklander /* 2709e935234SJens Wiklander * SGI/PPI-n differs from primary CPU configuration, 27184603456SJens Wiklander * let's sync up. 27284603456SJens Wiklander */ 27384603456SJens Wiklander need_sync = true; 27484603456SJens Wiklander 27584603456SJens Wiklander /* Disable interrupt */ 27684603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(n)); 27784603456SJens Wiklander 2786c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */ 2796c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base); 2806c2d2e8aSJens Wiklander 28184603456SJens Wiklander /* Make interrupt non-pending */ 28284603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(n)); 28384603456SJens Wiklander 28484603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status) 28584603456SJens Wiklander grp0 |= BIT32(n); 28684603456SJens Wiklander else 28784603456SJens Wiklander grp0 &= ~BIT32(n); 28884603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_modifier) 28984603456SJens Wiklander gmod0 |= BIT32(n); 29084603456SJens Wiklander else 29184603456SJens Wiklander gmod0 &= ~BIT32(n); 29284603456SJens Wiklander } 29384603456SJens Wiklander 29484603456SJens Wiklander if (need_sync) { 29584603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, grp0); 29684603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, gmod0); 2979e935234SJens Wiklander io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable); 29884603456SJens Wiklander } 29984603456SJens Wiklander } 30084603456SJens Wiklander 3019e935234SJens Wiklander static void gic_legacy_sync_dist_config(struct gic_data *gd) 30284603456SJens Wiklander { 30384603456SJens Wiklander bool need_sync = false; 30484603456SJens Wiklander uint32_t grp0 = 0; 30584603456SJens Wiklander size_t n = 0; 30684603456SJens Wiklander 30784603456SJens Wiklander grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0)); 3089e935234SJens Wiklander for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) { 30984603456SJens Wiklander /* Ignore matching bits */ 31084603456SJens Wiklander if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status))) 31184603456SJens Wiklander continue; 31284603456SJens Wiklander /* 3139e935234SJens Wiklander * SGI/PPI-n differs from primary CPU configuration, 31484603456SJens Wiklander * let's sync up. 31584603456SJens Wiklander */ 31684603456SJens Wiklander need_sync = true; 31784603456SJens Wiklander 31884603456SJens Wiklander /* Disable interrupt */ 31984603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n)); 32084603456SJens Wiklander 32184603456SJens Wiklander /* Make interrupt non-pending */ 32284603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n)); 32384603456SJens Wiklander 32484603456SJens Wiklander if (BIT32(n) & gd->per_cpu_group_status) 32584603456SJens Wiklander grp0 |= BIT32(n); 32684603456SJens Wiklander else 32784603456SJens Wiklander grp0 &= ~BIT32(n); 32884603456SJens Wiklander } 32984603456SJens Wiklander 3309e935234SJens Wiklander if (need_sync) { 33184603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0); 3329e935234SJens Wiklander io_write32(gd->gicd_base + GICD_ISENABLER(0), 3339e935234SJens Wiklander gd->per_cpu_enable); 3349e935234SJens Wiklander } 33584603456SJens Wiklander } 33684603456SJens Wiklander 3375da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd) 338bedc2b9fSsunny { 33905089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status); 340bedc2b9fSsunny 34105089e5fSJens Wiklander /* 34205089e5fSJens Wiklander * Set the priority mask to permit Non-secure interrupts, and to 34330a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 34430a673e3SPeter Maydell */ 34518901324SDavid Wang #if defined(CFG_ARM_GICV3) 34618901324SDavid Wang write_icc_pmr(0x80); 3471fcac774SSandeep Tripathy write_icc_igrpen1(1); 34818901324SDavid Wang #else 349918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 35030a673e3SPeter Maydell 351bedc2b9fSsunny /* Enable GIC */ 352918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 353918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 354918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 35518901324SDavid Wang #endif 356bedc2b9fSsunny } 357bedc2b9fSsunny 3585da157f5SJens Wiklander void gic_init_per_cpu(void) 3595da157f5SJens Wiklander { 3605da157f5SJens Wiklander struct gic_data *gd = &gic_data; 3615da157f5SJens Wiklander 3625da157f5SJens Wiklander #if defined(CFG_ARM_GICV3) 3635da157f5SJens Wiklander assert(gd->gicd_base); 3645da157f5SJens Wiklander #else 3655da157f5SJens Wiklander assert(gd->gicd_base && gd->gicc_base); 3665da157f5SJens Wiklander #endif 3675da157f5SJens Wiklander 36884603456SJens Wiklander if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) { 36984603456SJens Wiklander /* 37084603456SJens Wiklander * GIC is already initialized by TF-A, we only need to 3719e935234SJens Wiklander * handle eventual SGI or PPI configuration changes. 37284603456SJens Wiklander */ 3737c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) 3749e935234SJens Wiklander gicv3_sync_redist_config(gd); 37584603456SJens Wiklander else 3769e935234SJens Wiklander gic_legacy_sync_dist_config(gd); 37784603456SJens Wiklander } else { 37884603456SJens Wiklander /* 37984603456SJens Wiklander * Non-TF-A case where all CPU specific configuration 38084603456SJens Wiklander * of GIC must be done here. 38184603456SJens Wiklander */ 3825da157f5SJens Wiklander init_gic_per_cpu(gd); 3835da157f5SJens Wiklander } 38484603456SJens Wiklander } 3855da157f5SJens Wiklander 38684603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it) 38784603456SJens Wiklander { 38884603456SJens Wiklander struct gic_data *gd = &gic_data; 38984603456SJens Wiklander 39084603456SJens Wiklander assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX); 39184603456SJens Wiklander 39284603456SJens Wiklander /* Assert it's secure to start with. */ 39384603456SJens Wiklander assert(!(gd->per_cpu_group_status & BIT32(it)) && 39484603456SJens Wiklander (gd->per_cpu_group_modifier & BIT32(it))); 39584603456SJens Wiklander 39684603456SJens Wiklander gd->per_cpu_group_modifier &= ~BIT32(it); 39784603456SJens Wiklander gd->per_cpu_group_status |= BIT32(it); 39884603456SJens Wiklander 3997c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) { 40084603456SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 40184603456SJens Wiklander 4027c4883aeSJens Wiklander if (!gicr_base) 4037c4883aeSJens Wiklander panic("GICR_BASE missing"); 4047c4883aeSJens Wiklander 40584603456SJens Wiklander /* Disable interrupt */ 40684603456SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it)); 40784603456SJens Wiklander 4086c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */ 4096c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base); 4106c2d2e8aSJens Wiklander 41184603456SJens Wiklander /* Make interrupt non-pending */ 41284603456SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it)); 41384603456SJens Wiklander 41484603456SJens Wiklander /* Make it to non-secure */ 41584603456SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status); 41684603456SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, 41784603456SJens Wiklander gd->per_cpu_group_modifier); 41884603456SJens Wiklander } else { 41984603456SJens Wiklander /* Disable interrupt */ 42084603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it)); 42184603456SJens Wiklander 42284603456SJens Wiklander /* Make interrupt non-pending */ 42384603456SJens Wiklander io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it)); 42484603456SJens Wiklander 42584603456SJens Wiklander /* Make it to non-secure */ 42684603456SJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(0), 42784603456SJens Wiklander gd->per_cpu_group_status); 42884603456SJens Wiklander } 42984603456SJens Wiklander } 43084603456SJens Wiklander 4310ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 4320ee3f52eSEtienne Carriere uint32_t *prio) 4330ee3f52eSEtienne Carriere { 4340ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT; 435141876e4SEtienne Carriere uint32_t detection_type = IRQ_TYPE_NONE; 436141876e4SEtienne Carriere uint32_t interrupt_type = GIC_PPI; 4370ee3f52eSEtienne Carriere 438141876e4SEtienne Carriere if (!properties || count < 2 || count > 3) 4390ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 4400ee3f52eSEtienne Carriere 441141876e4SEtienne Carriere interrupt_type = fdt32_to_cpu(properties[0]); 442141876e4SEtienne Carriere it_num = (int)fdt32_to_cpu(properties[1]); 4430ee3f52eSEtienne Carriere 444141876e4SEtienne Carriere if (count == 3) { 445141876e4SEtienne Carriere detection_type = fdt32_to_cpu(properties[2]) & GENMASK_32(3, 0); 446141876e4SEtienne Carriere if (interrupt_type == GIC_PPI && 447141876e4SEtienne Carriere detection_type != IRQ_TYPE_EDGE_RISING) { 448141876e4SEtienne Carriere EMSG("PPI must be edge rising"); 449141876e4SEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 450141876e4SEtienne Carriere } 451141876e4SEtienne Carriere 452141876e4SEtienne Carriere if (interrupt_type == GIC_SPI && 453141876e4SEtienne Carriere (detection_type != IRQ_TYPE_EDGE_RISING && 454141876e4SEtienne Carriere detection_type != IRQ_TYPE_LEVEL_HIGH)) { 455141876e4SEtienne Carriere EMSG("SPI must be edge rising or high level"); 456141876e4SEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 457141876e4SEtienne Carriere } 458141876e4SEtienne Carriere } 459141876e4SEtienne Carriere 460141876e4SEtienne Carriere switch (interrupt_type) { 4618c7282beSEtienne Carriere case GIC_PPI: 4620ee3f52eSEtienne Carriere it_num += 16; 463141876e4SEtienne Carriere detection_type = IRQ_TYPE_EDGE_RISING; 4640ee3f52eSEtienne Carriere break; 4658c7282beSEtienne Carriere case GIC_SPI: 4660ee3f52eSEtienne Carriere it_num += 32; 4670ee3f52eSEtienne Carriere break; 4680ee3f52eSEtienne Carriere default: 469141876e4SEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 4700ee3f52eSEtienne Carriere } 4710ee3f52eSEtienne Carriere 472141876e4SEtienne Carriere if (type) 473141876e4SEtienne Carriere *type = detection_type; 474141876e4SEtienne Carriere 475141876e4SEtienne Carriere if (prio) 476141876e4SEtienne Carriere *prio = 0; 477141876e4SEtienne Carriere 4780ee3f52eSEtienne Carriere return it_num; 4790ee3f52eSEtienne Carriere } 4800ee3f52eSEtienne Carriere 48105089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs, 48205089e5fSJens Wiklander paddr_t gicr_base_pa) 48305089e5fSJens Wiklander { 48405089e5fSJens Wiklander size_t sz = GICR_V3_PCPUBASE_SIZE; 48505089e5fSJens Wiklander paddr_t pa = gicr_base_pa; 48605089e5fSJens Wiklander size_t core_pos = 0; 48705089e5fSJens Wiklander uint64_t mt_bit = 0; 48805089e5fSJens Wiklander uint64_t mpidr = 0; 48905089e5fSJens Wiklander uint64_t tv = 0; 49005089e5fSJens Wiklander vaddr_t va = 0; 49105089e5fSJens Wiklander 49205089e5fSJens Wiklander #ifdef ARM64 49305089e5fSJens Wiklander mt_bit = read_mpidr_el1() & MPIDR_MT_MASK; 49405089e5fSJens Wiklander #endif 49505089e5fSJens Wiklander do { 49605089e5fSJens Wiklander va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz); 49705089e5fSJens Wiklander if (!va) 49805089e5fSJens Wiklander panic(); 49905089e5fSJens Wiklander tv = io_read64(va + GICR_TYPER); 50005089e5fSJens Wiklander 50105089e5fSJens Wiklander /* 50205089e5fSJens Wiklander * Extract an mpidr from the Type register to calculate the 50305089e5fSJens Wiklander * core position of this redistributer instance. 50405089e5fSJens Wiklander */ 50505089e5fSJens Wiklander mpidr = mt_bit; 50605089e5fSJens Wiklander mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) & 50705089e5fSJens Wiklander MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT); 50805089e5fSJens Wiklander mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) & 50905089e5fSJens Wiklander (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK); 51005089e5fSJens Wiklander core_pos = get_core_pos_mpidr(mpidr); 51105089e5fSJens Wiklander if (core_pos < CFG_TEE_CORE_NB_CORE) { 51205089e5fSJens Wiklander DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va); 51305089e5fSJens Wiklander gicr_base_addrs[core_pos] = va; 51405089e5fSJens Wiklander } else { 51505089e5fSJens Wiklander EMSG("Skipping too large core_pos %zu from GICR_TYPER", 51605089e5fSJens Wiklander core_pos); 51705089e5fSJens Wiklander } 51805089e5fSJens Wiklander pa += sz; 51905089e5fSJens Wiklander } while (!(tv & GICR_TYPER_LAST)); 52005089e5fSJens Wiklander } 52105089e5fSJens Wiklander 52205089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 52305089e5fSJens Wiklander paddr_t gicr_base_pa __maybe_unused) 524b0104773SPascal Brand { 52567e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 5260ee3f52eSEtienne Carriere vaddr_t gicc_base = 0; 5270ee3f52eSEtienne Carriere vaddr_t gicd_base = 0; 52869171becSJens Wiklander uint32_t vers __maybe_unused = 0; 5290ee3f52eSEtienne Carriere 5300ee3f52eSEtienne Carriere assert(cpu_mmu_enabled()); 5310ee3f52eSEtienne Carriere 5320ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 5330ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE); 5340ee3f52eSEtienne Carriere if (!gicd_base) 5350ee3f52eSEtienne Carriere panic(); 5360ee3f52eSEtienne Carriere 53769171becSJens Wiklander vers = io_read32(gicd_base + GICD_PIDR2); 53869171becSJens Wiklander vers >>= GICD_PIDR2_ARCHREV_SHIFT; 53969171becSJens Wiklander vers &= GICD_PIDR2_ARCHREV_MASK; 54069171becSJens Wiklander 54169171becSJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3)) { 542dd18bd87SZiad Elhanafy assert(vers == 4 || vers == 3); 54369171becSJens Wiklander } else { 544d3f6526eSJens Wiklander assert(vers == 2 || vers == 1); 5450ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 5460ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE); 5470ee3f52eSEtienne Carriere if (!gicc_base) 5480ee3f52eSEtienne Carriere panic(); 5490ee3f52eSEtienne Carriere } 5500ee3f52eSEtienne Carriere 5510ee3f52eSEtienne Carriere gd->gicc_base = gicc_base; 5520ee3f52eSEtienne Carriere gd->gicd_base = gicd_base; 5530ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base); 55405089e5fSJens Wiklander #if defined(CFG_ARM_GICV3) 5557c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd) && gicr_base_pa) 55605089e5fSJens Wiklander probe_redist_base_addrs(gd->gicr_base, gicr_base_pa); 55705089e5fSJens Wiklander #endif 5580ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops; 5590ee3f52eSEtienne Carriere 5600ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT)) 5610ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq; 5620ee3f52eSEtienne Carriere } 5630ee3f52eSEtienne Carriere 56405089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa, 56505089e5fSJens Wiklander paddr_t gicr_base_pa) 5660ee3f52eSEtienne Carriere { 5670ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data; 5680ee3f52eSEtienne Carriere size_t __maybe_unused n = 0; 569b0104773SPascal Brand 57005089e5fSJens Wiklander gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa); 571b0104773SPascal Brand 57205089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW) 5730ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */ 5747c4883aeSJens Wiklander if (affinity_routing_is_enabled(gd)) { 5757c4883aeSJens Wiklander /* Secure affinity routing enabled */ 57605089e5fSJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 57705089e5fSJens Wiklander 5787c4883aeSJens Wiklander if (gicr_base) { 5797c4883aeSJens Wiklander gd->per_cpu_group_status = io_read32(gicr_base + 5807c4883aeSJens Wiklander GICR_IGROUPR0); 58105089e5fSJens Wiklander gd->per_cpu_group_modifier = io_read32(gicr_base + 58205089e5fSJens Wiklander GICR_IGRPMODR0); 58305089e5fSJens Wiklander } else { 5847c4883aeSJens Wiklander IMSG("GIC redistributor base address not provided"); 5857c4883aeSJens Wiklander IMSG("Assuming default GIC group status and modifier"); 5867c4883aeSJens Wiklander gd->per_cpu_group_status = 0xffff00ff; 5877c4883aeSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 5887c4883aeSJens Wiklander } 5897c4883aeSJens Wiklander } else { 59005089e5fSJens Wiklander /* Legacy operation with secure affinity routing disabled */ 59105089e5fSJens Wiklander gd->per_cpu_group_status = io_read32(gd->gicd_base + 59205089e5fSJens Wiklander GICD_IGROUPR(0)); 59305089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 59405089e5fSJens Wiklander } 59505089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/ 59605089e5fSJens Wiklander /* 59705089e5fSJens Wiklander * Without TF-A, GIC is always configured in for legacy operation 59805089e5fSJens Wiklander * with secure affinity routing disabled. 59905089e5fSJens Wiklander */ 6007315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 601b0104773SPascal Brand /* Disable interrupts */ 602918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 603b0104773SPascal Brand 604b0104773SPascal Brand /* Make interrupts non-pending */ 605918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 606b0104773SPascal Brand 607b0104773SPascal Brand /* Mark interrupts non-secure */ 608bedc2b9fSsunny if (n == 0) { 609bedc2b9fSsunny /* per-CPU inerrupts config: 610bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 611bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 612bedc2b9fSsunny * All PPI config as Non-secure interrupts. 613bedc2b9fSsunny */ 61405089e5fSJens Wiklander gd->per_cpu_group_status = 0xffff00ff; 61505089e5fSJens Wiklander gd->per_cpu_group_modifier = ~gd->per_cpu_group_status; 61605089e5fSJens Wiklander io_write32(gd->gicd_base + GICD_IGROUPR(n), 61705089e5fSJens Wiklander gd->per_cpu_group_status); 618bedc2b9fSsunny } else { 619918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 620b0104773SPascal Brand } 621bedc2b9fSsunny } 622b0104773SPascal Brand 62330a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 62430a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 62530a673e3SPeter Maydell */ 62618901324SDavid Wang #if defined(CFG_ARM_GICV3) 62718901324SDavid Wang write_icc_pmr(0x80); 6281fcac774SSandeep Tripathy write_icc_igrpen1(1); 6291fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 63018901324SDavid Wang #else 631918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 63230a673e3SPeter Maydell 633b0104773SPascal Brand /* Enable GIC */ 634918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 635918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 636918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 63705089e5fSJens Wiklander GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS); 6381fcac774SSandeep Tripathy #endif 63905089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/ 64067e55c51SEtienne Carriere 64101980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip); 642b0104773SPascal Brand } 643b0104773SPascal Brand 644*2a50ce7dSEtienne Carriere static void gic_it_configure(struct gic_data *gd, size_t it) 645b0104773SPascal Brand { 64653bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 64753bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 648b0104773SPascal Brand 64967e55c51SEtienne Carriere assert(gd == &gic_data); 65067e55c51SEtienne Carriere 651b0104773SPascal Brand /* Disable the interrupt */ 652918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 653b0104773SPascal Brand /* Make it non-pending */ 654918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 655b0104773SPascal Brand /* Assign it to group0 */ 656918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 6571fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 6581fcac774SSandeep Tripathy /* Assign it to group1S */ 6591fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 6601fcac774SSandeep Tripathy #endif 661b0104773SPascal Brand } 662b0104773SPascal Brand 6637315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 6647315b7b4SJens Wiklander uint8_t cpu_mask) 665b0104773SPascal Brand { 6668ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 6678ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 668b012d115SEtienne Carriere uint32_t target = 0; 669b012d115SEtienne Carriere uint32_t target_shift = 0; 670918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 671918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 672b0104773SPascal Brand 67367e55c51SEtienne Carriere assert(gd == &gic_data); 67467e55c51SEtienne Carriere 675b0104773SPascal Brand /* Assigned to group0 */ 676918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 677b0104773SPascal Brand 678b0104773SPascal Brand /* Route it to selected CPUs */ 679918bb3a5SEtienne Carriere target = io_read32(itargetsr); 68053bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 68153bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 68253bd332aSSY Chiu target |= cpu_mask << target_shift; 683b012d115SEtienne Carriere DMSG("cpu_mask: writing %#"PRIx32" to %#" PRIxVA, target, itargetsr); 684918bb3a5SEtienne Carriere io_write32(itargetsr, target); 685b012d115SEtienne Carriere DMSG("cpu_mask: %#"PRIx32, io_read32(itargetsr)); 686b0104773SPascal Brand } 687b0104773SPascal Brand 6887315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 689b0104773SPascal Brand { 6908ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 6918ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 692b0104773SPascal Brand 69367e55c51SEtienne Carriere assert(gd == &gic_data); 69467e55c51SEtienne Carriere 695b0104773SPascal Brand /* Assigned to group0 */ 696918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 697b0104773SPascal Brand 698b0104773SPascal Brand /* Set prio it to selected CPUs */ 699b012d115SEtienne Carriere DMSG("prio: writing %#"PRIx8" to %#" PRIxVA, 7007315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 701918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 702b0104773SPascal Brand } 703b0104773SPascal Brand 704141876e4SEtienne Carriere static void gic_it_set_type(struct gic_data *gd, size_t it, uint32_t type) 705141876e4SEtienne Carriere { 706141876e4SEtienne Carriere size_t index = it / GICD_ICFGR_NUM_INTS_PER_REG; 707141876e4SEtienne Carriere uint32_t shift = (it % GICD_ICFGR_NUM_INTS_PER_REG) * 708141876e4SEtienne Carriere GICD_ICFGR_FIELD_BITS; 709141876e4SEtienne Carriere uint32_t icfg = 0; 710141876e4SEtienne Carriere 711141876e4SEtienne Carriere assert(type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH); 712141876e4SEtienne Carriere 713141876e4SEtienne Carriere if (type == IRQ_TYPE_EDGE_RISING) 714141876e4SEtienne Carriere icfg = GICD_ICFGR_TYPE_EDGE; 715141876e4SEtienne Carriere else 716141876e4SEtienne Carriere icfg = GICD_ICFGR_TYPE_LEVEL; 717141876e4SEtienne Carriere 718141876e4SEtienne Carriere io_mask32(gd->gicd_base + GICD_ICFGR(index), 719141876e4SEtienne Carriere SHIFT_U32(icfg, shift), 720141876e4SEtienne Carriere SHIFT_U32(GICD_ICFGR_FIELD_MASK, shift)); 721141876e4SEtienne Carriere } 722141876e4SEtienne Carriere 7237315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 724b0104773SPascal Brand { 72553bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 72653bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 727918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 728b0104773SPascal Brand 72967e55c51SEtienne Carriere assert(gd == &gic_data); 73067e55c51SEtienne Carriere 731b0104773SPascal Brand /* Assigned to group0 */ 732918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 733b0104773SPascal Brand 734b0104773SPascal Brand /* Enable the interrupt */ 735918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 736b0104773SPascal Brand } 737b0104773SPascal Brand 7387315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 739b0104773SPascal Brand { 74053bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 74153bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 742b0104773SPascal Brand 74367e55c51SEtienne Carriere assert(gd == &gic_data); 74467e55c51SEtienne Carriere 745b0104773SPascal Brand /* Assigned to group0 */ 746918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 747b0104773SPascal Brand 748b0104773SPascal Brand /* Disable the interrupt */ 749918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 750b0104773SPascal Brand } 751b0104773SPascal Brand 75226ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 75326ed70ecSGuanchao Liang { 75426ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 75526ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 75626ed70ecSGuanchao Liang 75767e55c51SEtienne Carriere assert(gd == &gic_data); 75867e55c51SEtienne Carriere 75926ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 76026ed70ecSGuanchao Liang assert(it >= NUM_SGI); 76126ed70ecSGuanchao Liang 76226ed70ecSGuanchao Liang /* Raise the interrupt */ 763918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 76426ed70ecSGuanchao Liang } 76526ed70ecSGuanchao Liang 766ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask) 767ec740b9fSJens Wiklander { 768ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS; 769ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU; 770ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff; 771ec740b9fSJens Wiklander 772ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */ 773ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1); 774ec740b9fSJens Wiklander } 775ec740b9fSJens Wiklander 77654739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it, 77784603456SJens Wiklander uint32_t cpu_mask, bool ns) 77826ed70ecSGuanchao Liang { 77954739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3) 78054739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf; 781ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24); 782ec740b9fSJens Wiklander 783ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 784ec740b9fSJens Wiklander 785ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 786ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT); 787ec740b9fSJens Wiklander } else { 78854739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr(); 789ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >> 790ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT; 791ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >> 792ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT; 793ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >> 794ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT; 795ec740b9fSJens Wiklander 796ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT); 797ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT); 798ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT); 799ec740b9fSJens Wiklander 800ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 801ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf); 802ec740b9fSJens Wiklander } else { 803ec740b9fSJens Wiklander /* 804ec740b9fSJens Wiklander * Only support sending SGI to the cores in the 805ec740b9fSJens Wiklander * same cluster now. 806ec740b9fSJens Wiklander */ 807ec740b9fSJens Wiklander mask |= cpu_mask & 0xff; 808ec740b9fSJens Wiklander } 809ec740b9fSJens Wiklander } 81054739cb4SMark-PK Tsai 81154739cb4SMark-PK Tsai /* Raise the interrupt */ 81284603456SJens Wiklander if (ns) 81354739cb4SMark-PK Tsai write_icc_asgi1r(mask); 81454739cb4SMark-PK Tsai else 81554739cb4SMark-PK Tsai write_icc_sgi1r(mask); 81654739cb4SMark-PK Tsai #else 817ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK; 81884603456SJens Wiklander uint32_t mask_group = ns; 819ec740b9fSJens Wiklander uint32_t mask = mask_id; 820ec740b9fSJens Wiklander 821ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 822ec740b9fSJens Wiklander 823ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT); 824ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 825ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS, 826ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 827ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 828ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU, 829ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 830ec740b9fSJens Wiklander } else { 831ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff, 832ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT); 833ec740b9fSJens Wiklander } 83426ed70ecSGuanchao Liang 83526ed70ecSGuanchao Liang /* Raise the interrupt */ 836918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 83754739cb4SMark-PK Tsai #endif 83826ed70ecSGuanchao Liang } 83926ed70ecSGuanchao Liang 84018901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 841b0104773SPascal Brand { 84267e55c51SEtienne Carriere assert(gd == &gic_data); 84367e55c51SEtienne Carriere 84418901324SDavid Wang #if defined(CFG_ARM_GICV3) 8451de462e1SSumit Garg return read_icc_iar1(); 84618901324SDavid Wang #else 847918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 84818901324SDavid Wang #endif 849b0104773SPascal Brand } 850b0104773SPascal Brand 85118901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 852b0104773SPascal Brand { 85367e55c51SEtienne Carriere assert(gd == &gic_data); 85467e55c51SEtienne Carriere 85518901324SDavid Wang #if defined(CFG_ARM_GICV3) 8561de462e1SSumit Garg write_icc_eoir1(eoir); 85718901324SDavid Wang #else 858918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 85918901324SDavid Wang #endif 860b0104773SPascal Brand } 861b0104773SPascal Brand 8627315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 8637315b7b4SJens Wiklander { 86453bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 86553bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 86667e55c51SEtienne Carriere 86767e55c51SEtienne Carriere assert(gd == &gic_data); 868918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 86953bd332aSSY Chiu } 87053bd332aSSY Chiu 8717315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 8727315b7b4SJens Wiklander { 87353bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 87453bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 87567e55c51SEtienne Carriere 87667e55c51SEtienne Carriere assert(gd == &gic_data); 877918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 87853bd332aSSY Chiu } 87953bd332aSSY Chiu 8807315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 8817315b7b4SJens Wiklander { 88253bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 8837315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 8847315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 88553bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 886918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 8877315b7b4SJens Wiklander 88867e55c51SEtienne Carriere assert(gd == &gic_data); 889918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 89053bd332aSSY Chiu } 89153bd332aSSY Chiu 89267e55c51SEtienne Carriere void gic_dump_state(void) 89353bd332aSSY Chiu { 89467e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 89567e55c51SEtienne Carriere int i = 0; 89653bd332aSSY Chiu 89718901324SDavid Wang #if defined(CFG_ARM_GICV3) 898b012d115SEtienne Carriere DMSG("GICC_CTLR: %#"PRIx32, read_icc_ctlr()); 89918901324SDavid Wang #else 900b012d115SEtienne Carriere DMSG("GICC_CTLR: %#"PRIx32, io_read32(gd->gicc_base + GICC_CTLR)); 90118901324SDavid Wang #endif 902b012d115SEtienne Carriere DMSG("GICD_CTLR: %#"PRIx32, io_read32(gd->gicd_base + GICD_CTLR)); 9037315b7b4SJens Wiklander 9044a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 9057315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 906b012d115SEtienne Carriere DMSG("irq%d: enabled, group:%d, target:%#"PRIx32, i, 9077315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 90853bd332aSSY Chiu } 90953bd332aSSY Chiu } 91053bd332aSSY Chiu } 9117315b7b4SJens Wiklander 91210cc5912SRunyang Chen TEE_Result gic_spi_release_to_ns(size_t it) 91310cc5912SRunyang Chen { 91410cc5912SRunyang Chen struct gic_data *gd = &gic_data; 91510cc5912SRunyang Chen size_t idx = it / NUM_INTS_PER_REG; 91610cc5912SRunyang Chen uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 91710cc5912SRunyang Chen 91810cc5912SRunyang Chen if (it >= gd->max_it || it < GIC_SPI_BASE) 91910cc5912SRunyang Chen return TEE_ERROR_BAD_PARAMETERS; 92010cc5912SRunyang Chen /* Make sure it's already disabled */ 92110cc5912SRunyang Chen if (!gic_it_is_enabled(gd, it)) 92210cc5912SRunyang Chen return TEE_ERROR_BAD_STATE; 92310cc5912SRunyang Chen /* Assert it's secure to start with */ 92410cc5912SRunyang Chen if (!gic_it_get_group(gd, it)) 92510cc5912SRunyang Chen return TEE_ERROR_BAD_STATE; 92610cc5912SRunyang Chen 92710cc5912SRunyang Chen mutex_lock(&gic_mutex); 92810cc5912SRunyang Chen gic_it_set_cpu_mask(gd, it, 0); 92910cc5912SRunyang Chen gic_it_set_prio(gd, it, GIC_SPI_PRI_NS_EL1); 93010cc5912SRunyang Chen 93110cc5912SRunyang Chen /* Clear pending status */ 93210cc5912SRunyang Chen io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 93310cc5912SRunyang Chen /* Assign it to NS Group1 */ 93410cc5912SRunyang Chen io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 93510cc5912SRunyang Chen #if defined(CFG_ARM_GICV3) 93610cc5912SRunyang Chen io_clrbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 93710cc5912SRunyang Chen #endif 93810cc5912SRunyang Chen mutex_unlock(&gic_mutex); 93910cc5912SRunyang Chen return TEE_SUCCESS; 94010cc5912SRunyang Chen } 94110cc5912SRunyang Chen 94267e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void) 9437315b7b4SJens Wiklander { 94467e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 94567e55c51SEtienne Carriere uint32_t iar = 0; 94667e55c51SEtienne Carriere uint32_t id = 0; 9477315b7b4SJens Wiklander 9487315b7b4SJens Wiklander iar = gic_read_iar(gd); 9497315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 9507315b7b4SJens Wiklander 9514a9ea08cSFangsuo Wu if (id <= gd->max_it) 95299e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id); 9533b3a4611SMathieu Briand else 9543b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 9557315b7b4SJens Wiklander 9567315b7b4SJens Wiklander gic_write_eoir(gd, iar); 9577315b7b4SJens Wiklander } 9587315b7b4SJens Wiklander 95967e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI 960358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */ 961358bf47cSEtienne Carriere void interrupt_main_handler(void) 96267e55c51SEtienne Carriere { 96367e55c51SEtienne Carriere gic_native_itr_handler(); 96467e55c51SEtienne Carriere } 96567e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/ 96667e55c51SEtienne Carriere 967*2a50ce7dSEtienne Carriere static void gic_op_configure(struct itr_chip *chip, size_t it, 968141876e4SEtienne Carriere uint32_t type, uint32_t prio __unused) 9697315b7b4SJens Wiklander { 9707315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 9717315b7b4SJens Wiklander 97267e55c51SEtienne Carriere assert(gd == &gic_data); 97367e55c51SEtienne Carriere 9744a9ea08cSFangsuo Wu if (it > gd->max_it) 975d13278b8SEtienne Carriere panic(); 976d13278b8SEtienne Carriere 9779e935234SJens Wiklander if (it < GIC_SPI_BASE) { 9789e935234SJens Wiklander if (gic_primary_done) 9799e935234SJens Wiklander panic("Cannot add SGI or PPI after boot"); 9809e935234SJens Wiklander 9819e935234SJens Wiklander /* Assign it to Secure Group 1, G1S */ 9829e935234SJens Wiklander gd->per_cpu_group_modifier |= BIT32(it); 9839e935234SJens Wiklander gd->per_cpu_group_status &= ~BIT32(it); 9849e935234SJens Wiklander } 9859e935234SJens Wiklander 9869e935234SJens Wiklander if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) { 9879e935234SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 9889e935234SJens Wiklander 9899e935234SJens Wiklander if (!gicr_base) 9909e935234SJens Wiklander panic("GICR_BASE missing"); 9919e935234SJens Wiklander 9929e935234SJens Wiklander /* Disable interrupt */ 9939e935234SJens Wiklander io_write32(gicr_base + GICR_ICENABLER0, BIT32(it)); 9949e935234SJens Wiklander 9956c2d2e8aSJens Wiklander /* Wait for the write to GICR_ICENABLER0 to propagate */ 9966c2d2e8aSJens Wiklander gicr_wait_for_pending_write(gicr_base); 9976c2d2e8aSJens Wiklander 9989e935234SJens Wiklander /* Make interrupt non-pending */ 9999e935234SJens Wiklander io_write32(gicr_base + GICR_ICPENDR0, BIT32(it)); 10009e935234SJens Wiklander 10019e935234SJens Wiklander /* Make it to Secure */ 10029e935234SJens Wiklander io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status); 10039e935234SJens Wiklander io_write32(gicr_base + GICR_IGRPMODR0, 10049e935234SJens Wiklander gd->per_cpu_group_modifier); 10059e935234SJens Wiklander } else { 1006*2a50ce7dSEtienne Carriere gic_it_configure(gd, it); 10077315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 10087315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 10097315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 1010141876e4SEtienne Carriere if (type != IRQ_TYPE_NONE) 1011141876e4SEtienne Carriere gic_it_set_type(gd, it, type); 10127315b7b4SJens Wiklander } 10139e935234SJens Wiklander } 10147315b7b4SJens Wiklander 10157315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 10167315b7b4SJens Wiklander { 10177315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 10187315b7b4SJens Wiklander 101967e55c51SEtienne Carriere assert(gd == &gic_data); 102067e55c51SEtienne Carriere 10214a9ea08cSFangsuo Wu if (it > gd->max_it) 1022d13278b8SEtienne Carriere panic(); 1023d13278b8SEtienne Carriere 10249e935234SJens Wiklander if (it < GIC_SPI_BASE) 10259e935234SJens Wiklander gd->per_cpu_enable |= BIT(it); 10269e935234SJens Wiklander 10279e935234SJens Wiklander if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) { 10289e935234SJens Wiklander vaddr_t gicr_base = get_gicr_base(gd); 10299e935234SJens Wiklander 10309e935234SJens Wiklander if (!gicr_base) 10319e935234SJens Wiklander panic("GICR_BASE missing"); 10329e935234SJens Wiklander 10339e935234SJens Wiklander /* Assigned to G1S */ 10349e935234SJens Wiklander assert(gd->per_cpu_group_modifier & BIT(it) && 10359e935234SJens Wiklander !(gd->per_cpu_group_status & BIT(it))); 10369e935234SJens Wiklander io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable); 10379e935234SJens Wiklander } else { 10387315b7b4SJens Wiklander gic_it_enable(gd, it); 10397315b7b4SJens Wiklander } 10409e935234SJens Wiklander } 10417315b7b4SJens Wiklander 10427315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 10437315b7b4SJens Wiklander { 10447315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 10457315b7b4SJens Wiklander 104667e55c51SEtienne Carriere assert(gd == &gic_data); 104767e55c51SEtienne Carriere 10484a9ea08cSFangsuo Wu if (it > gd->max_it) 1049d13278b8SEtienne Carriere panic(); 1050d13278b8SEtienne Carriere 10517315b7b4SJens Wiklander gic_it_disable(gd, it); 10527315b7b4SJens Wiklander } 105326ed70ecSGuanchao Liang 105426ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 105526ed70ecSGuanchao Liang { 105626ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 105726ed70ecSGuanchao Liang 105867e55c51SEtienne Carriere assert(gd == &gic_data); 105967e55c51SEtienne Carriere 10604a9ea08cSFangsuo Wu if (it > gd->max_it) 106126ed70ecSGuanchao Liang panic(); 106226ed70ecSGuanchao Liang 106326ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 106426ed70ecSGuanchao Liang } 106526ed70ecSGuanchao Liang 106626ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 1067ec740b9fSJens Wiklander uint32_t cpu_mask) 106826ed70ecSGuanchao Liang { 106926ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 107084603456SJens Wiklander bool ns = false; 107126ed70ecSGuanchao Liang 107267e55c51SEtienne Carriere assert(gd == &gic_data); 107367e55c51SEtienne Carriere 107454739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */ 107554739cb4SMark-PK Tsai assert(it < NUM_SGI); 107654739cb4SMark-PK Tsai 107784603456SJens Wiklander ns = BIT32(it) & gd->per_cpu_group_status; 107884603456SJens Wiklander gic_it_raise_sgi(gd, it, cpu_mask, ns); 107926ed70ecSGuanchao Liang } 108067e55c51SEtienne Carriere 108126ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 108226ed70ecSGuanchao Liang uint8_t cpu_mask) 108326ed70ecSGuanchao Liang { 108426ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 108526ed70ecSGuanchao Liang 108667e55c51SEtienne Carriere assert(gd == &gic_data); 108767e55c51SEtienne Carriere 10884a9ea08cSFangsuo Wu if (it > gd->max_it) 108926ed70ecSGuanchao Liang panic(); 109026ed70ecSGuanchao Liang 109126ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 109226ed70ecSGuanchao Liang } 109314885eb1SEtienne Carriere 109414885eb1SEtienne Carriere #ifdef CFG_DT 109514885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */ 109614885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data, 109714885eb1SEtienne Carriere struct itr_desc *itr_desc) 109814885eb1SEtienne Carriere { 109914885eb1SEtienne Carriere int itr_num = DT_INFO_INVALID_INTERRUPT; 110014885eb1SEtienne Carriere struct itr_chip *chip = priv_data; 1101141876e4SEtienne Carriere uint32_t phandle_args[3] = { }; 110214885eb1SEtienne Carriere uint32_t type = 0; 110314885eb1SEtienne Carriere uint32_t prio = 0; 110414885eb1SEtienne Carriere 110514885eb1SEtienne Carriere assert(arg && itr_desc); 110614885eb1SEtienne Carriere 110714885eb1SEtienne Carriere /* 110814885eb1SEtienne Carriere * gic_dt_get_irq() expects phandle arguments passed are still in DT 110914885eb1SEtienne Carriere * format (big-endian) whereas struct dt_pargs carries converted 111014885eb1SEtienne Carriere * formats. Therefore swap again phandle arguments. gic_dt_get_irq() 111114885eb1SEtienne Carriere * consumes only the 2 first arguments. 111214885eb1SEtienne Carriere */ 111314885eb1SEtienne Carriere if (arg->args_count < 2) 111414885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 1115141876e4SEtienne Carriere 111614885eb1SEtienne Carriere phandle_args[0] = cpu_to_fdt32(arg->args[0]); 111714885eb1SEtienne Carriere phandle_args[1] = cpu_to_fdt32(arg->args[1]); 1118141876e4SEtienne Carriere if (arg->args_count >= 3) 1119141876e4SEtienne Carriere phandle_args[2] = cpu_to_fdt32(arg->args[2]); 112014885eb1SEtienne Carriere 1121141876e4SEtienne Carriere itr_num = gic_dt_get_irq((const void *)phandle_args, arg->args_count, 1122141876e4SEtienne Carriere &type, &prio); 112314885eb1SEtienne Carriere if (itr_num == DT_INFO_INVALID_INTERRUPT) 112414885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 112514885eb1SEtienne Carriere 1126*2a50ce7dSEtienne Carriere gic_op_configure(chip, itr_num, type, prio); 112714885eb1SEtienne Carriere 112814885eb1SEtienne Carriere itr_desc->chip = chip; 112914885eb1SEtienne Carriere itr_desc->itr_num = itr_num; 113014885eb1SEtienne Carriere 113114885eb1SEtienne Carriere return TEE_SUCCESS; 113214885eb1SEtienne Carriere } 113314885eb1SEtienne Carriere 113414885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused) 113514885eb1SEtienne Carriere { 113614885eb1SEtienne Carriere if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb, 113714885eb1SEtienne Carriere &gic_data.chip)) 113814885eb1SEtienne Carriere panic(); 113914885eb1SEtienne Carriere 114014885eb1SEtienne Carriere return TEE_SUCCESS; 114114885eb1SEtienne Carriere } 114214885eb1SEtienne Carriere 114314885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = { 114414885eb1SEtienne Carriere { .compatible = "arm,cortex-a15-gic" }, 114514885eb1SEtienne Carriere { .compatible = "arm,cortex-a7-gic" }, 114614885eb1SEtienne Carriere { .compatible = "arm,cortex-a5-gic" }, 114714885eb1SEtienne Carriere { .compatible = "arm,cortex-a9-gic" }, 114814885eb1SEtienne Carriere { .compatible = "arm,gic-400" }, 114914885eb1SEtienne Carriere { } 115014885eb1SEtienne Carriere }; 115114885eb1SEtienne Carriere 115214885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = { 115314885eb1SEtienne Carriere .name = "gic", 115414885eb1SEtienne Carriere .match_table = gic_match_table, 115514885eb1SEtienne Carriere .probe = gic_probe, 115614885eb1SEtienne Carriere }; 115714885eb1SEtienne Carriere #endif /*CFG_DT*/ 11589e935234SJens Wiklander 11599e935234SJens Wiklander static TEE_Result gic_set_primary_done(void) 11609e935234SJens Wiklander { 11619e935234SJens Wiklander gic_primary_done = true; 11629e935234SJens Wiklander return TEE_SUCCESS; 11639e935234SJens Wiklander } 11649e935234SJens Wiklander 11659e935234SJens Wiklander nex_release_init_resource(gic_set_primary_done); 1166