xref: /optee_os/core/drivers/gic.c (revision 69171bec89ce7cae515a67a8b47d9764f915255c)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b0104773SPascal Brand /*
318901324SDavid Wang  * Copyright (c) 2016-2017, 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>
1067729d8dSLudovic Barre #include <config.h>
1167e55c51SEtienne Carriere #include <compiler.h>
12b0104773SPascal Brand #include <drivers/gic.h>
130f93de74SEtienne Carriere #include <keep.h>
1467729d8dSLudovic Barre #include <kernel/dt.h>
1514885eb1SEtienne Carriere #include <kernel/dt_driver.h>
167315b7b4SJens Wiklander #include <kernel/interrupt.h>
17d13278b8SEtienne Carriere #include <kernel/panic.h>
1860801696SVolodymyr Babchuk #include <mm/core_memprot.h>
1960801696SVolodymyr Babchuk #include <mm/core_mmu.h>
2067729d8dSLudovic Barre #include <libfdt.h>
217315b7b4SJens Wiklander #include <util.h>
22b0104773SPascal Brand #include <io.h>
234de4bebcSJens Wiklander #include <trace.h>
24b0104773SPascal Brand 
25b0104773SPascal Brand /* Offsets from gic.gicc_base */
26b0104773SPascal Brand #define GICC_CTLR		(0x000)
2730a673e3SPeter Maydell #define GICC_PMR		(0x004)
28b0104773SPascal Brand #define GICC_IAR		(0x00C)
29b0104773SPascal Brand #define GICC_EOIR		(0x010)
30b0104773SPascal Brand 
31b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0	(1 << 0)
32b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1	(1 << 1)
331fcac774SSandeep Tripathy #define GICD_CTLR_ENABLEGRP1S	(1 << 2)
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 
49*69171becSJens Wiklander #ifdef CFG_ARM_GICV3
50*69171becSJens Wiklander #define GICD_PIDR2		(0xFFE8)
51*69171becSJens Wiklander #else
52*69171becSJens Wiklander /* Called ICPIDR2 in GICv2 specification */
53*69171becSJens Wiklander #define GICD_PIDR2		(0xFE8)
54*69171becSJens Wiklander #endif
55*69171becSJens Wiklander 
56b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0	(1 << 0)
57b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1	(1 << 1)
58b0104773SPascal Brand 
59*69171becSJens Wiklander /* GICD IDR2 name differs on GICv3 and GICv2 but uses same bit map */
60*69171becSJens Wiklander #define GICD_PIDR2_ARCHREV_SHIFT	4
61*69171becSJens Wiklander #define GICD_PIDR2_ARCHREV_MASK		0xF
62*69171becSJens Wiklander 
6353bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
6453bd332aSSY Chiu #define NUM_PPI	32
6553bd332aSSY Chiu 
6626ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
6726ed70ecSGuanchao Liang #define NUM_SGI			16
6826ed70ecSGuanchao Liang 
6926ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
7026ed70ecSGuanchao Liang #define NUM_NS_SGI		8
7126ed70ecSGuanchao Liang 
7253bd332aSSY Chiu /* Number of interrupts in one register */
7353bd332aSSY Chiu #define NUM_INTS_PER_REG	32
7453bd332aSSY Chiu 
7553bd332aSSY Chiu /* Number of targets in one register */
7653bd332aSSY Chiu #define NUM_TARGETS_PER_REG	4
7753bd332aSSY Chiu 
7853bd332aSSY Chiu /* Accessors to access ITARGETSRn */
7953bd332aSSY Chiu #define ITARGETSR_FIELD_BITS	8
8053bd332aSSY Chiu #define ITARGETSR_FIELD_MASK	0xff
8153bd332aSSY Chiu 
821b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK	0x1f
837315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
847315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
857315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
86b0104773SPascal Brand 
87ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT	40
88ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT	16
89ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT	32
90ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT	48
91ec740b9fSJens Wiklander 
92ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK			0xf
93ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS			0x1
94ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU			0x2
95ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT	24
96ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT			15
97ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT		16
98ec740b9fSJens Wiklander 
9967e55c51SEtienne Carriere struct gic_data {
10067e55c51SEtienne Carriere 	vaddr_t gicc_base;
10167e55c51SEtienne Carriere 	vaddr_t gicd_base;
10267e55c51SEtienne Carriere 	size_t max_it;
10367e55c51SEtienne Carriere 	struct itr_chip chip;
10467e55c51SEtienne Carriere };
10567e55c51SEtienne Carriere 
10667e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
10767e55c51SEtienne Carriere 
108702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
109702fe5a7SClément Léger 		       uint32_t prio);
1107315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
1117315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
11226ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
11326ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
114ec740b9fSJens Wiklander 			     uint32_t cpu_mask);
11526ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
11626ed70ecSGuanchao Liang 			uint8_t cpu_mask);
1177315b7b4SJens Wiklander 
1187315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1197315b7b4SJens Wiklander 	.add = gic_op_add,
12008ded0e1SEtienne Carriere 	.mask = gic_op_disable,
12108ded0e1SEtienne Carriere 	.unmask = gic_op_enable,
1227315b7b4SJens Wiklander 	.enable = gic_op_enable,
1237315b7b4SJens Wiklander 	.disable = gic_op_disable,
12426ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
12526ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
12626ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1277315b7b4SJens Wiklander };
1283639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1297315b7b4SJens Wiklander 
13018901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
131b0104773SPascal Brand {
132b0104773SPascal Brand 	int i;
133b0104773SPascal Brand 	uint32_t old_ctlr;
134b0104773SPascal Brand 	size_t ret = 0;
1351b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1361b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
137b0104773SPascal Brand 
138b0104773SPascal Brand 	/*
139b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
140b0104773SPascal Brand 	 */
14118901324SDavid Wang #if defined(CFG_ARM_GICV3)
14218901324SDavid Wang 	old_ctlr = read_icc_ctlr();
14318901324SDavid Wang 	write_icc_ctlr(0);
14418901324SDavid Wang #else
145918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
146918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
14718901324SDavid Wang #endif
14879f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
149b0104773SPascal Brand 		uint32_t old_reg;
150b0104773SPascal Brand 		uint32_t reg;
151b0104773SPascal Brand 		int b;
152b0104773SPascal Brand 
153918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
154918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
155918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
156918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
15779f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
158007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
15953bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
160b0104773SPascal Brand 				goto out;
161b0104773SPascal Brand 			}
162b0104773SPascal Brand 		}
163b0104773SPascal Brand 	}
164b0104773SPascal Brand out:
16518901324SDavid Wang #if defined(CFG_ARM_GICV3)
16618901324SDavid Wang 	write_icc_ctlr(old_ctlr);
16718901324SDavid Wang #else
168918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
16918901324SDavid Wang #endif
170b0104773SPascal Brand 	return ret;
171b0104773SPascal Brand }
172b0104773SPascal Brand 
17367e55c51SEtienne Carriere void gic_cpu_init(void)
174bedc2b9fSsunny {
17567e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
17667e55c51SEtienne Carriere 
17718901324SDavid Wang #if defined(CFG_ARM_GICV3)
17818901324SDavid Wang 	assert(gd->gicd_base);
17918901324SDavid Wang #else
18005efe1e1SEtienne Carriere 	assert(gd->gicd_base && gd->gicc_base);
18118901324SDavid Wang #endif
18205efe1e1SEtienne Carriere 
183e06e6e74SPeter Maydell 	/* per-CPU interrupts config:
184bedc2b9fSsunny 	 * ID0-ID7(SGI)   for Non-secure interrupts
185bedc2b9fSsunny 	 * ID8-ID15(SGI)  for Secure interrupts.
186bedc2b9fSsunny 	 * All PPI config as Non-secure interrupts.
187bedc2b9fSsunny 	 */
188918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff);
189bedc2b9fSsunny 
19030a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
19130a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
19230a673e3SPeter Maydell 	 */
19318901324SDavid Wang #if defined(CFG_ARM_GICV3)
19418901324SDavid Wang 	write_icc_pmr(0x80);
1951fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
19618901324SDavid Wang #else
197918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
19830a673e3SPeter Maydell 
199bedc2b9fSsunny 	/* Enable GIC */
200918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
201918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
202918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
20318901324SDavid Wang #endif
204bedc2b9fSsunny }
205bedc2b9fSsunny 
2060ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
2070ee3f52eSEtienne Carriere 			  uint32_t *prio)
2080ee3f52eSEtienne Carriere {
2090ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
2100ee3f52eSEtienne Carriere 
2110ee3f52eSEtienne Carriere 	if (type)
2120ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
2130ee3f52eSEtienne Carriere 
2140ee3f52eSEtienne Carriere 	if (prio)
2150ee3f52eSEtienne Carriere 		*prio = 0;
2160ee3f52eSEtienne Carriere 
2170ee3f52eSEtienne Carriere 	if (!properties || count < 2)
2180ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
2190ee3f52eSEtienne Carriere 
2200ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
2210ee3f52eSEtienne Carriere 
2220ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
2238c7282beSEtienne Carriere 	case GIC_PPI:
2240ee3f52eSEtienne Carriere 		it_num += 16;
2250ee3f52eSEtienne Carriere 		break;
2268c7282beSEtienne Carriere 	case GIC_SPI:
2270ee3f52eSEtienne Carriere 		it_num += 32;
2280ee3f52eSEtienne Carriere 		break;
2290ee3f52eSEtienne Carriere 	default:
2300ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
2310ee3f52eSEtienne Carriere 	}
2320ee3f52eSEtienne Carriere 
2330ee3f52eSEtienne Carriere 	return it_num;
2340ee3f52eSEtienne Carriere }
2350ee3f52eSEtienne Carriere 
2360ee3f52eSEtienne Carriere static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa)
237b0104773SPascal Brand {
23867e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
2390ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
2400ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
241*69171becSJens Wiklander 	uint32_t vers __maybe_unused = 0;
2420ee3f52eSEtienne Carriere 
2430ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
2440ee3f52eSEtienne Carriere 
2450ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
2460ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
2470ee3f52eSEtienne Carriere 	if (!gicd_base)
2480ee3f52eSEtienne Carriere 		panic();
2490ee3f52eSEtienne Carriere 
250*69171becSJens Wiklander 	vers = io_read32(gicd_base + GICD_PIDR2);
251*69171becSJens Wiklander 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
252*69171becSJens Wiklander 	vers &= GICD_PIDR2_ARCHREV_MASK;
253*69171becSJens Wiklander 
254*69171becSJens Wiklander 	if (IS_ENABLED(CFG_ARM_GICV3)) {
255*69171becSJens Wiklander 		assert(vers == 3);
256*69171becSJens Wiklander 	} else {
257*69171becSJens Wiklander 		assert(vers == 2);
2580ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
2590ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
2600ee3f52eSEtienne Carriere 		if (!gicc_base)
2610ee3f52eSEtienne Carriere 			panic();
2620ee3f52eSEtienne Carriere 	}
2630ee3f52eSEtienne Carriere 
2640ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
2650ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
2660ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
2670ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
2680ee3f52eSEtienne Carriere 
2690ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
2700ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
2710ee3f52eSEtienne Carriere }
2720ee3f52eSEtienne Carriere 
2730ee3f52eSEtienne Carriere void gic_init(paddr_t gicc_base_pa, paddr_t gicd_base_pa)
2740ee3f52eSEtienne Carriere {
2750ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
2760ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
277b0104773SPascal Brand 
27867e55c51SEtienne Carriere 	gic_init_base_addr(gicc_base_pa, gicd_base_pa);
279b0104773SPascal Brand 
2800ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
2810ee3f52eSEtienne Carriere #ifndef CFG_WITH_ARM_TRUSTED_FW
2827315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
283b0104773SPascal Brand 		/* Disable interrupts */
284918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
285b0104773SPascal Brand 
286b0104773SPascal Brand 		/* Make interrupts non-pending */
287918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
288b0104773SPascal Brand 
289b0104773SPascal Brand 		/* Mark interrupts non-secure */
290bedc2b9fSsunny 		if (n == 0) {
291bedc2b9fSsunny 			/* per-CPU inerrupts config:
292bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
293bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
294bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
295bedc2b9fSsunny 			 */
296918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff);
297bedc2b9fSsunny 		} else {
298918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
299b0104773SPascal Brand 		}
300bedc2b9fSsunny 	}
301b0104773SPascal Brand 
30230a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
30330a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
30430a673e3SPeter Maydell 	 */
30518901324SDavid Wang #if defined(CFG_ARM_GICV3)
30618901324SDavid Wang 	write_icc_pmr(0x80);
3071fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
3081fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
30918901324SDavid Wang #else
310918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
31130a673e3SPeter Maydell 
312b0104773SPascal Brand 	/* Enable GIC */
313918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
314918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
315918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
316918bb3a5SEtienne Carriere 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1);
3171fcac774SSandeep Tripathy #endif
3180ee3f52eSEtienne Carriere #endif /*CFG_WITH_ARM_TRUSTED_FW*/
31967e55c51SEtienne Carriere 
32001980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
321b0104773SPascal Brand }
322b0104773SPascal Brand 
3237315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
324b0104773SPascal Brand {
32553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
32653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
327b0104773SPascal Brand 
32867e55c51SEtienne Carriere 	assert(gd == &gic_data);
32967e55c51SEtienne Carriere 
330b0104773SPascal Brand 	/* Disable the interrupt */
331918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
332b0104773SPascal Brand 	/* Make it non-pending */
333918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
334b0104773SPascal Brand 	/* Assign it to group0 */
335918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
3361fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
3371fcac774SSandeep Tripathy 	/* Assign it to group1S */
3381fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
3391fcac774SSandeep Tripathy #endif
340b0104773SPascal Brand }
341b0104773SPascal Brand 
3427315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
3437315b7b4SJens Wiklander 				uint8_t cpu_mask)
344b0104773SPascal Brand {
3458ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
3468ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
34753bd332aSSY Chiu 	uint32_t target, target_shift;
348918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
349918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
350b0104773SPascal Brand 
35167e55c51SEtienne Carriere 	assert(gd == &gic_data);
35267e55c51SEtienne Carriere 
353b0104773SPascal Brand 	/* Assigned to group0 */
354918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
355b0104773SPascal Brand 
356b0104773SPascal Brand 	/* Route it to selected CPUs */
357918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
35853bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
35953bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
36053bd332aSSY Chiu 	target |= cpu_mask << target_shift;
361918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
362918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
363918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
364b0104773SPascal Brand }
365b0104773SPascal Brand 
3667315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
367b0104773SPascal Brand {
3688ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
3698ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
370b0104773SPascal Brand 
37167e55c51SEtienne Carriere 	assert(gd == &gic_data);
37267e55c51SEtienne Carriere 
373b0104773SPascal Brand 	/* Assigned to group0 */
374918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
375b0104773SPascal Brand 
376b0104773SPascal Brand 	/* Set prio it to selected CPUs */
3771f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
3787315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
379918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
380b0104773SPascal Brand }
381b0104773SPascal Brand 
3827315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
383b0104773SPascal Brand {
38453bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
38553bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
386918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
387b0104773SPascal Brand 
38867e55c51SEtienne Carriere 	assert(gd == &gic_data);
38967e55c51SEtienne Carriere 
390b0104773SPascal Brand 	/* Assigned to group0 */
391918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
392b0104773SPascal Brand 
393b0104773SPascal Brand 	/* Enable the interrupt */
394918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
395b0104773SPascal Brand }
396b0104773SPascal Brand 
3977315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
398b0104773SPascal Brand {
39953bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
40053bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
401b0104773SPascal Brand 
40267e55c51SEtienne Carriere 	assert(gd == &gic_data);
40367e55c51SEtienne Carriere 
404b0104773SPascal Brand 	/* Assigned to group0 */
405918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
406b0104773SPascal Brand 
407b0104773SPascal Brand 	/* Disable the interrupt */
408918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
409b0104773SPascal Brand }
410b0104773SPascal Brand 
41126ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
41226ed70ecSGuanchao Liang {
41326ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
41426ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
41526ed70ecSGuanchao Liang 
41667e55c51SEtienne Carriere 	assert(gd == &gic_data);
41767e55c51SEtienne Carriere 
41826ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
41926ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
42026ed70ecSGuanchao Liang 
42126ed70ecSGuanchao Liang 	/* Raise the interrupt */
422918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
42326ed70ecSGuanchao Liang }
42426ed70ecSGuanchao Liang 
425ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
426ec740b9fSJens Wiklander {
427ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
428ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
429ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
430ec740b9fSJens Wiklander 
431ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
432ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
433ec740b9fSJens Wiklander }
434ec740b9fSJens Wiklander 
43554739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
436ec740b9fSJens Wiklander 			     uint32_t cpu_mask, uint8_t group)
43726ed70ecSGuanchao Liang {
43854739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
43954739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
440ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
441ec740b9fSJens Wiklander 
442ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
443ec740b9fSJens Wiklander 
444ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
445ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
446ec740b9fSJens Wiklander 	} else {
44754739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
448ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
449ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
450ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
451ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
452ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
453ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
454ec740b9fSJens Wiklander 
455ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
456ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
457ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
458ec740b9fSJens Wiklander 
459ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
460ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
461ec740b9fSJens Wiklander 		} else {
462ec740b9fSJens Wiklander 			/*
463ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
464ec740b9fSJens Wiklander 			 * same cluster now.
465ec740b9fSJens Wiklander 			 */
466ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
467ec740b9fSJens Wiklander 		}
468ec740b9fSJens Wiklander 	}
46954739cb4SMark-PK Tsai 
47054739cb4SMark-PK Tsai 	/* Raise the interrupt */
47154739cb4SMark-PK Tsai 	if (group)
47254739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
47354739cb4SMark-PK Tsai 	else
47454739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
47554739cb4SMark-PK Tsai #else
476ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
47726ed70ecSGuanchao Liang 	uint32_t mask_group = group & 0x1;
478ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
479ec740b9fSJens Wiklander 
480ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
481ec740b9fSJens Wiklander 
482ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
483ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
484ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
485ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
486ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
487ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
488ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
489ec740b9fSJens Wiklander 	} else {
490ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
491ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
492ec740b9fSJens Wiklander 	}
49326ed70ecSGuanchao Liang 
49426ed70ecSGuanchao Liang 	/* Raise the interrupt */
495918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
49654739cb4SMark-PK Tsai #endif
49726ed70ecSGuanchao Liang }
49826ed70ecSGuanchao Liang 
49918901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
500b0104773SPascal Brand {
50167e55c51SEtienne Carriere 	assert(gd == &gic_data);
50267e55c51SEtienne Carriere 
50318901324SDavid Wang #if defined(CFG_ARM_GICV3)
5041de462e1SSumit Garg 	return read_icc_iar1();
50518901324SDavid Wang #else
506918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
50718901324SDavid Wang #endif
508b0104773SPascal Brand }
509b0104773SPascal Brand 
51018901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
511b0104773SPascal Brand {
51267e55c51SEtienne Carriere 	assert(gd == &gic_data);
51367e55c51SEtienne Carriere 
51418901324SDavid Wang #if defined(CFG_ARM_GICV3)
5151de462e1SSumit Garg 	write_icc_eoir1(eoir);
51618901324SDavid Wang #else
517918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
51818901324SDavid Wang #endif
519b0104773SPascal Brand }
520b0104773SPascal Brand 
5217315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
5227315b7b4SJens Wiklander {
52353bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
52453bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
52567e55c51SEtienne Carriere 
52667e55c51SEtienne Carriere 	assert(gd == &gic_data);
527918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
52853bd332aSSY Chiu }
52953bd332aSSY Chiu 
5307315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
5317315b7b4SJens Wiklander {
53253bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
53353bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
53467e55c51SEtienne Carriere 
53567e55c51SEtienne Carriere 	assert(gd == &gic_data);
536918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
53753bd332aSSY Chiu }
53853bd332aSSY Chiu 
5397315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
5407315b7b4SJens Wiklander {
54153bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
5427315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
5437315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
54453bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
545918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
5467315b7b4SJens Wiklander 
54767e55c51SEtienne Carriere 	assert(gd == &gic_data);
548918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
54953bd332aSSY Chiu }
55053bd332aSSY Chiu 
55167e55c51SEtienne Carriere void gic_dump_state(void)
55253bd332aSSY Chiu {
55367e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
55467e55c51SEtienne Carriere 	int i = 0;
55553bd332aSSY Chiu 
55618901324SDavid Wang #if defined(CFG_ARM_GICV3)
55718901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
55818901324SDavid Wang #else
559918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
56018901324SDavid Wang #endif
561918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
5627315b7b4SJens Wiklander 
5634a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
5647315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
56553bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
5667315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
56753bd332aSSY Chiu 		}
56853bd332aSSY Chiu 	}
56953bd332aSSY Chiu }
5707315b7b4SJens Wiklander 
57167e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
5727315b7b4SJens Wiklander {
57367e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
57467e55c51SEtienne Carriere 	uint32_t iar = 0;
57567e55c51SEtienne Carriere 	uint32_t id = 0;
5767315b7b4SJens Wiklander 
5777315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
5787315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
5797315b7b4SJens Wiklander 
5804a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
58199e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
5823b3a4611SMathieu Briand 	else
5833b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
5847315b7b4SJens Wiklander 
5857315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
5867315b7b4SJens Wiklander }
5877315b7b4SJens Wiklander 
58867e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
589358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
590358bf47cSEtienne Carriere void interrupt_main_handler(void)
59167e55c51SEtienne Carriere {
59267e55c51SEtienne Carriere 	gic_native_itr_handler();
59367e55c51SEtienne Carriere }
59467e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
59567e55c51SEtienne Carriere 
5967315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
597702fe5a7SClément Léger 		       uint32_t type __unused,
598702fe5a7SClément Léger 		       uint32_t prio __unused)
5997315b7b4SJens Wiklander {
6007315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
6017315b7b4SJens Wiklander 
60267e55c51SEtienne Carriere 	assert(gd == &gic_data);
60367e55c51SEtienne Carriere 
6044a9ea08cSFangsuo Wu 	if (it > gd->max_it)
605d13278b8SEtienne Carriere 		panic();
606d13278b8SEtienne Carriere 
6077315b7b4SJens Wiklander 	gic_it_add(gd, it);
6087315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
6097315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
6107315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
6117315b7b4SJens Wiklander }
6127315b7b4SJens Wiklander 
6137315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
6147315b7b4SJens Wiklander {
6157315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
6167315b7b4SJens Wiklander 
61767e55c51SEtienne Carriere 	assert(gd == &gic_data);
61867e55c51SEtienne Carriere 
6194a9ea08cSFangsuo Wu 	if (it > gd->max_it)
620d13278b8SEtienne Carriere 		panic();
621d13278b8SEtienne Carriere 
6227315b7b4SJens Wiklander 	gic_it_enable(gd, it);
6237315b7b4SJens Wiklander }
6247315b7b4SJens Wiklander 
6257315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
6267315b7b4SJens Wiklander {
6277315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
6287315b7b4SJens Wiklander 
62967e55c51SEtienne Carriere 	assert(gd == &gic_data);
63067e55c51SEtienne Carriere 
6314a9ea08cSFangsuo Wu 	if (it > gd->max_it)
632d13278b8SEtienne Carriere 		panic();
633d13278b8SEtienne Carriere 
6347315b7b4SJens Wiklander 	gic_it_disable(gd, it);
6357315b7b4SJens Wiklander }
63626ed70ecSGuanchao Liang 
63726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
63826ed70ecSGuanchao Liang {
63926ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
64026ed70ecSGuanchao Liang 
64167e55c51SEtienne Carriere 	assert(gd == &gic_data);
64267e55c51SEtienne Carriere 
6434a9ea08cSFangsuo Wu 	if (it > gd->max_it)
64426ed70ecSGuanchao Liang 		panic();
64526ed70ecSGuanchao Liang 
64626ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
64726ed70ecSGuanchao Liang }
64826ed70ecSGuanchao Liang 
64926ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
650ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
65126ed70ecSGuanchao Liang {
65226ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
65326ed70ecSGuanchao Liang 
65467e55c51SEtienne Carriere 	assert(gd == &gic_data);
65567e55c51SEtienne Carriere 
65654739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
65754739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
65854739cb4SMark-PK Tsai 
6594a9ea08cSFangsuo Wu 	if (it > gd->max_it)
66026ed70ecSGuanchao Liang 		panic();
66126ed70ecSGuanchao Liang 
66226ed70ecSGuanchao Liang 	if (it < NUM_NS_SGI)
66326ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 1);
66426ed70ecSGuanchao Liang 	else
66526ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 0);
66626ed70ecSGuanchao Liang }
66767e55c51SEtienne Carriere 
66826ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
66926ed70ecSGuanchao Liang 			uint8_t cpu_mask)
67026ed70ecSGuanchao Liang {
67126ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
67226ed70ecSGuanchao Liang 
67367e55c51SEtienne Carriere 	assert(gd == &gic_data);
67467e55c51SEtienne Carriere 
6754a9ea08cSFangsuo Wu 	if (it > gd->max_it)
67626ed70ecSGuanchao Liang 		panic();
67726ed70ecSGuanchao Liang 
67826ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
67926ed70ecSGuanchao Liang }
68014885eb1SEtienne Carriere 
68114885eb1SEtienne Carriere #ifdef CFG_DT
68214885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
68314885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
68414885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
68514885eb1SEtienne Carriere {
68614885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
68714885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
68814885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
68914885eb1SEtienne Carriere 	uint32_t type = 0;
69014885eb1SEtienne Carriere 	uint32_t prio = 0;
69114885eb1SEtienne Carriere 
69214885eb1SEtienne Carriere 	assert(arg && itr_desc);
69314885eb1SEtienne Carriere 
69414885eb1SEtienne Carriere 	/*
69514885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
69614885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
69714885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
69814885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
69914885eb1SEtienne Carriere 	 */
70014885eb1SEtienne Carriere 	if (arg->args_count < 2)
70114885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
70214885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
70314885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
70414885eb1SEtienne Carriere 
70514885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
70614885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
70714885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
70814885eb1SEtienne Carriere 
70914885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
71014885eb1SEtienne Carriere 
71114885eb1SEtienne Carriere 	itr_desc->chip = chip;
71214885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
71314885eb1SEtienne Carriere 
71414885eb1SEtienne Carriere 	return TEE_SUCCESS;
71514885eb1SEtienne Carriere }
71614885eb1SEtienne Carriere 
71714885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
71814885eb1SEtienne Carriere {
71914885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
72014885eb1SEtienne Carriere 					&gic_data.chip))
72114885eb1SEtienne Carriere 		panic();
72214885eb1SEtienne Carriere 
72314885eb1SEtienne Carriere 	return TEE_SUCCESS;
72414885eb1SEtienne Carriere }
72514885eb1SEtienne Carriere 
72614885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
72714885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
72814885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
72914885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
73014885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
73114885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
73214885eb1SEtienne Carriere 	{ }
73314885eb1SEtienne Carriere };
73414885eb1SEtienne Carriere 
73514885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
73614885eb1SEtienne Carriere 	.name = "gic",
73714885eb1SEtienne Carriere 	.match_table = gic_match_table,
73814885eb1SEtienne Carriere 	.probe = gic_probe,
73914885eb1SEtienne Carriere };
74014885eb1SEtienne Carriere #endif /*CFG_DT*/
741