xref: /optee_os/core/drivers/gic.c (revision cebdec51cd247c389354e29be2af9059daa973aa)
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 <kernel/tee_core_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 
85 	/*
86 	 * Probe which interrupt number is the largest.
87 	 */
88 	old_ctlr = read32(gic.gicc_base + GICC_CTLR);
89 	write32(0, gic.gicc_base + GICC_CTLR);
90 	for (i = GIC_MAX_INTS / NUM_INTS_PER_REG; i > 0; i--) {
91 		uint32_t old_reg;
92 		uint32_t reg;
93 		int b;
94 
95 		old_reg = read32(gic.gicd_base + GICD_ISENABLER(i));
96 		write32(0xffffffff, gic.gicd_base + GICD_ISENABLER(i));
97 		reg = read32(gic.gicd_base + GICD_ISENABLER(i));
98 		write32(old_reg, gic.gicd_base + GICD_ICENABLER(i));
99 		for (b = NUM_INTS_PER_REG - 1; b > 0; b--) {
100 			if ((1 << b) & reg) {
101 				ret = i * NUM_INTS_PER_REG + b;
102 				goto out;
103 			}
104 		}
105 	}
106 out:
107 	write32(old_ctlr, gic.gicc_base + GICC_CTLR);
108 	return ret;
109 }
110 
111 void gic_init(vaddr_t gicc_base, vaddr_t gicd_base)
112 {
113 	size_t n;
114 
115 	gic.gicc_base = gicc_base;
116 	gic.gicd_base = gicd_base;
117 	gic.max_it = probe_max_it();
118 
119 	for (n = 0; n <= gic.max_it / NUM_INTS_PER_REG; n++) {
120 		/* Disable interrupts */
121 		write32(0xffffffff, gic.gicd_base + GICD_ICENABLER(n));
122 
123 		/* Make interrupts non-pending */
124 		write32(0xffffffff, gic.gicd_base + GICD_ICPENDR(n));
125 
126 		/* Mark interrupts non-secure */
127 		write32(0xffffffff, gic.gicd_base + GICD_IGROUPR(n));
128 	}
129 
130 	/* Enable GIC */
131 	write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
132 		gic.gicc_base + GICC_CTLR);
133 	write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1,
134 		gic.gicd_base + GICD_CTLR);
135 }
136 
137 void gic_init_base_addr(vaddr_t gicc_base, vaddr_t gicd_base)
138 {
139 	gic.gicc_base = gicc_base;
140 	gic.gicd_base = gicd_base;
141 	gic.max_it = probe_max_it();
142 }
143 
144 void gic_it_add(size_t it)
145 {
146 	size_t idx = it / NUM_INTS_PER_REG;
147 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
148 
149 	assert(it <= gic.max_it); /* Not too large */
150 
151 	/* Disable the interrupt */
152 	write32(mask, gic.gicd_base + GICD_ICENABLER(idx));
153 	/* Make it non-pending */
154 	write32(mask, gic.gicd_base + GICD_ICPENDR(idx));
155 	/* Assign it to group0 */
156 	write32(read32(gic.gicd_base + GICD_IGROUPR(idx)) & ~mask,
157 			gic.gicd_base + GICD_IGROUPR(idx));
158 }
159 
160 void gic_it_set_cpu_mask(size_t it, uint8_t cpu_mask)
161 {
162 	size_t idx = it / NUM_INTS_PER_REG;
163 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
164 	uint32_t target, target_shift;
165 
166 	assert(it <= gic.max_it); /* Not too large */
167 	/* Assigned to group0 */
168 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
169 
170 	/* Route it to selected CPUs */
171 	target = read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
172 	target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
173 	target &= ~(ITARGETSR_FIELD_MASK << target_shift);
174 	target |= cpu_mask << target_shift;
175 	DMSG("cpu_mask: writing 0x%x to 0x%x\n",
176 		target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
177 	write32(target, gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
178 	DMSG("cpu_mask: 0x%x\n",
179 		read32(gic.gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)));
180 }
181 
182 void gic_it_set_prio(size_t it, uint8_t prio)
183 {
184 	size_t idx = it / NUM_INTS_PER_REG;
185 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
186 
187 	assert(it <= gic.max_it); /* Not too large */
188 	/* Assigned to group0 */
189 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
190 
191 	/* Set prio it to selected CPUs */
192 	DMSG("prio: writing 0x%x to 0x%x\n",
193 		prio, gic.gicd_base + GICD_IPRIORITYR(0) + it);
194 	write8(prio, gic.gicd_base + GICD_IPRIORITYR(0) + it);
195 }
196 
197 void gic_it_enable(size_t it)
198 {
199 	size_t idx = it / NUM_INTS_PER_REG;
200 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
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 	/* Not enabled yet */
206 	assert(!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask));
207 
208 	/* Enable the interrupt */
209 	write32(mask, gic.gicd_base + GICD_ISENABLER(idx));
210 }
211 
212 void gic_it_disable(size_t it)
213 {
214 	size_t idx = it / NUM_INTS_PER_REG;
215 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
216 
217 	assert(it <= gic.max_it); /* Not too large */
218 	/* Assigned to group0 */
219 	assert(!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask));
220 
221 	/* Disable the interrupt */
222 	write32(mask, gic.gicd_base + GICD_ICENABLER(idx));
223 }
224 
225 uint32_t gic_read_iar(void)
226 {
227 	return read32(gic.gicc_base + GICC_IAR);
228 }
229 
230 void gic_write_eoir(uint32_t eoir)
231 {
232 	write32(eoir, gic.gicc_base + GICC_EOIR);
233 }
234 
235 bool gic_it_is_enabled(size_t it) {
236 	size_t idx = it / NUM_INTS_PER_REG;
237 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
238 	return !!(read32(gic.gicd_base + GICD_ISENABLER(idx)) & mask);
239 }
240 
241 bool gic_it_get_group(size_t it) {
242 	size_t idx = it / NUM_INTS_PER_REG;
243 	uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
244 	return !!(read32(gic.gicd_base + GICD_IGROUPR(idx)) & mask);
245 }
246 
247 uint32_t gic_it_get_target(size_t it) {
248 	size_t reg_idx = it / NUM_TARGETS_PER_REG;
249 	uint32_t target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
250 	uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
251 	uint32_t target =
252 		read32(gic.gicd_base + GICD_ITARGETSR(reg_idx)) & target_mask;
253 	target = target >> target_shift;
254 	return target;
255 }
256 
257 void gic_dump_state(void)
258 {
259 	int i;
260 	DMSG("GICC_CTLR: 0x%x", read32(gic.gicc_base + GICC_CTLR));
261 	DMSG("GICD_CTLR: 0x%x", read32(gic.gicd_base + GICD_CTLR));
262 
263 	for (i = 0; i < NUM_PPI; i++) {
264 		if (gic_it_is_enabled(i)) {
265 			DMSG("irq%d: enabled, group:%d, target:%x", i,
266 				gic_it_get_group(i), gic_it_get_target(i));
267 		}
268 	}
269 }
270