xref: /optee_os/core/drivers/gic.c (revision 05089e5f9a56db581046e9966179bb96e042a07e)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b0104773SPascal Brand /*
3*05089e5fSJens 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>
11*05089e5fSJens Wiklander #include <config.h>
12b0104773SPascal Brand #include <drivers/gic.h>
13*05089e5fSJens 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>
18*05089e5fSJens Wiklander #include <kernel/misc.h>
19d13278b8SEtienne Carriere #include <kernel/panic.h>
20*05089e5fSJens Wiklander #include <libfdt.h>
2160801696SVolodymyr Babchuk #include <mm/core_memprot.h>
2260801696SVolodymyr Babchuk #include <mm/core_mmu.h>
234de4bebcSJens Wiklander #include <trace.h>
24*05089e5fSJens 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 
56*05089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0	BIT32(0)
57*05089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS	BIT32(1)
58*05089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S	BIT32(2)
59*05089e5fSJens Wiklander #define GICD_CTLR_ARE_S		BIT32(4)
60*05089e5fSJens Wiklander #define GICD_CTLR_ARE_NS	BIT32(5)
61*05089e5fSJens Wiklander 
62*05089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */
63*05089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE	(2 * 64 * 1024)
64*05089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET	(64 * 1024)
65*05089e5fSJens Wiklander #define GICR_CTLR		(0x00)
66*05089e5fSJens Wiklander #define GICR_TYPER		(0x08)
67*05089e5fSJens Wiklander 
68*05089e5fSJens Wiklander #define GICR_IGROUPR0		(GICR_SGI_BASE_OFFSET + 0x080)
69*05089e5fSJens Wiklander #define GICR_IGRPMODR0		(GICR_SGI_BASE_OFFSET + 0xD00)
70*05089e5fSJens Wiklander 
71*05089e5fSJens Wiklander #define GICR_TYPER_LAST		BIT64(4)
72*05089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT	56
73*05089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT	48
74*05089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT	40
75*05089e5fSJens 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;
120*05089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
121*05089e5fSJens Wiklander 	vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE];
122*05089e5fSJens Wiklander #endif
12367e55c51SEtienne Carriere 	size_t max_it;
124*05089e5fSJens Wiklander 	uint32_t per_cpu_group_status;
125*05089e5fSJens 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 
153*05089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
154*05089e5fSJens Wiklander {
155*05089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
156*05089e5fSJens Wiklander 	return gd->gicr_base[get_core_pos()];
157*05089e5fSJens Wiklander #else
158*05089e5fSJens Wiklander 	return 0;
159*05089e5fSJens Wiklander #endif
160*05089e5fSJens Wiklander }
161*05089e5fSJens 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 
20567e55c51SEtienne Carriere void gic_cpu_init(void)
206bedc2b9fSsunny {
20767e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
20867e55c51SEtienne Carriere 
20918901324SDavid Wang #if defined(CFG_ARM_GICV3)
21018901324SDavid Wang 	assert(gd->gicd_base);
21118901324SDavid Wang #else
21205efe1e1SEtienne Carriere 	assert(gd->gicd_base && gd->gicc_base);
21318901324SDavid Wang #endif
21405efe1e1SEtienne Carriere 
215*05089e5fSJens Wiklander 	io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status);
216bedc2b9fSsunny 
217*05089e5fSJens Wiklander 	/*
218*05089e5fSJens Wiklander 	 * Set the priority mask to permit Non-secure interrupts, and to
21930a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
22030a673e3SPeter Maydell 	 */
22118901324SDavid Wang #if defined(CFG_ARM_GICV3)
22218901324SDavid Wang 	write_icc_pmr(0x80);
2231fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
22418901324SDavid Wang #else
225918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
22630a673e3SPeter Maydell 
227bedc2b9fSsunny 	/* Enable GIC */
228918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
229918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
230918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
23118901324SDavid Wang #endif
232bedc2b9fSsunny }
233bedc2b9fSsunny 
2340ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
2350ee3f52eSEtienne Carriere 			  uint32_t *prio)
2360ee3f52eSEtienne Carriere {
2370ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
2380ee3f52eSEtienne Carriere 
2390ee3f52eSEtienne Carriere 	if (type)
2400ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
2410ee3f52eSEtienne Carriere 
2420ee3f52eSEtienne Carriere 	if (prio)
2430ee3f52eSEtienne Carriere 		*prio = 0;
2440ee3f52eSEtienne Carriere 
2450ee3f52eSEtienne Carriere 	if (!properties || count < 2)
2460ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
2470ee3f52eSEtienne Carriere 
2480ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
2490ee3f52eSEtienne Carriere 
2500ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
2518c7282beSEtienne Carriere 	case GIC_PPI:
2520ee3f52eSEtienne Carriere 		it_num += 16;
2530ee3f52eSEtienne Carriere 		break;
2548c7282beSEtienne Carriere 	case GIC_SPI:
2550ee3f52eSEtienne Carriere 		it_num += 32;
2560ee3f52eSEtienne Carriere 		break;
2570ee3f52eSEtienne Carriere 	default:
2580ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
2590ee3f52eSEtienne Carriere 	}
2600ee3f52eSEtienne Carriere 
2610ee3f52eSEtienne Carriere 	return it_num;
2620ee3f52eSEtienne Carriere }
2630ee3f52eSEtienne Carriere 
264*05089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
265*05089e5fSJens Wiklander 						   paddr_t gicr_base_pa)
266*05089e5fSJens Wiklander {
267*05089e5fSJens Wiklander 	size_t sz = GICR_V3_PCPUBASE_SIZE;
268*05089e5fSJens Wiklander 	paddr_t pa = gicr_base_pa;
269*05089e5fSJens Wiklander 	size_t core_pos = 0;
270*05089e5fSJens Wiklander 	uint64_t mt_bit = 0;
271*05089e5fSJens Wiklander 	uint64_t mpidr = 0;
272*05089e5fSJens Wiklander 	uint64_t tv = 0;
273*05089e5fSJens Wiklander 	vaddr_t va = 0;
274*05089e5fSJens Wiklander 
275*05089e5fSJens Wiklander #ifdef ARM64
276*05089e5fSJens Wiklander 	mt_bit = read_mpidr_el1() & MPIDR_MT_MASK;
277*05089e5fSJens Wiklander #endif
278*05089e5fSJens Wiklander 	do {
279*05089e5fSJens Wiklander 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
280*05089e5fSJens Wiklander 		if (!va)
281*05089e5fSJens Wiklander 			panic();
282*05089e5fSJens Wiklander 		tv = io_read64(va + GICR_TYPER);
283*05089e5fSJens Wiklander 
284*05089e5fSJens Wiklander 		/*
285*05089e5fSJens Wiklander 		 * Extract an mpidr from the Type register to calculate the
286*05089e5fSJens Wiklander 		 * core position of this redistributer instance.
287*05089e5fSJens Wiklander 		 */
288*05089e5fSJens Wiklander 		mpidr = mt_bit;
289*05089e5fSJens Wiklander 		mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) &
290*05089e5fSJens Wiklander 				   MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT);
291*05089e5fSJens Wiklander 		mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) &
292*05089e5fSJens Wiklander 			 (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK);
293*05089e5fSJens Wiklander 		core_pos = get_core_pos_mpidr(mpidr);
294*05089e5fSJens Wiklander 		if (core_pos < CFG_TEE_CORE_NB_CORE) {
295*05089e5fSJens Wiklander 			DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va);
296*05089e5fSJens Wiklander 			gicr_base_addrs[core_pos] = va;
297*05089e5fSJens Wiklander 		} else {
298*05089e5fSJens Wiklander 			EMSG("Skipping too large core_pos %zu from GICR_TYPER",
299*05089e5fSJens Wiklander 			     core_pos);
300*05089e5fSJens Wiklander 		}
301*05089e5fSJens Wiklander 		pa += sz;
302*05089e5fSJens Wiklander 	} while (!(tv & GICR_TYPER_LAST));
303*05089e5fSJens Wiklander }
304*05089e5fSJens Wiklander 
305*05089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
306*05089e5fSJens Wiklander 			       paddr_t gicr_base_pa __maybe_unused)
307b0104773SPascal Brand {
30867e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
3090ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
3100ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
31169171becSJens Wiklander 	uint32_t vers __maybe_unused = 0;
3120ee3f52eSEtienne Carriere 
3130ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
3140ee3f52eSEtienne Carriere 
3150ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
3160ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
3170ee3f52eSEtienne Carriere 	if (!gicd_base)
3180ee3f52eSEtienne Carriere 		panic();
3190ee3f52eSEtienne Carriere 
32069171becSJens Wiklander 	vers = io_read32(gicd_base + GICD_PIDR2);
32169171becSJens Wiklander 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
32269171becSJens Wiklander 	vers &= GICD_PIDR2_ARCHREV_MASK;
32369171becSJens Wiklander 
32469171becSJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3)) {
32569171becSJens Wiklander 		assert(vers == 3);
32669171becSJens Wiklander 	} else {
32769171becSJens Wiklander 		assert(vers == 2);
3280ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
3290ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
3300ee3f52eSEtienne Carriere 		if (!gicc_base)
3310ee3f52eSEtienne Carriere 			panic();
3320ee3f52eSEtienne Carriere 	}
3330ee3f52eSEtienne Carriere 
3340ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
3350ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
3360ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
337*05089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
338*05089e5fSJens Wiklander 	probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
339*05089e5fSJens Wiklander #endif
3400ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
3410ee3f52eSEtienne Carriere 
3420ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
3430ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
3440ee3f52eSEtienne Carriere }
3450ee3f52eSEtienne Carriere 
346*05089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
347*05089e5fSJens Wiklander 		 paddr_t gicr_base_pa)
3480ee3f52eSEtienne Carriere {
3490ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
3500ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
351b0104773SPascal Brand 
352*05089e5fSJens Wiklander 	gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
353b0104773SPascal Brand 
354*05089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW)
3550ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
356*05089e5fSJens Wiklander 	if (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S) {
357*05089e5fSJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
358*05089e5fSJens Wiklander 
359*05089e5fSJens Wiklander 		if (!gicr_base)
360*05089e5fSJens Wiklander 			panic("GICR_BASE missing for affinity routing");
361*05089e5fSJens Wiklander 		/* Secure affinity routing enabled */
362*05089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gicr_base + GICR_IGROUPR0);
363*05089e5fSJens Wiklander 		gd->per_cpu_group_modifier = io_read32(gicr_base +
364*05089e5fSJens Wiklander 						       GICR_IGRPMODR0);
365*05089e5fSJens Wiklander 	} else {
366*05089e5fSJens Wiklander 		/* Legacy operation with secure affinity routing disabled */
367*05089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gd->gicd_base +
368*05089e5fSJens Wiklander 						     GICD_IGROUPR(0));
369*05089e5fSJens Wiklander 		gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
370*05089e5fSJens Wiklander 	}
371*05089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/
372*05089e5fSJens Wiklander 	/*
373*05089e5fSJens Wiklander 	 * Without TF-A, GIC is always configured in for legacy operation
374*05089e5fSJens Wiklander 	 * with secure affinity routing disabled.
375*05089e5fSJens Wiklander 	 */
3767315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
377b0104773SPascal Brand 		/* Disable interrupts */
378918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
379b0104773SPascal Brand 
380b0104773SPascal Brand 		/* Make interrupts non-pending */
381918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
382b0104773SPascal Brand 
383b0104773SPascal Brand 		/* Mark interrupts non-secure */
384bedc2b9fSsunny 		if (n == 0) {
385bedc2b9fSsunny 			/* per-CPU inerrupts config:
386bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
387bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
388bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
389bedc2b9fSsunny 			 */
390*05089e5fSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
391*05089e5fSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
392*05089e5fSJens Wiklander 			io_write32(gd->gicd_base + GICD_IGROUPR(n),
393*05089e5fSJens Wiklander 				   gd->per_cpu_group_status);
394bedc2b9fSsunny 		} else {
395918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
396b0104773SPascal Brand 		}
397bedc2b9fSsunny 	}
398b0104773SPascal Brand 
39930a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
40030a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
40130a673e3SPeter Maydell 	 */
40218901324SDavid Wang #if defined(CFG_ARM_GICV3)
40318901324SDavid Wang 	write_icc_pmr(0x80);
4041fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
4051fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
40618901324SDavid Wang #else
407918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
40830a673e3SPeter Maydell 
409b0104773SPascal Brand 	/* Enable GIC */
410918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
411918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
412918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
413*05089e5fSJens Wiklander 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS);
4141fcac774SSandeep Tripathy #endif
415*05089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/
41667e55c51SEtienne Carriere 
41701980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
418b0104773SPascal Brand }
419b0104773SPascal Brand 
4207315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
421b0104773SPascal Brand {
42253bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
42353bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
424b0104773SPascal Brand 
42567e55c51SEtienne Carriere 	assert(gd == &gic_data);
42667e55c51SEtienne Carriere 
427b0104773SPascal Brand 	/* Disable the interrupt */
428918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
429b0104773SPascal Brand 	/* Make it non-pending */
430918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
431b0104773SPascal Brand 	/* Assign it to group0 */
432918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
4331fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
4341fcac774SSandeep Tripathy 	/* Assign it to group1S */
4351fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
4361fcac774SSandeep Tripathy #endif
437b0104773SPascal Brand }
438b0104773SPascal Brand 
4397315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
4407315b7b4SJens Wiklander 				uint8_t cpu_mask)
441b0104773SPascal Brand {
4428ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
4438ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
44453bd332aSSY Chiu 	uint32_t target, target_shift;
445918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
446918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
447b0104773SPascal Brand 
44867e55c51SEtienne Carriere 	assert(gd == &gic_data);
44967e55c51SEtienne Carriere 
450b0104773SPascal Brand 	/* Assigned to group0 */
451918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
452b0104773SPascal Brand 
453b0104773SPascal Brand 	/* Route it to selected CPUs */
454918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
45553bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
45653bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
45753bd332aSSY Chiu 	target |= cpu_mask << target_shift;
458918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
459918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
460918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
461b0104773SPascal Brand }
462b0104773SPascal Brand 
4637315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
464b0104773SPascal Brand {
4658ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
4668ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
467b0104773SPascal Brand 
46867e55c51SEtienne Carriere 	assert(gd == &gic_data);
46967e55c51SEtienne Carriere 
470b0104773SPascal Brand 	/* Assigned to group0 */
471918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
472b0104773SPascal Brand 
473b0104773SPascal Brand 	/* Set prio it to selected CPUs */
4741f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
4757315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
476918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
477b0104773SPascal Brand }
478b0104773SPascal Brand 
4797315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
480b0104773SPascal Brand {
48153bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
48253bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
483918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
484b0104773SPascal Brand 
48567e55c51SEtienne Carriere 	assert(gd == &gic_data);
48667e55c51SEtienne Carriere 
487b0104773SPascal Brand 	/* Assigned to group0 */
488918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
489b0104773SPascal Brand 
490b0104773SPascal Brand 	/* Enable the interrupt */
491918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
492b0104773SPascal Brand }
493b0104773SPascal Brand 
4947315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
495b0104773SPascal Brand {
49653bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
49753bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
498b0104773SPascal Brand 
49967e55c51SEtienne Carriere 	assert(gd == &gic_data);
50067e55c51SEtienne Carriere 
501b0104773SPascal Brand 	/* Assigned to group0 */
502918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
503b0104773SPascal Brand 
504b0104773SPascal Brand 	/* Disable the interrupt */
505918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
506b0104773SPascal Brand }
507b0104773SPascal Brand 
50826ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
50926ed70ecSGuanchao Liang {
51026ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
51126ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
51226ed70ecSGuanchao Liang 
51367e55c51SEtienne Carriere 	assert(gd == &gic_data);
51467e55c51SEtienne Carriere 
51526ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
51626ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
51726ed70ecSGuanchao Liang 
51826ed70ecSGuanchao Liang 	/* Raise the interrupt */
519918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
52026ed70ecSGuanchao Liang }
52126ed70ecSGuanchao Liang 
522ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
523ec740b9fSJens Wiklander {
524ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
525ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
526ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
527ec740b9fSJens Wiklander 
528ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
529ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
530ec740b9fSJens Wiklander }
531ec740b9fSJens Wiklander 
53254739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
533ec740b9fSJens Wiklander 			     uint32_t cpu_mask, uint8_t group)
53426ed70ecSGuanchao Liang {
53554739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
53654739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
537ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
538ec740b9fSJens Wiklander 
539ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
540ec740b9fSJens Wiklander 
541ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
542ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
543ec740b9fSJens Wiklander 	} else {
54454739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
545ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
546ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
547ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
548ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
549ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
550ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
551ec740b9fSJens Wiklander 
552ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
553ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
554ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
555ec740b9fSJens Wiklander 
556ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
557ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
558ec740b9fSJens Wiklander 		} else {
559ec740b9fSJens Wiklander 			/*
560ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
561ec740b9fSJens Wiklander 			 * same cluster now.
562ec740b9fSJens Wiklander 			 */
563ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
564ec740b9fSJens Wiklander 		}
565ec740b9fSJens Wiklander 	}
56654739cb4SMark-PK Tsai 
56754739cb4SMark-PK Tsai 	/* Raise the interrupt */
56854739cb4SMark-PK Tsai 	if (group)
56954739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
57054739cb4SMark-PK Tsai 	else
57154739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
57254739cb4SMark-PK Tsai #else
573ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
57426ed70ecSGuanchao Liang 	uint32_t mask_group = group & 0x1;
575ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
576ec740b9fSJens Wiklander 
577ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
578ec740b9fSJens Wiklander 
579ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
580ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
581ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
582ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
583ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
584ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
585ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
586ec740b9fSJens Wiklander 	} else {
587ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
588ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
589ec740b9fSJens Wiklander 	}
59026ed70ecSGuanchao Liang 
59126ed70ecSGuanchao Liang 	/* Raise the interrupt */
592918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
59354739cb4SMark-PK Tsai #endif
59426ed70ecSGuanchao Liang }
59526ed70ecSGuanchao Liang 
59618901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
597b0104773SPascal Brand {
59867e55c51SEtienne Carriere 	assert(gd == &gic_data);
59967e55c51SEtienne Carriere 
60018901324SDavid Wang #if defined(CFG_ARM_GICV3)
6011de462e1SSumit Garg 	return read_icc_iar1();
60218901324SDavid Wang #else
603918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
60418901324SDavid Wang #endif
605b0104773SPascal Brand }
606b0104773SPascal Brand 
60718901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
608b0104773SPascal Brand {
60967e55c51SEtienne Carriere 	assert(gd == &gic_data);
61067e55c51SEtienne Carriere 
61118901324SDavid Wang #if defined(CFG_ARM_GICV3)
6121de462e1SSumit Garg 	write_icc_eoir1(eoir);
61318901324SDavid Wang #else
614918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
61518901324SDavid Wang #endif
616b0104773SPascal Brand }
617b0104773SPascal Brand 
6187315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
6197315b7b4SJens Wiklander {
62053bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
62153bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
62267e55c51SEtienne Carriere 
62367e55c51SEtienne Carriere 	assert(gd == &gic_data);
624918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
62553bd332aSSY Chiu }
62653bd332aSSY Chiu 
6277315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
6287315b7b4SJens Wiklander {
62953bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
63053bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
63167e55c51SEtienne Carriere 
63267e55c51SEtienne Carriere 	assert(gd == &gic_data);
633918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
63453bd332aSSY Chiu }
63553bd332aSSY Chiu 
6367315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
6377315b7b4SJens Wiklander {
63853bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
6397315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
6407315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
64153bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
642918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
6437315b7b4SJens Wiklander 
64467e55c51SEtienne Carriere 	assert(gd == &gic_data);
645918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
64653bd332aSSY Chiu }
64753bd332aSSY Chiu 
64867e55c51SEtienne Carriere void gic_dump_state(void)
64953bd332aSSY Chiu {
65067e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
65167e55c51SEtienne Carriere 	int i = 0;
65253bd332aSSY Chiu 
65318901324SDavid Wang #if defined(CFG_ARM_GICV3)
65418901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
65518901324SDavid Wang #else
656918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
65718901324SDavid Wang #endif
658918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
6597315b7b4SJens Wiklander 
6604a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
6617315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
66253bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
6637315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
66453bd332aSSY Chiu 		}
66553bd332aSSY Chiu 	}
66653bd332aSSY Chiu }
6677315b7b4SJens Wiklander 
66867e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
6697315b7b4SJens Wiklander {
67067e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
67167e55c51SEtienne Carriere 	uint32_t iar = 0;
67267e55c51SEtienne Carriere 	uint32_t id = 0;
6737315b7b4SJens Wiklander 
6747315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
6757315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
6767315b7b4SJens Wiklander 
6774a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
67899e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
6793b3a4611SMathieu Briand 	else
6803b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
6817315b7b4SJens Wiklander 
6827315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
6837315b7b4SJens Wiklander }
6847315b7b4SJens Wiklander 
68567e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
686358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
687358bf47cSEtienne Carriere void interrupt_main_handler(void)
68867e55c51SEtienne Carriere {
68967e55c51SEtienne Carriere 	gic_native_itr_handler();
69067e55c51SEtienne Carriere }
69167e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
69267e55c51SEtienne Carriere 
6937315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
694702fe5a7SClément Léger 		       uint32_t type __unused,
695702fe5a7SClément Léger 		       uint32_t prio __unused)
6967315b7b4SJens Wiklander {
6977315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
6987315b7b4SJens Wiklander 
69967e55c51SEtienne Carriere 	assert(gd == &gic_data);
70067e55c51SEtienne Carriere 
7014a9ea08cSFangsuo Wu 	if (it > gd->max_it)
702d13278b8SEtienne Carriere 		panic();
703d13278b8SEtienne Carriere 
7047315b7b4SJens Wiklander 	gic_it_add(gd, it);
7057315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
7067315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
7077315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
7087315b7b4SJens Wiklander }
7097315b7b4SJens Wiklander 
7107315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
7117315b7b4SJens Wiklander {
7127315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
7137315b7b4SJens Wiklander 
71467e55c51SEtienne Carriere 	assert(gd == &gic_data);
71567e55c51SEtienne Carriere 
7164a9ea08cSFangsuo Wu 	if (it > gd->max_it)
717d13278b8SEtienne Carriere 		panic();
718d13278b8SEtienne Carriere 
7197315b7b4SJens Wiklander 	gic_it_enable(gd, it);
7207315b7b4SJens Wiklander }
7217315b7b4SJens Wiklander 
7227315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
7237315b7b4SJens Wiklander {
7247315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
7257315b7b4SJens Wiklander 
72667e55c51SEtienne Carriere 	assert(gd == &gic_data);
72767e55c51SEtienne Carriere 
7284a9ea08cSFangsuo Wu 	if (it > gd->max_it)
729d13278b8SEtienne Carriere 		panic();
730d13278b8SEtienne Carriere 
7317315b7b4SJens Wiklander 	gic_it_disable(gd, it);
7327315b7b4SJens Wiklander }
73326ed70ecSGuanchao Liang 
73426ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
73526ed70ecSGuanchao Liang {
73626ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
73726ed70ecSGuanchao Liang 
73867e55c51SEtienne Carriere 	assert(gd == &gic_data);
73967e55c51SEtienne Carriere 
7404a9ea08cSFangsuo Wu 	if (it > gd->max_it)
74126ed70ecSGuanchao Liang 		panic();
74226ed70ecSGuanchao Liang 
74326ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
74426ed70ecSGuanchao Liang }
74526ed70ecSGuanchao Liang 
74626ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
747ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
74826ed70ecSGuanchao Liang {
74926ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
75026ed70ecSGuanchao Liang 
75167e55c51SEtienne Carriere 	assert(gd == &gic_data);
75267e55c51SEtienne Carriere 
75354739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
75454739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
75554739cb4SMark-PK Tsai 
75626ed70ecSGuanchao Liang 	if (it < NUM_NS_SGI)
75726ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 1);
75826ed70ecSGuanchao Liang 	else
75926ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 0);
76026ed70ecSGuanchao Liang }
76167e55c51SEtienne Carriere 
76226ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
76326ed70ecSGuanchao Liang 			uint8_t cpu_mask)
76426ed70ecSGuanchao Liang {
76526ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
76626ed70ecSGuanchao Liang 
76767e55c51SEtienne Carriere 	assert(gd == &gic_data);
76867e55c51SEtienne Carriere 
7694a9ea08cSFangsuo Wu 	if (it > gd->max_it)
77026ed70ecSGuanchao Liang 		panic();
77126ed70ecSGuanchao Liang 
77226ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
77326ed70ecSGuanchao Liang }
77414885eb1SEtienne Carriere 
77514885eb1SEtienne Carriere #ifdef CFG_DT
77614885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
77714885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
77814885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
77914885eb1SEtienne Carriere {
78014885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
78114885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
78214885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
78314885eb1SEtienne Carriere 	uint32_t type = 0;
78414885eb1SEtienne Carriere 	uint32_t prio = 0;
78514885eb1SEtienne Carriere 
78614885eb1SEtienne Carriere 	assert(arg && itr_desc);
78714885eb1SEtienne Carriere 
78814885eb1SEtienne Carriere 	/*
78914885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
79014885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
79114885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
79214885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
79314885eb1SEtienne Carriere 	 */
79414885eb1SEtienne Carriere 	if (arg->args_count < 2)
79514885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
79614885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
79714885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
79814885eb1SEtienne Carriere 
79914885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
80014885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
80114885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
80214885eb1SEtienne Carriere 
80314885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
80414885eb1SEtienne Carriere 
80514885eb1SEtienne Carriere 	itr_desc->chip = chip;
80614885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
80714885eb1SEtienne Carriere 
80814885eb1SEtienne Carriere 	return TEE_SUCCESS;
80914885eb1SEtienne Carriere }
81014885eb1SEtienne Carriere 
81114885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
81214885eb1SEtienne Carriere {
81314885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
81414885eb1SEtienne Carriere 					&gic_data.chip))
81514885eb1SEtienne Carriere 		panic();
81614885eb1SEtienne Carriere 
81714885eb1SEtienne Carriere 	return TEE_SUCCESS;
81814885eb1SEtienne Carriere }
81914885eb1SEtienne Carriere 
82014885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
82114885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
82214885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
82314885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
82414885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
82514885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
82614885eb1SEtienne Carriere 	{ }
82714885eb1SEtienne Carriere };
82814885eb1SEtienne Carriere 
82914885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
83014885eb1SEtienne Carriere 	.name = "gic",
83114885eb1SEtienne Carriere 	.match_table = gic_match_table,
83214885eb1SEtienne Carriere 	.probe = gic_probe,
83314885eb1SEtienne Carriere };
83414885eb1SEtienne Carriere #endif /*CFG_DT*/
835