xref: /optee_os/core/drivers/gic.c (revision f17691b3f6b27866f66636a53685bd3a6f7daa8a)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <drivers/gic.h>
29 #include <io.h>
30 #include <trace.h>
31 
32 #include <assert.h>
33 
34 /* Offsets from gic.gicc_base */
35 #define GICC_CTLR		(0x000)
36 #define GICC_PMR		(0x004)
37 #define GICC_IAR		(0x00C)
38 #define GICC_EOIR		(0x010)
39 
40 #define GICC_CTLR_ENABLEGRP0	(1 << 0)
41 #define GICC_CTLR_ENABLEGRP1	(1 << 1)
42 #define GICC_CTLR_FIQEN		(1 << 3)
43 
44 /* Offsets from gic.gicd_base */
45 #define GICD_CTLR		(0x000)
46 #define GICD_TYPER		(0x004)
47 #define GICD_IGROUPR(n)		(0x080 + (n) * 4)
48 #define GICD_ISENABLER(n)	(0x100 + (n) * 4)
49 #define GICD_ICENABLER(n)	(0x180 + (n) * 4)
50 #define GICD_ICPENDR(n)		(0x280 + (n) * 4)
51 #define GICD_IPRIORITYR(n)	(0x400 + (n) * 4)
52 #define GICD_ITARGETSR(n)	(0x800 + (n) * 4)
53 
54 #define GICD_CTLR_ENABLEGRP0	(1 << 0)
55 #define GICD_CTLR_ENABLEGRP1	(1 << 1)
56 
57 /* Number of Private Peripheral Interrupt */
58 #define NUM_PPI	32
59 
60 /* Number of interrupts in one register */
61 #define NUM_INTS_PER_REG	32
62 
63 /* Number of targets in one register */
64 #define NUM_TARGETS_PER_REG	4
65 
66 /* Accessors to access ITARGETSRn */
67 #define ITARGETSR_FIELD_BITS	8
68 #define ITARGETSR_FIELD_MASK	0xff
69 
70 /* Maximum number of interrups a GIC can support */
71 #define GIC_MAX_INTS		1020
72 
73 
74 static struct {
75 	vaddr_t gicc_base;
76 	vaddr_t gicd_base;
77 	size_t max_it;
78 } gic;
79 
80 static size_t probe_max_it(void)
81 {
82 	int i;
83 	uint32_t old_ctlr;
84 	size_t ret = 0;
85 	const size_t max_regs = ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) /
86 					NUM_INTS_PER_REG) - 1;
87 
88 	/*
89 	 * Probe which interrupt number is the largest.
90 	 */
91 	old_ctlr = read32(gic.gicc_base + GICC_CTLR);
92 	write32(0, gic.gicc_base + GICC_CTLR);
93 	for (i = max_regs; i >= 0; i--) {
94 		uint32_t old_reg;
95 		uint32_t reg;
96 		int b;
97 
98 		old_reg = read32(gic.gicd_base + GICD_ISENABLER(i));
99 		write32(0xffffffff, gic.gicd_base + GICD_ISENABLER(i));
100 		reg = read32(gic.gicd_base + GICD_ISENABLER(i));
101 		write32(old_reg, gic.gicd_base + GICD_ICENABLER(i));
102 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
103 			if ((1 << b) & reg) {
104 				ret = i * NUM_INTS_PER_REG + b;
105 				goto out;
106 			}
107 		}
108 	}
109 out:
110 	write32(old_ctlr, gic.gicc_base + GICC_CTLR);
111 	return ret;
112 }
113 
114 void gic_cpu_init(void)
115 {
116 	/* per-CPU interrupts config:
117 	 * ID0-ID7(SGI)   for Non-secure interrupts
118 	 * ID8-ID15(SGI)  for Secure interrupts.
119 	 * All PPI config as Non-secure interrupts.
120 	 */
121 	write32(0xffff00ff, gic.gicd_base + GICD_IGROUPR(0));
122 
123 	/* Set the priority mask to permit Non-secure interrupts, and to
124 	 * allow the Non-secure world to adjust the priority mask itself
125 	 */
126 	write32(0x80, gic.gicc_base + GICC_PMR);
127 
128 	/* Enable GIC */
129 	write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
130 		gic.gicc_base + GICC_CTLR);
131 }
132 
133 void gic_init(vaddr_t gicc_base, vaddr_t gicd_base)
134 {
135 	size_t n;
136 
137 	gic.gicc_base = gicc_base;
138 	gic.gicd_base = gicd_base;
139 	gic.max_it = probe_max_it();
140 
141 	for (n = 0; n <= gic.max_it / NUM_INTS_PER_REG; n++) {
142 		/* Disable interrupts */
143 		write32(0xffffffff, gic.gicd_base + GICD_ICENABLER(n));
144 
145 		/* Make interrupts non-pending */
146 		write32(0xffffffff, gic.gicd_base + GICD_ICPENDR(n));
147 
148 		/* Mark interrupts non-secure */
149 		if (n == 0) {
150 			/* per-CPU inerrupts config:
151                          * ID0-ID7(SGI)   for Non-secure interrupts
152                          * ID8-ID15(SGI)  for Secure interrupts.
153                          * All PPI config as Non-secure interrupts.
154 			 */
155 			write32(0xffff00ff, gic.gicd_base + GICD_IGROUPR(n));
156 		} else {
157 			write32(0xffffffff, gic.gicd_base + GICD_IGROUPR(n));
158 		}
159 	}
160 
161 	/* Set the priority mask to permit Non-secure interrupts, and to
162 	 * allow the Non-secure world to adjust the priority mask itself
163 	 */
164 	write32(0x80, gic.gicc_base + GICC_PMR);
165 
166 	/* Enable GIC */
167 	write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
168 		gic.gicc_base + GICC_CTLR);
169 	write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1,
170 		gic.gicd_base + GICD_CTLR);
171 }
172 
173 void gic_init_base_addr(vaddr_t gicc_base, vaddr_t gicd_base)
174 {
175 	gic.gicc_base = gicc_base;
176 	gic.gicd_base = gicd_base;
177 	gic.max_it = probe_max_it();
178 }
179 
180 void gic_it_add(size_t it)
181 {
182 	size_t idx = it / NUM_INTS_PER_REG;
183 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
184 
185 	assert(it <= gic.max_it); /* Not too large */
186 
187 	/* Disable the interrupt */
188 	write32(mask, gic.gicd_base + GICD_ICENABLER(idx));
189 	/* Make it non-pending */
190 	write32(mask, gic.gicd_base + GICD_ICPENDR(idx));
191 	/* Assign it to group0 */
192 	write32(read32(gic.gicd_base + GICD_IGROUPR(idx)) & ~mask,
193 			gic.gicd_base + GICD_IGROUPR(idx));
194 }
195 
196 void gic_it_set_cpu_mask(size_t it, uint8_t cpu_mask)
197 {
198 	size_t idx = it / NUM_INTS_PER_REG;
199 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
200 	uint32_t target, target_shift;
201 
202 	assert(it <= gic.max_it); /* Not too large */
203 	/* Assigned to group0 */
204 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
205 
206 	/* Route it to selected CPUs */
207 	target = read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
208 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
209 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
210 	target |= cpu_mask << target_shift;
211 	DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA,
212 		target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
213 	write32(target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
214 	DMSG("cpu_mask: 0x%x\n",
215 		read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)));
216 }
217 
218 void gic_it_set_prio(size_t it, uint8_t prio)
219 {
220 	size_t idx = it / NUM_INTS_PER_REG;
221 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
222 
223 	assert(it <= gic.max_it); /* Not too large */
224 	/* Assigned to group0 */
225 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
226 
227 	/* Set prio it to selected CPUs */
228 	DMSG("prio: writing 0x%x to 0x%" PRIxVA,
229 		prio, gic.gicd_base + GICD_IPRIORITYR(0) + it);
230 	write8(prio, gic.gicd_base + GICD_IPRIORITYR(0) + it);
231 }
232 
233 void gic_it_enable(size_t it)
234 {
235 	size_t idx = it / NUM_INTS_PER_REG;
236 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
237 
238 	assert(it <= gic.max_it); /* Not too large */
239 	/* Assigned to group0 */
240 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
241 	/* Not enabled yet */
242 	assert(!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask));
243 
244 	/* Enable the interrupt */
245 	write32(mask, gic.gicd_base + GICD_ISENABLER(idx));
246 }
247 
248 void gic_it_disable(size_t it)
249 {
250 	size_t idx = it / NUM_INTS_PER_REG;
251 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
252 
253 	assert(it <= gic.max_it); /* Not too large */
254 	/* Assigned to group0 */
255 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
256 
257 	/* Disable the interrupt */
258 	write32(mask, gic.gicd_base + GICD_ICENABLER(idx));
259 }
260 
261 uint32_t gic_read_iar(void)
262 {
263 	return read32(gic.gicc_base + GICC_IAR);
264 }
265 
266 void gic_write_eoir(uint32_t eoir)
267 {
268 	write32(eoir, gic.gicc_base + GICC_EOIR);
269 }
270 
271 bool gic_it_is_enabled(size_t it) {
272 	size_t idx = it / NUM_INTS_PER_REG;
273 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
274 	return !!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask);
275 }
276 
277 bool gic_it_get_group(size_t it) {
278 	size_t idx = it / NUM_INTS_PER_REG;
279 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
280 	return !!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask);
281 }
282 
283 uint32_t gic_it_get_target(size_t it) {
284 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
285 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
286 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
287 	uint32_t target =
288 		read32(gic.gicd_base + GICD_ITARGETSR(reg_idx)) & target_mask;
289 	target = target >> target_shift;
290 	return target;
291 }
292 
293 void gic_dump_state(void)
294 {
295 	int i;
296 	DMSG("GICC_CTLR: 0x%x", read32(gic.gicc_base + GICC_CTLR));
297 	DMSG("GICD_CTLR: 0x%x", read32(gic.gicd_base + GICD_CTLR));
298 
299 	for (i = 0; i < (int)gic.max_it; i++) {
300 		if (gic_it_is_enabled(i)) {
301 			DMSG("irq%d: enabled, group:%d, target:%x", i,
302 				gic_it_get_group(i), gic_it_get_target(i));
303 		}
304 	}
305 }
306