blob: ef930074ef7f4e9a916e12c068568fe8114c779d [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
133 assert(gicd_itargets_val);
134
135 /* Convert the bit pos returned by read of ITARGETSR0 to GIC CPU ID */
136 gic_cpu_id[core_pos] = __builtin_ctz(gicd_itargets_val);
137}
138
139void gicv2_setup_cpuif(void)
140{
141 assert(gicc_base_addr);
142
143 /* Set the priority mask register to allow all interrupts to trickle in */
144 gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
145 gicv2_enable_cpuif();
146}
147
148void gicv2_disable_cpuif(void)
149{
150 unsigned int gicc_ctlr;
151
152 assert(gicc_base_addr);
153
154 /* Disable non-secure interrupts and disable their bypass */
155 gicc_ctlr = gicc_read_ctlr(gicc_base_addr);
156 gicc_ctlr &= ~GICC_CTLR_ENABLE;
157 gicc_ctlr |= FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
158 gicc_write_ctlr(gicc_base_addr, gicc_ctlr);
159}
160
161void gicv2_save_cpuif_context(void)
162{
163 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
164
165 assert(gicc_base_addr);
166 pcpu_gic_ctx[core_pos].gicc_ctlr =
167 gicc_read_ctlr(gicc_base_addr);
168}
169
170void gicv2_restore_cpuif_context(void)
171{
172 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
173
174 assert(gicc_base_addr);
175
176 /* The GICC_PMR is never modified, hence we initialize this register */
177 gicc_write_pmr(gicc_base_addr, GIC_PRI_MASK);
178
179 gicc_write_ctlr(gicc_base_addr,
180 pcpu_gic_ctx[core_pos].gicc_ctlr);
181}
182
183void gicv2_setup_distif(void)
184{
185 unsigned int gicd_ctlr;
186
187 assert(gicd_base_addr);
188
189 /* Enable the forwarding of interrupts to CPU interface */
190 gicd_ctlr = gicd_read_ctlr(gicd_base_addr);
191 gicd_ctlr |= GICD_CTLR_ENABLE;
192 gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
193}
194
195/* Save the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
196void gicv2_save_sgi_ppi_context(void)
197{
198 unsigned int i;
199 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
200
201 assert(gicd_base_addr);
202 pcpu_gic_ctx[core_pos].gicd_isenabler0 =
203 gicd_read_isenabler(gicd_base_addr, 0);
204
205 /* Read the ipriority registers, 4 at a time */
206 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
207 pcpu_gic_ctx[core_pos].gicd_ipriorityr[i] =
208 gicd_read_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT);
209
210 pcpu_gic_ctx[core_pos].gicd_icfgr =
211 gicd_read_icfgr(gicd_base_addr, MIN_PPI_ID);
212}
213
214/* Restore the per-cpu GICD ISENABLER, IPRIORITYR and ICFGR registers */
215void gicv2_restore_sgi_ppi_context(void)
216{
217 unsigned int i;
218 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
219
220 assert(gicd_base_addr);
221
222 /* Write the ipriority registers, 4 at a time */
223 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
224 gicd_write_ipriorityr(gicd_base_addr, i << IPRIORITYR_SHIFT,
225 pcpu_gic_ctx[core_pos].gicd_ipriorityr[i]);
226
227 gicd_write_icfgr(gicd_base_addr, MIN_PPI_ID,
228 pcpu_gic_ctx[core_pos].gicd_icfgr);
229
230 gicd_write_isenabler(gicd_base_addr, 0,
231 pcpu_gic_ctx[core_pos].gicd_isenabler0);
232}
233
234unsigned int gicv2_gicd_get_ipriorityr(unsigned int interrupt_id)
235{
236 assert(gicd_base_addr);
237 assert(IS_VALID_INTR_ID(interrupt_id));
238
239 return gicd_get_ipriorityr(gicd_base_addr, interrupt_id);
240}
241
242void gicv2_gicd_set_ipriorityr(unsigned int interrupt_id,
243 unsigned int priority)
244{
245 assert(gicd_base_addr);
246 assert(IS_VALID_INTR_ID(interrupt_id));
247
248 gicd_set_ipriorityr(gicd_base_addr, interrupt_id, priority);
249}
250
251void gicv2_send_sgi(unsigned int sgi_id, unsigned int core_pos)
252{
253 unsigned int sgir_val;
254
255 assert(gicd_base_addr);
256 assert(IS_SGI(sgi_id));
257
258 sgir_val = sgi_id << GICD_SGIR_INTID_SHIFT;
259 sgir_val |= (1 << core_pos_to_gic_id(core_pos)) << GICD_SGIR_CPUTL_SHIFT;
260
261 gicd_write_sgir(gicd_base_addr, sgir_val);
262}
263
264void gicv2_set_itargetsr(unsigned int num, unsigned int core_pos)
265{
266 unsigned int gic_cpu_id;
267 assert(gicd_base_addr);
268 assert(IS_SPI(num));
269
270 gic_cpu_id = core_pos_to_gic_id(core_pos);
271 gicd_set_itargetsr(gicd_base_addr, num, gic_cpu_id);
272}
273
Madhukar Pappireddy94730072020-06-08 16:59:38 -0500274uint8_t gicv2_read_itargetsr_value(unsigned int num)
275{
276 return gicd_read_itargetsr_byte(gicd_base_addr, num);
277}
278
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200279void gicv2_set_itargetsr_value(unsigned int num, unsigned int val)
280{
281 assert(gicd_base_addr);
282 assert(IS_SPI(num));
283
284 gicd_write_itargetsr_byte(gicd_base_addr, num, val);
Madhukar Pappireddy94730072020-06-08 16:59:38 -0500285
286 assert(gicv2_read_itargetsr_value(num) == val);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200287}
288
289unsigned int gicv2_gicd_get_isenabler(unsigned int num)
290{
291 assert(gicd_base_addr);
292 assert(IS_VALID_INTR_ID(num));
293
294 return gicd_get_isenabler(gicd_base_addr, num);
295}
296
297void gicv2_gicd_set_isenabler(unsigned int num)
298{
299 assert(gicd_base_addr);
300 assert(IS_VALID_INTR_ID(num));
301
302 gicd_set_isenabler(gicd_base_addr, num);
303}
304
305void gicv2_gicd_set_icenabler(unsigned int num)
306{
307 assert(gicd_base_addr);
308 assert(IS_VALID_INTR_ID(num));
309
310 gicd_set_icenabler(gicd_base_addr, num);
311}
312
313unsigned int gicv2_gicc_read_iar(void)
314{
315 assert(gicc_base_addr);
316 return gicc_read_iar(gicc_base_addr);
317}
318
319unsigned int gicv2_gicd_get_ispendr(unsigned int interrupt_id)
320{
321 unsigned int ispendr;
322 unsigned int bit_pos;
323
324 assert(gicd_base_addr);
325 assert(IS_VALID_INTR_ID(interrupt_id));
326
327 ispendr = gicd_read_ispendr(gicd_base_addr, interrupt_id);
328 bit_pos = interrupt_id % (1 << ISPENDR_SHIFT);
329
330 return !!(ispendr & (1 << bit_pos));
331}
332
333void gicv2_gicd_set_ispendr(unsigned int interrupt_id)
334{
335 assert(gicd_base_addr);
336 assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
337 gicd_set_ispendr(gicd_base_addr, interrupt_id);
338}
339
340void gicv2_gicd_set_icpendr(unsigned int interrupt_id)
341{
342 assert(gicd_base_addr);
343 assert(IS_PPI(interrupt_id) || IS_SPI(interrupt_id));
344
345 gicd_set_icpendr(gicd_base_addr, interrupt_id);
346}
347
348void gicv2_gicc_write_eoir(unsigned int val)
349{
350 assert(gicc_base_addr);
351
352 gicc_write_eoir(gicc_base_addr, val);
353}
354
355void gicv2_init(uintptr_t gicc_base,
356 uintptr_t gicd_base)
357{
358 assert(gicc_base);
359 assert(gicd_base);
360
361 /* Assert that this is a GICv2 system */
362 assert(!is_gicv3_mode());
363 gicc_base_addr = gicc_base;
364 gicd_base_addr = gicd_base;
365}