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> 98c7282beSEtienne Carriere #include <dt-bindings/interrupt-controller/arm-gic.h> 1067729d8dSLudovic Barre #include <config.h> 1167e55c51SEtienne Carriere #include <compiler.h> 12b0104773SPascal Brand #include <drivers/gic.h> 130f93de74SEtienne Carriere #include <keep.h> 1467729d8dSLudovic Barre #include <kernel/dt.h> 1514885eb1SEtienne Carriere #include <kernel/dt_driver.h> 167315b7b4SJens Wiklander #include <kernel/interrupt.h> 17d13278b8SEtienne Carriere #include <kernel/panic.h> 1860801696SVolodymyr Babchuk #include <mm/core_memprot.h> 1960801696SVolodymyr Babchuk #include <mm/core_mmu.h> 2067729d8dSLudovic Barre #include <libfdt.h> 217315b7b4SJens Wiklander #include <util.h> 22b0104773SPascal Brand #include <io.h> 234de4bebcSJens Wiklander #include <trace.h> 24b0104773SPascal Brand 25b0104773SPascal Brand /* Offsets from gic.gicc_base */ 26b0104773SPascal Brand #define GICC_CTLR (0x000) 2730a673e3SPeter Maydell #define GICC_PMR (0x004) 28b0104773SPascal Brand #define GICC_IAR (0x00C) 29b0104773SPascal Brand #define GICC_EOIR (0x010) 30b0104773SPascal Brand 31b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0) 32b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1) 331fcac774SSandeep Tripathy #define GICD_CTLR_ENABLEGRP1S (1 << 2) 34b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3) 35b0104773SPascal Brand 36b0104773SPascal Brand /* Offsets from gic.gicd_base */ 37b0104773SPascal Brand #define GICD_CTLR (0x000) 38b0104773SPascal Brand #define GICD_TYPER (0x004) 39b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4) 40b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4) 41b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4) 4226ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4) 43b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4) 44b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) 45b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4) 461fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 4726ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 48b0104773SPascal Brand 49*69171becSJens Wiklander #ifdef CFG_ARM_GICV3 50*69171becSJens Wiklander #define GICD_PIDR2 (0xFFE8) 51*69171becSJens Wiklander #else 52*69171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */ 53*69171becSJens Wiklander #define GICD_PIDR2 (0xFE8) 54*69171becSJens Wiklander #endif 55*69171becSJens Wiklander 56b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0 (1 << 0) 57b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1 (1 << 1) 58b0104773SPascal Brand 59*69171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */ 60*69171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT 4 61*69171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK 0xF 62*69171becSJens Wiklander 6353bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 6453bd332aSSY Chiu #define NUM_PPI 32 6553bd332aSSY Chiu 6626ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 6726ed70ecSGuanchao Liang #define NUM_SGI 16 6826ed70ecSGuanchao Liang 6926ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 7026ed70ecSGuanchao Liang #define NUM_NS_SGI 8 7126ed70ecSGuanchao Liang 7253bd332aSSY Chiu /* Number of interrupts in one register */ 7353bd332aSSY Chiu #define NUM_INTS_PER_REG 32 7453bd332aSSY Chiu 7553bd332aSSY Chiu /* Number of targets in one register */ 7653bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 7753bd332aSSY Chiu 7853bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 7953bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 8053bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 8153bd332aSSY Chiu 821b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK 0x1f 837315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 847315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 857315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 86b0104773SPascal Brand 87ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT 40 88ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT 16 89ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT 32 90ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT 48 91ec740b9fSJens Wiklander 92ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK 0xf 93ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS 0x1 94ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU 0x2 95ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT 24 96ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT 15 97ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT 16 98ec740b9fSJens Wiklander 9967e55c51SEtienne Carriere struct gic_data { 10067e55c51SEtienne Carriere vaddr_t gicc_base; 10167e55c51SEtienne Carriere vaddr_t gicd_base; 10267e55c51SEtienne Carriere size_t max_it; 10367e55c51SEtienne Carriere struct itr_chip chip; 10467e55c51SEtienne Carriere }; 10567e55c51SEtienne Carriere 10667e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss; 10767e55c51SEtienne Carriere 108702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type, 109702fe5a7SClément Léger uint32_t prio); 1107315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 1117315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 11226ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 11326ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 114ec740b9fSJens Wiklander uint32_t cpu_mask); 11526ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 11626ed70ecSGuanchao Liang uint8_t cpu_mask); 1177315b7b4SJens Wiklander 1187315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 1197315b7b4SJens Wiklander .add = gic_op_add, 12008ded0e1SEtienne Carriere .mask = gic_op_disable, 12108ded0e1SEtienne Carriere .unmask = gic_op_enable, 1227315b7b4SJens Wiklander .enable = gic_op_enable, 1237315b7b4SJens Wiklander .disable = gic_op_disable, 12426ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 12526ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 12626ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 1277315b7b4SJens Wiklander }; 1283639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 1297315b7b4SJens Wiklander 13018901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 131b0104773SPascal Brand { 132b0104773SPascal Brand int i; 133b0104773SPascal Brand uint32_t old_ctlr; 134b0104773SPascal Brand size_t ret = 0; 1351b4c5002SIzhar Nevo size_t max_regs = io_read32(gicd_base + GICD_TYPER) & 1361b4c5002SIzhar Nevo GICD_TYPER_IT_LINES_NUM_MASK; 137b0104773SPascal Brand 138b0104773SPascal Brand /* 139b0104773SPascal Brand * Probe which interrupt number is the largest. 140b0104773SPascal Brand */ 14118901324SDavid Wang #if defined(CFG_ARM_GICV3) 14218901324SDavid Wang old_ctlr = read_icc_ctlr(); 14318901324SDavid Wang write_icc_ctlr(0); 14418901324SDavid Wang #else 145918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 146918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 14718901324SDavid Wang #endif 14879f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 149b0104773SPascal Brand uint32_t old_reg; 150b0104773SPascal Brand uint32_t reg; 151b0104773SPascal Brand int b; 152b0104773SPascal Brand 153918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 154918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 155918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 156918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 15779f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 158007a97a2SJens Wiklander if (BIT32(b) & reg) { 15953bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 160b0104773SPascal Brand goto out; 161b0104773SPascal Brand } 162b0104773SPascal Brand } 163b0104773SPascal Brand } 164b0104773SPascal Brand out: 16518901324SDavid Wang #if defined(CFG_ARM_GICV3) 16618901324SDavid Wang write_icc_ctlr(old_ctlr); 16718901324SDavid Wang #else 168918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 16918901324SDavid Wang #endif 170b0104773SPascal Brand return ret; 171b0104773SPascal Brand } 172b0104773SPascal Brand 17367e55c51SEtienne Carriere void gic_cpu_init(void) 174bedc2b9fSsunny { 17567e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 17667e55c51SEtienne Carriere 17718901324SDavid Wang #if defined(CFG_ARM_GICV3) 17818901324SDavid Wang assert(gd->gicd_base); 17918901324SDavid Wang #else 18005efe1e1SEtienne Carriere assert(gd->gicd_base && gd->gicc_base); 18118901324SDavid Wang #endif 18205efe1e1SEtienne Carriere 183e06e6e74SPeter Maydell /* per-CPU interrupts config: 184bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 185bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 186bedc2b9fSsunny * All PPI config as Non-secure interrupts. 187bedc2b9fSsunny */ 188918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff); 189bedc2b9fSsunny 19030a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 19130a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 19230a673e3SPeter Maydell */ 19318901324SDavid Wang #if defined(CFG_ARM_GICV3) 19418901324SDavid Wang write_icc_pmr(0x80); 1951fcac774SSandeep Tripathy write_icc_igrpen1(1); 19618901324SDavid Wang #else 197918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 19830a673e3SPeter Maydell 199bedc2b9fSsunny /* Enable GIC */ 200918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 201918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 202918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 20318901324SDavid Wang #endif 204bedc2b9fSsunny } 205bedc2b9fSsunny 2060ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 2070ee3f52eSEtienne Carriere uint32_t *prio) 2080ee3f52eSEtienne Carriere { 2090ee3f52eSEtienne Carriere int it_num = DT_INFO_INVALID_INTERRUPT; 2100ee3f52eSEtienne Carriere 2110ee3f52eSEtienne Carriere if (type) 2120ee3f52eSEtienne Carriere *type = IRQ_TYPE_NONE; 2130ee3f52eSEtienne Carriere 2140ee3f52eSEtienne Carriere if (prio) 2150ee3f52eSEtienne Carriere *prio = 0; 2160ee3f52eSEtienne Carriere 2170ee3f52eSEtienne Carriere if (!properties || count < 2) 2180ee3f52eSEtienne Carriere return DT_INFO_INVALID_INTERRUPT; 2190ee3f52eSEtienne Carriere 2200ee3f52eSEtienne Carriere it_num = fdt32_to_cpu(properties[1]); 2210ee3f52eSEtienne Carriere 2220ee3f52eSEtienne Carriere switch (fdt32_to_cpu(properties[0])) { 2238c7282beSEtienne Carriere case GIC_PPI: 2240ee3f52eSEtienne Carriere it_num += 16; 2250ee3f52eSEtienne Carriere break; 2268c7282beSEtienne Carriere case GIC_SPI: 2270ee3f52eSEtienne Carriere it_num += 32; 2280ee3f52eSEtienne Carriere break; 2290ee3f52eSEtienne Carriere default: 2300ee3f52eSEtienne Carriere it_num = DT_INFO_INVALID_INTERRUPT; 2310ee3f52eSEtienne Carriere } 2320ee3f52eSEtienne Carriere 2330ee3f52eSEtienne Carriere return it_num; 2340ee3f52eSEtienne Carriere } 2350ee3f52eSEtienne Carriere 2360ee3f52eSEtienne Carriere static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa) 237b0104773SPascal Brand { 23867e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 2390ee3f52eSEtienne Carriere vaddr_t gicc_base = 0; 2400ee3f52eSEtienne Carriere vaddr_t gicd_base = 0; 241*69171becSJens Wiklander uint32_t vers __maybe_unused = 0; 2420ee3f52eSEtienne Carriere 2430ee3f52eSEtienne Carriere assert(cpu_mmu_enabled()); 2440ee3f52eSEtienne Carriere 2450ee3f52eSEtienne Carriere gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 2460ee3f52eSEtienne Carriere GIC_DIST_REG_SIZE); 2470ee3f52eSEtienne Carriere if (!gicd_base) 2480ee3f52eSEtienne Carriere panic(); 2490ee3f52eSEtienne Carriere 250*69171becSJens Wiklander vers = io_read32(gicd_base + GICD_PIDR2); 251*69171becSJens Wiklander vers >>= GICD_PIDR2_ARCHREV_SHIFT; 252*69171becSJens Wiklander vers &= GICD_PIDR2_ARCHREV_MASK; 253*69171becSJens Wiklander 254*69171becSJens Wiklander if (IS_ENABLED(CFG_ARM_GICV3)) { 255*69171becSJens Wiklander assert(vers == 3); 256*69171becSJens Wiklander } else { 257*69171becSJens Wiklander assert(vers == 2); 2580ee3f52eSEtienne Carriere gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 2590ee3f52eSEtienne Carriere GIC_CPU_REG_SIZE); 2600ee3f52eSEtienne Carriere if (!gicc_base) 2610ee3f52eSEtienne Carriere panic(); 2620ee3f52eSEtienne Carriere } 2630ee3f52eSEtienne Carriere 2640ee3f52eSEtienne Carriere gd->gicc_base = gicc_base; 2650ee3f52eSEtienne Carriere gd->gicd_base = gicd_base; 2660ee3f52eSEtienne Carriere gd->max_it = probe_max_it(gicc_base, gicd_base); 2670ee3f52eSEtienne Carriere gd->chip.ops = &gic_ops; 2680ee3f52eSEtienne Carriere 2690ee3f52eSEtienne Carriere if (IS_ENABLED(CFG_DT)) 2700ee3f52eSEtienne Carriere gd->chip.dt_get_irq = gic_dt_get_irq; 2710ee3f52eSEtienne Carriere } 2720ee3f52eSEtienne Carriere 2730ee3f52eSEtienne Carriere void gic_init(paddr_t gicc_base_pa, paddr_t gicd_base_pa) 2740ee3f52eSEtienne Carriere { 2750ee3f52eSEtienne Carriere struct gic_data __maybe_unused *gd = &gic_data; 2760ee3f52eSEtienne Carriere size_t __maybe_unused n = 0; 277b0104773SPascal Brand 27867e55c51SEtienne Carriere gic_init_base_addr(gicc_base_pa, gicd_base_pa); 279b0104773SPascal Brand 2800ee3f52eSEtienne Carriere /* GIC configuration is initialized from TF-A when embedded */ 2810ee3f52eSEtienne Carriere #ifndef CFG_WITH_ARM_TRUSTED_FW 2827315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 283b0104773SPascal Brand /* Disable interrupts */ 284918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 285b0104773SPascal Brand 286b0104773SPascal Brand /* Make interrupts non-pending */ 287918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 288b0104773SPascal Brand 289b0104773SPascal Brand /* Mark interrupts non-secure */ 290bedc2b9fSsunny if (n == 0) { 291bedc2b9fSsunny /* per-CPU inerrupts config: 292bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 293bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 294bedc2b9fSsunny * All PPI config as Non-secure interrupts. 295bedc2b9fSsunny */ 296918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff); 297bedc2b9fSsunny } else { 298918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 299b0104773SPascal Brand } 300bedc2b9fSsunny } 301b0104773SPascal Brand 30230a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 30330a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 30430a673e3SPeter Maydell */ 30518901324SDavid Wang #if defined(CFG_ARM_GICV3) 30618901324SDavid Wang write_icc_pmr(0x80); 3071fcac774SSandeep Tripathy write_icc_igrpen1(1); 3081fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 30918901324SDavid Wang #else 310918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 31130a673e3SPeter Maydell 312b0104773SPascal Brand /* Enable GIC */ 313918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 314918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 315918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 316918bb3a5SEtienne Carriere GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1); 3171fcac774SSandeep Tripathy #endif 3180ee3f52eSEtienne Carriere #endif /*CFG_WITH_ARM_TRUSTED_FW*/ 31967e55c51SEtienne Carriere 32001980f3fSEtienne Carriere interrupt_main_init(&gic_data.chip); 321b0104773SPascal Brand } 322b0104773SPascal Brand 3237315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 324b0104773SPascal Brand { 32553bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 32653bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 327b0104773SPascal Brand 32867e55c51SEtienne Carriere assert(gd == &gic_data); 32967e55c51SEtienne Carriere 330b0104773SPascal Brand /* Disable the interrupt */ 331918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 332b0104773SPascal Brand /* Make it non-pending */ 333918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 334b0104773SPascal Brand /* Assign it to group0 */ 335918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 3361fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 3371fcac774SSandeep Tripathy /* Assign it to group1S */ 3381fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 3391fcac774SSandeep Tripathy #endif 340b0104773SPascal Brand } 341b0104773SPascal Brand 3427315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 3437315b7b4SJens Wiklander uint8_t cpu_mask) 344b0104773SPascal Brand { 3458ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 3468ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 34753bd332aSSY Chiu uint32_t target, target_shift; 348918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 349918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 350b0104773SPascal Brand 35167e55c51SEtienne Carriere assert(gd == &gic_data); 35267e55c51SEtienne Carriere 353b0104773SPascal Brand /* Assigned to group0 */ 354918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 355b0104773SPascal Brand 356b0104773SPascal Brand /* Route it to selected CPUs */ 357918bb3a5SEtienne Carriere target = io_read32(itargetsr); 35853bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 35953bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 36053bd332aSSY Chiu target |= cpu_mask << target_shift; 361918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 362918bb3a5SEtienne Carriere io_write32(itargetsr, target); 363918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 364b0104773SPascal Brand } 365b0104773SPascal Brand 3667315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 367b0104773SPascal Brand { 3688ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 3698ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 370b0104773SPascal Brand 37167e55c51SEtienne Carriere assert(gd == &gic_data); 37267e55c51SEtienne Carriere 373b0104773SPascal Brand /* Assigned to group0 */ 374918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 375b0104773SPascal Brand 376b0104773SPascal Brand /* Set prio it to selected CPUs */ 3771f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 3787315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 379918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 380b0104773SPascal Brand } 381b0104773SPascal Brand 3827315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 383b0104773SPascal Brand { 38453bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 38553bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 386918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 387b0104773SPascal Brand 38867e55c51SEtienne Carriere assert(gd == &gic_data); 38967e55c51SEtienne Carriere 390b0104773SPascal Brand /* Assigned to group0 */ 391918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 392b0104773SPascal Brand 393b0104773SPascal Brand /* Enable the interrupt */ 394918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 395b0104773SPascal Brand } 396b0104773SPascal Brand 3977315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 398b0104773SPascal Brand { 39953bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 40053bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 401b0104773SPascal Brand 40267e55c51SEtienne Carriere assert(gd == &gic_data); 40367e55c51SEtienne Carriere 404b0104773SPascal Brand /* Assigned to group0 */ 405918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 406b0104773SPascal Brand 407b0104773SPascal Brand /* Disable the interrupt */ 408918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 409b0104773SPascal Brand } 410b0104773SPascal Brand 41126ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 41226ed70ecSGuanchao Liang { 41326ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 41426ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 41526ed70ecSGuanchao Liang 41667e55c51SEtienne Carriere assert(gd == &gic_data); 41767e55c51SEtienne Carriere 41826ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 41926ed70ecSGuanchao Liang assert(it >= NUM_SGI); 42026ed70ecSGuanchao Liang 42126ed70ecSGuanchao Liang /* Raise the interrupt */ 422918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 42326ed70ecSGuanchao Liang } 42426ed70ecSGuanchao Liang 425ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask) 426ec740b9fSJens Wiklander { 427ec740b9fSJens Wiklander bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS; 428ec740b9fSJens Wiklander bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU; 429ec740b9fSJens Wiklander bool __maybe_unused to_list = cpu_mask & 0xff; 430ec740b9fSJens Wiklander 431ec740b9fSJens Wiklander /* One and only one of the bit fields shall be non-zero */ 432ec740b9fSJens Wiklander assert(to_others + to_current + to_list == 1); 433ec740b9fSJens Wiklander } 434ec740b9fSJens Wiklander 43554739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it, 436ec740b9fSJens Wiklander uint32_t cpu_mask, uint8_t group) 43726ed70ecSGuanchao Liang { 43854739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3) 43954739cb4SMark-PK Tsai uint32_t mask_id = it & 0xf; 440ec740b9fSJens Wiklander uint64_t mask = SHIFT_U64(mask_id, 24); 441ec740b9fSJens Wiklander 442ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 443ec740b9fSJens Wiklander 444ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 445ec740b9fSJens Wiklander mask |= BIT64(GICC_SGI_IRM_BIT); 446ec740b9fSJens Wiklander } else { 44754739cb4SMark-PK Tsai uint64_t mpidr = read_mpidr(); 448ec740b9fSJens Wiklander uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >> 449ec740b9fSJens Wiklander MPIDR_AFF1_SHIFT; 450ec740b9fSJens Wiklander uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >> 451ec740b9fSJens Wiklander MPIDR_AFF2_SHIFT; 452ec740b9fSJens Wiklander uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >> 453ec740b9fSJens Wiklander MPIDR_AFF3_SHIFT; 454ec740b9fSJens Wiklander 455ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT); 456ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT); 457ec740b9fSJens Wiklander mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT); 458ec740b9fSJens Wiklander 459ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 460ec740b9fSJens Wiklander mask |= BIT32(mpidr & 0xf); 461ec740b9fSJens Wiklander } else { 462ec740b9fSJens Wiklander /* 463ec740b9fSJens Wiklander * Only support sending SGI to the cores in the 464ec740b9fSJens Wiklander * same cluster now. 465ec740b9fSJens Wiklander */ 466ec740b9fSJens Wiklander mask |= cpu_mask & 0xff; 467ec740b9fSJens Wiklander } 468ec740b9fSJens Wiklander } 46954739cb4SMark-PK Tsai 47054739cb4SMark-PK Tsai /* Raise the interrupt */ 47154739cb4SMark-PK Tsai if (group) 47254739cb4SMark-PK Tsai write_icc_asgi1r(mask); 47354739cb4SMark-PK Tsai else 47454739cb4SMark-PK Tsai write_icc_sgi1r(mask); 47554739cb4SMark-PK Tsai #else 476ec740b9fSJens Wiklander uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK; 47726ed70ecSGuanchao Liang uint32_t mask_group = group & 0x1; 478ec740b9fSJens Wiklander uint32_t mask = mask_id; 479ec740b9fSJens Wiklander 480ec740b9fSJens Wiklander assert_cpu_mask_is_valid(cpu_mask); 481ec740b9fSJens Wiklander 482ec740b9fSJens Wiklander mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT); 483ec740b9fSJens Wiklander if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) { 484ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS, 485ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 486ec740b9fSJens Wiklander } else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) { 487ec740b9fSJens Wiklander mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU, 488ec740b9fSJens Wiklander GICD_SGIR_TARGET_LIST_FILTER_SHIFT); 489ec740b9fSJens Wiklander } else { 490ec740b9fSJens Wiklander mask |= SHIFT_U32(cpu_mask & 0xff, 491ec740b9fSJens Wiklander GICD_SGIR_CPU_TARGET_LIST_SHIFT); 492ec740b9fSJens Wiklander } 49326ed70ecSGuanchao Liang 49426ed70ecSGuanchao Liang /* Raise the interrupt */ 495918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 49654739cb4SMark-PK Tsai #endif 49726ed70ecSGuanchao Liang } 49826ed70ecSGuanchao Liang 49918901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 500b0104773SPascal Brand { 50167e55c51SEtienne Carriere assert(gd == &gic_data); 50267e55c51SEtienne Carriere 50318901324SDavid Wang #if defined(CFG_ARM_GICV3) 5041de462e1SSumit Garg return read_icc_iar1(); 50518901324SDavid Wang #else 506918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 50718901324SDavid Wang #endif 508b0104773SPascal Brand } 509b0104773SPascal Brand 51018901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 511b0104773SPascal Brand { 51267e55c51SEtienne Carriere assert(gd == &gic_data); 51367e55c51SEtienne Carriere 51418901324SDavid Wang #if defined(CFG_ARM_GICV3) 5151de462e1SSumit Garg write_icc_eoir1(eoir); 51618901324SDavid Wang #else 517918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 51818901324SDavid Wang #endif 519b0104773SPascal Brand } 520b0104773SPascal Brand 5217315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 5227315b7b4SJens Wiklander { 52353bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 52453bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 52567e55c51SEtienne Carriere 52667e55c51SEtienne Carriere assert(gd == &gic_data); 527918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 52853bd332aSSY Chiu } 52953bd332aSSY Chiu 5307315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 5317315b7b4SJens Wiklander { 53253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 53353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 53467e55c51SEtienne Carriere 53567e55c51SEtienne Carriere assert(gd == &gic_data); 536918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 53753bd332aSSY Chiu } 53853bd332aSSY Chiu 5397315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 5407315b7b4SJens Wiklander { 54153bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 5427315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 5437315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 54453bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 545918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 5467315b7b4SJens Wiklander 54767e55c51SEtienne Carriere assert(gd == &gic_data); 548918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 54953bd332aSSY Chiu } 55053bd332aSSY Chiu 55167e55c51SEtienne Carriere void gic_dump_state(void) 55253bd332aSSY Chiu { 55367e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 55467e55c51SEtienne Carriere int i = 0; 55553bd332aSSY Chiu 55618901324SDavid Wang #if defined(CFG_ARM_GICV3) 55718901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 55818901324SDavid Wang #else 559918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 56018901324SDavid Wang #endif 561918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 5627315b7b4SJens Wiklander 5634a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 5647315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 56553bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 5667315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 56753bd332aSSY Chiu } 56853bd332aSSY Chiu } 56953bd332aSSY Chiu } 5707315b7b4SJens Wiklander 57167e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void) 5727315b7b4SJens Wiklander { 57367e55c51SEtienne Carriere struct gic_data *gd = &gic_data; 57467e55c51SEtienne Carriere uint32_t iar = 0; 57567e55c51SEtienne Carriere uint32_t id = 0; 5767315b7b4SJens Wiklander 5777315b7b4SJens Wiklander iar = gic_read_iar(gd); 5787315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 5797315b7b4SJens Wiklander 5804a9ea08cSFangsuo Wu if (id <= gd->max_it) 58199e2612cSEtienne Carriere interrupt_call_handlers(&gd->chip, id); 5823b3a4611SMathieu Briand else 5833b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 5847315b7b4SJens Wiklander 5857315b7b4SJens Wiklander gic_write_eoir(gd, iar); 5867315b7b4SJens Wiklander } 5877315b7b4SJens Wiklander 58867e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI 589358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */ 590358bf47cSEtienne Carriere void interrupt_main_handler(void) 59167e55c51SEtienne Carriere { 59267e55c51SEtienne Carriere gic_native_itr_handler(); 59367e55c51SEtienne Carriere } 59467e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/ 59567e55c51SEtienne Carriere 5967315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 597702fe5a7SClément Léger uint32_t type __unused, 598702fe5a7SClément Léger uint32_t prio __unused) 5997315b7b4SJens Wiklander { 6007315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 6017315b7b4SJens Wiklander 60267e55c51SEtienne Carriere assert(gd == &gic_data); 60367e55c51SEtienne Carriere 6044a9ea08cSFangsuo Wu if (it > gd->max_it) 605d13278b8SEtienne Carriere panic(); 606d13278b8SEtienne Carriere 6077315b7b4SJens Wiklander gic_it_add(gd, it); 6087315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 6097315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 6107315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 6117315b7b4SJens Wiklander } 6127315b7b4SJens Wiklander 6137315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 6147315b7b4SJens Wiklander { 6157315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 6167315b7b4SJens Wiklander 61767e55c51SEtienne Carriere assert(gd == &gic_data); 61867e55c51SEtienne Carriere 6194a9ea08cSFangsuo Wu if (it > gd->max_it) 620d13278b8SEtienne Carriere panic(); 621d13278b8SEtienne Carriere 6227315b7b4SJens Wiklander gic_it_enable(gd, it); 6237315b7b4SJens Wiklander } 6247315b7b4SJens Wiklander 6257315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 6267315b7b4SJens Wiklander { 6277315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 6287315b7b4SJens Wiklander 62967e55c51SEtienne Carriere assert(gd == &gic_data); 63067e55c51SEtienne Carriere 6314a9ea08cSFangsuo Wu if (it > gd->max_it) 632d13278b8SEtienne Carriere panic(); 633d13278b8SEtienne Carriere 6347315b7b4SJens Wiklander gic_it_disable(gd, it); 6357315b7b4SJens Wiklander } 63626ed70ecSGuanchao Liang 63726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 63826ed70ecSGuanchao Liang { 63926ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 64026ed70ecSGuanchao Liang 64167e55c51SEtienne Carriere assert(gd == &gic_data); 64267e55c51SEtienne Carriere 6434a9ea08cSFangsuo Wu if (it > gd->max_it) 64426ed70ecSGuanchao Liang panic(); 64526ed70ecSGuanchao Liang 64626ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 64726ed70ecSGuanchao Liang } 64826ed70ecSGuanchao Liang 64926ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 650ec740b9fSJens Wiklander uint32_t cpu_mask) 65126ed70ecSGuanchao Liang { 65226ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 65326ed70ecSGuanchao Liang 65467e55c51SEtienne Carriere assert(gd == &gic_data); 65567e55c51SEtienne Carriere 65654739cb4SMark-PK Tsai /* Should be Software Generated Interrupt */ 65754739cb4SMark-PK Tsai assert(it < NUM_SGI); 65854739cb4SMark-PK Tsai 6594a9ea08cSFangsuo Wu if (it > gd->max_it) 66026ed70ecSGuanchao Liang panic(); 66126ed70ecSGuanchao Liang 66226ed70ecSGuanchao Liang if (it < NUM_NS_SGI) 66326ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 1); 66426ed70ecSGuanchao Liang else 66526ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 0); 66626ed70ecSGuanchao Liang } 66767e55c51SEtienne Carriere 66826ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 66926ed70ecSGuanchao Liang uint8_t cpu_mask) 67026ed70ecSGuanchao Liang { 67126ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 67226ed70ecSGuanchao Liang 67367e55c51SEtienne Carriere assert(gd == &gic_data); 67467e55c51SEtienne Carriere 6754a9ea08cSFangsuo Wu if (it > gd->max_it) 67626ed70ecSGuanchao Liang panic(); 67726ed70ecSGuanchao Liang 67826ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 67926ed70ecSGuanchao Liang } 68014885eb1SEtienne Carriere 68114885eb1SEtienne Carriere #ifdef CFG_DT 68214885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */ 68314885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data, 68414885eb1SEtienne Carriere struct itr_desc *itr_desc) 68514885eb1SEtienne Carriere { 68614885eb1SEtienne Carriere int itr_num = DT_INFO_INVALID_INTERRUPT; 68714885eb1SEtienne Carriere struct itr_chip *chip = priv_data; 68814885eb1SEtienne Carriere uint32_t phandle_args[2] = { }; 68914885eb1SEtienne Carriere uint32_t type = 0; 69014885eb1SEtienne Carriere uint32_t prio = 0; 69114885eb1SEtienne Carriere 69214885eb1SEtienne Carriere assert(arg && itr_desc); 69314885eb1SEtienne Carriere 69414885eb1SEtienne Carriere /* 69514885eb1SEtienne Carriere * gic_dt_get_irq() expects phandle arguments passed are still in DT 69614885eb1SEtienne Carriere * format (big-endian) whereas struct dt_pargs carries converted 69714885eb1SEtienne Carriere * formats. Therefore swap again phandle arguments. gic_dt_get_irq() 69814885eb1SEtienne Carriere * consumes only the 2 first arguments. 69914885eb1SEtienne Carriere */ 70014885eb1SEtienne Carriere if (arg->args_count < 2) 70114885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 70214885eb1SEtienne Carriere phandle_args[0] = cpu_to_fdt32(arg->args[0]); 70314885eb1SEtienne Carriere phandle_args[1] = cpu_to_fdt32(arg->args[1]); 70414885eb1SEtienne Carriere 70514885eb1SEtienne Carriere itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio); 70614885eb1SEtienne Carriere if (itr_num == DT_INFO_INVALID_INTERRUPT) 70714885eb1SEtienne Carriere return TEE_ERROR_GENERIC; 70814885eb1SEtienne Carriere 70914885eb1SEtienne Carriere gic_op_add(chip, itr_num, type, prio); 71014885eb1SEtienne Carriere 71114885eb1SEtienne Carriere itr_desc->chip = chip; 71214885eb1SEtienne Carriere itr_desc->itr_num = itr_num; 71314885eb1SEtienne Carriere 71414885eb1SEtienne Carriere return TEE_SUCCESS; 71514885eb1SEtienne Carriere } 71614885eb1SEtienne Carriere 71714885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused) 71814885eb1SEtienne Carriere { 71914885eb1SEtienne Carriere if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb, 72014885eb1SEtienne Carriere &gic_data.chip)) 72114885eb1SEtienne Carriere panic(); 72214885eb1SEtienne Carriere 72314885eb1SEtienne Carriere return TEE_SUCCESS; 72414885eb1SEtienne Carriere } 72514885eb1SEtienne Carriere 72614885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = { 72714885eb1SEtienne Carriere { .compatible = "arm,cortex-a15-gic" }, 72814885eb1SEtienne Carriere { .compatible = "arm,cortex-a7-gic" }, 72914885eb1SEtienne Carriere { .compatible = "arm,cortex-a5-gic" }, 73014885eb1SEtienne Carriere { .compatible = "arm,cortex-a9-gic" }, 73114885eb1SEtienne Carriere { .compatible = "arm,gic-400" }, 73214885eb1SEtienne Carriere { } 73314885eb1SEtienne Carriere }; 73414885eb1SEtienne Carriere 73514885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = { 73614885eb1SEtienne Carriere .name = "gic", 73714885eb1SEtienne Carriere .match_table = gic_match_table, 73814885eb1SEtienne Carriere .probe = gic_probe, 73914885eb1SEtienne Carriere }; 74014885eb1SEtienne Carriere #endif /*CFG_DT*/ 741