blob: 84f72925cd52362f4ae0b3626897ee307b1369e3 [file] [log] [blame]
Varun Wadekareea6dc12021-05-04 16:14:09 -07001/*
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 */
47static 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 */
91uint64_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 */
107uint64_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 */
123uint64_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 */
138uint64_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 */
153uint32_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 */
161uint32_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 */
169uint64_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 */
184uint32_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 */
192uint32_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 */
200void 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 */
209void 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 */
218void 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 */
226void 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 */
235void 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 */
245void 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 */
254void gic_fmu_write_pingmask(uintptr_t base, uint64_t val)
255{
256 GIC_FMU_WRITE_64(base, GICFMU_PINGMASK, 0, val);
257}