blob: f91427cada65d5d6c4085e21f40747fbbee47e5e [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>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02009#include <assert.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +000010#include <drivers/arm/arm_gic.h>
11#include <drivers/arm/gic_common.h>
12#include <drivers/arm/gic_v2.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020013#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 ******************************************************************************/
Madhukar Pappireddy94730072020-06-08 16:59:38 -050047uint8_t gicd_read_itargetsr_byte(unsigned int base, unsigned int interrupt_id)
48{
49 return mmio_read_8(base + GICD_ITARGETSR + interrupt_id);
50}
51
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020052unsigned int gicd_read_itargetsr(unsigned int base, unsigned int interrupt_id)
53{
54 unsigned n = interrupt_id >> ITARGETSR_SHIFT;
55 return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
56}
57
58unsigned int gicd_read_cpendsgir(unsigned int base, unsigned int interrupt_id)
59{
60 unsigned n = interrupt_id >> CPENDSGIR_SHIFT;
61 return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
62}
63
64unsigned int gicd_read_spendsgir(unsigned int base, unsigned int interrupt_id)
65{
66 unsigned n = interrupt_id >> SPENDSGIR_SHIFT;
67 return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
68}
69
70/*******************************************************************************
71 * GIC Distributor interface accessors for writing entire registers
72 ******************************************************************************/
73void gicd_write_itargetsr(unsigned int base,
74 unsigned int interrupt_id, unsigned int val)
75{
76 unsigned n = interrupt_id >> ITARGETSR_SHIFT;
77 mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
78}
79
80void gicd_write_itargetsr_byte(unsigned int base,
81 unsigned int interrupt_id, unsigned int val)
82{
83 mmio_write_8(base + GICD_ITARGETSR + interrupt_id, val);
84}
85
86void gicd_write_cpendsgir(unsigned int base,
87 unsigned int interrupt_id, unsigned int val)
88{
89 unsigned n = interrupt_id >> CPENDSGIR_SHIFT;
90 mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
91}
92
93void gicd_write_spendsgir(unsigned int base,
94 unsigned int interrupt_id, unsigned int val)
95{
96 unsigned n = interrupt_id >> SPENDSGIR_SHIFT;
97 mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
98}
99
100/*******************************************************************************
101 * GIC Distributor interface accessors for individual interrupt manipulation
102 ******************************************************************************/
103void gicd_set_itargetsr(unsigned int base,
104 unsigned int interrupt_id, unsigned int iface)
105{
106 mmio_write_8(base + GICD_ITARGETSR + interrupt_id, (1 << iface));
107}
108
109/******************************************************************************
110 * GICv2 public driver API
111 *****************************************************************************/
112
113void gicv2_enable_cpuif(void)
114{
115 unsigned int gicc_ctlr;
116
117 assert(gicc_base_addr);
118
119 /* Enable the GICC and disable bypass */
120 gicc_ctlr = GICC_CTLR_ENABLE | FIQ_BYP_DIS_GRP1
121 | IRQ_BYP_DIS_GRP1;
122 gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
123}
124
125void gicv2_probe_gic_cpu_id(void)
126{
127 unsigned int gicd_itargets_val, core_pos;
128
129 assert(gicd_base_addr);
130 core_pos = platform_get_core_pos(read_mpidr_el1());
131 gicd_itargets_val = gicd_read_itargetsr(gicd_base_addr, 0);
132
Pranjal Shrivastava6f204002024-08-28 12:29:48 +0000133 /* In a uniprocessor implementation the GICD_ITARGETSRs are RAZ/WI. */
134 if (PLATFORM_CORE_COUNT > 1)
135 assert(gicd_itargets_val);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200136
137 /* Convert the bit pos returned by read of ITARGETSR0 to GIC CPU ID */
138 gic_cpu_id[core_pos] = __builtin_ctz(gicd_itargets_val);
139}
140
141void gicv2_setup_cpuif(void)
142{
143 assert(gicc_base_addr);
144
145 /* Set the priority mask register to allow all interrupts to trickle in */
146 gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
147 gicv2_enable_cpuif();
148}
149
150void gicv2_disable_cpuif(void)
151{
152 unsigned int gicc_ctlr;
153
154 assert(gicc_base_addr);
155
156 /* Disable non-secure interrupts and disable their bypass */
157 gicc_ctlr = gicc_read_ctlr(gicc_base_addr);
158 gicc_ctlr &= ~GICC_CTLR_ENABLE;
159 gicc_ctlr |= FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
160 gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
161}
162
163void gicv2_save_cpuif_context(void)
164{
165 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
166
167 assert(gicc_base_addr);
168 pcpu_gic_ctx[core_pos].gicc_ctlr =
169 gicc_read_ctlr(gicc_base_addr);
170}
171
172void gicv2_restore_cpuif_context(void)
173{
174 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
175
176 assert(gicc_base_addr);
177
178 /* The GICC_PMR is never modified, hence we initialize this register */
179 gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
180
181 gicc_write_ctlr(gicc_base_addr,
182 pcpu_gic_ctx[core_pos].gicc_ctlr);
183}
184
185void gicv2_setup_distif(void)
186{
187 unsigned int gicd_ctlr;
188
189 assert(gicd_base_addr);
190
191 /* Enable the forwarding of interrupts to CPU interface */
192 gicd_ctlr = gicd_read_ctlr(gicd_base_addr);
193 gicd_ctlr |= GICD_CTLR_ENABLE;
194 gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
195}
196
197/* Save the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
198void gicv2_save_sgi_ppi_context(void)
199{
200 unsigned int i;
201 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
202
203 assert(gicd_base_addr);
204 pcpu_gic_ctx[core_pos].gicd_isenabler0 =
205 gicd_read_isenabler(gicd_base_addr, 0);
206
207 /* Read the ipriority registers, 4 at a time */
208 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
209 pcpu_gic_ctx[core_pos].gicd_ipriorityr[i] =
210 gicd_read_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT);
211
212 pcpu_gic_ctx[core_pos].gicd_icfgr =
213 gicd_read_icfgr(gicd_base_addr, MIN_PPI_ID);
214}
215
216/* Restore the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
217void gicv2_restore_sgi_ppi_context(void)
218{
219 unsigned int i;
220 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
221
222 assert(gicd_base_addr);
223
224 /* Write the ipriority registers, 4 at a time */
225 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
226 gicd_write_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT,
227 pcpu_gic_ctx[core_pos].gicd_ipriorityr[i]);
228
229 gicd_write_icfgr(gicd_base_addr, MIN_PPI_ID,
230 pcpu_gic_ctx[core_pos].gicd_icfgr);
231
232 gicd_write_isenabler(gicd_base_addr, 0,
233 pcpu_gic_ctx[core_pos].gicd_isenabler0);
234}
235
236unsigned int gicv2_gicd_get_ipriorityr(unsigned int interrupt_id)
237{
238 assert(gicd_base_addr);
239 assert(IS_VALID_INTR_ID(interrupt_id));
240
241 return gicd_get_ipriorityr(gicd_base_addr, interrupt_id);
242}
243
244void gicv2_gicd_set_ipriorityr(unsigned int interrupt_id,
245 unsigned int priority)
246{
247 assert(gicd_base_addr);
248 assert(IS_VALID_INTR_ID(interrupt_id));
249
250 gicd_set_ipriorityr(gicd_base_addr, interrupt_id, priority);
251}
252
253void gicv2_send_sgi(unsigned int sgi_id, unsigned int core_pos)
254{
255 unsigned int sgir_val;
256
257 assert(gicd_base_addr);
258 assert(IS_SGI(sgi_id));
259
260 sgir_val = sgi_id << GICD_SGIR_INTID_SHIFT;
261 sgir_val |= (1 << core_pos_to_gic_id(core_pos)) << GICD_SGIR_CPUTL_SHIFT;
262
263 gicd_write_sgir(gicd_base_addr, sgir_val);
264}
265
266void gicv2_set_itargetsr(unsigned int num, unsigned int core_pos)
267{
268 unsigned int gic_cpu_id;
269 assert(gicd_base_addr);
270 assert(IS_SPI(num));
271
272 gic_cpu_id = core_pos_to_gic_id(core_pos);
273 gicd_set_itargetsr(gicd_base_addr, num, gic_cpu_id);
274}
275
Madhukar Pappireddy94730072020-06-08 16:59:38 -0500276uint8_t gicv2_read_itargetsr_value(unsigned int num)
277{
278 return gicd_read_itargetsr_byte(gicd_base_addr, num);
279}
280
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200281void gicv2_set_itargetsr_value(unsigned int num, unsigned int val)
282{
283 assert(gicd_base_addr);
284 assert(IS_SPI(num));
285
286 gicd_write_itargetsr_byte(gicd_base_addr, num, val);
Madhukar Pappireddy94730072020-06-08 16:59:38 -0500287
288 assert(gicv2_read_itargetsr_value(num) == val);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200289}
290
291unsigned int gicv2_gicd_get_isenabler(unsigned int num)
292{
293 assert(gicd_base_addr);
294 assert(IS_VALID_INTR_ID(num));
295
296 return gicd_get_isenabler(gicd_base_addr, num);
297}
298
299void gicv2_gicd_set_isenabler(unsigned int num)
300{
301 assert(gicd_base_addr);
302 assert(IS_VALID_INTR_ID(num));
303
304 gicd_set_isenabler(gicd_base_addr, num);
305}
306
307void gicv2_gicd_set_icenabler(unsigned int num)
308{
309 assert(gicd_base_addr);
310 assert(IS_VALID_INTR_ID(num));
311
312 gicd_set_icenabler(gicd_base_addr, num);
313}
314
315unsigned int gicv2_gicc_read_iar(void)
316{
317 assert(gicc_base_addr);
318 return gicc_read_iar(gicc_base_addr);
319}
320
321unsigned int gicv2_gicd_get_ispendr(unsigned int interrupt_id)
322{
323 unsigned int ispendr;
324 unsigned int bit_pos;
325
326 assert(gicd_base_addr);
327 assert(IS_VALID_INTR_ID(interrupt_id));
328
329 ispendr = gicd_read_ispendr(gicd_base_addr, interrupt_id);
330 bit_pos = interrupt_id % (1 << ISPENDR_SHIFT);
331
332 return !!(ispendr & (1 << bit_pos));
333}
334
335void gicv2_gicd_set_ispendr(unsigned int interrupt_id)
336{
337 assert(gicd_base_addr);
338 assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
339 gicd_set_ispendr(gicd_base_addr, interrupt_id);
340}
341
342void gicv2_gicd_set_icpendr(unsigned int interrupt_id)
343{
344 assert(gicd_base_addr);
345 assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
346
347 gicd_set_icpendr(gicd_base_addr, interrupt_id);
348}
349
350void gicv2_gicc_write_eoir(unsigned int val)
351{
352 assert(gicc_base_addr);
353
354 gicc_write_eoir(gicc_base_addr, val);
355}
356
357void gicv2_init(uintptr_t gicc_base,
358 uintptr_t gicd_base)
359{
360 assert(gicc_base);
361 assert(gicd_base);
362
363 /* Assert that this is a GICv2 system */
364 assert(!is_gicv3_mode());
365 gicc_base_addr = gicc_base;
366 gicd_base_addr = gicd_base;
367}