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