1 /*
2  * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
3  * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
4  * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include <common/debug.h>
10 #include <common/interrupt_props.h>
11 #include <drivers/arm/gicv3.h>
12 #include <lib/utils.h>
13 #include <plat/common/platform.h>
14 
15 #include <plat_private.h>
16 #include <platform_def.h>
17 
18 /******************************************************************************
19  * The following functions are defined as weak to allow a platform to override
20  * the way the GICv3 driver is initialised and used.
21  *****************************************************************************/
22 #pragma weak plat_versal_net_gic_driver_init
23 #pragma weak plat_versal_net_gic_init
24 #pragma weak plat_versal_net_gic_cpuif_enable
25 #pragma weak plat_versal_net_gic_cpuif_disable
26 #pragma weak plat_versal_net_gic_pcpu_init
27 #pragma weak plat_versal_net_gic_redistif_on
28 #pragma weak plat_versal_net_gic_redistif_off
29 
30 /* The GICv3 driver only needs to be initialized in EL3 */
31 static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
32 
33 static const uintptr_t gicr_base_addrs[2] = {
34 	PLAT_VERSAL_NET_GICR_BASE,	/* GICR Base address of the primary CPU */
35 	0U				/* Zero Termination */
36 };
37 
38 /* List of zero terminated GICR frame addresses which CPUs will probe */
39 static const uintptr_t *gicr_frames;
40 
41 static const interrupt_prop_t versal_net_interrupt_props[] = {
42 	PLAT_VERSAL_NET_G1S_IRQ_PROPS(INTR_GROUP1S),
43 	PLAT_VERSAL_NET_G0_IRQ_PROPS(INTR_GROUP0)
44 };
45 
46 /*
47  * We save and restore the GICv3 context on system suspend. Allocate the
48  * data in the designated EL3 Secure carve-out memory.
49  */
50 static gicv3_redist_ctx_t rdist_ctx __section("versal_net_el3_tzc_dram");
51 static gicv3_dist_ctx_t dist_ctx __section("versal_net_el3_tzc_dram");
52 
53 /*
54  * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
55  * to core position.
56  *
57  * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
58  * values read from GICR_TYPER don't have an MT field. To reuse the same
59  * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
60  * that read from GICR_TYPER.
61  *
62  * Assumptions:
63  *
64  *   - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
65  *   - No CPUs implemented in the system use affinity level 3.
66  */
versal_net_gicv3_mpidr_hash(u_register_t mpidr)67 static uint32_t versal_net_gicv3_mpidr_hash(u_register_t mpidr)
68 {
69 	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
70 	return plat_core_pos_by_mpidr(mpidr);
71 }
72 
73 static const gicv3_driver_data_t versal_net_gic_data __unused = {
74 	.gicd_base = PLAT_VERSAL_NET_GICD_BASE,
75 	.gicr_base = 0U,
76 	.interrupt_props = versal_net_interrupt_props,
77 	.interrupt_props_num = ARRAY_SIZE(versal_net_interrupt_props),
78 	.rdistif_num = PLATFORM_CORE_COUNT,
79 	.rdistif_base_addrs = rdistif_base_addrs,
80 	.mpidr_to_core_pos = versal_net_gicv3_mpidr_hash
81 };
82 
plat_versal_net_gic_driver_init(void)83 void __init plat_versal_net_gic_driver_init(void)
84 {
85 	/*
86 	 * The GICv3 driver is initialized in EL3 and does not need
87 	 * to be initialized again in SEL1. This is because the S-EL1
88 	 * can use GIC system registers to manage interrupts and does
89 	 * not need GIC interface base addresses to be configured.
90 	 */
91 #if IMAGE_BL31
92 	gicv3_driver_init(&versal_net_gic_data);
93 	gicr_frames = gicr_base_addrs;
94 
95 	if (gicv3_rdistif_probe(gicr_frames[0]) == -1) {
96 		ERROR("No GICR base frame found for Primary CPU\n");
97 		panic();
98 	}
99 #endif
100 }
101 
102 /******************************************************************************
103  * Versal NET common helper to initialize the GIC. Only invoked by BL31
104  *****************************************************************************/
plat_versal_net_gic_init(void)105 void __init plat_versal_net_gic_init(void)
106 {
107 	gicv3_distif_init();
108 	gicv3_rdistif_init(plat_my_core_pos());
109 	gicv3_cpuif_enable(plat_my_core_pos());
110 }
111 
112 /******************************************************************************
113  * Versal NET common helper to enable the GIC CPU interface
114  *****************************************************************************/
plat_versal_net_gic_cpuif_enable(void)115 void plat_versal_net_gic_cpuif_enable(void)
116 {
117 	gicv3_cpuif_enable(plat_my_core_pos());
118 }
119 
120 /******************************************************************************
121  * Versal NET common helper to disable the GIC CPU interface
122  *****************************************************************************/
plat_versal_net_gic_cpuif_disable(void)123 void plat_versal_net_gic_cpuif_disable(void)
124 {
125 	gicv3_cpuif_disable(plat_my_core_pos());
126 }
127 
128 /******************************************************************************
129  * Versal NET common helper to initialize the per-cpu redistributor interface in
130  * GICv3
131  *****************************************************************************/
plat_versal_net_gic_pcpu_init(void)132 void plat_versal_net_gic_pcpu_init(void)
133 {
134 	int32_t result;
135 	const uintptr_t *plat_gicr_frames = gicr_frames;
136 
137 	do {
138 		result = gicv3_rdistif_probe(*plat_gicr_frames);
139 
140 		/* If the probe is successful, no need to proceed further */
141 		if (result == 0) {
142 			break;
143 		}
144 
145 		plat_gicr_frames++;
146 	} while (*plat_gicr_frames != 0U);
147 
148 	if (result == -1) {
149 		ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
150 		panic();
151 	}
152 
153 	gicv3_rdistif_init(plat_my_core_pos());
154 }
155 
156 /******************************************************************************
157  * Versal NET common helpers to power GIC redistributor interface
158  *****************************************************************************/
plat_versal_net_gic_redistif_on(void)159 void plat_versal_net_gic_redistif_on(void)
160 {
161 	gicv3_rdistif_on(plat_my_core_pos());
162 }
163 
plat_versal_net_gic_redistif_off(void)164 void plat_versal_net_gic_redistif_off(void)
165 {
166 	gicv3_rdistif_off(plat_my_core_pos());
167 }
168 
169 /******************************************************************************
170  * Versal NET common helper to save & restore the GICv3 on resume from system
171  * suspend
172  *****************************************************************************/
plat_versal_net_gic_save(void)173 void plat_versal_net_gic_save(void)
174 {
175 	/*
176 	 * If an ITS is available, save its context before
177 	 * the Redistributor using:
178 	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
179 	 * Additionnaly, an implementation-defined sequence may
180 	 * be required to save the whole ITS state.
181 	 */
182 
183 	/*
184 	 * Save the GIC Redistributors and ITS contexts before the
185 	 * Distributor context. As we only handle SYSTEM SUSPEND API,
186 	 * we only need to save the context of the CPU that is issuing
187 	 * the SYSTEM SUSPEND call, i.e. the current CPU.
188 	 */
189 	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
190 
191 	/* Save the GIC Distributor context */
192 	gicv3_distif_save(&dist_ctx);
193 
194 	/*
195 	 * From here, all the components of the GIC can be safely powered down
196 	 * as long as there is an alternate way to handle wakeup interrupt
197 	 * sources.
198 	 */
199 }
200 
plat_versal_net_gic_resume(void)201 void plat_versal_net_gic_resume(void)
202 {
203 	/* Restore the GIC Distributor context */
204 	gicv3_distif_init_restore(&dist_ctx);
205 
206 	/*
207 	 * Restore the GIC Redistributor and ITS contexts after the
208 	 * Distributor context. As we only handle SYSTEM SUSPEND API,
209 	 * we only need to restore the context of the CPU that issued
210 	 * the SYSTEM SUSPEND call.
211 	 */
212 	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
213 
214 	/*
215 	 * If an ITS is available, restore its context after
216 	 * the Redistributor using:
217 	 * gicv3_its_restore(gits_base, &its_ctx[i])
218 	 * An implementation-defined sequence may be required to
219 	 * restore the whole ITS state. The ITS must also be
220 	 * re-enabled after this sequence has been executed.
221 	 */
222 }
223