1 /*
2  * Copyright 2018-2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  */
8 
9 #include "fsl_k4_controller.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /*!
16  * @name Flash controller command numbers
17  * @{
18  */
19 #define FLASH_VERIFY_ERASE_ALL        0x00U /*!< RD1ALL*/
20 #define FLASH_VERIFY_ERASE_BLOCK      0x01U /*!< RD1BLK*/
21 #define FLASH_VERIFY_ERASE_SECTOR     0x02U /*!< RD1SCR*/
22 #define FLASH_VERIFY_ERASE_PAGE       0x03U /*!< RD1PG*/
23 #define FLASH_VERIFY_ERASE_PHRASE     0x04U /*!< RD1PHR*/
24 #define FLASH_READ_INTO_MISR          0x05U /*!< RDMISR*/
25 #define FLASH_VERIFY_ERASE_IFR_SECTOR 0x12U /*!< RD1ISCR*/
26 #define FLASH_VERIFY_ERASE_IFR_PAGE   0x13U /*!< RD1IPG*/
27 #define FLASH_VERIFY_ERASE_IFR_PHRASE 0x14U /*!< RD1IPHR*/
28 #define FLASH_READ_IFR_INTO_MISR      0x15U /*!< RDIMISR*/
29 #define FLASH_PROGRAM_PAGE            0x23U /*!< PGMPG*/
30 #define FLASH_PROGRAM_PHRASE          0x24U /*!< PGMPHR*/
31 #define FLASH_ERASE_ALL               0x40U /*!< ERSALL*/
32 #define FLASH_ERASE_SECTOR            0x42U /*!< ERSSCR*/
33 /*@}*/
34 
35 /*******************************************************************************
36  * Prototypes
37  ******************************************************************************/
38 
39 static void flash_command_pre_sequence(FMU_Type *base);
40 
41 static void flash_command_sequence(FMU_Type *base);
42 
43 static void flash_erase_sequence(FMU_Type *base, uint32_t start);
44 
45 static void flash_pgm_sequence(FMU_Type *base, uint32_t start, uint32_t *src, uint8_t isPage);
46 
47 /*! @brief Internal function Flash command*/
48 static status_t flash_command_complete(FMU_Type *base);
49 
50 /*******************************************************************************
51  * Variables
52  ******************************************************************************/
53 
54 /*******************************************************************************
55  * Code
56  ******************************************************************************/
57 
FLASH_CMD_EraseSector(FMU_Type * base,uint32_t start)58 status_t FLASH_CMD_EraseSector(FMU_Type *base, uint32_t start)
59 {
60     status_t returnCode = kStatus_Fail;
61 
62     flash_command_pre_sequence(base);
63     /* preparing passing parameter to erase a sector flash */
64     base->FCCOB[0] = FLASH_ERASE_SECTOR;
65     /* Erase Command sequence */
66     flash_erase_sequence(base, start);
67     /* check command completion and error handling */
68     returnCode = flash_command_complete(base);
69 
70     return returnCode;
71 }
72 
FLASH_CMD_EraseAll(FMU_Type * base)73 status_t FLASH_CMD_EraseAll(FMU_Type *base)
74 {
75     status_t returnCode = kStatus_Fail;
76 
77     flash_command_pre_sequence(base);
78     /* preparing passing parameter to erase all flash blocks */
79     base->FCCOB[0] = FLASH_ERASE_ALL;
80     flash_command_sequence(base);
81     /* calling flash command sequence function to execute the command */
82     returnCode = flash_command_complete(base);
83 
84     return returnCode;
85 }
86 
FLASH_CMD_ProgramPhrase(FMU_Type * base,uint32_t start,uint32_t * src)87 status_t FLASH_CMD_ProgramPhrase(FMU_Type *base, uint32_t start, uint32_t *src)
88 {
89     status_t returnCode = kStatus_Fail;
90     uint8_t isPage      = 0;
91 
92     flash_command_pre_sequence(base);
93     /* preparing passing parameter to program the flash block */
94     base->FCCOB[0] = FLASH_PROGRAM_PHRASE;
95     /* Program Command sequence */
96     flash_pgm_sequence(base, start, src, isPage);
97     returnCode = flash_command_complete(base);
98 
99     return returnCode;
100 }
101 
FLASH_CMD_ProgramPage(FMU_Type * base,uint32_t start,uint32_t * src)102 status_t FLASH_CMD_ProgramPage(FMU_Type *base, uint32_t start, uint32_t *src)
103 {
104     status_t returnCode = kStatus_Fail;
105     uint8_t isPage      = 1;
106 
107     flash_command_pre_sequence(base);
108     /* preparing passing parameter to program the flash block */
109     base->FCCOB[0] = FLASH_PROGRAM_PAGE;
110     /* Program Command sequence */
111     flash_pgm_sequence(base, start, src, isPage);
112     returnCode = flash_command_complete(base);
113 
114     return returnCode;
115 }
116 
FLASH_CMD_VerifyErasePhrase(FMU_Type * base,uint32_t start)117 status_t FLASH_CMD_VerifyErasePhrase(FMU_Type *base, uint32_t start)
118 {
119     status_t returnCode = kStatus_Fail;
120 
121     flash_command_pre_sequence(base);
122     /* Fill in verify erase phrase command parameters. */
123     base->FCCOB[0] = FLASH_VERIFY_ERASE_PHRASE;
124     base->FCCOB[2] = start;
125     flash_command_sequence(base);
126     /* calling flash command sequence function to execute the command */
127     returnCode = flash_command_complete(base);
128 
129     return returnCode;
130 }
131 
FLASH_CMD_VerifyErasePage(FMU_Type * base,uint32_t start)132 status_t FLASH_CMD_VerifyErasePage(FMU_Type *base, uint32_t start)
133 {
134     status_t returnCode = kStatus_Fail;
135 
136     flash_command_pre_sequence(base);
137     /* Fill in verify erase page command parameters. */
138     base->FCCOB[0] = FLASH_VERIFY_ERASE_PAGE;
139     base->FCCOB[2] = start;
140     flash_command_sequence(base);
141     /* calling flash command sequence function to execute the command */
142     returnCode = flash_command_complete(base);
143 
144     return returnCode;
145 }
146 
FLASH_CMD_VerifyEraseSector(FMU_Type * base,uint32_t start)147 status_t FLASH_CMD_VerifyEraseSector(FMU_Type *base, uint32_t start)
148 {
149     status_t returnCode = kStatus_Fail;
150 
151     flash_command_pre_sequence(base);
152     /* Fill in verify erase sector command parameters. */
153     base->FCCOB[0] = FLASH_VERIFY_ERASE_SECTOR;
154     base->FCCOB[2] = start;
155     flash_command_sequence(base);
156     /* calling flash command sequence function to execute the command */
157     returnCode = flash_command_complete(base);
158 
159     return returnCode;
160 }
161 
FLASH_CMD_VerifyEraseIFRPhrase(FMU_Type * base,uint32_t start)162 status_t FLASH_CMD_VerifyEraseIFRPhrase(FMU_Type *base, uint32_t start)
163 {
164     status_t returnCode = kStatus_Fail;
165 
166     flash_command_pre_sequence(base);
167     /* Fill in verify erase ifr phrase command parameters. */
168     base->FCCOB[0] = FLASH_VERIFY_ERASE_IFR_PHRASE;
169     base->FCCOB[2] = start;
170     flash_command_sequence(base);
171     /* calling flash command function to execute the command */
172     returnCode = flash_command_complete(base);
173 
174     return returnCode;
175 }
176 
FLASH_CMD_VerifyEraseIFRPage(FMU_Type * base,uint32_t start)177 status_t FLASH_CMD_VerifyEraseIFRPage(FMU_Type *base, uint32_t start)
178 {
179     status_t returnCode = kStatus_Fail;
180 
181     flash_command_pre_sequence(base);
182     /* Fill in verify erase ifr page command parameters. */
183     base->FCCOB[0] = FLASH_VERIFY_ERASE_IFR_PAGE;
184     base->FCCOB[2] = start;
185     flash_command_sequence(base);
186     /* calling flash command function to execute the command */
187     returnCode = flash_command_complete(base);
188 
189     return returnCode;
190 }
191 
FLASH_CMD_VerifyEraseIFRSector(FMU_Type * base,uint32_t start)192 status_t FLASH_CMD_VerifyEraseIFRSector(FMU_Type *base, uint32_t start)
193 {
194     status_t returnCode = kStatus_Fail;
195 
196     flash_command_pre_sequence(base);
197     /* Fill in verify erase ifr sector command parameters. */
198     base->FCCOB[0] = FLASH_VERIFY_ERASE_IFR_SECTOR;
199     base->FCCOB[2] = start;
200     flash_command_sequence(base);
201     /* calling flash command function to execute the command */
202     returnCode = flash_command_complete(base);
203 
204     return returnCode;
205 }
206 
FLASH_CMD_VerifyEraseBlock(FMU_Type * base,uint32_t blockaddr)207 status_t FLASH_CMD_VerifyEraseBlock(FMU_Type *base, uint32_t blockaddr)
208 {
209     status_t returnCode = kStatus_Fail;
210 
211     flash_command_pre_sequence(base);
212     /* preparing passing parameter to verify erase block command */
213     base->FCCOB[0] = FLASH_VERIFY_ERASE_BLOCK;
214     base->FCCOB[2] = blockaddr;
215     flash_command_sequence(base);
216     /* calling flash command sequence function to execute the command */
217     returnCode = flash_command_complete(base);
218 
219     return returnCode;
220 }
221 
FLASH_CMD_VerifyEraseAll(FMU_Type * base)222 status_t FLASH_CMD_VerifyEraseAll(FMU_Type *base)
223 {
224     status_t returnCode = kStatus_Fail;
225 
226     flash_command_pre_sequence(base);
227     /* preparing passing parameter to verify erase all command */
228     base->FCCOB[0] = FLASH_VERIFY_ERASE_ALL;
229     flash_command_sequence(base);
230     /* calling flash command sequence function to execute the command */
231     returnCode = flash_command_complete(base);
232     return returnCode;
233 }
234 
FLASH_CMD_ReadIntoMISR(FMU_Type * base,uint32_t start,uint32_t ending,uint32_t * seed,uint32_t * signature)235 status_t FLASH_CMD_ReadIntoMISR(FMU_Type *base, uint32_t start, uint32_t ending, uint32_t *seed, uint32_t *signature)
236 {
237     status_t returnCode = kStatus_Fail;
238 
239     flash_command_pre_sequence(base);
240     /* preparing passing parameter to read into misr command */
241     base->FCCOB[0] = FLASH_READ_INTO_MISR;
242     base->FCCOB[2] = start;
243     base->FCCOB[3] = ending;
244     base->FCCOB[4] = seed[0];
245     base->FCCOB[5] = seed[1];
246     base->FCCOB[6] = seed[2];
247     base->FCCOB[7] = seed[3];
248     flash_command_sequence(base);
249     /* calling flash command sequence function to execute the command */
250     returnCode = flash_command_complete(base);
251 
252     if ((kStatus_FLASH_Success == returnCode) && (signature != NULL))
253     {
254         signature[0] = base->FCCOB[4];
255         signature[1] = base->FCCOB[5];
256         signature[2] = base->FCCOB[6];
257         signature[3] = base->FCCOB[7];
258     }
259 
260     return returnCode;
261 }
262 
FLASH_CMD_ReadIFRIntoMISR(FMU_Type * base,uint32_t start,uint32_t ending,uint32_t * seed,uint32_t * signature)263 status_t FLASH_CMD_ReadIFRIntoMISR(FMU_Type *base, uint32_t start, uint32_t ending, uint32_t *seed, uint32_t *signature)
264 {
265     status_t returnCode = kStatus_Fail;
266 
267     flash_command_pre_sequence(base);
268     /* preparing passing parameter to read into misr command */
269     base->FCCOB[0] = FLASH_READ_IFR_INTO_MISR;
270     base->FCCOB[2] = start;
271     base->FCCOB[3] = ending;
272     base->FCCOB[4] = seed[0];
273     base->FCCOB[5] = seed[1];
274     base->FCCOB[6] = seed[2];
275     base->FCCOB[7] = seed[3];
276     flash_command_sequence(base);
277     /* calling flash command sequence function to execute the command */
278     returnCode = flash_command_complete(base);
279 
280     if ((kStatus_FLASH_Success == returnCode) && (signature != NULL))
281     {
282         signature[0] = base->FCCOB[4];
283         signature[1] = base->FCCOB[5];
284         signature[2] = base->FCCOB[6];
285         signature[3] = base->FCCOB[7];
286     }
287 
288     return returnCode;
289 }
290 
291 /*!
292  * @brief FLASH Command Pre Sequence
293  *
294  * This function is used to perform the check before loading FCCOB registers
295  *
296  * @param
297  * @return
298  */
299 #if defined(FLASH_DRIVER_IS_FLASH_RESIDENT) && (FLASH_DRIVER_IS_FLASH_RESIDENT == 1)
300 #if defined(__IAR_SYSTEMS_ICC__)
301 __ramfunc
302 #elif defined(__GNUC__)
303 __attribute__((section(".ramfunc"))) __attribute__((__noinline__))
304 #endif
305 #endif
flash_command_pre_sequence(FMU_Type * base)306 static void flash_command_pre_sequence(FMU_Type *base)
307 {
308     if ((base->FSTAT & FLASH_FSTAT_DFDIF_MASK) != 0U)
309     {
310         /* Acknowledge previous ECC fault. The fault occured during a previous read or verify erase but too late to  */
311         base->FSTAT = FLASH_FSTAT_DFDIF_MASK;
312     }
313     // Check if previous command complete, CCIF==1, wait for CCIF set
314     while (((base->FSTAT) & FLASH_FSTAT_CCIF_MASK) == 0U)
315     {
316     }
317 
318     /* clear CMDABT & ACCERR & PVIOL flag in flash status register */
319     base->FSTAT = (FLASH_FSTAT_CMDABT_MASK | FLASH_FSTAT_ACCERR_MASK | FLASH_FSTAT_PVIOL_MASK);
320 }
321 
322 /*!
323  * @brief FLASH Command Pre Sequence
324  *
325  * This function is used to perform launching command and wait for completion
326  *
327  * @param
328  * @return
329  */
330 #if defined(FLASH_DRIVER_IS_FLASH_RESIDENT) && (FLASH_DRIVER_IS_FLASH_RESIDENT == 1)
331 #if defined(__IAR_SYSTEMS_ICC__)
332 __ramfunc
333 #elif defined(__GNUC__)
334 __attribute__((section(".ramfunc"))) __attribute__((__noinline__))
335 #endif
336 #endif
flash_command_sequence(FMU_Type * base)337 static void flash_command_sequence(FMU_Type *base)
338 {
339     /* clear CCIF bit to launch the command */
340     base->FSTAT = FLASH_FSTAT_CCIF_MASK;
341 
342     /* Check CCIF bit of the flash status register, wait till it is set */
343     while ((base->FSTAT & FLASH_FSTAT_CCIF_MASK) == 0U)
344     {
345     }
346 }
347 
348 /*!
349  * @brief Flash Erase Sector(ERSSCR) Command
350  *
351  * This function is used to perform the erase sector command sequence to the flash.
352  *
353  * @param driver Pointer to storage for the driver runtime state.
354  * @return
355  */
356 #if defined(FLASH_DRIVER_IS_FLASH_RESIDENT) && (FLASH_DRIVER_IS_FLASH_RESIDENT == 1)
357 #if defined(__IAR_SYSTEMS_ICC__)
358 __ramfunc
359 #elif defined(__GNUC__)
360 __attribute__((section(".ramfunc"))) __attribute__((__noinline__))
361 #endif
362 #endif
flash_erase_sequence(FMU_Type * base,uint32_t start)363 static void flash_erase_sequence(FMU_Type *base, uint32_t start)
364 {
365     /* clear CCIF bit to launch the command */
366     base->FSTAT = FLASH_FSTAT_CCIF_MASK;
367 
368     while ((base->FSTAT & FLASH_FSTAT_PEWEN_MASK) == 0U)
369     {
370     }
371 
372     for (uint32_t i = 0u; i < 4u; i++)
373     {
374         *((uint32_t *)(start + i * 4U)) = 0x0U;
375     }
376 
377     while ((base->FSTAT & FLASH_FSTAT_PERDY_MASK) == 0U)
378     {
379     }
380 
381     base->FSTAT = FLASH_FSTAT_PERDY_MASK;
382 
383     /* Check CCIF bit of the flash status register, wait till it is set */
384     while ((base->FSTAT & FLASH_FSTAT_CCIF_MASK) == 0U)
385     {
386     }
387 }
388 
389 /*!
390  * @brief Flash Program Command
391  *
392  * This function is used to perform the program command sequence to the flash.
393  *
394  * @param driver Pointer to storage for the driver runtime state.
395  * @return
396  */
397 #if defined(FLASH_DRIVER_IS_FLASH_RESIDENT) && (FLASH_DRIVER_IS_FLASH_RESIDENT == 1)
398 #if defined(__IAR_SYSTEMS_ICC__)
399 __ramfunc
400 #elif defined(__GNUC__)
401 __attribute__((section(".ramfunc"))) __attribute__((__noinline__))
402 #endif
403 #endif
flash_pgm_sequence(FMU_Type * base,uint32_t start,uint32_t * src,uint8_t isPage)404 static void flash_pgm_sequence(FMU_Type *base, uint32_t start, uint32_t *src, uint8_t isPage)
405 {
406     /* clear CCIF bit to launch the command */
407     base->FSTAT = FLASH_FSTAT_CCIF_MASK;
408 
409     while ((base->FSTAT & FLASH_FSTAT_PEWEN_MASK) == 0U)
410     {
411     }
412 
413     uint8_t lengthInWord;
414 
415     if (isPage == 1U)
416     {
417         lengthInWord = FLASH_FEATURE_PAGE_SIZE_IN_WORD;
418     }
419     else
420     {
421         lengthInWord = FLASH_FEATURE_PHRASE_SIZE_IN_WORD;
422     }
423 
424     for (uint32_t i = 0; i < lengthInWord; i++)
425     {
426         *((uint32_t *)(start + i * 4U)) = src[i];
427     }
428 
429     while ((base->FSTAT & FLASH_FSTAT_PERDY_MASK) == 0U)
430     {
431     }
432 
433     base->FSTAT = FLASH_FSTAT_PERDY_MASK;
434 
435     /* Check CCIF bit of the flash status register, wait till it is set */
436     while ((base->FSTAT & FLASH_FSTAT_CCIF_MASK) == 0U)
437     {
438     }
439 }
440 
441 /*!
442  * @brief FLASH Command
443  *
444  * This function is used to perform the program/erase command sequence to the flash.
445  *
446  * @param driver Pointer to storage for the driver runtime state.
447  * @return An error code or kStatus_FLASH_Success
448  */
flash_command_complete(FMU_Type * base)449 static status_t flash_command_complete(FMU_Type *base)
450 {
451     uint32_t registerValue;
452 
453     /* Check error bits */
454     /* Get flash status register value */
455     registerValue   = base->FSTAT;
456     status_t status = kStatus_Fail;
457 
458     /* checking access error */
459     if ((registerValue & FLASH_FSTAT_ACCERR_MASK) != 0U)
460     {
461         status = kStatus_FLASH_AccessError;
462     }
463     /* checking protection error */
464     else if ((registerValue & FLASH_FSTAT_PVIOL_MASK) != 0U)
465     {
466         status = kStatus_FLASH_ProtectionViolation;
467     }
468     /* check  protection level */
469     else if ((registerValue & FLASH_FSTAT_CMDABT_MASK) != 0U)
470     {
471         status = kStatus_FLASH_CommandAborOption;
472     }
473     else if ((registerValue & FLASH_FSTAT_FAIL_MASK) != 0U)
474     {
475         status = kStatus_FLASH_CommandFailure;
476     }
477     else if ((registerValue & FLASH_FSTAT_DFDIF_MASK) != 0U)
478     {
479         status      = kStatus_FLASH_EccFaultDetected;
480         base->FSTAT = FLASH_FSTAT_DFDIF_MASK;
481     }
482     else
483     {
484         status = kStatus_FLASH_Success;
485     }
486     return status;
487 }
488