blob: 448989286304c55d14221bf39f8ac35494671c2d [file] [log] [blame]
Soby Mathew327548c2017-07-13 15:19:51 +01001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * Driver for implementation defined features that are identical in ARM GICv3
9* implementations (GIC-500 and GIC-600 for now). This driver only overrides
10* APIs that are different to those generic ones in GICv3 driver.
11 */
12
Soby Mathew327548c2017-07-13 15:19:51 +010013#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014
15#include <arch_helpers.h>
16#include <drivers/arm/arm_gicv3_common.h>
17#include <drivers/arm/gicv3.h>
Soby Mathew327548c2017-07-13 15:19:51 +010018
19#include "gicv3_private.h"
Soby Mathew327548c2017-07-13 15:19:51 +010020
21/*
22 * Flush the internal GIC cache of the LPIs pending tables to memory before
23 * saving the state of the Redistributor. This is required before powering off
24 * the GIC when the pending status must be preserved.
25 * `rdist_proc_num` is the processor number corresponding to the Redistributor of the
26 * current CPU.
27 */
28void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
29{
30 uintptr_t gicr_base = 0;
31
32 assert(gicv3_driver_data);
33 assert(gicv3_driver_data->rdistif_base_addrs);
34
35 /*
36 * The GICR_WAKER.Sleep bit should be set only when both
37 * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
38 * all the Redistributors.
39 */
40 for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) {
41 gicr_base = gicv3_driver_data->rdistif_base_addrs[i];
42 assert(gicr_base);
43 assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
44 assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT);
45 }
46
47 gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
48 /*
49 * According to the TRM, there is only one instance of the
50 * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
51 * through any of the Redistributor.
52 */
53
54 /*
55 * Set GICR_WAKER.Sleep
56 * After this point, the system must be configured so that the
57 * wake_request signals for the right cores are asserted when a wakeup
58 * interrupt is detected. The GIC will not be able to do that anymore
59 * when the GICR_WAKER.Sleep bit is set to 1.
60 */
61 gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
62
63 /* Wait until the GICR_WAKER.Quiescent bit is set */
64 while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
65 ;
66}
67
68/*
69 * Allow the LPIs pending state to be read back from the tables in memory after
70 * having restored the state of the GIC Redistributor.
71 */
72void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
73{
74 uintptr_t gicr_base;
75
76 assert(gicv3_driver_data);
77 assert(gicv3_driver_data->rdistif_base_addrs);
78
79 /*
80 * According to the TRM, there is only one instance of the
81 * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
82 * through any of the Redistributor.
83 */
84 gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
85 assert(gicr_base);
86
87 /*
Derek Basehore45bcb6e2018-01-23 15:49:17 -080088 * If the GIC had power removed, the GICR_WAKER state will be reset.
89 * Since the GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits are cleared,
90 * we can exit early. This also prevents the following assert from
91 * erroneously triggering.
92 */
93 if (!(gicr_read_waker(gicr_base) & WAKER_SL_BIT))
94 return;
95
96 /*
Soby Mathew327548c2017-07-13 15:19:51 +010097 * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent
98 * bit is not set. We should be alright on power on path, therefore
99 * coming out of sleep and Quiescent should be set, but we assert in
100 * case.
101 */
102 assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT);
103
104 /* Clear GICR_WAKER.Sleep */
105 gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT);
106
107 /*
108 * We don't know if the effects of setting GICR_WAKER.Sleep bit is
109 * instantaneous, so we wait until the interface is not Quiescent
110 * anymore.
111 */
112 while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT)
113 ;
114}
115