xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/arm/gic/v3/gic-x00.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
4*54fd6939SJiyong Park  *
5*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
6*54fd6939SJiyong Park  */
7*54fd6939SJiyong Park 
8*54fd6939SJiyong Park /*
9*54fd6939SJiyong Park  * Driver for GIC-500 and GIC-600 specific features. This driver only
10*54fd6939SJiyong Park  * overrides APIs that are different to those generic ones in GICv3
11*54fd6939SJiyong Park  * driver.
12*54fd6939SJiyong Park  *
13*54fd6939SJiyong Park  * GIC-600 supports independently power-gating redistributor interface.
14*54fd6939SJiyong Park  */
15*54fd6939SJiyong Park 
16*54fd6939SJiyong Park #include <assert.h>
17*54fd6939SJiyong Park 
18*54fd6939SJiyong Park #include <arch_helpers.h>
19*54fd6939SJiyong Park #include <drivers/arm/arm_gicv3_common.h>
20*54fd6939SJiyong Park #include <drivers/arm/gicv3.h>
21*54fd6939SJiyong Park 
22*54fd6939SJiyong Park #include "gicv3_private.h"
23*54fd6939SJiyong Park 
24*54fd6939SJiyong Park /* GIC-600 specific register offsets */
25*54fd6939SJiyong Park #define GICR_PWRR			0x24U
26*54fd6939SJiyong Park 
27*54fd6939SJiyong Park /* GICR_PWRR fields */
28*54fd6939SJiyong Park #define PWRR_RDPD_SHIFT			0
29*54fd6939SJiyong Park #define PWRR_RDAG_SHIFT			1
30*54fd6939SJiyong Park #define PWRR_RDGPD_SHIFT		2
31*54fd6939SJiyong Park #define PWRR_RDGPO_SHIFT		3
32*54fd6939SJiyong Park 
33*54fd6939SJiyong Park #define PWRR_RDPD			(1U << PWRR_RDPD_SHIFT)
34*54fd6939SJiyong Park #define PWRR_RDAG			(1U << PWRR_RDAG_SHIFT)
35*54fd6939SJiyong Park #define PWRR_RDGPD			(1U << PWRR_RDGPD_SHIFT)
36*54fd6939SJiyong Park #define PWRR_RDGPO			(1U << PWRR_RDGPO_SHIFT)
37*54fd6939SJiyong Park 
38*54fd6939SJiyong Park /*
39*54fd6939SJiyong Park  * Values to write to GICR_PWRR register to power redistributor
40*54fd6939SJiyong Park  * for operating through the core (GICR_PWRR.RDAG = 0)
41*54fd6939SJiyong Park  */
42*54fd6939SJiyong Park #define PWRR_ON				(0U << PWRR_RDPD_SHIFT)
43*54fd6939SJiyong Park #define PWRR_OFF			(1U << PWRR_RDPD_SHIFT)
44*54fd6939SJiyong Park 
45*54fd6939SJiyong Park #if GICV3_SUPPORT_GIC600
46*54fd6939SJiyong Park 
47*54fd6939SJiyong Park /* GIC-600/700 specific accessor functions */
gicr_write_pwrr(uintptr_t base,unsigned int val)48*54fd6939SJiyong Park static void gicr_write_pwrr(uintptr_t base, unsigned int val)
49*54fd6939SJiyong Park {
50*54fd6939SJiyong Park 	mmio_write_32(base + GICR_PWRR, val);
51*54fd6939SJiyong Park }
52*54fd6939SJiyong Park 
gicr_read_pwrr(uintptr_t base)53*54fd6939SJiyong Park static uint32_t gicr_read_pwrr(uintptr_t base)
54*54fd6939SJiyong Park {
55*54fd6939SJiyong Park 	return mmio_read_32(base + GICR_PWRR);
56*54fd6939SJiyong Park }
57*54fd6939SJiyong Park 
gicr_wait_group_not_in_transit(uintptr_t base)58*54fd6939SJiyong Park static void gicr_wait_group_not_in_transit(uintptr_t base)
59*54fd6939SJiyong Park {
60*54fd6939SJiyong Park 	uint32_t pwrr;
61*54fd6939SJiyong Park 
62*54fd6939SJiyong Park 	do {
63*54fd6939SJiyong Park 		pwrr = gicr_read_pwrr(base);
64*54fd6939SJiyong Park 
65*54fd6939SJiyong Park 	/* Check group not transitioning: RDGPD == RDGPO */
66*54fd6939SJiyong Park 	} while (((pwrr & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) !=
67*54fd6939SJiyong Park 		 ((pwrr & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT));
68*54fd6939SJiyong Park }
69*54fd6939SJiyong Park 
gic600_pwr_on(uintptr_t base)70*54fd6939SJiyong Park static void gic600_pwr_on(uintptr_t base)
71*54fd6939SJiyong Park {
72*54fd6939SJiyong Park 	do {	/* Wait until group not transitioning */
73*54fd6939SJiyong Park 		gicr_wait_group_not_in_transit(base);
74*54fd6939SJiyong Park 
75*54fd6939SJiyong Park 		/* Power on redistributor */
76*54fd6939SJiyong Park 		gicr_write_pwrr(base, PWRR_ON);
77*54fd6939SJiyong Park 
78*54fd6939SJiyong Park 		/*
79*54fd6939SJiyong Park 		 * Wait until the power on state is reflected.
80*54fd6939SJiyong Park 		 * If RDPD == 0 then powered on.
81*54fd6939SJiyong Park 		 */
82*54fd6939SJiyong Park 	} while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON);
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park 
gic600_pwr_off(uintptr_t base)85*54fd6939SJiyong Park static void gic600_pwr_off(uintptr_t base)
86*54fd6939SJiyong Park {
87*54fd6939SJiyong Park 	/* Wait until group not transitioning */
88*54fd6939SJiyong Park 	gicr_wait_group_not_in_transit(base);
89*54fd6939SJiyong Park 
90*54fd6939SJiyong Park 	/* Power off redistributor */
91*54fd6939SJiyong Park 	gicr_write_pwrr(base, PWRR_OFF);
92*54fd6939SJiyong Park 
93*54fd6939SJiyong Park 	/*
94*54fd6939SJiyong Park 	 * If this is the last man, turning this redistributor frame off will
95*54fd6939SJiyong Park 	 * result in the group itself being powered off and RDGPD = 1.
96*54fd6939SJiyong Park 	 * In that case, wait as long as it's in transition, or has aborted
97*54fd6939SJiyong Park 	 * the transition altogether for any reason.
98*54fd6939SJiyong Park 	 */
99*54fd6939SJiyong Park 	if ((gicr_read_pwrr(base) & PWRR_RDGPD) != 0U) {
100*54fd6939SJiyong Park 		/* Wait until group not transitioning */
101*54fd6939SJiyong Park 		gicr_wait_group_not_in_transit(base);
102*54fd6939SJiyong Park 	}
103*54fd6939SJiyong Park }
104*54fd6939SJiyong Park 
get_gicr_base(unsigned int proc_num)105*54fd6939SJiyong Park static uintptr_t get_gicr_base(unsigned int proc_num)
106*54fd6939SJiyong Park {
107*54fd6939SJiyong Park 	uintptr_t gicr_base;
108*54fd6939SJiyong Park 
109*54fd6939SJiyong Park 	assert(gicv3_driver_data != NULL);
110*54fd6939SJiyong Park 	assert(proc_num < gicv3_driver_data->rdistif_num);
111*54fd6939SJiyong Park 	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
112*54fd6939SJiyong Park 
113*54fd6939SJiyong Park 	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
114*54fd6939SJiyong Park 	assert(gicr_base != 0UL);
115*54fd6939SJiyong Park 
116*54fd6939SJiyong Park 	return gicr_base;
117*54fd6939SJiyong Park }
118*54fd6939SJiyong Park 
gicv3_redists_need_power_mgmt(uintptr_t gicr_base)119*54fd6939SJiyong Park static bool gicv3_redists_need_power_mgmt(uintptr_t gicr_base)
120*54fd6939SJiyong Park {
121*54fd6939SJiyong Park 	uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR);
122*54fd6939SJiyong Park 
123*54fd6939SJiyong Park 	/*
124*54fd6939SJiyong Park 	 * The Arm GIC-600 and GIC-700 models have their redistributors
125*54fd6939SJiyong Park 	 * powered down at reset.
126*54fd6939SJiyong Park 	 */
127*54fd6939SJiyong Park 	return (((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
128*54fd6939SJiyong Park 		((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600AE) ||
129*54fd6939SJiyong Park 		((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700));
130*54fd6939SJiyong Park }
131*54fd6939SJiyong Park 
132*54fd6939SJiyong Park #endif	/* GICV3_SUPPORT_GIC600 */
133*54fd6939SJiyong Park 
gicv3_distif_pre_save(unsigned int proc_num)134*54fd6939SJiyong Park void gicv3_distif_pre_save(unsigned int proc_num)
135*54fd6939SJiyong Park {
136*54fd6939SJiyong Park 	arm_gicv3_distif_pre_save(proc_num);
137*54fd6939SJiyong Park }
138*54fd6939SJiyong Park 
gicv3_distif_post_restore(unsigned int proc_num)139*54fd6939SJiyong Park void gicv3_distif_post_restore(unsigned int proc_num)
140*54fd6939SJiyong Park {
141*54fd6939SJiyong Park 	arm_gicv3_distif_post_restore(proc_num);
142*54fd6939SJiyong Park }
143*54fd6939SJiyong Park 
144*54fd6939SJiyong Park /*
145*54fd6939SJiyong Park  * Power off GIC-600 redistributor (if configured and detected)
146*54fd6939SJiyong Park  */
gicv3_rdistif_off(unsigned int proc_num)147*54fd6939SJiyong Park void gicv3_rdistif_off(unsigned int proc_num)
148*54fd6939SJiyong Park {
149*54fd6939SJiyong Park #if GICV3_SUPPORT_GIC600
150*54fd6939SJiyong Park 	uintptr_t gicr_base = get_gicr_base(proc_num);
151*54fd6939SJiyong Park 
152*54fd6939SJiyong Park 	/* Attempt to power redistributor off */
153*54fd6939SJiyong Park 	if (gicv3_redists_need_power_mgmt(gicr_base)) {
154*54fd6939SJiyong Park 		gic600_pwr_off(gicr_base);
155*54fd6939SJiyong Park 	}
156*54fd6939SJiyong Park #endif
157*54fd6939SJiyong Park }
158*54fd6939SJiyong Park 
159*54fd6939SJiyong Park /*
160*54fd6939SJiyong Park  * Power on GIC-600 redistributor (if configured and detected)
161*54fd6939SJiyong Park  */
gicv3_rdistif_on(unsigned int proc_num)162*54fd6939SJiyong Park void gicv3_rdistif_on(unsigned int proc_num)
163*54fd6939SJiyong Park {
164*54fd6939SJiyong Park #if GICV3_SUPPORT_GIC600
165*54fd6939SJiyong Park 	uintptr_t gicr_base = get_gicr_base(proc_num);
166*54fd6939SJiyong Park 
167*54fd6939SJiyong Park 	/* Power redistributor on */
168*54fd6939SJiyong Park 	if (gicv3_redists_need_power_mgmt(gicr_base)) {
169*54fd6939SJiyong Park 		gic600_pwr_on(gicr_base);
170*54fd6939SJiyong Park 	}
171*54fd6939SJiyong Park #endif
172*54fd6939SJiyong Park }
173