1 /*
2  * Copyright 2022, 2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include <string.h>
8 #include "board.h"
9 #include "fsl_lpspi_nor_flash.h"
10 #include "fsl_nor_flash.h"
11 #include "fsl_lpspi_mem_adapter.h"
12 
13 /*******************************************************************************
14  * Definitions
15  ******************************************************************************/
16 
17 /*******************************************************************************
18  * Prototypes
19  ******************************************************************************/
20 extern uint32_t BOARD_GetLpspiClock(void);
21 extern uint32_t BOARD_GetNorFlashBaudrate(void);
22 extern LPSPI_Type *BOARD_GetLpspiForNorFlash(void);
23 /*******************************************************************************
24  * Variables
25  ******************************************************************************/
26 
27 /*******************************************************************************
28  * Code
29  ******************************************************************************/
30 /*!
31  * @brief Initialize NOR FLASH devices.
32  *
33  *  This function initialize NOR Flash controller and NOR Flash.
34  *
35  * @param config    NOR flash configuration.
36  *        The "memControlConfig" and "driverBaseAddr" are controller specific structure.
37  *        please set those two parameter with your Nand controller configuration structure type pointer.
38  *        such as for SEMC:
39  *
40  *        spifi_mem_nor_config_t spifiNorconfig =
41  *        {
42  *            .....
43  *        }
44  *        nor_config_t config =
45  *        {
46  *            .memControlConfig = (void *)\&spifiNorconfig;
47  *            .driverBaseAddr   = (void *)SPIFI0;
48  *        }
49  * @param handle    The NOR Flash handler.
50  * @retval execution status
51  */
Nor_Flash_Init(nor_config_t * config,nor_handle_t * handle)52 status_t Nor_Flash_Init(nor_config_t *config, nor_handle_t *handle)
53 {
54     assert(config);
55     assert(handle);
56 
57     uint32_t baudRate   = BOARD_GetNorFlashBaudrate();
58     status_t initStatus = kStatus_Fail;
59     lpspi_memory_config_t *memConfig = (lpspi_memory_config_t *)(config->memControlConfig);
60 
61     handle->bytesInSectorSize = memConfig->bytesInSectorSize;
62     handle->bytesInPageSize   = memConfig->bytesInPageSize;
63     handle->driverBaseAddr    = BOARD_GetLpspiForNorFlash();
64 
65     do
66     {
67         uint32_t spiClock_Hz = BOARD_GetLpspiClock();
68 
69         spi_master_config_t spiMasterCfg;
70         spiMasterCfg.baudRate  = baudRate;
71         spiMasterCfg.clockFreq = spiClock_Hz;
72         spiMasterCfg.whichPcs  = 0;
73         status_t status        = LPSPI_MemInit(&spiMasterCfg, handle->driverBaseAddr);
74         if (status != kStatus_Success)
75         {
76             break;
77         }
78 
79         flash_id_t flashId;
80 
81         status = LPSPI_MemReadId(&flashId, handle->driverBaseAddr);
82         if (status != kStatus_Success)
83         {
84             break;
85         }
86 
87         initStatus = kStatus_Success;
88     } while (false);
89 
90     return initStatus;
91 }
92 
93 /*!
94  * @brief Read page data from NOR Flash.
95  *
96  * @param handle    The NOR Flash handler.
97  * @param address  NOR flash start address to read data from.
98  * @param buffer  NOR flash buffer to read data to.
99  * @param length  NOR flash read length.
100  * @retval execution status
101  */
Nor_Flash_Read(nor_handle_t * handle,uint32_t address,uint8_t * buffer,uint32_t length)102 status_t Nor_Flash_Read(nor_handle_t *handle, uint32_t address, uint8_t *buffer, uint32_t length)
103 {
104     assert(handle);
105 
106     status_t readStatus = kStatus_Fail;
107 
108     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
109 
110     assert(base);
111 
112     readStatus = LPSPI_MemRead(address, buffer, length, true, base);
113 
114     return readStatus;
115 }
116 
117 /*!
118  * @brief Initialize NOR FLASH devices.
119  *
120  *  This function initialize NOR Flash controller and NOR Flash.
121  *
122  * @param config    NOR flash configuration.
123  * @param handle    The NOR Flash handler.
124  * @retval execution status
125  */
Nor_Flash_Initialization(nor_config_t * config,nor_handle_t * handle)126 status_t Nor_Flash_Initialization(nor_config_t *config, nor_handle_t *handle)
127 {
128     return Nor_Flash_Init(config, handle);
129 }
130 
131 /*!
132  * @brief Program page data to NOR Flash.
133  *
134  * @param handle    The NOR Flash handler.
135  * @param address  The address to be programed.
136  * @param buffer  The buffer to be programed to the page.
137  * @retval execution status
138  */
Nor_Flash_Page_Program(nor_handle_t * handle,uint32_t address,uint8_t * buffer)139 status_t Nor_Flash_Page_Program(nor_handle_t *handle, uint32_t address, uint8_t *buffer)
140 {
141     assert(handle);
142 
143     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
144 
145     assert(base);
146 
147     status_t status = kStatus_Fail;
148 
149     bool blocking = true;
150 
151     if (handle->deviceSpecific != NULL)
152     {
153         blocking = (*(bool *)(handle->deviceSpecific));
154     }
155 
156     status = LPSPI_MemWritePage(address, buffer, handle->bytesInPageSize, blocking, base);
157 
158     return status;
159 }
160 
161 /*!
162  * @brief Program data to NOR Flash.
163  *
164  * @param handle    The NOR Flash handler.
165  * @param address  The address to be programed.
166  * @param buffer  The buffer to be programed to the page.
167  * @param length  The data length to be programed to the page.
168  * @retval execution status
169  */
Nor_Flash_Program(nor_handle_t * handle,uint32_t address,uint8_t * buffer,uint32_t length)170 status_t Nor_Flash_Program(nor_handle_t *handle, uint32_t address, uint8_t *buffer, uint32_t length)
171 {
172     assert(handle);
173 
174     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
175 
176     assert(base);
177 
178     status_t writeStatus = kStatus_Fail;
179 
180     bool blocking = true;
181 
182     if (handle->deviceSpecific != NULL)
183     {
184         blocking = (*(bool *)(handle->deviceSpecific));
185     }
186 
187     do
188     {
189         while ((address & 0xFFu) + length > 0xFFu)
190         {
191             uint32_t bytes = 0x100u - (address & 0xFFu);
192 
193             writeStatus = LPSPI_MemWritePage(address, buffer, bytes, blocking, base);
194             length -= bytes;
195             address += bytes;
196             buffer += bytes;
197 
198             if (writeStatus != kStatus_Success)
199             {
200                 break;
201             }
202         }
203 
204         writeStatus = LPSPI_MemWritePage(address, buffer, length, blocking, base);
205         if (writeStatus != kStatus_Success)
206         {
207             break;
208         }
209         writeStatus = kStatus_Success;
210 
211     } while (false);
212 
213     return writeStatus;
214 }
215 
216 /*!
217  * @brief Erase page.
218  *
219  * @note Not all device support to erase page.
220 
221  * @param handle    The NOR Flash handler.
222  * @param address   The start address to be erased.
223  * @retval execution status
224  */
Nor_Flash_Erase_Page(nor_handle_t * handle,uint32_t address)225 status_t Nor_Flash_Erase_Page(nor_handle_t *handle, uint32_t address)
226 {
227     assert(handle);
228 
229     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
230 
231     assert(base);
232 
233     status_t status = kStatus_Fail;
234 
235     bool blocking = true;
236 
237     if (handle->deviceSpecific != NULL)
238     {
239         blocking = (*(bool *)(handle->deviceSpecific));
240     }
241 
242     status = LPSPI_MemErase(address, kSize_ErasePage, blocking, base);
243 
244     return status;
245 }
246 
247 /*!
248  * @brief Erase sector.
249  *
250  * @param handle    The NOR Flash handler.
251  * @param address   The start address to be erased.
252  * @retval execution status
253  */
Nor_Flash_Erase_Sector(nor_handle_t * handle,uint32_t address)254 status_t Nor_Flash_Erase_Sector(nor_handle_t *handle, uint32_t address)
255 {
256     assert(handle);
257 
258     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
259 
260     assert(base);
261 
262     eraseOptions_t tmpEraseOption = kSize_Erase4K;
263     status_t status = kStatus_Fail;
264 
265     bool blocking = true;
266 
267     if (handle->deviceSpecific != NULL)
268     {
269         blocking = (*(bool *)(handle->deviceSpecific));
270     }
271 
272     switch (handle->bytesInSectorSize)
273     {
274         case 4096UL:
275         {
276             tmpEraseOption = kSize_Erase4K;
277             break;
278         }
279         case 32768UL:
280         {
281             tmpEraseOption = kSize_Erase32K;
282             break;
283         }
284         case 65536UL:
285         {
286             tmpEraseOption = kSize_Erase64K;
287             break;
288         }
289         default:
290         {
291             return kStatus_OutOfRange;
292         }
293     }
294     status = LPSPI_MemErase(address, tmpEraseOption, blocking, base);
295 
296     return status;
297 }
298 
299 /*!
300  * @brief Erase 4K block.
301  *
302  * @param handle    The NOR Flash handler.
303  * @param address   The start address to be erased.
304  * @retval execution status
305  */
Nor_Flash_Erase_Block_4K(nor_handle_t * handle,uint32_t address)306 status_t Nor_Flash_Erase_Block_4K(nor_handle_t *handle, uint32_t address)
307 {
308     assert(handle);
309 
310     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
311 
312     assert(base);
313 
314     status_t status = kStatus_Fail;
315 
316     bool blocking = true;
317 
318     if (handle->deviceSpecific != NULL)
319     {
320         blocking = (*(bool *)(handle->deviceSpecific));
321     }
322 
323     status = LPSPI_MemErase(address, kSize_Erase4K, blocking, base);
324 
325     return status;
326 }
327 
328 /*!
329  * @brief Erase 32K block.
330  *
331  * @param handle    The NOR Flash handler.
332  * @param address   The start address to be erased.
333  * @retval execution status
334  */
Nor_Flash_Erase_Block_32K(nor_handle_t * handle,uint32_t address)335 status_t Nor_Flash_Erase_Block_32K(nor_handle_t *handle, uint32_t address)
336 {
337     assert(handle);
338 
339     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
340 
341     assert(base);
342 
343     status_t status = kStatus_Fail;
344 
345     bool blocking = true;
346 
347     if (handle->deviceSpecific != NULL)
348     {
349         blocking = (*(bool *)(handle->deviceSpecific));
350     }
351 
352     status = LPSPI_MemErase(address, kSize_Erase32K, blocking, base);
353 
354     return status;
355 }
356 
357 /*!
358  * @brief Erase 64K block.
359  *
360  * @param handle    The NOR Flash handler.
361  * @param address   The start address to be erased.
362  * @retval execution status
363  */
Nor_Flash_Erase_Block_64K(nor_handle_t * handle,uint32_t address)364 status_t Nor_Flash_Erase_Block_64K(nor_handle_t *handle, uint32_t address)
365 {
366     assert(handle);
367 
368     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
369 
370     assert(base);
371 
372     status_t status = kStatus_Fail;
373 
374     bool blocking = true;
375 
376     if (handle->deviceSpecific != NULL)
377     {
378         blocking = (*(bool *)(handle->deviceSpecific));
379     }
380 
381     status = LPSPI_MemErase(address, kSize_Erase64K, blocking, base);
382 
383     return status;
384 }
385 
386 /*!
387  * @brief Erase block.
388  *
389  * @param handle    The NOR Flash handler.
390  * @param address   The start address to be erased.
391  * @retval execution status
392  */
Nor_Flash_Erase_Block(nor_handle_t * handle,uint32_t address)393 status_t Nor_Flash_Erase_Block(nor_handle_t *handle, uint32_t address)
394 {
395     assert(handle);
396 
397     status_t status = kStatus_Fail;
398 
399     status = Nor_Flash_Erase_Block_4K(handle, address);
400 
401     return status;
402 }
403 
404 /*!
405  * @brief Erase flash.
406  *
407  * @param handle    The NOR Flash handler.
408  * @param address   The start address to be erased.
409  * @param size_Byte The size to be erased.
410  * @retval execution status
411  */
Nor_Flash_Erase(nor_handle_t * handle,uint32_t address,uint32_t size_Byte)412 status_t Nor_Flash_Erase(nor_handle_t *handle, uint32_t address, uint32_t size_Byte)
413 {
414     assert(handle);
415 
416     status_t status  = kStatus_Fail;
417     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
418 
419     assert((size_Byte == 256U) || (size_Byte == 4096U) || (size_Byte == 32768U) || (size_Byte == 65536U));
420     assert(base);
421 
422     bool blocking = true;
423 
424     if (handle->deviceSpecific != NULL)
425     {
426         blocking = (*(bool *)(handle->deviceSpecific));
427     }
428 
429     switch (size_Byte)
430     {
431         case 256U:
432             status = LPSPI_MemErase(address, kSize_ErasePage, blocking, base);
433             break;
434         case 4096U:
435             status = LPSPI_MemErase(address, kSize_Erase4K, blocking, base);
436             break;
437         case 32768U:
438             status = LPSPI_MemErase(address, kSize_Erase32K, blocking, base);
439             break;
440         case 65536U:
441             status = LPSPI_MemErase(address, kSize_Erase64K, blocking, base);
442             break;
443         default:
444             /* All the cases have been listed above, the default clause should not be reached. */
445             assert(false);
446             break;
447     }
448 
449     return status;
450 }
451 
452 /*!
453  * @brief Erase Chip NOR Flash .
454  *
455  * @param handle    The NOR Flash handler.
456  * @retval execution status
457  */
Nor_Flash_Erase_Chip(nor_handle_t * handle)458 status_t Nor_Flash_Erase_Chip(nor_handle_t *handle)
459 {
460     assert(handle);
461 
462     status_t status = kStatus_Fail;
463 
464     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
465 
466     assert(base);
467 
468     bool blocking = true;
469 
470     if (handle->deviceSpecific != NULL)
471     {
472         blocking = (*(bool *)(handle->deviceSpecific));
473     }
474 
475     status = LPSPI_MemErase(0x0, kSize_EraseAll, blocking, base);
476 
477     return status;
478 }
479 
480 /*!
481  * @brief Deinitialize NOR FLASH devices.
482  *
483  * @param handle    The NOR Flash handler.
484  * @retval execution status
485  */
Nor_Flash_DeInit(nor_handle_t * handle)486 status_t Nor_Flash_DeInit(nor_handle_t *handle)
487 {
488     assert(handle);
489 
490     status_t status = kStatus_Fail;
491 
492     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
493 
494     assert(base);
495 
496     status = LPSPI_MemDeinit(base);
497 
498     return status;
499 }
500 
501 /*!
502  * @brief  Get the busy status of the NOR Flash.
503  *
504  * @param handle    The NOR Flash handler.
505  * @retval execution status
506  */
Nor_Flash_Is_Busy(nor_handle_t * handle,bool * isBusy)507 status_t Nor_Flash_Is_Busy(nor_handle_t *handle, bool *isBusy)
508 {
509     assert(handle);
510 
511     status_t status = kStatus_Fail;
512 
513     LPSPI_Type *base = (LPSPI_Type *)handle->driverBaseAddr;
514 
515     assert(base);
516 
517     status = LPSPI_MemIsBusy(base, isBusy);
518 
519     return status;
520 }
521 
Nor_Flash_Enter_Lowpower(nor_handle_t * handle)522 status_t Nor_Flash_Enter_Lowpower(nor_handle_t *handle)
523 {
524     status_t status = kStatus_Fail;
525     bool busy;
526 
527     assert(handle);
528 
529     do
530     {
531         /* Make sure the flash is not busy */
532         (void)Nor_Flash_Is_Busy(handle, &busy);
533     } while (busy == true);
534 
535     status = Nor_Flash_DeInit(handle);
536 
537     return status;
538 }
539 
Nor_Flash_Exit_Lowpower(nor_handle_t * handle)540 status_t Nor_Flash_Exit_Lowpower(nor_handle_t *handle)
541 {
542     assert(handle);
543 
544     uint32_t baudRate   = BOARD_GetNorFlashBaudrate();
545     status_t initStatus = kStatus_Fail;
546 
547     handle->bytesInSectorSize = 256U;
548     handle->bytesInPageSize   = 256U;
549     handle->driverBaseAddr    = BOARD_GetLpspiForNorFlash();
550 
551     do
552     {
553         uint32_t spiClock_Hz = BOARD_GetLpspiClock();
554 
555         spi_master_config_t spiMasterCfg;
556         spiMasterCfg.baudRate  = baudRate;
557         spiMasterCfg.clockFreq = spiClock_Hz;
558         spiMasterCfg.whichPcs  = 0;
559         status_t status        = LPSPI_MemInit(&spiMasterCfg, handle->driverBaseAddr);
560         if (status != kStatus_Success)
561         {
562             break;
563         }
564 
565         initStatus = kStatus_Success;
566     } while (false);
567 
568     return initStatus;
569 }
570