blob: 09806dcfc544fea6b6687ed5c798e91fbad65236 [file] [log] [blame]
Varun Wadekareea6dc12021-05-04 16:14:09 -07001/*
Varun Wadekarf6e7c952022-01-25 03:39:28 -08002 * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
Varun Wadekareea6dc12021-05-04 16:14:09 -07003 *
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 */
47static void wait_until_fmu_is_idle(uintptr_t base)
48{
anzhou31cf3182021-11-18 19:18:13 +080049 uint32_t timeout_count = GICFMU_IDLE_TIMEOUT_US;
Varun Wadekareea6dc12021-05-04 16:14:09 -070050 uint64_t status;
51
52 /* wait until status is 'busy' */
53 do {
54 status = (gic_fmu_read_status(base) & BIT(0));
55
anzhou31cf3182021-11-18 19:18:13 +080056 if (timeout_count-- == 0U) {
Varun Wadekareea6dc12021-05-04 16:14:09 -070057 ERROR("GIC600 AE FMU is not responding\n");
58 panic();
59 }
anzhou31cf3182021-11-18 19:18:13 +080060
61 udelay(1U);
62
Varun Wadekareea6dc12021-05-04 16:14:09 -070063 } 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 */
94uint64_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 */
110uint64_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 */
126uint64_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 */
141uint64_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 */
156uint32_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 */
164uint32_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 */
172uint64_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 */
187uint32_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 */
195uint32_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 */
203void 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 */
212void 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 */
221void 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 */
229void 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 */
238void 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 */
248void 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 */
257void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
258{
259 GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
260}
Varun Wadekarf6e7c952022-01-25 03:39:28 -0800261
262/*
263 * Helper function to disable all safety mechanisms for a given block
264 */
265void gic_fmu_disable_all_sm_blkid(uintptr_t base, unsigned int blkid)
266{
267 uint32_t smen, max_smid = U(0);
268
269 /* Sanity check block ID */
270 assert((blkid >= FMU_BLK_GICD) && (blkid <= FMU_BLK_PPI31));
271
272 /* Find the max safety mechanism ID for the block */
273 switch (blkid) {
274 case FMU_BLK_GICD:
275 max_smid = FMU_SMID_GICD_MAX;
276 break;
277
278 case FMU_BLK_SPICOL:
279 max_smid = FMU_SMID_SPICOL_MAX;
280 break;
281
282 case FMU_BLK_WAKERQ:
283 max_smid = FMU_SMID_WAKERQ_MAX;
284 break;
285
286 case FMU_BLK_ITS0...FMU_BLK_ITS7:
287 max_smid = FMU_SMID_ITS_MAX;
288 break;
289
290 case FMU_BLK_PPI0...FMU_BLK_PPI31:
291 max_smid = FMU_SMID_PPI_MAX;
292 break;
293
294 default:
295 assert(false);
296 break;
297 }
298
299 /* Disable all Safety Mechanisms for a given block id */
300 for (unsigned int i = 0U; i < max_smid; i++) {
301 smen = (blkid << FMU_SMEN_BLK_SHIFT) | (i << FMU_SMEN_SMID_SHIFT);
302 gic_fmu_write_smen(base, smen);
303 }
304}