xref: /optee_os/core/drivers/gic.c (revision 10cc591295fadef442ff1be5e1338d990bef97d1)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b0104773SPascal Brand /*
39e935234SJens Wiklander  * Copyright (c) 2016-2017, 2023-2024 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>
967e55c51SEtienne Carriere #include <compiler.h>
1005089e5fSJens Wiklander #include <config.h>
11b0104773SPascal Brand #include <drivers/gic.h>
129e935234SJens Wiklander #include <dt-bindings/interrupt-controller/arm-gic.h>
139e935234SJens Wiklander #include <initcall.h>
1405089e5fSJens Wiklander #include <io.h>
150f93de74SEtienne Carriere #include <keep.h>
1667729d8dSLudovic Barre #include <kernel/dt.h>
1714885eb1SEtienne Carriere #include <kernel/dt_driver.h>
187315b7b4SJens Wiklander #include <kernel/interrupt.h>
1905089e5fSJens Wiklander #include <kernel/misc.h>
20*10cc5912SRunyang Chen #include <kernel/mutex.h>
21d13278b8SEtienne Carriere #include <kernel/panic.h>
2205089e5fSJens Wiklander #include <libfdt.h>
2360801696SVolodymyr Babchuk #include <mm/core_memprot.h>
2460801696SVolodymyr Babchuk #include <mm/core_mmu.h>
254de4bebcSJens Wiklander #include <trace.h>
2605089e5fSJens Wiklander #include <util.h>
27b0104773SPascal Brand 
28b0104773SPascal Brand /* Offsets from gic.gicc_base */
29b0104773SPascal Brand #define GICC_CTLR		(0x000)
3030a673e3SPeter Maydell #define GICC_PMR		(0x004)
31b0104773SPascal Brand #define GICC_IAR		(0x00C)
32b0104773SPascal Brand #define GICC_EOIR		(0x010)
33b0104773SPascal Brand 
34b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0	(1 << 0)
35b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1	(1 << 1)
36b0104773SPascal Brand #define GICC_CTLR_FIQEN		(1 << 3)
37b0104773SPascal Brand 
38b0104773SPascal Brand /* Offsets from gic.gicd_base */
39b0104773SPascal Brand #define GICD_CTLR		(0x000)
40b0104773SPascal Brand #define GICD_TYPER		(0x004)
41b0104773SPascal Brand #define GICD_IGROUPR(n)		(0x080 + (n) * 4)
42b0104773SPascal Brand #define GICD_ISENABLER(n)	(0x100 + (n) * 4)
43b0104773SPascal Brand #define GICD_ICENABLER(n)	(0x180 + (n) * 4)
4426ed70ecSGuanchao Liang #define GICD_ISPENDR(n)		(0x200 + (n) * 4)
45b0104773SPascal Brand #define GICD_ICPENDR(n)		(0x280 + (n) * 4)
46b0104773SPascal Brand #define GICD_IPRIORITYR(n)	(0x400 + (n) * 4)
47b0104773SPascal Brand #define GICD_ITARGETSR(n)	(0x800 + (n) * 4)
481fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n)	(0xd00 + (n) * 4)
4926ed70ecSGuanchao Liang #define GICD_SGIR		(0xF00)
50b0104773SPascal Brand 
5169171becSJens Wiklander #ifdef CFG_ARM_GICV3
5269171becSJens Wiklander #define GICD_PIDR2		(0xFFE8)
5369171becSJens Wiklander #else
5469171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */
5569171becSJens Wiklander #define GICD_PIDR2		(0xFE8)
5669171becSJens Wiklander #endif
5769171becSJens Wiklander 
5805089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP0	BIT32(0)
5905089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1NS	BIT32(1)
6005089e5fSJens Wiklander #define GICD_CTLR_ENABLEGRP1S	BIT32(2)
6105089e5fSJens Wiklander #define GICD_CTLR_ARE_S		BIT32(4)
6205089e5fSJens Wiklander #define GICD_CTLR_ARE_NS	BIT32(5)
6305089e5fSJens Wiklander 
6405089e5fSJens Wiklander /* Offsets from gic.gicr_base[core_pos] */
6505089e5fSJens Wiklander #define GICR_V3_PCPUBASE_SIZE	(2 * 64 * 1024)
6605089e5fSJens Wiklander #define GICR_SGI_BASE_OFFSET	(64 * 1024)
6705089e5fSJens Wiklander #define GICR_CTLR		(0x00)
6805089e5fSJens Wiklander #define GICR_TYPER		(0x08)
6905089e5fSJens Wiklander 
7005089e5fSJens Wiklander #define GICR_IGROUPR0		(GICR_SGI_BASE_OFFSET + 0x080)
7105089e5fSJens Wiklander #define GICR_IGRPMODR0		(GICR_SGI_BASE_OFFSET + 0xD00)
7284603456SJens Wiklander #define GICR_ICENABLER0		(GICR_SGI_BASE_OFFSET + 0x180)
7384603456SJens Wiklander #define GICR_ICPENDR0		(GICR_SGI_BASE_OFFSET + 0x280)
749e935234SJens Wiklander #define GICR_ISENABLER0		(GICR_SGI_BASE_OFFSET + 0x100)
759e935234SJens Wiklander #define GICR_ICFGR0		(GICR_SGI_BASE_OFFSET + 0xC00)
769e935234SJens Wiklander #define GICR_ICFGR1		(GICR_SGI_BASE_OFFSET + 0xC04)
779e935234SJens Wiklander #define GICR_IPRIORITYR(n)	(GICR_SGI_BASE_OFFSET + 0x400 + (n) * 4)
789e935234SJens Wiklander 
796c2d2e8aSJens Wiklander #define GICR_CTLR_RWP		BIT32(3)
8005089e5fSJens Wiklander 
8105089e5fSJens Wiklander #define GICR_TYPER_LAST		BIT64(4)
8205089e5fSJens Wiklander #define GICR_TYPER_AFF3_SHIFT	56
8305089e5fSJens Wiklander #define GICR_TYPER_AFF2_SHIFT	48
8405089e5fSJens Wiklander #define GICR_TYPER_AFF1_SHIFT	40
8505089e5fSJens Wiklander #define GICR_TYPER_AFF0_SHIFT	32
86b0104773SPascal Brand 
8769171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */
8869171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT	4
8969171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK		0xF
9069171becSJens Wiklander 
9153bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
9253bd332aSSY Chiu #define NUM_PPI	32
9353bd332aSSY Chiu 
9426ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
9526ed70ecSGuanchao Liang #define NUM_SGI			16
9626ed70ecSGuanchao Liang 
9726ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
9826ed70ecSGuanchao Liang #define NUM_NS_SGI		8
9926ed70ecSGuanchao Liang 
10053bd332aSSY Chiu /* Number of interrupts in one register */
10153bd332aSSY Chiu #define NUM_INTS_PER_REG	32
10253bd332aSSY Chiu 
10353bd332aSSY Chiu /* Number of targets in one register */
10453bd332aSSY Chiu #define NUM_TARGETS_PER_REG	4
10553bd332aSSY Chiu 
10653bd332aSSY Chiu /* Accessors to access ITARGETSRn */
10753bd332aSSY Chiu #define ITARGETSR_FIELD_BITS	8
10853bd332aSSY Chiu #define ITARGETSR_FIELD_MASK	0xff
10953bd332aSSY Chiu 
1101b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK	0x1f
1117315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
1127315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
1137315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
114b0104773SPascal Brand 
115ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT	40
116ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT	16
117ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT	32
118ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT	48
119ec740b9fSJens Wiklander 
120ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK			0xf
121ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS			0x1
122ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU			0x2
123ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT	24
124ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT			15
125ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT		16
126ec740b9fSJens Wiklander 
12767e55c51SEtienne Carriere struct gic_data {
12867e55c51SEtienne Carriere 	vaddr_t gicc_base;
12967e55c51SEtienne Carriere 	vaddr_t gicd_base;
13005089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
13105089e5fSJens Wiklander 	vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE];
13205089e5fSJens Wiklander #endif
13367e55c51SEtienne Carriere 	size_t max_it;
13405089e5fSJens Wiklander 	uint32_t per_cpu_group_status;
13505089e5fSJens Wiklander 	uint32_t per_cpu_group_modifier;
1369e935234SJens Wiklander 	uint32_t per_cpu_enable;
13767e55c51SEtienne Carriere 	struct itr_chip chip;
13867e55c51SEtienne Carriere };
13967e55c51SEtienne Carriere 
1409e935234SJens Wiklander static bool gic_primary_done __nex_bss;
14167e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
142*10cc5912SRunyang Chen static struct mutex gic_mutex = MUTEX_INITIALIZER;
14367e55c51SEtienne Carriere 
144702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
145702fe5a7SClément Léger 		       uint32_t prio);
1467315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
1477315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
14826ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
14926ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
150ec740b9fSJens Wiklander 			     uint32_t cpu_mask);
15126ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
15226ed70ecSGuanchao Liang 			uint8_t cpu_mask);
1537315b7b4SJens Wiklander 
1547315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1557315b7b4SJens Wiklander 	.add = gic_op_add,
15608ded0e1SEtienne Carriere 	.mask = gic_op_disable,
15708ded0e1SEtienne Carriere 	.unmask = gic_op_enable,
1587315b7b4SJens Wiklander 	.enable = gic_op_enable,
1597315b7b4SJens Wiklander 	.disable = gic_op_disable,
16026ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
16126ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
16226ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1637315b7b4SJens Wiklander };
1643639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1657315b7b4SJens Wiklander 
16605089e5fSJens Wiklander static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
16705089e5fSJens Wiklander {
16805089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
16905089e5fSJens Wiklander 	return gd->gicr_base[get_core_pos()];
17005089e5fSJens Wiklander #else
17105089e5fSJens Wiklander 	return 0;
17205089e5fSJens Wiklander #endif
17305089e5fSJens Wiklander }
17405089e5fSJens Wiklander 
1757c4883aeSJens Wiklander static bool affinity_routing_is_enabled(struct gic_data *gd)
1767c4883aeSJens Wiklander {
1777c4883aeSJens Wiklander 	return IS_ENABLED(CFG_ARM_GICV3) &&
1787c4883aeSJens Wiklander 	       io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S;
1797c4883aeSJens Wiklander }
1807c4883aeSJens Wiklander 
18118901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
182b0104773SPascal Brand {
183b0104773SPascal Brand 	int i;
184b0104773SPascal Brand 	uint32_t old_ctlr;
185b0104773SPascal Brand 	size_t ret = 0;
1861b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1871b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
188b0104773SPascal Brand 
189b0104773SPascal Brand 	/*
190b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
191b0104773SPascal Brand 	 */
19218901324SDavid Wang #if defined(CFG_ARM_GICV3)
19318901324SDavid Wang 	old_ctlr = read_icc_ctlr();
19418901324SDavid Wang 	write_icc_ctlr(0);
19518901324SDavid Wang #else
196918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
197918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
19818901324SDavid Wang #endif
19979f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
200b0104773SPascal Brand 		uint32_t old_reg;
201b0104773SPascal Brand 		uint32_t reg;
202b0104773SPascal Brand 		int b;
203b0104773SPascal Brand 
204918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
205918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
206918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
207918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
20879f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
209007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
21053bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
211b0104773SPascal Brand 				goto out;
212b0104773SPascal Brand 			}
213b0104773SPascal Brand 		}
214b0104773SPascal Brand 	}
215b0104773SPascal Brand out:
21618901324SDavid Wang #if defined(CFG_ARM_GICV3)
21718901324SDavid Wang 	write_icc_ctlr(old_ctlr);
21818901324SDavid Wang #else
219918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
22018901324SDavid Wang #endif
221b0104773SPascal Brand 	return ret;
222b0104773SPascal Brand }
223b0104773SPascal Brand 
2246c2d2e8aSJens Wiklander static void gicr_wait_for_pending_write(vaddr_t gicr_base)
2256c2d2e8aSJens Wiklander {
2266c2d2e8aSJens Wiklander 	/*
2276c2d2e8aSJens Wiklander 	 * Wait for changes to
2286c2d2e8aSJens Wiklander 	 * - GICR_ICENABLER0
2296c2d2e8aSJens Wiklander 	 * - GICR_CTLR.DPG1S
2306c2d2e8aSJens Wiklander 	 * - GICR_CTLR.DPG1NS
2316c2d2e8aSJens Wiklander 	 * - GICR_CTLR.DPG0
2326c2d2e8aSJens Wiklander 	 * to be visible to all agents in the system.
2336c2d2e8aSJens Wiklander 	 */
2346c2d2e8aSJens Wiklander 	while (io_read32(gicr_base + GICR_CTLR) & GICR_CTLR_RWP)
2356c2d2e8aSJens Wiklander 		;
2366c2d2e8aSJens Wiklander }
2376c2d2e8aSJens Wiklander 
2389e935234SJens Wiklander static void gicv3_sync_redist_config(struct gic_data *gd)
23984603456SJens Wiklander {
24084603456SJens Wiklander 	vaddr_t gicr_base = get_gicr_base(gd);
24184603456SJens Wiklander 	bool need_sync = false;
24284603456SJens Wiklander 	uint32_t gmod0 = 0;
24384603456SJens Wiklander 	uint32_t grp0 = 0;
24484603456SJens Wiklander 	size_t n = 0;
24584603456SJens Wiklander 
2467c4883aeSJens Wiklander 	/*
2477c4883aeSJens Wiklander 	 * If gicr_base isn't available there's no need to synchronize SGI
2487c4883aeSJens Wiklander 	 * configuration since gic_init_donate_sgi_to_ns() would panic.
2497c4883aeSJens Wiklander 	 */
25084603456SJens Wiklander 	if (!gicr_base)
2517c4883aeSJens Wiklander 		return;
25284603456SJens Wiklander 
25384603456SJens Wiklander 	grp0 = io_read32(gicr_base + GICR_IGROUPR0);
25484603456SJens Wiklander 	gmod0 = io_read32(gicr_base + GICR_IGRPMODR0);
2559e935234SJens Wiklander 	for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) {
25684603456SJens Wiklander 		/* Ignore matching bits */
25784603456SJens Wiklander 		if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)) &&
25884603456SJens Wiklander 		    !(BIT32(n) & (gmod0 ^ gd->per_cpu_group_modifier)))
25984603456SJens Wiklander 			continue;
26084603456SJens Wiklander 		/*
2619e935234SJens Wiklander 		 * SGI/PPI-n differs from primary CPU configuration,
26284603456SJens Wiklander 		 * let's sync up.
26384603456SJens Wiklander 		 */
26484603456SJens Wiklander 		need_sync = true;
26584603456SJens Wiklander 
26684603456SJens Wiklander 		/* Disable interrupt */
26784603456SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(n));
26884603456SJens Wiklander 
2696c2d2e8aSJens Wiklander 		/* Wait for the write to GICR_ICENABLER0 to propagate */
2706c2d2e8aSJens Wiklander 		gicr_wait_for_pending_write(gicr_base);
2716c2d2e8aSJens Wiklander 
27284603456SJens Wiklander 		/* Make interrupt non-pending */
27384603456SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(n));
27484603456SJens Wiklander 
27584603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_status)
27684603456SJens Wiklander 			grp0 |= BIT32(n);
27784603456SJens Wiklander 		else
27884603456SJens Wiklander 			grp0 &= ~BIT32(n);
27984603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_modifier)
28084603456SJens Wiklander 			gmod0 |= BIT32(n);
28184603456SJens Wiklander 		else
28284603456SJens Wiklander 			gmod0 &= ~BIT32(n);
28384603456SJens Wiklander 	}
28484603456SJens Wiklander 
28584603456SJens Wiklander 	if (need_sync) {
28684603456SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, grp0);
28784603456SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0, gmod0);
2889e935234SJens Wiklander 		io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable);
28984603456SJens Wiklander 	}
29084603456SJens Wiklander }
29184603456SJens Wiklander 
2929e935234SJens Wiklander static void gic_legacy_sync_dist_config(struct gic_data *gd)
29384603456SJens Wiklander {
29484603456SJens Wiklander 	bool need_sync = false;
29584603456SJens Wiklander 	uint32_t grp0 = 0;
29684603456SJens Wiklander 	size_t n = 0;
29784603456SJens Wiklander 
29884603456SJens Wiklander 	grp0 = io_read32(gd->gicd_base + GICD_IGROUPR(0));
2999e935234SJens Wiklander 	for (n = GIC_SGI_SEC_BASE; n < GIC_SPI_BASE; n++) {
30084603456SJens Wiklander 		/* Ignore matching bits */
30184603456SJens Wiklander 		if (!(BIT32(n) & (grp0 ^ gd->per_cpu_group_status)))
30284603456SJens Wiklander 			continue;
30384603456SJens Wiklander 		/*
3049e935234SJens Wiklander 		 * SGI/PPI-n differs from primary CPU configuration,
30584603456SJens Wiklander 		 * let's sync up.
30684603456SJens Wiklander 		 */
30784603456SJens Wiklander 		need_sync = true;
30884603456SJens Wiklander 
30984603456SJens Wiklander 		/* Disable interrupt */
31084603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(n));
31184603456SJens Wiklander 
31284603456SJens Wiklander 		/* Make interrupt non-pending */
31384603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(n));
31484603456SJens Wiklander 
31584603456SJens Wiklander 		if (BIT32(n) & gd->per_cpu_group_status)
31684603456SJens Wiklander 			grp0 |= BIT32(n);
31784603456SJens Wiklander 		else
31884603456SJens Wiklander 			grp0 &= ~BIT32(n);
31984603456SJens Wiklander 	}
32084603456SJens Wiklander 
3219e935234SJens Wiklander 	if (need_sync) {
32284603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_IGROUPR(0), grp0);
3239e935234SJens Wiklander 		io_write32(gd->gicd_base + GICD_ISENABLER(0),
3249e935234SJens Wiklander 			   gd->per_cpu_enable);
3259e935234SJens Wiklander 	}
32684603456SJens Wiklander }
32784603456SJens Wiklander 
3285da157f5SJens Wiklander static void init_gic_per_cpu(struct gic_data *gd)
329bedc2b9fSsunny {
33005089e5fSJens Wiklander 	io_write32(gd->gicd_base + GICD_IGROUPR(0), gd->per_cpu_group_status);
331bedc2b9fSsunny 
33205089e5fSJens Wiklander 	/*
33305089e5fSJens Wiklander 	 * Set the priority mask to permit Non-secure interrupts, and to
33430a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
33530a673e3SPeter Maydell 	 */
33618901324SDavid Wang #if defined(CFG_ARM_GICV3)
33718901324SDavid Wang 	write_icc_pmr(0x80);
3381fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
33918901324SDavid Wang #else
340918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
34130a673e3SPeter Maydell 
342bedc2b9fSsunny 	/* Enable GIC */
343918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
344918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
345918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
34618901324SDavid Wang #endif
347bedc2b9fSsunny }
348bedc2b9fSsunny 
3495da157f5SJens Wiklander void gic_init_per_cpu(void)
3505da157f5SJens Wiklander {
3515da157f5SJens Wiklander 	struct gic_data *gd = &gic_data;
3525da157f5SJens Wiklander 
3535da157f5SJens Wiklander #if defined(CFG_ARM_GICV3)
3545da157f5SJens Wiklander 	assert(gd->gicd_base);
3555da157f5SJens Wiklander #else
3565da157f5SJens Wiklander 	assert(gd->gicd_base && gd->gicc_base);
3575da157f5SJens Wiklander #endif
3585da157f5SJens Wiklander 
35984603456SJens Wiklander 	if (IS_ENABLED(CFG_WITH_ARM_TRUSTED_FW)) {
36084603456SJens Wiklander 		/*
36184603456SJens Wiklander 		 * GIC is already initialized by TF-A, we only need to
3629e935234SJens Wiklander 		 * handle eventual SGI or PPI configuration changes.
36384603456SJens Wiklander 		 */
3647c4883aeSJens Wiklander 		if (affinity_routing_is_enabled(gd))
3659e935234SJens Wiklander 			gicv3_sync_redist_config(gd);
36684603456SJens Wiklander 		else
3679e935234SJens Wiklander 			gic_legacy_sync_dist_config(gd);
36884603456SJens Wiklander 	} else {
36984603456SJens Wiklander 		/*
37084603456SJens Wiklander 		 * Non-TF-A case where all CPU specific configuration
37184603456SJens Wiklander 		 * of GIC must be done here.
37284603456SJens Wiklander 		 */
3735da157f5SJens Wiklander 		init_gic_per_cpu(gd);
3745da157f5SJens Wiklander 	}
37584603456SJens Wiklander }
3765da157f5SJens Wiklander 
37784603456SJens Wiklander void gic_init_donate_sgi_to_ns(size_t it)
37884603456SJens Wiklander {
37984603456SJens Wiklander 	struct gic_data *gd = &gic_data;
38084603456SJens Wiklander 
38184603456SJens Wiklander 	assert(it >= GIC_SGI_SEC_BASE && it <= GIC_SGI_SEC_MAX);
38284603456SJens Wiklander 
38384603456SJens Wiklander 	/* Assert it's secure to start with. */
38484603456SJens Wiklander 	assert(!(gd->per_cpu_group_status & BIT32(it)) &&
38584603456SJens Wiklander 	       (gd->per_cpu_group_modifier & BIT32(it)));
38684603456SJens Wiklander 
38784603456SJens Wiklander 	gd->per_cpu_group_modifier &= ~BIT32(it);
38884603456SJens Wiklander 	gd->per_cpu_group_status |= BIT32(it);
38984603456SJens Wiklander 
3907c4883aeSJens Wiklander 	if (affinity_routing_is_enabled(gd)) {
39184603456SJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
39284603456SJens Wiklander 
3937c4883aeSJens Wiklander 		if (!gicr_base)
3947c4883aeSJens Wiklander 			panic("GICR_BASE missing");
3957c4883aeSJens Wiklander 
39684603456SJens Wiklander 		/* Disable interrupt */
39784603456SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(it));
39884603456SJens Wiklander 
3996c2d2e8aSJens Wiklander 		/* Wait for the write to GICR_ICENABLER0 to propagate */
4006c2d2e8aSJens Wiklander 		gicr_wait_for_pending_write(gicr_base);
4016c2d2e8aSJens Wiklander 
40284603456SJens Wiklander 		/* Make interrupt non-pending */
40384603456SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(it));
40484603456SJens Wiklander 
40584603456SJens Wiklander 		/* Make it to non-secure */
40684603456SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status);
40784603456SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0,
40884603456SJens Wiklander 			   gd->per_cpu_group_modifier);
40984603456SJens Wiklander 	} else {
41084603456SJens Wiklander 		/* Disable interrupt */
41184603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICENABLER(0), BIT(it));
41284603456SJens Wiklander 
41384603456SJens Wiklander 		/* Make interrupt non-pending */
41484603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_ICPENDR(0), BIT(it));
41584603456SJens Wiklander 
41684603456SJens Wiklander 		/* Make it to non-secure */
41784603456SJens Wiklander 		io_write32(gd->gicd_base + GICD_IGROUPR(0),
41884603456SJens Wiklander 			   gd->per_cpu_group_status);
41984603456SJens Wiklander 	}
42084603456SJens Wiklander }
42184603456SJens Wiklander 
4220ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
4230ee3f52eSEtienne Carriere 			  uint32_t *prio)
4240ee3f52eSEtienne Carriere {
4250ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
4260ee3f52eSEtienne Carriere 
4270ee3f52eSEtienne Carriere 	if (type)
4280ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
4290ee3f52eSEtienne Carriere 
4300ee3f52eSEtienne Carriere 	if (prio)
4310ee3f52eSEtienne Carriere 		*prio = 0;
4320ee3f52eSEtienne Carriere 
4330ee3f52eSEtienne Carriere 	if (!properties || count < 2)
4340ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
4350ee3f52eSEtienne Carriere 
4360ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
4370ee3f52eSEtienne Carriere 
4380ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
4398c7282beSEtienne Carriere 	case GIC_PPI:
4400ee3f52eSEtienne Carriere 		it_num += 16;
4410ee3f52eSEtienne Carriere 		break;
4428c7282beSEtienne Carriere 	case GIC_SPI:
4430ee3f52eSEtienne Carriere 		it_num += 32;
4440ee3f52eSEtienne Carriere 		break;
4450ee3f52eSEtienne Carriere 	default:
4460ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
4470ee3f52eSEtienne Carriere 	}
4480ee3f52eSEtienne Carriere 
4490ee3f52eSEtienne Carriere 	return it_num;
4500ee3f52eSEtienne Carriere }
4510ee3f52eSEtienne Carriere 
45205089e5fSJens Wiklander static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
45305089e5fSJens Wiklander 						   paddr_t gicr_base_pa)
45405089e5fSJens Wiklander {
45505089e5fSJens Wiklander 	size_t sz = GICR_V3_PCPUBASE_SIZE;
45605089e5fSJens Wiklander 	paddr_t pa = gicr_base_pa;
45705089e5fSJens Wiklander 	size_t core_pos = 0;
45805089e5fSJens Wiklander 	uint64_t mt_bit = 0;
45905089e5fSJens Wiklander 	uint64_t mpidr = 0;
46005089e5fSJens Wiklander 	uint64_t tv = 0;
46105089e5fSJens Wiklander 	vaddr_t va = 0;
46205089e5fSJens Wiklander 
46305089e5fSJens Wiklander #ifdef ARM64
46405089e5fSJens Wiklander 	mt_bit = read_mpidr_el1() & MPIDR_MT_MASK;
46505089e5fSJens Wiklander #endif
46605089e5fSJens Wiklander 	do {
46705089e5fSJens Wiklander 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
46805089e5fSJens Wiklander 		if (!va)
46905089e5fSJens Wiklander 			panic();
47005089e5fSJens Wiklander 		tv = io_read64(va + GICR_TYPER);
47105089e5fSJens Wiklander 
47205089e5fSJens Wiklander 		/*
47305089e5fSJens Wiklander 		 * Extract an mpidr from the Type register to calculate the
47405089e5fSJens Wiklander 		 * core position of this redistributer instance.
47505089e5fSJens Wiklander 		 */
47605089e5fSJens Wiklander 		mpidr = mt_bit;
47705089e5fSJens Wiklander 		mpidr |= SHIFT_U64((tv >> GICR_TYPER_AFF3_SHIFT) &
47805089e5fSJens Wiklander 				   MPIDR_AFFLVL_MASK, MPIDR_AFF3_SHIFT);
47905089e5fSJens Wiklander 		mpidr |= (tv >> GICR_TYPER_AFF0_SHIFT) &
48005089e5fSJens Wiklander 			 (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK);
48105089e5fSJens Wiklander 		core_pos = get_core_pos_mpidr(mpidr);
48205089e5fSJens Wiklander 		if (core_pos < CFG_TEE_CORE_NB_CORE) {
48305089e5fSJens Wiklander 			DMSG("GICR_BASE[%zu] at %#"PRIxVA, core_pos, va);
48405089e5fSJens Wiklander 			gicr_base_addrs[core_pos] = va;
48505089e5fSJens Wiklander 		} else {
48605089e5fSJens Wiklander 			EMSG("Skipping too large core_pos %zu from GICR_TYPER",
48705089e5fSJens Wiklander 			     core_pos);
48805089e5fSJens Wiklander 		}
48905089e5fSJens Wiklander 		pa += sz;
49005089e5fSJens Wiklander 	} while (!(tv & GICR_TYPER_LAST));
49105089e5fSJens Wiklander }
49205089e5fSJens Wiklander 
49305089e5fSJens Wiklander static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
49405089e5fSJens Wiklander 			       paddr_t gicr_base_pa __maybe_unused)
495b0104773SPascal Brand {
49667e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
4970ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
4980ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
49969171becSJens Wiklander 	uint32_t vers __maybe_unused = 0;
5000ee3f52eSEtienne Carriere 
5010ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
5020ee3f52eSEtienne Carriere 
5030ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
5040ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
5050ee3f52eSEtienne Carriere 	if (!gicd_base)
5060ee3f52eSEtienne Carriere 		panic();
5070ee3f52eSEtienne Carriere 
50869171becSJens Wiklander 	vers = io_read32(gicd_base + GICD_PIDR2);
50969171becSJens Wiklander 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
51069171becSJens Wiklander 	vers &= GICD_PIDR2_ARCHREV_MASK;
51169171becSJens Wiklander 
51269171becSJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3)) {
513dd18bd87SZiad Elhanafy 		assert(vers == 4 || vers == 3);
51469171becSJens Wiklander 	} else {
515d3f6526eSJens Wiklander 		assert(vers == 2 || vers == 1);
5160ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
5170ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
5180ee3f52eSEtienne Carriere 		if (!gicc_base)
5190ee3f52eSEtienne Carriere 			panic();
5200ee3f52eSEtienne Carriere 	}
5210ee3f52eSEtienne Carriere 
5220ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
5230ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
5240ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
52505089e5fSJens Wiklander #if defined(CFG_ARM_GICV3)
5267c4883aeSJens Wiklander 	if (affinity_routing_is_enabled(gd) && gicr_base_pa)
52705089e5fSJens Wiklander 		probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
52805089e5fSJens Wiklander #endif
5290ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
5300ee3f52eSEtienne Carriere 
5310ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
5320ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
5330ee3f52eSEtienne Carriere }
5340ee3f52eSEtienne Carriere 
53505089e5fSJens Wiklander void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
53605089e5fSJens Wiklander 		 paddr_t gicr_base_pa)
5370ee3f52eSEtienne Carriere {
5380ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
5390ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
540b0104773SPascal Brand 
54105089e5fSJens Wiklander 	gic_init_base_addr(gicc_base_pa, gicd_base_pa, gicr_base_pa);
542b0104773SPascal Brand 
54305089e5fSJens Wiklander #if defined(CFG_WITH_ARM_TRUSTED_FW)
5440ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
5457c4883aeSJens Wiklander 	if (affinity_routing_is_enabled(gd)) {
5467c4883aeSJens Wiklander 		/* Secure affinity routing enabled */
54705089e5fSJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
54805089e5fSJens Wiklander 
5497c4883aeSJens Wiklander 		if (gicr_base) {
5507c4883aeSJens Wiklander 			gd->per_cpu_group_status = io_read32(gicr_base +
5517c4883aeSJens Wiklander 							     GICR_IGROUPR0);
55205089e5fSJens Wiklander 			gd->per_cpu_group_modifier = io_read32(gicr_base +
55305089e5fSJens Wiklander 							       GICR_IGRPMODR0);
55405089e5fSJens Wiklander 		} else {
5557c4883aeSJens Wiklander 			IMSG("GIC redistributor base address not provided");
5567c4883aeSJens Wiklander 			IMSG("Assuming default GIC group status and modifier");
5577c4883aeSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
5587c4883aeSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
5597c4883aeSJens Wiklander 		}
5607c4883aeSJens Wiklander 	} else {
56105089e5fSJens Wiklander 		/* Legacy operation with secure affinity routing disabled */
56205089e5fSJens Wiklander 		gd->per_cpu_group_status = io_read32(gd->gicd_base +
56305089e5fSJens Wiklander 						     GICD_IGROUPR(0));
56405089e5fSJens Wiklander 		gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
56505089e5fSJens Wiklander 	}
56605089e5fSJens Wiklander #else /*!CFG_WITH_ARM_TRUSTED_FW*/
56705089e5fSJens Wiklander 	/*
56805089e5fSJens Wiklander 	 * Without TF-A, GIC is always configured in for legacy operation
56905089e5fSJens Wiklander 	 * with secure affinity routing disabled.
57005089e5fSJens Wiklander 	 */
5717315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
572b0104773SPascal Brand 		/* Disable interrupts */
573918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
574b0104773SPascal Brand 
575b0104773SPascal Brand 		/* Make interrupts non-pending */
576918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
577b0104773SPascal Brand 
578b0104773SPascal Brand 		/* Mark interrupts non-secure */
579bedc2b9fSsunny 		if (n == 0) {
580bedc2b9fSsunny 			/* per-CPU inerrupts config:
581bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
582bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
583bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
584bedc2b9fSsunny 			 */
58505089e5fSJens Wiklander 			gd->per_cpu_group_status = 0xffff00ff;
58605089e5fSJens Wiklander 			gd->per_cpu_group_modifier = ~gd->per_cpu_group_status;
58705089e5fSJens Wiklander 			io_write32(gd->gicd_base + GICD_IGROUPR(n),
58805089e5fSJens Wiklander 				   gd->per_cpu_group_status);
589bedc2b9fSsunny 		} else {
590918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
591b0104773SPascal Brand 		}
592bedc2b9fSsunny 	}
593b0104773SPascal Brand 
59430a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
59530a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
59630a673e3SPeter Maydell 	 */
59718901324SDavid Wang #if defined(CFG_ARM_GICV3)
59818901324SDavid Wang 	write_icc_pmr(0x80);
5991fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
6001fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
60118901324SDavid Wang #else
602918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
60330a673e3SPeter Maydell 
604b0104773SPascal Brand 	/* Enable GIC */
605918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
606918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
607918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
60805089e5fSJens Wiklander 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1NS);
6091fcac774SSandeep Tripathy #endif
61005089e5fSJens Wiklander #endif /*!CFG_WITH_ARM_TRUSTED_FW*/
61167e55c51SEtienne Carriere 
61201980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
613b0104773SPascal Brand }
614b0104773SPascal Brand 
6157315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
616b0104773SPascal Brand {
61753bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
61853bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
619b0104773SPascal Brand 
62067e55c51SEtienne Carriere 	assert(gd == &gic_data);
62167e55c51SEtienne Carriere 
622b0104773SPascal Brand 	/* Disable the interrupt */
623918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
624b0104773SPascal Brand 	/* Make it non-pending */
625918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
626b0104773SPascal Brand 	/* Assign it to group0 */
627918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
6281fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
6291fcac774SSandeep Tripathy 	/* Assign it to group1S */
6301fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
6311fcac774SSandeep Tripathy #endif
632b0104773SPascal Brand }
633b0104773SPascal Brand 
6347315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
6357315b7b4SJens Wiklander 				uint8_t cpu_mask)
636b0104773SPascal Brand {
6378ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6388ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
63953bd332aSSY Chiu 	uint32_t target, target_shift;
640918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
641918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
642b0104773SPascal Brand 
64367e55c51SEtienne Carriere 	assert(gd == &gic_data);
64467e55c51SEtienne Carriere 
645b0104773SPascal Brand 	/* Assigned to group0 */
646918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
647b0104773SPascal Brand 
648b0104773SPascal Brand 	/* Route it to selected CPUs */
649918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
65053bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
65153bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
65253bd332aSSY Chiu 	target |= cpu_mask << target_shift;
653918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
654918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
655918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
656b0104773SPascal Brand }
657b0104773SPascal Brand 
6587315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
659b0104773SPascal Brand {
6608ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
6618ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
662b0104773SPascal Brand 
66367e55c51SEtienne Carriere 	assert(gd == &gic_data);
66467e55c51SEtienne Carriere 
665b0104773SPascal Brand 	/* Assigned to group0 */
666918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
667b0104773SPascal Brand 
668b0104773SPascal Brand 	/* Set prio it to selected CPUs */
6691f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
6707315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
671918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
672b0104773SPascal Brand }
673b0104773SPascal Brand 
6747315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
675b0104773SPascal Brand {
67653bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
67753bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
678918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
679b0104773SPascal Brand 
68067e55c51SEtienne Carriere 	assert(gd == &gic_data);
68167e55c51SEtienne Carriere 
682b0104773SPascal Brand 	/* Assigned to group0 */
683918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
684b0104773SPascal Brand 
685b0104773SPascal Brand 	/* Enable the interrupt */
686918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
687b0104773SPascal Brand }
688b0104773SPascal Brand 
6897315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
690b0104773SPascal Brand {
69153bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
69253bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
693b0104773SPascal Brand 
69467e55c51SEtienne Carriere 	assert(gd == &gic_data);
69567e55c51SEtienne Carriere 
696b0104773SPascal Brand 	/* Assigned to group0 */
697918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
698b0104773SPascal Brand 
699b0104773SPascal Brand 	/* Disable the interrupt */
700918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
701b0104773SPascal Brand }
702b0104773SPascal Brand 
70326ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
70426ed70ecSGuanchao Liang {
70526ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
70626ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
70726ed70ecSGuanchao Liang 
70867e55c51SEtienne Carriere 	assert(gd == &gic_data);
70967e55c51SEtienne Carriere 
71026ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
71126ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
71226ed70ecSGuanchao Liang 
71326ed70ecSGuanchao Liang 	/* Raise the interrupt */
714918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
71526ed70ecSGuanchao Liang }
71626ed70ecSGuanchao Liang 
717ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
718ec740b9fSJens Wiklander {
719ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
720ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
721ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
722ec740b9fSJens Wiklander 
723ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
724ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
725ec740b9fSJens Wiklander }
726ec740b9fSJens Wiklander 
72754739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
72884603456SJens Wiklander 			     uint32_t cpu_mask, bool ns)
72926ed70ecSGuanchao Liang {
73054739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
73154739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
732ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
733ec740b9fSJens Wiklander 
734ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
735ec740b9fSJens Wiklander 
736ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
737ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
738ec740b9fSJens Wiklander 	} else {
73954739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
740ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
741ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
742ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
743ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
744ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
745ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
746ec740b9fSJens Wiklander 
747ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
748ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
749ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
750ec740b9fSJens Wiklander 
751ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
752ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
753ec740b9fSJens Wiklander 		} else {
754ec740b9fSJens Wiklander 			/*
755ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
756ec740b9fSJens Wiklander 			 * same cluster now.
757ec740b9fSJens Wiklander 			 */
758ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
759ec740b9fSJens Wiklander 		}
760ec740b9fSJens Wiklander 	}
76154739cb4SMark-PK Tsai 
76254739cb4SMark-PK Tsai 	/* Raise the interrupt */
76384603456SJens Wiklander 	if (ns)
76454739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
76554739cb4SMark-PK Tsai 	else
76654739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
76754739cb4SMark-PK Tsai #else
768ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
76984603456SJens Wiklander 	uint32_t mask_group = ns;
770ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
771ec740b9fSJens Wiklander 
772ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
773ec740b9fSJens Wiklander 
774ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
775ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
776ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
777ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
778ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
779ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
780ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
781ec740b9fSJens Wiklander 	} else {
782ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
783ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
784ec740b9fSJens Wiklander 	}
78526ed70ecSGuanchao Liang 
78626ed70ecSGuanchao Liang 	/* Raise the interrupt */
787918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
78854739cb4SMark-PK Tsai #endif
78926ed70ecSGuanchao Liang }
79026ed70ecSGuanchao Liang 
79118901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
792b0104773SPascal Brand {
79367e55c51SEtienne Carriere 	assert(gd == &gic_data);
79467e55c51SEtienne Carriere 
79518901324SDavid Wang #if defined(CFG_ARM_GICV3)
7961de462e1SSumit Garg 	return read_icc_iar1();
79718901324SDavid Wang #else
798918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
79918901324SDavid Wang #endif
800b0104773SPascal Brand }
801b0104773SPascal Brand 
80218901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
803b0104773SPascal Brand {
80467e55c51SEtienne Carriere 	assert(gd == &gic_data);
80567e55c51SEtienne Carriere 
80618901324SDavid Wang #if defined(CFG_ARM_GICV3)
8071de462e1SSumit Garg 	write_icc_eoir1(eoir);
80818901324SDavid Wang #else
809918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
81018901324SDavid Wang #endif
811b0104773SPascal Brand }
812b0104773SPascal Brand 
8137315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
8147315b7b4SJens Wiklander {
81553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
81653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
81767e55c51SEtienne Carriere 
81867e55c51SEtienne Carriere 	assert(gd == &gic_data);
819918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
82053bd332aSSY Chiu }
82153bd332aSSY Chiu 
8227315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
8237315b7b4SJens Wiklander {
82453bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
82553bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
82667e55c51SEtienne Carriere 
82767e55c51SEtienne Carriere 	assert(gd == &gic_data);
828918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
82953bd332aSSY Chiu }
83053bd332aSSY Chiu 
8317315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
8327315b7b4SJens Wiklander {
83353bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
8347315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
8357315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
83653bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
837918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
8387315b7b4SJens Wiklander 
83967e55c51SEtienne Carriere 	assert(gd == &gic_data);
840918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
84153bd332aSSY Chiu }
84253bd332aSSY Chiu 
84367e55c51SEtienne Carriere void gic_dump_state(void)
84453bd332aSSY Chiu {
84567e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
84667e55c51SEtienne Carriere 	int i = 0;
84753bd332aSSY Chiu 
84818901324SDavid Wang #if defined(CFG_ARM_GICV3)
84918901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
85018901324SDavid Wang #else
851918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
85218901324SDavid Wang #endif
853918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
8547315b7b4SJens Wiklander 
8554a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
8567315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
85753bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
8587315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
85953bd332aSSY Chiu 		}
86053bd332aSSY Chiu 	}
86153bd332aSSY Chiu }
8627315b7b4SJens Wiklander 
863*10cc5912SRunyang Chen TEE_Result gic_spi_release_to_ns(size_t it)
864*10cc5912SRunyang Chen {
865*10cc5912SRunyang Chen 	struct gic_data *gd = &gic_data;
866*10cc5912SRunyang Chen 	size_t idx = it / NUM_INTS_PER_REG;
867*10cc5912SRunyang Chen 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
868*10cc5912SRunyang Chen 
869*10cc5912SRunyang Chen 	if (it >= gd->max_it || it < GIC_SPI_BASE)
870*10cc5912SRunyang Chen 		return TEE_ERROR_BAD_PARAMETERS;
871*10cc5912SRunyang Chen 	/* Make sure it's already disabled */
872*10cc5912SRunyang Chen 	if (!gic_it_is_enabled(gd, it))
873*10cc5912SRunyang Chen 		return TEE_ERROR_BAD_STATE;
874*10cc5912SRunyang Chen 	/* Assert it's secure to start with */
875*10cc5912SRunyang Chen 	if (!gic_it_get_group(gd, it))
876*10cc5912SRunyang Chen 		return TEE_ERROR_BAD_STATE;
877*10cc5912SRunyang Chen 
878*10cc5912SRunyang Chen 	mutex_lock(&gic_mutex);
879*10cc5912SRunyang Chen 	gic_it_set_cpu_mask(gd, it, 0);
880*10cc5912SRunyang Chen 	gic_it_set_prio(gd, it, GIC_SPI_PRI_NS_EL1);
881*10cc5912SRunyang Chen 
882*10cc5912SRunyang Chen 	/* Clear pending status */
883*10cc5912SRunyang Chen 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
884*10cc5912SRunyang Chen 	/* Assign it to NS Group1 */
885*10cc5912SRunyang Chen 	io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
886*10cc5912SRunyang Chen #if defined(CFG_ARM_GICV3)
887*10cc5912SRunyang Chen 	io_clrbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
888*10cc5912SRunyang Chen #endif
889*10cc5912SRunyang Chen 	mutex_unlock(&gic_mutex);
890*10cc5912SRunyang Chen 	return TEE_SUCCESS;
891*10cc5912SRunyang Chen }
892*10cc5912SRunyang Chen 
89367e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
8947315b7b4SJens Wiklander {
89567e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
89667e55c51SEtienne Carriere 	uint32_t iar = 0;
89767e55c51SEtienne Carriere 	uint32_t id = 0;
8987315b7b4SJens Wiklander 
8997315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
9007315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
9017315b7b4SJens Wiklander 
9024a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
90399e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
9043b3a4611SMathieu Briand 	else
9053b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
9067315b7b4SJens Wiklander 
9077315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
9087315b7b4SJens Wiklander }
9097315b7b4SJens Wiklander 
91067e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
911358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
912358bf47cSEtienne Carriere void interrupt_main_handler(void)
91367e55c51SEtienne Carriere {
91467e55c51SEtienne Carriere 	gic_native_itr_handler();
91567e55c51SEtienne Carriere }
91667e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
91767e55c51SEtienne Carriere 
9187315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
919702fe5a7SClément Léger 		       uint32_t type __unused,
920702fe5a7SClément Léger 		       uint32_t prio __unused)
9217315b7b4SJens Wiklander {
9227315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
9237315b7b4SJens Wiklander 
92467e55c51SEtienne Carriere 	assert(gd == &gic_data);
92567e55c51SEtienne Carriere 
9264a9ea08cSFangsuo Wu 	if (it > gd->max_it)
927d13278b8SEtienne Carriere 		panic();
928d13278b8SEtienne Carriere 
9299e935234SJens Wiklander 	if (it < GIC_SPI_BASE) {
9309e935234SJens Wiklander 		if (gic_primary_done)
9319e935234SJens Wiklander 			panic("Cannot add SGI or PPI after boot");
9329e935234SJens Wiklander 
9339e935234SJens Wiklander 		/* Assign it to Secure Group 1, G1S */
9349e935234SJens Wiklander 		gd->per_cpu_group_modifier |= BIT32(it);
9359e935234SJens Wiklander 		gd->per_cpu_group_status &= ~BIT32(it);
9369e935234SJens Wiklander 	}
9379e935234SJens Wiklander 
9389e935234SJens Wiklander 	if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) {
9399e935234SJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
9409e935234SJens Wiklander 
9419e935234SJens Wiklander 		if (!gicr_base)
9429e935234SJens Wiklander 			panic("GICR_BASE missing");
9439e935234SJens Wiklander 
9449e935234SJens Wiklander 		/* Disable interrupt */
9459e935234SJens Wiklander 		io_write32(gicr_base + GICR_ICENABLER0, BIT32(it));
9469e935234SJens Wiklander 
9476c2d2e8aSJens Wiklander 		/* Wait for the write to GICR_ICENABLER0 to propagate */
9486c2d2e8aSJens Wiklander 		gicr_wait_for_pending_write(gicr_base);
9496c2d2e8aSJens Wiklander 
9509e935234SJens Wiklander 		/* Make interrupt non-pending */
9519e935234SJens Wiklander 		io_write32(gicr_base + GICR_ICPENDR0, BIT32(it));
9529e935234SJens Wiklander 
9539e935234SJens Wiklander 		/* Make it to Secure */
9549e935234SJens Wiklander 		io_write32(gicr_base + GICR_IGROUPR0, gd->per_cpu_group_status);
9559e935234SJens Wiklander 		io_write32(gicr_base + GICR_IGRPMODR0,
9569e935234SJens Wiklander 			   gd->per_cpu_group_modifier);
9579e935234SJens Wiklander 	} else {
9587315b7b4SJens Wiklander 		gic_it_add(gd, it);
9597315b7b4SJens Wiklander 		/* Set the CPU mask to deliver interrupts to any online core */
9607315b7b4SJens Wiklander 		gic_it_set_cpu_mask(gd, it, 0xff);
9617315b7b4SJens Wiklander 		gic_it_set_prio(gd, it, 0x1);
9627315b7b4SJens Wiklander 	}
9639e935234SJens Wiklander }
9647315b7b4SJens Wiklander 
9657315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
9667315b7b4SJens Wiklander {
9677315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
9687315b7b4SJens Wiklander 
96967e55c51SEtienne Carriere 	assert(gd == &gic_data);
97067e55c51SEtienne Carriere 
9714a9ea08cSFangsuo Wu 	if (it > gd->max_it)
972d13278b8SEtienne Carriere 		panic();
973d13278b8SEtienne Carriere 
9749e935234SJens Wiklander 	if (it < GIC_SPI_BASE)
9759e935234SJens Wiklander 		gd->per_cpu_enable |= BIT(it);
9769e935234SJens Wiklander 
9779e935234SJens Wiklander 	if (it < GIC_SPI_BASE && affinity_routing_is_enabled(gd)) {
9789e935234SJens Wiklander 		vaddr_t gicr_base = get_gicr_base(gd);
9799e935234SJens Wiklander 
9809e935234SJens Wiklander 		if (!gicr_base)
9819e935234SJens Wiklander 			panic("GICR_BASE missing");
9829e935234SJens Wiklander 
9839e935234SJens Wiklander 		/* Assigned to G1S */
9849e935234SJens Wiklander 		assert(gd->per_cpu_group_modifier & BIT(it) &&
9859e935234SJens Wiklander 		       !(gd->per_cpu_group_status & BIT(it)));
9869e935234SJens Wiklander 		io_write32(gicr_base + GICR_ISENABLER0, gd->per_cpu_enable);
9879e935234SJens Wiklander 	} else {
9887315b7b4SJens Wiklander 		gic_it_enable(gd, it);
9897315b7b4SJens Wiklander 	}
9909e935234SJens Wiklander }
9917315b7b4SJens Wiklander 
9927315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
9937315b7b4SJens Wiklander {
9947315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
9957315b7b4SJens Wiklander 
99667e55c51SEtienne Carriere 	assert(gd == &gic_data);
99767e55c51SEtienne Carriere 
9984a9ea08cSFangsuo Wu 	if (it > gd->max_it)
999d13278b8SEtienne Carriere 		panic();
1000d13278b8SEtienne Carriere 
10017315b7b4SJens Wiklander 	gic_it_disable(gd, it);
10027315b7b4SJens Wiklander }
100326ed70ecSGuanchao Liang 
100426ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
100526ed70ecSGuanchao Liang {
100626ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
100726ed70ecSGuanchao Liang 
100867e55c51SEtienne Carriere 	assert(gd == &gic_data);
100967e55c51SEtienne Carriere 
10104a9ea08cSFangsuo Wu 	if (it > gd->max_it)
101126ed70ecSGuanchao Liang 		panic();
101226ed70ecSGuanchao Liang 
101326ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
101426ed70ecSGuanchao Liang }
101526ed70ecSGuanchao Liang 
101626ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
1017ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
101826ed70ecSGuanchao Liang {
101926ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
102084603456SJens Wiklander 	bool ns = false;
102126ed70ecSGuanchao Liang 
102267e55c51SEtienne Carriere 	assert(gd == &gic_data);
102367e55c51SEtienne Carriere 
102454739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
102554739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
102654739cb4SMark-PK Tsai 
102784603456SJens Wiklander 	ns = BIT32(it) & gd->per_cpu_group_status;
102884603456SJens Wiklander 	gic_it_raise_sgi(gd, it, cpu_mask, ns);
102926ed70ecSGuanchao Liang }
103067e55c51SEtienne Carriere 
103126ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
103226ed70ecSGuanchao Liang 			uint8_t cpu_mask)
103326ed70ecSGuanchao Liang {
103426ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
103526ed70ecSGuanchao Liang 
103667e55c51SEtienne Carriere 	assert(gd == &gic_data);
103767e55c51SEtienne Carriere 
10384a9ea08cSFangsuo Wu 	if (it > gd->max_it)
103926ed70ecSGuanchao Liang 		panic();
104026ed70ecSGuanchao Liang 
104126ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
104226ed70ecSGuanchao Liang }
104314885eb1SEtienne Carriere 
104414885eb1SEtienne Carriere #ifdef CFG_DT
104514885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
104614885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
104714885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
104814885eb1SEtienne Carriere {
104914885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
105014885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
105114885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
105214885eb1SEtienne Carriere 	uint32_t type = 0;
105314885eb1SEtienne Carriere 	uint32_t prio = 0;
105414885eb1SEtienne Carriere 
105514885eb1SEtienne Carriere 	assert(arg && itr_desc);
105614885eb1SEtienne Carriere 
105714885eb1SEtienne Carriere 	/*
105814885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
105914885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
106014885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
106114885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
106214885eb1SEtienne Carriere 	 */
106314885eb1SEtienne Carriere 	if (arg->args_count < 2)
106414885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
106514885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
106614885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
106714885eb1SEtienne Carriere 
106814885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
106914885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
107014885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
107114885eb1SEtienne Carriere 
107214885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
107314885eb1SEtienne Carriere 
107414885eb1SEtienne Carriere 	itr_desc->chip = chip;
107514885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
107614885eb1SEtienne Carriere 
107714885eb1SEtienne Carriere 	return TEE_SUCCESS;
107814885eb1SEtienne Carriere }
107914885eb1SEtienne Carriere 
108014885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
108114885eb1SEtienne Carriere {
108214885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
108314885eb1SEtienne Carriere 					&gic_data.chip))
108414885eb1SEtienne Carriere 		panic();
108514885eb1SEtienne Carriere 
108614885eb1SEtienne Carriere 	return TEE_SUCCESS;
108714885eb1SEtienne Carriere }
108814885eb1SEtienne Carriere 
108914885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
109014885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
109114885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
109214885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
109314885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
109414885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
109514885eb1SEtienne Carriere 	{ }
109614885eb1SEtienne Carriere };
109714885eb1SEtienne Carriere 
109814885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
109914885eb1SEtienne Carriere 	.name = "gic",
110014885eb1SEtienne Carriere 	.match_table = gic_match_table,
110114885eb1SEtienne Carriere 	.probe = gic_probe,
110214885eb1SEtienne Carriere };
110314885eb1SEtienne Carriere #endif /*CFG_DT*/
11049e935234SJens Wiklander 
11059e935234SJens Wiklander static TEE_Result gic_set_primary_done(void)
11069e935234SJens Wiklander {
11079e935234SJens Wiklander 	gic_primary_done = true;
11089e935234SJens Wiklander 	return TEE_SUCCESS;
11099e935234SJens Wiklander }
11109e935234SJens Wiklander 
11119e935234SJens Wiklander nex_release_init_resource(gic_set_primary_done);
1112