blob: 221f1b539a426038aba89338625ad302a8abc72d [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;
Antonio Nino Diazca994e72018-08-21 10:02:33 +010097 num_ints = (num_ints + 1U) << 5;
Soby Mathewe063d3c2015-10-07 09:45:27 +010098
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 */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100103 for (index = MIN_SPI_ID; index < num_ints; index += 32U)
Soby Mathewe063d3c2015-10-07 09:45:27 +0100104 gicd_write_igroupr(gicd_base, index, ~0U);
105
106 /* Setup the default SPI priorities doing four at a time */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100107 for (index = MIN_SPI_ID; index < num_ints; index += 4U)
Soby Mathewe063d3c2015-10-07 09:45:27 +0100108 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 */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100113 for (index = MIN_SPI_ID; index < num_ints; index += 16U)
114 gicd_write_icfgr(gicd_base, index, 0U);
Soby Mathewe063d3c2015-10-07 09:45:27 +0100115}
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 */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100128 if (num_ints != 0U)
129 assert(sec_intr_list != NULL);
Soby Mathewe063d3c2015-10-07 09:45:27 +0100130
131 for (index = 0; index < num_ints; index++) {
132 irq_num = sec_intr_list[index];
133 if (irq_num >= MIN_SPI_ID) {
134 /* Configure this interrupt as a secure interrupt */
135 gicd_clr_igroupr(gicd_base, irq_num);
136
137 /* Set the priority of this interrupt */
Soby Mathew421259e2016-01-15 14:20:57 +0000138 gicd_set_ipriorityr(gicd_base,
Soby Mathewe063d3c2015-10-07 09:45:27 +0100139 irq_num,
140 GIC_HIGHEST_SEC_PRIORITY);
141
142 /* Target the secure interrupts to primary CPU */
143 gicd_set_itargetsr(gicd_base, irq_num,
144 gicv2_get_cpuif_id(gicd_base));
145
146 /* Enable this interrupt */
147 gicd_set_isenabler(gicd_base, irq_num);
148 }
149 }
150
151}
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100152#endif
Soby Mathewe063d3c2015-10-07 09:45:27 +0100153
154/*******************************************************************************
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100155 * Helper function to configure properties of secure G0 SPIs.
156 ******************************************************************************/
157void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
158 const interrupt_prop_t *interrupt_props,
159 unsigned int interrupt_props_num)
160{
161 unsigned int i;
162 const interrupt_prop_t *prop_desc;
163
164 /* Make sure there's a valid property array */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100165 if (interrupt_props_num != 0U)
166 assert(interrupt_props != NULL);
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100167
168 for (i = 0; i < interrupt_props_num; i++) {
169 prop_desc = &interrupt_props[i];
170
171 if (prop_desc->intr_num < MIN_SPI_ID)
172 continue;
173
174 /* Configure this interrupt as a secure interrupt */
175 assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
176 gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
177
178 /* Set the priority of this interrupt */
179 gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
180 prop_desc->intr_pri);
181
182 /* Target the secure interrupts to primary CPU */
183 gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
184 gicv2_get_cpuif_id(gicd_base));
185
186 /* Set interrupt configuration */
187 gicd_set_icfgr(gicd_base, prop_desc->intr_num,
188 prop_desc->intr_cfg);
189
190 /* Enable this interrupt */
191 gicd_set_isenabler(gicd_base, prop_desc->intr_num);
192 }
193}
194
195#if !ERROR_DEPRECATED
196/*******************************************************************************
Soby Mathewe063d3c2015-10-07 09:45:27 +0100197 * Helper function to configure secure G0 SGIs and PPIs.
198 ******************************************************************************/
199void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
200 unsigned int num_ints,
201 const unsigned int *sec_intr_list)
202{
203 unsigned int index, irq_num, sec_ppi_sgi_mask = 0;
204
205 /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
206 assert(num_ints ? (uintptr_t)sec_intr_list : 1);
207
208 /*
209 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
210 * more scalable approach as it avoids clearing the enable bits in the
211 * GICD_CTLR.
212 */
213 gicd_write_icenabler(gicd_base, 0, ~0);
214
215 /* Setup the default PPI/SGI priorities doing four at a time */
216 for (index = 0; index < MIN_SPI_ID; index += 4)
217 gicd_write_ipriorityr(gicd_base,
218 index,
219 GICD_IPRIORITYR_DEF_VAL);
220
221 for (index = 0; index < num_ints; index++) {
222 irq_num = sec_intr_list[index];
223 if (irq_num < MIN_SPI_ID) {
224 /* We have an SGI or a PPI. They are Group0 at reset */
225 sec_ppi_sgi_mask |= 1U << irq_num;
226
227 /* Set the priority of this interrupt */
Soby Mathew421259e2016-01-15 14:20:57 +0000228 gicd_set_ipriorityr(gicd_base,
Soby Mathewe063d3c2015-10-07 09:45:27 +0100229 irq_num,
230 GIC_HIGHEST_SEC_PRIORITY);
231 }
232 }
233
234 /*
235 * Invert the bitmask to create a mask for non-secure PPIs and
236 * SGIs. Program the GICD_IGROUPR0 with this bit mask.
237 */
238 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
239
240 /* Enable the Group 0 SGIs and PPIs */
241 gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
242}
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100243#endif
244
245/*******************************************************************************
246 * Helper function to configure properties of secure G0 SGIs and PPIs.
247 ******************************************************************************/
248void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
249 const interrupt_prop_t *interrupt_props,
250 unsigned int interrupt_props_num)
251{
252 unsigned int i;
253 uint32_t sec_ppi_sgi_mask = 0;
254 const interrupt_prop_t *prop_desc;
255
256 /* Make sure there's a valid property array */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100257 if (interrupt_props_num != 0U)
258 assert(interrupt_props != NULL);
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100259
260 /*
261 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
262 * more scalable approach as it avoids clearing the enable bits in the
263 * GICD_CTLR.
264 */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100265 gicd_write_icenabler(gicd_base, 0U, ~0U);
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100266
267 /* Setup the default PPI/SGI priorities doing four at a time */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100268 for (i = 0U; i < MIN_SPI_ID; i += 4U)
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100269 gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
270
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100271 for (i = 0U; i < interrupt_props_num; i++) {
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100272 prop_desc = &interrupt_props[i];
273
274 if (prop_desc->intr_num >= MIN_SPI_ID)
275 continue;
276
277 /* Configure this interrupt as a secure interrupt */
278 assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
279
280 /*
281 * Set interrupt configuration for PPIs. Configuration for SGIs
282 * are ignored.
283 */
284 if ((prop_desc->intr_num >= MIN_PPI_ID) &&
285 (prop_desc->intr_num < MIN_SPI_ID)) {
286 gicd_set_icfgr(gicd_base, prop_desc->intr_num,
287 prop_desc->intr_cfg);
288 }
289
290 /* We have an SGI or a PPI. They are Group0 at reset */
291 sec_ppi_sgi_mask |= (1u << prop_desc->intr_num);
292
293 /* Set the priority of this interrupt */
294 gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
295 prop_desc->intr_pri);
296 }
297
298 /*
299 * Invert the bitmask to create a mask for non-secure PPIs and SGIs.
300 * Program the GICD_IGROUPR0 with this bit mask.
301 */
302 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
303
304 /* Enable the Group 0 SGIs and PPIs */
305 gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
306}