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 */
wait_until_fmu_is_idle(uintptr_t base)47 static void wait_until_fmu_is_idle(uintptr_t base)
48 {
49 	uint32_t timeout_count = 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_count-- == 0U) {
57 			ERROR("GIC600 AE FMU is not responding\n");
58 			panic();
59 		}
60 
61 		udelay(1U);
62 
63 	} while (status == U(0));
64 }
65 
66 #define GIC_FMU_WRITE_ON_IDLE_32(base, reg, val) \
67 	do { \
68 		/* Wait until FMU is ready */ \
69 		wait_until_fmu_is_idle(base); \
70 		/* Actual register write */ \
71 		GIC_FMU_WRITE_32(base, reg, val); \
72 		/* Wait until FMU is ready */ \
73 		wait_until_fmu_is_idle(base); \
74 	} while (false)
75 
76 #define GIC_FMU_WRITE_ON_IDLE_64(base, reg, n, val) \
77 	do { \
78 		/* Wait until FMU is ready */ \
79 		wait_until_fmu_is_idle(base); \
80 		/* Actual register write */ \
81 		GIC_FMU_WRITE_64(base, reg, n, val); \
82 		/* Wait until FMU is ready */ \
83 		wait_until_fmu_is_idle(base); \
84 	} while (false)
85 
86 /*******************************************************************************
87  * GIC FMU functions for accessing the Fault Management Unit registers
88  ******************************************************************************/
89 
90 /*
91  * Accessors to read the Error Record Feature Register bits corresponding
92  * to an error record 'n'
93  */
gic_fmu_read_errfr(uintptr_t base,unsigned int n)94 uint64_t gic_fmu_read_errfr(uintptr_t base, unsigned int n)
95 {
96 	/*
97 	 * APB bus is 32-bit wide; so split the 64-bit read into
98 	 * two 32-bit reads
99 	 */
100 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRFR_LO + n * 64U);
101 
102 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRFR_HI + n * 64U) << 32);
103 	return reg_val;
104 }
105 
106 /*
107  * Accessors to read the Error Record Control Register bits corresponding
108  * to an error record 'n'
109  */
gic_fmu_read_errctlr(uintptr_t base,unsigned int n)110 uint64_t gic_fmu_read_errctlr(uintptr_t base, unsigned int n)
111 {
112 	/*
113 	 * APB bus is 32-bit wide; so split the 64-bit read into
114 	 * two 32-bit reads
115 	 */
116 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_LO + n * 64U);
117 
118 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRCTLR_HI + n * 64U) << 32);
119 	return reg_val;
120 }
121 
122 /*
123  * Accessors to read the Error Record Primary Status Register bits
124  * corresponding to an error record 'n'
125  */
gic_fmu_read_errstatus(uintptr_t base,unsigned int n)126 uint64_t gic_fmu_read_errstatus(uintptr_t base, unsigned int n)
127 {
128 	/*
129 	 * APB bus is 32-bit wide; so split the 64-bit read into
130 	 * two 32-bit reads
131 	 */
132 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_LO + n * 64U);
133 
134 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRSTATUS_HI + n * 64U) << 32);
135 	return reg_val;
136 }
137 
138 /*
139  * Accessors to read the Error Group Status Register
140  */
gic_fmu_read_errgsr(uintptr_t base)141 uint64_t gic_fmu_read_errgsr(uintptr_t base)
142 {
143 	/*
144 	 * APB bus is 32-bit wide; so split the 64-bit read into
145 	 * two 32-bit reads
146 	 */
147 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_ERRGSR_LO);
148 
149 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_ERRGSR_HI) << 32);
150 	return reg_val;
151 }
152 
153 /*
154  * Accessors to read the Ping Control Register
155  */
gic_fmu_read_pingctlr(uintptr_t base)156 uint32_t gic_fmu_read_pingctlr(uintptr_t base)
157 {
158 	return mmio_read_32(base + GICFMU_PINGCTLR);
159 }
160 
161 /*
162  * Accessors to read the Ping Now Register
163  */
gic_fmu_read_pingnow(uintptr_t base)164 uint32_t gic_fmu_read_pingnow(uintptr_t base)
165 {
166 	return mmio_read_32(base + GICFMU_PINGNOW);
167 }
168 
169 /*
170  * Accessors to read the Ping Mask Register
171  */
gic_fmu_read_pingmask(uintptr_t base)172 uint64_t gic_fmu_read_pingmask(uintptr_t base)
173 {
174 	/*
175 	 * APB bus is 32-bit wide; so split the 64-bit read into
176 	 * two 32-bit reads
177 	 */
178 	uint64_t reg_val = (uint64_t)mmio_read_32(base + GICFMU_PINGMASK_LO);
179 
180 	reg_val |= ((uint64_t)mmio_read_32(base + GICFMU_PINGMASK_HI) << 32);
181 	return reg_val;
182 }
183 
184 /*
185  * Accessors to read the FMU Status Register
186  */
gic_fmu_read_status(uintptr_t base)187 uint32_t gic_fmu_read_status(uintptr_t base)
188 {
189 	return mmio_read_32(base + GICFMU_STATUS);
190 }
191 
192 /*
193  * Accessors to read the Error Record ID Register
194  */
gic_fmu_read_erridr(uintptr_t base)195 uint32_t gic_fmu_read_erridr(uintptr_t base)
196 {
197 	return mmio_read_32(base + GICFMU_ERRIDR);
198 }
199 
200 /*
201  * Accessors to write a 64 bit value to the Error Record Control Register
202  */
gic_fmu_write_errctlr(uintptr_t base,unsigned int n,uint64_t val)203 void gic_fmu_write_errctlr(uintptr_t base, unsigned int n, uint64_t val)
204 {
205 	GIC_FMU_WRITE_64(base, GICFMU_ERRCTLR, n, val);
206 }
207 
208 /*
209  * Accessors to write a 64 bit value to the Error Record Primary Status
210  * Register
211  */
gic_fmu_write_errstatus(uintptr_t base,unsigned int n,uint64_t val)212 void gic_fmu_write_errstatus(uintptr_t base, unsigned int n, uint64_t val)
213 {
214 	/* Wait until FMU is ready before writing */
215 	GIC_FMU_WRITE_ON_IDLE_64(base, GICFMU_ERRSTATUS, n, val);
216 }
217 
218 /*
219  * Accessors to write a 32 bit value to the Ping Control Register
220  */
gic_fmu_write_pingctlr(uintptr_t base,uint32_t val)221 void gic_fmu_write_pingctlr(uintptr_t base, uint32_t val)
222 {
223 	GIC_FMU_WRITE_32(base, GICFMU_PINGCTLR, val);
224 }
225 
226 /*
227  * Accessors to write a 32 bit value to the Ping Now Register
228  */
gic_fmu_write_pingnow(uintptr_t base,uint32_t val)229 void gic_fmu_write_pingnow(uintptr_t base, uint32_t val)
230 {
231 	/* Wait until FMU is ready before writing */
232 	GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_PINGNOW, val);
233 }
234 
235 /*
236  * Accessors to write a 32 bit value to the Safety Mechanism Enable Register
237  */
gic_fmu_write_smen(uintptr_t base,uint32_t val)238 void gic_fmu_write_smen(uintptr_t base, uint32_t val)
239 {
240 	/* Wait until FMU is ready before writing */
241 	GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMEN, val);
242 }
243 
244 /*
245  * Accessors to write a 32 bit value to the Safety Mechanism Inject Error
246  * Register
247  */
gic_fmu_write_sminjerr(uintptr_t base,uint32_t val)248 void gic_fmu_write_sminjerr(uintptr_t base, uint32_t val)
249 {
250 	/* Wait until FMU is ready before writing */
251 	GIC_FMU_WRITE_ON_IDLE_32(base, GICFMU_SMINJERR, val);
252 }
253 
254 /*
255  * Accessors to write a 64 bit value to the Ping Mask Register
256  */
gic_fmu_write_pingmask(uintptr_t base,uint64_t val)257 void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
258 {
259 	GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
260 }
261