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