1 /*
2 * Copyright 2019-2021 NXP
3 * All rights reserved.
4 *
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_mecc.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.mecc"
18 #endif
19
20 /*******************************************************************************
21 * Prototypes
22 ******************************************************************************/
23 /*!
24 * @brief Gets the instance from the base address to be used to gate or ungate the module clock
25 *
26 * @param base MECC base address
27 *
28 * @return The MECC instance
29 */
30 static uint32_t MECC_GetInstance(MECC_Type *base);
31 /*******************************************************************************
32 * Variables
33 ******************************************************************************/
34 /*! @brief Pointers to MECC bases for each instance. */
35 static MECC_Type *const s_meccBases[] = MECC_BASE_PTRS;
36 /*******************************************************************************
37 * Code
38 ******************************************************************************/
MECC_GetInstance(MECC_Type * base)39 static uint32_t MECC_GetInstance(MECC_Type *base)
40 {
41 uint32_t instance;
42
43 /* Find the instance index from base address mappings. */
44 for (instance = 0; instance < ARRAY_SIZE(s_meccBases); instance++)
45 {
46 if (s_meccBases[instance] == base)
47 {
48 break;
49 }
50 }
51
52 assert(instance < ARRAY_SIZE(s_meccBases));
53
54 return instance;
55 }
56
57 /*!
58 * brief MECC module initialization function.
59 *
60 * param base MECC base address.
61 */
MECC_Init(MECC_Type * base,mecc_config_t * config)62 void MECC_Init(MECC_Type *base, mecc_config_t *config)
63 {
64 uint32_t instance = MECC_GetInstance(base);
65 volatile uint64_t *ocramStartAddr = NULL;
66
67 /* enable all the interrupt status */
68 base->ERR_STAT_EN = kMECC_AllInterruptsStatusEnable;
69 /* clear all the interrupt status */
70 base->ERR_STATUS = kMECC_AllInterruptsFlag;
71 /* disable all the interrpt */
72 base->ERR_SIG_EN = 0U;
73
74 /* enable ECC function */
75 base->PIPE_ECC_EN = MECC_PIPE_ECC_EN_ECC_EN(config->enableMecc);
76
77 __DSB();
78
79 if (instance == (uint32_t)kMECC_Instance0)
80 {
81 /* Need to be initialized for ECC function operation, note that do not use memset() to initialize,
82 because it will use STR instruction and STR is byte access and MECC is 64 bits access operation. */
83 ocramStartAddr = (uint64_t *)config->Ocram1StartAddress;
84 while (ocramStartAddr < (uint64_t *)config->Ocram1EndAddress)
85 {
86 *ocramStartAddr = 0x00;
87 ocramStartAddr++;
88 }
89 }
90 else if (instance == (uint32_t)kMECC_Instance1)
91 {
92 /* Need to be initialized for ECC function operation, note that do not use memset() to initialize,
93 because it will use STR instruction and STR is byte access and MECC is 64 bits access operation. */
94 ocramStartAddr = (uint64_t *)config->Ocram2StartAddress;
95 while (ocramStartAddr < (uint64_t *)config->Ocram2EndAddress)
96 {
97 *ocramStartAddr = 0x00;
98 ocramStartAddr++;
99 }
100 }
101 else
102 {
103 ; /* Intentional empty for MISRA rule 15.7 */
104 }
105 }
106
107 /*!
108 * brief Deinitializes the MECC.
109 *
110 */
MECC_Deinit(MECC_Type * base)111 void MECC_Deinit(MECC_Type *base)
112 {
113 /* Disable ECC function */
114 base->PIPE_ECC_EN &= ~MECC_PIPE_ECC_EN_ECC_EN(1);
115 }
116
MECC_GetDefaultConfig(mecc_config_t * config)117 void MECC_GetDefaultConfig(mecc_config_t *config)
118 {
119 assert(NULL != config);
120
121 /* Initializes the configure structure to zero. */
122 (void)memset(config, 0, sizeof(*config));
123
124 /* Default MECC function. */
125 config->enableMecc = false;
126 /* Ocram 1 start address */
127 config->Ocram1StartAddress = 0x20240000;
128 /* Ocram 1 end address */
129 config->Ocram1EndAddress = 0x202BFFFF;
130 /* Ocram 2 address */
131 config->Ocram1StartAddress = 0x202C0000;
132 /* Ocram 2 address */
133 config->Ocram1EndAddress = 0x2033FFFF;
134 }
135
136 /* Initialize OCRAM */
137
138 /* Mainly use for debug, it can be deprecated when release */
MECC_ErrorInjection(MECC_Type * base,uint32_t lowerrordata,uint32_t higherrordata,uint8_t eccdata,uint8_t banknumber)139 status_t MECC_ErrorInjection(
140 MECC_Type *base, uint32_t lowerrordata, uint32_t higherrordata, uint8_t eccdata, uint8_t banknumber)
141 {
142 status_t status = kStatus_Success;
143
144 switch (banknumber)
145 {
146 case kMECC_OcramBank0:
147 /* Low 32 bits of Ocram bank0 error injection */
148 base->ERR_DATA_INJ_LOW0 = lowerrordata;
149 /* High 32 bits of Ocram bank0 error injection */
150 base->ERR_DATA_INJ_HIGH0 = higherrordata;
151 /* Ecc code of Ocram bank0 error injection */
152 base->ERR_ECC_INJ0 = eccdata;
153 break;
154
155 case kMECC_OcramBank1:
156 /* Low 32 bits of Ocram bank1 error injection */
157 base->ERR_DATA_INJ_LOW1 = lowerrordata;
158 /* High 32 bits of Ocram bank1 error injection */
159 base->ERR_DATA_INJ_HIGH1 = higherrordata;
160 /* Ecc code of Ocram bank1 error injection */
161 base->ERR_ECC_INJ1 = eccdata;
162 break;
163
164 case kMECC_OcramBank2:
165 /* Low 32 bits of Ocram bank2 error injection */
166 base->ERR_DATA_INJ_LOW2 = lowerrordata;
167 /* High 32 bits of Ocram bank2 error injection */
168 base->ERR_DATA_INJ_HIGH2 = higherrordata;
169 /* Ecc code of Ocram bank2 error injection */
170 base->ERR_ECC_INJ2 = eccdata;
171 break;
172
173 case kMECC_OcramBank3:
174 /* Low 32 bits of Ocram bank3 error injection */
175 base->ERR_DATA_INJ_LOW3 = lowerrordata;
176 /* High 32 bits of Ocram bank3 error injection */
177 base->ERR_DATA_INJ_HIGH3 = higherrordata;
178 /* Ecc code of Ocram bank3 error injection */
179 base->ERR_ECC_INJ3 = eccdata;
180 break;
181
182 default:
183 status = kStatus_MECC_BankMiss;
184 break;
185 }
186
187 return status;
188 }
189
MECC_GetSingleErrorInfo(MECC_Type * base,mecc_single_error_info_t * info,uint8_t banknumber)190 status_t MECC_GetSingleErrorInfo(MECC_Type *base, mecc_single_error_info_t *info, uint8_t banknumber)
191 {
192 assert(info != NULL);
193 status_t status = kStatus_Success;
194 uint8_t tempPosLow = 0U;
195 uint8_t tempPosHigh = 0U;
196 uint32_t counter = 0U;
197
198 switch (banknumber)
199 {
200 case kMECC_OcramBank0:
201 info->singleErrorEccCode =
202 (uint8_t)((base->SINGLE_ERR_ADDR_ECC0 & MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ECC_MASK) >>
203 MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ECC_SHIFT);
204 info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC0 & MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ADDR_MASK) >>
205 MECC_SINGLE_ERR_ADDR_ECC0_SINGLE_ERR_ADDR_SHIFT;
206 info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW0;
207 info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH0;
208 tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW0;
209 tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH0;
210 break;
211
212 case kMECC_OcramBank1:
213 info->singleErrorEccCode =
214 (uint8_t)((base->SINGLE_ERR_ADDR_ECC1 & MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ECC_MASK) >>
215 MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ECC_SHIFT);
216 info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC1 & MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ADDR_MASK) >>
217 MECC_SINGLE_ERR_ADDR_ECC1_SINGLE_ERR_ADDR_SHIFT;
218 info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW1;
219 info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH1;
220 tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW1;
221 tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH1;
222 break;
223
224 case kMECC_OcramBank2:
225 info->singleErrorEccCode =
226 (uint8_t)((base->SINGLE_ERR_ADDR_ECC2 & MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ECC_MASK) >>
227 MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ECC_SHIFT);
228 info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC2 & MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ADDR_MASK) >>
229 MECC_SINGLE_ERR_ADDR_ECC2_SINGLE_ERR_ADDR_SHIFT;
230 info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW2;
231 info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH2;
232 tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW2;
233 tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH2;
234 break;
235
236 case kMECC_OcramBank3:
237 info->singleErrorEccCode =
238 (uint8_t)((base->SINGLE_ERR_ADDR_ECC3 & MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ECC_MASK) >>
239 MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ECC_SHIFT);
240 info->singleErrorAddress = (base->SINGLE_ERR_ADDR_ECC3 & MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ADDR_MASK) >>
241 MECC_SINGLE_ERR_ADDR_ECC3_SINGLE_ERR_ADDR_SHIFT;
242 info->singleErrorDataLow = base->SINGLE_ERR_DATA_LOW3;
243 info->singleErrorDataHigh = base->SINGLE_ERR_DATA_HIGH3;
244 tempPosLow = (uint8_t)base->SINGLE_ERR_POS_LOW3;
245 tempPosHigh = (uint8_t)base->SINGLE_ERR_POS_HIGH3;
246 break;
247
248 default:
249 status = kStatus_MECC_BankMiss;
250 break;
251 }
252
253 while (tempPosLow > 0U)
254 {
255 tempPosLow = tempPosLow >> 1;
256 counter++;
257 }
258
259 if (counter == 0U)
260 {
261 info->singleErrorPosLow = 0;
262 }
263 else
264 {
265 info->singleErrorPosLow = counter - 1U;
266 }
267
268 counter = 0U;
269 while (tempPosHigh > 0U)
270 {
271 tempPosHigh = tempPosHigh >> 1;
272 counter++;
273 }
274
275 if (counter == 0U)
276 {
277 info->singleErrorPosHigh = 0;
278 }
279 else
280 {
281 info->singleErrorPosHigh = counter - 1U;
282 }
283
284 return status;
285 }
286
MECC_GetMultiErrorInfo(MECC_Type * base,mecc_multi_error_info_t * info,uint8_t banknumber)287 status_t MECC_GetMultiErrorInfo(MECC_Type *base, mecc_multi_error_info_t *info, uint8_t banknumber)
288 {
289 assert(info != NULL);
290 status_t status = kStatus_Success;
291
292 switch (banknumber)
293 {
294 case kMECC_OcramBank0:
295 info->multiErrorEccCode =
296 (uint8_t)((base->MULTI_ERR_ADDR_ECC0 & MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ECC_MASK) >>
297 MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ECC_SHIFT);
298 info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC0 & MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ADDR_MASK) >>
299 MECC_MULTI_ERR_ADDR_ECC0_MULTI_ERR_ADDR_SHIFT;
300 info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW0;
301 info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH0;
302 break;
303
304 case kMECC_OcramBank1:
305 info->multiErrorEccCode =
306 (uint8_t)((base->MULTI_ERR_ADDR_ECC1 & MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ECC_MASK) >>
307 MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ECC_SHIFT);
308 info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC1 & MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ADDR_MASK) >>
309 MECC_MULTI_ERR_ADDR_ECC1_MULTI_ERR_ADDR_SHIFT;
310 info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW1;
311 info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH1;
312 break;
313
314 case kMECC_OcramBank2:
315 info->multiErrorEccCode =
316 (uint8_t)((base->MULTI_ERR_ADDR_ECC2 & MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ECC_MASK) >>
317 MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ECC_SHIFT);
318 info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC2 & MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ADDR_MASK) >>
319 MECC_MULTI_ERR_ADDR_ECC2_MULTI_ERR_ADDR_SHIFT;
320 info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW2;
321 info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH2;
322 break;
323
324 case kMECC_OcramBank3:
325 info->multiErrorEccCode =
326 (uint8_t)((base->MULTI_ERR_ADDR_ECC3 & MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ECC_MASK) >>
327 MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ECC_SHIFT);
328 info->multiErrorAddress = (base->MULTI_ERR_ADDR_ECC3 & MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ADDR_MASK) >>
329 MECC_MULTI_ERR_ADDR_ECC3_MULTI_ERR_ADDR_SHIFT;
330 info->multiErrorDataLow = base->MULTI_ERR_DATA_LOW3;
331 info->multiErrorDataHigh = base->MULTI_ERR_DATA_HIGH3;
332 break;
333
334 default:
335 status = kStatus_MECC_BankMiss;
336 break;
337 }
338
339 return status;
340 }
341