xref: /optee_os/core/drivers/gic.c (revision d3f6526e4411459dae71b72f0feee74c08e37e92)
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)
7084603456SJens Wiklander #define GICR_ICENABLER0		(GICR_SGI_BASE_OFFSET + 0x180)
7184603456SJens 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 
1647c4883aeSJens Wiklander static bool affinity_routing_is_enabled(struct gic_data *gd)
1657c4883aeSJens Wiklander {
1667c4883aeSJens Wiklander 	return IS_ENABLED(CFG_ARM_GICV3) &&
1677c4883aeSJens Wiklander 	       io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S;
1687c4883aeSJens Wiklander }
1697c4883aeSJens Wiklander 
17018901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
171b0104773SPascal Brand {
172b0104773SPascal Brand 	int i;
173b0104773SPascal Brand 	uint32_t old_ctlr;
174b0104773SPascal Brand 	size_t ret = 0;
1751b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1761b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
177b0104773SPascal Brand 
178b0104773SPascal Brand 	/*
179b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
180b0104773SPascal Brand 	 */
18118901324SDavid Wang #if defined(CFG_ARM_GICV3)
18218901324SDavid Wang 	old_ctlr = read_icc_ctlr();
18318901324SDavid Wang 	write_icc_ctlr(0);
18418901324SDavid Wang #else
185918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
186918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
18718901324SDavid Wang #endif
18879f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
189b0104773SPascal Brand 		uint32_t old_reg;
190b0104773SPascal Brand 		uint32_t reg;
191b0104773SPascal Brand 		int b;
192b0104773SPascal Brand 
193918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
194918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
195918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
196918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
19779f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
198007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
19953bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
200b0104773SPascal Brand 				goto out;
201b0104773SPascal Brand 			}
202b0104773SPascal Brand 		}
203b0104773SPascal Brand 	}
204b0104773SPascal Brand out:
20518901324SDavid Wang #if defined(CFG_ARM_GICV3)
20618901324SDavid Wang 	write_icc_ctlr(old_ctlr);
20718901324SDavid Wang #else
208918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
20918901324SDavid Wang #endif
210b0104773SPascal Brand 	return ret;
211b0104773SPascal Brand }
212b0104773SPascal Brand 
21384603456SJens Wiklander static void gicv3_sync_sgi_config(struct gic_data *gd)
21484603456SJens Wiklander {
21584603456SJens Wiklander 	vaddr_t gicr_base = get_gicr_base(gd);
21684603456SJens Wiklander 	bool need_sync = false;
21784603456SJens Wiklander 	uint32_t gmod0 = 0;
21884603456SJens Wiklander 	uint32_t grp0 = 0;
21984603456SJens Wiklander 	size_t n = 0;
22084603456SJens Wiklander 
2217c4883aeSJens Wiklander 	/*
2227c4883aeSJens Wiklander 	 * If gicr_base isn't available there's no need to synchronize SGI
2237c4883aeSJens Wiklander 	 * configuration since gic_init_donate_sgi_to_ns() would panic.
2247c4883aeSJens Wiklander 	 */
22584603456SJens Wiklander 	if (!gicr_base)
2267c4883aeSJens Wiklander 		return;
22784603456SJens Wiklander 
22884603456SJens Wiklander 	grp0 = io_read32(gicr_base + GICR_IGROUPR0);
22984603456SJens Wiklander 	gmod0 = io_read32(gicr_base + GICR_IGRPMODR0);
23084603456SJens Wiklander 	for (n = GIC_SGI_SEC_BASE; n <= GIC_SGI_SEC_MAX; n++) {
23184603456SJens Wiklander 		/* Ignore matching bits */
23284603456SJens Wiklander 		if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) &&
23384603456SJens Wiklander 		    !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier)))
23484603456SJens Wiklander 			continue;
23584603456SJens Wiklander 		/*
23684603456SJens Wiklander 		 * SGI-n differs from primary CPU configuration,
23784603456SJens Wiklander 		 * let's sync up.
23884603456SJens Wiklander 		 */
23984603456SJens Wiklander 		need_sync = true;
24084603456SJens Wiklander 
24184603456SJens Wiklander 		/* Disable interrupt */
24284603456SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(n));
24384603456SJens Wiklander 
24484603456SJens Wiklander 		/* Make interrupt non-pending */
24584603456SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(n));
24684603456SJens Wiklander 
24784603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_status)
24884603456SJens Wiklander 			grp0 |= BIT32(n);
24984603456SJens Wiklander 		else
25084603456SJens Wiklander 			grp0 &= ~BIT32(n);
25184603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_modifier)
25284603456SJens Wiklander 			gmod0 |= BIT32(n);
25384603456SJens Wiklander 		else
25484603456SJens Wiklander 			gmod0 &= ~BIT32(n);
25584603456SJens Wiklander 	}
25684603456SJens Wiklander 
25784603456SJens Wiklander 	if (need_sync) {
25884603456SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, grp0);
25984603456SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0, gmod0);
26084603456SJens Wiklander 	}
26184603456SJens Wiklander }
26284603456SJens Wiklander 
26384603456SJens Wiklander static void gic_legacy_sync_sgi_config(struct gic_data *gd)
26484603456SJens Wiklander {
26584603456SJens Wiklander 	bool need_sync = false;
26684603456SJens Wiklander 	uint32_t grp0 = 0;
26784603456SJens Wiklander 	size_t n = 0;
26884603456SJens Wiklander 
26984603456SJens Wiklander 	grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0));
27084603456SJens Wiklander 	for (n = GIC_SGI_SEC_BASE; n <= GIC_SGI_SEC_MAX; n++) {
27184603456SJens Wiklander 		/* Ignore matching bits */
27284603456SJens Wiklander 		if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)))
27384603456SJens Wiklander 			continue;
27484603456SJens Wiklander 		/*
27584603456SJens Wiklander 		 * SGI-n differs from primary CPU configuration,
27684603456SJens Wiklander 		 * let's sync up.
27784603456SJens Wiklander 		 */
27884603456SJens Wiklander 		need_sync = true;
27984603456SJens Wiklander 
28084603456SJens Wiklander 		/* Disable interrupt */
28184603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n));
28284603456SJens Wiklander 
28384603456SJens Wiklander 		/* Make interrupt non-pending */
28484603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n));
28584603456SJens Wiklander 
28684603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_status)
28784603456SJens Wiklander 			grp0 |= BIT32(n);
28884603456SJens Wiklander 		else
28984603456SJens Wiklander 			grp0 &= ~BIT32(n);
29084603456SJens Wiklander 	}
29184603456SJens Wiklander 
29284603456SJens Wiklander 	if (need_sync)
29384603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0);
29484603456SJens Wiklander }
29584603456SJens Wiklander 
2965da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd)
297bedc2b9fSsunny {
29805089e5fSJens Wiklander 	io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status);
299bedc2b9fSsunny 
30005089e5fSJens Wiklander 	/*
30105089e5fSJens Wiklander 	 * Set the priority mask to permit Non-secure interrupts, and to
30230a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
30330a673e3SPeter Maydell 	 */
30418901324SDavid Wang #if defined(CFG_ARM_GICV3)
30518901324SDavid Wang 	write_icc_pmr(0x80);
3061fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
30718901324SDavid Wang #else
308918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
30930a673e3SPeter Maydell 
310bedc2b9fSsunny 	/* Enable GIC */
311918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
312918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
313918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
31418901324SDavid Wang #endif
315bedc2b9fSsunny }
316bedc2b9fSsunny 
3175da157f5SJens Wiklander void gic_init_per_cpu(void)
3185da157f5SJens Wiklander {
3195da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
3205da157f5SJens Wiklander 
3215da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
3225da157f5SJens Wiklander 	assert(gd->gicd_base);
3235da157f5SJens Wiklander #else
3245da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
3255da157f5SJens Wiklander #endif
3265da157f5SJens Wiklander 
32784603456SJens Wiklander 	if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) {
32884603456SJens Wiklander 		/*
32984603456SJens Wiklander 		 * GIC is already initialized by TF-A, we only need to
33084603456SJens Wiklander 		 * handle eventual SGI configuration changes.
33184603456SJens Wiklander 		 */
3327c4883aeSJens Wiklander 		if (affinity_routing_is_enabled(gd))
33384603456SJens Wiklander 			gicv3_sync_sgi_config(gd);
33484603456SJens Wiklander 		else
33584603456SJens Wiklander 			gic_legacy_sync_sgi_config(gd);
33684603456SJens Wiklander 	} else {
33784603456SJens Wiklander 		/*
33884603456SJens Wiklander 		 * Non-TF-A case where all CPU specific configuration
33984603456SJens Wiklander 		 * of GIC must be done here.
34084603456SJens Wiklander 		 */
3415da157f5SJens Wiklander 		init_gic_per_cpu(gd);
3425da157f5SJens Wiklander 	}
34384603456SJens Wiklander }
3445da157f5SJens Wiklander 
3455da157f5SJens Wiklander void gic_cpu_init(void)
3465da157f5SJens Wiklander {
3475da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
3485da157f5SJens Wiklander 
3495da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
3505da157f5SJens Wiklander 	assert(gd->gicd_base);
3515da157f5SJens Wiklander #else
3525da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
3535da157f5SJens Wiklander #endif
3545da157f5SJens Wiklander 	IMSG("%s is deprecated, please use gic_init_per_cpu()", __func__);
3555da157f5SJens Wiklander 
3565da157f5SJens Wiklander 	init_gic_per_cpu(gd);
3575da157f5SJens Wiklander }
3585da157f5SJens Wiklander 
35984603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it)
36084603456SJens Wiklander {
36184603456SJens Wiklander 	struct gic_data *gd = &gic_data;
36284603456SJens Wiklander 
36384603456SJens Wiklander 	assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX);
36484603456SJens Wiklander 
36584603456SJens Wiklander 	/* Assert it's secure to start with. */
36684603456SJens Wiklander 	assert(!(gd->per_cpu_group_status & BIT32(it)) &&
36784603456SJens Wiklander 	       (gd->per_cpu_group_modifier & BIT32(it)));
36884603456SJens Wiklander 
36984603456SJens Wiklander 	gd->per_cpu_group_modifier &= ~BIT32(it);
37084603456SJens Wiklander 	gd->per_cpu_group_status |= BIT32(it);
37184603456SJens Wiklander 
3727c4883aeSJens Wiklander 	if (affinity_routing_is_enabled(gd)) {
37384603456SJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
37484603456SJens Wiklander 
3757c4883aeSJens Wiklander 		if (!gicr_base)
3767c4883aeSJens Wiklander 			panic("GICR_BASE missing");
3777c4883aeSJens Wiklander 
37884603456SJens Wiklander 		/* Disable interrupt */
37984603456SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(it));
38084603456SJens Wiklander 
38184603456SJens Wiklander 		/* Make interrupt non-pending */
38284603456SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(it));
38384603456SJens Wiklander 
38484603456SJens Wiklander 		/* Make it to non-secure */
38584603456SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status);
38684603456SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0,
38784603456SJens Wiklander 			   gd->per_cpu_group_modifier);
38884603456SJens Wiklander 	} else {
38984603456SJens Wiklander 		/* Disable interrupt */
39084603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it));
39184603456SJens Wiklander 
39284603456SJens Wiklander 		/* Make interrupt non-pending */
39384603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it));
39484603456SJens Wiklander 
39584603456SJens Wiklander 		/* Make it to non-secure */
39684603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_IGROUPR(0),
39784603456SJens Wiklander 			   gd->per_cpu_group_status);
39884603456SJens Wiklander 	}
39984603456SJens Wiklander }
40084603456SJens Wiklander 
4010ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
4020ee3f52eSEtienne Carriere 			  uint32_t *prio)
4030ee3f52eSEtienne Carriere {
4040ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
4050ee3f52eSEtienne Carriere 
4060ee3f52eSEtienne Carriere 	if (type)
4070ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
4080ee3f52eSEtienne Carriere 
4090ee3f52eSEtienne Carriere 	if (prio)
4100ee3f52eSEtienne Carriere 		*prio = 0;
4110ee3f52eSEtienne Carriere 
4120ee3f52eSEtienne Carriere 	if (!properties || count < 2)
4130ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
4140ee3f52eSEtienne Carriere 
4150ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
4160ee3f52eSEtienne Carriere 
4170ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
4188c7282beSEtienne Carriere 	case GIC_PPI:
4190ee3f52eSEtienne Carriere 		it_num += 16;
4200ee3f52eSEtienne Carriere 		break;
4218c7282beSEtienne Carriere 	case GIC_SPI:
4220ee3f52eSEtienne Carriere 		it_num += 32;
4230ee3f52eSEtienne Carriere 		break;
4240ee3f52eSEtienne Carriere 	default:
4250ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
4260ee3f52eSEtienne Carriere 	}
4270ee3f52eSEtienne Carriere 
4280ee3f52eSEtienne Carriere 	return it_num;
4290ee3f52eSEtienne Carriere }
4300ee3f52eSEtienne Carriere 
43105089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
43205089e5fSJens Wiklander 						   paddr_t gicr_base_pa)
43305089e5fSJens Wiklander {
43405089e5fSJens Wiklander 	size_t sz = GICR_V3_PCPUBASE_SIZE;
43505089e5fSJens Wiklander 	paddr_t pa = gicr_base_pa;
43605089e5fSJens Wiklander 	size_t core_pos = 0;
43705089e5fSJens Wiklander 	uint64_t mt_bit = 0;
43805089e5fSJens Wiklander 	uint64_t mpidr = 0;
43905089e5fSJens Wiklander 	uint64_t tv = 0;
44005089e5fSJens Wiklander 	vaddr_t va = 0;
44105089e5fSJens Wiklander 
44205089e5fSJens Wiklander #ifdef ARM64
44305089e5fSJens Wiklander 	mt_bit = read_mpidr_el1() & MPIDR_MT_MASK;
44405089e5fSJens Wiklander #endif
44505089e5fSJens Wiklander 	do {
44605089e5fSJens Wiklander 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
44705089e5fSJens Wiklander 		if (!va)
44805089e5fSJens Wiklander 			panic();
44905089e5fSJens Wiklander 		tv = io_read64(va + GICR_TYPER);
45005089e5fSJens Wiklander 
45105089e5fSJens Wiklander 		/*
45205089e5fSJens Wiklander 		 * Extract an mpidr from the Type register to calculate the
45305089e5fSJens Wiklander 		 * core position of this redistributer instance.
45405089e5fSJens Wiklander 		 */
45505089e5fSJens Wiklander 		mpidr = mt_bit;
45605089e5fSJens Wiklander 		mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) &
45705089e5fSJens Wiklander 				   MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT);
45805089e5fSJens Wiklander 		mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) &
45905089e5fSJens Wiklander 			 (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK);
46005089e5fSJens Wiklander 		core_pos = get_core_pos_mpidr(mpidr);
46105089e5fSJens Wiklander 		if (core_pos < CFG_TEE_CORE_NB_CORE) {
46205089e5fSJens Wiklander 			DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va);
46305089e5fSJens Wiklander 			gicr_base_addrs[core_pos] = va;
46405089e5fSJens Wiklander 		} else {
46505089e5fSJens Wiklander 			EMSG("Skipping too large core_pos %zu from GICR_TYPER",
46605089e5fSJens Wiklander 			     core_pos);
46705089e5fSJens Wiklander 		}
46805089e5fSJens Wiklander 		pa += sz;
46905089e5fSJens Wiklander 	} while (!(tv & GICR_TYPER_LAST));
47005089e5fSJens Wiklander }
47105089e5fSJens Wiklander 
47205089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
47305089e5fSJens Wiklander 			       paddr_t gicr_base_pa __maybe_unused)
474b0104773SPascal Brand {
47567e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
4760ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
4770ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
47869171becSJens Wiklander 	uint32_t vers __maybe_unused = 0;
4790ee3f52eSEtienne Carriere 
4800ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
4810ee3f52eSEtienne Carriere 
4820ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
4830ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
4840ee3f52eSEtienne Carriere 	if (!gicd_base)
4850ee3f52eSEtienne Carriere 		panic();
4860ee3f52eSEtienne Carriere 
48769171becSJens Wiklander 	vers = io_read32(gicd_base + GICD_PIDR2);
48869171becSJens Wiklander 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
48969171becSJens Wiklander 	vers &= GICD_PIDR2_ARCHREV_MASK;
49069171becSJens Wiklander 
49169171becSJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3)) {
49269171becSJens Wiklander 		assert(vers == 3);
49369171becSJens Wiklander 	} else {
494*d3f6526eSJens Wiklander 		assert(vers == 2 || vers == 1);
4950ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
4960ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
4970ee3f52eSEtienne Carriere 		if (!gicc_base)
4980ee3f52eSEtienne Carriere 			panic();
4990ee3f52eSEtienne Carriere 	}
5000ee3f52eSEtienne Carriere 
5010ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
5020ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
5030ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
50405089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
5057c4883aeSJens Wiklander 	if (affinity_routing_is_enabled(gd) && gicr_base_pa)
50605089e5fSJens Wiklander 		probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
50705089e5fSJens Wiklander #endif
5080ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
5090ee3f52eSEtienne Carriere 
5100ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
5110ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
5120ee3f52eSEtienne Carriere }
5130ee3f52eSEtienne Carriere 
51405089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
51505089e5fSJens Wiklander 		 paddr_t gicr_base_pa)
5160ee3f52eSEtienne Carriere {
5170ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
5180ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
519b0104773SPascal Brand 
52005089e5fSJens Wiklander 	gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
521b0104773SPascal Brand 
52205089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW)
5230ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
5247c4883aeSJens Wiklander 	if (affinity_routing_is_enabled(gd)) {
5257c4883aeSJens Wiklander 		/* Secure affinity routing enabled */
52605089e5fSJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
52705089e5fSJens Wiklander 
5287c4883aeSJens Wiklander 		if (gicr_base) {
5297c4883aeSJens Wiklander 			gd->per_cpu_group_status = io_read32(gicr_base +
5307c4883aeSJens Wiklander 							     GICR_IGROUPR0);
53105089e5fSJens Wiklander 			gd->per_cpu_group_modifier = io_read32(gicr_base +
53205089e5fSJens Wiklander 							       GICR_IGRPMODR0);
53305089e5fSJens Wiklander 		} else {
5347c4883aeSJens Wiklander 			IMSG("GIC redistributor base address not provided");
5357c4883aeSJens Wiklander 			IMSG("Assuming default GIC group status and modifier");
5367c4883aeSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
5377c4883aeSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
5387c4883aeSJens Wiklander 		}
5397c4883aeSJens Wiklander 	} else {
54005089e5fSJens Wiklander 		/* Legacy operation with secure affinity routing disabled */
54105089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gd->gicd_base +
54205089e5fSJens Wiklander 						     GICD_IGROUPR(0));
54305089e5fSJens Wiklander 		gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
54405089e5fSJens Wiklander 	}
54505089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/
54605089e5fSJens Wiklander 	/*
54705089e5fSJens Wiklander 	 * Without TF-A, GIC is always configured in for legacy operation
54805089e5fSJens Wiklander 	 * with secure affinity routing disabled.
54905089e5fSJens Wiklander 	 */
5507315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
551b0104773SPascal Brand 		/* Disable interrupts */
552918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
553b0104773SPascal Brand 
554b0104773SPascal Brand 		/* Make interrupts non-pending */
555918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
556b0104773SPascal Brand 
557b0104773SPascal Brand 		/* Mark interrupts non-secure */
558bedc2b9fSsunny 		if (n == 0) {
559bedc2b9fSsunny 			/* per-CPU inerrupts config:
560bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
561bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
562bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
563bedc2b9fSsunny 			 */
56405089e5fSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
56505089e5fSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
56605089e5fSJens Wiklander 			io_write32(gd->gicd_base + GICD_IGROUPR(n),
56705089e5fSJens Wiklander 				   gd->per_cpu_group_status);
568bedc2b9fSsunny 		} else {
569918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
570b0104773SPascal Brand 		}
571bedc2b9fSsunny 	}
572b0104773SPascal Brand 
57330a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
57430a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
57530a673e3SPeter Maydell 	 */
57618901324SDavid Wang #if defined(CFG_ARM_GICV3)
57718901324SDavid Wang 	write_icc_pmr(0x80);
5781fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
5791fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
58018901324SDavid Wang #else
581918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
58230a673e3SPeter Maydell 
583b0104773SPascal Brand 	/* Enable GIC */
584918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
585918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
586918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
58705089e5fSJens Wiklander 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS);
5881fcac774SSandeep Tripathy #endif
58905089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/
59067e55c51SEtienne Carriere 
59101980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
592b0104773SPascal Brand }
593b0104773SPascal Brand 
5947315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
595b0104773SPascal Brand {
59653bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
59753bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
598b0104773SPascal Brand 
59967e55c51SEtienne Carriere 	assert(gd == &gic_data);
60067e55c51SEtienne Carriere 
601b0104773SPascal Brand 	/* Disable the interrupt */
602918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
603b0104773SPascal Brand 	/* Make it non-pending */
604918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
605b0104773SPascal Brand 	/* Assign it to group0 */
606918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
6071fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
6081fcac774SSandeep Tripathy 	/* Assign it to group1S */
6091fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
6101fcac774SSandeep Tripathy #endif
611b0104773SPascal Brand }
612b0104773SPascal Brand 
6137315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
6147315b7b4SJens Wiklander 				uint8_t cpu_mask)
615b0104773SPascal Brand {
6168ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6178ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
61853bd332aSSY Chiu 	uint32_t target, target_shift;
619918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
620918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
621b0104773SPascal Brand 
62267e55c51SEtienne Carriere 	assert(gd == &gic_data);
62367e55c51SEtienne Carriere 
624b0104773SPascal Brand 	/* Assigned to group0 */
625918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
626b0104773SPascal Brand 
627b0104773SPascal Brand 	/* Route it to selected CPUs */
628918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
62953bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
63053bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
63153bd332aSSY Chiu 	target |= cpu_mask << target_shift;
632918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
633918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
634918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
635b0104773SPascal Brand }
636b0104773SPascal Brand 
6377315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
638b0104773SPascal Brand {
6398ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6408ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
641b0104773SPascal Brand 
64267e55c51SEtienne Carriere 	assert(gd == &gic_data);
64367e55c51SEtienne Carriere 
644b0104773SPascal Brand 	/* Assigned to group0 */
645918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
646b0104773SPascal Brand 
647b0104773SPascal Brand 	/* Set prio it to selected CPUs */
6481f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
6497315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
650918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
651b0104773SPascal Brand }
652b0104773SPascal Brand 
6537315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
654b0104773SPascal Brand {
65553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
65653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
657918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
658b0104773SPascal Brand 
65967e55c51SEtienne Carriere 	assert(gd == &gic_data);
66067e55c51SEtienne Carriere 
661b0104773SPascal Brand 	/* Assigned to group0 */
662918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
663b0104773SPascal Brand 
664b0104773SPascal Brand 	/* Enable the interrupt */
665918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
666b0104773SPascal Brand }
667b0104773SPascal Brand 
6687315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
669b0104773SPascal Brand {
67053bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
67153bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
672b0104773SPascal Brand 
67367e55c51SEtienne Carriere 	assert(gd == &gic_data);
67467e55c51SEtienne Carriere 
675b0104773SPascal Brand 	/* Assigned to group0 */
676918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
677b0104773SPascal Brand 
678b0104773SPascal Brand 	/* Disable the interrupt */
679918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
680b0104773SPascal Brand }
681b0104773SPascal Brand 
68226ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
68326ed70ecSGuanchao Liang {
68426ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
68526ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
68626ed70ecSGuanchao Liang 
68767e55c51SEtienne Carriere 	assert(gd == &gic_data);
68867e55c51SEtienne Carriere 
68926ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
69026ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
69126ed70ecSGuanchao Liang 
69226ed70ecSGuanchao Liang 	/* Raise the interrupt */
693918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
69426ed70ecSGuanchao Liang }
69526ed70ecSGuanchao Liang 
696ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
697ec740b9fSJens Wiklander {
698ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
699ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
700ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
701ec740b9fSJens Wiklander 
702ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
703ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
704ec740b9fSJens Wiklander }
705ec740b9fSJens Wiklander 
70654739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
70784603456SJens Wiklander 			     uint32_t cpu_mask, bool ns)
70826ed70ecSGuanchao Liang {
70954739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
71054739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
711ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
712ec740b9fSJens Wiklander 
713ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
714ec740b9fSJens Wiklander 
715ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
716ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
717ec740b9fSJens Wiklander 	} else {
71854739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
719ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
720ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
721ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
722ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
723ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
724ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
725ec740b9fSJens Wiklander 
726ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
727ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
728ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
729ec740b9fSJens Wiklander 
730ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
731ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
732ec740b9fSJens Wiklander 		} else {
733ec740b9fSJens Wiklander 			/*
734ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
735ec740b9fSJens Wiklander 			 * same cluster now.
736ec740b9fSJens Wiklander 			 */
737ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
738ec740b9fSJens Wiklander 		}
739ec740b9fSJens Wiklander 	}
74054739cb4SMark-PK Tsai 
74154739cb4SMark-PK Tsai 	/* Raise the interrupt */
74284603456SJens Wiklander 	if (ns)
74354739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
74454739cb4SMark-PK Tsai 	else
74554739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
74654739cb4SMark-PK Tsai #else
747ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
74884603456SJens Wiklander 	uint32_t mask_group = ns;
749ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
750ec740b9fSJens Wiklander 
751ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
752ec740b9fSJens Wiklander 
753ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
754ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
755ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
756ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
757ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
758ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
759ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
760ec740b9fSJens Wiklander 	} else {
761ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
762ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
763ec740b9fSJens Wiklander 	}
76426ed70ecSGuanchao Liang 
76526ed70ecSGuanchao Liang 	/* Raise the interrupt */
766918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
76754739cb4SMark-PK Tsai #endif
76826ed70ecSGuanchao Liang }
76926ed70ecSGuanchao Liang 
77018901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
771b0104773SPascal Brand {
77267e55c51SEtienne Carriere 	assert(gd == &gic_data);
77367e55c51SEtienne Carriere 
77418901324SDavid Wang #if defined(CFG_ARM_GICV3)
7751de462e1SSumit Garg 	return read_icc_iar1();
77618901324SDavid Wang #else
777918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
77818901324SDavid Wang #endif
779b0104773SPascal Brand }
780b0104773SPascal Brand 
78118901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
782b0104773SPascal Brand {
78367e55c51SEtienne Carriere 	assert(gd == &gic_data);
78467e55c51SEtienne Carriere 
78518901324SDavid Wang #if defined(CFG_ARM_GICV3)
7861de462e1SSumit Garg 	write_icc_eoir1(eoir);
78718901324SDavid Wang #else
788918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
78918901324SDavid Wang #endif
790b0104773SPascal Brand }
791b0104773SPascal Brand 
7927315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
7937315b7b4SJens Wiklander {
79453bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
79553bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
79667e55c51SEtienne Carriere 
79767e55c51SEtienne Carriere 	assert(gd == &gic_data);
798918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
79953bd332aSSY Chiu }
80053bd332aSSY Chiu 
8017315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
8027315b7b4SJens Wiklander {
80353bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
80453bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
80567e55c51SEtienne Carriere 
80667e55c51SEtienne Carriere 	assert(gd == &gic_data);
807918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
80853bd332aSSY Chiu }
80953bd332aSSY Chiu 
8107315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
8117315b7b4SJens Wiklander {
81253bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
8137315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
8147315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
81553bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
816918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
8177315b7b4SJens Wiklander 
81867e55c51SEtienne Carriere 	assert(gd == &gic_data);
819918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
82053bd332aSSY Chiu }
82153bd332aSSY Chiu 
82267e55c51SEtienne Carriere void gic_dump_state(void)
82353bd332aSSY Chiu {
82467e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
82567e55c51SEtienne Carriere 	int i = 0;
82653bd332aSSY Chiu 
82718901324SDavid Wang #if defined(CFG_ARM_GICV3)
82818901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
82918901324SDavid Wang #else
830918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
83118901324SDavid Wang #endif
832918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
8337315b7b4SJens Wiklander 
8344a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
8357315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
83653bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
8377315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
83853bd332aSSY Chiu 		}
83953bd332aSSY Chiu 	}
84053bd332aSSY Chiu }
8417315b7b4SJens Wiklander 
84267e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
8437315b7b4SJens Wiklander {
84467e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
84567e55c51SEtienne Carriere 	uint32_t iar = 0;
84667e55c51SEtienne Carriere 	uint32_t id = 0;
8477315b7b4SJens Wiklander 
8487315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
8497315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
8507315b7b4SJens Wiklander 
8514a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
85299e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
8533b3a4611SMathieu Briand 	else
8543b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
8557315b7b4SJens Wiklander 
8567315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
8577315b7b4SJens Wiklander }
8587315b7b4SJens Wiklander 
85967e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
860358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
861358bf47cSEtienne Carriere void interrupt_main_handler(void)
86267e55c51SEtienne Carriere {
86367e55c51SEtienne Carriere 	gic_native_itr_handler();
86467e55c51SEtienne Carriere }
86567e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
86667e55c51SEtienne Carriere 
8677315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
868702fe5a7SClément Léger 		       uint32_t type __unused,
869702fe5a7SClément Léger 		       uint32_t prio __unused)
8707315b7b4SJens Wiklander {
8717315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
8727315b7b4SJens Wiklander 
87367e55c51SEtienne Carriere 	assert(gd == &gic_data);
87467e55c51SEtienne Carriere 
8754a9ea08cSFangsuo Wu 	if (it > gd->max_it)
876d13278b8SEtienne Carriere 		panic();
877d13278b8SEtienne Carriere 
8787315b7b4SJens Wiklander 	gic_it_add(gd, it);
8797315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
8807315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
8817315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
8827315b7b4SJens Wiklander }
8837315b7b4SJens Wiklander 
8847315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
8857315b7b4SJens Wiklander {
8867315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
8877315b7b4SJens Wiklander 
88867e55c51SEtienne Carriere 	assert(gd == &gic_data);
88967e55c51SEtienne Carriere 
8904a9ea08cSFangsuo Wu 	if (it > gd->max_it)
891d13278b8SEtienne Carriere 		panic();
892d13278b8SEtienne Carriere 
8937315b7b4SJens Wiklander 	gic_it_enable(gd, it);
8947315b7b4SJens Wiklander }
8957315b7b4SJens Wiklander 
8967315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
8977315b7b4SJens Wiklander {
8987315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
8997315b7b4SJens Wiklander 
90067e55c51SEtienne Carriere 	assert(gd == &gic_data);
90167e55c51SEtienne Carriere 
9024a9ea08cSFangsuo Wu 	if (it > gd->max_it)
903d13278b8SEtienne Carriere 		panic();
904d13278b8SEtienne Carriere 
9057315b7b4SJens Wiklander 	gic_it_disable(gd, it);
9067315b7b4SJens Wiklander }
90726ed70ecSGuanchao Liang 
90826ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
90926ed70ecSGuanchao Liang {
91026ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
91126ed70ecSGuanchao Liang 
91267e55c51SEtienne Carriere 	assert(gd == &gic_data);
91367e55c51SEtienne Carriere 
9144a9ea08cSFangsuo Wu 	if (it > gd->max_it)
91526ed70ecSGuanchao Liang 		panic();
91626ed70ecSGuanchao Liang 
91726ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
91826ed70ecSGuanchao Liang }
91926ed70ecSGuanchao Liang 
92026ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
921ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
92226ed70ecSGuanchao Liang {
92326ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
92484603456SJens Wiklander 	bool ns = false;
92526ed70ecSGuanchao Liang 
92667e55c51SEtienne Carriere 	assert(gd == &gic_data);
92767e55c51SEtienne Carriere 
92854739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
92954739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
93054739cb4SMark-PK Tsai 
93184603456SJens Wiklander 	ns = BIT32(it) & gd->per_cpu_group_status;
93284603456SJens Wiklander 	gic_it_raise_sgi(gd, it, cpu_mask, ns);
93326ed70ecSGuanchao Liang }
93467e55c51SEtienne Carriere 
93526ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
93626ed70ecSGuanchao Liang 			uint8_t cpu_mask)
93726ed70ecSGuanchao Liang {
93826ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
93926ed70ecSGuanchao Liang 
94067e55c51SEtienne Carriere 	assert(gd == &gic_data);
94167e55c51SEtienne Carriere 
9424a9ea08cSFangsuo Wu 	if (it > gd->max_it)
94326ed70ecSGuanchao Liang 		panic();
94426ed70ecSGuanchao Liang 
94526ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
94626ed70ecSGuanchao Liang }
94714885eb1SEtienne Carriere 
94814885eb1SEtienne Carriere #ifdef CFG_DT
94914885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
95014885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
95114885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
95214885eb1SEtienne Carriere {
95314885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
95414885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
95514885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
95614885eb1SEtienne Carriere 	uint32_t type = 0;
95714885eb1SEtienne Carriere 	uint32_t prio = 0;
95814885eb1SEtienne Carriere 
95914885eb1SEtienne Carriere 	assert(arg && itr_desc);
96014885eb1SEtienne Carriere 
96114885eb1SEtienne Carriere 	/*
96214885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
96314885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
96414885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
96514885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
96614885eb1SEtienne Carriere 	 */
96714885eb1SEtienne Carriere 	if (arg->args_count < 2)
96814885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
96914885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
97014885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
97114885eb1SEtienne Carriere 
97214885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
97314885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
97414885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
97514885eb1SEtienne Carriere 
97614885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
97714885eb1SEtienne Carriere 
97814885eb1SEtienne Carriere 	itr_desc->chip = chip;
97914885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
98014885eb1SEtienne Carriere 
98114885eb1SEtienne Carriere 	return TEE_SUCCESS;
98214885eb1SEtienne Carriere }
98314885eb1SEtienne Carriere 
98414885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
98514885eb1SEtienne Carriere {
98614885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
98714885eb1SEtienne Carriere 					&gic_data.chip))
98814885eb1SEtienne Carriere 		panic();
98914885eb1SEtienne Carriere 
99014885eb1SEtienne Carriere 	return TEE_SUCCESS;
99114885eb1SEtienne Carriere }
99214885eb1SEtienne Carriere 
99314885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
99414885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
99514885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
99614885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
99714885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
99814885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
99914885eb1SEtienne Carriere 	{ }
100014885eb1SEtienne Carriere };
100114885eb1SEtienne Carriere 
100214885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
100314885eb1SEtienne Carriere 	.name = "gic",
100414885eb1SEtienne Carriere 	.match_table = gic_match_table,
100514885eb1SEtienne Carriere 	.probe = gic_probe,
100614885eb1SEtienne Carriere };
100714885eb1SEtienne Carriere #endif /*CFG_DT*/
1008