xref: /optee_os/core/drivers/gic.c (revision 18901324e00a073b06dc413d6b7a87f1c0b2f8d1)
1b0104773SPascal Brand /*
2*18901324SDavid Wang  * Copyright (c) 2016-2017, Linaro Limited
3b0104773SPascal Brand  * Copyright (c) 2014, STMicroelectronics International N.V.
4b0104773SPascal Brand  * All rights reserved.
5b0104773SPascal Brand  *
6b0104773SPascal Brand  * Redistribution and use in source and binary forms, with or without
7b0104773SPascal Brand  * modification, are permitted provided that the following conditions are met:
8b0104773SPascal Brand  *
9b0104773SPascal Brand  * 1. Redistributions of source code must retain the above copyright notice,
10b0104773SPascal Brand  * this list of conditions and the following disclaimer.
11b0104773SPascal Brand  *
12b0104773SPascal Brand  * 2. Redistributions in binary form must reproduce the above copyright notice,
13b0104773SPascal Brand  * this list of conditions and the following disclaimer in the documentation
14b0104773SPascal Brand  * and/or other materials provided with the distribution.
15b0104773SPascal Brand  *
16b0104773SPascal Brand  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17b0104773SPascal Brand  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b0104773SPascal Brand  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b0104773SPascal Brand  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20b0104773SPascal Brand  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21b0104773SPascal Brand  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22b0104773SPascal Brand  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23b0104773SPascal Brand  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24b0104773SPascal Brand  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25b0104773SPascal Brand  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26b0104773SPascal Brand  * POSSIBILITY OF SUCH DAMAGE.
27b0104773SPascal Brand  */
28b0104773SPascal Brand 
29*18901324SDavid Wang #include <arm.h>
308ddf5a4eSEtienne Carriere #include <assert.h>
31b0104773SPascal Brand #include <drivers/gic.h>
327315b7b4SJens Wiklander #include <kernel/interrupt.h>
33d13278b8SEtienne Carriere #include <kernel/panic.h>
347315b7b4SJens Wiklander #include <util.h>
35b0104773SPascal Brand #include <io.h>
364de4bebcSJens Wiklander #include <trace.h>
37b0104773SPascal Brand 
38b0104773SPascal Brand /* Offsets from gic.gicc_base */
39b0104773SPascal Brand #define GICC_CTLR		(0x000)
4030a673e3SPeter Maydell #define GICC_PMR		(0x004)
41b0104773SPascal Brand #define GICC_IAR		(0x00C)
42b0104773SPascal Brand #define GICC_EOIR		(0x010)
43b0104773SPascal Brand 
44b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP0	(1 << 0)
45b0104773SPascal Brand #define GICC_CTLR_ENABLEGRP1	(1 << 1)
46b0104773SPascal Brand #define GICC_CTLR_FIQEN		(1 << 3)
47b0104773SPascal Brand 
48b0104773SPascal Brand /* Offsets from gic.gicd_base */
49b0104773SPascal Brand #define GICD_CTLR		(0x000)
50b0104773SPascal Brand #define GICD_TYPER		(0x004)
51b0104773SPascal Brand #define GICD_IGROUPR(n)		(0x080 + (n) * 4)
52b0104773SPascal Brand #define GICD_ISENABLER(n)	(0x100 + (n) * 4)
53b0104773SPascal Brand #define GICD_ICENABLER(n)	(0x180 + (n) * 4)
5426ed70ecSGuanchao Liang #define GICD_ISPENDR(n)		(0x200 + (n) * 4)
55b0104773SPascal Brand #define GICD_ICPENDR(n)		(0x280 + (n) * 4)
56b0104773SPascal Brand #define GICD_IPRIORITYR(n)	(0x400 + (n) * 4)
57b0104773SPascal Brand #define GICD_ITARGETSR(n)	(0x800 + (n) * 4)
5826ed70ecSGuanchao Liang #define GICD_SGIR		(0xF00)
59b0104773SPascal Brand 
60b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP0	(1 << 0)
61b0104773SPascal Brand #define GICD_CTLR_ENABLEGRP1	(1 << 1)
62b0104773SPascal Brand 
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 
82b0104773SPascal Brand /* Maximum number of interrups a GIC can support */
83b0104773SPascal Brand #define GIC_MAX_INTS		1020
84b0104773SPascal Brand 
857315b7b4SJens Wiklander #define GICC_IAR_IT_ID_MASK	0x3ff
867315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_MASK	0x7
877315b7b4SJens Wiklander #define GICC_IAR_CPU_ID_SHIFT	10
88b0104773SPascal Brand 
897315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t flags);
907315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it);
917315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it);
9226ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
9326ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
9426ed70ecSGuanchao Liang 			uint8_t cpu_mask);
9526ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
9626ed70ecSGuanchao Liang 			uint8_t cpu_mask);
977315b7b4SJens Wiklander 
987315b7b4SJens Wiklander static const struct itr_ops gic_ops = {
997315b7b4SJens Wiklander 	.add = gic_op_add,
1007315b7b4SJens Wiklander 	.enable = gic_op_enable,
1017315b7b4SJens Wiklander 	.disable = gic_op_disable,
10226ed70ecSGuanchao Liang 	.raise_pi = gic_op_raise_pi,
10326ed70ecSGuanchao Liang 	.raise_sgi = gic_op_raise_sgi,
10426ed70ecSGuanchao Liang 	.set_affinity = gic_op_set_affinity,
1057315b7b4SJens Wiklander };
1067315b7b4SJens Wiklander 
107*18901324SDavid Wang static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
108b0104773SPascal Brand {
109b0104773SPascal Brand 	int i;
110b0104773SPascal Brand 	uint32_t old_ctlr;
111b0104773SPascal Brand 	size_t ret = 0;
11279f008d3SJens Wiklander 	const size_t max_regs = ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) /
11379f008d3SJens Wiklander 					NUM_INTS_PER_REG) - 1;
114b0104773SPascal Brand 
115b0104773SPascal Brand 	/*
116b0104773SPascal Brand 	 * Probe which interrupt number is the largest.
117b0104773SPascal Brand 	 */
118*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
119*18901324SDavid Wang 	old_ctlr = read_icc_ctlr();
120*18901324SDavid Wang 	write_icc_ctlr(0);
121*18901324SDavid Wang #else
1227315b7b4SJens Wiklander 	old_ctlr = read32(gicc_base + GICC_CTLR);
1237315b7b4SJens Wiklander 	write32(0, gicc_base + GICC_CTLR);
124*18901324SDavid Wang #endif
12579f008d3SJens Wiklander 	for (i = max_regs; i >= 0; i--) {
126b0104773SPascal Brand 		uint32_t old_reg;
127b0104773SPascal Brand 		uint32_t reg;
128b0104773SPascal Brand 		int b;
129b0104773SPascal Brand 
1307315b7b4SJens Wiklander 		old_reg = read32(gicd_base + GICD_ISENABLER(i));
1317315b7b4SJens Wiklander 		write32(0xffffffff, gicd_base + GICD_ISENABLER(i));
1327315b7b4SJens Wiklander 		reg = read32(gicd_base + GICD_ISENABLER(i));
1337315b7b4SJens Wiklander 		write32(old_reg, gicd_base + GICD_ICENABLER(i));
13479f008d3SJens Wiklander 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
135007a97a2SJens Wiklander 			if (BIT32(b) & reg) {
13653bd332aSSY Chiu 				ret = i * NUM_INTS_PER_REG + b;
137b0104773SPascal Brand 				goto out;
138b0104773SPascal Brand 			}
139b0104773SPascal Brand 		}
140b0104773SPascal Brand 	}
141b0104773SPascal Brand out:
142*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
143*18901324SDavid Wang 	write_icc_ctlr(old_ctlr);
144*18901324SDavid Wang #else
1457315b7b4SJens Wiklander 	write32(old_ctlr, gicc_base + GICC_CTLR);
146*18901324SDavid Wang #endif
147b0104773SPascal Brand 	return ret;
148b0104773SPascal Brand }
149b0104773SPascal Brand 
1507315b7b4SJens Wiklander void gic_cpu_init(struct gic_data *gd)
151bedc2b9fSsunny {
152*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
153*18901324SDavid Wang 	assert(gd->gicd_base);
154*18901324SDavid Wang #else
15505efe1e1SEtienne Carriere 	assert(gd->gicd_base && gd->gicc_base);
156*18901324SDavid Wang #endif
15705efe1e1SEtienne Carriere 
158e06e6e74SPeter Maydell 	/* per-CPU interrupts config:
159bedc2b9fSsunny 	 * ID0-ID7(SGI)   for Non-secure interrupts
160bedc2b9fSsunny 	 * ID8-ID15(SGI)  for Secure interrupts.
161bedc2b9fSsunny 	 * All PPI config as Non-secure interrupts.
162bedc2b9fSsunny 	 */
1637315b7b4SJens Wiklander 	write32(0xffff00ff, gd->gicd_base + GICD_IGROUPR(0));
164bedc2b9fSsunny 
16530a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
16630a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
16730a673e3SPeter Maydell 	 */
168*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
169*18901324SDavid Wang 	write_icc_pmr(0x80);
170*18901324SDavid Wang 	write_icc_ctlr(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
171*18901324SDavid Wang 		       GICC_CTLR_FIQEN);
172*18901324SDavid Wang #else
1737315b7b4SJens Wiklander 	write32(0x80, gd->gicc_base + GICC_PMR);
17430a673e3SPeter Maydell 
175bedc2b9fSsunny 	/* Enable GIC */
176bedc2b9fSsunny 	write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
1777315b7b4SJens Wiklander 		gd->gicc_base + GICC_CTLR);
178*18901324SDavid Wang #endif
179bedc2b9fSsunny }
180bedc2b9fSsunny 
181*18901324SDavid Wang void gic_init(struct gic_data *gd, vaddr_t gicc_base __maybe_unused,
182*18901324SDavid Wang 	      vaddr_t gicd_base)
183b0104773SPascal Brand {
184b0104773SPascal Brand 	size_t n;
185b0104773SPascal Brand 
1867315b7b4SJens Wiklander 	gic_init_base_addr(gd, gicc_base, gicd_base);
187b0104773SPascal Brand 
1887315b7b4SJens Wiklander 	for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
189b0104773SPascal Brand 		/* Disable interrupts */
1907315b7b4SJens Wiklander 		write32(0xffffffff, gd->gicd_base + GICD_ICENABLER(n));
191b0104773SPascal Brand 
192b0104773SPascal Brand 		/* Make interrupts non-pending */
1937315b7b4SJens Wiklander 		write32(0xffffffff, gd->gicd_base + GICD_ICPENDR(n));
194b0104773SPascal Brand 
195b0104773SPascal Brand 		/* Mark interrupts non-secure */
196bedc2b9fSsunny 		if (n == 0) {
197bedc2b9fSsunny 			/* per-CPU inerrupts config:
198bedc2b9fSsunny                          * ID0-ID7(SGI)   for Non-secure interrupts
199bedc2b9fSsunny                          * ID8-ID15(SGI)  for Secure interrupts.
200bedc2b9fSsunny                          * All PPI config as Non-secure interrupts.
201bedc2b9fSsunny 			 */
2027315b7b4SJens Wiklander 			write32(0xffff00ff, gd->gicd_base + GICD_IGROUPR(n));
203bedc2b9fSsunny 		} else {
2047315b7b4SJens Wiklander 			write32(0xffffffff, gd->gicd_base + GICD_IGROUPR(n));
205b0104773SPascal Brand 		}
206bedc2b9fSsunny 	}
207b0104773SPascal Brand 
20830a673e3SPeter Maydell 	/* Set the priority mask to permit Non-secure interrupts, and to
20930a673e3SPeter Maydell 	 * allow the Non-secure world to adjust the priority mask itself
21030a673e3SPeter Maydell 	 */
211*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
212*18901324SDavid Wang 	write_icc_pmr(0x80);
213*18901324SDavid Wang 	write_icc_ctlr(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 |
214*18901324SDavid Wang 		       GICC_CTLR_FIQEN);
215*18901324SDavid Wang #else
2167315b7b4SJens Wiklander 	write32(0x80, gd->gicc_base + GICC_PMR);
21730a673e3SPeter Maydell 
218b0104773SPascal Brand 	/* Enable GIC */
219b0104773SPascal Brand 	write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
2207315b7b4SJens Wiklander 		gd->gicc_base + GICC_CTLR);
221*18901324SDavid Wang #endif
222b0104773SPascal Brand 	write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1,
2237315b7b4SJens Wiklander 		gd->gicd_base + GICD_CTLR);
224b0104773SPascal Brand }
225b0104773SPascal Brand 
226*18901324SDavid Wang void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base __maybe_unused,
2277315b7b4SJens Wiklander 			vaddr_t gicd_base)
22853bd332aSSY Chiu {
2297315b7b4SJens Wiklander 	gd->gicc_base = gicc_base;
2307315b7b4SJens Wiklander 	gd->gicd_base = gicd_base;
2317315b7b4SJens Wiklander 	gd->max_it = probe_max_it(gicc_base, gicd_base);
2327315b7b4SJens Wiklander 	gd->chip.ops = &gic_ops;
23353bd332aSSY Chiu }
23453bd332aSSY Chiu 
2357315b7b4SJens Wiklander static void gic_it_add(struct gic_data *gd, size_t it)
236b0104773SPascal Brand {
23753bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
23853bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
239b0104773SPascal Brand 
240b0104773SPascal Brand 	/* Disable the interrupt */
2417315b7b4SJens Wiklander 	write32(mask, gd->gicd_base + GICD_ICENABLER(idx));
242b0104773SPascal Brand 	/* Make it non-pending */
2437315b7b4SJens Wiklander 	write32(mask, gd->gicd_base + GICD_ICPENDR(idx));
244b0104773SPascal Brand 	/* Assign it to group0 */
2457315b7b4SJens Wiklander 	write32(read32(gd->gicd_base + GICD_IGROUPR(idx)) & ~mask,
2467315b7b4SJens Wiklander 			gd->gicd_base + GICD_IGROUPR(idx));
247b0104773SPascal Brand }
248b0104773SPascal Brand 
2497315b7b4SJens Wiklander static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
2507315b7b4SJens Wiklander 				uint8_t cpu_mask)
251b0104773SPascal Brand {
2528ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
2538ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
25453bd332aSSY Chiu 	uint32_t target, target_shift;
255b0104773SPascal Brand 
256b0104773SPascal Brand 	/* Assigned to group0 */
2577315b7b4SJens Wiklander 	assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
258b0104773SPascal Brand 
259b0104773SPascal Brand 	/* Route it to selected CPUs */
2607315b7b4SJens Wiklander 	target = read32(gd->gicd_base +
2617315b7b4SJens Wiklander 			GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
26253bd332aSSY Chiu 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
26353bd332aSSY Chiu 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
26453bd332aSSY Chiu 	target |= cpu_mask << target_shift;
2651f60363aSJens Wiklander 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA,
2667315b7b4SJens Wiklander 	     target, gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
2677315b7b4SJens Wiklander 	write32(target,
2687315b7b4SJens Wiklander 		gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
269b0104773SPascal Brand 	DMSG("cpu_mask: 0x%x\n",
2707315b7b4SJens Wiklander 	     read32(gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)));
271b0104773SPascal Brand }
272b0104773SPascal Brand 
2737315b7b4SJens Wiklander static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
274b0104773SPascal Brand {
2758ddf5a4eSEtienne Carriere 	size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
2768ddf5a4eSEtienne Carriere 	uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
277b0104773SPascal Brand 
278b0104773SPascal Brand 	/* Assigned to group0 */
2797315b7b4SJens Wiklander 	assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
280b0104773SPascal Brand 
281b0104773SPascal Brand 	/* Set prio it to selected CPUs */
2821f60363aSJens Wiklander 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
2837315b7b4SJens Wiklander 		prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
2847315b7b4SJens Wiklander 	write8(prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
285b0104773SPascal Brand }
286b0104773SPascal Brand 
2877315b7b4SJens Wiklander static void gic_it_enable(struct gic_data *gd, size_t it)
288b0104773SPascal Brand {
28953bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
29053bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
291b0104773SPascal Brand 
292b0104773SPascal Brand 	/* Assigned to group0 */
2937315b7b4SJens Wiklander 	assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
29426ed70ecSGuanchao Liang 	if (it >= NUM_SGI) {
29526ed70ecSGuanchao Liang 		/*
29626ed70ecSGuanchao Liang 		 * Not enabled yet, except Software Generated Interrupt
29726ed70ecSGuanchao Liang 		 * which is implementation defined
29826ed70ecSGuanchao Liang 		 */
2997315b7b4SJens Wiklander 		assert(!(read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask));
30026ed70ecSGuanchao Liang 	}
301b0104773SPascal Brand 
302b0104773SPascal Brand 	/* Enable the interrupt */
3037315b7b4SJens Wiklander 	write32(mask, gd->gicd_base + GICD_ISENABLER(idx));
304b0104773SPascal Brand }
305b0104773SPascal Brand 
3067315b7b4SJens Wiklander static void gic_it_disable(struct gic_data *gd, size_t it)
307b0104773SPascal Brand {
30853bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
30953bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
310b0104773SPascal Brand 
311b0104773SPascal Brand 	/* Assigned to group0 */
3127315b7b4SJens Wiklander 	assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
313b0104773SPascal Brand 
314b0104773SPascal Brand 	/* Disable the interrupt */
3157315b7b4SJens Wiklander 	write32(mask, gd->gicd_base + GICD_ICENABLER(idx));
316b0104773SPascal Brand }
317b0104773SPascal Brand 
31826ed70ecSGuanchao Liang static void gic_it_set_pending(struct gic_data *gd, size_t it)
31926ed70ecSGuanchao Liang {
32026ed70ecSGuanchao Liang 	size_t idx = it / NUM_INTS_PER_REG;
32126ed70ecSGuanchao Liang 	uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
32226ed70ecSGuanchao Liang 
32326ed70ecSGuanchao Liang 	/* Should be Peripheral Interrupt */
32426ed70ecSGuanchao Liang 	assert(it >= NUM_SGI);
32526ed70ecSGuanchao Liang 	/* Assigned to group0 */
32626ed70ecSGuanchao Liang 	assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
32726ed70ecSGuanchao Liang 
32826ed70ecSGuanchao Liang 	/* Raise the interrupt */
32926ed70ecSGuanchao Liang 	write32(mask, gd->gicd_base + GICD_ISPENDR(idx));
33026ed70ecSGuanchao Liang }
33126ed70ecSGuanchao Liang 
33226ed70ecSGuanchao Liang static void gic_it_raise_sgi(struct gic_data *gd, size_t it,
33326ed70ecSGuanchao Liang 		uint8_t cpu_mask, uint8_t group)
33426ed70ecSGuanchao Liang {
33526ed70ecSGuanchao Liang 	uint32_t mask_id = it & 0xf;
33626ed70ecSGuanchao Liang 	uint32_t mask_group = group & 0x1;
33726ed70ecSGuanchao Liang 	uint32_t mask_cpu = cpu_mask & 0xff;
33826ed70ecSGuanchao Liang 	uint32_t mask = (mask_id | SHIFT_U32(mask_group, 15) |
33926ed70ecSGuanchao Liang 		SHIFT_U32(mask_cpu, 16));
34026ed70ecSGuanchao Liang 
34126ed70ecSGuanchao Liang 	/* Should be Software Generated Interrupt */
34226ed70ecSGuanchao Liang 	assert(it < NUM_SGI);
34326ed70ecSGuanchao Liang 
34426ed70ecSGuanchao Liang 	/* Raise the interrupt */
34526ed70ecSGuanchao Liang 	write32(mask, gd->gicd_base + GICD_SGIR);
34626ed70ecSGuanchao Liang }
34726ed70ecSGuanchao Liang 
348*18901324SDavid Wang static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
349b0104773SPascal Brand {
350*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
351*18901324SDavid Wang 	return read_icc_iar0();
352*18901324SDavid Wang #else
3537315b7b4SJens Wiklander 	return read32(gd->gicc_base + GICC_IAR);
354*18901324SDavid Wang #endif
355b0104773SPascal Brand }
356b0104773SPascal Brand 
357*18901324SDavid Wang static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
358b0104773SPascal Brand {
359*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
360*18901324SDavid Wang 	write_icc_eoir0(eoir);
361*18901324SDavid Wang #else
3627315b7b4SJens Wiklander 	write32(eoir, gd->gicc_base + GICC_EOIR);
363*18901324SDavid Wang #endif
364b0104773SPascal Brand }
365b0104773SPascal Brand 
3667315b7b4SJens Wiklander static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
3677315b7b4SJens Wiklander {
36853bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
36953bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
3707315b7b4SJens Wiklander 	return !!(read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
37153bd332aSSY Chiu }
37253bd332aSSY Chiu 
3737315b7b4SJens Wiklander static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
3747315b7b4SJens Wiklander {
37553bd332aSSY Chiu 	size_t idx = it / NUM_INTS_PER_REG;
37653bd332aSSY Chiu 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
3777315b7b4SJens Wiklander 	return !!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
37853bd332aSSY Chiu }
37953bd332aSSY Chiu 
3807315b7b4SJens Wiklander static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
3817315b7b4SJens Wiklander {
38253bd332aSSY Chiu 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
3837315b7b4SJens Wiklander 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
3847315b7b4SJens Wiklander 				ITARGETSR_FIELD_BITS;
38553bd332aSSY Chiu 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
38653bd332aSSY Chiu 	uint32_t target =
3877315b7b4SJens Wiklander 		read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)) & target_mask;
3887315b7b4SJens Wiklander 
38953bd332aSSY Chiu 	target = target >> target_shift;
39053bd332aSSY Chiu 	return target;
39153bd332aSSY Chiu }
39253bd332aSSY Chiu 
3937315b7b4SJens Wiklander void gic_dump_state(struct gic_data *gd)
39453bd332aSSY Chiu {
39553bd332aSSY Chiu 	int i;
39653bd332aSSY Chiu 
397*18901324SDavid Wang #if defined(CFG_ARM_GICV3)
398*18901324SDavid Wang 	DMSG("GICC_CTLR: 0x%x", read_icc_ctlr());
399*18901324SDavid Wang #else
4007315b7b4SJens Wiklander 	DMSG("GICC_CTLR: 0x%x", read32(gd->gicc_base + GICC_CTLR));
401*18901324SDavid Wang #endif
4027315b7b4SJens Wiklander 	DMSG("GICD_CTLR: 0x%x", read32(gd->gicd_base + GICD_CTLR));
4037315b7b4SJens Wiklander 
4047315b7b4SJens Wiklander 	for (i = 0; i < (int)gd->max_it; i++) {
4057315b7b4SJens Wiklander 		if (gic_it_is_enabled(gd, i)) {
40653bd332aSSY Chiu 			DMSG("irq%d: enabled, group:%d, target:%x", i,
4077315b7b4SJens Wiklander 			     gic_it_get_group(gd, i), gic_it_get_target(gd, i));
40853bd332aSSY Chiu 		}
40953bd332aSSY Chiu 	}
41053bd332aSSY Chiu }
4117315b7b4SJens Wiklander 
4127315b7b4SJens Wiklander void gic_it_handle(struct gic_data *gd)
4137315b7b4SJens Wiklander {
4147315b7b4SJens Wiklander 	uint32_t iar;
4157315b7b4SJens Wiklander 	uint32_t id;
4167315b7b4SJens Wiklander 
4177315b7b4SJens Wiklander 	iar = gic_read_iar(gd);
4187315b7b4SJens Wiklander 	id = iar & GICC_IAR_IT_ID_MASK;
4197315b7b4SJens Wiklander 
4203b3a4611SMathieu Briand 	if (id < gd->max_it)
4217315b7b4SJens Wiklander 		itr_handle(id);
4223b3a4611SMathieu Briand 	else
4233b3a4611SMathieu Briand 		DMSG("ignoring interrupt %" PRIu32, id);
4247315b7b4SJens Wiklander 
4257315b7b4SJens Wiklander 	gic_write_eoir(gd, iar);
4267315b7b4SJens Wiklander }
4277315b7b4SJens Wiklander 
4287315b7b4SJens Wiklander static void gic_op_add(struct itr_chip *chip, size_t it,
4297315b7b4SJens Wiklander 		       uint32_t flags __unused)
4307315b7b4SJens Wiklander {
4317315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
4327315b7b4SJens Wiklander 
433d13278b8SEtienne Carriere 	if (it >= gd->max_it)
434d13278b8SEtienne Carriere 		panic();
435d13278b8SEtienne Carriere 
4367315b7b4SJens Wiklander 	gic_it_add(gd, it);
4377315b7b4SJens Wiklander 	/* Set the CPU mask to deliver interrupts to any online core */
4387315b7b4SJens Wiklander 	gic_it_set_cpu_mask(gd, it, 0xff);
4397315b7b4SJens Wiklander 	gic_it_set_prio(gd, it, 0x1);
4407315b7b4SJens Wiklander }
4417315b7b4SJens Wiklander 
4427315b7b4SJens Wiklander static void gic_op_enable(struct itr_chip *chip, size_t it)
4437315b7b4SJens Wiklander {
4447315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
4457315b7b4SJens Wiklander 
446d13278b8SEtienne Carriere 	if (it >= gd->max_it)
447d13278b8SEtienne Carriere 		panic();
448d13278b8SEtienne Carriere 
4497315b7b4SJens Wiklander 	gic_it_enable(gd, it);
4507315b7b4SJens Wiklander }
4517315b7b4SJens Wiklander 
4527315b7b4SJens Wiklander static void gic_op_disable(struct itr_chip *chip, size_t it)
4537315b7b4SJens Wiklander {
4547315b7b4SJens Wiklander 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
4557315b7b4SJens Wiklander 
456d13278b8SEtienne Carriere 	if (it >= gd->max_it)
457d13278b8SEtienne Carriere 		panic();
458d13278b8SEtienne Carriere 
4597315b7b4SJens Wiklander 	gic_it_disable(gd, it);
4607315b7b4SJens Wiklander }
46126ed70ecSGuanchao Liang 
46226ed70ecSGuanchao Liang static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
46326ed70ecSGuanchao Liang {
46426ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
46526ed70ecSGuanchao Liang 
46626ed70ecSGuanchao Liang 	if (it >= gd->max_it)
46726ed70ecSGuanchao Liang 		panic();
46826ed70ecSGuanchao Liang 
46926ed70ecSGuanchao Liang 	gic_it_set_pending(gd, it);
47026ed70ecSGuanchao Liang }
47126ed70ecSGuanchao Liang 
47226ed70ecSGuanchao Liang static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
47326ed70ecSGuanchao Liang 			uint8_t cpu_mask)
47426ed70ecSGuanchao Liang {
47526ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
47626ed70ecSGuanchao Liang 
47726ed70ecSGuanchao Liang 	if (it >= gd->max_it)
47826ed70ecSGuanchao Liang 		panic();
47926ed70ecSGuanchao Liang 
48026ed70ecSGuanchao Liang 	if (it < NUM_NS_SGI)
48126ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 1);
48226ed70ecSGuanchao Liang 	else
48326ed70ecSGuanchao Liang 		gic_it_raise_sgi(gd, it, cpu_mask, 0);
48426ed70ecSGuanchao Liang }
48526ed70ecSGuanchao Liang static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
48626ed70ecSGuanchao Liang 			uint8_t cpu_mask)
48726ed70ecSGuanchao Liang {
48826ed70ecSGuanchao Liang 	struct gic_data *gd = container_of(chip, struct gic_data, chip);
48926ed70ecSGuanchao Liang 
49026ed70ecSGuanchao Liang 	if (it >= gd->max_it)
49126ed70ecSGuanchao Liang 		panic();
49226ed70ecSGuanchao Liang 
49326ed70ecSGuanchao Liang 	gic_it_set_cpu_mask(gd, it, cpu_mask);
49426ed70ecSGuanchao Liang }
495