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