1 /*
2  * Copyright (c) 2021, NVIDIA Corporation. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * Driver for GIC-600AE Fault Management Unit
9  */
10 
11 #include <assert.h>
12 
13 #include <arch_helpers.h>
14 #include <common/debug.h>
15 #include <drivers/arm/gic600ae_fmu.h>
16 #include <drivers/arm/gicv3.h>
17 
18 /* GIC-600 AE FMU specific register offsets */
19 
20 /* GIC-600 AE FMU specific macros */
21 #define FMU_ERRIDR_NUM			U(44)
22 #define FMU_ERRIDR_NUM_MASK		U(0xFFFF)
23 
24 /* Safety mechanisms for GICD block */
25 static char *gicd_sm_info[] = {
26 	"Reserved",
27 	"GICD dual lockstep error",
28 	"GICD AXI4 slave interface error",
29 	"GICD-PPI AXI4-Stream interface error",
30 	"GICD-ITS AXI4-Stream interface error",
31 	"GICD-SPI-Collator AXI4-Stream interface error",
32 	"GICD AXI4 master interface error",
33 	"SPI RAM DED error",
34 	"SGI RAM DED error",
35 	"Reserved",
36 	"LPI RAM DED error",
37 	"GICD-remote-GICD AXI4-Stream interface error",
38 	"GICD Q-Channel interface error",
39 	"GICD P-Channel interface error",
40 	"SPI RAM address decode error",
41 	"SGI RAM address decode error",
42 	"Reserved",
43 	"LPI RAM address decode error",
44 	"FMU dual lockstep error",
45 	"FMU ping ACK error",
46 	"FMU APB parity error",
47 	"GICD-Wake AXI4-Stream interface error",
48 	"GICD PageOffset or Chip ID error",
49 	"MBIST REQ error",
50 	"SPI RAM SEC error",
51 	"SGI RAM SEC error",
52 	"Reserved",
53 	"LPI RAM SEC error",
54 	"User custom SM0 error",
55 	"User custom SM1 error",
56 	"GICD-ITS Monolithic switch error",
57 	"GICD-ITS Q-Channel interface error",
58 	"GICD-ITS Monolithic interface error",
59 	"GICD FMU ClkGate override"
60 };
61 
62 /* Safety mechanisms for PPI block */
63 static char *ppi_sm_info[] = {
64 	"Reserved",
65 	"PPI dual lockstep error",
66 	"PPI-GICD AXI4-Stream interface error",
67 	"PPI-CPU-IF AXI4-Stream interface error",
68 	"PPI Q-Channel interface error",
69 	"PPI RAM DED error",
70 	"PPI RAM address decode error",
71 	"PPI RAM SEC error",
72 	"PPI User0 SM",
73 	"PPI User1 SM",
74 	"MBIST REQ error",
75 	"PPI interrupt parity protection error",
76 	"PPI FMU ClkGate override"
77 };
78 
79 /* Safety mechanisms for ITS block */
80 static char *its_sm_info[] = {
81 	"Reserved",
82 	"ITS dual lockstep error",
83 	"ITS-GICD AXI4-Stream interface error",
84 	"ITS AXI4 slave interface error",
85 	"ITS AXI4 master interface error",
86 	"ITS Q-Channel interface error",
87 	"ITS RAM DED error",
88 	"ITS RAM address decode error",
89 	"Bypass ACE switch error",
90 	"ITS RAM SEC error",
91 	"ITS User0 SM",
92 	"ITS User1 SM",
93 	"ITS-GICD Monolithic interface error",
94 	"MBIST REQ error",
95 	"ITS FMU ClkGate override"
96 };
97 
98 /* Safety mechanisms for SPI Collator block */
99 static char *spicol_sm_info[] = {
100 	"Reserved",
101 	"SPI Collator dual lockstep error",
102 	"SPI-Collator-GICD AXI4-Stream interface error",
103 	"SPI Collator Q-Channel interface error",
104 	"SPI Collator Q-Channel clock error",
105 	"SPI interrupt parity error"
106 };
107 
108 /* Safety mechanisms for Wake Request block */
109 static char *wkrqst_sm_info[] = {
110 	"Reserved",
111 	"Wake dual lockstep error",
112 	"Wake-GICD AXI4-Stream interface error"
113 };
114 
115 /*
116  * Initialization sequence for the FMU
117  *
118  * 1. enable error detection for error records that are passed in the blk_present_mask
119  * 2. enable MBIST REQ and FMU Clk Gate override safety mechanisms for error records
120  *    that are present on the platform
121  *
122  * The platforms are expected to pass `errctlr_ce_en` and `errctlr_ue_en`.
123  */
gic600_fmu_init(uint64_t base,uint64_t blk_present_mask,bool errctlr_ce_en,bool errctlr_ue_en)124 void gic600_fmu_init(uint64_t base, uint64_t blk_present_mask,
125 		     bool errctlr_ce_en, bool errctlr_ue_en)
126 {
127 	unsigned int num_blk = gic_fmu_read_erridr(base) & FMU_ERRIDR_NUM_MASK;
128 	uint64_t errctlr;
129 	uint32_t smen;
130 
131 	INFO("GIC600-AE FMU supports %d error records\n", num_blk);
132 
133 	assert(num_blk == FMU_ERRIDR_NUM);
134 
135 	/* sanitize block present mask */
136 	blk_present_mask &= FMU_BLK_PRESENT_MASK;
137 
138 	/* Enable error detection for all error records */
139 	for (unsigned int i = 0U; i < num_blk; i++) {
140 
141 		/* Skip next steps if the block is not present */
142 		if ((blk_present_mask & BIT(i)) == 0U) {
143 			continue;
144 		}
145 
146 		/* Read the error record control register */
147 		errctlr = gic_fmu_read_errctlr(base, i);
148 
149 		/* Enable error reporting and logging, if it is disabled */
150 		if ((errctlr & FMU_ERRCTLR_ED_BIT) == 0U) {
151 			errctlr |= FMU_ERRCTLR_ED_BIT;
152 		}
153 
154 		/* Enable client provided ERRCTLR settings */
155 		errctlr |= (errctlr_ce_en ? (FMU_ERRCTLR_CI_BIT | FMU_ERRCTLR_CE_EN_BIT) : 0);
156 		errctlr |= (errctlr_ue_en ? FMU_ERRCTLR_UI_BIT : 0U);
157 
158 		gic_fmu_write_errctlr(base, i, errctlr);
159 	}
160 
161 	/*
162 	 * Enable MBIST REQ error and FMU CLK gate override safety mechanisms for
163 	 * all blocks
164 	 *
165 	 * GICD, SMID 23 and SMID 33
166 	 * PPI, SMID 10 and SMID 12
167 	 * ITS, SMID 13 and SMID 14
168 	 */
169 	if ((blk_present_mask & BIT(FMU_BLK_GICD)) != 0U) {
170 		smen = (GICD_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
171 			(FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT);
172 		gic_fmu_write_smen(base, smen);
173 
174 		smen = (GICD_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
175 			(FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT);
176 		gic_fmu_write_smen(base, smen);
177 	}
178 
179 	for (unsigned int i = FMU_BLK_PPI0; i < FMU_BLK_PPI31; i++) {
180 		if ((blk_present_mask & BIT(i)) != 0U) {
181 			smen = (PPI_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
182 				(i << FMU_SMEN_BLK_SHIFT);
183 			gic_fmu_write_smen(base, smen);
184 
185 			smen = (PPI_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
186 				(i << FMU_SMEN_BLK_SHIFT);
187 			gic_fmu_write_smen(base, smen);
188 		}
189 	}
190 
191 	for (unsigned int i = FMU_BLK_ITS0; i < FMU_BLK_ITS7; i++) {
192 		if ((blk_present_mask & BIT(i)) != 0U) {
193 			smen = (ITS_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
194 				(i << FMU_SMEN_BLK_SHIFT);
195 			gic_fmu_write_smen(base, smen);
196 
197 			smen = (ITS_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
198 				(i << FMU_SMEN_BLK_SHIFT);
199 			gic_fmu_write_smen(base, smen);
200 		}
201 	}
202 }
203 
204 /*
205  * This function enable the GICD background ping engine. The GICD sends ping
206  * messages to each remote GIC block, and expects a PING_ACK back within the
207  * specified timeout. Pings need to be enabled after programming the timeout
208  * value.
209  */
gic600_fmu_enable_ping(uint64_t base,uint64_t blk_present_mask,unsigned int timeout_val,unsigned int interval_diff)210 void gic600_fmu_enable_ping(uint64_t base, uint64_t blk_present_mask,
211 		unsigned int timeout_val, unsigned int interval_diff)
212 {
213 	/*
214 	 * Populate the PING Mask to skip a specific block while generating
215 	 * background ping messages and enable the ping mechanism.
216 	 */
217 	gic_fmu_write_pingmask(base, ~blk_present_mask);
218 	gic_fmu_write_pingctlr(base, (interval_diff << FMU_PINGCTLR_INTDIFF_SHIFT) |
219 		(timeout_val << FMU_PINGCTLR_TIMEOUTVAL_SHIFT) | FMU_PINGCTLR_EN_BIT);
220 }
221 
222 /* Print the safety mechanism description for a given block */
gic600_fmu_print_sm_info(uint64_t base,unsigned int blk,unsigned int smid)223 void gic600_fmu_print_sm_info(uint64_t base, unsigned int blk, unsigned int smid)
224 {
225 	if (blk == FMU_BLK_GICD && smid <= FMU_SMID_GICD_MAX) {
226 		INFO("GICD, SMID %d: %s\n", smid, gicd_sm_info[smid]);
227 	}
228 
229 	if (blk == FMU_BLK_SPICOL && smid <= FMU_SMID_SPICOL_MAX) {
230 		INFO("SPI Collator, SMID %d: %s\n", smid, spicol_sm_info[smid]);
231 	}
232 
233 	if (blk == FMU_BLK_WAKERQ && (smid <= FMU_SMID_WAKERQ_MAX)) {
234 		INFO("Wake Request, SMID %d: %s\n", smid, wkrqst_sm_info[smid]);
235 	}
236 
237 	if (((blk >= FMU_BLK_ITS0) && (blk <= FMU_BLK_ITS7)) && (smid <= FMU_SMID_ITS_MAX)) {
238 		INFO("ITS, SMID %d: %s\n", smid, its_sm_info[smid]);
239 	}
240 
241 	if (((blk >= FMU_BLK_PPI0) && (blk <= FMU_BLK_PPI31)) && (smid <= FMU_SMID_PPI_MAX)) {
242 		INFO("PPI, SMID %d: %s\n", smid, ppi_sm_info[smid]);
243 	}
244 }
245