11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2b0104773SPascal Brand /* 318901324SDavid Wang * Copyright (c) 2016-2017, 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> 967729d8dSLudovic Barre #include <config.h> 1067e55c51SEtienne Carriere #include <compiler.h> 11b0104773SPascal Brand #include <drivers/gic.h> 120f93de74SEtienne Carriere #include <keep.h> 1367729d8dSLudovic Barre #include <kernel/dt.h> 147315b7b4SJens Wiklander #include <kernel/interrupt.h> 15d13278b8SEtienne Carriere #include <kernel/panic.h> 1660801696SVolodymyr Babchuk #include <mm/core_memprot.h> 1760801696SVolodymyr Babchuk #include <mm/core_mmu.h> 1867729d8dSLudovic Barre #include <libfdt.h> 197315b7b4SJens Wiklander #include <util.h> 20b0104773SPascal Brand #include <io.h> 214de4bebcSJens Wiklander #include <trace.h> 22b0104773SPascal Brand 23b0104773SPascal Brand /* Offsets from gic.gicc_base */ 24b0104773SPascal Brand #define GICC_CTLR (0x000) 2530a673e3SPeter Maydell #define GICC_PMR (0x004) 26b0104773SPascal Brand #define GICC_IAR (0x00C) 27b0104773SPascal Brand #define GICC_EOIR (0x010) 28b0104773SPascal Brand 29b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0) 30b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1) 311fcac774SSandeep Tripathy #define GICD_CTLR_ENABLEGRP1S (1 << 2) 32b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3) 33b0104773SPascal Brand 34b0104773SPascal Brand /* Offsets from gic.gicd_base */ 35b0104773SPascal Brand #define GICD_CTLR (0x000) 36b0104773SPascal Brand #define GICD_TYPER (0x004) 37b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4) 38b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4) 39b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4) 4026ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4) 41b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4) 42b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) 43b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4) 441fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 4526ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 46b0104773SPascal Brand 47b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0 (1 << 0) 48b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1 (1 << 1) 49b0104773SPascal Brand 5053bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 5153bd332aSSY Chiu #define NUM_PPI 32 5253bd332aSSY Chiu 5326ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 5426ed70ecSGuanchao Liang #define NUM_SGI 16 5526ed70ecSGuanchao Liang 5626ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 5726ed70ecSGuanchao Liang #define NUM_NS_SGI 8 5826ed70ecSGuanchao Liang 5953bd332aSSY Chiu /* Number of interrupts in one register */ 6053bd332aSSY Chiu #define NUM_INTS_PER_REG 32 6153bd332aSSY Chiu 6253bd332aSSY Chiu /* Number of targets in one register */ 6353bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 6453bd332aSSY Chiu 6553bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 6653bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 6753bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 6853bd332aSSY Chiu 691b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f 707315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 717315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 727315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 73b0104773SPascal Brand 74*ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40 75*ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16 76*ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32 77*ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48 78*ec740b9fSJens Wiklander 79*ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf 80*ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1 81*ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2 82*ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24 83*ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15 84*ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16 85*ec740b9fSJens Wiklander 8667e55c51SEtienne Carriere struct gic_data { 8767e55c51SEtienne Carriere vaddr_t gicc_base; 8867e55c51SEtienne Carriere vaddr_t gicd_base; 8967e55c51SEtienne Carriere size_t max_it; 9067e55c51SEtienne Carriere struct itr_chip chip; 9167e55c51SEtienne Carriere }; 9267e55c51SEtienne Carriere 9367e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss; 9467e55c51SEtienne Carriere 95702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type, 96702fe5a7SClément Léger uint32_t prio); 977315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 987315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 9926ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 10026ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 101*ec740b9fSJens Wiklander uint32_t cpu_mask); 10226ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 10326ed70ecSGuanchao Liang uint8_t cpu_mask); 1047315b7b4SJens Wiklander 1057315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 1067315b7b4SJens Wiklander .add = gic_op_add, 10708ded0e1SEtienne Carriere .mask = gic_op_disable, 10808ded0e1SEtienne Carriere .unmask = gic_op_enable, 1097315b7b4SJens Wiklander .enable = gic_op_enable, 1107315b7b4SJens Wiklander .disable = gic_op_disable, 11126ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 11226ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 11326ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 1147315b7b4SJens Wiklander }; 1153639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 1167315b7b4SJens Wiklander 11718901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 118b0104773SPascal Brand { 119b0104773SPascal Brand int i; 120b0104773SPascal Brand uint32_t old_ctlr; 121b0104773SPascal Brand size_t ret = 0; 1221b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) & 1231b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK; 124b0104773SPascal Brand 125b0104773SPascal Brand /* 126b0104773SPascal Brand * Probe which interrupt number is the largest. 127b0104773SPascal Brand */ 12818901324SDavid Wang #if defined(CFG_ARM_GICV3) 12918901324SDavid Wang old_ctlr = read_icc_ctlr(); 13018901324SDavid Wang write_icc_ctlr(0); 13118901324SDavid Wang #else 132918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 133918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 13418901324SDavid Wang #endif 13579f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 136b0104773SPascal Brand uint32_t old_reg; 137b0104773SPascal Brand uint32_t reg; 138b0104773SPascal Brand int b; 139b0104773SPascal Brand 140918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 141918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 142918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 143918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 14479f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 145007a97a2SJens Wiklander if (BIT32(b) & reg) { 14653bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 147b0104773SPascal Brand goto out; 148b0104773SPascal Brand } 149b0104773SPascal Brand } 150b0104773SPascal Brand } 151b0104773SPascal Brand out: 15218901324SDavid Wang #if defined(CFG_ARM_GICV3) 15318901324SDavid Wang write_icc_ctlr(old_ctlr); 15418901324SDavid Wang #else 155918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 15618901324SDavid Wang #endif 157b0104773SPascal Brand return ret; 158b0104773SPascal Brand } 159b0104773SPascal Brand 16067e55c51SEtienne Carriere void gic_cpu_init(void) 161bedc2b9fSsunny { 16267e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 16367e55c51SEtienne Carriere 16418901324SDavid Wang #if defined(CFG_ARM_GICV3) 16518901324SDavid Wang assert(gd->gicd_base); 16618901324SDavid Wang #else 16705efe1e1SEtienne Carriere assert(gd->gicd_base && gd->gicc_base); 16818901324SDavid Wang #endif 16905efe1e1SEtienne Carriere 170e06e6e74SPeter Maydell /* per-CPU interrupts config: 171bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 172bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 173bedc2b9fSsunny * All PPI config as Non-secure interrupts. 174bedc2b9fSsunny */ 175918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff); 176bedc2b9fSsunny 17730a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 17830a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 17930a673e3SPeter Maydell */ 18018901324SDavid Wang #if defined(CFG_ARM_GICV3) 18118901324SDavid Wang write_icc_pmr(0x80); 1821fcac774SSandeep Tripathy write_icc_igrpen1(1); 18318901324SDavid Wang #else 184918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 18530a673e3SPeter Maydell 186bedc2b9fSsunny /* Enable GIC */ 187918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 188918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 189918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 19018901324SDavid Wang #endif 191bedc2b9fSsunny } 192bedc2b9fSsunny 1930ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 1940ee3f52eSEtienne Carriere uint32_t *prio) 1950ee3f52eSEtienne Carriere { 1960ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT; 1970ee3f52eSEtienne Carriere 1980ee3f52eSEtienne Carriere if (type) 1990ee3f52eSEtienne Carriere *type = IRQ_TYPE_NONE; 2000ee3f52eSEtienne Carriere 2010ee3f52eSEtienne Carriere if (prio) 2020ee3f52eSEtienne Carriere *prio = 0; 2030ee3f52eSEtienne Carriere 2040ee3f52eSEtienne Carriere if (!properties || count < 2) 2050ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 2060ee3f52eSEtienne Carriere 2070ee3f52eSEtienne Carriere it_num = fdt32_to_cpu(properties[1]); 2080ee3f52eSEtienne Carriere 2090ee3f52eSEtienne Carriere switch (fdt32_to_cpu(properties[0])) { 2100ee3f52eSEtienne Carriere case 1: 2110ee3f52eSEtienne Carriere it_num += 16; 2120ee3f52eSEtienne Carriere break; 2130ee3f52eSEtienne Carriere case 0: 2140ee3f52eSEtienne Carriere it_num += 32; 2150ee3f52eSEtienne Carriere break; 2160ee3f52eSEtienne Carriere default: 2170ee3f52eSEtienne Carriere it_num = DT_INFO_INVALID_INTERRUPT; 2180ee3f52eSEtienne Carriere } 2190ee3f52eSEtienne Carriere 2200ee3f52eSEtienne Carriere return it_num; 2210ee3f52eSEtienne Carriere } 2220ee3f52eSEtienne Carriere 2230ee3f52eSEtienne Carriere static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa) 224b0104773SPascal Brand { 22567e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 2260ee3f52eSEtienne Carriere vaddr_t gicc_base = 0; 2270ee3f52eSEtienne Carriere vaddr_t gicd_base = 0; 2280ee3f52eSEtienne Carriere 2290ee3f52eSEtienne Carriere assert(cpu_mmu_enabled()); 2300ee3f52eSEtienne Carriere 2310ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 2320ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE); 2330ee3f52eSEtienne Carriere if (!gicd_base) 2340ee3f52eSEtienne Carriere panic(); 2350ee3f52eSEtienne Carriere 2360ee3f52eSEtienne Carriere if (!IS_ENABLED(CFG_ARM_GICV3)) { 2370ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 2380ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE); 2390ee3f52eSEtienne Carriere if (!gicc_base) 2400ee3f52eSEtienne Carriere panic(); 2410ee3f52eSEtienne Carriere } 2420ee3f52eSEtienne Carriere 2430ee3f52eSEtienne Carriere gd->gicc_base = gicc_base; 2440ee3f52eSEtienne Carriere gd->gicd_base = gicd_base; 2450ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base); 2460ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops; 2470ee3f52eSEtienne Carriere 2480ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT)) 2490ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq; 2500ee3f52eSEtienne Carriere } 2510ee3f52eSEtienne Carriere 2520ee3f52eSEtienne Carriere void gic_init(paddr_t gicc_base_pa, paddr_t gicd_base_pa) 2530ee3f52eSEtienne Carriere { 2540ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data; 2550ee3f52eSEtienne Carriere size_t __maybe_unused n = 0; 256b0104773SPascal Brand 25767e55c51SEtienne Carriere gic_init_base_addr(gicc_base_pa, gicd_base_pa); 258b0104773SPascal Brand 2590ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */ 2600ee3f52eSEtienne Carriere #ifndef CFG_WITH_ARM_TRUSTED_FW 2617315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 262b0104773SPascal Brand /* Disable interrupts */ 263918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 264b0104773SPascal Brand 265b0104773SPascal Brand /* Make interrupts non-pending */ 266918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 267b0104773SPascal Brand 268b0104773SPascal Brand /* Mark interrupts non-secure */ 269bedc2b9fSsunny if (n == 0) { 270bedc2b9fSsunny /* per-CPU inerrupts config: 271bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 272bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 273bedc2b9fSsunny * All PPI config as Non-secure interrupts. 274bedc2b9fSsunny */ 275918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff); 276bedc2b9fSsunny } else { 277918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 278b0104773SPascal Brand } 279bedc2b9fSsunny } 280b0104773SPascal Brand 28130a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 28230a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 28330a673e3SPeter Maydell */ 28418901324SDavid Wang #if defined(CFG_ARM_GICV3) 28518901324SDavid Wang write_icc_pmr(0x80); 2861fcac774SSandeep Tripathy write_icc_igrpen1(1); 2871fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 28818901324SDavid Wang #else 289918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 29030a673e3SPeter Maydell 291b0104773SPascal Brand /* Enable GIC */ 292918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 293918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 294918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 295918bb3a5SEtienne Carriere GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1); 2961fcac774SSandeep Tripathy #endif 2970ee3f52eSEtienne Carriere #endif /*CFG_WITH_ARM_TRUSTED_FW*/ 29867e55c51SEtienne Carriere 29901980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip); 300b0104773SPascal Brand } 301b0104773SPascal Brand 3027315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 303b0104773SPascal Brand { 30453bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 30553bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 306b0104773SPascal Brand 30767e55c51SEtienne Carriere assert(gd == &gic_data); 30867e55c51SEtienne Carriere 309b0104773SPascal Brand /* Disable the interrupt */ 310918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 311b0104773SPascal Brand /* Make it non-pending */ 312918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 313b0104773SPascal Brand /* Assign it to group0 */ 314918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 3151fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 3161fcac774SSandeep Tripathy /* Assign it to group1S */ 3171fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 3181fcac774SSandeep Tripathy #endif 319b0104773SPascal Brand } 320b0104773SPascal Brand 3217315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 3227315b7b4SJens Wiklander uint8_t cpu_mask) 323b0104773SPascal Brand { 3248ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 3258ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 32653bd332aSSY Chiu uint32_t target, target_shift; 327918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 328918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 329b0104773SPascal Brand 33067e55c51SEtienne Carriere assert(gd == &gic_data); 33167e55c51SEtienne Carriere 332b0104773SPascal Brand /* Assigned to group0 */ 333918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 334b0104773SPascal Brand 335b0104773SPascal Brand /* Route it to selected CPUs */ 336918bb3a5SEtienne Carriere target = io_read32(itargetsr); 33753bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 33853bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 33953bd332aSSY Chiu target |= cpu_mask << target_shift; 340918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 341918bb3a5SEtienne Carriere io_write32(itargetsr, target); 342918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 343b0104773SPascal Brand } 344b0104773SPascal Brand 3457315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 346b0104773SPascal Brand { 3478ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 3488ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 349b0104773SPascal Brand 35067e55c51SEtienne Carriere assert(gd == &gic_data); 35167e55c51SEtienne Carriere 352b0104773SPascal Brand /* Assigned to group0 */ 353918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 354b0104773SPascal Brand 355b0104773SPascal Brand /* Set prio it to selected CPUs */ 3561f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 3577315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 358918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 359b0104773SPascal Brand } 360b0104773SPascal Brand 3617315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 362b0104773SPascal Brand { 36353bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 36453bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 365918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 366b0104773SPascal Brand 36767e55c51SEtienne Carriere assert(gd == &gic_data); 36867e55c51SEtienne Carriere 369b0104773SPascal Brand /* Assigned to group0 */ 370918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 371b0104773SPascal Brand 372b0104773SPascal Brand /* Enable the interrupt */ 373918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 374b0104773SPascal Brand } 375b0104773SPascal Brand 3767315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 377b0104773SPascal Brand { 37853bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 37953bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 380b0104773SPascal Brand 38167e55c51SEtienne Carriere assert(gd == &gic_data); 38267e55c51SEtienne Carriere 383b0104773SPascal Brand /* Assigned to group0 */ 384918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 385b0104773SPascal Brand 386b0104773SPascal Brand /* Disable the interrupt */ 387918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 388b0104773SPascal Brand } 389b0104773SPascal Brand 39026ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 39126ed70ecSGuanchao Liang { 39226ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 39326ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 39426ed70ecSGuanchao Liang 39567e55c51SEtienne Carriere assert(gd == &gic_data); 39667e55c51SEtienne Carriere 39726ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 39826ed70ecSGuanchao Liang assert(it >= NUM_SGI); 39926ed70ecSGuanchao Liang 40026ed70ecSGuanchao Liang /* Raise the interrupt */ 401918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 40226ed70ecSGuanchao Liang } 40326ed70ecSGuanchao Liang 404*ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask) 405*ec740b9fSJens Wiklander { 406*ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS; 407*ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU; 408*ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff; 409*ec740b9fSJens Wiklander 410*ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */ 411*ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1); 412*ec740b9fSJens Wiklander } 413*ec740b9fSJens Wiklander 41454739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it, 415*ec740b9fSJens Wiklander uint32_t cpu_mask, uint8_t group) 41626ed70ecSGuanchao Liang { 41754739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3) 41854739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf; 419*ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24); 420*ec740b9fSJens Wiklander 421*ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 422*ec740b9fSJens Wiklander 423*ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 424*ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT); 425*ec740b9fSJens Wiklander } else { 42654739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr(); 427*ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >> 428*ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT; 429*ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >> 430*ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT; 431*ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >> 432*ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT; 433*ec740b9fSJens Wiklander 434*ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT); 435*ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT); 436*ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT); 437*ec740b9fSJens Wiklander 438*ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 439*ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf); 440*ec740b9fSJens Wiklander } else { 441*ec740b9fSJens Wiklander /* 442*ec740b9fSJens Wiklander * Only support sending SGI to the cores in the 443*ec740b9fSJens Wiklander * same cluster now. 444*ec740b9fSJens Wiklander */ 445*ec740b9fSJens Wiklander mask |= cpu_mask & 0xff; 446*ec740b9fSJens Wiklander } 447*ec740b9fSJens Wiklander } 44854739cb4SMark-PK Tsai 44954739cb4SMark-PK Tsai /* Raise the interrupt */ 45054739cb4SMark-PK Tsai if (group) 45154739cb4SMark-PK Tsai write_icc_asgi1r(mask); 45254739cb4SMark-PK Tsai else 45354739cb4SMark-PK Tsai write_icc_sgi1r(mask); 45454739cb4SMark-PK Tsai #else 455*ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK; 45626ed70ecSGuanchao Liang uint32_t mask_group = group & 0x1; 457*ec740b9fSJens Wiklander uint32_t mask = mask_id; 458*ec740b9fSJens Wiklander 459*ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 460*ec740b9fSJens Wiklander 461*ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT); 462*ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 463*ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS, 464*ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 465*ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 466*ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU, 467*ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 468*ec740b9fSJens Wiklander } else { 469*ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff, 470*ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT); 471*ec740b9fSJens Wiklander } 47226ed70ecSGuanchao Liang 47326ed70ecSGuanchao Liang /* Raise the interrupt */ 474918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 47554739cb4SMark-PK Tsai #endif 47626ed70ecSGuanchao Liang } 47726ed70ecSGuanchao Liang 47818901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 479b0104773SPascal Brand { 48067e55c51SEtienne Carriere assert(gd == &gic_data); 48167e55c51SEtienne Carriere 48218901324SDavid Wang #if defined(CFG_ARM_GICV3) 4831de462e1SSumit Garg return read_icc_iar1(); 48418901324SDavid Wang #else 485918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 48618901324SDavid Wang #endif 487b0104773SPascal Brand } 488b0104773SPascal Brand 48918901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 490b0104773SPascal Brand { 49167e55c51SEtienne Carriere assert(gd == &gic_data); 49267e55c51SEtienne Carriere 49318901324SDavid Wang #if defined(CFG_ARM_GICV3) 4941de462e1SSumit Garg write_icc_eoir1(eoir); 49518901324SDavid Wang #else 496918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 49718901324SDavid Wang #endif 498b0104773SPascal Brand } 499b0104773SPascal Brand 5007315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 5017315b7b4SJens Wiklander { 50253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 50353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 50467e55c51SEtienne Carriere 50567e55c51SEtienne Carriere assert(gd == &gic_data); 506918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 50753bd332aSSY Chiu } 50853bd332aSSY Chiu 5097315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 5107315b7b4SJens Wiklander { 51153bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 51253bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 51367e55c51SEtienne Carriere 51467e55c51SEtienne Carriere assert(gd == &gic_data); 515918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 51653bd332aSSY Chiu } 51753bd332aSSY Chiu 5187315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 5197315b7b4SJens Wiklander { 52053bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 5217315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 5227315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 52353bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 524918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 5257315b7b4SJens Wiklander 52667e55c51SEtienne Carriere assert(gd == &gic_data); 527918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 52853bd332aSSY Chiu } 52953bd332aSSY Chiu 53067e55c51SEtienne Carriere void gic_dump_state(void) 53153bd332aSSY Chiu { 53267e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 53367e55c51SEtienne Carriere int i = 0; 53453bd332aSSY Chiu 53518901324SDavid Wang #if defined(CFG_ARM_GICV3) 53618901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 53718901324SDavid Wang #else 538918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 53918901324SDavid Wang #endif 540918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 5417315b7b4SJens Wiklander 5424a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 5437315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 54453bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 5457315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 54653bd332aSSY Chiu } 54753bd332aSSY Chiu } 54853bd332aSSY Chiu } 5497315b7b4SJens Wiklander 55067e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void) 5517315b7b4SJens Wiklander { 55267e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 55367e55c51SEtienne Carriere uint32_t iar = 0; 55467e55c51SEtienne Carriere uint32_t id = 0; 5557315b7b4SJens Wiklander 5567315b7b4SJens Wiklander iar = gic_read_iar(gd); 5577315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 5587315b7b4SJens Wiklander 5594a9ea08cSFangsuo Wu if (id <= gd->max_it) 56099e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id); 5613b3a4611SMathieu Briand else 5623b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 5637315b7b4SJens Wiklander 5647315b7b4SJens Wiklander gic_write_eoir(gd, iar); 5657315b7b4SJens Wiklander } 5667315b7b4SJens Wiklander 56767e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI 568358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */ 569358bf47cSEtienne Carriere void interrupt_main_handler(void) 57067e55c51SEtienne Carriere { 57167e55c51SEtienne Carriere gic_native_itr_handler(); 57267e55c51SEtienne Carriere } 57367e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/ 57467e55c51SEtienne Carriere 5757315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 576702fe5a7SClément Léger uint32_t type __unused, 577702fe5a7SClément Léger uint32_t prio __unused) 5787315b7b4SJens Wiklander { 5797315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 5807315b7b4SJens Wiklander 58167e55c51SEtienne Carriere assert(gd == &gic_data); 58267e55c51SEtienne Carriere 5834a9ea08cSFangsuo Wu if (it > gd->max_it) 584d13278b8SEtienne Carriere panic(); 585d13278b8SEtienne Carriere 5867315b7b4SJens Wiklander gic_it_add(gd, it); 5877315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 5887315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 5897315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 5907315b7b4SJens Wiklander } 5917315b7b4SJens Wiklander 5927315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 5937315b7b4SJens Wiklander { 5947315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 5957315b7b4SJens Wiklander 59667e55c51SEtienne Carriere assert(gd == &gic_data); 59767e55c51SEtienne Carriere 5984a9ea08cSFangsuo Wu if (it > gd->max_it) 599d13278b8SEtienne Carriere panic(); 600d13278b8SEtienne Carriere 6017315b7b4SJens Wiklander gic_it_enable(gd, it); 6027315b7b4SJens Wiklander } 6037315b7b4SJens Wiklander 6047315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 6057315b7b4SJens Wiklander { 6067315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 6077315b7b4SJens Wiklander 60867e55c51SEtienne Carriere assert(gd == &gic_data); 60967e55c51SEtienne Carriere 6104a9ea08cSFangsuo Wu if (it > gd->max_it) 611d13278b8SEtienne Carriere panic(); 612d13278b8SEtienne Carriere 6137315b7b4SJens Wiklander gic_it_disable(gd, it); 6147315b7b4SJens Wiklander } 61526ed70ecSGuanchao Liang 61626ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 61726ed70ecSGuanchao Liang { 61826ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 61926ed70ecSGuanchao Liang 62067e55c51SEtienne Carriere assert(gd == &gic_data); 62167e55c51SEtienne Carriere 6224a9ea08cSFangsuo Wu if (it > gd->max_it) 62326ed70ecSGuanchao Liang panic(); 62426ed70ecSGuanchao Liang 62526ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 62626ed70ecSGuanchao Liang } 62726ed70ecSGuanchao Liang 62826ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 629*ec740b9fSJens Wiklander uint32_t cpu_mask) 63026ed70ecSGuanchao Liang { 63126ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 63226ed70ecSGuanchao Liang 63367e55c51SEtienne Carriere assert(gd == &gic_data); 63467e55c51SEtienne Carriere 63554739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */ 63654739cb4SMark-PK Tsai assert(it < NUM_SGI); 63754739cb4SMark-PK Tsai 6384a9ea08cSFangsuo Wu if (it > gd->max_it) 63926ed70ecSGuanchao Liang panic(); 64026ed70ecSGuanchao Liang 64126ed70ecSGuanchao Liang if (it < NUM_NS_SGI) 64226ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 1); 64326ed70ecSGuanchao Liang else 64426ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 0); 64526ed70ecSGuanchao Liang } 64667e55c51SEtienne Carriere 64726ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 64826ed70ecSGuanchao Liang uint8_t cpu_mask) 64926ed70ecSGuanchao Liang { 65026ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 65126ed70ecSGuanchao Liang 65267e55c51SEtienne Carriere assert(gd == &gic_data); 65367e55c51SEtienne Carriere 6544a9ea08cSFangsuo Wu if (it > gd->max_it) 65526ed70ecSGuanchao Liang panic(); 65626ed70ecSGuanchao Liang 65726ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 65826ed70ecSGuanchao Liang } 659