xref: /optee_os/core/drivers/gic.c (revision 846034561d2fb13e177396e9cd199ffb90c4ad9c)
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)
70*84603456SJens Wiklander #define GICR_ICENABLER0		(GICR_SGI_BASE_OFFSET + 0x180)
71*84603456SJens Wiklander #define GICR_ICPENDR0		(GICR_SGI_BASE_OFFSET + 0x280)
7205089e5fSJens Wiklander 
7305089e5fSJens Wiklander #define GICR_TYPER_LAST		BIT64(4)
7405089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT	56
7505089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT	48
7605089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT	40
7705089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT	32
78b0104773SPascal Brand 
7969171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */
8069171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT	4
8169171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK		0xF
8269171becSJens Wiklander 
8353bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
8453bd332aSSY Chiu #define NUM_PPI	32
8553bd332aSSY Chiu 
8626ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
8726ed70ecSGuanchao Liang #define NUM_SGI			16
8826ed70ecSGuanchao Liang 
8926ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
9026ed70ecSGuanchao Liang #define NUM_NS_SGI		8
9126ed70ecSGuanchao Liang 
9253bd332aSSY Chiu /* Number of interrupts in one register */
9353bd332aSSY Chiu #define NUM_INTS_PER_REG	32
9453bd332aSSY Chiu 
9553bd332aSSY Chiu /* Number of targets in one register */
9653bd332aSSY Chiu #define NUM_TARGETS_PER_REG	4
9753bd332aSSY Chiu 
9853bd332aSSY Chiu /* Accessors to access ITARGETSRn */
9953bd332aSSY Chiu #define ITARGETSR_FIELD_BITS	8
10053bd332aSSY Chiu #define ITARGETSR_FIELD_MASK	0xff
10153bd332aSSY Chiu 
1021b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK	0x1f
1037315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
1047315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
1057315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
106b0104773SPascal Brand 
107ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT	40
108ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT	16
109ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT	32
110ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT	48
111ec740b9fSJens Wiklander 
112ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK			0xf
113ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS			0x1
114ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU			0x2
115ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT	24
116ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT			15
117ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT		16
118ec740b9fSJens Wiklander 
11967e55c51SEtienne Carriere struct gic_data {
12067e55c51SEtienne Carriere 	vaddr_t gicc_base;
12167e55c51SEtienne Carriere 	vaddr_t gicd_base;
12205089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
12305089e5fSJens Wiklander 	vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE];
12405089e5fSJens Wiklander #endif
12567e55c51SEtienne Carriere 	size_t max_it;
12605089e5fSJens Wiklander 	uint32_t per_cpu_group_status;
12705089e5fSJens Wiklander 	uint32_t per_cpu_group_modifier;
12867e55c51SEtienne Carriere 	struct itr_chip chip;
12967e55c51SEtienne Carriere };
13067e55c51SEtienne Carriere 
13167e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
13267e55c51SEtienne Carriere 
133702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
134702fe5a7SClément Léger 		       uint32_t prio);
1357315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
1367315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
13726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
13826ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
139ec740b9fSJens Wiklander 			     uint32_t cpu_mask);
14026ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
14126ed70ecSGuanchao Liang 			uint8_t cpu_mask);
1427315b7b4SJens Wiklander 
1437315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1447315b7b4SJens Wiklander 	.add = gic_op_add,
14508ded0e1SEtienne Carriere 	.mask = gic_op_disable,
14608ded0e1SEtienne Carriere 	.unmask = gic_op_enable,
1477315b7b4SJens Wiklander 	.enable = gic_op_enable,
1487315b7b4SJens Wiklander 	.disable = gic_op_disable,
14926ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
15026ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
15126ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1527315b7b4SJens Wiklander };
1533639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1547315b7b4SJens Wiklander 
15505089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
15605089e5fSJens Wiklander {
15705089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
15805089e5fSJens Wiklander 	return gd->gicr_base[get_core_pos()];
15905089e5fSJens Wiklander #else
16005089e5fSJens Wiklander 	return 0;
16105089e5fSJens Wiklander #endif
16205089e5fSJens Wiklander }
16305089e5fSJens Wiklander 
16418901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
165b0104773SPascal Brand {
166b0104773SPascal Brand 	int i;
167b0104773SPascal Brand 	uint32_t old_ctlr;
168b0104773SPascal Brand 	size_t ret = 0;
1691b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1701b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
171b0104773SPascal Brand 
172b0104773SPascal Brand 	/*
173b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
174b0104773SPascal Brand 	 */
17518901324SDavid Wang #if defined(CFG_ARM_GICV3)
17618901324SDavid Wang 	old_ctlr = read_icc_ctlr();
17718901324SDavid Wang 	write_icc_ctlr(0);
17818901324SDavid Wang #else
179918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
180918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
18118901324SDavid Wang #endif
18279f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
183b0104773SPascal Brand 		uint32_t old_reg;
184b0104773SPascal Brand 		uint32_t reg;
185b0104773SPascal Brand 		int b;
186b0104773SPascal Brand 
187918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
188918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
189918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
190918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
19179f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
192007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
19353bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
194b0104773SPascal Brand 				goto out;
195b0104773SPascal Brand 			}
196b0104773SPascal Brand 		}
197b0104773SPascal Brand 	}
198b0104773SPascal Brand out:
19918901324SDavid Wang #if defined(CFG_ARM_GICV3)
20018901324SDavid Wang 	write_icc_ctlr(old_ctlr);
20118901324SDavid Wang #else
202918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
20318901324SDavid Wang #endif
204b0104773SPascal Brand 	return ret;
205b0104773SPascal Brand }
206b0104773SPascal Brand 
207*84603456SJens Wiklander static void gicv3_sync_sgi_config(struct gic_data *gd)
208*84603456SJens Wiklander {
209*84603456SJens Wiklander 	vaddr_t gicr_base = get_gicr_base(gd);
210*84603456SJens Wiklander 	bool need_sync = false;
211*84603456SJens Wiklander 	uint32_t gmod0 = 0;
212*84603456SJens Wiklander 	uint32_t grp0 = 0;
213*84603456SJens Wiklander 	size_t n = 0;
214*84603456SJens Wiklander 
215*84603456SJens Wiklander 	if (!gicr_base)
216*84603456SJens Wiklander 		panic("GICR_BASE missing for affinity routing");
217*84603456SJens Wiklander 
218*84603456SJens Wiklander 	grp0 = io_read32(gicr_base + GICR_IGROUPR0);
219*84603456SJens Wiklander 	gmod0 = io_read32(gicr_base + GICR_IGRPMODR0);
220*84603456SJens Wiklander 	for (n = GIC_SGI_SEC_BASE; n <= GIC_SGI_SEC_MAX; n++) {
221*84603456SJens Wiklander 		/* Ignore matching bits */
222*84603456SJens Wiklander 		if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) &&
223*84603456SJens Wiklander 		    !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier)))
224*84603456SJens Wiklander 			continue;
225*84603456SJens Wiklander 		/*
226*84603456SJens Wiklander 		 * SGI-n differs from primary CPU configuration,
227*84603456SJens Wiklander 		 * let's sync up.
228*84603456SJens Wiklander 		 */
229*84603456SJens Wiklander 		need_sync = true;
230*84603456SJens Wiklander 
231*84603456SJens Wiklander 		/* Disable interrupt */
232*84603456SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(n));
233*84603456SJens Wiklander 
234*84603456SJens Wiklander 		/* Make interrupt non-pending */
235*84603456SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(n));
236*84603456SJens Wiklander 
237*84603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_status)
238*84603456SJens Wiklander 			grp0 |= BIT32(n);
239*84603456SJens Wiklander 		else
240*84603456SJens Wiklander 			grp0 &= ~BIT32(n);
241*84603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_modifier)
242*84603456SJens Wiklander 			gmod0 |= BIT32(n);
243*84603456SJens Wiklander 		else
244*84603456SJens Wiklander 			gmod0 &= ~BIT32(n);
245*84603456SJens Wiklander 	}
246*84603456SJens Wiklander 
247*84603456SJens Wiklander 	if (need_sync) {
248*84603456SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, grp0);
249*84603456SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0, gmod0);
250*84603456SJens Wiklander 	}
251*84603456SJens Wiklander }
252*84603456SJens Wiklander 
253*84603456SJens Wiklander static void gic_legacy_sync_sgi_config(struct gic_data *gd)
254*84603456SJens Wiklander {
255*84603456SJens Wiklander 	bool need_sync = false;
256*84603456SJens Wiklander 	uint32_t grp0 = 0;
257*84603456SJens Wiklander 	size_t n = 0;
258*84603456SJens Wiklander 
259*84603456SJens Wiklander 	grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0));
260*84603456SJens Wiklander 	for (n = GIC_SGI_SEC_BASE; n <= GIC_SGI_SEC_MAX; n++) {
261*84603456SJens Wiklander 		/* Ignore matching bits */
262*84603456SJens Wiklander 		if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)))
263*84603456SJens Wiklander 			continue;
264*84603456SJens Wiklander 		/*
265*84603456SJens Wiklander 		 * SGI-n differs from primary CPU configuration,
266*84603456SJens Wiklander 		 * let's sync up.
267*84603456SJens Wiklander 		 */
268*84603456SJens Wiklander 		need_sync = true;
269*84603456SJens Wiklander 
270*84603456SJens Wiklander 		/* Disable interrupt */
271*84603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n));
272*84603456SJens Wiklander 
273*84603456SJens Wiklander 		/* Make interrupt non-pending */
274*84603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n));
275*84603456SJens Wiklander 
276*84603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_status)
277*84603456SJens Wiklander 			grp0 |= BIT32(n);
278*84603456SJens Wiklander 		else
279*84603456SJens Wiklander 			grp0 &= ~BIT32(n);
280*84603456SJens Wiklander 	}
281*84603456SJens Wiklander 
282*84603456SJens Wiklander 	if (need_sync)
283*84603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0);
284*84603456SJens Wiklander }
285*84603456SJens Wiklander 
2865da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd)
287bedc2b9fSsunny {
28805089e5fSJens Wiklander 	io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status);
289bedc2b9fSsunny 
29005089e5fSJens Wiklander 	/*
29105089e5fSJens Wiklander 	 * Set the priority mask to permit Non-secure interrupts, and to
29230a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
29330a673e3SPeter Maydell 	 */
29418901324SDavid Wang #if defined(CFG_ARM_GICV3)
29518901324SDavid Wang 	write_icc_pmr(0x80);
2961fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
29718901324SDavid Wang #else
298918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
29930a673e3SPeter Maydell 
300bedc2b9fSsunny 	/* Enable GIC */
301918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
302918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
303918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
30418901324SDavid Wang #endif
305bedc2b9fSsunny }
306bedc2b9fSsunny 
3075da157f5SJens Wiklander void gic_init_per_cpu(void)
3085da157f5SJens Wiklander {
3095da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
3105da157f5SJens Wiklander 
3115da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
3125da157f5SJens Wiklander 	assert(gd->gicd_base);
3135da157f5SJens Wiklander #else
3145da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
3155da157f5SJens Wiklander #endif
3165da157f5SJens Wiklander 
317*84603456SJens Wiklander 	if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) {
318*84603456SJens Wiklander 		/*
319*84603456SJens Wiklander 		 * GIC is already initialized by TF-A, we only need to
320*84603456SJens Wiklander 		 * handle eventual SGI configuration changes.
321*84603456SJens Wiklander 		 */
322*84603456SJens Wiklander 		if (IS_ENABLED(CFG_ARM_GICV3) &&
323*84603456SJens Wiklander 		    io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S)
324*84603456SJens Wiklander 			gicv3_sync_sgi_config(gd);
325*84603456SJens Wiklander 		else
326*84603456SJens Wiklander 			gic_legacy_sync_sgi_config(gd);
327*84603456SJens Wiklander 	} else {
328*84603456SJens Wiklander 		/*
329*84603456SJens Wiklander 		 * Non-TF-A case where all CPU specific configuration
330*84603456SJens Wiklander 		 * of GIC must be done here.
331*84603456SJens Wiklander 		 */
3325da157f5SJens Wiklander 		init_gic_per_cpu(gd);
3335da157f5SJens Wiklander 	}
334*84603456SJens Wiklander }
3355da157f5SJens Wiklander 
3365da157f5SJens Wiklander void gic_cpu_init(void)
3375da157f5SJens Wiklander {
3385da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
3395da157f5SJens Wiklander 
3405da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
3415da157f5SJens Wiklander 	assert(gd->gicd_base);
3425da157f5SJens Wiklander #else
3435da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
3445da157f5SJens Wiklander #endif
3455da157f5SJens Wiklander 	IMSG("%s is deprecated, please use gic_init_per_cpu()", __func__);
3465da157f5SJens Wiklander 
3475da157f5SJens Wiklander 	init_gic_per_cpu(gd);
3485da157f5SJens Wiklander }
3495da157f5SJens Wiklander 
350*84603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it)
351*84603456SJens Wiklander {
352*84603456SJens Wiklander 	struct gic_data *gd = &gic_data;
353*84603456SJens Wiklander 
354*84603456SJens Wiklander 	assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX);
355*84603456SJens Wiklander 
356*84603456SJens Wiklander 	/* Assert it's secure to start with. */
357*84603456SJens Wiklander 	assert(!(gd->per_cpu_group_status & BIT32(it)) &&
358*84603456SJens Wiklander 	       (gd->per_cpu_group_modifier & BIT32(it)));
359*84603456SJens Wiklander 
360*84603456SJens Wiklander 	gd->per_cpu_group_modifier &= ~BIT32(it);
361*84603456SJens Wiklander 	gd->per_cpu_group_status |= BIT32(it);
362*84603456SJens Wiklander 
363*84603456SJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3) &&
364*84603456SJens Wiklander 	    (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S)) {
365*84603456SJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
366*84603456SJens Wiklander 
367*84603456SJens Wiklander 		/* Disable interrupt */
368*84603456SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(it));
369*84603456SJens Wiklander 
370*84603456SJens Wiklander 		/* Make interrupt non-pending */
371*84603456SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(it));
372*84603456SJens Wiklander 
373*84603456SJens Wiklander 		/* Make it to non-secure */
374*84603456SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status);
375*84603456SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0,
376*84603456SJens Wiklander 			   gd->per_cpu_group_modifier);
377*84603456SJens Wiklander 	} else {
378*84603456SJens Wiklander 		/* Disable interrupt */
379*84603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it));
380*84603456SJens Wiklander 
381*84603456SJens Wiklander 		/* Make interrupt non-pending */
382*84603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it));
383*84603456SJens Wiklander 
384*84603456SJens Wiklander 		/* Make it to non-secure */
385*84603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_IGROUPR(0),
386*84603456SJens Wiklander 			   gd->per_cpu_group_status);
387*84603456SJens Wiklander 	}
388*84603456SJens Wiklander }
389*84603456SJens Wiklander 
3900ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
3910ee3f52eSEtienne Carriere 			  uint32_t *prio)
3920ee3f52eSEtienne Carriere {
3930ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
3940ee3f52eSEtienne Carriere 
3950ee3f52eSEtienne Carriere 	if (type)
3960ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
3970ee3f52eSEtienne Carriere 
3980ee3f52eSEtienne Carriere 	if (prio)
3990ee3f52eSEtienne Carriere 		*prio = 0;
4000ee3f52eSEtienne Carriere 
4010ee3f52eSEtienne Carriere 	if (!properties || count < 2)
4020ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
4030ee3f52eSEtienne Carriere 
4040ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
4050ee3f52eSEtienne Carriere 
4060ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
4078c7282beSEtienne Carriere 	case GIC_PPI:
4080ee3f52eSEtienne Carriere 		it_num += 16;
4090ee3f52eSEtienne Carriere 		break;
4108c7282beSEtienne Carriere 	case GIC_SPI:
4110ee3f52eSEtienne Carriere 		it_num += 32;
4120ee3f52eSEtienne Carriere 		break;
4130ee3f52eSEtienne Carriere 	default:
4140ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
4150ee3f52eSEtienne Carriere 	}
4160ee3f52eSEtienne Carriere 
4170ee3f52eSEtienne Carriere 	return it_num;
4180ee3f52eSEtienne Carriere }
4190ee3f52eSEtienne Carriere 
42005089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
42105089e5fSJens Wiklander 						   paddr_t gicr_base_pa)
42205089e5fSJens Wiklander {
42305089e5fSJens Wiklander 	size_t sz = GICR_V3_PCPUBASE_SIZE;
42405089e5fSJens Wiklander 	paddr_t pa = gicr_base_pa;
42505089e5fSJens Wiklander 	size_t core_pos = 0;
42605089e5fSJens Wiklander 	uint64_t mt_bit = 0;
42705089e5fSJens Wiklander 	uint64_t mpidr = 0;
42805089e5fSJens Wiklander 	uint64_t tv = 0;
42905089e5fSJens Wiklander 	vaddr_t va = 0;
43005089e5fSJens Wiklander 
43105089e5fSJens Wiklander #ifdef ARM64
43205089e5fSJens Wiklander 	mt_bit = read_mpidr_el1() & MPIDR_MT_MASK;
43305089e5fSJens Wiklander #endif
43405089e5fSJens Wiklander 	do {
43505089e5fSJens Wiklander 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
43605089e5fSJens Wiklander 		if (!va)
43705089e5fSJens Wiklander 			panic();
43805089e5fSJens Wiklander 		tv = io_read64(va + GICR_TYPER);
43905089e5fSJens Wiklander 
44005089e5fSJens Wiklander 		/*
44105089e5fSJens Wiklander 		 * Extract an mpidr from the Type register to calculate the
44205089e5fSJens Wiklander 		 * core position of this redistributer instance.
44305089e5fSJens Wiklander 		 */
44405089e5fSJens Wiklander 		mpidr = mt_bit;
44505089e5fSJens Wiklander 		mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) &
44605089e5fSJens Wiklander 				   MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT);
44705089e5fSJens Wiklander 		mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) &
44805089e5fSJens Wiklander 			 (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK);
44905089e5fSJens Wiklander 		core_pos = get_core_pos_mpidr(mpidr);
45005089e5fSJens Wiklander 		if (core_pos < CFG_TEE_CORE_NB_CORE) {
45105089e5fSJens Wiklander 			DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va);
45205089e5fSJens Wiklander 			gicr_base_addrs[core_pos] = va;
45305089e5fSJens Wiklander 		} else {
45405089e5fSJens Wiklander 			EMSG("Skipping too large core_pos %zu from GICR_TYPER",
45505089e5fSJens Wiklander 			     core_pos);
45605089e5fSJens Wiklander 		}
45705089e5fSJens Wiklander 		pa += sz;
45805089e5fSJens Wiklander 	} while (!(tv & GICR_TYPER_LAST));
45905089e5fSJens Wiklander }
46005089e5fSJens Wiklander 
46105089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
46205089e5fSJens Wiklander 			       paddr_t gicr_base_pa __maybe_unused)
463b0104773SPascal Brand {
46467e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
4650ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
4660ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
46769171becSJens Wiklander 	uint32_t vers __maybe_unused = 0;
4680ee3f52eSEtienne Carriere 
4690ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
4700ee3f52eSEtienne Carriere 
4710ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
4720ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
4730ee3f52eSEtienne Carriere 	if (!gicd_base)
4740ee3f52eSEtienne Carriere 		panic();
4750ee3f52eSEtienne Carriere 
47669171becSJens Wiklander 	vers = io_read32(gicd_base + GICD_PIDR2);
47769171becSJens Wiklander 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
47869171becSJens Wiklander 	vers &= GICD_PIDR2_ARCHREV_MASK;
47969171becSJens Wiklander 
48069171becSJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3)) {
48169171becSJens Wiklander 		assert(vers == 3);
48269171becSJens Wiklander 	} else {
48369171becSJens Wiklander 		assert(vers == 2);
4840ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
4850ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
4860ee3f52eSEtienne Carriere 		if (!gicc_base)
4870ee3f52eSEtienne Carriere 			panic();
4880ee3f52eSEtienne Carriere 	}
4890ee3f52eSEtienne Carriere 
4900ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
4910ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
4920ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
49305089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
49405089e5fSJens Wiklander 	probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
49505089e5fSJens Wiklander #endif
4960ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
4970ee3f52eSEtienne Carriere 
4980ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
4990ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
5000ee3f52eSEtienne Carriere }
5010ee3f52eSEtienne Carriere 
50205089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
50305089e5fSJens Wiklander 		 paddr_t gicr_base_pa)
5040ee3f52eSEtienne Carriere {
5050ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
5060ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
507b0104773SPascal Brand 
50805089e5fSJens Wiklander 	gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
509b0104773SPascal Brand 
51005089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW)
5110ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
51205089e5fSJens Wiklander 	if (io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S) {
51305089e5fSJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
51405089e5fSJens Wiklander 
51505089e5fSJens Wiklander 		if (!gicr_base)
51605089e5fSJens Wiklander 			panic("GICR_BASE missing for affinity routing");
51705089e5fSJens Wiklander 		/* Secure affinity routing enabled */
51805089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gicr_base + GICR_IGROUPR0);
51905089e5fSJens Wiklander 		gd->per_cpu_group_modifier = io_read32(gicr_base +
52005089e5fSJens Wiklander 						       GICR_IGRPMODR0);
52105089e5fSJens Wiklander 	} else {
52205089e5fSJens Wiklander 		/* Legacy operation with secure affinity routing disabled */
52305089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gd->gicd_base +
52405089e5fSJens Wiklander 						     GICD_IGROUPR(0));
52505089e5fSJens Wiklander 		gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
52605089e5fSJens Wiklander 	}
52705089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/
52805089e5fSJens Wiklander 	/*
52905089e5fSJens Wiklander 	 * Without TF-A, GIC is always configured in for legacy operation
53005089e5fSJens Wiklander 	 * with secure affinity routing disabled.
53105089e5fSJens Wiklander 	 */
5327315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
533b0104773SPascal Brand 		/* Disable interrupts */
534918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
535b0104773SPascal Brand 
536b0104773SPascal Brand 		/* Make interrupts non-pending */
537918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
538b0104773SPascal Brand 
539b0104773SPascal Brand 		/* Mark interrupts non-secure */
540bedc2b9fSsunny 		if (n == 0) {
541bedc2b9fSsunny 			/* per-CPU inerrupts config:
542bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
543bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
544bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
545bedc2b9fSsunny 			 */
54605089e5fSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
54705089e5fSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
54805089e5fSJens Wiklander 			io_write32(gd->gicd_base + GICD_IGROUPR(n),
54905089e5fSJens Wiklander 				   gd->per_cpu_group_status);
550bedc2b9fSsunny 		} else {
551918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
552b0104773SPascal Brand 		}
553bedc2b9fSsunny 	}
554b0104773SPascal Brand 
55530a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
55630a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
55730a673e3SPeter Maydell 	 */
55818901324SDavid Wang #if defined(CFG_ARM_GICV3)
55918901324SDavid Wang 	write_icc_pmr(0x80);
5601fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
5611fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
56218901324SDavid Wang #else
563918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
56430a673e3SPeter Maydell 
565b0104773SPascal Brand 	/* Enable GIC */
566918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
567918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
568918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
56905089e5fSJens Wiklander 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS);
5701fcac774SSandeep Tripathy #endif
57105089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/
57267e55c51SEtienne Carriere 
57301980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
574b0104773SPascal Brand }
575b0104773SPascal Brand 
5767315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
577b0104773SPascal Brand {
57853bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
57953bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
580b0104773SPascal Brand 
58167e55c51SEtienne Carriere 	assert(gd == &gic_data);
58267e55c51SEtienne Carriere 
583b0104773SPascal Brand 	/* Disable the interrupt */
584918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
585b0104773SPascal Brand 	/* Make it non-pending */
586918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
587b0104773SPascal Brand 	/* Assign it to group0 */
588918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
5891fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
5901fcac774SSandeep Tripathy 	/* Assign it to group1S */
5911fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
5921fcac774SSandeep Tripathy #endif
593b0104773SPascal Brand }
594b0104773SPascal Brand 
5957315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
5967315b7b4SJens Wiklander 				uint8_t cpu_mask)
597b0104773SPascal Brand {
5988ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
5998ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
60053bd332aSSY Chiu 	uint32_t target, target_shift;
601918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
602918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
603b0104773SPascal Brand 
60467e55c51SEtienne Carriere 	assert(gd == &gic_data);
60567e55c51SEtienne Carriere 
606b0104773SPascal Brand 	/* Assigned to group0 */
607918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
608b0104773SPascal Brand 
609b0104773SPascal Brand 	/* Route it to selected CPUs */
610918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
61153bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
61253bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
61353bd332aSSY Chiu 	target |= cpu_mask << target_shift;
614918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
615918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
616918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
617b0104773SPascal Brand }
618b0104773SPascal Brand 
6197315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
620b0104773SPascal Brand {
6218ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6228ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
623b0104773SPascal Brand 
62467e55c51SEtienne Carriere 	assert(gd == &gic_data);
62567e55c51SEtienne Carriere 
626b0104773SPascal Brand 	/* Assigned to group0 */
627918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
628b0104773SPascal Brand 
629b0104773SPascal Brand 	/* Set prio it to selected CPUs */
6301f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
6317315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
632918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
633b0104773SPascal Brand }
634b0104773SPascal Brand 
6357315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
636b0104773SPascal Brand {
63753bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
63853bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
639918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
640b0104773SPascal Brand 
64167e55c51SEtienne Carriere 	assert(gd == &gic_data);
64267e55c51SEtienne Carriere 
643b0104773SPascal Brand 	/* Assigned to group0 */
644918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
645b0104773SPascal Brand 
646b0104773SPascal Brand 	/* Enable the interrupt */
647918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
648b0104773SPascal Brand }
649b0104773SPascal Brand 
6507315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
651b0104773SPascal Brand {
65253bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
65353bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
654b0104773SPascal Brand 
65567e55c51SEtienne Carriere 	assert(gd == &gic_data);
65667e55c51SEtienne Carriere 
657b0104773SPascal Brand 	/* Assigned to group0 */
658918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
659b0104773SPascal Brand 
660b0104773SPascal Brand 	/* Disable the interrupt */
661918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
662b0104773SPascal Brand }
663b0104773SPascal Brand 
66426ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
66526ed70ecSGuanchao Liang {
66626ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
66726ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
66826ed70ecSGuanchao Liang 
66967e55c51SEtienne Carriere 	assert(gd == &gic_data);
67067e55c51SEtienne Carriere 
67126ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
67226ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
67326ed70ecSGuanchao Liang 
67426ed70ecSGuanchao Liang 	/* Raise the interrupt */
675918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
67626ed70ecSGuanchao Liang }
67726ed70ecSGuanchao Liang 
678ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
679ec740b9fSJens Wiklander {
680ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
681ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
682ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
683ec740b9fSJens Wiklander 
684ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
685ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
686ec740b9fSJens Wiklander }
687ec740b9fSJens Wiklander 
68854739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
689*84603456SJens Wiklander 			     uint32_t cpu_mask, bool ns)
69026ed70ecSGuanchao Liang {
69154739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
69254739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
693ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
694ec740b9fSJens Wiklander 
695ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
696ec740b9fSJens Wiklander 
697ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
698ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
699ec740b9fSJens Wiklander 	} else {
70054739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
701ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
702ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
703ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
704ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
705ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
706ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
707ec740b9fSJens Wiklander 
708ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
709ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
710ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
711ec740b9fSJens Wiklander 
712ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
713ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
714ec740b9fSJens Wiklander 		} else {
715ec740b9fSJens Wiklander 			/*
716ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
717ec740b9fSJens Wiklander 			 * same cluster now.
718ec740b9fSJens Wiklander 			 */
719ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
720ec740b9fSJens Wiklander 		}
721ec740b9fSJens Wiklander 	}
72254739cb4SMark-PK Tsai 
72354739cb4SMark-PK Tsai 	/* Raise the interrupt */
724*84603456SJens Wiklander 	if (ns)
72554739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
72654739cb4SMark-PK Tsai 	else
72754739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
72854739cb4SMark-PK Tsai #else
729ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
730*84603456SJens Wiklander 	uint32_t mask_group = ns;
731ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
732ec740b9fSJens Wiklander 
733ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
734ec740b9fSJens Wiklander 
735ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
736ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
737ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
738ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
739ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
740ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
741ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
742ec740b9fSJens Wiklander 	} else {
743ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
744ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
745ec740b9fSJens Wiklander 	}
74626ed70ecSGuanchao Liang 
74726ed70ecSGuanchao Liang 	/* Raise the interrupt */
748918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
74954739cb4SMark-PK Tsai #endif
75026ed70ecSGuanchao Liang }
75126ed70ecSGuanchao Liang 
75218901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
753b0104773SPascal Brand {
75467e55c51SEtienne Carriere 	assert(gd == &gic_data);
75567e55c51SEtienne Carriere 
75618901324SDavid Wang #if defined(CFG_ARM_GICV3)
7571de462e1SSumit Garg 	return read_icc_iar1();
75818901324SDavid Wang #else
759918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
76018901324SDavid Wang #endif
761b0104773SPascal Brand }
762b0104773SPascal Brand 
76318901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
764b0104773SPascal Brand {
76567e55c51SEtienne Carriere 	assert(gd == &gic_data);
76667e55c51SEtienne Carriere 
76718901324SDavid Wang #if defined(CFG_ARM_GICV3)
7681de462e1SSumit Garg 	write_icc_eoir1(eoir);
76918901324SDavid Wang #else
770918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
77118901324SDavid Wang #endif
772b0104773SPascal Brand }
773b0104773SPascal Brand 
7747315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
7757315b7b4SJens Wiklander {
77653bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
77753bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
77867e55c51SEtienne Carriere 
77967e55c51SEtienne Carriere 	assert(gd == &gic_data);
780918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
78153bd332aSSY Chiu }
78253bd332aSSY Chiu 
7837315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
7847315b7b4SJens Wiklander {
78553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
78653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
78767e55c51SEtienne Carriere 
78867e55c51SEtienne Carriere 	assert(gd == &gic_data);
789918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
79053bd332aSSY Chiu }
79153bd332aSSY Chiu 
7927315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
7937315b7b4SJens Wiklander {
79453bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
7957315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
7967315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
79753bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
798918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
7997315b7b4SJens Wiklander 
80067e55c51SEtienne Carriere 	assert(gd == &gic_data);
801918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
80253bd332aSSY Chiu }
80353bd332aSSY Chiu 
80467e55c51SEtienne Carriere void gic_dump_state(void)
80553bd332aSSY Chiu {
80667e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
80767e55c51SEtienne Carriere 	int i = 0;
80853bd332aSSY Chiu 
80918901324SDavid Wang #if defined(CFG_ARM_GICV3)
81018901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
81118901324SDavid Wang #else
812918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
81318901324SDavid Wang #endif
814918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
8157315b7b4SJens Wiklander 
8164a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
8177315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
81853bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
8197315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
82053bd332aSSY Chiu 		}
82153bd332aSSY Chiu 	}
82253bd332aSSY Chiu }
8237315b7b4SJens Wiklander 
82467e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
8257315b7b4SJens Wiklander {
82667e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
82767e55c51SEtienne Carriere 	uint32_t iar = 0;
82867e55c51SEtienne Carriere 	uint32_t id = 0;
8297315b7b4SJens Wiklander 
8307315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
8317315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
8327315b7b4SJens Wiklander 
8334a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
83499e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
8353b3a4611SMathieu Briand 	else
8363b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
8377315b7b4SJens Wiklander 
8387315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
8397315b7b4SJens Wiklander }
8407315b7b4SJens Wiklander 
84167e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
842358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
843358bf47cSEtienne Carriere void interrupt_main_handler(void)
84467e55c51SEtienne Carriere {
84567e55c51SEtienne Carriere 	gic_native_itr_handler();
84667e55c51SEtienne Carriere }
84767e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
84867e55c51SEtienne Carriere 
8497315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
850702fe5a7SClément Léger 		       uint32_t type __unused,
851702fe5a7SClément Léger 		       uint32_t prio __unused)
8527315b7b4SJens Wiklander {
8537315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
8547315b7b4SJens Wiklander 
85567e55c51SEtienne Carriere 	assert(gd == &gic_data);
85667e55c51SEtienne Carriere 
8574a9ea08cSFangsuo Wu 	if (it > gd->max_it)
858d13278b8SEtienne Carriere 		panic();
859d13278b8SEtienne Carriere 
8607315b7b4SJens Wiklander 	gic_it_add(gd, it);
8617315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
8627315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
8637315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
8647315b7b4SJens Wiklander }
8657315b7b4SJens Wiklander 
8667315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
8677315b7b4SJens Wiklander {
8687315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
8697315b7b4SJens Wiklander 
87067e55c51SEtienne Carriere 	assert(gd == &gic_data);
87167e55c51SEtienne Carriere 
8724a9ea08cSFangsuo Wu 	if (it > gd->max_it)
873d13278b8SEtienne Carriere 		panic();
874d13278b8SEtienne Carriere 
8757315b7b4SJens Wiklander 	gic_it_enable(gd, it);
8767315b7b4SJens Wiklander }
8777315b7b4SJens Wiklander 
8787315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
8797315b7b4SJens Wiklander {
8807315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
8817315b7b4SJens Wiklander 
88267e55c51SEtienne Carriere 	assert(gd == &gic_data);
88367e55c51SEtienne Carriere 
8844a9ea08cSFangsuo Wu 	if (it > gd->max_it)
885d13278b8SEtienne Carriere 		panic();
886d13278b8SEtienne Carriere 
8877315b7b4SJens Wiklander 	gic_it_disable(gd, it);
8887315b7b4SJens Wiklander }
88926ed70ecSGuanchao Liang 
89026ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
89126ed70ecSGuanchao Liang {
89226ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
89326ed70ecSGuanchao Liang 
89467e55c51SEtienne Carriere 	assert(gd == &gic_data);
89567e55c51SEtienne Carriere 
8964a9ea08cSFangsuo Wu 	if (it > gd->max_it)
89726ed70ecSGuanchao Liang 		panic();
89826ed70ecSGuanchao Liang 
89926ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
90026ed70ecSGuanchao Liang }
90126ed70ecSGuanchao Liang 
90226ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
903ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
90426ed70ecSGuanchao Liang {
90526ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
906*84603456SJens Wiklander 	bool ns = false;
90726ed70ecSGuanchao Liang 
90867e55c51SEtienne Carriere 	assert(gd == &gic_data);
90967e55c51SEtienne Carriere 
91054739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
91154739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
91254739cb4SMark-PK Tsai 
913*84603456SJens Wiklander 	ns = BIT32(it) & gd->per_cpu_group_status;
914*84603456SJens Wiklander 	gic_it_raise_sgi(gd, it, cpu_mask, ns);
91526ed70ecSGuanchao Liang }
91667e55c51SEtienne Carriere 
91726ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
91826ed70ecSGuanchao Liang 			uint8_t cpu_mask)
91926ed70ecSGuanchao Liang {
92026ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
92126ed70ecSGuanchao Liang 
92267e55c51SEtienne Carriere 	assert(gd == &gic_data);
92367e55c51SEtienne Carriere 
9244a9ea08cSFangsuo Wu 	if (it > gd->max_it)
92526ed70ecSGuanchao Liang 		panic();
92626ed70ecSGuanchao Liang 
92726ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
92826ed70ecSGuanchao Liang }
92914885eb1SEtienne Carriere 
93014885eb1SEtienne Carriere #ifdef CFG_DT
93114885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
93214885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
93314885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
93414885eb1SEtienne Carriere {
93514885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
93614885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
93714885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
93814885eb1SEtienne Carriere 	uint32_t type = 0;
93914885eb1SEtienne Carriere 	uint32_t prio = 0;
94014885eb1SEtienne Carriere 
94114885eb1SEtienne Carriere 	assert(arg && itr_desc);
94214885eb1SEtienne Carriere 
94314885eb1SEtienne Carriere 	/*
94414885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
94514885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
94614885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
94714885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
94814885eb1SEtienne Carriere 	 */
94914885eb1SEtienne Carriere 	if (arg->args_count < 2)
95014885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
95114885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
95214885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
95314885eb1SEtienne Carriere 
95414885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
95514885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
95614885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
95714885eb1SEtienne Carriere 
95814885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
95914885eb1SEtienne Carriere 
96014885eb1SEtienne Carriere 	itr_desc->chip = chip;
96114885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
96214885eb1SEtienne Carriere 
96314885eb1SEtienne Carriere 	return TEE_SUCCESS;
96414885eb1SEtienne Carriere }
96514885eb1SEtienne Carriere 
96614885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
96714885eb1SEtienne Carriere {
96814885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
96914885eb1SEtienne Carriere 					&gic_data.chip))
97014885eb1SEtienne Carriere 		panic();
97114885eb1SEtienne Carriere 
97214885eb1SEtienne Carriere 	return TEE_SUCCESS;
97314885eb1SEtienne Carriere }
97414885eb1SEtienne Carriere 
97514885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
97614885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
97714885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
97814885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
97914885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
98014885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
98114885eb1SEtienne Carriere 	{ }
98214885eb1SEtienne Carriere };
98314885eb1SEtienne Carriere 
98414885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
98514885eb1SEtienne Carriere 	.name = "gic",
98614885eb1SEtienne Carriere 	.match_table = gic_match_table,
98714885eb1SEtienne Carriere 	.probe = gic_probe,
98814885eb1SEtienne Carriere };
98914885eb1SEtienne Carriere #endif /*CFG_DT*/
990