blob: bc4c1d165884b6b94d61c81da960214b1c6a8399 [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
Soby Mathewe063d3c2015-10-07 09:45:27 +0100117/*******************************************************************************
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100118 * Helper function to configure properties of secure G0 SPIs.
119 ******************************************************************************/
120void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
121 const interrupt_prop_t *interrupt_props,
122 unsigned int interrupt_props_num)
123{
124 unsigned int i;
125 const interrupt_prop_t *prop_desc;
126
127 /* Make sure there's a valid property array */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100128 if (interrupt_props_num != 0U)
129 assert(interrupt_props != NULL);
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100130
131 for (i = 0; i < interrupt_props_num; i++) {
132 prop_desc = &interrupt_props[i];
133
134 if (prop_desc->intr_num < MIN_SPI_ID)
135 continue;
136
137 /* Configure this interrupt as a secure interrupt */
138 assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
139 gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
140
141 /* Set the priority of this interrupt */
142 gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
143 prop_desc->intr_pri);
144
145 /* Target the secure interrupts to primary CPU */
146 gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
147 gicv2_get_cpuif_id(gicd_base));
148
149 /* Set interrupt configuration */
150 gicd_set_icfgr(gicd_base, prop_desc->intr_num,
151 prop_desc->intr_cfg);
152
153 /* Enable this interrupt */
154 gicd_set_isenabler(gicd_base, prop_desc->intr_num);
155 }
156}
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100157
158/*******************************************************************************
159 * Helper function to configure properties of secure G0 SGIs and PPIs.
160 ******************************************************************************/
161void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
162 const interrupt_prop_t *interrupt_props,
163 unsigned int interrupt_props_num)
164{
165 unsigned int i;
166 uint32_t sec_ppi_sgi_mask = 0;
167 const interrupt_prop_t *prop_desc;
168
169 /* Make sure there's a valid property array */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100170 if (interrupt_props_num != 0U)
171 assert(interrupt_props != NULL);
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100172
173 /*
174 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
175 * more scalable approach as it avoids clearing the enable bits in the
176 * GICD_CTLR.
177 */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100178 gicd_write_icenabler(gicd_base, 0U, ~0U);
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100179
180 /* Setup the default PPI/SGI priorities doing four at a time */
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100181 for (i = 0U; i < MIN_SPI_ID; i += 4U)
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100182 gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
183
Antonio Nino Diazca994e72018-08-21 10:02:33 +0100184 for (i = 0U; i < interrupt_props_num; i++) {
Jeenu Viswambharanaeb267c2017-09-22 08:32:09 +0100185 prop_desc = &interrupt_props[i];
186
187 if (prop_desc->intr_num >= MIN_SPI_ID)
188 continue;
189
190 /* Configure this interrupt as a secure interrupt */
191 assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
192
193 /*
194 * Set interrupt configuration for PPIs. Configuration for SGIs
195 * are ignored.
196 */
197 if ((prop_desc->intr_num >= MIN_PPI_ID) &&
198 (prop_desc->intr_num < MIN_SPI_ID)) {
199 gicd_set_icfgr(gicd_base, prop_desc->intr_num,
200 prop_desc->intr_cfg);
201 }
202
203 /* We have an SGI or a PPI. They are Group0 at reset */
204 sec_ppi_sgi_mask |= (1u << prop_desc->intr_num);
205
206 /* Set the priority of this interrupt */
207 gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
208 prop_desc->intr_pri);
209 }
210
211 /*
212 * Invert the bitmask to create a mask for non-secure PPIs and SGIs.
213 * Program the GICD_IGROUPR0 with this bit mask.
214 */
215 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
216
217 /* Enable the Group 0 SGIs and PPIs */
218 gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
219}