blob: 0df50fb008d897eddb83aa488ffa731b625dd80f [file] [log] [blame]
Soby Mathewe063d3c2015-10-07 09:45:27 +01001/*
Jeenu Viswambharandce70b32017-09-22 08:32:09 +01002 * Copyright (c) 2015-2017, 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>
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +010012#include <interrupt_props.h>
Soby Mathew50f6fe42016-02-01 17:59:22 +000013#include "../common/gic_common_private.h"
Soby Mathewe063d3c2015-10-07 09:45:27 +010014#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 */
20unsigned 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 */
30unsigned 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 */
40unsigned 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 */
50void 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 */
60void 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 */
70void 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
Soby Mathewe063d3c2015-10-07 09:45:27 +010076/*******************************************************************************
77 * Get the current CPU bit mask from GICD_ITARGETSR0
78 ******************************************************************************/
79unsigned 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 ******************************************************************************/
90void 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
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100116#if !ERROR_DEPRECATED
Soby Mathewe063d3c2015-10-07 09:45:27 +0100117/*******************************************************************************
118 * Helper function to configure secure G0 SPIs.
119 ******************************************************************************/
120void 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 */
Soby Mathew421259e2016-01-15 14:20:57 +0000136 gicd_set_ipriorityr(gicd_base,
Soby Mathewe063d3c2015-10-07 09:45:27 +0100137 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}
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100150#endif
Soby Mathewe063d3c2015-10-07 09:45:27 +0100151
152/*******************************************************************************
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100153 * Helper function to configure properties of secure G0 SPIs.
154 ******************************************************************************/
155void 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/*******************************************************************************
Soby Mathewe063d3c2015-10-07 09:45:27 +0100194 * Helper function to configure secure G0 SGIs and PPIs.
195 ******************************************************************************/
196void 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 */
Soby Mathew421259e2016-01-15 14:20:57 +0000225 gicd_set_ipriorityr(gicd_base,
Soby Mathewe063d3c2015-10-07 09:45:27 +0100226 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}
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100240#endif
241
242/*******************************************************************************
243 * Helper function to configure properties of secure G0 SGIs and PPIs.
244 ******************************************************************************/
245void 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}