xref: /optee_os/core/drivers/gic.c (revision d1d226a5264ce5654695edc656ef759fc48f675f)
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_IAR		(0x00C)
37 #define GICC_EOIR		(0x010)
38 
39 #define GICC_CTLR_ENABLEGRP0	(1 << 0)
40 #define GICC_CTLR_ENABLEGRP1	(1 << 1)
41 #define GICC_CTLR_FIQEN		(1 << 3)
42 
43 /* Offsets from gic.gicd_base */
44 #define GICD_CTLR		(0x000)
45 #define GICD_TYPER		(0x004)
46 #define GICD_IGROUPR(n)		(0x080 + (n) * 4)
47 #define GICD_ISENABLER(n)	(0x100 + (n) * 4)
48 #define GICD_ICENABLER(n)	(0x180 + (n) * 4)
49 #define GICD_ICPENDR(n)		(0x280 + (n) * 4)
50 #define GICD_IPRIORITYR(n)	(0x400 + (n) * 4)
51 #define GICD_ITARGETSR(n)	(0x800 + (n) * 4)
52 
53 #define GICD_CTLR_ENABLEGRP0	(1 << 0)
54 #define GICD_CTLR_ENABLEGRP1	(1 << 1)
55 
56 /* Number of Private Peripheral Interrupt */
57 #define NUM_PPI	32
58 
59 /* Number of interrupts in one register */
60 #define NUM_INTS_PER_REG	32
61 
62 /* Number of targets in one register */
63 #define NUM_TARGETS_PER_REG	4
64 
65 /* Accessors to access ITARGETSRn */
66 #define ITARGETSR_FIELD_BITS	8
67 #define ITARGETSR_FIELD_MASK	0xff
68 
69 /* Maximum number of interrups a GIC can support */
70 #define GIC_MAX_INTS		1020
71 
72 
73 static struct {
74 	vaddr_t gicc_base;
75 	vaddr_t gicd_base;
76 	size_t max_it;
77 } gic;
78 
79 static size_t probe_max_it(void)
80 {
81 	int i;
82 	uint32_t old_ctlr;
83 	size_t ret = 0;
84 	const size_t max_regs = ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) /
85 					NUM_INTS_PER_REG) - 1;
86 
87 	/*
88 	 * Probe which interrupt number is the largest.
89 	 */
90 	old_ctlr = read32(gic.gicc_base + GICC_CTLR);
91 	write32(0, gic.gicc_base + GICC_CTLR);
92 	for (i = max_regs; i >= 0; i--) {
93 		uint32_t old_reg;
94 		uint32_t reg;
95 		int b;
96 
97 		old_reg = read32(gic.gicd_base + GICD_ISENABLER(i));
98 		write32(0xffffffff, gic.gicd_base + GICD_ISENABLER(i));
99 		reg = read32(gic.gicd_base + GICD_ISENABLER(i));
100 		write32(old_reg, gic.gicd_base + GICD_ICENABLER(i));
101 		for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
102 			if ((1 << b) & reg) {
103 				ret = i * NUM_INTS_PER_REG + b;
104 				goto out;
105 			}
106 		}
107 	}
108 out:
109 	write32(old_ctlr, gic.gicc_base + GICC_CTLR);
110 	return ret;
111 }
112 
113 void gic_init(vaddr_t gicc_base, vaddr_t gicd_base)
114 {
115 	size_t n;
116 
117 	gic.gicc_base = gicc_base;
118 	gic.gicd_base = gicd_base;
119 	gic.max_it = probe_max_it();
120 
121 	for (n = 0; n <= gic.max_it / NUM_INTS_PER_REG; n++) {
122 		/* Disable interrupts */
123 		write32(0xffffffff, gic.gicd_base + GICD_ICENABLER(n));
124 
125 		/* Make interrupts non-pending */
126 		write32(0xffffffff, gic.gicd_base + GICD_ICPENDR(n));
127 
128 		/* Mark interrupts non-secure */
129 		write32(0xffffffff, gic.gicd_base + GICD_IGROUPR(n));
130 	}
131 
132 	/* Enable GIC */
133 	write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
134 		gic.gicc_base + GICC_CTLR);
135 	write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1,
136 		gic.gicd_base + GICD_CTLR);
137 }
138 
139 void gic_init_base_addr(vaddr_t gicc_base, vaddr_t gicd_base)
140 {
141 	gic.gicc_base = gicc_base;
142 	gic.gicd_base = gicd_base;
143 	gic.max_it = probe_max_it();
144 }
145 
146 void gic_it_add(size_t it)
147 {
148 	size_t idx = it / NUM_INTS_PER_REG;
149 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
150 
151 	assert(it <= gic.max_it); /* Not too large */
152 
153 	/* Disable the interrupt */
154 	write32(mask, gic.gicd_base + GICD_ICENABLER(idx));
155 	/* Make it non-pending */
156 	write32(mask, gic.gicd_base + GICD_ICPENDR(idx));
157 	/* Assign it to group0 */
158 	write32(read32(gic.gicd_base + GICD_IGROUPR(idx)) & ~mask,
159 			gic.gicd_base + GICD_IGROUPR(idx));
160 }
161 
162 void gic_it_set_cpu_mask(size_t it, uint8_t cpu_mask)
163 {
164 	size_t idx = it / NUM_INTS_PER_REG;
165 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
166 	uint32_t target, target_shift;
167 
168 	assert(it <= gic.max_it); /* Not too large */
169 	/* Assigned to group0 */
170 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
171 
172 	/* Route it to selected CPUs */
173 	target = read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
174 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
175 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
176 	target |= cpu_mask << target_shift;
177 	DMSG("cpu_mask: writing 0x%x to 0x%x\n",
178 		target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
179 	write32(target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
180 	DMSG("cpu_mask: 0x%x\n",
181 		read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)));
182 }
183 
184 void gic_it_set_prio(size_t it, uint8_t prio)
185 {
186 	size_t idx = it / NUM_INTS_PER_REG;
187 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
188 
189 	assert(it <= gic.max_it); /* Not too large */
190 	/* Assigned to group0 */
191 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
192 
193 	/* Set prio it to selected CPUs */
194 	DMSG("prio: writing 0x%x to 0x%x\n",
195 		prio, gic.gicd_base + GICD_IPRIORITYR(0) + it);
196 	write8(prio, gic.gicd_base + GICD_IPRIORITYR(0) + it);
197 }
198 
199 void gic_it_enable(size_t it)
200 {
201 	size_t idx = it / NUM_INTS_PER_REG;
202 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
203 
204 	assert(it <= gic.max_it); /* Not too large */
205 	/* Assigned to group0 */
206 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
207 	/* Not enabled yet */
208 	assert(!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask));
209 
210 	/* Enable the interrupt */
211 	write32(mask, gic.gicd_base + GICD_ISENABLER(idx));
212 }
213 
214 void gic_it_disable(size_t it)
215 {
216 	size_t idx = it / NUM_INTS_PER_REG;
217 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
218 
219 	assert(it <= gic.max_it); /* Not too large */
220 	/* Assigned to group0 */
221 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
222 
223 	/* Disable the interrupt */
224 	write32(mask, gic.gicd_base + GICD_ICENABLER(idx));
225 }
226 
227 uint32_t gic_read_iar(void)
228 {
229 	return read32(gic.gicc_base + GICC_IAR);
230 }
231 
232 void gic_write_eoir(uint32_t eoir)
233 {
234 	write32(eoir, gic.gicc_base + GICC_EOIR);
235 }
236 
237 bool gic_it_is_enabled(size_t it) {
238 	size_t idx = it / NUM_INTS_PER_REG;
239 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
240 	return !!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask);
241 }
242 
243 bool gic_it_get_group(size_t it) {
244 	size_t idx = it / NUM_INTS_PER_REG;
245 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
246 	return !!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask);
247 }
248 
249 uint32_t gic_it_get_target(size_t it) {
250 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
251 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
252 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
253 	uint32_t target =
254 		read32(gic.gicd_base + GICD_ITARGETSR(reg_idx)) & target_mask;
255 	target = target >> target_shift;
256 	return target;
257 }
258 
259 void gic_dump_state(void)
260 {
261 	int i;
262 	DMSG("GICC_CTLR: 0x%x", read32(gic.gicc_base + GICC_CTLR));
263 	DMSG("GICD_CTLR: 0x%x", read32(gic.gicd_base + GICD_CTLR));
264 
265 	for (i = 0; i < (int)gic.max_it; i++) {
266 		if (gic_it_is_enabled(i)) {
267 			DMSG("irq%d: enabled, group:%d, target:%x", i,
268 				gic_it_get_group(i), gic_it_get_target(i));
269 		}
270 	}
271 }
272