1 /*
2  * Copyright 2018 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include "fsl_nand_flash.h"
12 #include "fsl_flexspi_nand_flash.h"
13 
14 /*******************************************************************************
15  * Definitions
16  ******************************************************************************/
17 
18 /*******************************************************************************
19  * Prototypes
20  ******************************************************************************/
21 
22 /*******************************************************************************
23  * Variables
24  ******************************************************************************/
25 static flexspi_mem_nand_handle_t flexspiMemHandle;
26 /*******************************************************************************
27  * Code
28  ******************************************************************************/
29 /* NAND Flash write enable */
flexspi_nand_write_enable(FLEXSPI_Type * base,flexspi_port_t port,uint32_t baseAddr)30 static status_t flexspi_nand_write_enable(FLEXSPI_Type *base, flexspi_port_t port, uint32_t baseAddr)
31 {
32     flexspi_transfer_t flashXfer;
33     status_t status;
34 
35     /* Write enable */
36     flashXfer.deviceAddress = baseAddr;
37     flashXfer.port          = port;
38     flashXfer.cmdType       = kFLEXSPI_Command;
39     flashXfer.SeqNumber     = 1;
40     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_WRITEENABLE;
41 
42     status = FLEXSPI_TransferBlocking(base, &flashXfer);
43 
44     return status;
45 }
46 
47 /* NAND Flash wait status busy */
flexspi_nand_wait_bus_busy(FLEXSPI_Type * base,flexspi_mem_nand_handle_t * handle,uint32_t baseAddr)48 static status_t flexspi_nand_wait_bus_busy(FLEXSPI_Type *base, flexspi_mem_nand_handle_t *handle, uint32_t baseAddr)
49 {
50     /* Wait status ready. */
51     bool isBusy = true;
52     uint32_t readValue;
53     status_t status;
54     flexspi_transfer_t flashXfer;
55 
56     flashXfer.deviceAddress = baseAddr;
57     flashXfer.port          = handle->port;
58     flashXfer.cmdType       = kFLEXSPI_Read;
59     flashXfer.SeqNumber     = 1;
60     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_READSTATUS;
61     flashXfer.data          = &readValue;
62     flashXfer.dataSize      = 1;
63 
64     do
65     {
66         status = FLEXSPI_TransferBlocking(base, &flashXfer);
67 
68         if (status != kStatus_Success)
69         {
70             return status;
71         }
72 
73         if (handle->busyBitPolarity)
74         {
75             isBusy = (~readValue) & (1 << handle->busyOffset);
76         }
77         else
78         {
79             isBusy = readValue & (1 << handle->busyOffset);
80         }
81 
82     } while (isBusy);
83 
84     return status;
85 }
86 
flexspi_nand_check_ecc_status(FLEXSPI_Type * base,flexspi_mem_nand_handle_t * handle,uint32_t baseAddr,bool * isCheckPassed)87 static status_t flexspi_nand_check_ecc_status(FLEXSPI_Type *base,
88                                               flexspi_mem_nand_handle_t *handle,
89                                               uint32_t baseAddr,
90                                               bool *isCheckPassed)
91 {
92     flexspi_transfer_t flashXfer;
93     status_t status;
94     uint32_t eccStatus;
95 
96     /* Write neable */
97     flashXfer.deviceAddress = baseAddr;
98     flashXfer.port          = handle->port;
99     flashXfer.cmdType       = kFLEXSPI_Read;
100     flashXfer.SeqNumber     = 1;
101     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_READECCSTAT;
102     flashXfer.data          = &eccStatus;
103     flashXfer.dataSize      = 1;
104 
105     status = FLEXSPI_TransferBlocking(base, &flashXfer);
106     if (status != kStatus_Success)
107     {
108         return status;
109     }
110 
111     *isCheckPassed = false;
112 
113     if ((eccStatus & handle->eccStatusMask) != handle->eccFailureMask)
114     {
115         *isCheckPassed = true;
116     }
117 
118     return status;
119 }
120 
flexspi_nand_unlock_all_blocks(FLEXSPI_Type * base,flexspi_port_t port)121 status_t flexspi_nand_unlock_all_blocks(FLEXSPI_Type *base, flexspi_port_t port)
122 {
123     uint32_t temp;
124     flexspi_transfer_t flashXfer;
125     status_t status = kStatus_Success;
126 
127     /* unlock all blocks. */
128     temp                    = 0;
129     flashXfer.deviceAddress = 0;
130     flashXfer.port          = port;
131     flashXfer.cmdType       = kFLEXSPI_Write;
132     flashXfer.SeqNumber     = 1;
133     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_UNLOCKALL;
134     flashXfer.data          = &temp;
135     flashXfer.dataSize      = 1;
136 
137     status = FLEXSPI_TransferBlocking(base, &flashXfer);
138 
139     return status;
140 }
141 
142 /* Initialize NAND Flash device */
Nand_Flash_Init(nand_config_t * config,nand_handle_t * handle)143 status_t Nand_Flash_Init(nand_config_t *config, nand_handle_t *handle)
144 {
145     assert(config);
146     assert(handle);
147 
148     flexspi_mem_config_t *memConfig = (flexspi_mem_config_t *)config->memControlConfig;
149 
150     /* Cleanup nand operation info */
151     memset(handle, 0, sizeof(handle));
152 
153     handle->deviceSpecific           = &flexspiMemHandle;
154     handle->driverBaseAddr           = config->driverBaseAddr;
155     flexspiMemHandle.port            = memConfig->devicePort;
156     flexspiMemHandle.busyOffset      = memConfig->busyOffset;
157     flexspiMemHandle.busyBitPolarity = memConfig->busyBitPolarity;
158     flexspiMemHandle.eccStatusMask   = memConfig->eccStatusMask;
159     flexspiMemHandle.eccFailureMask  = memConfig->eccFailureMask;
160 
161     /* Configure flash settings according to serial flash feature. */
162     FLEXSPI_SetFlashConfig((FLEXSPI_Type *)handle->driverBaseAddr, &(memConfig->deviceConfig), memConfig->devicePort);
163 
164     /* Fill default look up table */
165     memset(memConfig->lookupTable, 0, sizeof(memConfig->lookupTable));
166     /* Read Cache 1X */
167     memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READCACHE] =
168         FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_CADDR_SDR, kFLEXSPI_1PAD, 0x10),
169                                memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READCACHE + 1] =
170                                    FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08,
171                                                    kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x80),
172 
173                                /* Read Status */
174         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READSTATUS] =
175             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0F, kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC0),
176                                memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READSTATUS + 1] =
177                                    FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01,
178                                                    kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
179 
180                                /* Write Enable */
181         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_WRITEENABLE] =
182             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
183 
184                                /* Erase block */
185         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_ERASEBLOCK] =
186             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xD8, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
187 
188                                /* Page Program Load */
189         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_PROGRAMLOAD] =
190             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_CADDR_SDR, kFLEXSPI_1PAD, 0x10),
191                                memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_PROGRAMLOAD + 1] =
192                                    FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x40,
193                                                    kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
194 
195                                /* Page Program Execute */
196         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_PROGRAMEXECUTE] =
197             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x10, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
198 
199                                /* Read Page */
200         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READPAGE] =
201             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x13, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
202 
203                                /* Read ECC status */
204         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READECCSTAT] =
205             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0F, kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC0),
206                                memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READECCSTAT + 1] =
207                                    FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01,
208                                                    kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
209 
210                                /* Read JEDEC ID */
211         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READJEDECID] =
212             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0),
213                                memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_READJEDECID + 1] =
214                                    FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01,
215                                                    kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
216 
217                                /* Unlock all blocks */
218         memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_UNLOCKALL] =
219             FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x1F, kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xA0),
220                                memConfig->lookupTable[4 * NAND_CMD_LUT_SEQ_IDX_UNLOCKALL + 1] =
221                                    FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x00,
222                                                    kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
223 
224                                /* Update LUT table. */
225         FLEXSPI_UpdateLUT((FLEXSPI_Type *)config->driverBaseAddr, 0, memConfig->lookupTable,
226                           ARRAY_SIZE(memConfig->lookupTable));
227 
228     /* Do software reset. */
229     FLEXSPI_SoftwareReset((FLEXSPI_Type *)config->driverBaseAddr);
230 
231     handle->bytesInPageDataArea  = memConfig->dataBytesPerPage;
232     handle->bytesInPageSpareArea = memConfig->bytesInPageSpareArea;
233     handle->pagesInBlock         = memConfig->pagesPerBlock;
234 
235     return kStatus_Success;
236 }
237 
Nand_Flash_Read_Page(nand_handle_t * handle,uint32_t pageIndex,uint8_t * buffer,uint32_t length)238 status_t Nand_Flash_Read_Page(nand_handle_t *handle, uint32_t pageIndex, uint8_t *buffer, uint32_t length)
239 {
240     status_t status = kStatus_Success;
241 
242     flexspi_transfer_t flashXfer;
243     uint32_t readAddress                 = pageIndex * (2 * handle->bytesInPageDataArea);
244     flexspi_mem_nand_handle_t *memHandle = (flexspi_mem_nand_handle_t *)handle->deviceSpecific;
245     flexspi_port_t port                  = memHandle->port;
246 
247     /* Read page. */
248     flashXfer.deviceAddress = readAddress;
249     flashXfer.port          = port;
250     flashXfer.cmdType       = kFLEXSPI_Command;
251     flashXfer.SeqNumber     = 1;
252     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_READPAGE;
253 
254     status = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
255 
256     if (status != kStatus_Success)
257     {
258         return status;
259     }
260 
261     status = flexspi_nand_wait_bus_busy((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, readAddress);
262     if (status != kStatus_Success)
263     {
264         return status;
265     }
266 
267     flashXfer.deviceAddress = readAddress;
268     flashXfer.port          = port;
269     flashXfer.cmdType       = kFLEXSPI_Read;
270     flashXfer.SeqNumber     = 1;
271     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_READCACHE;
272     flashXfer.data          = (uint32_t *)buffer;
273     flashXfer.dataSize      = length;
274 
275     status = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
276 
277     if (status != kStatus_Success)
278     {
279         return status;
280     }
281 
282     bool isCheckPassed;
283     status =
284         flexspi_nand_check_ecc_status((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, readAddress, &isCheckPassed);
285 
286     if (status != kStatus_Success)
287     {
288         return status;
289     }
290 
291     if (isCheckPassed == false)
292     {
293         status = kStatus_Fail;
294     }
295 
296     return status;
297 }
298 
Nand_Flash_Read_Page_Partial(nand_handle_t * handle,uint32_t pageIndex,uint32_t offset_bytes,uint8_t * buffer,uint32_t length)299 status_t Nand_Flash_Read_Page_Partial(
300     nand_handle_t *handle, uint32_t pageIndex, uint32_t offset_bytes, uint8_t *buffer, uint32_t length)
301 {
302     status_t status = kStatus_Success;
303 
304     flexspi_transfer_t flashXfer;
305     uint32_t readAddress                 = pageIndex * (2 * handle->bytesInPageDataArea);
306     flexspi_mem_nand_handle_t *memHandle = (flexspi_mem_nand_handle_t *)handle->deviceSpecific;
307     flexspi_port_t port                  = memHandle->port;
308 
309     /* Read page. */
310     flashXfer.deviceAddress = readAddress;
311     flashXfer.port          = port;
312     flashXfer.cmdType       = kFLEXSPI_Command;
313     flashXfer.SeqNumber     = 1;
314     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_READPAGE;
315 
316     status = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
317 
318     if (status != kStatus_Success)
319     {
320         return status;
321     }
322 
323     status = flexspi_nand_wait_bus_busy((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, readAddress);
324     if (status != kStatus_Success)
325     {
326         return status;
327     }
328 
329     flashXfer.deviceAddress = (readAddress + offset_bytes);
330     flashXfer.port          = port;
331     flashXfer.cmdType       = kFLEXSPI_Read;
332     flashXfer.SeqNumber     = 1;
333     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_READCACHE;
334     flashXfer.data          = (uint32_t *)buffer;
335     flashXfer.dataSize      = length;
336 
337     status = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
338 
339     if (status != kStatus_Success)
340     {
341         return status;
342     }
343 
344     bool isCheckPassed;
345     status =
346         flexspi_nand_check_ecc_status((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, readAddress, &isCheckPassed);
347 
348     if (status != kStatus_Success)
349     {
350         return status;
351     }
352 
353     if (isCheckPassed == false)
354     {
355         status = kStatus_Fail;
356     }
357 
358     return status;
359 }
Nand_Flash_Page_Program(nand_handle_t * handle,uint32_t pageIndex,const uint8_t * src,uint32_t length)360 status_t Nand_Flash_Page_Program(nand_handle_t *handle, uint32_t pageIndex, const uint8_t *src, uint32_t length)
361 {
362     status_t status;
363     flexspi_transfer_t flashXfer;
364     uint32_t address                     = pageIndex * (handle->bytesInPageDataArea + handle->bytesInPageSpareArea);
365     flexspi_mem_nand_handle_t *memHandle = (flexspi_mem_nand_handle_t *)handle->deviceSpecific;
366     flexspi_port_t port                  = memHandle->port;
367 
368     /* Write enable. */
369     status = flexspi_nand_write_enable((FLEXSPI_Type *)handle->driverBaseAddr, port, address);
370     if (status != kStatus_Success)
371     {
372         return status;
373     }
374 
375     /* Send page load command. */
376     flashXfer.deviceAddress = address;
377     flashXfer.port          = port;
378     flashXfer.cmdType       = kFLEXSPI_Write;
379     flashXfer.SeqNumber     = 1;
380     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_PROGRAMLOAD;
381     flashXfer.data          = (uint32_t *)src;
382     flashXfer.dataSize      = length;
383 
384     status = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
385     if (status != kStatus_Success)
386     {
387         return status;
388     }
389 
390     /* Send program execute command. */
391     flashXfer.deviceAddress = address;
392     flashXfer.port          = port;
393     flashXfer.cmdType       = kFLEXSPI_Command;
394     flashXfer.SeqNumber     = 1;
395     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_PROGRAMEXECUTE;
396     status                  = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
397     if (status != kStatus_Success)
398     {
399         return status;
400     }
401 
402     status = flexspi_nand_wait_bus_busy((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, address);
403     if (status != kStatus_Success)
404     {
405         return status;
406     }
407 
408     bool isCheckPassed;
409     status = flexspi_nand_check_ecc_status((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, address, &isCheckPassed);
410 
411     if (status != kStatus_Success)
412     {
413         return status;
414     }
415 
416     if (isCheckPassed == false)
417     {
418         status = kStatus_Fail;
419     }
420 
421     return status;
422 }
423 
Nand_Flash_Erase_Block(nand_handle_t * handle,uint32_t blockIndex)424 status_t Nand_Flash_Erase_Block(nand_handle_t *handle, uint32_t blockIndex)
425 {
426     flexspi_mem_nand_handle_t *memHandle = (flexspi_mem_nand_handle_t *)handle->deviceSpecific;
427     flexspi_port_t port                  = memHandle->port;
428     status_t status;
429     flexspi_transfer_t flashXfer;
430 
431     uint32_t address = blockIndex * (handle->bytesInPageDataArea * 2) * handle->pagesInBlock;
432 
433     /* Unlock block */
434     flexspi_nand_unlock_all_blocks((FLEXSPI_Type *)handle->driverBaseAddr, port);
435 
436     /* Write enable */
437     status = flexspi_nand_write_enable((FLEXSPI_Type *)handle->driverBaseAddr, port, address);
438     if (status != kStatus_Success)
439     {
440         return status;
441     }
442 
443     /* Send erase command. */
444     flashXfer.deviceAddress = address;
445     flashXfer.port          = port;
446     flashXfer.cmdType       = kFLEXSPI_Command;
447     flashXfer.SeqNumber     = 1;
448     flashXfer.seqIndex      = NAND_CMD_LUT_SEQ_IDX_ERASEBLOCK;
449 
450     status = FLEXSPI_TransferBlocking((FLEXSPI_Type *)handle->driverBaseAddr, &flashXfer);
451     if (status != kStatus_Success)
452     {
453         return status;
454     }
455 
456     status = flexspi_nand_wait_bus_busy((FLEXSPI_Type *)handle->driverBaseAddr, memHandle, address);
457     if (status != kStatus_Success)
458     {
459         return status;
460     }
461 
462     return status;
463 }
464