xref: /optee_os/core/drivers/gic.c (revision 8c7282be2bf86536ba1658f7a2040ec06304fdfb)
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>
9*8c7282beSEtienne 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 
49b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0	(1 << 0)
50b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1	(1 << 1)
51b0104773SPascal Brand 
5253bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
5353bd332aSSY Chiu #define NUM_PPI	32
5453bd332aSSY Chiu 
5526ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
5626ed70ecSGuanchao Liang #define NUM_SGI			16
5726ed70ecSGuanchao Liang 
5826ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
5926ed70ecSGuanchao Liang #define NUM_NS_SGI		8
6026ed70ecSGuanchao Liang 
6153bd332aSSY Chiu /* Number of interrupts in one register */
6253bd332aSSY Chiu #define NUM_INTS_PER_REG	32
6353bd332aSSY Chiu 
6453bd332aSSY Chiu /* Number of targets in one register */
6553bd332aSSY Chiu #define NUM_TARGETS_PER_REG	4
6653bd332aSSY Chiu 
6753bd332aSSY Chiu /* Accessors to access ITARGETSRn */
6853bd332aSSY Chiu #define ITARGETSR_FIELD_BITS	8
6953bd332aSSY Chiu #define ITARGETSR_FIELD_MASK	0xff
7053bd332aSSY Chiu 
711b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK	0x1f
727315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
737315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
747315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
75b0104773SPascal Brand 
76ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT	40
77ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT	16
78ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT	32
79ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT	48
80ec740b9fSJens Wiklander 
81ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK			0xf
82ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS			0x1
83ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU			0x2
84ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT	24
85ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT			15
86ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT		16
87ec740b9fSJens Wiklander 
8867e55c51SEtienne Carriere struct gic_data {
8967e55c51SEtienne Carriere 	vaddr_t gicc_base;
9067e55c51SEtienne Carriere 	vaddr_t gicd_base;
9167e55c51SEtienne Carriere 	size_t max_it;
9267e55c51SEtienne Carriere 	struct itr_chip chip;
9367e55c51SEtienne Carriere };
9467e55c51SEtienne Carriere 
9567e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
9667e55c51SEtienne Carriere 
97702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
98702fe5a7SClément Léger 		       uint32_t prio);
997315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
1007315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
10126ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
10226ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
103ec740b9fSJens Wiklander 			     uint32_t cpu_mask);
10426ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
10526ed70ecSGuanchao Liang 			uint8_t cpu_mask);
1067315b7b4SJens Wiklander 
1077315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1087315b7b4SJens Wiklander 	.add = gic_op_add,
10908ded0e1SEtienne Carriere 	.mask = gic_op_disable,
11008ded0e1SEtienne Carriere 	.unmask = gic_op_enable,
1117315b7b4SJens Wiklander 	.enable = gic_op_enable,
1127315b7b4SJens Wiklander 	.disable = gic_op_disable,
11326ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
11426ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
11526ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1167315b7b4SJens Wiklander };
1173639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1187315b7b4SJens Wiklander 
11918901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
120b0104773SPascal Brand {
121b0104773SPascal Brand 	int i;
122b0104773SPascal Brand 	uint32_t old_ctlr;
123b0104773SPascal Brand 	size_t ret = 0;
1241b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1251b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
126b0104773SPascal Brand 
127b0104773SPascal Brand 	/*
128b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
129b0104773SPascal Brand 	 */
13018901324SDavid Wang #if defined(CFG_ARM_GICV3)
13118901324SDavid Wang 	old_ctlr = read_icc_ctlr();
13218901324SDavid Wang 	write_icc_ctlr(0);
13318901324SDavid Wang #else
134918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
135918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
13618901324SDavid Wang #endif
13779f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
138b0104773SPascal Brand 		uint32_t old_reg;
139b0104773SPascal Brand 		uint32_t reg;
140b0104773SPascal Brand 		int b;
141b0104773SPascal Brand 
142918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
143918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
144918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
145918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
14679f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
147007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
14853bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
149b0104773SPascal Brand 				goto out;
150b0104773SPascal Brand 			}
151b0104773SPascal Brand 		}
152b0104773SPascal Brand 	}
153b0104773SPascal Brand out:
15418901324SDavid Wang #if defined(CFG_ARM_GICV3)
15518901324SDavid Wang 	write_icc_ctlr(old_ctlr);
15618901324SDavid Wang #else
157918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
15818901324SDavid Wang #endif
159b0104773SPascal Brand 	return ret;
160b0104773SPascal Brand }
161b0104773SPascal Brand 
16267e55c51SEtienne Carriere void gic_cpu_init(void)
163bedc2b9fSsunny {
16467e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
16567e55c51SEtienne Carriere 
16618901324SDavid Wang #if defined(CFG_ARM_GICV3)
16718901324SDavid Wang 	assert(gd->gicd_base);
16818901324SDavid Wang #else
16905efe1e1SEtienne Carriere 	assert(gd->gicd_base && gd->gicc_base);
17018901324SDavid Wang #endif
17105efe1e1SEtienne Carriere 
172e06e6e74SPeter Maydell 	/* per-CPU interrupts config:
173bedc2b9fSsunny 	 * ID0-ID7(SGI)   for Non-secure interrupts
174bedc2b9fSsunny 	 * ID8-ID15(SGI)  for Secure interrupts.
175bedc2b9fSsunny 	 * All PPI config as Non-secure interrupts.
176bedc2b9fSsunny 	 */
177918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff);
178bedc2b9fSsunny 
17930a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
18030a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
18130a673e3SPeter Maydell 	 */
18218901324SDavid Wang #if defined(CFG_ARM_GICV3)
18318901324SDavid Wang 	write_icc_pmr(0x80);
1841fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
18518901324SDavid Wang #else
186918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
18730a673e3SPeter Maydell 
188bedc2b9fSsunny 	/* Enable GIC */
189918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
190918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
191918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
19218901324SDavid Wang #endif
193bedc2b9fSsunny }
194bedc2b9fSsunny 
1950ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
1960ee3f52eSEtienne Carriere 			  uint32_t *prio)
1970ee3f52eSEtienne Carriere {
1980ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
1990ee3f52eSEtienne Carriere 
2000ee3f52eSEtienne Carriere 	if (type)
2010ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
2020ee3f52eSEtienne Carriere 
2030ee3f52eSEtienne Carriere 	if (prio)
2040ee3f52eSEtienne Carriere 		*prio = 0;
2050ee3f52eSEtienne Carriere 
2060ee3f52eSEtienne Carriere 	if (!properties || count < 2)
2070ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
2080ee3f52eSEtienne Carriere 
2090ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
2100ee3f52eSEtienne Carriere 
2110ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
212*8c7282beSEtienne Carriere 	case GIC_PPI:
2130ee3f52eSEtienne Carriere 		it_num += 16;
2140ee3f52eSEtienne Carriere 		break;
215*8c7282beSEtienne Carriere 	case GIC_SPI:
2160ee3f52eSEtienne Carriere 		it_num += 32;
2170ee3f52eSEtienne Carriere 		break;
2180ee3f52eSEtienne Carriere 	default:
2190ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
2200ee3f52eSEtienne Carriere 	}
2210ee3f52eSEtienne Carriere 
2220ee3f52eSEtienne Carriere 	return it_num;
2230ee3f52eSEtienne Carriere }
2240ee3f52eSEtienne Carriere 
2250ee3f52eSEtienne Carriere static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa)
226b0104773SPascal Brand {
22767e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
2280ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
2290ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
2300ee3f52eSEtienne Carriere 
2310ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
2320ee3f52eSEtienne Carriere 
2330ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
2340ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
2350ee3f52eSEtienne Carriere 	if (!gicd_base)
2360ee3f52eSEtienne Carriere 		panic();
2370ee3f52eSEtienne Carriere 
2380ee3f52eSEtienne Carriere 	if (!IS_ENABLED(CFG_ARM_GICV3)) {
2390ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
2400ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
2410ee3f52eSEtienne Carriere 		if (!gicc_base)
2420ee3f52eSEtienne Carriere 			panic();
2430ee3f52eSEtienne Carriere 	}
2440ee3f52eSEtienne Carriere 
2450ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
2460ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
2470ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
2480ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
2490ee3f52eSEtienne Carriere 
2500ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
2510ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
2520ee3f52eSEtienne Carriere }
2530ee3f52eSEtienne Carriere 
2540ee3f52eSEtienne Carriere void gic_init(paddr_t gicc_base_pa, paddr_t gicd_base_pa)
2550ee3f52eSEtienne Carriere {
2560ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
2570ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
258b0104773SPascal Brand 
25967e55c51SEtienne Carriere 	gic_init_base_addr(gicc_base_pa, gicd_base_pa);
260b0104773SPascal Brand 
2610ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
2620ee3f52eSEtienne Carriere #ifndef CFG_WITH_ARM_TRUSTED_FW
2637315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
264b0104773SPascal Brand 		/* Disable interrupts */
265918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
266b0104773SPascal Brand 
267b0104773SPascal Brand 		/* Make interrupts non-pending */
268918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
269b0104773SPascal Brand 
270b0104773SPascal Brand 		/* Mark interrupts non-secure */
271bedc2b9fSsunny 		if (n == 0) {
272bedc2b9fSsunny 			/* per-CPU inerrupts config:
273bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
274bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
275bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
276bedc2b9fSsunny 			 */
277918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff);
278bedc2b9fSsunny 		} else {
279918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
280b0104773SPascal Brand 		}
281bedc2b9fSsunny 	}
282b0104773SPascal Brand 
28330a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
28430a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
28530a673e3SPeter Maydell 	 */
28618901324SDavid Wang #if defined(CFG_ARM_GICV3)
28718901324SDavid Wang 	write_icc_pmr(0x80);
2881fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
2891fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
29018901324SDavid Wang #else
291918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
29230a673e3SPeter Maydell 
293b0104773SPascal Brand 	/* Enable GIC */
294918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
295918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
296918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
297918bb3a5SEtienne Carriere 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1);
2981fcac774SSandeep Tripathy #endif
2990ee3f52eSEtienne Carriere #endif /*CFG_WITH_ARM_TRUSTED_FW*/
30067e55c51SEtienne Carriere 
30101980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
302b0104773SPascal Brand }
303b0104773SPascal Brand 
3047315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
305b0104773SPascal Brand {
30653bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
30753bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
308b0104773SPascal Brand 
30967e55c51SEtienne Carriere 	assert(gd == &gic_data);
31067e55c51SEtienne Carriere 
311b0104773SPascal Brand 	/* Disable the interrupt */
312918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
313b0104773SPascal Brand 	/* Make it non-pending */
314918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
315b0104773SPascal Brand 	/* Assign it to group0 */
316918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
3171fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
3181fcac774SSandeep Tripathy 	/* Assign it to group1S */
3191fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
3201fcac774SSandeep Tripathy #endif
321b0104773SPascal Brand }
322b0104773SPascal Brand 
3237315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
3247315b7b4SJens Wiklander 				uint8_t cpu_mask)
325b0104773SPascal Brand {
3268ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
3278ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
32853bd332aSSY Chiu 	uint32_t target, target_shift;
329918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
330918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
331b0104773SPascal Brand 
33267e55c51SEtienne Carriere 	assert(gd == &gic_data);
33367e55c51SEtienne Carriere 
334b0104773SPascal Brand 	/* Assigned to group0 */
335918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
336b0104773SPascal Brand 
337b0104773SPascal Brand 	/* Route it to selected CPUs */
338918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
33953bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
34053bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
34153bd332aSSY Chiu 	target |= cpu_mask << target_shift;
342918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
343918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
344918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
345b0104773SPascal Brand }
346b0104773SPascal Brand 
3477315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
348b0104773SPascal Brand {
3498ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
3508ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
351b0104773SPascal Brand 
35267e55c51SEtienne Carriere 	assert(gd == &gic_data);
35367e55c51SEtienne Carriere 
354b0104773SPascal Brand 	/* Assigned to group0 */
355918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
356b0104773SPascal Brand 
357b0104773SPascal Brand 	/* Set prio it to selected CPUs */
3581f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
3597315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
360918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
361b0104773SPascal Brand }
362b0104773SPascal Brand 
3637315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
364b0104773SPascal Brand {
36553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
36653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
367918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
368b0104773SPascal Brand 
36967e55c51SEtienne Carriere 	assert(gd == &gic_data);
37067e55c51SEtienne Carriere 
371b0104773SPascal Brand 	/* Assigned to group0 */
372918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
373b0104773SPascal Brand 
374b0104773SPascal Brand 	/* Enable the interrupt */
375918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
376b0104773SPascal Brand }
377b0104773SPascal Brand 
3787315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
379b0104773SPascal Brand {
38053bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
38153bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
382b0104773SPascal Brand 
38367e55c51SEtienne Carriere 	assert(gd == &gic_data);
38467e55c51SEtienne Carriere 
385b0104773SPascal Brand 	/* Assigned to group0 */
386918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
387b0104773SPascal Brand 
388b0104773SPascal Brand 	/* Disable the interrupt */
389918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
390b0104773SPascal Brand }
391b0104773SPascal Brand 
39226ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
39326ed70ecSGuanchao Liang {
39426ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
39526ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
39626ed70ecSGuanchao Liang 
39767e55c51SEtienne Carriere 	assert(gd == &gic_data);
39867e55c51SEtienne Carriere 
39926ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
40026ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
40126ed70ecSGuanchao Liang 
40226ed70ecSGuanchao Liang 	/* Raise the interrupt */
403918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
40426ed70ecSGuanchao Liang }
40526ed70ecSGuanchao Liang 
406ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
407ec740b9fSJens Wiklander {
408ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
409ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
410ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
411ec740b9fSJens Wiklander 
412ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
413ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
414ec740b9fSJens Wiklander }
415ec740b9fSJens Wiklander 
41654739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
417ec740b9fSJens Wiklander 			     uint32_t cpu_mask, uint8_t group)
41826ed70ecSGuanchao Liang {
41954739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
42054739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
421ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
422ec740b9fSJens Wiklander 
423ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
424ec740b9fSJens Wiklander 
425ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
426ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
427ec740b9fSJens Wiklander 	} else {
42854739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
429ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
430ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
431ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
432ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
433ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
434ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
435ec740b9fSJens Wiklander 
436ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
437ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
438ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
439ec740b9fSJens Wiklander 
440ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
441ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
442ec740b9fSJens Wiklander 		} else {
443ec740b9fSJens Wiklander 			/*
444ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
445ec740b9fSJens Wiklander 			 * same cluster now.
446ec740b9fSJens Wiklander 			 */
447ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
448ec740b9fSJens Wiklander 		}
449ec740b9fSJens Wiklander 	}
45054739cb4SMark-PK Tsai 
45154739cb4SMark-PK Tsai 	/* Raise the interrupt */
45254739cb4SMark-PK Tsai 	if (group)
45354739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
45454739cb4SMark-PK Tsai 	else
45554739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
45654739cb4SMark-PK Tsai #else
457ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
45826ed70ecSGuanchao Liang 	uint32_t mask_group = group & 0x1;
459ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
460ec740b9fSJens Wiklander 
461ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
462ec740b9fSJens Wiklander 
463ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
464ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
465ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
466ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
467ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
468ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
469ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
470ec740b9fSJens Wiklander 	} else {
471ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
472ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
473ec740b9fSJens Wiklander 	}
47426ed70ecSGuanchao Liang 
47526ed70ecSGuanchao Liang 	/* Raise the interrupt */
476918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
47754739cb4SMark-PK Tsai #endif
47826ed70ecSGuanchao Liang }
47926ed70ecSGuanchao Liang 
48018901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
481b0104773SPascal Brand {
48267e55c51SEtienne Carriere 	assert(gd == &gic_data);
48367e55c51SEtienne Carriere 
48418901324SDavid Wang #if defined(CFG_ARM_GICV3)
4851de462e1SSumit Garg 	return read_icc_iar1();
48618901324SDavid Wang #else
487918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
48818901324SDavid Wang #endif
489b0104773SPascal Brand }
490b0104773SPascal Brand 
49118901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
492b0104773SPascal Brand {
49367e55c51SEtienne Carriere 	assert(gd == &gic_data);
49467e55c51SEtienne Carriere 
49518901324SDavid Wang #if defined(CFG_ARM_GICV3)
4961de462e1SSumit Garg 	write_icc_eoir1(eoir);
49718901324SDavid Wang #else
498918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
49918901324SDavid Wang #endif
500b0104773SPascal Brand }
501b0104773SPascal Brand 
5027315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
5037315b7b4SJens Wiklander {
50453bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
50553bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
50667e55c51SEtienne Carriere 
50767e55c51SEtienne Carriere 	assert(gd == &gic_data);
508918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
50953bd332aSSY Chiu }
51053bd332aSSY Chiu 
5117315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
5127315b7b4SJens Wiklander {
51353bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
51453bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
51567e55c51SEtienne Carriere 
51667e55c51SEtienne Carriere 	assert(gd == &gic_data);
517918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
51853bd332aSSY Chiu }
51953bd332aSSY Chiu 
5207315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
5217315b7b4SJens Wiklander {
52253bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
5237315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
5247315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
52553bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
526918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
5277315b7b4SJens Wiklander 
52867e55c51SEtienne Carriere 	assert(gd == &gic_data);
529918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
53053bd332aSSY Chiu }
53153bd332aSSY Chiu 
53267e55c51SEtienne Carriere void gic_dump_state(void)
53353bd332aSSY Chiu {
53467e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
53567e55c51SEtienne Carriere 	int i = 0;
53653bd332aSSY Chiu 
53718901324SDavid Wang #if defined(CFG_ARM_GICV3)
53818901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
53918901324SDavid Wang #else
540918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
54118901324SDavid Wang #endif
542918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
5437315b7b4SJens Wiklander 
5444a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
5457315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
54653bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
5477315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
54853bd332aSSY Chiu 		}
54953bd332aSSY Chiu 	}
55053bd332aSSY Chiu }
5517315b7b4SJens Wiklander 
55267e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
5537315b7b4SJens Wiklander {
55467e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
55567e55c51SEtienne Carriere 	uint32_t iar = 0;
55667e55c51SEtienne Carriere 	uint32_t id = 0;
5577315b7b4SJens Wiklander 
5587315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
5597315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
5607315b7b4SJens Wiklander 
5614a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
56299e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
5633b3a4611SMathieu Briand 	else
5643b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
5657315b7b4SJens Wiklander 
5667315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
5677315b7b4SJens Wiklander }
5687315b7b4SJens Wiklander 
56967e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
570358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
571358bf47cSEtienne Carriere void interrupt_main_handler(void)
57267e55c51SEtienne Carriere {
57367e55c51SEtienne Carriere 	gic_native_itr_handler();
57467e55c51SEtienne Carriere }
57567e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
57667e55c51SEtienne Carriere 
5777315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
578702fe5a7SClément Léger 		       uint32_t type __unused,
579702fe5a7SClément Léger 		       uint32_t prio __unused)
5807315b7b4SJens Wiklander {
5817315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
5827315b7b4SJens Wiklander 
58367e55c51SEtienne Carriere 	assert(gd == &gic_data);
58467e55c51SEtienne Carriere 
5854a9ea08cSFangsuo Wu 	if (it > gd->max_it)
586d13278b8SEtienne Carriere 		panic();
587d13278b8SEtienne Carriere 
5887315b7b4SJens Wiklander 	gic_it_add(gd, it);
5897315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
5907315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
5917315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
5927315b7b4SJens Wiklander }
5937315b7b4SJens Wiklander 
5947315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
5957315b7b4SJens Wiklander {
5967315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
5977315b7b4SJens Wiklander 
59867e55c51SEtienne Carriere 	assert(gd == &gic_data);
59967e55c51SEtienne Carriere 
6004a9ea08cSFangsuo Wu 	if (it > gd->max_it)
601d13278b8SEtienne Carriere 		panic();
602d13278b8SEtienne Carriere 
6037315b7b4SJens Wiklander 	gic_it_enable(gd, it);
6047315b7b4SJens Wiklander }
6057315b7b4SJens Wiklander 
6067315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
6077315b7b4SJens Wiklander {
6087315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
6097315b7b4SJens Wiklander 
61067e55c51SEtienne Carriere 	assert(gd == &gic_data);
61167e55c51SEtienne Carriere 
6124a9ea08cSFangsuo Wu 	if (it > gd->max_it)
613d13278b8SEtienne Carriere 		panic();
614d13278b8SEtienne Carriere 
6157315b7b4SJens Wiklander 	gic_it_disable(gd, it);
6167315b7b4SJens Wiklander }
61726ed70ecSGuanchao Liang 
61826ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
61926ed70ecSGuanchao Liang {
62026ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
62126ed70ecSGuanchao Liang 
62267e55c51SEtienne Carriere 	assert(gd == &gic_data);
62367e55c51SEtienne Carriere 
6244a9ea08cSFangsuo Wu 	if (it > gd->max_it)
62526ed70ecSGuanchao Liang 		panic();
62626ed70ecSGuanchao Liang 
62726ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
62826ed70ecSGuanchao Liang }
62926ed70ecSGuanchao Liang 
63026ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
631ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
63226ed70ecSGuanchao Liang {
63326ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
63426ed70ecSGuanchao Liang 
63567e55c51SEtienne Carriere 	assert(gd == &gic_data);
63667e55c51SEtienne Carriere 
63754739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
63854739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
63954739cb4SMark-PK Tsai 
6404a9ea08cSFangsuo Wu 	if (it > gd->max_it)
64126ed70ecSGuanchao Liang 		panic();
64226ed70ecSGuanchao Liang 
64326ed70ecSGuanchao Liang 	if (it < NUM_NS_SGI)
64426ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 1);
64526ed70ecSGuanchao Liang 	else
64626ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 0);
64726ed70ecSGuanchao Liang }
64867e55c51SEtienne Carriere 
64926ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
65026ed70ecSGuanchao Liang 			uint8_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 
6564a9ea08cSFangsuo Wu 	if (it > gd->max_it)
65726ed70ecSGuanchao Liang 		panic();
65826ed70ecSGuanchao Liang 
65926ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
66026ed70ecSGuanchao Liang }
66114885eb1SEtienne Carriere 
66214885eb1SEtienne Carriere #ifdef CFG_DT
66314885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
66414885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
66514885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
66614885eb1SEtienne Carriere {
66714885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
66814885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
66914885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
67014885eb1SEtienne Carriere 	uint32_t type = 0;
67114885eb1SEtienne Carriere 	uint32_t prio = 0;
67214885eb1SEtienne Carriere 
67314885eb1SEtienne Carriere 	assert(arg && itr_desc);
67414885eb1SEtienne Carriere 
67514885eb1SEtienne Carriere 	/*
67614885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
67714885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
67814885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
67914885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
68014885eb1SEtienne Carriere 	 */
68114885eb1SEtienne Carriere 	if (arg->args_count < 2)
68214885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
68314885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
68414885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
68514885eb1SEtienne Carriere 
68614885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
68714885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
68814885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
68914885eb1SEtienne Carriere 
69014885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
69114885eb1SEtienne Carriere 
69214885eb1SEtienne Carriere 	itr_desc->chip = chip;
69314885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
69414885eb1SEtienne Carriere 
69514885eb1SEtienne Carriere 	return TEE_SUCCESS;
69614885eb1SEtienne Carriere }
69714885eb1SEtienne Carriere 
69814885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
69914885eb1SEtienne Carriere {
70014885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
70114885eb1SEtienne Carriere 					&gic_data.chip))
70214885eb1SEtienne Carriere 		panic();
70314885eb1SEtienne Carriere 
70414885eb1SEtienne Carriere 	return TEE_SUCCESS;
70514885eb1SEtienne Carriere }
70614885eb1SEtienne Carriere 
70714885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
70814885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
70914885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
71014885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
71114885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
71214885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
71314885eb1SEtienne Carriere 	{ }
71414885eb1SEtienne Carriere };
71514885eb1SEtienne Carriere 
71614885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
71714885eb1SEtienne Carriere 	.name = "gic",
71814885eb1SEtienne Carriere 	.match_table = gic_match_table,
71914885eb1SEtienne Carriere 	.probe = gic_probe,
72014885eb1SEtienne Carriere };
72114885eb1SEtienne Carriere #endif /*CFG_DT*/
722