• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch.h>
8 #include <arch_helpers.h>
9 #include <assert.h>
10 #include <debug.h>
11 #include <gic_common.h>
12 #include <interrupt_props.h>
13 #include "../common/gic_common_private.h"
14 #include "gicv2_private.h"
15 
16 /*
17  * Accessor to read the GIC Distributor ITARGETSR corresponding to the
18  * interrupt `id`, 4 interrupt IDs at a time.
19  */
gicd_read_itargetsr(uintptr_t base,unsigned int id)20 unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id)
21 {
22 	unsigned n = id >> ITARGETSR_SHIFT;
23 	return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
24 }
25 
26 /*
27  * Accessor to read the GIC Distributor CPENDSGIR corresponding to the
28  * interrupt `id`, 4 interrupt IDs at a time.
29  */
gicd_read_cpendsgir(uintptr_t base,unsigned int id)30 unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id)
31 {
32 	unsigned n = id >> CPENDSGIR_SHIFT;
33 	return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
34 }
35 
36 /*
37  * Accessor to read the GIC Distributor SPENDSGIR corresponding to the
38  * interrupt `id`, 4 interrupt IDs at a time.
39  */
gicd_read_spendsgir(uintptr_t base,unsigned int id)40 unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id)
41 {
42 	unsigned n = id >> SPENDSGIR_SHIFT;
43 	return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
44 }
45 
46 /*
47  * Accessor to write the GIC Distributor ITARGETSR corresponding to the
48  * interrupt `id`, 4 interrupt IDs at a time.
49  */
gicd_write_itargetsr(uintptr_t base,unsigned int id,unsigned int val)50 void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val)
51 {
52 	unsigned n = id >> ITARGETSR_SHIFT;
53 	mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
54 }
55 
56 /*
57  * Accessor to write the GIC Distributor CPENDSGIR corresponding to the
58  * interrupt `id`, 4 interrupt IDs at a time.
59  */
gicd_write_cpendsgir(uintptr_t base,unsigned int id,unsigned int val)60 void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val)
61 {
62 	unsigned n = id >> CPENDSGIR_SHIFT;
63 	mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
64 }
65 
66 /*
67  * Accessor to write the GIC Distributor SPENDSGIR corresponding to the
68  * interrupt `id`, 4 interrupt IDs at a time.
69  */
gicd_write_spendsgir(uintptr_t base,unsigned int id,unsigned int val)70 void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
71 {
72 	unsigned n = id >> SPENDSGIR_SHIFT;
73 	mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
74 }
75 
76 /*******************************************************************************
77  * Get the current CPU bit mask from GICD_ITARGETSR0
78  ******************************************************************************/
gicv2_get_cpuif_id(uintptr_t base)79 unsigned int gicv2_get_cpuif_id(uintptr_t base)
80 {
81 	unsigned int val;
82 
83 	val = gicd_read_itargetsr(base, 0);
84 	return val & GIC_TARGET_CPU_MASK;
85 }
86 
87 /*******************************************************************************
88  * Helper function to configure the default attributes of SPIs.
89  ******************************************************************************/
gicv2_spis_configure_defaults(uintptr_t gicd_base)90 void gicv2_spis_configure_defaults(uintptr_t gicd_base)
91 {
92 	unsigned int index, num_ints;
93 
94 	num_ints = gicd_read_typer(gicd_base);
95 	num_ints &= TYPER_IT_LINES_NO_MASK;
96 	num_ints = (num_ints + 1) << 5;
97 
98 	/*
99 	 * Treat all SPIs as G1NS by default. The number of interrupts is
100 	 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
101 	 */
102 	for (index = MIN_SPI_ID; index < num_ints; index += 32)
103 		gicd_write_igroupr(gicd_base, index, ~0U);
104 
105 	/* Setup the default SPI priorities doing four at a time */
106 	for (index = MIN_SPI_ID; index < num_ints; index += 4)
107 		gicd_write_ipriorityr(gicd_base,
108 				      index,
109 				      GICD_IPRIORITYR_DEF_VAL);
110 
111 	/* Treat all SPIs as level triggered by default, 16 at a time */
112 	for (index = MIN_SPI_ID; index < num_ints; index += 16)
113 		gicd_write_icfgr(gicd_base, index, 0);
114 }
115 
116 #if !ERROR_DEPRECATED
117 /*******************************************************************************
118  * Helper function to configure secure G0 SPIs.
119  ******************************************************************************/
gicv2_secure_spis_configure(uintptr_t gicd_base,unsigned int num_ints,const unsigned int * sec_intr_list)120 void gicv2_secure_spis_configure(uintptr_t gicd_base,
121 				     unsigned int num_ints,
122 				     const unsigned int *sec_intr_list)
123 {
124 	unsigned int index, irq_num;
125 
126 	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
127 	assert(num_ints ? (uintptr_t)sec_intr_list : 1);
128 
129 	for (index = 0; index < num_ints; index++) {
130 		irq_num = sec_intr_list[index];
131 		if (irq_num >= MIN_SPI_ID) {
132 			/* Configure this interrupt as a secure interrupt */
133 			gicd_clr_igroupr(gicd_base, irq_num);
134 
135 			/* Set the priority of this interrupt */
136 			gicd_set_ipriorityr(gicd_base,
137 					      irq_num,
138 					      GIC_HIGHEST_SEC_PRIORITY);
139 
140 			/* Target the secure interrupts to primary CPU */
141 			gicd_set_itargetsr(gicd_base, irq_num,
142 					gicv2_get_cpuif_id(gicd_base));
143 
144 			/* Enable this interrupt */
145 			gicd_set_isenabler(gicd_base, irq_num);
146 		}
147 	}
148 
149 }
150 #endif
151 
152 /*******************************************************************************
153  * Helper function to configure properties of secure G0 SPIs.
154  ******************************************************************************/
gicv2_secure_spis_configure_props(uintptr_t gicd_base,const interrupt_prop_t * interrupt_props,unsigned int interrupt_props_num)155 void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
156 		const interrupt_prop_t *interrupt_props,
157 		unsigned int interrupt_props_num)
158 {
159 	unsigned int i;
160 	const interrupt_prop_t *prop_desc;
161 
162 	/* Make sure there's a valid property array */
163 	assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1);
164 
165 	for (i = 0; i < interrupt_props_num; i++) {
166 		prop_desc = &interrupt_props[i];
167 
168 		if (prop_desc->intr_num < MIN_SPI_ID)
169 			continue;
170 
171 		/* Configure this interrupt as a secure interrupt */
172 		assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
173 		gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
174 
175 		/* Set the priority of this interrupt */
176 		gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
177 				prop_desc->intr_pri);
178 
179 		/* Target the secure interrupts to primary CPU */
180 		gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
181 				gicv2_get_cpuif_id(gicd_base));
182 
183 		/* Set interrupt configuration */
184 		gicd_set_icfgr(gicd_base, prop_desc->intr_num,
185 				prop_desc->intr_cfg);
186 
187 		/* Enable this interrupt */
188 		gicd_set_isenabler(gicd_base, prop_desc->intr_num);
189 	}
190 }
191 
192 #if !ERROR_DEPRECATED
193 /*******************************************************************************
194  * Helper function to configure secure G0 SGIs and PPIs.
195  ******************************************************************************/
gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,unsigned int num_ints,const unsigned int * sec_intr_list)196 void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
197 					unsigned int num_ints,
198 					const unsigned int *sec_intr_list)
199 {
200 	unsigned int index, irq_num, sec_ppi_sgi_mask = 0;
201 
202 	/* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
203 	assert(num_ints ? (uintptr_t)sec_intr_list : 1);
204 
205 	/*
206 	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
207 	 * more scalable approach as it avoids clearing the enable bits in the
208 	 * GICD_CTLR.
209 	 */
210 	gicd_write_icenabler(gicd_base, 0, ~0);
211 
212 	/* Setup the default PPI/SGI priorities doing four at a time */
213 	for (index = 0; index < MIN_SPI_ID; index += 4)
214 		gicd_write_ipriorityr(gicd_base,
215 				      index,
216 				      GICD_IPRIORITYR_DEF_VAL);
217 
218 	for (index = 0; index < num_ints; index++) {
219 		irq_num = sec_intr_list[index];
220 		if (irq_num < MIN_SPI_ID) {
221 			/* We have an SGI or a PPI. They are Group0 at reset */
222 			sec_ppi_sgi_mask |= 1U << irq_num;
223 
224 			/* Set the priority of this interrupt */
225 			gicd_set_ipriorityr(gicd_base,
226 					    irq_num,
227 					    GIC_HIGHEST_SEC_PRIORITY);
228 		}
229 	}
230 
231 	/*
232 	 * Invert the bitmask to create a mask for non-secure PPIs and
233 	 * SGIs. Program the GICD_IGROUPR0 with this bit mask.
234 	 */
235 	gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
236 
237 	/* Enable the Group 0 SGIs and PPIs */
238 	gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
239 }
240 #endif
241 
242 /*******************************************************************************
243  * Helper function to configure properties of secure G0 SGIs and PPIs.
244  ******************************************************************************/
gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,const interrupt_prop_t * interrupt_props,unsigned int interrupt_props_num)245 void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
246 		const interrupt_prop_t *interrupt_props,
247 		unsigned int interrupt_props_num)
248 {
249 	unsigned int i;
250 	uint32_t sec_ppi_sgi_mask = 0;
251 	const interrupt_prop_t *prop_desc;
252 
253 	/* Make sure there's a valid property array */
254 	assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1);
255 
256 	/*
257 	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
258 	 * more scalable approach as it avoids clearing the enable bits in the
259 	 * GICD_CTLR.
260 	 */
261 	gicd_write_icenabler(gicd_base, 0, ~0);
262 
263 	/* Setup the default PPI/SGI priorities doing four at a time */
264 	for (i = 0; i < MIN_SPI_ID; i += 4)
265 		gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
266 
267 	for (i = 0; i < interrupt_props_num; i++) {
268 		prop_desc = &interrupt_props[i];
269 
270 		if (prop_desc->intr_num >= MIN_SPI_ID)
271 			continue;
272 
273 		/* Configure this interrupt as a secure interrupt */
274 		assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
275 
276 		/*
277 		 * Set interrupt configuration for PPIs. Configuration for SGIs
278 		 * are ignored.
279 		 */
280 		if ((prop_desc->intr_num >= MIN_PPI_ID) &&
281 				(prop_desc->intr_num < MIN_SPI_ID)) {
282 			gicd_set_icfgr(gicd_base, prop_desc->intr_num,
283 					prop_desc->intr_cfg);
284 		}
285 
286 		/* We have an SGI or a PPI. They are Group0 at reset */
287 		sec_ppi_sgi_mask |= (1u << prop_desc->intr_num);
288 
289 		/* Set the priority of this interrupt */
290 		gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
291 				prop_desc->intr_pri);
292 	}
293 
294 	/*
295 	 * Invert the bitmask to create a mask for non-secure PPIs and SGIs.
296 	 * Program the GICD_IGROUPR0 with this bit mask.
297 	 */
298 	gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
299 
300 	/* Enable the Group 0 SGIs and PPIs */
301 	gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
302 }
303