xref: /arm-trusted-firmware/drivers/arm/gic/v3/gic600ae_fmu_helpers.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <arch.h>
11*91f16700Schasinglulu #include <arch_helpers.h>
12*91f16700Schasinglulu #include <drivers/arm/gic600ae_fmu.h>
13*91f16700Schasinglulu #include <drivers/delay_timer.h>
14*91f16700Schasinglulu #include <lib/mmio.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu #define GICFMU_IDLE_TIMEOUT_US		U(2000000)
17*91f16700Schasinglulu 
18*91f16700Schasinglulu /* Macro to write 32-bit FMU registers */
19*91f16700Schasinglulu #define GIC_FMU_WRITE_32(base, reg, val) \
20*91f16700Schasinglulu 	do { \
21*91f16700Schasinglulu 		/* \
22*91f16700Schasinglulu 		 * This register receives the unlock key that is required for \
23*91f16700Schasinglulu 		 * writes to FMU registers to be successful. \
24*91f16700Schasinglulu 		 */ \
25*91f16700Schasinglulu 		mmio_write_32(base + GICFMU_KEY, 0xBE); \
26*91f16700Schasinglulu 		/* Perform the actual write */ \
27*91f16700Schasinglulu 		mmio_write_32((base) + (reg), (val)); \
28*91f16700Schasinglulu 	} while (false)
29*91f16700Schasinglulu 
30*91f16700Schasinglulu /* Macro to write 64-bit FMU registers */
31*91f16700Schasinglulu #define GIC_FMU_WRITE_64(base, reg, n, val) \
32*91f16700Schasinglulu 	do { \
33*91f16700Schasinglulu 		/* \
34*91f16700Schasinglulu 		 * This register receives the unlock key that is required for \
35*91f16700Schasinglulu 		 * writes to FMU registers to be successful. \
36*91f16700Schasinglulu 		 */ \
37*91f16700Schasinglulu 		mmio_write_32(base + GICFMU_KEY, 0xBE); \
38*91f16700Schasinglulu 		/* \
39*91f16700Schasinglulu 		 * APB bus is 32-bit wide; so split the 64-bit write into \
40*91f16700Schasinglulu 		 * two 32-bit writes \
41*91f16700Schasinglulu 		 */ \
42*91f16700Schasinglulu 		mmio_write_32((base) + reg##_LO + (n * 64), (val)); \
43*91f16700Schasinglulu 		mmio_write_32((base) + reg##_HI + (n * 64), (val)); \
44*91f16700Schasinglulu 	} while (false)
45*91f16700Schasinglulu 
46*91f16700Schasinglulu /* Helper function to wait until FMU is ready to accept the next command */
47*91f16700Schasinglulu static void wait_until_fmu_is_idle(uintptr_t base)
48*91f16700Schasinglulu {
49*91f16700Schasinglulu 	uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US;
50*91f16700Schasinglulu 	uint64_t status;
51*91f16700Schasinglulu 
52*91f16700Schasinglulu 	/* wait until status is 'busy' */
53*91f16700Schasinglulu 	do {
54*91f16700Schasinglulu 		status = (gic_fmu_read_status(base) & BIT(0));
55*91f16700Schasinglulu 
56*91f16700Schasinglulu 		if (timeout_count-- == 0U) {
57*91f16700Schasinglulu 			ERROR("GIC600 AE FMU is not responding\n");
58*91f16700Schasinglulu 			panic();
59*91f16700Schasinglulu 		}
60*91f16700Schasinglulu 
61*91f16700Schasinglulu 		udelay(1U);
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	} while (status == U(0));
64*91f16700Schasinglulu }
65*91f16700Schasinglulu 
66*91f16700Schasinglulu #define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \
67*91f16700Schasinglulu 	do { \
68*91f16700Schasinglulu 		/* Wait until FMU is ready */ \
69*91f16700Schasinglulu 		wait_until_fmu_is_idle(base); \
70*91f16700Schasinglulu 		/* Actual register write */ \
71*91f16700Schasinglulu 		GIC_FMU_WRITE_32(base, reg, val); \
72*91f16700Schasinglulu 		/* Wait until FMU is ready */ \
73*91f16700Schasinglulu 		wait_until_fmu_is_idle(base); \
74*91f16700Schasinglulu 	} while (false)
75*91f16700Schasinglulu 
76*91f16700Schasinglulu #define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \
77*91f16700Schasinglulu 	do { \
78*91f16700Schasinglulu 		/* Wait until FMU is ready */ \
79*91f16700Schasinglulu 		wait_until_fmu_is_idle(base); \
80*91f16700Schasinglulu 		/* Actual register write */ \
81*91f16700Schasinglulu 		GIC_FMU_WRITE_64(base, reg, n, val); \
82*91f16700Schasinglulu 		/* Wait until FMU is ready */ \
83*91f16700Schasinglulu 		wait_until_fmu_is_idle(base); \
84*91f16700Schasinglulu 	} while (false)
85*91f16700Schasinglulu 
86*91f16700Schasinglulu /*******************************************************************************
87*91f16700Schasinglulu  * GIC FMU functions for accessing the Fault Management Unit registers
88*91f16700Schasinglulu  ******************************************************************************/
89*91f16700Schasinglulu 
90*91f16700Schasinglulu /*
91*91f16700Schasinglulu  * Accessors to read the Error Record Feature Register bits corresponding
92*91f16700Schasinglulu  * to an error record 'n'
93*91f16700Schasinglulu  */
94*91f16700Schasinglulu uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n)
95*91f16700Schasinglulu {
96*91f16700Schasinglulu 	/*
97*91f16700Schasinglulu 	 * APB bus is 32-bit wide; so split the 64-bit read into
98*91f16700Schasinglulu 	 * two 32-bit reads
99*91f16700Schasinglulu 	 */
100*91f16700Schasinglulu 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U);
101*91f16700Schasinglulu 
102*91f16700Schasinglulu 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32);
103*91f16700Schasinglulu 	return reg_val;
104*91f16700Schasinglulu }
105*91f16700Schasinglulu 
106*91f16700Schasinglulu /*
107*91f16700Schasinglulu  * Accessors to read the Error Record Control Register bits corresponding
108*91f16700Schasinglulu  * to an error record 'n'
109*91f16700Schasinglulu  */
110*91f16700Schasinglulu uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n)
111*91f16700Schasinglulu {
112*91f16700Schasinglulu 	/*
113*91f16700Schasinglulu 	 * APB bus is 32-bit wide; so split the 64-bit read into
114*91f16700Schasinglulu 	 * two 32-bit reads
115*91f16700Schasinglulu 	 */
116*91f16700Schasinglulu 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U);
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32);
119*91f16700Schasinglulu 	return reg_val;
120*91f16700Schasinglulu }
121*91f16700Schasinglulu 
122*91f16700Schasinglulu /*
123*91f16700Schasinglulu  * Accessors to read the Error Record Primary Status Register bits
124*91f16700Schasinglulu  * corresponding to an error record 'n'
125*91f16700Schasinglulu  */
126*91f16700Schasinglulu uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n)
127*91f16700Schasinglulu {
128*91f16700Schasinglulu 	/*
129*91f16700Schasinglulu 	 * APB bus is 32-bit wide; so split the 64-bit read into
130*91f16700Schasinglulu 	 * two 32-bit reads
131*91f16700Schasinglulu 	 */
132*91f16700Schasinglulu 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U);
133*91f16700Schasinglulu 
134*91f16700Schasinglulu 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32);
135*91f16700Schasinglulu 	return reg_val;
136*91f16700Schasinglulu }
137*91f16700Schasinglulu 
138*91f16700Schasinglulu /*
139*91f16700Schasinglulu  * Accessors to read the Error Group Status Register
140*91f16700Schasinglulu  */
141*91f16700Schasinglulu uint64_t gic_fmu_read_errgsr(uintptr_t base)
142*91f16700Schasinglulu {
143*91f16700Schasinglulu 	/*
144*91f16700Schasinglulu 	 * APB bus is 32-bit wide; so split the 64-bit read into
145*91f16700Schasinglulu 	 * two 32-bit reads
146*91f16700Schasinglulu 	 */
147*91f16700Schasinglulu 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO);
148*91f16700Schasinglulu 
149*91f16700Schasinglulu 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32);
150*91f16700Schasinglulu 	return reg_val;
151*91f16700Schasinglulu }
152*91f16700Schasinglulu 
153*91f16700Schasinglulu /*
154*91f16700Schasinglulu  * Accessors to read the Ping Control Register
155*91f16700Schasinglulu  */
156*91f16700Schasinglulu uint32_t gic_fmu_read_pingctlr(uintptr_t base)
157*91f16700Schasinglulu {
158*91f16700Schasinglulu 	return mmio_read_32(base + GICFMU_PINGCTLR);
159*91f16700Schasinglulu }
160*91f16700Schasinglulu 
161*91f16700Schasinglulu /*
162*91f16700Schasinglulu  * Accessors to read the Ping Now Register
163*91f16700Schasinglulu  */
164*91f16700Schasinglulu uint32_t gic_fmu_read_pingnow(uintptr_t base)
165*91f16700Schasinglulu {
166*91f16700Schasinglulu 	return mmio_read_32(base + GICFMU_PINGNOW);
167*91f16700Schasinglulu }
168*91f16700Schasinglulu 
169*91f16700Schasinglulu /*
170*91f16700Schasinglulu  * Accessors to read the Ping Mask Register
171*91f16700Schasinglulu  */
172*91f16700Schasinglulu uint64_t gic_fmu_read_pingmask(uintptr_t base)
173*91f16700Schasinglulu {
174*91f16700Schasinglulu 	/*
175*91f16700Schasinglulu 	 * APB bus is 32-bit wide; so split the 64-bit read into
176*91f16700Schasinglulu 	 * two 32-bit reads
177*91f16700Schasinglulu 	 */
178*91f16700Schasinglulu 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO);
179*91f16700Schasinglulu 
180*91f16700Schasinglulu 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32);
181*91f16700Schasinglulu 	return reg_val;
182*91f16700Schasinglulu }
183*91f16700Schasinglulu 
184*91f16700Schasinglulu /*
185*91f16700Schasinglulu  * Accessors to read the FMU Status Register
186*91f16700Schasinglulu  */
187*91f16700Schasinglulu uint32_t gic_fmu_read_status(uintptr_t base)
188*91f16700Schasinglulu {
189*91f16700Schasinglulu 	return mmio_read_32(base + GICFMU_STATUS);
190*91f16700Schasinglulu }
191*91f16700Schasinglulu 
192*91f16700Schasinglulu /*
193*91f16700Schasinglulu  * Accessors to read the Error Record ID Register
194*91f16700Schasinglulu  */
195*91f16700Schasinglulu uint32_t gic_fmu_read_erridr(uintptr_t base)
196*91f16700Schasinglulu {
197*91f16700Schasinglulu 	return mmio_read_32(base + GICFMU_ERRIDR);
198*91f16700Schasinglulu }
199*91f16700Schasinglulu 
200*91f16700Schasinglulu /*
201*91f16700Schasinglulu  * Accessors to write a 64 bit value to the Error Record Control Register
202*91f16700Schasinglulu  */
203*91f16700Schasinglulu void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val)
204*91f16700Schasinglulu {
205*91f16700Schasinglulu 	GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val);
206*91f16700Schasinglulu }
207*91f16700Schasinglulu 
208*91f16700Schasinglulu /*
209*91f16700Schasinglulu  * Accessors to write a 64 bit value to the Error Record Primary Status
210*91f16700Schasinglulu  * Register
211*91f16700Schasinglulu  */
212*91f16700Schasinglulu void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val)
213*91f16700Schasinglulu {
214*91f16700Schasinglulu 	/* Wait until FMU is ready before writing */
215*91f16700Schasinglulu 	GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val);
216*91f16700Schasinglulu }
217*91f16700Schasinglulu 
218*91f16700Schasinglulu /*
219*91f16700Schasinglulu  * Accessors to write a 32 bit value to the Ping Control Register
220*91f16700Schasinglulu  */
221*91f16700Schasinglulu void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val)
222*91f16700Schasinglulu {
223*91f16700Schasinglulu 	GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val);
224*91f16700Schasinglulu }
225*91f16700Schasinglulu 
226*91f16700Schasinglulu /*
227*91f16700Schasinglulu  * Accessors to write a 32 bit value to the Ping Now Register
228*91f16700Schasinglulu  */
229*91f16700Schasinglulu void gic_fmu_write_pingnow(uintptr_t base, uint32_t val)
230*91f16700Schasinglulu {
231*91f16700Schasinglulu 	/* Wait until FMU is ready before writing */
232*91f16700Schasinglulu 	GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val);
233*91f16700Schasinglulu }
234*91f16700Schasinglulu 
235*91f16700Schasinglulu /*
236*91f16700Schasinglulu  * Accessors to write a 32 bit value to the Safety Mechanism Enable Register
237*91f16700Schasinglulu  */
238*91f16700Schasinglulu void gic_fmu_write_smen(uintptr_t base, uint32_t val)
239*91f16700Schasinglulu {
240*91f16700Schasinglulu 	/* Wait until FMU is ready before writing */
241*91f16700Schasinglulu 	GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val);
242*91f16700Schasinglulu }
243*91f16700Schasinglulu 
244*91f16700Schasinglulu /*
245*91f16700Schasinglulu  * Accessors to write a 32 bit value to the Safety Mechanism Inject Error
246*91f16700Schasinglulu  * Register
247*91f16700Schasinglulu  */
248*91f16700Schasinglulu void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val)
249*91f16700Schasinglulu {
250*91f16700Schasinglulu 	/* Wait until FMU is ready before writing */
251*91f16700Schasinglulu 	GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val);
252*91f16700Schasinglulu }
253*91f16700Schasinglulu 
254*91f16700Schasinglulu /*
255*91f16700Schasinglulu  * Accessors to write a 64 bit value to the Ping Mask Register
256*91f16700Schasinglulu  */
257*91f16700Schasinglulu void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
258*91f16700Schasinglulu {
259*91f16700Schasinglulu 	GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
260*91f16700Schasinglulu }
261*91f16700Schasinglulu 
262*91f16700Schasinglulu /*
263*91f16700Schasinglulu  * Helper function to disable all safety mechanisms for a given block
264*91f16700Schasinglulu  */
265*91f16700Schasinglulu void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid)
266*91f16700Schasinglulu {
267*91f16700Schasinglulu 	uint32_t smen, max_smid = U(0);
268*91f16700Schasinglulu 
269*91f16700Schasinglulu 	/* Sanity check block ID */
270*91f16700Schasinglulu 	assert((blkid >= FMU_BLK_GICD) && (blkid <= FMU_BLK_PPI31));
271*91f16700Schasinglulu 
272*91f16700Schasinglulu 	/* Find the max safety mechanism ID for the block */
273*91f16700Schasinglulu 	switch (blkid) {
274*91f16700Schasinglulu 	case FMU_BLK_GICD:
275*91f16700Schasinglulu 		max_smid = FMU_SMID_GICD_MAX;
276*91f16700Schasinglulu 		break;
277*91f16700Schasinglulu 
278*91f16700Schasinglulu 	case FMU_BLK_SPICOL:
279*91f16700Schasinglulu 		max_smid = FMU_SMID_SPICOL_MAX;
280*91f16700Schasinglulu 		break;
281*91f16700Schasinglulu 
282*91f16700Schasinglulu 	case FMU_BLK_WAKERQ:
283*91f16700Schasinglulu 		max_smid = FMU_SMID_WAKERQ_MAX;
284*91f16700Schasinglulu 		break;
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 	case FMU_BLK_ITS0...FMU_BLK_ITS7:
287*91f16700Schasinglulu 		max_smid = FMU_SMID_ITS_MAX;
288*91f16700Schasinglulu 		break;
289*91f16700Schasinglulu 
290*91f16700Schasinglulu 	case FMU_BLK_PPI0...FMU_BLK_PPI31:
291*91f16700Schasinglulu 		max_smid = FMU_SMID_PPI_MAX;
292*91f16700Schasinglulu 		break;
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 	default:
295*91f16700Schasinglulu 		assert(false);
296*91f16700Schasinglulu 		break;
297*91f16700Schasinglulu 	}
298*91f16700Schasinglulu 
299*91f16700Schasinglulu 	/* Disable all Safety Mechanisms for a given block id */
300*91f16700Schasinglulu 	for (unsigned int i = 0U; i < max_smid; i++) {
301*91f16700Schasinglulu 		smen = (blkid << FMU_SMEN_BLK_SHIFT) | (i << FMU_SMEN_SMID_SHIFT);
302*91f16700Schasinglulu 		gic_fmu_write_smen(base, smen);
303*91f16700Schasinglulu 	}
304*91f16700Schasinglulu }
305