blob: 48ee29e2a05d8f630ea2ece812c6d167f5376174 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <arch_helpers.h>
9#include <arm_gic.h>
10#include <assert.h>
11#include <gic_common.h>
12#include <gic_v2.h>
13#include <mmio.h>
14#include <platform.h>
15
16/*
17 * Data structure to store the GIC per CPU context before entering
18 * system suspend. Only the GIC context of first 32 interrupts (SGIs and PPIs)
19 * will be saved. The GIC SPI context needs to be restored by the respective
20 * drivers. The GICC_PMR is not saved here as it will be reinitialized during
21 * GIC restore.
22 */
23struct gicv2_pcpu_ctx {
24 unsigned int gicc_ctlr;
25 unsigned int gicd_isenabler0;
26 unsigned int gicd_ipriorityr[NUM_PCPU_INTR >> IPRIORITYR_SHIFT];
27 unsigned int gicd_icfgr;
28};
29
30static struct gicv2_pcpu_ctx pcpu_gic_ctx[PLATFORM_CORE_COUNT];
31
32static uintptr_t gicc_base_addr;
33static uintptr_t gicd_base_addr;
34
35static unsigned int gic_cpu_id[PLATFORM_CORE_COUNT] = {UINT32_MAX};
36
37/* Helper function to convert core pos to gic id */
38static unsigned int core_pos_to_gic_id(unsigned int core_pos)
39{
40 assert(gic_cpu_id[core_pos] != UINT32_MAX);
41 return gic_cpu_id[core_pos];
42}
43
44/*******************************************************************************
45 * GIC Distributor interface accessors for reading entire registers
46 ******************************************************************************/
47unsigned int gicd_read_itargetsr(unsigned int base, unsigned int interrupt_id)
48{
49 unsigned n = interrupt_id >> ITARGETSR_SHIFT;
50 return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
51}
52
53unsigned int gicd_read_cpendsgir(unsigned int base, unsigned int interrupt_id)
54{
55 unsigned n = interrupt_id >> CPENDSGIR_SHIFT;
56 return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
57}
58
59unsigned int gicd_read_spendsgir(unsigned int base, unsigned int interrupt_id)
60{
61 unsigned n = interrupt_id >> SPENDSGIR_SHIFT;
62 return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
63}
64
65/*******************************************************************************
66 * GIC Distributor interface accessors for writing entire registers
67 ******************************************************************************/
68void gicd_write_itargetsr(unsigned int base,
69 unsigned int interrupt_id, unsigned int val)
70{
71 unsigned n = interrupt_id >> ITARGETSR_SHIFT;
72 mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
73}
74
75void gicd_write_itargetsr_byte(unsigned int base,
76 unsigned int interrupt_id, unsigned int val)
77{
78 mmio_write_8(base + GICD_ITARGETSR + interrupt_id, val);
79}
80
81void gicd_write_cpendsgir(unsigned int base,
82 unsigned int interrupt_id, unsigned int val)
83{
84 unsigned n = interrupt_id >> CPENDSGIR_SHIFT;
85 mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
86}
87
88void gicd_write_spendsgir(unsigned int base,
89 unsigned int interrupt_id, unsigned int val)
90{
91 unsigned n = interrupt_id >> SPENDSGIR_SHIFT;
92 mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
93}
94
95/*******************************************************************************
96 * GIC Distributor interface accessors for individual interrupt manipulation
97 ******************************************************************************/
98void gicd_set_itargetsr(unsigned int base,
99 unsigned int interrupt_id, unsigned int iface)
100{
101 mmio_write_8(base + GICD_ITARGETSR + interrupt_id, (1 << iface));
102}
103
104/******************************************************************************
105 * GICv2 public driver API
106 *****************************************************************************/
107
108void gicv2_enable_cpuif(void)
109{
110 unsigned int gicc_ctlr;
111
112 assert(gicc_base_addr);
113
114 /* Enable the GICC and disable bypass */
115 gicc_ctlr = GICC_CTLR_ENABLE | FIQ_BYP_DIS_GRP1
116 | IRQ_BYP_DIS_GRP1;
117 gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
118}
119
120void gicv2_probe_gic_cpu_id(void)
121{
122 unsigned int gicd_itargets_val, core_pos;
123
124 assert(gicd_base_addr);
125 core_pos = platform_get_core_pos(read_mpidr_el1());
126 gicd_itargets_val = gicd_read_itargetsr(gicd_base_addr, 0);
127
128 assert(gicd_itargets_val);
129
130 /* Convert the bit pos returned by read of ITARGETSR0 to GIC CPU ID */
131 gic_cpu_id[core_pos] = __builtin_ctz(gicd_itargets_val);
132}
133
134void gicv2_setup_cpuif(void)
135{
136 assert(gicc_base_addr);
137
138 /* Set the priority mask register to allow all interrupts to trickle in */
139 gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
140 gicv2_enable_cpuif();
141}
142
143void gicv2_disable_cpuif(void)
144{
145 unsigned int gicc_ctlr;
146
147 assert(gicc_base_addr);
148
149 /* Disable non-secure interrupts and disable their bypass */
150 gicc_ctlr = gicc_read_ctlr(gicc_base_addr);
151 gicc_ctlr &= ~GICC_CTLR_ENABLE;
152 gicc_ctlr |= FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
153 gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
154}
155
156void gicv2_save_cpuif_context(void)
157{
158 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
159
160 assert(gicc_base_addr);
161 pcpu_gic_ctx[core_pos].gicc_ctlr =
162 gicc_read_ctlr(gicc_base_addr);
163}
164
165void gicv2_restore_cpuif_context(void)
166{
167 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
168
169 assert(gicc_base_addr);
170
171 /* The GICC_PMR is never modified, hence we initialize this register */
172 gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
173
174 gicc_write_ctlr(gicc_base_addr,
175 pcpu_gic_ctx[core_pos].gicc_ctlr);
176}
177
178void gicv2_setup_distif(void)
179{
180 unsigned int gicd_ctlr;
181
182 assert(gicd_base_addr);
183
184 /* Enable the forwarding of interrupts to CPU interface */
185 gicd_ctlr = gicd_read_ctlr(gicd_base_addr);
186 gicd_ctlr |= GICD_CTLR_ENABLE;
187 gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
188}
189
190/* Save the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
191void gicv2_save_sgi_ppi_context(void)
192{
193 unsigned int i;
194 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
195
196 assert(gicd_base_addr);
197 pcpu_gic_ctx[core_pos].gicd_isenabler0 =
198 gicd_read_isenabler(gicd_base_addr, 0);
199
200 /* Read the ipriority registers, 4 at a time */
201 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
202 pcpu_gic_ctx[core_pos].gicd_ipriorityr[i] =
203 gicd_read_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT);
204
205 pcpu_gic_ctx[core_pos].gicd_icfgr =
206 gicd_read_icfgr(gicd_base_addr, MIN_PPI_ID);
207}
208
209/* Restore the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
210void gicv2_restore_sgi_ppi_context(void)
211{
212 unsigned int i;
213 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
214
215 assert(gicd_base_addr);
216
217 /* Write the ipriority registers, 4 at a time */
218 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
219 gicd_write_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT,
220 pcpu_gic_ctx[core_pos].gicd_ipriorityr[i]);
221
222 gicd_write_icfgr(gicd_base_addr, MIN_PPI_ID,
223 pcpu_gic_ctx[core_pos].gicd_icfgr);
224
225 gicd_write_isenabler(gicd_base_addr, 0,
226 pcpu_gic_ctx[core_pos].gicd_isenabler0);
227}
228
229unsigned int gicv2_gicd_get_ipriorityr(unsigned int interrupt_id)
230{
231 assert(gicd_base_addr);
232 assert(IS_VALID_INTR_ID(interrupt_id));
233
234 return gicd_get_ipriorityr(gicd_base_addr, interrupt_id);
235}
236
237void gicv2_gicd_set_ipriorityr(unsigned int interrupt_id,
238 unsigned int priority)
239{
240 assert(gicd_base_addr);
241 assert(IS_VALID_INTR_ID(interrupt_id));
242
243 gicd_set_ipriorityr(gicd_base_addr, interrupt_id, priority);
244}
245
246void gicv2_send_sgi(unsigned int sgi_id, unsigned int core_pos)
247{
248 unsigned int sgir_val;
249
250 assert(gicd_base_addr);
251 assert(IS_SGI(sgi_id));
252
253 sgir_val = sgi_id << GICD_SGIR_INTID_SHIFT;
254 sgir_val |= (1 << core_pos_to_gic_id(core_pos)) << GICD_SGIR_CPUTL_SHIFT;
255
256 gicd_write_sgir(gicd_base_addr, sgir_val);
257}
258
259void gicv2_set_itargetsr(unsigned int num, unsigned int core_pos)
260{
261 unsigned int gic_cpu_id;
262 assert(gicd_base_addr);
263 assert(IS_SPI(num));
264
265 gic_cpu_id = core_pos_to_gic_id(core_pos);
266 gicd_set_itargetsr(gicd_base_addr, num, gic_cpu_id);
267}
268
269void gicv2_set_itargetsr_value(unsigned int num, unsigned int val)
270{
271 assert(gicd_base_addr);
272 assert(IS_SPI(num));
273
274 gicd_write_itargetsr_byte(gicd_base_addr, num, val);
275}
276
277unsigned int gicv2_gicd_get_isenabler(unsigned int num)
278{
279 assert(gicd_base_addr);
280 assert(IS_VALID_INTR_ID(num));
281
282 return gicd_get_isenabler(gicd_base_addr, num);
283}
284
285void gicv2_gicd_set_isenabler(unsigned int num)
286{
287 assert(gicd_base_addr);
288 assert(IS_VALID_INTR_ID(num));
289
290 gicd_set_isenabler(gicd_base_addr, num);
291}
292
293void gicv2_gicd_set_icenabler(unsigned int num)
294{
295 assert(gicd_base_addr);
296 assert(IS_VALID_INTR_ID(num));
297
298 gicd_set_icenabler(gicd_base_addr, num);
299}
300
301unsigned int gicv2_gicc_read_iar(void)
302{
303 assert(gicc_base_addr);
304 return gicc_read_iar(gicc_base_addr);
305}
306
307unsigned int gicv2_gicd_get_ispendr(unsigned int interrupt_id)
308{
309 unsigned int ispendr;
310 unsigned int bit_pos;
311
312 assert(gicd_base_addr);
313 assert(IS_VALID_INTR_ID(interrupt_id));
314
315 ispendr = gicd_read_ispendr(gicd_base_addr, interrupt_id);
316 bit_pos = interrupt_id % (1 << ISPENDR_SHIFT);
317
318 return !!(ispendr & (1 << bit_pos));
319}
320
321void gicv2_gicd_set_ispendr(unsigned int interrupt_id)
322{
323 assert(gicd_base_addr);
324 assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
325 gicd_set_ispendr(gicd_base_addr, interrupt_id);
326}
327
328void gicv2_gicd_set_icpendr(unsigned int interrupt_id)
329{
330 assert(gicd_base_addr);
331 assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
332
333 gicd_set_icpendr(gicd_base_addr, interrupt_id);
334}
335
336void gicv2_gicc_write_eoir(unsigned int val)
337{
338 assert(gicc_base_addr);
339
340 gicc_write_eoir(gicc_base_addr, val);
341}
342
343void gicv2_init(uintptr_t gicc_base,
344 uintptr_t gicd_base)
345{
346 assert(gicc_base);
347 assert(gicd_base);
348
349 /* Assert that this is a GICv2 system */
350 assert(!is_gicv3_mode());
351 gicc_base_addr = gicc_base;
352 gicd_base_addr = gicd_base;
353}