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> 9b0104773SPascal Brand #include <drivers/gic.h> 100f93de74SEtienne Carriere #include <keep.h> 117315b7b4SJens Wiklander #include <kernel/interrupt.h> 12d13278b8SEtienne Carriere #include <kernel/panic.h> 137315b7b4SJens Wiklander #include <util.h> 14b0104773SPascal Brand #include <io.h> 154de4bebcSJens Wiklander #include <trace.h> 16b0104773SPascal Brand 17b0104773SPascal Brand /* Offsets from gic.gicc_base */ 18b0104773SPascal Brand #define GICC_CTLR (0x000) 1930a673e3SPeter Maydell #define GICC_PMR (0x004) 20b0104773SPascal Brand #define GICC_IAR (0x00C) 21b0104773SPascal Brand #define GICC_EOIR (0x010) 22b0104773SPascal Brand 23b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0 (1 << 0) 24b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1 (1 << 1) 25*1fcac774SSandeep Tripathy #define GICD_CTLR_ENABLEGRP1S (1 << 2) 26b0104773SPascal Brand #define GICC_CTLR_FIQEN (1 << 3) 27b0104773SPascal Brand 28b0104773SPascal Brand /* Offsets from gic.gicd_base */ 29b0104773SPascal Brand #define GICD_CTLR (0x000) 30b0104773SPascal Brand #define GICD_TYPER (0x004) 31b0104773SPascal Brand #define GICD_IGROUPR(n) (0x080 + (n) * 4) 32b0104773SPascal Brand #define GICD_ISENABLER(n) (0x100 + (n) * 4) 33b0104773SPascal Brand #define GICD_ICENABLER(n) (0x180 + (n) * 4) 3426ed70ecSGuanchao Liang #define GICD_ISPENDR(n) (0x200 + (n) * 4) 35b0104773SPascal Brand #define GICD_ICPENDR(n) (0x280 + (n) * 4) 36b0104773SPascal Brand #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) 37b0104773SPascal Brand #define GICD_ITARGETSR(n) (0x800 + (n) * 4) 38*1fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n) (0xd00 + (n) * 4) 3926ed70ecSGuanchao Liang #define GICD_SGIR (0xF00) 40b0104773SPascal Brand 41b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0 (1 << 0) 42b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1 (1 << 1) 43b0104773SPascal Brand 4453bd332aSSY Chiu /* Number of Private Peripheral Interrupt */ 4553bd332aSSY Chiu #define NUM_PPI 32 4653bd332aSSY Chiu 4726ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */ 4826ed70ecSGuanchao Liang #define NUM_SGI 16 4926ed70ecSGuanchao Liang 5026ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */ 5126ed70ecSGuanchao Liang #define NUM_NS_SGI 8 5226ed70ecSGuanchao Liang 5353bd332aSSY Chiu /* Number of interrupts in one register */ 5453bd332aSSY Chiu #define NUM_INTS_PER_REG 32 5553bd332aSSY Chiu 5653bd332aSSY Chiu /* Number of targets in one register */ 5753bd332aSSY Chiu #define NUM_TARGETS_PER_REG 4 5853bd332aSSY Chiu 5953bd332aSSY Chiu /* Accessors to access ITARGETSRn */ 6053bd332aSSY Chiu #define ITARGETSR_FIELD_BITS 8 6153bd332aSSY Chiu #define ITARGETSR_FIELD_MASK 0xff 6253bd332aSSY Chiu 63b0104773SPascal Brand /* Maximum number of interrups a GIC can support */ 64b0104773SPascal Brand #define GIC_MAX_INTS 1020 65b0104773SPascal Brand 667315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK 0x3ff 677315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK 0x7 687315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT 10 69b0104773SPascal Brand 707315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t flags); 717315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it); 727315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it); 7326ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it); 7426ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 7526ed70ecSGuanchao Liang uint8_t cpu_mask); 7626ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 7726ed70ecSGuanchao Liang uint8_t cpu_mask); 787315b7b4SJens Wiklander 797315b7b4SJens Wiklander static const struct itr_ops gic_ops = { 807315b7b4SJens Wiklander .add = gic_op_add, 817315b7b4SJens Wiklander .enable = gic_op_enable, 827315b7b4SJens Wiklander .disable = gic_op_disable, 8326ed70ecSGuanchao Liang .raise_pi = gic_op_raise_pi, 8426ed70ecSGuanchao Liang .raise_sgi = gic_op_raise_sgi, 8526ed70ecSGuanchao Liang .set_affinity = gic_op_set_affinity, 867315b7b4SJens Wiklander }; 870f93de74SEtienne Carriere KEEP_PAGER(gic_ops); 887315b7b4SJens Wiklander 8918901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base) 90b0104773SPascal Brand { 91b0104773SPascal Brand int i; 92b0104773SPascal Brand uint32_t old_ctlr; 93b0104773SPascal Brand size_t ret = 0; 9479f008d3SJens Wiklander const size_t max_regs = ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) / 9579f008d3SJens Wiklander NUM_INTS_PER_REG) - 1; 96b0104773SPascal Brand 97b0104773SPascal Brand /* 98b0104773SPascal Brand * Probe which interrupt number is the largest. 99b0104773SPascal Brand */ 10018901324SDavid Wang #if defined(CFG_ARM_GICV3) 10118901324SDavid Wang old_ctlr = read_icc_ctlr(); 10218901324SDavid Wang write_icc_ctlr(0); 10318901324SDavid Wang #else 104918bb3a5SEtienne Carriere old_ctlr = io_read32(gicc_base + GICC_CTLR); 105918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, 0); 10618901324SDavid Wang #endif 10779f008d3SJens Wiklander for (i = max_regs; i >= 0; i--) { 108b0104773SPascal Brand uint32_t old_reg; 109b0104773SPascal Brand uint32_t reg; 110b0104773SPascal Brand int b; 111b0104773SPascal Brand 112918bb3a5SEtienne Carriere old_reg = io_read32(gicd_base + GICD_ISENABLER(i)); 113918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff); 114918bb3a5SEtienne Carriere reg = io_read32(gicd_base + GICD_ISENABLER(i)); 115918bb3a5SEtienne Carriere io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg); 11679f008d3SJens Wiklander for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) { 117007a97a2SJens Wiklander if (BIT32(b) & reg) { 11853bd332aSSY Chiu ret = i * NUM_INTS_PER_REG + b; 119b0104773SPascal Brand goto out; 120b0104773SPascal Brand } 121b0104773SPascal Brand } 122b0104773SPascal Brand } 123b0104773SPascal Brand out: 12418901324SDavid Wang #if defined(CFG_ARM_GICV3) 12518901324SDavid Wang write_icc_ctlr(old_ctlr); 12618901324SDavid Wang #else 127918bb3a5SEtienne Carriere io_write32(gicc_base + GICC_CTLR, old_ctlr); 12818901324SDavid Wang #endif 129b0104773SPascal Brand return ret; 130b0104773SPascal Brand } 131b0104773SPascal Brand 1327315b7b4SJens Wiklander void gic_cpu_init(struct gic_data *gd) 133bedc2b9fSsunny { 13418901324SDavid Wang #if defined(CFG_ARM_GICV3) 13518901324SDavid Wang assert(gd->gicd_base); 13618901324SDavid Wang #else 13705efe1e1SEtienne Carriere assert(gd->gicd_base && gd->gicc_base); 13818901324SDavid Wang #endif 13905efe1e1SEtienne Carriere 140e06e6e74SPeter Maydell /* per-CPU interrupts config: 141bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 142bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 143bedc2b9fSsunny * All PPI config as Non-secure interrupts. 144bedc2b9fSsunny */ 145918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff); 146bedc2b9fSsunny 14730a673e3SPeter Maydell /* Set the priority mask to permit Non-secure interrupts, and to 14830a673e3SPeter Maydell * allow the Non-secure world to adjust the priority mask itself 14930a673e3SPeter Maydell */ 15018901324SDavid Wang #if defined(CFG_ARM_GICV3) 15118901324SDavid Wang write_icc_pmr(0x80); 152*1fcac774SSandeep Tripathy write_icc_igrpen1(1); 15318901324SDavid Wang #else 154918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 15530a673e3SPeter Maydell 156bedc2b9fSsunny /* Enable GIC */ 157918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, 158918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | 159918bb3a5SEtienne Carriere GICC_CTLR_FIQEN); 16018901324SDavid Wang #endif 161bedc2b9fSsunny } 162bedc2b9fSsunny 16318901324SDavid Wang void gic_init(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, 16418901324SDavid Wang vaddr_t gicd_base) 165b0104773SPascal Brand { 166b0104773SPascal Brand size_t n; 167b0104773SPascal Brand 1687315b7b4SJens Wiklander gic_init_base_addr(gd, gicc_base, gicd_base); 169b0104773SPascal Brand 1707315b7b4SJens Wiklander for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) { 171b0104773SPascal Brand /* Disable interrupts */ 172918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff); 173b0104773SPascal Brand 174b0104773SPascal Brand /* Make interrupts non-pending */ 175918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff); 176b0104773SPascal Brand 177b0104773SPascal Brand /* Mark interrupts non-secure */ 178bedc2b9fSsunny if (n == 0) { 179bedc2b9fSsunny /* per-CPU inerrupts config: 180bedc2b9fSsunny * ID0-ID7(SGI) for Non-secure interrupts 181bedc2b9fSsunny * ID8-ID15(SGI) for Secure interrupts. 182bedc2b9fSsunny * All PPI config as Non-secure interrupts. 183bedc2b9fSsunny */ 184918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff); 185bedc2b9fSsunny } else { 186918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff); 187b0104773SPascal Brand } 188bedc2b9fSsunny } 189b0104773SPascal Brand 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); 195*1fcac774SSandeep Tripathy write_icc_igrpen1(1); 196*1fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S); 19718901324SDavid Wang #else 198918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_PMR, 0x80); 19930a673e3SPeter Maydell 200b0104773SPascal Brand /* Enable GIC */ 201918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN | 202918bb3a5SEtienne Carriere GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1); 203918bb3a5SEtienne Carriere io_setbits32(gd->gicd_base + GICD_CTLR, 204918bb3a5SEtienne Carriere GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1); 205*1fcac774SSandeep Tripathy #endif 206b0104773SPascal Brand } 207b0104773SPascal Brand 20818901324SDavid Wang void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, 2097315b7b4SJens Wiklander vaddr_t gicd_base) 21053bd332aSSY Chiu { 2117315b7b4SJens Wiklander gd->gicc_base = gicc_base; 2127315b7b4SJens Wiklander gd->gicd_base = gicd_base; 2137315b7b4SJens Wiklander gd->max_it = probe_max_it(gicc_base, gicd_base); 2147315b7b4SJens Wiklander gd->chip.ops = &gic_ops; 21553bd332aSSY Chiu } 21653bd332aSSY Chiu 2177315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it) 218b0104773SPascal Brand { 21953bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 22053bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 221b0104773SPascal Brand 222b0104773SPascal Brand /* Disable the interrupt */ 223918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 224b0104773SPascal Brand /* Make it non-pending */ 225918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask); 226b0104773SPascal Brand /* Assign it to group0 */ 227918bb3a5SEtienne Carriere io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask); 228*1fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3) 229*1fcac774SSandeep Tripathy /* Assign it to group1S */ 230*1fcac774SSandeep Tripathy io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask); 231*1fcac774SSandeep Tripathy #endif 232b0104773SPascal Brand } 233b0104773SPascal Brand 2347315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it, 2357315b7b4SJens Wiklander uint8_t cpu_mask) 236b0104773SPascal Brand { 2378ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 2388ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 23953bd332aSSY Chiu uint32_t target, target_shift; 240918bb3a5SEtienne Carriere vaddr_t itargetsr = gd->gicd_base + 241918bb3a5SEtienne Carriere GICD_ITARGETSR(it / NUM_TARGETS_PER_REG); 242b0104773SPascal Brand 243b0104773SPascal Brand /* Assigned to group0 */ 244918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 245b0104773SPascal Brand 246b0104773SPascal Brand /* Route it to selected CPUs */ 247918bb3a5SEtienne Carriere target = io_read32(itargetsr); 24853bd332aSSY Chiu target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS; 24953bd332aSSY Chiu target &= ~(ITARGETSR_FIELD_MASK << target_shift); 25053bd332aSSY Chiu target |= cpu_mask << target_shift; 251918bb3a5SEtienne Carriere DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr); 252918bb3a5SEtienne Carriere io_write32(itargetsr, target); 253918bb3a5SEtienne Carriere DMSG("cpu_mask: 0x%x", io_read32(itargetsr)); 254b0104773SPascal Brand } 255b0104773SPascal Brand 2567315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) 257b0104773SPascal Brand { 2588ddf5a4eSEtienne Carriere size_t idx __maybe_unused = it / NUM_INTS_PER_REG; 2598ddf5a4eSEtienne Carriere uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); 260b0104773SPascal Brand 261b0104773SPascal Brand /* Assigned to group0 */ 262918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 263b0104773SPascal Brand 264b0104773SPascal Brand /* Set prio it to selected CPUs */ 2651f60363aSJens Wiklander DMSG("prio: writing 0x%x to 0x%" PRIxVA, 2667315b7b4SJens Wiklander prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); 267918bb3a5SEtienne Carriere io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio); 268b0104773SPascal Brand } 269b0104773SPascal Brand 2707315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it) 271b0104773SPascal Brand { 27253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 27353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 274918bb3a5SEtienne Carriere vaddr_t base = gd->gicd_base; 275b0104773SPascal Brand 276b0104773SPascal Brand /* Assigned to group0 */ 277918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask)); 27826ed70ecSGuanchao Liang if (it >= NUM_SGI) { 27926ed70ecSGuanchao Liang /* 28026ed70ecSGuanchao Liang * Not enabled yet, except Software Generated Interrupt 28126ed70ecSGuanchao Liang * which is implementation defined 28226ed70ecSGuanchao Liang */ 283918bb3a5SEtienne Carriere assert(!(io_read32(base + GICD_ISENABLER(idx)) & mask)); 28426ed70ecSGuanchao Liang } 285b0104773SPascal Brand 286b0104773SPascal Brand /* Enable the interrupt */ 287918bb3a5SEtienne Carriere io_write32(base + GICD_ISENABLER(idx), mask); 288b0104773SPascal Brand } 289b0104773SPascal Brand 2907315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it) 291b0104773SPascal Brand { 29253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 29353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 294b0104773SPascal Brand 295b0104773SPascal Brand /* Assigned to group0 */ 296918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 297b0104773SPascal Brand 298b0104773SPascal Brand /* Disable the interrupt */ 299918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask); 300b0104773SPascal Brand } 301b0104773SPascal Brand 30226ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it) 30326ed70ecSGuanchao Liang { 30426ed70ecSGuanchao Liang size_t idx = it / NUM_INTS_PER_REG; 30526ed70ecSGuanchao Liang uint32_t mask = BIT32(it % NUM_INTS_PER_REG); 30626ed70ecSGuanchao Liang 30726ed70ecSGuanchao Liang /* Should be Peripheral Interrupt */ 30826ed70ecSGuanchao Liang assert(it >= NUM_SGI); 30926ed70ecSGuanchao Liang /* Assigned to group0 */ 310918bb3a5SEtienne Carriere assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); 31126ed70ecSGuanchao Liang 31226ed70ecSGuanchao Liang /* Raise the interrupt */ 313918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask); 31426ed70ecSGuanchao Liang } 31526ed70ecSGuanchao Liang 31626ed70ecSGuanchao Liang static void gic_it_raise_sgi(struct gic_data *gd, size_t it, 31726ed70ecSGuanchao Liang uint8_t cpu_mask, uint8_t group) 31826ed70ecSGuanchao Liang { 31926ed70ecSGuanchao Liang uint32_t mask_id = it & 0xf; 32026ed70ecSGuanchao Liang uint32_t mask_group = group & 0x1; 32126ed70ecSGuanchao Liang uint32_t mask_cpu = cpu_mask & 0xff; 32226ed70ecSGuanchao Liang uint32_t mask = (mask_id | SHIFT_U32(mask_group, 15) | 32326ed70ecSGuanchao Liang SHIFT_U32(mask_cpu, 16)); 32426ed70ecSGuanchao Liang 32526ed70ecSGuanchao Liang /* Should be Software Generated Interrupt */ 32626ed70ecSGuanchao Liang assert(it < NUM_SGI); 32726ed70ecSGuanchao Liang 32826ed70ecSGuanchao Liang /* Raise the interrupt */ 329918bb3a5SEtienne Carriere io_write32(gd->gicd_base + GICD_SGIR, mask); 33026ed70ecSGuanchao Liang } 33126ed70ecSGuanchao Liang 33218901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused) 333b0104773SPascal Brand { 33418901324SDavid Wang #if defined(CFG_ARM_GICV3) 3351de462e1SSumit Garg return read_icc_iar1(); 33618901324SDavid Wang #else 337918bb3a5SEtienne Carriere return io_read32(gd->gicc_base + GICC_IAR); 33818901324SDavid Wang #endif 339b0104773SPascal Brand } 340b0104773SPascal Brand 34118901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir) 342b0104773SPascal Brand { 34318901324SDavid Wang #if defined(CFG_ARM_GICV3) 3441de462e1SSumit Garg write_icc_eoir1(eoir); 34518901324SDavid Wang #else 346918bb3a5SEtienne Carriere io_write32(gd->gicc_base + GICC_EOIR, eoir); 34718901324SDavid Wang #endif 348b0104773SPascal Brand } 349b0104773SPascal Brand 3507315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it) 3517315b7b4SJens Wiklander { 35253bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 35353bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 354918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask); 35553bd332aSSY Chiu } 35653bd332aSSY Chiu 3577315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it) 3587315b7b4SJens Wiklander { 35953bd332aSSY Chiu size_t idx = it / NUM_INTS_PER_REG; 36053bd332aSSY Chiu uint32_t mask = 1 << (it % NUM_INTS_PER_REG); 361918bb3a5SEtienne Carriere return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask); 36253bd332aSSY Chiu } 36353bd332aSSY Chiu 3647315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it) 3657315b7b4SJens Wiklander { 36653bd332aSSY Chiu size_t reg_idx = it / NUM_TARGETS_PER_REG; 3677315b7b4SJens Wiklander uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * 3687315b7b4SJens Wiklander ITARGETSR_FIELD_BITS; 36953bd332aSSY Chiu uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift; 370918bb3a5SEtienne Carriere uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)); 3717315b7b4SJens Wiklander 372918bb3a5SEtienne Carriere return (target & target_mask) >> target_shift; 37353bd332aSSY Chiu } 37453bd332aSSY Chiu 3757315b7b4SJens Wiklander void gic_dump_state(struct gic_data *gd) 37653bd332aSSY Chiu { 37753bd332aSSY Chiu int i; 37853bd332aSSY Chiu 37918901324SDavid Wang #if defined(CFG_ARM_GICV3) 38018901324SDavid Wang DMSG("GICC_CTLR: 0x%x", read_icc_ctlr()); 38118901324SDavid Wang #else 382918bb3a5SEtienne Carriere DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR)); 38318901324SDavid Wang #endif 384918bb3a5SEtienne Carriere DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR)); 3857315b7b4SJens Wiklander 3867315b7b4SJens Wiklander for (i = 0; i < (int)gd->max_it; i++) { 3877315b7b4SJens Wiklander if (gic_it_is_enabled(gd, i)) { 38853bd332aSSY Chiu DMSG("irq%d: enabled, group:%d, target:%x", i, 3897315b7b4SJens Wiklander gic_it_get_group(gd, i), gic_it_get_target(gd, i)); 39053bd332aSSY Chiu } 39153bd332aSSY Chiu } 39253bd332aSSY Chiu } 3937315b7b4SJens Wiklander 3947315b7b4SJens Wiklander void gic_it_handle(struct gic_data *gd) 3957315b7b4SJens Wiklander { 3967315b7b4SJens Wiklander uint32_t iar; 3977315b7b4SJens Wiklander uint32_t id; 3987315b7b4SJens Wiklander 3997315b7b4SJens Wiklander iar = gic_read_iar(gd); 4007315b7b4SJens Wiklander id = iar & GICC_IAR_IT_ID_MASK; 4017315b7b4SJens Wiklander 4023b3a4611SMathieu Briand if (id < gd->max_it) 4037315b7b4SJens Wiklander itr_handle(id); 4043b3a4611SMathieu Briand else 4053b3a4611SMathieu Briand DMSG("ignoring interrupt %" PRIu32, id); 4067315b7b4SJens Wiklander 4077315b7b4SJens Wiklander gic_write_eoir(gd, iar); 4087315b7b4SJens Wiklander } 4097315b7b4SJens Wiklander 4107315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, 4117315b7b4SJens Wiklander uint32_t flags __unused) 4127315b7b4SJens Wiklander { 4137315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 4147315b7b4SJens Wiklander 415d13278b8SEtienne Carriere if (it >= gd->max_it) 416d13278b8SEtienne Carriere panic(); 417d13278b8SEtienne Carriere 4187315b7b4SJens Wiklander gic_it_add(gd, it); 4197315b7b4SJens Wiklander /* Set the CPU mask to deliver interrupts to any online core */ 4207315b7b4SJens Wiklander gic_it_set_cpu_mask(gd, it, 0xff); 4217315b7b4SJens Wiklander gic_it_set_prio(gd, it, 0x1); 4227315b7b4SJens Wiklander } 4237315b7b4SJens Wiklander 4247315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it) 4257315b7b4SJens Wiklander { 4267315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 4277315b7b4SJens Wiklander 428d13278b8SEtienne Carriere if (it >= gd->max_it) 429d13278b8SEtienne Carriere panic(); 430d13278b8SEtienne Carriere 4317315b7b4SJens Wiklander gic_it_enable(gd, it); 4327315b7b4SJens Wiklander } 4337315b7b4SJens Wiklander 4347315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it) 4357315b7b4SJens Wiklander { 4367315b7b4SJens Wiklander struct gic_data *gd = container_of(chip, struct gic_data, chip); 4377315b7b4SJens Wiklander 438d13278b8SEtienne Carriere if (it >= gd->max_it) 439d13278b8SEtienne Carriere panic(); 440d13278b8SEtienne Carriere 4417315b7b4SJens Wiklander gic_it_disable(gd, it); 4427315b7b4SJens Wiklander } 44326ed70ecSGuanchao Liang 44426ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it) 44526ed70ecSGuanchao Liang { 44626ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 44726ed70ecSGuanchao Liang 44826ed70ecSGuanchao Liang if (it >= gd->max_it) 44926ed70ecSGuanchao Liang panic(); 45026ed70ecSGuanchao Liang 45126ed70ecSGuanchao Liang gic_it_set_pending(gd, it); 45226ed70ecSGuanchao Liang } 45326ed70ecSGuanchao Liang 45426ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, 45526ed70ecSGuanchao Liang uint8_t cpu_mask) 45626ed70ecSGuanchao Liang { 45726ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 45826ed70ecSGuanchao Liang 45926ed70ecSGuanchao Liang if (it >= gd->max_it) 46026ed70ecSGuanchao Liang panic(); 46126ed70ecSGuanchao Liang 46226ed70ecSGuanchao Liang if (it < NUM_NS_SGI) 46326ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 1); 46426ed70ecSGuanchao Liang else 46526ed70ecSGuanchao Liang gic_it_raise_sgi(gd, it, cpu_mask, 0); 46626ed70ecSGuanchao Liang } 46726ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it, 46826ed70ecSGuanchao Liang uint8_t cpu_mask) 46926ed70ecSGuanchao Liang { 47026ed70ecSGuanchao Liang struct gic_data *gd = container_of(chip, struct gic_data, chip); 47126ed70ecSGuanchao Liang 47226ed70ecSGuanchao Liang if (it >= gd->max_it) 47326ed70ecSGuanchao Liang panic(); 47426ed70ecSGuanchao Liang 47526ed70ecSGuanchao Liang gic_it_set_cpu_mask(gd, it, cpu_mask); 47626ed70ecSGuanchao Liang } 477