blob: 93c707a5d73198be349c469b97e2eb31d7fc3f31 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -06002 * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
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>
10#include <debug.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +000011#include <drivers/arm/arm_gic.h>
12#include <drivers/arm/gic_common.h>
13#include <drivers/arm/gic_v3.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020014#include <mmio.h>
15#include <platform.h>
16
17/* Global variables to store the GIC base addresses */
18static uintptr_t gicr_base_addr;
19static uintptr_t gicd_base_addr;
20
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -060021#ifdef __aarch64__
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020022#define MPIDR_AFFLVL3_MASK ((unsigned long long)MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT)
23#define gic_typer_affinity_from_mpidr(mpidr) \
24 (((mpidr) & (~MPIDR_AFFLVL3_MASK)) | (((mpidr) & MPIDR_AFFLVL3_MASK) >> 8))
25#else
26#define gic_typer_affinity_from_mpidr(mpidr) \
27 ((mpidr) & ((MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT) | MPID_MASK))
28#endif
29
30/*
31 * Data structure to store the GIC per CPU context before entering
32 * system suspend. Only the GIC context of first 32 interrupts (SGIs and PPIs)
33 * will be saved. The GIC SPI context needs to be restored by the respective
34 * drivers.
35 */
36struct gicv3_pcpu_ctx {
37 /* Flag to indicate whether the CPU is suspended */
38 unsigned int is_suspended;
39 unsigned int icc_igrpen1;
40 unsigned int gicr_isenabler;
41 unsigned int gicr_ipriorityr[NUM_PCPU_INTR >> IPRIORITYR_SHIFT];
42 unsigned int gicr_icfgr;
43};
44
45/* Array to store the per-cpu GICv3 context when being suspended.*/
46static struct gicv3_pcpu_ctx pcpu_ctx[PLATFORM_CORE_COUNT];
47
48/* Array to store the per-cpu redistributor frame addresses */
49static uintptr_t rdist_pcpu_base[PLATFORM_CORE_COUNT];
50
51/*
52 * Array to store the mpidr corresponding to each initialized per-CPU
53 * redistributor interface.
54 */
55static unsigned long long mpidr_list[PLATFORM_CORE_COUNT] = {UINT64_MAX};
56
57/******************************************************************************
58 * GIC Distributor interface accessors for writing entire registers
59 *****************************************************************************/
Marek Bykowskid6514442019-12-17 07:41:43 -060060static void gicd_write_irouter(uintptr_t base,
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020061 unsigned int interrupt_id,
62 unsigned long long route)
63{
64 assert(interrupt_id >= MIN_SPI_ID);
65 mmio_write_64(base + GICD_IROUTER + (interrupt_id << 3), route);
66}
67
68/******************************************************************************
69 * GIC Re-distributor interface accessors for writing entire registers
70 *****************************************************************************/
Marek Bykowskid6514442019-12-17 07:41:43 -060071static void gicr_write_isenabler0(uintptr_t base, unsigned int val)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020072{
73 mmio_write_32(base + GICR_ISENABLER0, val);
74}
75
Marek Bykowskid6514442019-12-17 07:41:43 -060076static void gicr_write_icenabler0(uintptr_t base, unsigned int val)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020077{
78 mmio_write_32(base + GICR_ICENABLER0, val);
79}
80
Marek Bykowskid6514442019-12-17 07:41:43 -060081static void gicr_write_icpendr0(uintptr_t base, unsigned int val)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020082{
83 mmio_write_32(base + GICR_ICPENDR0, val);
84}
85
86static void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
87{
88 unsigned n = id >> IPRIORITYR_SHIFT;
89 mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val);
90}
91
92static void gicr_write_icfgr1(uintptr_t base, unsigned int val)
93{
94 mmio_write_32(base + GICR_ICFGR1, val);
95}
96
97/******************************************************************************
98 * GIC Re-distributor interface accessors for reading entire registers
99 *****************************************************************************/
100static unsigned long long gicr_read_typer(uintptr_t base)
101{
102 return mmio_read_64(base + GICR_TYPER);
103}
104
105static unsigned int gicr_read_icfgr1(uintptr_t base)
106{
107 return mmio_read_32(base + GICR_ICFGR1);
108}
109
Marek Bykowskid6514442019-12-17 07:41:43 -0600110static unsigned int gicr_read_isenabler0(uintptr_t base)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200111{
112 return mmio_read_32(base + GICR_ISENABLER0);
113}
114
115static unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id)
116{
117 unsigned n = id >> IPRIORITYR_SHIFT;
118 return mmio_read_32(base + GICR_IPRIORITYR + (n << 2));
119}
120
Marek Bykowskid6514442019-12-17 07:41:43 -0600121static unsigned int gicr_read_ispendr0(uintptr_t base)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200122{
123 return mmio_read_32(base + GICR_ISPENDR0);
124}
125
126/******************************************************************************
127 * GIC Re-distributor interface accessors for individual interrupt
128 * manipulation
129 *****************************************************************************/
Marek Bykowskid6514442019-12-17 07:41:43 -0600130static unsigned int gicr_get_isenabler0(uintptr_t base,
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200131 unsigned int interrupt_id)
132{
133 unsigned bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
134 return gicr_read_isenabler0(base) & (1 << bit_num);
135}
136
Marek Bykowskid6514442019-12-17 07:41:43 -0600137static void gicr_set_isenabler0(uintptr_t base, unsigned int interrupt_id)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200138{
139 unsigned bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
140 gicr_write_isenabler0(base, (1 << bit_num));
141}
142
Marek Bykowskid6514442019-12-17 07:41:43 -0600143static void gicr_set_icenabler0(uintptr_t base, unsigned int interrupt_id)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200144{
145 unsigned bit_num = interrupt_id & ((1 << ISENABLER_SHIFT) - 1);
146 gicr_write_icenabler0(base, (1 << bit_num));
147}
148
Marek Bykowskid6514442019-12-17 07:41:43 -0600149static void gicr_set_icpendr0(uintptr_t base, unsigned int interrupt_id)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200150{
151 unsigned bit_num = interrupt_id & ((1 << ICPENDR_SHIFT) - 1);
152 gicr_write_icpendr0(base, (1 << bit_num));
153}
154
155/******************************************************************************
156 * GICv3 public driver API
157 *****************************************************************************/
158void gicv3_enable_cpuif(void)
159{
160 /* Assert that system register access is enabled */
161 assert(IS_IN_EL2() ? (read_icc_sre_el2() & ICC_SRE_SRE_BIT) :
162 (read_icc_sre_el1() & ICC_SRE_SRE_BIT));
163
164 /* Enable Group1 non secure interrupts */
165 write_icc_igrpen1_el1(read_icc_igrpen1_el1() | IGRPEN1_EL1_ENABLE_BIT);
166 isb();
167}
168
169void gicv3_setup_cpuif(void)
170{
171 /* Set the priority mask register to allow all interrupts to trickle in */
172 write_icc_pmr_el1(GIC_PRI_MASK);
173 isb();
174 gicv3_enable_cpuif();
175}
176
177void gicv3_disable_cpuif(void)
178{
179 /* Disable Group1 non secure interrupts */
180 write_icc_igrpen1_el1(read_icc_igrpen1_el1() &
181 ~IGRPEN1_EL1_ENABLE_BIT);
182 isb();
183}
184
185void gicv3_save_cpuif_context(void)
186{
187 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
188
189 /* Set the `is_suspended` flag as this core is being suspended. */
190 pcpu_ctx[core_pos].is_suspended = 1;
191 pcpu_ctx[core_pos].icc_igrpen1 = read_icc_igrpen1_el1();
192}
193
194void gicv3_restore_cpuif_context(void)
195{
196 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
197
198 /* Reset the `is_suspended` flag as this core has resumed from suspend. */
199 pcpu_ctx[core_pos].is_suspended = 0;
200 write_icc_pmr_el1(GIC_PRI_MASK);
201 write_icc_igrpen1_el1(pcpu_ctx[core_pos].icc_igrpen1);
202 isb();
203}
204
205void gicv3_save_sgi_ppi_context(void)
206{
207 unsigned int i, core_pos;
208 unsigned int my_core_pos = platform_get_core_pos(read_mpidr_el1());
209
210 /* Save the context for all the suspended cores */
211 for (core_pos = 0; core_pos < PLATFORM_CORE_COUNT; core_pos++) {
212 /*
213 * Continue if the core pos is not the current core
214 * and has not suspended
215 */
216 if ((core_pos != my_core_pos) &&
217 (!pcpu_ctx[core_pos].is_suspended))
218 continue;
219
220 assert(rdist_pcpu_base[core_pos]);
221
222 pcpu_ctx[core_pos].gicr_isenabler =
223 gicr_read_isenabler0(rdist_pcpu_base[core_pos]);
224
225 /* Read the ipriority registers, 4 at a time */
226 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
227 pcpu_ctx[core_pos].gicr_ipriorityr[i] =
228 gicr_read_ipriorityr(rdist_pcpu_base[core_pos],
229 i << IPRIORITYR_SHIFT);
230
231 pcpu_ctx[core_pos].gicr_icfgr =
232 gicr_read_icfgr1(rdist_pcpu_base[core_pos]);
233 }
234}
235
236void gicv3_restore_sgi_ppi_context(void)
237{
238 unsigned int i, core_pos;
239 unsigned int my_core_pos = platform_get_core_pos(read_mpidr_el1());
240
241 /* Restore the context for all the suspended cores */
242 for (core_pos = 0; core_pos < PLATFORM_CORE_COUNT; core_pos++) {
243 /*
244 * Continue if the core pos is not the current core
245 * and has not suspended
246 */
247 if ((core_pos != my_core_pos) &&
248 (!pcpu_ctx[core_pos].is_suspended))
249 continue;
250
251 assert(rdist_pcpu_base[core_pos]);
252
253 /* Read the ipriority registers, 4 at a time */
254 for (i = 0; i < (NUM_PCPU_INTR >> IPRIORITYR_SHIFT); i++)
255 gicr_write_ipriorityr(rdist_pcpu_base[core_pos],
256 i << IPRIORITYR_SHIFT,
257 pcpu_ctx[core_pos].gicr_ipriorityr[i]);
258
259 gicr_write_icfgr1(rdist_pcpu_base[core_pos],
260 pcpu_ctx[core_pos].gicr_icfgr);
261 gicr_write_isenabler0(rdist_pcpu_base[core_pos],
262 pcpu_ctx[core_pos].gicr_isenabler);
263 }
264}
265
266unsigned int gicv3_get_ipriorityr(unsigned int interrupt_id)
267{
268 unsigned int core_pos;
269 assert(gicd_base_addr);
270 assert(IS_VALID_INTR_ID(interrupt_id));
271
272 if (interrupt_id < MIN_SPI_ID) {
273 core_pos = platform_get_core_pos(read_mpidr_el1());
274 assert(rdist_pcpu_base[core_pos]);
275 return mmio_read_8(rdist_pcpu_base[core_pos] + GICR_IPRIORITYR
276 + interrupt_id);
277 } else {
278 return mmio_read_8(gicd_base_addr +
279 GICD_IPRIORITYR + interrupt_id);
280 }
281}
282
283void gicv3_set_ipriorityr(unsigned int interrupt_id,
284 unsigned int priority)
285{
286 unsigned int core_pos;
287 assert(gicd_base_addr);
288 assert(IS_VALID_INTR_ID(interrupt_id));
289
290 if (interrupt_id < MIN_SPI_ID) {
291 core_pos = platform_get_core_pos(read_mpidr_el1());
292 assert(rdist_pcpu_base[core_pos]);
293 mmio_write_8(rdist_pcpu_base[core_pos] + GICR_IPRIORITYR
294 + interrupt_id, priority & GIC_PRI_MASK);
295 } else {
296 mmio_write_8(gicd_base_addr + GICD_IPRIORITYR + interrupt_id,
297 priority & GIC_PRI_MASK);
298 }
299}
300
301void gicv3_send_sgi(unsigned int sgi_id, unsigned int core_pos)
302{
303 unsigned long long aff0, aff1, aff2;
304 unsigned long long sgir, target_list;
305
306 assert(IS_SGI(sgi_id));
307 assert(core_pos < PLATFORM_CORE_COUNT);
308
309 assert(mpidr_list[core_pos] != UINT64_MAX);
310
311 /* Extract the affinity information */
312 aff0 = MPIDR_AFF_ID(mpidr_list[core_pos], 0);
313 aff1 = MPIDR_AFF_ID(mpidr_list[core_pos], 1);
314 aff2 = MPIDR_AFF_ID(mpidr_list[core_pos], 2);
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600315#ifdef __aarch64__
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200316 unsigned long long aff3;
317 aff3 = MPIDR_AFF_ID(mpidr_list[core_pos], 3);
318#endif
319
320 /* Construct the SGI target list using Affinity 0 */
321 assert(aff0 < SGI_TARGET_MAX_AFF0);
322 target_list = 1 << aff0;
323
324 /* Construct the SGI target affinity */
325 sgir =
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600326#ifdef __aarch64__
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200327 ((aff3 & SGI1R_AFF_MASK) << SGI1R_AFF3_SHIFT) |
328#endif
329 ((aff2 & SGI1R_AFF_MASK) << SGI1R_AFF2_SHIFT) |
330 ((aff1 & SGI1R_AFF_MASK) << SGI1R_AFF1_SHIFT) |
331 ((target_list & SGI1R_TARGET_LIST_MASK)
332 << SGI1R_TARGET_LIST_SHIFT);
333
334 /* Combine SGI target affinity with the SGI ID */
335 sgir |= ((sgi_id & SGI1R_INTID_MASK) << SGI1R_INTID_SHIFT);
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600336#ifdef __aarch64__
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200337 write_icc_sgi1r(sgir);
338#else
339 write64_icc_sgi1r(sgir);
340#endif
341 isb();
342}
343
344void gicv3_set_intr_route(unsigned int interrupt_id,
345 unsigned int core_pos)
346{
347 unsigned long long route_affinity;
348
349 assert(gicd_base_addr);
350 assert(core_pos < PLATFORM_CORE_COUNT);
351 assert(mpidr_list[core_pos] != UINT64_MAX);
352
353 /* Routing information can be set only for SPIs */
354 assert(IS_SPI(interrupt_id));
355 route_affinity = mpidr_list[core_pos];
356
357 gicd_write_irouter(gicd_base_addr, interrupt_id, route_affinity);
358}
359
360unsigned int gicv3_get_isenabler(unsigned int interrupt_id)
361{
362 unsigned int core_pos;
363
364 assert(gicd_base_addr);
365 assert(IS_VALID_INTR_ID(interrupt_id));
366
367 if (interrupt_id < MIN_SPI_ID) {
368 core_pos = platform_get_core_pos(read_mpidr_el1());
369 assert(rdist_pcpu_base[core_pos]);
370 return gicr_get_isenabler0(rdist_pcpu_base[core_pos], interrupt_id);
371 } else
372 return gicd_get_isenabler(gicd_base_addr, interrupt_id);
373}
374
375void gicv3_set_isenabler(unsigned int interrupt_id)
376{
377 unsigned int core_pos;
378
379 assert(gicd_base_addr);
380 assert(IS_VALID_INTR_ID(interrupt_id));
381
382 if (interrupt_id < MIN_SPI_ID) {
383 core_pos = platform_get_core_pos(read_mpidr_el1());
384 assert(rdist_pcpu_base[core_pos]);
385 gicr_set_isenabler0(rdist_pcpu_base[core_pos], interrupt_id);
386 } else
387 gicd_set_isenabler(gicd_base_addr, interrupt_id);
388}
389
390void gicv3_set_icenabler(unsigned int interrupt_id)
391{
392 unsigned int core_pos;
393
394 assert(gicd_base_addr);
395 assert(IS_VALID_INTR_ID(interrupt_id));
396
397 if (interrupt_id < MIN_SPI_ID) {
398 core_pos = platform_get_core_pos(read_mpidr_el1());
399 assert(rdist_pcpu_base[core_pos]);
400 gicr_set_icenabler0(rdist_pcpu_base[core_pos], interrupt_id);
401 } else
402 gicd_set_icenabler(gicd_base_addr, interrupt_id);
403}
404
405unsigned int gicv3_get_ispendr(unsigned int interrupt_id)
406{
407 unsigned int ispendr;
408 unsigned int bit_pos, core_pos;
409
410 assert(gicd_base_addr);
411 assert(IS_VALID_INTR_ID(interrupt_id));
412
413 if (interrupt_id < MIN_SPI_ID) {
414 core_pos = platform_get_core_pos(read_mpidr_el1());
415 assert(rdist_pcpu_base[core_pos]);
416 ispendr = gicr_read_ispendr0(rdist_pcpu_base[core_pos]);
417 } else
418 ispendr = gicd_read_ispendr(gicd_base_addr, interrupt_id);
419
420 bit_pos = interrupt_id % (1 << ISPENDR_SHIFT);
421 return !!(ispendr & (1 << bit_pos));
422}
423
424void gicv3_set_icpendr(unsigned int interrupt_id)
425{
426 unsigned int core_pos;
427
428 assert(gicd_base_addr);
429 assert(IS_SPI(interrupt_id) || IS_PPI(interrupt_id));
430
431 if (interrupt_id < MIN_SPI_ID) {
432 core_pos = platform_get_core_pos(read_mpidr_el1());
433 assert(rdist_pcpu_base[core_pos]);
434 gicr_set_icpendr0(rdist_pcpu_base[core_pos], interrupt_id);
435
436 } else
437 gicd_set_icpendr(gicd_base_addr, interrupt_id);
438}
439
440void gicv3_probe_redistif_addr(void)
441{
442 unsigned long long typer_val;
443 uintptr_t rdistif_base;
444 unsigned long long affinity;
445 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
446
447 assert(gicr_base_addr);
448
449 /*
450 * Return if the re-distributor base address is already populated
451 * for this core.
452 */
453 if (rdist_pcpu_base[core_pos])
454 return;
455
456 /* Iterate over the GICR frames and find the matching frame*/
457 rdistif_base = gicr_base_addr;
458 affinity = gic_typer_affinity_from_mpidr(read_mpidr_el1() & MPIDR_AFFINITY_MASK);
459 do {
460 typer_val = gicr_read_typer(rdistif_base);
461 if (affinity == ((typer_val >> TYPER_AFF_VAL_SHIFT) & TYPER_AFF_VAL_MASK)) {
462 rdist_pcpu_base[core_pos] = rdistif_base;
463 mpidr_list[core_pos] = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
464 return;
465 }
466 rdistif_base += (1 << GICR_PCPUBASE_SHIFT);
467 } while (!(typer_val & TYPER_LAST_BIT));
468
469 ERROR("Re-distributor address not found for core %d\n", core_pos);
470 panic();
471}
472
473void gicv3_setup_distif(void)
474{
475 unsigned int gicd_ctlr;
476
477 assert(gicd_base_addr);
478
479 /* Check for system register support */
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600480#ifdef __aarch64__
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200481 assert(read_id_aa64pfr0_el1() &
482 (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT));
483#else
484 assert(read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT));
485#endif
486
487 /* Assert that system register access is enabled */
488 assert(is_sre_enabled());
489
490 /* Enable the forwarding of interrupts to CPU interface */
491 gicd_ctlr = gicd_read_ctlr(gicd_base_addr);
492
493 /* Assert ARE_NS bit in GICD */
494 assert(gicd_ctlr & (GICD_CTLR_ARE_NS_MASK << GICD_CTLR_ARE_NS_SHIFT));
495
496 gicd_ctlr |= GICD_CTLR_ENABLE_GRP1A;
497 gicd_write_ctlr(gicd_base_addr, gicd_ctlr);
498}
499
500void gicv3_init(uintptr_t gicr_base, uintptr_t gicd_base)
501{
502 assert(gicr_base);
503 assert(gicd_base);
504
505 gicr_base_addr = gicr_base;
506 gicd_base_addr = gicd_base;
507}
Madhukar Pappireddyc6a3abf2023-10-25 16:47:23 -0500508
509unsigned int gicv3_get_gicd_typer(void)
510{
511 return gicd_read_typer(gicd_base_addr);
512}