xref: /optee_os/core/drivers/gic.c (revision 14885eb1688bb0826c53522d4c3d99ef9c461f25)
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>
967729d8dSLudovic Barre #include <config.h>
1067e55c51SEtienne Carriere #include <compiler.h>
11b0104773SPascal Brand #include <drivers/gic.h>
120f93de74SEtienne Carriere #include <keep.h>
1367729d8dSLudovic Barre #include <kernel/dt.h>
14*14885eb1SEtienne Carriere #include <kernel/dt_driver.h>
157315b7b4SJens Wiklander #include <kernel/interrupt.h>
16d13278b8SEtienne Carriere #include <kernel/panic.h>
1760801696SVolodymyr Babchuk #include <mm/core_memprot.h>
1860801696SVolodymyr Babchuk #include <mm/core_mmu.h>
1967729d8dSLudovic Barre #include <libfdt.h>
207315b7b4SJens Wiklander #include <util.h>
21b0104773SPascal Brand #include <io.h>
224de4bebcSJens Wiklander #include <trace.h>
23b0104773SPascal Brand 
24b0104773SPascal Brand /* Offsets from gic.gicc_base */
25b0104773SPascal Brand #define GICC_CTLR		(0x000)
2630a673e3SPeter Maydell #define GICC_PMR		(0x004)
27b0104773SPascal Brand #define GICC_IAR		(0x00C)
28b0104773SPascal Brand #define GICC_EOIR		(0x010)
29b0104773SPascal Brand 
30b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0	(1 << 0)
31b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1	(1 << 1)
321fcac774SSandeep Tripathy #define GICD_CTLR_ENABLEGRP1S	(1 << 2)
33b0104773SPascal Brand #define GICC_CTLR_FIQEN		(1 << 3)
34b0104773SPascal Brand 
35b0104773SPascal Brand /* Offsets from gic.gicd_base */
36b0104773SPascal Brand #define GICD_CTLR		(0x000)
37b0104773SPascal Brand #define GICD_TYPER		(0x004)
38b0104773SPascal Brand #define GICD_IGROUPR(n)		(0x080 + (n) * 4)
39b0104773SPascal Brand #define GICD_ISENABLER(n)	(0x100 + (n) * 4)
40b0104773SPascal Brand #define GICD_ICENABLER(n)	(0x180 + (n) * 4)
4126ed70ecSGuanchao Liang #define GICD_ISPENDR(n)		(0x200 + (n) * 4)
42b0104773SPascal Brand #define GICD_ICPENDR(n)		(0x280 + (n) * 4)
43b0104773SPascal Brand #define GICD_IPRIORITYR(n)	(0x400 + (n) * 4)
44b0104773SPascal Brand #define GICD_ITARGETSR(n)	(0x800 + (n) * 4)
451fcac774SSandeep Tripathy #define GICD_IGROUPMODR(n)	(0xd00 + (n) * 4)
4626ed70ecSGuanchao Liang #define GICD_SGIR		(0xF00)
47b0104773SPascal Brand 
48b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0	(1 << 0)
49b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1	(1 << 1)
50b0104773SPascal Brand 
5153bd332aSSY Chiu /* Number of Private Peripheral Interrupt */
5253bd332aSSY Chiu #define NUM_PPI	32
5353bd332aSSY Chiu 
5426ed70ecSGuanchao Liang /* Number of Software Generated Interrupt */
5526ed70ecSGuanchao Liang #define NUM_SGI			16
5626ed70ecSGuanchao Liang 
5726ed70ecSGuanchao Liang /* Number of Non-secure Software Generated Interrupt */
5826ed70ecSGuanchao Liang #define NUM_NS_SGI		8
5926ed70ecSGuanchao Liang 
6053bd332aSSY Chiu /* Number of interrupts in one register */
6153bd332aSSY Chiu #define NUM_INTS_PER_REG	32
6253bd332aSSY Chiu 
6353bd332aSSY Chiu /* Number of targets in one register */
6453bd332aSSY Chiu #define NUM_TARGETS_PER_REG	4
6553bd332aSSY Chiu 
6653bd332aSSY Chiu /* Accessors to access ITARGETSRn */
6753bd332aSSY Chiu #define ITARGETSR_FIELD_BITS	8
6853bd332aSSY Chiu #define ITARGETSR_FIELD_MASK	0xff
6953bd332aSSY Chiu 
701b4c5002SIzhar Nevo #define GICD_TYPER_IT_LINES_NUM_MASK	0x1f
717315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
727315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
737315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
74b0104773SPascal Brand 
75ec740b9fSJens Wiklander #define GICC_SGI_IRM_BIT	40
76ec740b9fSJens Wiklander #define GICC_SGI_AFF1_SHIFT	16
77ec740b9fSJens Wiklander #define GICC_SGI_AFF2_SHIFT	32
78ec740b9fSJens Wiklander #define GICC_SGI_AFF3_SHIFT	48
79ec740b9fSJens Wiklander 
80ec740b9fSJens Wiklander #define GICD_SGIR_SIGINTID_MASK			0xf
81ec740b9fSJens Wiklander #define GICD_SGIR_TO_OTHER_CPUS			0x1
82ec740b9fSJens Wiklander #define GICD_SGIR_TO_THIS_CPU			0x2
83ec740b9fSJens Wiklander #define GICD_SGIR_TARGET_LIST_FILTER_SHIFT	24
84ec740b9fSJens Wiklander #define GICD_SGIR_NSATT_SHIFT			15
85ec740b9fSJens Wiklander #define GICD_SGIR_CPU_TARGET_LIST_SHIFT		16
86ec740b9fSJens Wiklander 
8767e55c51SEtienne Carriere struct gic_data {
8867e55c51SEtienne Carriere 	vaddr_t gicc_base;
8967e55c51SEtienne Carriere 	vaddr_t gicd_base;
9067e55c51SEtienne Carriere 	size_t max_it;
9167e55c51SEtienne Carriere 	struct itr_chip chip;
9267e55c51SEtienne Carriere };
9367e55c51SEtienne Carriere 
9467e55c51SEtienne Carriere static struct gic_data gic_data __nex_bss;
9567e55c51SEtienne Carriere 
96702fe5a7SClément Léger static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t type,
97702fe5a7SClément Léger 		       uint32_t prio);
987315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
997315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
10026ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
10126ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
102ec740b9fSJens Wiklander 			     uint32_t cpu_mask);
10326ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
10426ed70ecSGuanchao Liang 			uint8_t cpu_mask);
1057315b7b4SJens Wiklander 
1067315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
1077315b7b4SJens Wiklander 	.add = gic_op_add,
10808ded0e1SEtienne Carriere 	.mask = gic_op_disable,
10908ded0e1SEtienne Carriere 	.unmask = gic_op_enable,
1107315b7b4SJens Wiklander 	.enable = gic_op_enable,
1117315b7b4SJens Wiklander 	.disable = gic_op_disable,
11226ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
11326ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
11426ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1157315b7b4SJens Wiklander };
1163639b55fSJerome Forissier DECLARE_KEEP_PAGER(gic_ops);
1177315b7b4SJens Wiklander 
11818901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
119b0104773SPascal Brand {
120b0104773SPascal Brand 	int i;
121b0104773SPascal Brand 	uint32_t old_ctlr;
122b0104773SPascal Brand 	size_t ret = 0;
1231b4c5002SIzhar Nevo 	size_t max_regs = io_read32(gicd_base + GICD_TYPER) &
1241b4c5002SIzhar Nevo 			  GICD_TYPER_IT_LINES_NUM_MASK;
125b0104773SPascal Brand 
126b0104773SPascal Brand 	/*
127b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
128b0104773SPascal Brand 	 */
12918901324SDavid Wang #if defined(CFG_ARM_GICV3)
13018901324SDavid Wang 	old_ctlr = read_icc_ctlr();
13118901324SDavid Wang 	write_icc_ctlr(0);
13218901324SDavid Wang #else
133918bb3a5SEtienne Carriere 	old_ctlr = io_read32(gicc_base + GICC_CTLR);
134918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, 0);
13518901324SDavid Wang #endif
13679f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
137b0104773SPascal Brand 		uint32_t old_reg;
138b0104773SPascal Brand 		uint32_t reg;
139b0104773SPascal Brand 		int b;
140b0104773SPascal Brand 
141918bb3a5SEtienne Carriere 		old_reg = io_read32(gicd_base + GICD_ISENABLER(i));
142918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ISENABLER(i), 0xffffffff);
143918bb3a5SEtienne Carriere 		reg = io_read32(gicd_base + GICD_ISENABLER(i));
144918bb3a5SEtienne Carriere 		io_write32(gicd_base + GICD_ICENABLER(i), ~old_reg);
14579f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
146007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
14753bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
148b0104773SPascal Brand 				goto out;
149b0104773SPascal Brand 			}
150b0104773SPascal Brand 		}
151b0104773SPascal Brand 	}
152b0104773SPascal Brand out:
15318901324SDavid Wang #if defined(CFG_ARM_GICV3)
15418901324SDavid Wang 	write_icc_ctlr(old_ctlr);
15518901324SDavid Wang #else
156918bb3a5SEtienne Carriere 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
15718901324SDavid Wang #endif
158b0104773SPascal Brand 	return ret;
159b0104773SPascal Brand }
160b0104773SPascal Brand 
16167e55c51SEtienne Carriere void gic_cpu_init(void)
162bedc2b9fSsunny {
16367e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
16467e55c51SEtienne Carriere 
16518901324SDavid Wang #if defined(CFG_ARM_GICV3)
16618901324SDavid Wang 	assert(gd->gicd_base);
16718901324SDavid Wang #else
16805efe1e1SEtienne Carriere 	assert(gd->gicd_base && gd->gicc_base);
16918901324SDavid Wang #endif
17005efe1e1SEtienne Carriere 
171e06e6e74SPeter Maydell 	/* per-CPU interrupts config:
172bedc2b9fSsunny 	 * ID0-ID7(SGI)   for Non-secure interrupts
173bedc2b9fSsunny 	 * ID8-ID15(SGI)  for Secure interrupts.
174bedc2b9fSsunny 	 * All PPI config as Non-secure interrupts.
175bedc2b9fSsunny 	 */
176918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_IGROUPR(0), 0xffff00ff);
177bedc2b9fSsunny 
17830a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
17930a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
18030a673e3SPeter Maydell 	 */
18118901324SDavid Wang #if defined(CFG_ARM_GICV3)
18218901324SDavid Wang 	write_icc_pmr(0x80);
1831fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
18418901324SDavid Wang #else
185918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
18630a673e3SPeter Maydell 
187bedc2b9fSsunny 	/* Enable GIC */
188918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR,
189918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
190918bb3a5SEtienne Carriere 		   GICC_CTLR_FIQEN);
19118901324SDavid Wang #endif
192bedc2b9fSsunny }
193bedc2b9fSsunny 
1940ee3f52eSEtienne Carriere static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
1950ee3f52eSEtienne Carriere 			  uint32_t *prio)
1960ee3f52eSEtienne Carriere {
1970ee3f52eSEtienne Carriere 	int it_num = DT_INFO_INVALID_INTERRUPT;
1980ee3f52eSEtienne Carriere 
1990ee3f52eSEtienne Carriere 	if (type)
2000ee3f52eSEtienne Carriere 		*type = IRQ_TYPE_NONE;
2010ee3f52eSEtienne Carriere 
2020ee3f52eSEtienne Carriere 	if (prio)
2030ee3f52eSEtienne Carriere 		*prio = 0;
2040ee3f52eSEtienne Carriere 
2050ee3f52eSEtienne Carriere 	if (!properties || count < 2)
2060ee3f52eSEtienne Carriere 		return DT_INFO_INVALID_INTERRUPT;
2070ee3f52eSEtienne Carriere 
2080ee3f52eSEtienne Carriere 	it_num = fdt32_to_cpu(properties[1]);
2090ee3f52eSEtienne Carriere 
2100ee3f52eSEtienne Carriere 	switch (fdt32_to_cpu(properties[0])) {
2110ee3f52eSEtienne Carriere 	case 1:
2120ee3f52eSEtienne Carriere 		it_num += 16;
2130ee3f52eSEtienne Carriere 		break;
2140ee3f52eSEtienne Carriere 	case 0:
2150ee3f52eSEtienne Carriere 		it_num += 32;
2160ee3f52eSEtienne Carriere 		break;
2170ee3f52eSEtienne Carriere 	default:
2180ee3f52eSEtienne Carriere 		it_num = DT_INFO_INVALID_INTERRUPT;
2190ee3f52eSEtienne Carriere 	}
2200ee3f52eSEtienne Carriere 
2210ee3f52eSEtienne Carriere 	return it_num;
2220ee3f52eSEtienne Carriere }
2230ee3f52eSEtienne Carriere 
2240ee3f52eSEtienne Carriere static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa)
225b0104773SPascal Brand {
22667e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
2270ee3f52eSEtienne Carriere 	vaddr_t gicc_base = 0;
2280ee3f52eSEtienne Carriere 	vaddr_t gicd_base = 0;
2290ee3f52eSEtienne Carriere 
2300ee3f52eSEtienne Carriere 	assert(cpu_mmu_enabled());
2310ee3f52eSEtienne Carriere 
2320ee3f52eSEtienne Carriere 	gicd_base = core_mmu_get_va(gicd_base_pa, MEM_AREA_IO_SEC,
2330ee3f52eSEtienne Carriere 				    GIC_DIST_REG_SIZE);
2340ee3f52eSEtienne Carriere 	if (!gicd_base)
2350ee3f52eSEtienne Carriere 		panic();
2360ee3f52eSEtienne Carriere 
2370ee3f52eSEtienne Carriere 	if (!IS_ENABLED(CFG_ARM_GICV3)) {
2380ee3f52eSEtienne Carriere 		gicc_base = core_mmu_get_va(gicc_base_pa, MEM_AREA_IO_SEC,
2390ee3f52eSEtienne Carriere 					    GIC_CPU_REG_SIZE);
2400ee3f52eSEtienne Carriere 		if (!gicc_base)
2410ee3f52eSEtienne Carriere 			panic();
2420ee3f52eSEtienne Carriere 	}
2430ee3f52eSEtienne Carriere 
2440ee3f52eSEtienne Carriere 	gd->gicc_base = gicc_base;
2450ee3f52eSEtienne Carriere 	gd->gicd_base = gicd_base;
2460ee3f52eSEtienne Carriere 	gd->max_it = probe_max_it(gicc_base, gicd_base);
2470ee3f52eSEtienne Carriere 	gd->chip.ops = &gic_ops;
2480ee3f52eSEtienne Carriere 
2490ee3f52eSEtienne Carriere 	if (IS_ENABLED(CFG_DT))
2500ee3f52eSEtienne Carriere 		gd->chip.dt_get_irq = gic_dt_get_irq;
2510ee3f52eSEtienne Carriere }
2520ee3f52eSEtienne Carriere 
2530ee3f52eSEtienne Carriere void gic_init(paddr_t gicc_base_pa, paddr_t gicd_base_pa)
2540ee3f52eSEtienne Carriere {
2550ee3f52eSEtienne Carriere 	struct gic_data __maybe_unused *gd = &gic_data;
2560ee3f52eSEtienne Carriere 	size_t __maybe_unused n = 0;
257b0104773SPascal Brand 
25867e55c51SEtienne Carriere 	gic_init_base_addr(gicc_base_pa, gicd_base_pa);
259b0104773SPascal Brand 
2600ee3f52eSEtienne Carriere 	/* GIC configuration is initialized from TF-A when embedded */
2610ee3f52eSEtienne Carriere #ifndef CFG_WITH_ARM_TRUSTED_FW
2627315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
263b0104773SPascal Brand 		/* Disable interrupts */
264918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICENABLER(n), 0xffffffff);
265b0104773SPascal Brand 
266b0104773SPascal Brand 		/* Make interrupts non-pending */
267918bb3a5SEtienne Carriere 		io_write32(gd->gicd_base + GICD_ICPENDR(n), 0xffffffff);
268b0104773SPascal Brand 
269b0104773SPascal Brand 		/* Mark interrupts non-secure */
270bedc2b9fSsunny 		if (n == 0) {
271bedc2b9fSsunny 			/* per-CPU inerrupts config:
272bedc2b9fSsunny 			 * ID0-ID7(SGI)	  for Non-secure interrupts
273bedc2b9fSsunny 			 * ID8-ID15(SGI)  for Secure interrupts.
274bedc2b9fSsunny 			 * All PPI config as Non-secure interrupts.
275bedc2b9fSsunny 			 */
276918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffff00ff);
277bedc2b9fSsunny 		} else {
278918bb3a5SEtienne Carriere 			io_write32(gd->gicd_base + GICD_IGROUPR(n), 0xffffffff);
279b0104773SPascal Brand 		}
280bedc2b9fSsunny 	}
281b0104773SPascal Brand 
28230a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
28330a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
28430a673e3SPeter Maydell 	 */
28518901324SDavid Wang #if defined(CFG_ARM_GICV3)
28618901324SDavid Wang 	write_icc_pmr(0x80);
2871fcac774SSandeep Tripathy 	write_icc_igrpen1(1);
2881fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
28918901324SDavid Wang #else
290918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_PMR, 0x80);
29130a673e3SPeter Maydell 
292b0104773SPascal Brand 	/* Enable GIC */
293918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_CTLR, GICC_CTLR_FIQEN |
294918bb3a5SEtienne Carriere 		   GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1);
295918bb3a5SEtienne Carriere 	io_setbits32(gd->gicd_base + GICD_CTLR,
296918bb3a5SEtienne Carriere 		     GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1);
2971fcac774SSandeep Tripathy #endif
2980ee3f52eSEtienne Carriere #endif /*CFG_WITH_ARM_TRUSTED_FW*/
29967e55c51SEtienne Carriere 
30001980f3fSEtienne Carriere 	interrupt_main_init(&gic_data.chip);
301b0104773SPascal Brand }
302b0104773SPascal Brand 
3037315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
304b0104773SPascal Brand {
30553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
30653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
307b0104773SPascal Brand 
30867e55c51SEtienne Carriere 	assert(gd == &gic_data);
30967e55c51SEtienne Carriere 
310b0104773SPascal Brand 	/* Disable the interrupt */
311918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
312b0104773SPascal Brand 	/* Make it non-pending */
313918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
314b0104773SPascal Brand 	/* Assign it to group0 */
315918bb3a5SEtienne Carriere 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
3161fcac774SSandeep Tripathy #if defined(CFG_ARM_GICV3)
3171fcac774SSandeep Tripathy 	/* Assign it to group1S */
3181fcac774SSandeep Tripathy 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
3191fcac774SSandeep Tripathy #endif
320b0104773SPascal Brand }
321b0104773SPascal Brand 
3227315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
3237315b7b4SJens Wiklander 				uint8_t cpu_mask)
324b0104773SPascal Brand {
3258ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
3268ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
32753bd332aSSY Chiu 	uint32_t target, target_shift;
328918bb3a5SEtienne Carriere 	vaddr_t itargetsr = gd->gicd_base +
329918bb3a5SEtienne Carriere 			    GICD_ITARGETSR(it / NUM_TARGETS_PER_REG);
330b0104773SPascal Brand 
33167e55c51SEtienne Carriere 	assert(gd == &gic_data);
33267e55c51SEtienne Carriere 
333b0104773SPascal Brand 	/* Assigned to group0 */
334918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
335b0104773SPascal Brand 
336b0104773SPascal Brand 	/* Route it to selected CPUs */
337918bb3a5SEtienne Carriere 	target = io_read32(itargetsr);
33853bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
33953bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
34053bd332aSSY Chiu 	target |= cpu_mask << target_shift;
341918bb3a5SEtienne Carriere 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA, target, itargetsr);
342918bb3a5SEtienne Carriere 	io_write32(itargetsr, target);
343918bb3a5SEtienne Carriere 	DMSG("cpu_mask: 0x%x", io_read32(itargetsr));
344b0104773SPascal Brand }
345b0104773SPascal Brand 
3467315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
347b0104773SPascal Brand {
3488ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
3498ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_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 	/* Set prio it to selected CPUs */
3571f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
3587315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
359918bb3a5SEtienne Carriere 	io_write8(gd->gicd_base + GICD_IPRIORITYR(0) + it, prio);
360b0104773SPascal Brand }
361b0104773SPascal Brand 
3627315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
363b0104773SPascal Brand {
36453bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
36553bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
366918bb3a5SEtienne Carriere 	vaddr_t base = gd->gicd_base;
367b0104773SPascal Brand 
36867e55c51SEtienne Carriere 	assert(gd == &gic_data);
36967e55c51SEtienne Carriere 
370b0104773SPascal Brand 	/* Assigned to group0 */
371918bb3a5SEtienne Carriere 	assert(!(io_read32(base + GICD_IGROUPR(idx)) & mask));
372b0104773SPascal Brand 
373b0104773SPascal Brand 	/* Enable the interrupt */
374918bb3a5SEtienne Carriere 	io_write32(base + GICD_ISENABLER(idx), mask);
375b0104773SPascal Brand }
376b0104773SPascal Brand 
3777315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
378b0104773SPascal Brand {
37953bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
38053bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
381b0104773SPascal Brand 
38267e55c51SEtienne Carriere 	assert(gd == &gic_data);
38367e55c51SEtienne Carriere 
384b0104773SPascal Brand 	/* Assigned to group0 */
385918bb3a5SEtienne Carriere 	assert(!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
386b0104773SPascal Brand 
387b0104773SPascal Brand 	/* Disable the interrupt */
388918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ICENABLER(idx), mask);
389b0104773SPascal Brand }
390b0104773SPascal Brand 
39126ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
39226ed70ecSGuanchao Liang {
39326ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
39426ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
39526ed70ecSGuanchao Liang 
39667e55c51SEtienne Carriere 	assert(gd == &gic_data);
39767e55c51SEtienne Carriere 
39826ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
39926ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
40026ed70ecSGuanchao Liang 
40126ed70ecSGuanchao Liang 	/* Raise the interrupt */
402918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_ISPENDR(idx), mask);
40326ed70ecSGuanchao Liang }
40426ed70ecSGuanchao Liang 
405ec740b9fSJens Wiklander static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
406ec740b9fSJens Wiklander {
407ec740b9fSJens Wiklander 	bool __maybe_unused to_others = cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS;
408ec740b9fSJens Wiklander 	bool __maybe_unused to_current = cpu_mask & ITR_CPU_MASK_TO_THIS_CPU;
409ec740b9fSJens Wiklander 	bool __maybe_unused to_list = cpu_mask & 0xff;
410ec740b9fSJens Wiklander 
411ec740b9fSJens Wiklander 	/* One and only one of the bit fields shall be non-zero */
412ec740b9fSJens Wiklander 	assert(to_others + to_current + to_list == 1);
413ec740b9fSJens Wiklander }
414ec740b9fSJens Wiklander 
41554739cb4SMark-PK Tsai static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
416ec740b9fSJens Wiklander 			     uint32_t cpu_mask, uint8_t group)
41726ed70ecSGuanchao Liang {
41854739cb4SMark-PK Tsai #if defined(CFG_ARM_GICV3)
41954739cb4SMark-PK Tsai 	uint32_t mask_id = it & 0xf;
420ec740b9fSJens Wiklander 	uint64_t mask = SHIFT_U64(mask_id, 24);
421ec740b9fSJens Wiklander 
422ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
423ec740b9fSJens Wiklander 
424ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
425ec740b9fSJens Wiklander 		mask |= BIT64(GICC_SGI_IRM_BIT);
426ec740b9fSJens Wiklander 	} else {
42754739cb4SMark-PK Tsai 		uint64_t mpidr = read_mpidr();
428ec740b9fSJens Wiklander 		uint64_t mask_aff1 = (mpidr & MPIDR_AFF1_MASK) >>
429ec740b9fSJens Wiklander 				     MPIDR_AFF1_SHIFT;
430ec740b9fSJens Wiklander 		uint64_t mask_aff2 = (mpidr & MPIDR_AFF2_MASK) >>
431ec740b9fSJens Wiklander 				     MPIDR_AFF2_SHIFT;
432ec740b9fSJens Wiklander 		uint64_t mask_aff3 = (mpidr & MPIDR_AFF3_MASK) >>
433ec740b9fSJens Wiklander 				     MPIDR_AFF3_SHIFT;
434ec740b9fSJens Wiklander 
435ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff1, GICC_SGI_AFF1_SHIFT);
436ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff2, GICC_SGI_AFF2_SHIFT);
437ec740b9fSJens Wiklander 		mask |= SHIFT_U64(mask_aff3, GICC_SGI_AFF3_SHIFT);
438ec740b9fSJens Wiklander 
439ec740b9fSJens Wiklander 		if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
440ec740b9fSJens Wiklander 			mask |= BIT32(mpidr & 0xf);
441ec740b9fSJens Wiklander 		} else {
442ec740b9fSJens Wiklander 			/*
443ec740b9fSJens Wiklander 			 * Only support sending SGI to the cores in the
444ec740b9fSJens Wiklander 			 * same cluster now.
445ec740b9fSJens Wiklander 			 */
446ec740b9fSJens Wiklander 			mask |= cpu_mask & 0xff;
447ec740b9fSJens Wiklander 		}
448ec740b9fSJens Wiklander 	}
44954739cb4SMark-PK Tsai 
45054739cb4SMark-PK Tsai 	/* Raise the interrupt */
45154739cb4SMark-PK Tsai 	if (group)
45254739cb4SMark-PK Tsai 		write_icc_asgi1r(mask);
45354739cb4SMark-PK Tsai 	else
45454739cb4SMark-PK Tsai 		write_icc_sgi1r(mask);
45554739cb4SMark-PK Tsai #else
456ec740b9fSJens Wiklander 	uint32_t mask_id = it & GICD_SGIR_SIGINTID_MASK;
45726ed70ecSGuanchao Liang 	uint32_t mask_group = group & 0x1;
458ec740b9fSJens Wiklander 	uint32_t mask = mask_id;
459ec740b9fSJens Wiklander 
460ec740b9fSJens Wiklander 	assert_cpu_mask_is_valid(cpu_mask);
461ec740b9fSJens Wiklander 
462ec740b9fSJens Wiklander 	mask |= SHIFT_U32(mask_group, GICD_SGIR_NSATT_SHIFT);
463ec740b9fSJens Wiklander 	if (cpu_mask & ITR_CPU_MASK_TO_OTHER_CPUS) {
464ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_OTHER_CPUS,
465ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
466ec740b9fSJens Wiklander 	} else if (cpu_mask & ITR_CPU_MASK_TO_THIS_CPU) {
467ec740b9fSJens Wiklander 		mask |= SHIFT_U32(GICD_SGIR_TO_THIS_CPU,
468ec740b9fSJens Wiklander 				  GICD_SGIR_TARGET_LIST_FILTER_SHIFT);
469ec740b9fSJens Wiklander 	} else {
470ec740b9fSJens Wiklander 		mask |= SHIFT_U32(cpu_mask & 0xff,
471ec740b9fSJens Wiklander 				  GICD_SGIR_CPU_TARGET_LIST_SHIFT);
472ec740b9fSJens Wiklander 	}
47326ed70ecSGuanchao Liang 
47426ed70ecSGuanchao Liang 	/* Raise the interrupt */
475918bb3a5SEtienne Carriere 	io_write32(gd->gicd_base + GICD_SGIR, mask);
47654739cb4SMark-PK Tsai #endif
47726ed70ecSGuanchao Liang }
47826ed70ecSGuanchao Liang 
47918901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
480b0104773SPascal Brand {
48167e55c51SEtienne Carriere 	assert(gd == &gic_data);
48267e55c51SEtienne Carriere 
48318901324SDavid Wang #if defined(CFG_ARM_GICV3)
4841de462e1SSumit Garg 	return read_icc_iar1();
48518901324SDavid Wang #else
486918bb3a5SEtienne Carriere 	return io_read32(gd->gicc_base + GICC_IAR);
48718901324SDavid Wang #endif
488b0104773SPascal Brand }
489b0104773SPascal Brand 
49018901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
491b0104773SPascal Brand {
49267e55c51SEtienne Carriere 	assert(gd == &gic_data);
49367e55c51SEtienne Carriere 
49418901324SDavid Wang #if defined(CFG_ARM_GICV3)
4951de462e1SSumit Garg 	write_icc_eoir1(eoir);
49618901324SDavid Wang #else
497918bb3a5SEtienne Carriere 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
49818901324SDavid Wang #endif
499b0104773SPascal Brand }
500b0104773SPascal Brand 
5017315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
5027315b7b4SJens Wiklander {
50353bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
50453bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
50567e55c51SEtienne Carriere 
50667e55c51SEtienne Carriere 	assert(gd == &gic_data);
507918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
50853bd332aSSY Chiu }
50953bd332aSSY Chiu 
5107315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
5117315b7b4SJens Wiklander {
51253bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
51353bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
51467e55c51SEtienne Carriere 
51567e55c51SEtienne Carriere 	assert(gd == &gic_data);
516918bb3a5SEtienne Carriere 	return !!(io_read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
51753bd332aSSY Chiu }
51853bd332aSSY Chiu 
5197315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
5207315b7b4SJens Wiklander {
52153bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
5227315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
5237315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
52453bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
525918bb3a5SEtienne Carriere 	uint32_t target = io_read32(gd->gicd_base + GICD_ITARGETSR(reg_idx));
5267315b7b4SJens Wiklander 
52767e55c51SEtienne Carriere 	assert(gd == &gic_data);
528918bb3a5SEtienne Carriere 	return (target & target_mask) >> target_shift;
52953bd332aSSY Chiu }
53053bd332aSSY Chiu 
53167e55c51SEtienne Carriere void gic_dump_state(void)
53253bd332aSSY Chiu {
53367e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
53467e55c51SEtienne Carriere 	int i = 0;
53553bd332aSSY Chiu 
53618901324SDavid Wang #if defined(CFG_ARM_GICV3)
53718901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
53818901324SDavid Wang #else
539918bb3a5SEtienne Carriere 	DMSG("GICC_CTLR: 0x%x", io_read32(gd->gicc_base + GICC_CTLR));
54018901324SDavid Wang #endif
541918bb3a5SEtienne Carriere 	DMSG("GICD_CTLR: 0x%x", io_read32(gd->gicd_base + GICD_CTLR));
5427315b7b4SJens Wiklander 
5434a9ea08cSFangsuo Wu 	for (i = 0; i <= (int)gd->max_it; i++) {
5447315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
54553bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
5467315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
54753bd332aSSY Chiu 		}
54853bd332aSSY Chiu 	}
54953bd332aSSY Chiu }
5507315b7b4SJens Wiklander 
55167e55c51SEtienne Carriere static void __maybe_unused gic_native_itr_handler(void)
5527315b7b4SJens Wiklander {
55367e55c51SEtienne Carriere 	struct gic_data *gd = &gic_data;
55467e55c51SEtienne Carriere 	uint32_t iar = 0;
55567e55c51SEtienne Carriere 	uint32_t id = 0;
5567315b7b4SJens Wiklander 
5577315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
5587315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
5597315b7b4SJens Wiklander 
5604a9ea08cSFangsuo Wu 	if (id <= gd->max_it)
56199e2612cSEtienne Carriere 		interrupt_call_handlers(&gd->chip, id);
5623b3a4611SMathieu Briand 	else
5633b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
5647315b7b4SJens Wiklander 
5657315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
5667315b7b4SJens Wiklander }
5677315b7b4SJens Wiklander 
56867e55c51SEtienne Carriere #ifndef CFG_CORE_WORKAROUND_ARM_NMFI
569358bf47cSEtienne Carriere /* Override interrupt_main_handler() with driver implementation */
570358bf47cSEtienne Carriere void interrupt_main_handler(void)
57167e55c51SEtienne Carriere {
57267e55c51SEtienne Carriere 	gic_native_itr_handler();
57367e55c51SEtienne Carriere }
57467e55c51SEtienne Carriere #endif /*CFG_CORE_WORKAROUND_ARM_NMFI*/
57567e55c51SEtienne Carriere 
5767315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
577702fe5a7SClément Léger 		       uint32_t type __unused,
578702fe5a7SClément Léger 		       uint32_t prio __unused)
5797315b7b4SJens Wiklander {
5807315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
5817315b7b4SJens Wiklander 
58267e55c51SEtienne Carriere 	assert(gd == &gic_data);
58367e55c51SEtienne Carriere 
5844a9ea08cSFangsuo Wu 	if (it > gd->max_it)
585d13278b8SEtienne Carriere 		panic();
586d13278b8SEtienne Carriere 
5877315b7b4SJens Wiklander 	gic_it_add(gd, it);
5887315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
5897315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
5907315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
5917315b7b4SJens Wiklander }
5927315b7b4SJens Wiklander 
5937315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
5947315b7b4SJens Wiklander {
5957315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
5967315b7b4SJens Wiklander 
59767e55c51SEtienne Carriere 	assert(gd == &gic_data);
59867e55c51SEtienne Carriere 
5994a9ea08cSFangsuo Wu 	if (it > gd->max_it)
600d13278b8SEtienne Carriere 		panic();
601d13278b8SEtienne Carriere 
6027315b7b4SJens Wiklander 	gic_it_enable(gd, it);
6037315b7b4SJens Wiklander }
6047315b7b4SJens Wiklander 
6057315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
6067315b7b4SJens Wiklander {
6077315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
6087315b7b4SJens Wiklander 
60967e55c51SEtienne Carriere 	assert(gd == &gic_data);
61067e55c51SEtienne Carriere 
6114a9ea08cSFangsuo Wu 	if (it > gd->max_it)
612d13278b8SEtienne Carriere 		panic();
613d13278b8SEtienne Carriere 
6147315b7b4SJens Wiklander 	gic_it_disable(gd, it);
6157315b7b4SJens Wiklander }
61626ed70ecSGuanchao Liang 
61726ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
61826ed70ecSGuanchao Liang {
61926ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
62026ed70ecSGuanchao Liang 
62167e55c51SEtienne Carriere 	assert(gd == &gic_data);
62267e55c51SEtienne Carriere 
6234a9ea08cSFangsuo Wu 	if (it > gd->max_it)
62426ed70ecSGuanchao Liang 		panic();
62526ed70ecSGuanchao Liang 
62626ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
62726ed70ecSGuanchao Liang }
62826ed70ecSGuanchao Liang 
62926ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
630ec740b9fSJens Wiklander 			     uint32_t cpu_mask)
63126ed70ecSGuanchao Liang {
63226ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
63326ed70ecSGuanchao Liang 
63467e55c51SEtienne Carriere 	assert(gd == &gic_data);
63567e55c51SEtienne Carriere 
63654739cb4SMark-PK Tsai 	/* Should be Software Generated Interrupt */
63754739cb4SMark-PK Tsai 	assert(it < NUM_SGI);
63854739cb4SMark-PK Tsai 
6394a9ea08cSFangsuo Wu 	if (it > gd->max_it)
64026ed70ecSGuanchao Liang 		panic();
64126ed70ecSGuanchao Liang 
64226ed70ecSGuanchao Liang 	if (it < NUM_NS_SGI)
64326ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 1);
64426ed70ecSGuanchao Liang 	else
64526ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 0);
64626ed70ecSGuanchao Liang }
64767e55c51SEtienne Carriere 
64826ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
64926ed70ecSGuanchao Liang 			uint8_t cpu_mask)
65026ed70ecSGuanchao Liang {
65126ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
65226ed70ecSGuanchao Liang 
65367e55c51SEtienne Carriere 	assert(gd == &gic_data);
65467e55c51SEtienne Carriere 
6554a9ea08cSFangsuo Wu 	if (it > gd->max_it)
65626ed70ecSGuanchao Liang 		panic();
65726ed70ecSGuanchao Liang 
65826ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
65926ed70ecSGuanchao Liang }
660*14885eb1SEtienne Carriere 
661*14885eb1SEtienne Carriere #ifdef CFG_DT
662*14885eb1SEtienne Carriere /* Callback for "interrupts" and "interrupts-extended" DT node properties */
663*14885eb1SEtienne Carriere static TEE_Result dt_get_gic_chip_cb(struct dt_pargs *arg, void *priv_data,
664*14885eb1SEtienne Carriere 				     struct itr_desc *itr_desc)
665*14885eb1SEtienne Carriere {
666*14885eb1SEtienne Carriere 	int itr_num = DT_INFO_INVALID_INTERRUPT;
667*14885eb1SEtienne Carriere 	struct itr_chip *chip = priv_data;
668*14885eb1SEtienne Carriere 	uint32_t phandle_args[2] = { };
669*14885eb1SEtienne Carriere 	uint32_t type = 0;
670*14885eb1SEtienne Carriere 	uint32_t prio = 0;
671*14885eb1SEtienne Carriere 
672*14885eb1SEtienne Carriere 	assert(arg && itr_desc);
673*14885eb1SEtienne Carriere 
674*14885eb1SEtienne Carriere 	/*
675*14885eb1SEtienne Carriere 	 * gic_dt_get_irq() expects phandle arguments passed are still in DT
676*14885eb1SEtienne Carriere 	 * format (big-endian) whereas struct dt_pargs carries converted
677*14885eb1SEtienne Carriere 	 * formats. Therefore swap again phandle arguments. gic_dt_get_irq()
678*14885eb1SEtienne Carriere 	 * consumes only the 2 first arguments.
679*14885eb1SEtienne Carriere 	 */
680*14885eb1SEtienne Carriere 	if (arg->args_count < 2)
681*14885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
682*14885eb1SEtienne Carriere 	phandle_args[0] = cpu_to_fdt32(arg->args[0]);
683*14885eb1SEtienne Carriere 	phandle_args[1] = cpu_to_fdt32(arg->args[1]);
684*14885eb1SEtienne Carriere 
685*14885eb1SEtienne Carriere 	itr_num = gic_dt_get_irq((const void *)phandle_args, 2, &type, &prio);
686*14885eb1SEtienne Carriere 	if (itr_num == DT_INFO_INVALID_INTERRUPT)
687*14885eb1SEtienne Carriere 		return TEE_ERROR_GENERIC;
688*14885eb1SEtienne Carriere 
689*14885eb1SEtienne Carriere 	gic_op_add(chip, itr_num, type, prio);
690*14885eb1SEtienne Carriere 
691*14885eb1SEtienne Carriere 	itr_desc->chip = chip;
692*14885eb1SEtienne Carriere 	itr_desc->itr_num = itr_num;
693*14885eb1SEtienne Carriere 
694*14885eb1SEtienne Carriere 	return TEE_SUCCESS;
695*14885eb1SEtienne Carriere }
696*14885eb1SEtienne Carriere 
697*14885eb1SEtienne Carriere static TEE_Result gic_probe(const void *fdt, int offs, const void *cd __unused)
698*14885eb1SEtienne Carriere {
699*14885eb1SEtienne Carriere 	if (interrupt_register_provider(fdt, offs, dt_get_gic_chip_cb,
700*14885eb1SEtienne Carriere 					&gic_data.chip))
701*14885eb1SEtienne Carriere 		panic();
702*14885eb1SEtienne Carriere 
703*14885eb1SEtienne Carriere 	return TEE_SUCCESS;
704*14885eb1SEtienne Carriere }
705*14885eb1SEtienne Carriere 
706*14885eb1SEtienne Carriere static const struct dt_device_match gic_match_table[] = {
707*14885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a15-gic" },
708*14885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a7-gic" },
709*14885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a5-gic" },
710*14885eb1SEtienne Carriere 	{ .compatible = "arm,cortex-a9-gic" },
711*14885eb1SEtienne Carriere 	{ .compatible = "arm,gic-400" },
712*14885eb1SEtienne Carriere 	{ }
713*14885eb1SEtienne Carriere };
714*14885eb1SEtienne Carriere 
715*14885eb1SEtienne Carriere DEFINE_DT_DRIVER(gic_dt_driver) = {
716*14885eb1SEtienne Carriere 	.name = "gic",
717*14885eb1SEtienne Carriere 	.match_table = gic_match_table,
718*14885eb1SEtienne Carriere 	.probe = gic_probe,
719*14885eb1SEtienne Carriere };
720*14885eb1SEtienne Carriere #endif /*CFG_DT*/
721