blob: 1f904c5166590972fdefcec26cfd4ede5980c61f [file] [log] [blame]
Soby Mathewe063d3c2015-10-07 09:45:27 +01001/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch.h>
32#include <arch_helpers.h>
33#include <assert.h>
34#include <debug.h>
35#include <gic_common.h>
36#include "gicv2_private.h"
37
38/*
39 * Accessor to read the GIC Distributor ITARGETSR corresponding to the
40 * interrupt `id`, 4 interrupt IDs at a time.
41 */
42unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id)
43{
44 unsigned n = id >> ITARGETSR_SHIFT;
45 return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
46}
47
48/*
49 * Accessor to read the GIC Distributor CPENDSGIR corresponding to the
50 * interrupt `id`, 4 interrupt IDs at a time.
51 */
52unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id)
53{
54 unsigned n = id >> CPENDSGIR_SHIFT;
55 return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
56}
57
58/*
59 * Accessor to read the GIC Distributor SPENDSGIR corresponding to the
60 * interrupt `id`, 4 interrupt IDs at a time.
61 */
62unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id)
63{
64 unsigned n = id >> SPENDSGIR_SHIFT;
65 return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
66}
67
68/*
69 * Accessor to write the GIC Distributor ITARGETSR corresponding to the
70 * interrupt `id`, 4 interrupt IDs at a time.
71 */
72void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val)
73{
74 unsigned n = id >> ITARGETSR_SHIFT;
75 mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
76}
77
78/*
79 * Accessor to write the GIC Distributor CPENDSGIR corresponding to the
80 * interrupt `id`, 4 interrupt IDs at a time.
81 */
82void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val)
83{
84 unsigned n = id >> CPENDSGIR_SHIFT;
85 mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
86}
87
88/*
89 * Accessor to write the GIC Distributor SPENDSGIR corresponding to the
90 * interrupt `id`, 4 interrupt IDs at a time.
91 */
92void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
93{
94 unsigned n = id >> SPENDSGIR_SHIFT;
95 mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
96}
97
98/*
99 * Accessor to write the GIC Distributor ITARGETSR corresponding to the
100 * interrupt `id`.
101 */
102void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target)
103{
104 unsigned byte_off = id & ((1 << ITARGETSR_SHIFT) - 1);
105 unsigned int reg_val = gicd_read_itargetsr(base, id);
106
107 gicd_write_itargetsr(base, id, reg_val | (target << (byte_off << 3)));
108}
109
110/*******************************************************************************
111 * Get the current CPU bit mask from GICD_ITARGETSR0
112 ******************************************************************************/
113unsigned int gicv2_get_cpuif_id(uintptr_t base)
114{
115 unsigned int val;
116
117 val = gicd_read_itargetsr(base, 0);
118 return val & GIC_TARGET_CPU_MASK;
119}
120
121/*******************************************************************************
122 * Helper function to configure the default attributes of SPIs.
123 ******************************************************************************/
124void gicv2_spis_configure_defaults(uintptr_t gicd_base)
125{
126 unsigned int index, num_ints;
127
128 num_ints = gicd_read_typer(gicd_base);
129 num_ints &= TYPER_IT_LINES_NO_MASK;
130 num_ints = (num_ints + 1) << 5;
131
132 /*
133 * Treat all SPIs as G1NS by default. The number of interrupts is
134 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
135 */
136 for (index = MIN_SPI_ID; index < num_ints; index += 32)
137 gicd_write_igroupr(gicd_base, index, ~0U);
138
139 /* Setup the default SPI priorities doing four at a time */
140 for (index = MIN_SPI_ID; index < num_ints; index += 4)
141 gicd_write_ipriorityr(gicd_base,
142 index,
143 GICD_IPRIORITYR_DEF_VAL);
144
145 /* Treat all SPIs as level triggered by default, 16 at a time */
146 for (index = MIN_SPI_ID; index < num_ints; index += 16)
147 gicd_write_icfgr(gicd_base, index, 0);
148}
149
150/*******************************************************************************
151 * Helper function to configure secure G0 SPIs.
152 ******************************************************************************/
153void gicv2_secure_spis_configure(uintptr_t gicd_base,
154 unsigned int num_ints,
155 const unsigned int *sec_intr_list)
156{
157 unsigned int index, irq_num;
158
159 /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
160 assert(num_ints ? (uintptr_t)sec_intr_list : 1);
161
162 for (index = 0; index < num_ints; index++) {
163 irq_num = sec_intr_list[index];
164 if (irq_num >= MIN_SPI_ID) {
165 /* Configure this interrupt as a secure interrupt */
166 gicd_clr_igroupr(gicd_base, irq_num);
167
168 /* Set the priority of this interrupt */
169 gicd_write_ipriorityr(gicd_base,
170 irq_num,
171 GIC_HIGHEST_SEC_PRIORITY);
172
173 /* Target the secure interrupts to primary CPU */
174 gicd_set_itargetsr(gicd_base, irq_num,
175 gicv2_get_cpuif_id(gicd_base));
176
177 /* Enable this interrupt */
178 gicd_set_isenabler(gicd_base, irq_num);
179 }
180 }
181
182}
183
184/*******************************************************************************
185 * Helper function to configure secure G0 SGIs and PPIs.
186 ******************************************************************************/
187void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base,
188 unsigned int num_ints,
189 const unsigned int *sec_intr_list)
190{
191 unsigned int index, irq_num, sec_ppi_sgi_mask = 0;
192
193 /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */
194 assert(num_ints ? (uintptr_t)sec_intr_list : 1);
195
196 /*
197 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
198 * more scalable approach as it avoids clearing the enable bits in the
199 * GICD_CTLR.
200 */
201 gicd_write_icenabler(gicd_base, 0, ~0);
202
203 /* Setup the default PPI/SGI priorities doing four at a time */
204 for (index = 0; index < MIN_SPI_ID; index += 4)
205 gicd_write_ipriorityr(gicd_base,
206 index,
207 GICD_IPRIORITYR_DEF_VAL);
208
209 for (index = 0; index < num_ints; index++) {
210 irq_num = sec_intr_list[index];
211 if (irq_num < MIN_SPI_ID) {
212 /* We have an SGI or a PPI. They are Group0 at reset */
213 sec_ppi_sgi_mask |= 1U << irq_num;
214
215 /* Set the priority of this interrupt */
216 gicd_write_ipriorityr(gicd_base,
217 irq_num,
218 GIC_HIGHEST_SEC_PRIORITY);
219 }
220 }
221
222 /*
223 * Invert the bitmask to create a mask for non-secure PPIs and
224 * SGIs. Program the GICD_IGROUPR0 with this bit mask.
225 */
226 gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
227
228 /* Enable the Group 0 SGIs and PPIs */
229 gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
230}