xref: /arm-trusted-firmware/drivers/arm/gic/v3/gic-x00.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu /*
9*91f16700Schasinglulu  * Driver for GIC-500 and GIC-600 specific features. This driver only
10*91f16700Schasinglulu  * overrides APIs that are different to those generic ones in GICv3
11*91f16700Schasinglulu  * driver.
12*91f16700Schasinglulu  *
13*91f16700Schasinglulu  * GIC-600 supports independently power-gating redistributor interface.
14*91f16700Schasinglulu  */
15*91f16700Schasinglulu 
16*91f16700Schasinglulu #include <assert.h>
17*91f16700Schasinglulu 
18*91f16700Schasinglulu #include <arch_helpers.h>
19*91f16700Schasinglulu #include <common/debug.h>
20*91f16700Schasinglulu #include <drivers/arm/arm_gicv3_common.h>
21*91f16700Schasinglulu #include <drivers/arm/gicv3.h>
22*91f16700Schasinglulu 
23*91f16700Schasinglulu #include "gicv3_private.h"
24*91f16700Schasinglulu 
25*91f16700Schasinglulu /* GIC-600 specific register offsets */
26*91f16700Schasinglulu #define GICR_PWRR			0x24U
27*91f16700Schasinglulu 
28*91f16700Schasinglulu /* GICR_PWRR fields */
29*91f16700Schasinglulu #define PWRR_RDPD_SHIFT			0
30*91f16700Schasinglulu #define PWRR_RDAG_SHIFT			1
31*91f16700Schasinglulu #define PWRR_RDGPD_SHIFT		2
32*91f16700Schasinglulu #define PWRR_RDGPO_SHIFT		3
33*91f16700Schasinglulu 
34*91f16700Schasinglulu #define PWRR_RDPD			(1U << PWRR_RDPD_SHIFT)
35*91f16700Schasinglulu #define PWRR_RDAG			(1U << PWRR_RDAG_SHIFT)
36*91f16700Schasinglulu #define PWRR_RDGPD			(1U << PWRR_RDGPD_SHIFT)
37*91f16700Schasinglulu #define PWRR_RDGPO			(1U << PWRR_RDGPO_SHIFT)
38*91f16700Schasinglulu 
39*91f16700Schasinglulu /*
40*91f16700Schasinglulu  * Values to write to GICR_PWRR register to power redistributor
41*91f16700Schasinglulu  * for operating through the core (GICR_PWRR.RDAG = 0)
42*91f16700Schasinglulu  */
43*91f16700Schasinglulu #define PWRR_ON				(0U << PWRR_RDPD_SHIFT)
44*91f16700Schasinglulu #define PWRR_OFF			(1U << PWRR_RDPD_SHIFT)
45*91f16700Schasinglulu 
46*91f16700Schasinglulu static bool gic600_errata_wa_2384374 __unused;
47*91f16700Schasinglulu 
48*91f16700Schasinglulu #if GICV3_SUPPORT_GIC600
49*91f16700Schasinglulu 
50*91f16700Schasinglulu /* GIC-600/700 specific accessor functions */
51*91f16700Schasinglulu static void gicr_write_pwrr(uintptr_t base, unsigned int val)
52*91f16700Schasinglulu {
53*91f16700Schasinglulu 	mmio_write_32(base + GICR_PWRR, val);
54*91f16700Schasinglulu }
55*91f16700Schasinglulu 
56*91f16700Schasinglulu static uint32_t gicr_read_pwrr(uintptr_t base)
57*91f16700Schasinglulu {
58*91f16700Schasinglulu 	return mmio_read_32(base + GICR_PWRR);
59*91f16700Schasinglulu }
60*91f16700Schasinglulu 
61*91f16700Schasinglulu static void gicr_wait_group_not_in_transit(uintptr_t base)
62*91f16700Schasinglulu {
63*91f16700Schasinglulu 	uint32_t pwrr;
64*91f16700Schasinglulu 
65*91f16700Schasinglulu 	do {
66*91f16700Schasinglulu 		pwrr = gicr_read_pwrr(base);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	/* Check group not transitioning: RDGPD == RDGPO */
69*91f16700Schasinglulu 	} while (((pwrr & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) !=
70*91f16700Schasinglulu 		 ((pwrr & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT));
71*91f16700Schasinglulu }
72*91f16700Schasinglulu 
73*91f16700Schasinglulu static void gic600_pwr_on(uintptr_t base)
74*91f16700Schasinglulu {
75*91f16700Schasinglulu 	do {	/* Wait until group not transitioning */
76*91f16700Schasinglulu 		gicr_wait_group_not_in_transit(base);
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 		/* Power on redistributor */
79*91f16700Schasinglulu 		gicr_write_pwrr(base, PWRR_ON);
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 		/*
82*91f16700Schasinglulu 		 * Wait until the power on state is reflected.
83*91f16700Schasinglulu 		 * If RDPD == 0 then powered on.
84*91f16700Schasinglulu 		 */
85*91f16700Schasinglulu 	} while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON);
86*91f16700Schasinglulu }
87*91f16700Schasinglulu 
88*91f16700Schasinglulu static void gic600_pwr_off(uintptr_t base)
89*91f16700Schasinglulu {
90*91f16700Schasinglulu 	/* Wait until group not transitioning */
91*91f16700Schasinglulu 	gicr_wait_group_not_in_transit(base);
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	/* Power off redistributor */
94*91f16700Schasinglulu 	gicr_write_pwrr(base, PWRR_OFF);
95*91f16700Schasinglulu 
96*91f16700Schasinglulu 	/*
97*91f16700Schasinglulu 	 * If this is the last man, turning this redistributor frame off will
98*91f16700Schasinglulu 	 * result in the group itself being powered off and RDGPD = 1.
99*91f16700Schasinglulu 	 * In that case, wait as long as it's in transition, or has aborted
100*91f16700Schasinglulu 	 * the transition altogether for any reason.
101*91f16700Schasinglulu 	 */
102*91f16700Schasinglulu 	if ((gicr_read_pwrr(base) & PWRR_RDGPD) != 0U) {
103*91f16700Schasinglulu 		/* Wait until group not transitioning */
104*91f16700Schasinglulu 		gicr_wait_group_not_in_transit(base);
105*91f16700Schasinglulu 	}
106*91f16700Schasinglulu }
107*91f16700Schasinglulu 
108*91f16700Schasinglulu static uintptr_t get_gicr_base(unsigned int proc_num)
109*91f16700Schasinglulu {
110*91f16700Schasinglulu 	uintptr_t gicr_base;
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	assert(gicv3_driver_data != NULL);
113*91f16700Schasinglulu 	assert(proc_num < gicv3_driver_data->rdistif_num);
114*91f16700Schasinglulu 	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
115*91f16700Schasinglulu 
116*91f16700Schasinglulu 	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
117*91f16700Schasinglulu 	assert(gicr_base != 0UL);
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 	return gicr_base;
120*91f16700Schasinglulu }
121*91f16700Schasinglulu 
122*91f16700Schasinglulu static bool gicv3_redists_need_power_mgmt(uintptr_t gicr_base)
123*91f16700Schasinglulu {
124*91f16700Schasinglulu 	uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR);
125*91f16700Schasinglulu 
126*91f16700Schasinglulu 	/*
127*91f16700Schasinglulu 	 * The Arm GIC-600 and GIC-700 models have their redistributors
128*91f16700Schasinglulu 	 * powered down at reset.
129*91f16700Schasinglulu 	 */
130*91f16700Schasinglulu 	return (((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
131*91f16700Schasinglulu 		((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600AE) ||
132*91f16700Schasinglulu 		((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700));
133*91f16700Schasinglulu }
134*91f16700Schasinglulu 
135*91f16700Schasinglulu #endif	/* GICV3_SUPPORT_GIC600 */
136*91f16700Schasinglulu 
137*91f16700Schasinglulu void gicv3_distif_pre_save(unsigned int proc_num)
138*91f16700Schasinglulu {
139*91f16700Schasinglulu 	arm_gicv3_distif_pre_save(proc_num);
140*91f16700Schasinglulu }
141*91f16700Schasinglulu 
142*91f16700Schasinglulu void gicv3_distif_post_restore(unsigned int proc_num)
143*91f16700Schasinglulu {
144*91f16700Schasinglulu 	arm_gicv3_distif_post_restore(proc_num);
145*91f16700Schasinglulu }
146*91f16700Schasinglulu 
147*91f16700Schasinglulu /*
148*91f16700Schasinglulu  * Power off GIC-600 redistributor (if configured and detected)
149*91f16700Schasinglulu  */
150*91f16700Schasinglulu void gicv3_rdistif_off(unsigned int proc_num)
151*91f16700Schasinglulu {
152*91f16700Schasinglulu #if GICV3_SUPPORT_GIC600
153*91f16700Schasinglulu 	uintptr_t gicr_base = get_gicr_base(proc_num);
154*91f16700Schasinglulu 
155*91f16700Schasinglulu 	/* Attempt to power redistributor off */
156*91f16700Schasinglulu 	if (gicv3_redists_need_power_mgmt(gicr_base)) {
157*91f16700Schasinglulu 		gic600_pwr_off(gicr_base);
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu #endif
160*91f16700Schasinglulu }
161*91f16700Schasinglulu 
162*91f16700Schasinglulu /*
163*91f16700Schasinglulu  * Power on GIC-600 redistributor (if configured and detected)
164*91f16700Schasinglulu  */
165*91f16700Schasinglulu void gicv3_rdistif_on(unsigned int proc_num)
166*91f16700Schasinglulu {
167*91f16700Schasinglulu #if GICV3_SUPPORT_GIC600
168*91f16700Schasinglulu 	uintptr_t gicr_base = get_gicr_base(proc_num);
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 	/* Power redistributor on */
171*91f16700Schasinglulu 	if (gicv3_redists_need_power_mgmt(gicr_base)) {
172*91f16700Schasinglulu 		gic600_pwr_on(gicr_base);
173*91f16700Schasinglulu 	}
174*91f16700Schasinglulu #endif
175*91f16700Schasinglulu }
176*91f16700Schasinglulu 
177*91f16700Schasinglulu #if GIC600_ERRATA_WA_2384374
178*91f16700Schasinglulu /*******************************************************************************
179*91f16700Schasinglulu  * Apply part 2 of workaround for errata-2384374 as per SDEN:
180*91f16700Schasinglulu  * https://developer.arm.com/documentation/sden892601/latest/
181*91f16700Schasinglulu  ******************************************************************************/
182*91f16700Schasinglulu void gicv3_apply_errata_wa_2384374(uintptr_t gicr_base)
183*91f16700Schasinglulu {
184*91f16700Schasinglulu 	if (gic600_errata_wa_2384374) {
185*91f16700Schasinglulu 		uint32_t gicr_ctlr_val = gicr_read_ctlr(gicr_base);
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 		gicr_write_ctlr(gicr_base, gicr_ctlr_val |
188*91f16700Schasinglulu 				(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
189*91f16700Schasinglulu 				GICR_CTLR_DPG1S_BIT));
190*91f16700Schasinglulu 		gicr_write_ctlr(gicr_base, gicr_ctlr_val &
191*91f16700Schasinglulu 				~(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
192*91f16700Schasinglulu 				  GICR_CTLR_DPG1S_BIT));
193*91f16700Schasinglulu 	}
194*91f16700Schasinglulu }
195*91f16700Schasinglulu #endif /* GIC600_ERRATA_WA_2384374 */
196*91f16700Schasinglulu 
197*91f16700Schasinglulu void gicv3_check_erratas_applies(uintptr_t gicd_base)
198*91f16700Schasinglulu {
199*91f16700Schasinglulu 	unsigned int gic_prod_id;
200*91f16700Schasinglulu 	uint8_t gic_rev;
201*91f16700Schasinglulu 
202*91f16700Schasinglulu 	assert(gicd_base != 0UL);
203*91f16700Schasinglulu 
204*91f16700Schasinglulu 	gicv3_get_component_prodid_rev(gicd_base, &gic_prod_id, &gic_rev);
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	/*
207*91f16700Schasinglulu 	 * This workaround applicable only to GIC600 and GIC600AE products with
208*91f16700Schasinglulu 	 * revision less than r1p6 and r0p2 respectively.
209*91f16700Schasinglulu 	 * As per GIC600/GIC600AE specification -
210*91f16700Schasinglulu 	 * r1p6 = 0x17 => GICD_IIDR[19:12]
211*91f16700Schasinglulu 	 * r0p2 = 0x04 => GICD_IIDR[19:12]
212*91f16700Schasinglulu 	 */
213*91f16700Schasinglulu 	if ((gic_prod_id == GIC_PRODUCT_ID_GIC600) ||
214*91f16700Schasinglulu 		    (gic_prod_id == GIC_PRODUCT_ID_GIC600AE)) {
215*91f16700Schasinglulu 		if (((gic_prod_id == GIC_PRODUCT_ID_GIC600) &&
216*91f16700Schasinglulu 		     (gic_rev <= GIC_REV(GIC_VARIANT_R1, GIC_REV_P6))) ||
217*91f16700Schasinglulu 		     ((gic_prod_id == GIC_PRODUCT_ID_GIC600AE) &&
218*91f16700Schasinglulu 		     (gic_rev <= GIC_REV(GIC_VARIANT_R0, GIC_REV_P2)))) {
219*91f16700Schasinglulu #if GIC600_ERRATA_WA_2384374
220*91f16700Schasinglulu 			gic600_errata_wa_2384374 = true;
221*91f16700Schasinglulu 			VERBOSE("%s applies\n",
222*91f16700Schasinglulu 				"GIC600/GIC600AE errata workaround 2384374");
223*91f16700Schasinglulu #else
224*91f16700Schasinglulu 			WARN("%s missing\n",
225*91f16700Schasinglulu 			     "GIC600/GIC600AE errata workaround 2384374");
226*91f16700Schasinglulu #endif /* GIC600_ERRATA_WA_2384374 */
227*91f16700Schasinglulu 		} else {
228*91f16700Schasinglulu 			VERBOSE("%s not applies\n",
229*91f16700Schasinglulu 				"GIC600/GIC600AE errata workaround 2384374");
230*91f16700Schasinglulu 		}
231*91f16700Schasinglulu 	}
232*91f16700Schasinglulu }
233