xref: /rk3399_ARM-atf/drivers/arm/gic/v3/gicv3_base.c (revision d9712f9cae10fdeb8696ffcd3ca35d58666ea9dd)
1 /*
2  * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <platform_def.h>
9 
10 #include <common/debug.h>
11 #include <common/interrupt_props.h>
12 #include <drivers/arm/gic.h>
13 #include <drivers/arm/gicv3.h>
14 #include <lib/utils.h>
15 #include <plat/arm/common/plat_arm.h>
16 #include <plat/common/platform.h>
17 
18 #if USE_GIC_DRIVER != 3
19 #error "This file should only be used with USE_GIC_DRIVER=3"
20 #endif
21 
22 /* The GICv3 driver only needs to be initialized in EL3 */
23 uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
24 
25 /* Default GICR base address to be used for GICR probe. */
26 static const uintptr_t gicr_base_addrs[2] = {
27 	PLAT_ARM_GICR_BASE,	/* GICR Base address of the primary CPU */
28 	0U			/* Zero Termination */
29 };
30 
31 /* List of zero terminated GICR frame addresses which CPUs will probe */
32 static const uintptr_t *gicr_frames = gicr_base_addrs;
33 
34 static const interrupt_prop_t arm_interrupt_props[] = {
35 #ifdef PLAT_ARM_G1S_IRQ_PROPS
36 	PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
37 #endif
38 #ifdef PLAT_ARM_G0_IRQ_PROPS
39 	PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0),
40 #endif
41 #if ENABLE_FEAT_RAS && FFH_SUPPORT
42 	INTR_PROP_DESC(PLAT_CORE_FAULT_IRQ, PLAT_RAS_PRI, INTR_GROUP0,
43 			GIC_INTR_CFG_LEVEL)
44 #endif
45 };
46 
47 /*
48  * We save and restore the GICv3 context on system suspend. Allocate the
49  * data in the designated EL3 Secure carve-out memory. The `used` attribute
50  * is used to prevent the compiler from removing the gicv3 contexts.
51  */
52 static gicv3_redist_ctx_t rdist_ctx __section(".arm_el3_tzc_dram") __used;
53 static gicv3_dist_ctx_t dist_ctx __section(".arm_el3_tzc_dram") __used;
54 
55 /* Define accessor function to get reference to the GICv3 context */
56 DEFINE_LOAD_SYM_ADDR(rdist_ctx)
57 DEFINE_LOAD_SYM_ADDR(dist_ctx)
58 
59 /*
60  * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
61  * to core position.
62  *
63  * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
64  * values read from GICR_TYPER don't have an MT field. To reuse the same
65  * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
66  * that read from GICR_TYPER.
67  *
68  * Assumptions:
69  *
70  *   - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
71  *   - No CPUs implemented in the system use affinity level 3.
72  */
73 static unsigned int arm_gicv3_mpidr_hash(u_register_t mpidr)
74 {
75 	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
76 	return plat_arm_calc_core_pos(mpidr);
77 }
78 
79 gicv3_driver_data_t gic_data __unused = {
80 	.gicd_base = PLAT_ARM_GICD_BASE,
81 	.gicr_base = 0U,
82 	.interrupt_props = arm_interrupt_props,
83 	.interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
84 	.rdistif_num = PLATFORM_CORE_COUNT,
85 	.rdistif_base_addrs = rdistif_base_addrs,
86 	.mpidr_to_core_pos = arm_gicv3_mpidr_hash
87 };
88 
89 /*
90  * By default, gicr_frames will be pointing to gicr_base_addrs. If
91  * the platform supports a non-contiguous GICR frames (GICR frames located
92  * at uneven offset), plat_arm_override_gicr_frames function can be used by
93  * such platform to override the gicr_frames.
94  */
95 void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames)
96 {
97 	assert(plat_gicr_frames != NULL);
98 	gicr_frames = plat_gicr_frames;
99 }
100 
101 /******************************************************************************
102  * ARM common helper to initialize the GIC. Only invoked by BL31
103  *****************************************************************************/
104 void __init gic_init(unsigned int cpu_idx)
105 {
106 	gicv3_driver_init(&gic_data);
107 	gicv3_distif_init();
108 }
109 
110 /******************************************************************************
111  * ARM common helper to enable the GIC CPU interface
112  *****************************************************************************/
113 void gic_cpuif_enable(unsigned int cpu_idx)
114 {
115 	gicv3_cpuif_enable(cpu_idx);
116 }
117 
118 /******************************************************************************
119  * ARM common helper to disable the GIC CPU interface
120  *****************************************************************************/
121 void gic_cpuif_disable(unsigned int cpu_idx)
122 {
123 	gicv3_cpuif_disable(cpu_idx);
124 }
125 
126 /******************************************************************************
127  * ARM common helper function to iterate over all GICR frames and discover the
128  * corresponding per-cpu redistributor frame as well as initialize the
129  * corresponding interface in GICv3.
130  *****************************************************************************/
131 void gic_pcpu_init(unsigned int cpu_idx)
132 {
133 	int result;
134 	const uintptr_t *plat_gicr_frames = gicr_frames;
135 
136 	do {
137 		result = gicv3_rdistif_probe(*plat_gicr_frames);
138 
139 		/* If the probe is successful, no need to proceed further */
140 		if (result == 0)
141 			break;
142 
143 		plat_gicr_frames++;
144 	} while (*plat_gicr_frames != 0U);
145 
146 	if (result == -1) {
147 		ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
148 		panic();
149 	}
150 	gicv3_rdistif_init(cpu_idx);
151 }
152 
153 /******************************************************************************
154  * ARM common helpers to power GIC redistributor interface
155  *****************************************************************************/
156 void gic_pcpu_off(unsigned int cpu_idx)
157 {
158 	gicv3_rdistif_off(cpu_idx);
159 }
160 
161 /******************************************************************************
162  * Common helper to save & restore the GICv3 on resume from system suspend. It
163  * is the platform's responsibility to call these.
164  *****************************************************************************/
165 void gic_save(void)
166 {
167 	gicv3_redist_ctx_t * const rdist_context =
168 			(gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
169 	gicv3_dist_ctx_t * const dist_context =
170 			(gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
171 
172 	/*
173 	 * If an ITS is available, save its context before
174 	 * the Redistributor using:
175 	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
176 	 * Additionally, an implementation-defined sequence may
177 	 * be required to save the whole ITS state.
178 	 */
179 
180 	/*
181 	 * Save the GIC Redistributors and ITS contexts before the
182 	 * Distributor context. As we only handle SYSTEM SUSPEND API,
183 	 * we only need to save the context of the CPU that is issuing
184 	 * the SYSTEM SUSPEND call, i.e. the current CPU.
185 	 */
186 	gicv3_rdistif_save(plat_my_core_pos(), rdist_context);
187 
188 	/* Save the GIC Distributor context */
189 	gicv3_distif_save(dist_context);
190 
191 	/*
192 	 * From here, all the components of the GIC can be safely powered down
193 	 * as long as there is an alternate way to handle wakeup interrupt
194 	 * sources.
195 	 */
196 }
197 
198 void gic_resume(void)
199 {
200 	const gicv3_redist_ctx_t *rdist_context =
201 			(gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
202 	const gicv3_dist_ctx_t *dist_context =
203 			(gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
204 
205 	/* Restore the GIC Distributor context */
206 	gicv3_distif_init_restore(dist_context);
207 
208 	/*
209 	 * Restore the GIC Redistributor and ITS contexts after the
210 	 * Distributor context. As we only handle SYSTEM SUSPEND API,
211 	 * we only need to restore the context of the CPU that issued
212 	 * the SYSTEM SUSPEND call.
213 	 */
214 	gicv3_rdistif_init_restore(plat_my_core_pos(), rdist_context);
215 
216 	/*
217 	 * If an ITS is available, restore its context after
218 	 * the Redistributor using:
219 	 * gicv3_its_restore(gits_base, &its_ctx[i])
220 	 * An implementation-defined sequence may be required to
221 	 * restore the whole ITS state. The ITS must also be
222 	 * re-enabled after this sequence has been executed.
223 	 */
224 }
225