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