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