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> 10b0104773SPascal Brand #include <drivers/gic.h> 110f93de74SEtienne Carriere #include <keep.h> 1267729d8dSLudovic Barre #include <kernel/dt.h> 137315b7b4SJens Wiklander #include <kernel/interrupt.h> 14d13278b8SEtienne Carriere #include <kernel/panic.h> 15*60801696SVolodymyr Babchuk #include <mm/core_memprot.h> 16*60801696SVolodymyr Babchuk #include <mm/core_mmu.h> 1767729d8dSLudovic Barre #include <libfdt.h> 187315b7b4SJens Wiklander #include <util.h> 19b0104773SPascal Brand #include <io.h> 204de4bebcSJens Wiklander #include <trace.h> 21b0104773SPascal Brand 22b0104773SPascal Brand /* Offsets from gic.gicc_base */ 23b0104773SPascal Brand #define GICC_CTLR (0x000) 2430a673e3SPeter Maydell #define GICC_PMR (0x004) 25b0104773SPascal Brand #define GICC_IAR (0x00C) 26b0104773SPascal Brand #define GICC_EOIR (0x010) 27b0104773SPascal Brand 28b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0) 29b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1) 301fcac774SSandeep Tripathy #define GICD_CTLR_ENABLEGRP1S (1 << 2) 31b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3) 32b0104773SPascal Brand 33b0104773SPascal Brand /* Offsets from gic.gicd_base */ 34b0104773SPascal Brand #define GICD_CTLR (0x000) 35b0104773SPascal Brand #define GICD_TYPER (0x004) 36b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4) 37b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4) 38b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4) 3926ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4) 40b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4) 41b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) 42b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4) 431fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 4426ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 45b0104773SPascal Brand 46b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0 (1 << 0) 47b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1 (1 << 1) 48b0104773SPascal Brand 4953bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 5053bd332aSSY Chiu #define NUM_PPI 32 5153bd332aSSY Chiu 5226ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 5326ed70ecSGuanchao Liang #define NUM_SGI 16 5426ed70ecSGuanchao Liang 5526ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 5626ed70ecSGuanchao Liang #define NUM_NS_SGI 8 5726ed70ecSGuanchao Liang 5853bd332aSSY Chiu /* Number of interrupts in one register */ 5953bd332aSSY Chiu #define NUM_INTS_PER_REG 32 6053bd332aSSY Chiu 6153bd332aSSY Chiu /* Number of targets in one register */ 6253bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 6353bd332aSSY Chiu 6453bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 6553bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 6653bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 6753bd332aSSY Chiu 68b0104773SPascal Brand /* Maximum number of interrups a GIC can support */ 69b0104773SPascal Brand #define GIC_MAX_INTS 1020 70b0104773SPascal Brand 717315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 727315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 737315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 74b0104773SPascal Brand 75702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type, 76702fe5a7SClément Léger uint32_t prio); 777315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 787315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 7926ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 8026ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 8126ed70ecSGuanchao Liang uint8_t cpu_mask); 8226ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 8326ed70ecSGuanchao Liang uint8_t cpu_mask); 847315b7b4SJens Wiklander 857315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 867315b7b4SJens Wiklander .add = gic_op_add, 877315b7b4SJens Wiklander .enable = gic_op_enable, 887315b7b4SJens Wiklander .disable = gic_op_disable, 8926ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 9026ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 9126ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 927315b7b4SJens Wiklander }; 933639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops); 947315b7b4SJens Wiklander 9518901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 96b0104773SPascal Brand { 97b0104773SPascal Brand int i; 98b0104773SPascal Brand uint32_t old_ctlr; 99b0104773SPascal Brand size_t ret = 0; 10079f008d3SJens Wiklander const size_t max_regs = ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) / 10179f008d3SJens Wiklander NUM_INTS_PER_REG) - 1; 102b0104773SPascal Brand 103b0104773SPascal Brand /* 104b0104773SPascal Brand * Probe which interrupt number is the largest. 105b0104773SPascal Brand */ 10618901324SDavid Wang #if defined(CFG_ARM_GICV3) 10718901324SDavid Wang old_ctlr = read_icc_ctlr(); 10818901324SDavid Wang write_icc_ctlr(0); 10918901324SDavid Wang #else 110918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 111918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 11218901324SDavid Wang #endif 11379f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 114b0104773SPascal Brand uint32_t old_reg; 115b0104773SPascal Brand uint32_t reg; 116b0104773SPascal Brand int b; 117b0104773SPascal Brand 118918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 119918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 120918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 121918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 12279f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 123007a97a2SJens Wiklander if (BIT32(b) & reg) { 12453bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 125b0104773SPascal Brand goto out; 126b0104773SPascal Brand } 127b0104773SPascal Brand } 128b0104773SPascal Brand } 129b0104773SPascal Brand out: 13018901324SDavid Wang #if defined(CFG_ARM_GICV3) 13118901324SDavid Wang write_icc_ctlr(old_ctlr); 13218901324SDavid Wang #else 133918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 13418901324SDavid Wang #endif 135b0104773SPascal Brand return ret; 136b0104773SPascal Brand } 137b0104773SPascal Brand 1387315b7b4SJens Wiklander void gic_cpu_init(struct gic_data *gd) 139bedc2b9fSsunny { 14018901324SDavid Wang #if defined(CFG_ARM_GICV3) 14118901324SDavid Wang assert(gd->gicd_base); 14218901324SDavid Wang #else 14305efe1e1SEtienne Carriere assert(gd->gicd_base && gd->gicc_base); 14418901324SDavid Wang #endif 14505efe1e1SEtienne Carriere 146e06e6e74SPeter Maydell /* per-CPU interrupts config: 147bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 148bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 149bedc2b9fSsunny * All PPI config as Non-secure interrupts. 150bedc2b9fSsunny */ 151918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff); 152bedc2b9fSsunny 15330a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 15430a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 15530a673e3SPeter Maydell */ 15618901324SDavid Wang #if defined(CFG_ARM_GICV3) 15718901324SDavid Wang write_icc_pmr(0x80); 1581fcac774SSandeep Tripathy write_icc_igrpen1(1); 15918901324SDavid Wang #else 160918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 16130a673e3SPeter Maydell 162bedc2b9fSsunny /* Enable GIC */ 163918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 164918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 165918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 16618901324SDavid Wang #endif 167bedc2b9fSsunny } 168bedc2b9fSsunny 169*60801696SVolodymyr Babchuk void gic_init(struct gic_data *gd, paddr_t gicc_base_pa, paddr_t gicd_base_pa) 170b0104773SPascal Brand { 171b0104773SPascal Brand size_t n; 172b0104773SPascal Brand 173*60801696SVolodymyr Babchuk gic_init_base_addr(gd, gicc_base_pa, gicd_base_pa); 174b0104773SPascal Brand 1757315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 176b0104773SPascal Brand /* Disable interrupts */ 177918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 178b0104773SPascal Brand 179b0104773SPascal Brand /* Make interrupts non-pending */ 180918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 181b0104773SPascal Brand 182b0104773SPascal Brand /* Mark interrupts non-secure */ 183bedc2b9fSsunny if (n == 0) { 184bedc2b9fSsunny /* per-CPU inerrupts config: 185bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 186bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 187bedc2b9fSsunny * All PPI config as Non-secure interrupts. 188bedc2b9fSsunny */ 189918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff); 190bedc2b9fSsunny } else { 191918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 192b0104773SPascal Brand } 193bedc2b9fSsunny } 194b0104773SPascal Brand 19530a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 19630a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 19730a673e3SPeter Maydell */ 19818901324SDavid Wang #if defined(CFG_ARM_GICV3) 19918901324SDavid Wang write_icc_pmr(0x80); 2001fcac774SSandeep Tripathy write_icc_igrpen1(1); 2011fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 20218901324SDavid Wang #else 203918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 20430a673e3SPeter Maydell 205b0104773SPascal Brand /* Enable GIC */ 206918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 207918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 208918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 209918bb3a5SEtienne Carriere GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1); 2101fcac774SSandeep Tripathy #endif 211b0104773SPascal Brand } 212b0104773SPascal Brand 213702fe5a7SClément Léger static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type, 214702fe5a7SClément Léger uint32_t *prio) 21567729d8dSLudovic Barre { 216ed74d1c4SLudovic Barre int it_num = DT_INFO_INVALID_INTERRUPT; 217ed74d1c4SLudovic Barre 218702fe5a7SClément Léger if (type) 219702fe5a7SClément Léger *type = IRQ_TYPE_NONE; 220702fe5a7SClément Léger 221702fe5a7SClément Léger if (prio) 222702fe5a7SClément Léger *prio = 0; 223702fe5a7SClément Léger 224888bb63dSClément Léger if (!properties || count < 2) 22567729d8dSLudovic Barre return DT_INFO_INVALID_INTERRUPT; 22667729d8dSLudovic Barre 227ed74d1c4SLudovic Barre it_num = fdt32_to_cpu(properties[1]); 228ed74d1c4SLudovic Barre 229ed74d1c4SLudovic Barre switch (fdt32_to_cpu(properties[0])) { 230ed74d1c4SLudovic Barre case 1: 231ed74d1c4SLudovic Barre it_num += 16; 232ed74d1c4SLudovic Barre break; 233ed74d1c4SLudovic Barre case 0: 234ed74d1c4SLudovic Barre it_num += 32; 235ed74d1c4SLudovic Barre break; 236ed74d1c4SLudovic Barre default: 237ed74d1c4SLudovic Barre it_num = DT_INFO_INVALID_INTERRUPT; 238ed74d1c4SLudovic Barre } 239ed74d1c4SLudovic Barre 240ed74d1c4SLudovic Barre return it_num; 24167729d8dSLudovic Barre } 24267729d8dSLudovic Barre 243*60801696SVolodymyr Babchuk void gic_init_base_addr(struct gic_data *gd, 244*60801696SVolodymyr Babchuk paddr_t gicc_base_pa __maybe_unused, 245*60801696SVolodymyr Babchuk paddr_t gicd_base_pa) 24653bd332aSSY Chiu { 247*60801696SVolodymyr Babchuk vaddr_t gicc_base = 0; 248*60801696SVolodymyr Babchuk vaddr_t gicd_base = 0; 249*60801696SVolodymyr Babchuk 250*60801696SVolodymyr Babchuk assert(cpu_mmu_enabled()); 251*60801696SVolodymyr Babchuk 252*60801696SVolodymyr Babchuk gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC, 253*60801696SVolodymyr Babchuk GIC_DIST_REG_SIZE); 254*60801696SVolodymyr Babchuk if (!gicd_base) 255*60801696SVolodymyr Babchuk panic(); 256*60801696SVolodymyr Babchuk 257*60801696SVolodymyr Babchuk if (!IS_ENABLED(CFG_ARM_GICV3)) { 258*60801696SVolodymyr Babchuk gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC, 259*60801696SVolodymyr Babchuk GIC_CPU_REG_SIZE); 260*60801696SVolodymyr Babchuk if (!gicc_base) 261*60801696SVolodymyr Babchuk panic(); 262*60801696SVolodymyr Babchuk } 263*60801696SVolodymyr Babchuk 2647315b7b4SJens Wiklander gd->gicc_base = gicc_base; 2657315b7b4SJens Wiklander gd->gicd_base = gicd_base; 2667315b7b4SJens Wiklander gd->max_it = probe_max_it(gicc_base, gicd_base); 2677315b7b4SJens Wiklander gd->chip.ops = &gic_ops; 26867729d8dSLudovic Barre 26967729d8dSLudovic Barre if (IS_ENABLED(CFG_DT)) 27067729d8dSLudovic Barre gd->chip.dt_get_irq = gic_dt_get_irq; 27153bd332aSSY Chiu } 27253bd332aSSY Chiu 2737315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 274b0104773SPascal Brand { 27553bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 27653bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 277b0104773SPascal Brand 278b0104773SPascal Brand /* Disable the interrupt */ 279918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 280b0104773SPascal Brand /* Make it non-pending */ 281918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 282b0104773SPascal Brand /* Assign it to group0 */ 283918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 2841fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 2851fcac774SSandeep Tripathy /* Assign it to group1S */ 2861fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 2871fcac774SSandeep Tripathy #endif 288b0104773SPascal Brand } 289b0104773SPascal Brand 2907315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 2917315b7b4SJens Wiklander uint8_t cpu_mask) 292b0104773SPascal Brand { 2938ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 2948ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 29553bd332aSSY Chiu uint32_t target, target_shift; 296918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 297918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 298b0104773SPascal Brand 299b0104773SPascal Brand /* Assigned to group0 */ 300918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 301b0104773SPascal Brand 302b0104773SPascal Brand /* Route it to selected CPUs */ 303918bb3a5SEtienne Carriere target = io_read32(itargetsr); 30453bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 30553bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 30653bd332aSSY Chiu target |= cpu_mask << target_shift; 307918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 308918bb3a5SEtienne Carriere io_write32(itargetsr, target); 309918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 310b0104773SPascal Brand } 311b0104773SPascal Brand 3127315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 313b0104773SPascal Brand { 3148ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 3158ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 316b0104773SPascal Brand 317b0104773SPascal Brand /* Assigned to group0 */ 318918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 319b0104773SPascal Brand 320b0104773SPascal Brand /* Set prio it to selected CPUs */ 3211f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 3227315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 323918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 324b0104773SPascal Brand } 325b0104773SPascal Brand 3267315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 327b0104773SPascal Brand { 32853bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 32953bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 330918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 331b0104773SPascal Brand 332b0104773SPascal Brand /* Assigned to group0 */ 333918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 334b0104773SPascal Brand 335b0104773SPascal Brand /* Enable the interrupt */ 336918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 337b0104773SPascal Brand } 338b0104773SPascal Brand 3397315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 340b0104773SPascal Brand { 34153bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 34253bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 343b0104773SPascal Brand 344b0104773SPascal Brand /* Assigned to group0 */ 345918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 346b0104773SPascal Brand 347b0104773SPascal Brand /* Disable the interrupt */ 348918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 349b0104773SPascal Brand } 350b0104773SPascal Brand 35126ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 35226ed70ecSGuanchao Liang { 35326ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 35426ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 35526ed70ecSGuanchao Liang 35626ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 35726ed70ecSGuanchao Liang assert(it >= NUM_SGI); 35826ed70ecSGuanchao Liang 35926ed70ecSGuanchao Liang /* Raise the interrupt */ 360918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 36126ed70ecSGuanchao Liang } 36226ed70ecSGuanchao Liang 36326ed70ecSGuanchao Liang static void gic_it_raise_sgi(struct gic_data *gd, size_t it, 36426ed70ecSGuanchao Liang uint8_t cpu_mask, uint8_t group) 36526ed70ecSGuanchao Liang { 36626ed70ecSGuanchao Liang uint32_t mask_id = it & 0xf; 36726ed70ecSGuanchao Liang uint32_t mask_group = group & 0x1; 36826ed70ecSGuanchao Liang uint32_t mask_cpu = cpu_mask & 0xff; 36926ed70ecSGuanchao Liang uint32_t mask = (mask_id | SHIFT_U32(mask_group, 15) | 37026ed70ecSGuanchao Liang SHIFT_U32(mask_cpu, 16)); 37126ed70ecSGuanchao Liang 37226ed70ecSGuanchao Liang /* Should be Software Generated Interrupt */ 37326ed70ecSGuanchao Liang assert(it < NUM_SGI); 37426ed70ecSGuanchao Liang 37526ed70ecSGuanchao Liang /* Raise the interrupt */ 376918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 37726ed70ecSGuanchao Liang } 37826ed70ecSGuanchao Liang 37918901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 380b0104773SPascal Brand { 38118901324SDavid Wang #if defined(CFG_ARM_GICV3) 3821de462e1SSumit Garg return read_icc_iar1(); 38318901324SDavid Wang #else 384918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 38518901324SDavid Wang #endif 386b0104773SPascal Brand } 387b0104773SPascal Brand 38818901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 389b0104773SPascal Brand { 39018901324SDavid Wang #if defined(CFG_ARM_GICV3) 3911de462e1SSumit Garg write_icc_eoir1(eoir); 39218901324SDavid Wang #else 393918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 39418901324SDavid Wang #endif 395b0104773SPascal Brand } 396b0104773SPascal Brand 3977315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 3987315b7b4SJens Wiklander { 39953bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 40053bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 401918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 40253bd332aSSY Chiu } 40353bd332aSSY Chiu 4047315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 4057315b7b4SJens Wiklander { 40653bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 40753bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 408918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 40953bd332aSSY Chiu } 41053bd332aSSY Chiu 4117315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 4127315b7b4SJens Wiklander { 41353bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 4147315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 4157315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 41653bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 417918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 4187315b7b4SJens Wiklander 419918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 42053bd332aSSY Chiu } 42153bd332aSSY Chiu 4227315b7b4SJens Wiklander void gic_dump_state(struct gic_data *gd) 42353bd332aSSY Chiu { 42453bd332aSSY Chiu int i; 42553bd332aSSY Chiu 42618901324SDavid Wang #if defined(CFG_ARM_GICV3) 42718901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 42818901324SDavid Wang #else 429918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 43018901324SDavid Wang #endif 431918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 4327315b7b4SJens Wiklander 4334a9ea08cSFangsuo Wu for (i = 0; i <= (int)gd->max_it; i++) { 4347315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 43553bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 4367315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 43753bd332aSSY Chiu } 43853bd332aSSY Chiu } 43953bd332aSSY Chiu } 4407315b7b4SJens Wiklander 4417315b7b4SJens Wiklander void gic_it_handle(struct gic_data *gd) 4427315b7b4SJens Wiklander { 4437315b7b4SJens Wiklander uint32_t iar; 4447315b7b4SJens Wiklander uint32_t id; 4457315b7b4SJens Wiklander 4467315b7b4SJens Wiklander iar = gic_read_iar(gd); 4477315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 4487315b7b4SJens Wiklander 4494a9ea08cSFangsuo Wu if (id <= gd->max_it) 4507315b7b4SJens Wiklander itr_handle(id); 4513b3a4611SMathieu Briand else 4523b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 4537315b7b4SJens Wiklander 4547315b7b4SJens Wiklander gic_write_eoir(gd, iar); 4557315b7b4SJens Wiklander } 4567315b7b4SJens Wiklander 4577315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 458702fe5a7SClément Léger uint32_t type __unused, 459702fe5a7SClément Léger uint32_t prio __unused) 4607315b7b4SJens Wiklander { 4617315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 4627315b7b4SJens Wiklander 4634a9ea08cSFangsuo Wu if (it > gd->max_it) 464d13278b8SEtienne Carriere panic(); 465d13278b8SEtienne Carriere 4667315b7b4SJens Wiklander gic_it_add(gd, it); 4677315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 4687315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 4697315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 4707315b7b4SJens Wiklander } 4717315b7b4SJens Wiklander 4727315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 4737315b7b4SJens Wiklander { 4747315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 4757315b7b4SJens Wiklander 4764a9ea08cSFangsuo Wu if (it > gd->max_it) 477d13278b8SEtienne Carriere panic(); 478d13278b8SEtienne Carriere 4797315b7b4SJens Wiklander gic_it_enable(gd, it); 4807315b7b4SJens Wiklander } 4817315b7b4SJens Wiklander 4827315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 4837315b7b4SJens Wiklander { 4847315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 4857315b7b4SJens Wiklander 4864a9ea08cSFangsuo Wu if (it > gd->max_it) 487d13278b8SEtienne Carriere panic(); 488d13278b8SEtienne Carriere 4897315b7b4SJens Wiklander gic_it_disable(gd, it); 4907315b7b4SJens Wiklander } 49126ed70ecSGuanchao Liang 49226ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 49326ed70ecSGuanchao Liang { 49426ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 49526ed70ecSGuanchao Liang 4964a9ea08cSFangsuo Wu if (it > gd->max_it) 49726ed70ecSGuanchao Liang panic(); 49826ed70ecSGuanchao Liang 49926ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 50026ed70ecSGuanchao Liang } 50126ed70ecSGuanchao Liang 50226ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 50326ed70ecSGuanchao Liang uint8_t cpu_mask) 50426ed70ecSGuanchao Liang { 50526ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 50626ed70ecSGuanchao Liang 5074a9ea08cSFangsuo Wu if (it > gd->max_it) 50826ed70ecSGuanchao Liang panic(); 50926ed70ecSGuanchao Liang 51026ed70ecSGuanchao Liang if (it < NUM_NS_SGI) 51126ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 1); 51226ed70ecSGuanchao Liang else 51326ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 0); 51426ed70ecSGuanchao Liang } 51526ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 51626ed70ecSGuanchao Liang uint8_t cpu_mask) 51726ed70ecSGuanchao Liang { 51826ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 51926ed70ecSGuanchao Liang 5204a9ea08cSFangsuo Wu if (it > gd->max_it) 52126ed70ecSGuanchao Liang panic(); 52226ed70ecSGuanchao Liang 52326ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 52426ed70ecSGuanchao Liang } 525