xref: /optee_os/core/drivers/gic.c (revision 5da157f55e4ae09227454c134be945bc73929dbc)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b0104773SPascal Brand /*
305089e5fSJens Wiklander  * Copyright (c) 2016-2017, 2023 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>
1067e55c51SEtienne Carriere #include <compiler.h>
1105089e5fSJens Wiklander #include <config.h>
12b0104773SPascal Brand #include <drivers/gic.h>
1305089e5fSJens Wiklander #include <io.h>
140f93de74SEtienne Carriere #include <keep.h>
1567729d8dSLudovic Barre #include <kernel/dt.h>
1614885eb1SEtienne Carriere #include <kernel/dt_driver.h>
177315b7b4SJens Wiklander #include <kernel/interrupt.h>
1805089e5fSJens Wiklander #include <kernel/misc.h>
19d13278b8SEtienne Carriere #include <kernel/panic.h>
2005089e5fSJens Wiklander #include <libfdt.h>
2160801696SVolodymyr Babchuk #include <mm/core_memprot.h>
2260801696SVolodymyr Babchuk #include <mm/core_mmu.h>
234de4bebcSJens Wiklander #include <trace.h>
2405089e5fSJens Wiklander #include <util.h>
25b0104773SPascal Brand 
26b0104773SPascal Brand /* Offsets from gic.gicc_base */
27b0104773SPascal Brand #define GICC_CTLR		(0x000)
2830a673e3SPeter Maydell #define GICC_PMR		(0x004)
29b0104773SPascal Brand #define GICC_IAR		(0x00C)
30b0104773SPascal Brand #define GICC_EOIR		(0x010)
31b0104773SPascal Brand 
32b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0	(1 << 0)
33b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1	(1 << 1)
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 
4969171becSJens Wiklander #ifdef CFG_ARM_GICV3
5069171becSJens Wiklander #define GICD_PIDR2		(0xFFE8)
5169171becSJens Wiklander #else
5269171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */
5369171becSJens Wiklander #define GICD_PIDR2		(0xFE8)
5469171becSJens Wiklander #endif
5569171becSJens Wiklander 
5605089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0	BIT32(0)
5705089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS	BIT32(1)
5805089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S	BIT32(2)
5905089e5fSJens Wiklander #define GICD_CTLR_ARE_S		BIT32(4)
6005089e5fSJens Wiklander #define GICD_CTLR_ARE_NS	BIT32(5)
6105089e5fSJens Wiklander 
6205089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */
6305089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE	(2 * 64 * 1024)
6405089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET	(64 * 1024)
6505089e5fSJens Wiklander #define GICR_CTLR		(0x00)
6605089e5fSJens Wiklander #define GICR_TYPER		(0x08)
6705089e5fSJens Wiklander 
6805089e5fSJens Wiklander #define GICR_IGROUPR0		(GICR_SGI_BASE_OFFSET + 0x080)
6905089e5fSJens Wiklander #define GICR_IGRPMODR0		(GICR_SGI_BASE_OFFSET + 0xD00)
7005089e5fSJens Wiklander 
7105089e5fSJens Wiklander #define GICR_TYPER_LAST		BIT64(4)
7205089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT	56
7305089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT	48
7405089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT	40
7505089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT	32
76b0104773SPascal Brand 
7769171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */
7869171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT	4
7969171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK		0xF
8069171becSJens Wiklander 
8153bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
8253bd332aSSY Chiu #define NUM_PPI	32
8353bd332aSSY Chiu 
8426ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
8526ed70ecSGuanchao Liang #define NUM_SGI			16
8626ed70ecSGuanchao Liang 
8726ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
8826ed70ecSGuanchao Liang #define NUM_NS_SGI		8
8926ed70ecSGuanchao Liang 
9053bd332aSSY Chiu /* Number of interrupts in one register */
9153bd332aSSY Chiu #define NUM_INTS_PER_REG	32
9253bd332aSSY Chiu 
9353bd332aSSY Chiu /* Number of targets in one register */
9453bd332aSSY Chiu #define NUM_TARGETS_PER_REG	4
9553bd332aSSY Chiu 
9653bd332aSSY Chiu /* Accessors to access ITARGETSRn */
9753bd332aSSY Chiu #define ITARGETSR_FIELD_BITS	8
9853bd332aSSY Chiu #define ITARGETSR_FIELD_MASK	0xff
9953bd332aSSY Chiu 
1001b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK	0x1f
1017315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
1027315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
1037315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
104b0104773SPascal Brand 
105ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT	40
106ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT	16
107ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT	32
108ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT	48
109ec740b9fSJens Wiklander 
110ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK			0xf
111ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS			0x1
112ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU			0x2
113ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT	24
114ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT			15
115ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT		16
116ec740b9fSJens Wiklander 
11767e55c51SEtienne Carriere struct gic_data {
11867e55c51SEtienne Carriere 	vaddr_t gicc_base;
11967e55c51SEtienne Carriere 	vaddr_t gicd_base;
12005089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
12105089e5fSJens Wiklander 	vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE];
12205089e5fSJens Wiklander #endif
12367e55c51SEtienne Carriere 	size_t max_it;
12405089e5fSJens Wiklander 	uint32_t per_cpu_group_status;
12505089e5fSJens Wiklander 	uint32_t per_cpu_group_modifier;
12667e55c51SEtienne Carriere 	struct itr_chip chip;
12767e55c51SEtienne Carriere };
12867e55c51SEtienne Carriere 
12967e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
13067e55c51SEtienne Carriere 
131702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
132702fe5a7SClément Léger 		       uint32_t prio);
1337315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
1347315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
13526ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
13626ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
137ec740b9fSJens Wiklander 			     uint32_t cpu_mask);
13826ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
13926ed70ecSGuanchao Liang 			uint8_t cpu_mask);
1407315b7b4SJens Wiklander 
1417315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1427315b7b4SJens Wiklander 	.add = gic_op_add,
14308ded0e1SEtienne Carriere 	.mask = gic_op_disable,
14408ded0e1SEtienne Carriere 	.unmask = gic_op_enable,
1457315b7b4SJens Wiklander 	.enable = gic_op_enable,
1467315b7b4SJens Wiklander 	.disable = gic_op_disable,
14726ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
14826ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
14926ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1507315b7b4SJens Wiklander };
1513639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1527315b7b4SJens Wiklander 
15305089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
15405089e5fSJens Wiklander {
15505089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
15605089e5fSJens Wiklander 	return gd->gicr_base[get_core_pos()];
15705089e5fSJens Wiklander #else
15805089e5fSJens Wiklander 	return 0;
15905089e5fSJens Wiklander #endif
16005089e5fSJens Wiklander }
16105089e5fSJens Wiklander 
16218901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
163b0104773SPascal Brand {
164b0104773SPascal Brand 	int i;
165b0104773SPascal Brand 	uint32_t old_ctlr;
166b0104773SPascal Brand 	size_t ret = 0;
1671b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1681b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
169b0104773SPascal Brand 
170b0104773SPascal Brand 	/*
171b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
172b0104773SPascal Brand 	 */
17318901324SDavid Wang #if defined(CFG_ARM_GICV3)
17418901324SDavid Wang 	old_ctlr = read_icc_ctlr();
17518901324SDavid Wang 	write_icc_ctlr(0);
17618901324SDavid Wang #else
177918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
178918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
17918901324SDavid Wang #endif
18079f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
181b0104773SPascal Brand 		uint32_t old_reg;
182b0104773SPascal Brand 		uint32_t reg;
183b0104773SPascal Brand 		int b;
184b0104773SPascal Brand 
185918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
186918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
187918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
188918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
18979f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
190007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
19153bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
192b0104773SPascal Brand 				goto out;
193b0104773SPascal Brand 			}
194b0104773SPascal Brand 		}
195b0104773SPascal Brand 	}
196b0104773SPascal Brand out:
19718901324SDavid Wang #if defined(CFG_ARM_GICV3)
19818901324SDavid Wang 	write_icc_ctlr(old_ctlr);
19918901324SDavid Wang #else
200918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
20118901324SDavid Wang #endif
202b0104773SPascal Brand 	return ret;
203b0104773SPascal Brand }
204b0104773SPascal Brand 
205*5da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd)
206bedc2b9fSsunny {
20705089e5fSJens Wiklander 	io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status);
208bedc2b9fSsunny 
20905089e5fSJens Wiklander 	/*
21005089e5fSJens Wiklander 	 * Set the priority mask to permit Non-secure interrupts, and to
21130a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
21230a673e3SPeter Maydell 	 */
21318901324SDavid Wang #if defined(CFG_ARM_GICV3)
21418901324SDavid Wang 	write_icc_pmr(0x80);
2151fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
21618901324SDavid Wang #else
217918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
21830a673e3SPeter Maydell 
219bedc2b9fSsunny 	/* Enable GIC */
220918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
221918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
222918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
22318901324SDavid Wang #endif
224bedc2b9fSsunny }
225bedc2b9fSsunny 
226*5da157f5SJens Wiklander void gic_init_per_cpu(void)
227*5da157f5SJens Wiklander {
228*5da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
229*5da157f5SJens Wiklander 
230*5da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
231*5da157f5SJens Wiklander 	assert(gd->gicd_base);
232*5da157f5SJens Wiklander #else
233*5da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
234*5da157f5SJens Wiklander #endif
235*5da157f5SJens Wiklander 
236*5da157f5SJens Wiklander 	/* GIC is already configured in TF-A configurations */
237*5da157f5SJens Wiklander 	if (!IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW))
238*5da157f5SJens Wiklander 		init_gic_per_cpu(gd);
239*5da157f5SJens Wiklander }
240*5da157f5SJens Wiklander 
241*5da157f5SJens Wiklander void gic_cpu_init(void)
242*5da157f5SJens Wiklander {
243*5da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
244*5da157f5SJens Wiklander 
245*5da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
246*5da157f5SJens Wiklander 	assert(gd->gicd_base);
247*5da157f5SJens Wiklander #else
248*5da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
249*5da157f5SJens Wiklander #endif
250*5da157f5SJens Wiklander 	IMSG("%s is deprecated, please use gic_init_per_cpu()", __func__);
251*5da157f5SJens Wiklander 
252*5da157f5SJens Wiklander 	init_gic_per_cpu(gd);
253*5da157f5SJens Wiklander }
254*5da157f5SJens Wiklander 
2550ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
2560ee3f52eSEtienne Carriere 			  uint32_t *prio)
2570ee3f52eSEtienne Carriere {
2580ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
2590ee3f52eSEtienne Carriere 
2600ee3f52eSEtienne Carriere 	if (type)
2610ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
2620ee3f52eSEtienne Carriere 
2630ee3f52eSEtienne Carriere 	if (prio)
2640ee3f52eSEtienne Carriere 		*prio = 0;
2650ee3f52eSEtienne Carriere 
2660ee3f52eSEtienne Carriere 	if (!properties || count < 2)
2670ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
2680ee3f52eSEtienne Carriere 
2690ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
2700ee3f52eSEtienne Carriere 
2710ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
2728c7282beSEtienne Carriere 	case GIC_PPI:
2730ee3f52eSEtienne Carriere 		it_num += 16;
2740ee3f52eSEtienne Carriere 		break;
2758c7282beSEtienne Carriere 	case GIC_SPI:
2760ee3f52eSEtienne Carriere 		it_num += 32;
2770ee3f52eSEtienne Carriere 		break;
2780ee3f52eSEtienne Carriere 	default:
2790ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
2800ee3f52eSEtienne Carriere 	}
2810ee3f52eSEtienne Carriere 
2820ee3f52eSEtienne Carriere 	return it_num;
2830ee3f52eSEtienne Carriere }
2840ee3f52eSEtienne Carriere 
28505089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
28605089e5fSJens Wiklander 						   paddr_t gicr_base_pa)
28705089e5fSJens Wiklander {
28805089e5fSJens Wiklander 	size_t sz = GICR_V3_PCPUBASE_SIZE;
28905089e5fSJens Wiklander 	paddr_t pa = gicr_base_pa;
29005089e5fSJens Wiklander 	size_t core_pos = 0;
29105089e5fSJens Wiklander 	uint64_t mt_bit = 0;
29205089e5fSJens Wiklander 	uint64_t mpidr = 0;
29305089e5fSJens Wiklander 	uint64_t tv = 0;
29405089e5fSJens Wiklander 	vaddr_t va = 0;
29505089e5fSJens Wiklander 
29605089e5fSJens Wiklander #ifdef ARM64
29705089e5fSJens Wiklander 	mt_bit = read_mpidr_el1() & MPIDR_MT_MASK;
29805089e5fSJens Wiklander #endif
29905089e5fSJens Wiklander 	do {
30005089e5fSJens Wiklander 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
30105089e5fSJens Wiklander 		if (!va)
30205089e5fSJens Wiklander 			panic();
30305089e5fSJens Wiklander 		tv = io_read64(va + GICR_TYPER);
30405089e5fSJens Wiklander 
30505089e5fSJens Wiklander 		/*
30605089e5fSJens Wiklander 		 * Extract an mpidr from the Type register to calculate the
30705089e5fSJens Wiklander 		 * core position of this redistributer instance.
30805089e5fSJens Wiklander 		 */
30905089e5fSJens Wiklander 		mpidr = mt_bit;
31005089e5fSJens Wiklander 		mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) &
31105089e5fSJens Wiklander 				   MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT);
31205089e5fSJens Wiklander 		mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) &
31305089e5fSJens Wiklander 			 (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK);
31405089e5fSJens Wiklander 		core_pos = get_core_pos_mpidr(mpidr);
31505089e5fSJens Wiklander 		if (core_pos < CFG_TEE_CORE_NB_CORE) {
31605089e5fSJens Wiklander 			DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va);
31705089e5fSJens Wiklander 			gicr_base_addrs[core_pos] = va;
31805089e5fSJens Wiklander 		} else {
31905089e5fSJens Wiklander 			EMSG("Skipping too large core_pos %zu from GICR_TYPER",
32005089e5fSJens Wiklander 			     core_pos);
32105089e5fSJens Wiklander 		}
32205089e5fSJens Wiklander 		pa += sz;
32305089e5fSJens Wiklander 	} while (!(tv & GICR_TYPER_LAST));
32405089e5fSJens Wiklander }
32505089e5fSJens Wiklander 
32605089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
32705089e5fSJens Wiklander 			       paddr_t gicr_base_pa __maybe_unused)
328b0104773SPascal Brand {
32967e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
3300ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
3310ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
33269171becSJens Wiklander 	uint32_t vers __maybe_unused = 0;
3330ee3f52eSEtienne Carriere 
3340ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
3350ee3f52eSEtienne Carriere 
3360ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
3370ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
3380ee3f52eSEtienne Carriere 	if (!gicd_base)
3390ee3f52eSEtienne Carriere 		panic();
3400ee3f52eSEtienne Carriere 
34169171becSJens Wiklander 	vers = io_read32(gicd_base + GICD_PIDR2);
34269171becSJens Wiklander 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
34369171becSJens Wiklander 	vers &= GICD_PIDR2_ARCHREV_MASK;
34469171becSJens Wiklander 
34569171becSJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3)) {
34669171becSJens Wiklander 		assert(vers == 3);
34769171becSJens Wiklander 	} else {
34869171becSJens Wiklander 		assert(vers == 2);
3490ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
3500ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
3510ee3f52eSEtienne Carriere 		if (!gicc_base)
3520ee3f52eSEtienne Carriere 			panic();
3530ee3f52eSEtienne Carriere 	}
3540ee3f52eSEtienne Carriere 
3550ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
3560ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
3570ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
35805089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
35905089e5fSJens Wiklander 	probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
36005089e5fSJens Wiklander #endif
3610ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
3620ee3f52eSEtienne Carriere 
3630ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
3640ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
3650ee3f52eSEtienne Carriere }
3660ee3f52eSEtienne Carriere 
36705089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
36805089e5fSJens Wiklander 		 paddr_t gicr_base_pa)
3690ee3f52eSEtienne Carriere {
3700ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
3710ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
372b0104773SPascal Brand 
37305089e5fSJens Wiklander 	gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
374b0104773SPascal Brand 
37505089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW)
3760ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
37705089e5fSJens Wiklander 	if (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S) {
37805089e5fSJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
37905089e5fSJens Wiklander 
38005089e5fSJens Wiklander 		if (!gicr_base)
38105089e5fSJens Wiklander 			panic("GICR_BASE missing for affinity routing");
38205089e5fSJens Wiklander 		/* Secure affinity routing enabled */
38305089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gicr_base + GICR_IGROUPR0);
38405089e5fSJens Wiklander 		gd->per_cpu_group_modifier = io_read32(gicr_base +
38505089e5fSJens Wiklander 						       GICR_IGRPMODR0);
38605089e5fSJens Wiklander 	} else {
38705089e5fSJens Wiklander 		/* Legacy operation with secure affinity routing disabled */
38805089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gd->gicd_base +
38905089e5fSJens Wiklander 						     GICD_IGROUPR(0));
39005089e5fSJens Wiklander 		gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
39105089e5fSJens Wiklander 	}
39205089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/
39305089e5fSJens Wiklander 	/*
39405089e5fSJens Wiklander 	 * Without TF-A, GIC is always configured in for legacy operation
39505089e5fSJens Wiklander 	 * with secure affinity routing disabled.
39605089e5fSJens Wiklander 	 */
3977315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
398b0104773SPascal Brand 		/* Disable interrupts */
399918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
400b0104773SPascal Brand 
401b0104773SPascal Brand 		/* Make interrupts non-pending */
402918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
403b0104773SPascal Brand 
404b0104773SPascal Brand 		/* Mark interrupts non-secure */
405bedc2b9fSsunny 		if (n == 0) {
406bedc2b9fSsunny 			/* per-CPU inerrupts config:
407bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
408bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
409bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
410bedc2b9fSsunny 			 */
41105089e5fSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
41205089e5fSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
41305089e5fSJens Wiklander 			io_write32(gd->gicd_base + GICD_IGROUPR(n),
41405089e5fSJens Wiklander 				   gd->per_cpu_group_status);
415bedc2b9fSsunny 		} else {
416918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
417b0104773SPascal Brand 		}
418bedc2b9fSsunny 	}
419b0104773SPascal Brand 
42030a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
42130a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
42230a673e3SPeter Maydell 	 */
42318901324SDavid Wang #if defined(CFG_ARM_GICV3)
42418901324SDavid Wang 	write_icc_pmr(0x80);
4251fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
4261fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
42718901324SDavid Wang #else
428918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
42930a673e3SPeter Maydell 
430b0104773SPascal Brand 	/* Enable GIC */
431918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
432918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
433918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
43405089e5fSJens Wiklander 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS);
4351fcac774SSandeep Tripathy #endif
43605089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/
43767e55c51SEtienne Carriere 
43801980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
439b0104773SPascal Brand }
440b0104773SPascal Brand 
4417315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
442b0104773SPascal Brand {
44353bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
44453bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
445b0104773SPascal Brand 
44667e55c51SEtienne Carriere 	assert(gd == &gic_data);
44767e55c51SEtienne Carriere 
448b0104773SPascal Brand 	/* Disable the interrupt */
449918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
450b0104773SPascal Brand 	/* Make it non-pending */
451918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
452b0104773SPascal Brand 	/* Assign it to group0 */
453918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
4541fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
4551fcac774SSandeep Tripathy 	/* Assign it to group1S */
4561fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
4571fcac774SSandeep Tripathy #endif
458b0104773SPascal Brand }
459b0104773SPascal Brand 
4607315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
4617315b7b4SJens Wiklander 				uint8_t cpu_mask)
462b0104773SPascal Brand {
4638ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
4648ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
46553bd332aSSY Chiu 	uint32_t target, target_shift;
466918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
467918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
468b0104773SPascal Brand 
46967e55c51SEtienne Carriere 	assert(gd == &gic_data);
47067e55c51SEtienne Carriere 
471b0104773SPascal Brand 	/* Assigned to group0 */
472918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
473b0104773SPascal Brand 
474b0104773SPascal Brand 	/* Route it to selected CPUs */
475918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
47653bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
47753bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
47853bd332aSSY Chiu 	target |= cpu_mask << target_shift;
479918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
480918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
481918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
482b0104773SPascal Brand }
483b0104773SPascal Brand 
4847315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
485b0104773SPascal Brand {
4868ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
4878ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
488b0104773SPascal Brand 
48967e55c51SEtienne Carriere 	assert(gd == &gic_data);
49067e55c51SEtienne Carriere 
491b0104773SPascal Brand 	/* Assigned to group0 */
492918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
493b0104773SPascal Brand 
494b0104773SPascal Brand 	/* Set prio it to selected CPUs */
4951f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
4967315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
497918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
498b0104773SPascal Brand }
499b0104773SPascal Brand 
5007315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
501b0104773SPascal Brand {
50253bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
50353bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
504918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
505b0104773SPascal Brand 
50667e55c51SEtienne Carriere 	assert(gd == &gic_data);
50767e55c51SEtienne Carriere 
508b0104773SPascal Brand 	/* Assigned to group0 */
509918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
510b0104773SPascal Brand 
511b0104773SPascal Brand 	/* Enable the interrupt */
512918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
513b0104773SPascal Brand }
514b0104773SPascal Brand 
5157315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
516b0104773SPascal Brand {
51753bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
51853bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
519b0104773SPascal Brand 
52067e55c51SEtienne Carriere 	assert(gd == &gic_data);
52167e55c51SEtienne Carriere 
522b0104773SPascal Brand 	/* Assigned to group0 */
523918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
524b0104773SPascal Brand 
525b0104773SPascal Brand 	/* Disable the interrupt */
526918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
527b0104773SPascal Brand }
528b0104773SPascal Brand 
52926ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
53026ed70ecSGuanchao Liang {
53126ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
53226ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
53326ed70ecSGuanchao Liang 
53467e55c51SEtienne Carriere 	assert(gd == &gic_data);
53567e55c51SEtienne Carriere 
53626ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
53726ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
53826ed70ecSGuanchao Liang 
53926ed70ecSGuanchao Liang 	/* Raise the interrupt */
540918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
54126ed70ecSGuanchao Liang }
54226ed70ecSGuanchao Liang 
543ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
544ec740b9fSJens Wiklander {
545ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
546ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
547ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
548ec740b9fSJens Wiklander 
549ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
550ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
551ec740b9fSJens Wiklander }
552ec740b9fSJens Wiklander 
55354739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
554ec740b9fSJens Wiklander 			     uint32_t cpu_mask, uint8_t group)
55526ed70ecSGuanchao Liang {
55654739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
55754739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
558ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
559ec740b9fSJens Wiklander 
560ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
561ec740b9fSJens Wiklander 
562ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
563ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
564ec740b9fSJens Wiklander 	} else {
56554739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
566ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
567ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
568ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
569ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
570ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
571ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
572ec740b9fSJens Wiklander 
573ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
574ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
575ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
576ec740b9fSJens Wiklander 
577ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
578ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
579ec740b9fSJens Wiklander 		} else {
580ec740b9fSJens Wiklander 			/*
581ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
582ec740b9fSJens Wiklander 			 * same cluster now.
583ec740b9fSJens Wiklander 			 */
584ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
585ec740b9fSJens Wiklander 		}
586ec740b9fSJens Wiklander 	}
58754739cb4SMark-PK Tsai 
58854739cb4SMark-PK Tsai 	/* Raise the interrupt */
58954739cb4SMark-PK Tsai 	if (group)
59054739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
59154739cb4SMark-PK Tsai 	else
59254739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
59354739cb4SMark-PK Tsai #else
594ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
59526ed70ecSGuanchao Liang 	uint32_t mask_group = group & 0x1;
596ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
597ec740b9fSJens Wiklander 
598ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
599ec740b9fSJens Wiklander 
600ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
601ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
602ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
603ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
604ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
605ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
606ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
607ec740b9fSJens Wiklander 	} else {
608ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
609ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
610ec740b9fSJens Wiklander 	}
61126ed70ecSGuanchao Liang 
61226ed70ecSGuanchao Liang 	/* Raise the interrupt */
613918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
61454739cb4SMark-PK Tsai #endif
61526ed70ecSGuanchao Liang }
61626ed70ecSGuanchao Liang 
61718901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
618b0104773SPascal Brand {
61967e55c51SEtienne Carriere 	assert(gd == &gic_data);
62067e55c51SEtienne Carriere 
62118901324SDavid Wang #if defined(CFG_ARM_GICV3)
6221de462e1SSumit Garg 	return read_icc_iar1();
62318901324SDavid Wang #else
624918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
62518901324SDavid Wang #endif
626b0104773SPascal Brand }
627b0104773SPascal Brand 
62818901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
629b0104773SPascal Brand {
63067e55c51SEtienne Carriere 	assert(gd == &gic_data);
63167e55c51SEtienne Carriere 
63218901324SDavid Wang #if defined(CFG_ARM_GICV3)
6331de462e1SSumit Garg 	write_icc_eoir1(eoir);
63418901324SDavid Wang #else
635918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
63618901324SDavid Wang #endif
637b0104773SPascal Brand }
638b0104773SPascal Brand 
6397315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
6407315b7b4SJens Wiklander {
64153bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
64253bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
64367e55c51SEtienne Carriere 
64467e55c51SEtienne Carriere 	assert(gd == &gic_data);
645918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
64653bd332aSSY Chiu }
64753bd332aSSY Chiu 
6487315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
6497315b7b4SJens Wiklander {
65053bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
65153bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
65267e55c51SEtienne Carriere 
65367e55c51SEtienne Carriere 	assert(gd == &gic_data);
654918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
65553bd332aSSY Chiu }
65653bd332aSSY Chiu 
6577315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
6587315b7b4SJens Wiklander {
65953bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
6607315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
6617315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
66253bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
663918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
6647315b7b4SJens Wiklander 
66567e55c51SEtienne Carriere 	assert(gd == &gic_data);
666918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
66753bd332aSSY Chiu }
66853bd332aSSY Chiu 
66967e55c51SEtienne Carriere void gic_dump_state(void)
67053bd332aSSY Chiu {
67167e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
67267e55c51SEtienne Carriere 	int i = 0;
67353bd332aSSY Chiu 
67418901324SDavid Wang #if defined(CFG_ARM_GICV3)
67518901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
67618901324SDavid Wang #else
677918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
67818901324SDavid Wang #endif
679918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
6807315b7b4SJens Wiklander 
6814a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
6827315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
68353bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
6847315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
68553bd332aSSY Chiu 		}
68653bd332aSSY Chiu 	}
68753bd332aSSY Chiu }
6887315b7b4SJens Wiklander 
68967e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
6907315b7b4SJens Wiklander {
69167e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
69267e55c51SEtienne Carriere 	uint32_t iar = 0;
69367e55c51SEtienne Carriere 	uint32_t id = 0;
6947315b7b4SJens Wiklander 
6957315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
6967315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
6977315b7b4SJens Wiklander 
6984a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
69999e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
7003b3a4611SMathieu Briand 	else
7013b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
7027315b7b4SJens Wiklander 
7037315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
7047315b7b4SJens Wiklander }
7057315b7b4SJens Wiklander 
70667e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
707358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
708358bf47cSEtienne Carriere void interrupt_main_handler(void)
70967e55c51SEtienne Carriere {
71067e55c51SEtienne Carriere 	gic_native_itr_handler();
71167e55c51SEtienne Carriere }
71267e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
71367e55c51SEtienne Carriere 
7147315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
715702fe5a7SClément Léger 		       uint32_t type __unused,
716702fe5a7SClément Léger 		       uint32_t prio __unused)
7177315b7b4SJens Wiklander {
7187315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
7197315b7b4SJens Wiklander 
72067e55c51SEtienne Carriere 	assert(gd == &gic_data);
72167e55c51SEtienne Carriere 
7224a9ea08cSFangsuo Wu 	if (it > gd->max_it)
723d13278b8SEtienne Carriere 		panic();
724d13278b8SEtienne Carriere 
7257315b7b4SJens Wiklander 	gic_it_add(gd, it);
7267315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
7277315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
7287315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
7297315b7b4SJens Wiklander }
7307315b7b4SJens Wiklander 
7317315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
7327315b7b4SJens Wiklander {
7337315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
7347315b7b4SJens Wiklander 
73567e55c51SEtienne Carriere 	assert(gd == &gic_data);
73667e55c51SEtienne Carriere 
7374a9ea08cSFangsuo Wu 	if (it > gd->max_it)
738d13278b8SEtienne Carriere 		panic();
739d13278b8SEtienne Carriere 
7407315b7b4SJens Wiklander 	gic_it_enable(gd, it);
7417315b7b4SJens Wiklander }
7427315b7b4SJens Wiklander 
7437315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
7447315b7b4SJens Wiklander {
7457315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
7467315b7b4SJens Wiklander 
74767e55c51SEtienne Carriere 	assert(gd == &gic_data);
74867e55c51SEtienne Carriere 
7494a9ea08cSFangsuo Wu 	if (it > gd->max_it)
750d13278b8SEtienne Carriere 		panic();
751d13278b8SEtienne Carriere 
7527315b7b4SJens Wiklander 	gic_it_disable(gd, it);
7537315b7b4SJens Wiklander }
75426ed70ecSGuanchao Liang 
75526ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
75626ed70ecSGuanchao Liang {
75726ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
75826ed70ecSGuanchao Liang 
75967e55c51SEtienne Carriere 	assert(gd == &gic_data);
76067e55c51SEtienne Carriere 
7614a9ea08cSFangsuo Wu 	if (it > gd->max_it)
76226ed70ecSGuanchao Liang 		panic();
76326ed70ecSGuanchao Liang 
76426ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
76526ed70ecSGuanchao Liang }
76626ed70ecSGuanchao Liang 
76726ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
768ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
76926ed70ecSGuanchao Liang {
77026ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
77126ed70ecSGuanchao Liang 
77267e55c51SEtienne Carriere 	assert(gd == &gic_data);
77367e55c51SEtienne Carriere 
77454739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
77554739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
77654739cb4SMark-PK Tsai 
77726ed70ecSGuanchao Liang 	if (it < NUM_NS_SGI)
77826ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 1);
77926ed70ecSGuanchao Liang 	else
78026ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 0);
78126ed70ecSGuanchao Liang }
78267e55c51SEtienne Carriere 
78326ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
78426ed70ecSGuanchao Liang 			uint8_t cpu_mask)
78526ed70ecSGuanchao Liang {
78626ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
78726ed70ecSGuanchao Liang 
78867e55c51SEtienne Carriere 	assert(gd == &gic_data);
78967e55c51SEtienne Carriere 
7904a9ea08cSFangsuo Wu 	if (it > gd->max_it)
79126ed70ecSGuanchao Liang 		panic();
79226ed70ecSGuanchao Liang 
79326ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
79426ed70ecSGuanchao Liang }
79514885eb1SEtienne Carriere 
79614885eb1SEtienne Carriere #ifdef CFG_DT
79714885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
79814885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
79914885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
80014885eb1SEtienne Carriere {
80114885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
80214885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
80314885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
80414885eb1SEtienne Carriere 	uint32_t type = 0;
80514885eb1SEtienne Carriere 	uint32_t prio = 0;
80614885eb1SEtienne Carriere 
80714885eb1SEtienne Carriere 	assert(arg && itr_desc);
80814885eb1SEtienne Carriere 
80914885eb1SEtienne Carriere 	/*
81014885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
81114885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
81214885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
81314885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
81414885eb1SEtienne Carriere 	 */
81514885eb1SEtienne Carriere 	if (arg->args_count < 2)
81614885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
81714885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
81814885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
81914885eb1SEtienne Carriere 
82014885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
82114885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
82214885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
82314885eb1SEtienne Carriere 
82414885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
82514885eb1SEtienne Carriere 
82614885eb1SEtienne Carriere 	itr_desc->chip = chip;
82714885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
82814885eb1SEtienne Carriere 
82914885eb1SEtienne Carriere 	return TEE_SUCCESS;
83014885eb1SEtienne Carriere }
83114885eb1SEtienne Carriere 
83214885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
83314885eb1SEtienne Carriere {
83414885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
83514885eb1SEtienne Carriere 					&gic_data.chip))
83614885eb1SEtienne Carriere 		panic();
83714885eb1SEtienne Carriere 
83814885eb1SEtienne Carriere 	return TEE_SUCCESS;
83914885eb1SEtienne Carriere }
84014885eb1SEtienne Carriere 
84114885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
84214885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
84314885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
84414885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
84514885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
84614885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
84714885eb1SEtienne Carriere 	{ }
84814885eb1SEtienne Carriere };
84914885eb1SEtienne Carriere 
85014885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
85114885eb1SEtienne Carriere 	.name = "gic",
85214885eb1SEtienne Carriere 	.match_table = gic_match_table,
85314885eb1SEtienne Carriere 	.probe = gic_probe,
85414885eb1SEtienne Carriere };
85514885eb1SEtienne Carriere #endif /*CFG_DT*/
856