1 /*
2  * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-03-01     CDT          first version
9  * 2042-12-24     CDT          fix compiler warning
10  */
11 
12 
13 /*******************************************************************************
14  * Include files
15  ******************************************************************************/
16 #include <rtthread.h>
17 
18 
19 #if defined (BSP_USING_EXMC)
20 #if defined (BSP_USING_NAND)
21 
22 #include "drv_nand.h"
23 #include "board_config.h"
24 #include "nand_port.h"
25 
26 /*******************************************************************************
27  * Local type definitions ('typedef')
28  ******************************************************************************/
29 /* rthw nand */
30 struct rthw_nand
31 {
32     struct rt_mtd_nand_device nand_dev;
33 
34     rt_uint32_t nfc_bank;
35     rt_uint32_t id;
36     struct rt_mutex lock;
37 };
38 
39 /*******************************************************************************
40  * Local pre-processor symbols/macros ('#define')
41  ******************************************************************************/
42 //#define DRV_DEBUG
43 #define LOG_TAG "drv.nand"
44 #include <drv_log.h>
45 
46 /* Nand status */
47 #define NAND_BUSY                   0x00000000U
48 #define NAND_FAIL                   0x00000001U
49 #define NAND_READY                  0x00000040U
50 #define NAND_VALID_ADDRESS          0x00000100U
51 #define NAND_INVALID_ADDRESS        0x00000200U
52 #define NAND_TIMEOUT_ERROR          0x00000400U
53 
54 #define NAND_ERASE_TIMEOUT          2000000UL
55 #define NAND_READ_TIMEOUT           2000000UL
56 #define NAND_WRITE_TIMEOUT          2000000UL
57 #define NAND_RESET_TIMEOUT          2000000UL
58 
59 #define NAND_ECC_SECTOR_SIZE        512UL
60 #define NAND_ECC_CODE_SIZE          ((NAND_EXMC_NFC_ECC_MD == EXMC_NFC_1BIT_ECC) ? 3UL : 8UL)
61 #define NAND_SPARE_FREE_SIZE        (NAND_SPARE_AREA_SIZE - (NAND_BYTES_PER_PAGE / NAND_ECC_SECTOR_SIZE) * NAND_ECC_CODE_SIZE)
62 
63 /*******************************************************************************
64  * Global variable definitions (declared in header file with 'extern')
65  ******************************************************************************/
66 #if defined (BSP_USING_NAND)
67     extern rt_err_t rt_hw_board_nand_init(void);
68 #endif
69 
70 /*******************************************************************************
71  * Local function prototypes ('static')
72  ******************************************************************************/
73 
74 /*******************************************************************************
75  * Local variable definitions ('static')
76  ******************************************************************************/
77 struct rthw_nand _hw_nand;
78 
79 /*******************************************************************************
80  * Function implementation - global ('extern') and local ('static')
81  ******************************************************************************/
82 
_nand_verify_clock_frequency(void)83 static rt_err_t _nand_verify_clock_frequency(void)
84 {
85     rt_err_t ret = RT_EOK;
86 
87 #if defined (HC32F4A0)
88     /* EXCLK max frequency for Nand: 60MHz */
89     if (CLK_GetBusClockFreq(CLK_BUS_EXCLK) > (60 * 1000000))
90     {
91         ret = -RT_ERROR;
92     }
93 #endif
94 
95     return ret;
96 }
97 
_nand_init(struct rt_mtd_nand_device * device)98 static rt_err_t _nand_init(struct rt_mtd_nand_device *device)
99 {
100     rt_uint8_t au8DevId[4];
101     rt_err_t ret = -RT_ERROR;
102     stc_exmc_nfc_init_t nfc_init_params;
103     struct rthw_nand *hw_nand = (struct rthw_nand *)device;
104     rt_uint16_t oob_free = (rt_uint16_t)(NAND_SPARE_AREA_SIZE - \
105                                          (NAND_BYTES_PER_PAGE / NAND_ECC_SECTOR_SIZE) * NAND_ECC_CODE_SIZE);
106 
107     RT_ASSERT(device != RT_NULL);
108 
109     hw_nand->nfc_bank = NAND_EXMC_NFC_BANK;
110 
111     /* verify nand clock frequency */
112     if (_nand_verify_clock_frequency() != RT_EOK)
113     {
114         LOG_E("EXMC clock frequency is over limit for NAND!");
115         return -RT_ERROR;
116     }
117 
118     /* Initialize nand port.*/
119     rt_hw_board_nand_init();
120 
121     /* Enable NFC module clock */
122     FCG_Fcg3PeriphClockCmd(FCG3_PERIPH_NFC, ENABLE);
123 
124     /* Enable NFC. */
125     EXMC_NFC_Cmd(ENABLE);
126 
127     /* Configure NFC base parameters. */
128     nfc_init_params.u32OpenPage = EXMC_NFC_OPEN_PAGE_DISABLE;
129     nfc_init_params.stcBaseConfig.u32CapacitySize = NAND_EXMC_NFC_BANK_CAPACITY;
130     nfc_init_params.stcBaseConfig.u32MemoryWidth = NAND_EXMC_NFC_MEMORY_WIDTH;
131     nfc_init_params.stcBaseConfig.u32BankNum = EXMC_NFC_1BANK;
132     nfc_init_params.stcBaseConfig.u32PageSize = NAND_EXMC_NFC_PAGE_SIZE;
133     nfc_init_params.stcBaseConfig.u32WriteProtect = EXMC_NFC_WR_PROTECT_DISABLE;
134     nfc_init_params.stcBaseConfig.u32EccMode = NAND_EXMC_NFC_ECC_MD;
135     nfc_init_params.stcBaseConfig.u32RowAddrCycle = NAND_EXMC_NFC_ROW_ADDR_CYCLE;
136     nfc_init_params.stcBaseConfig.u8SpareSizeForUserData = (rt_uint8_t)(oob_free >> 2);
137 
138     /* Configure NFC timing */
139     nfc_init_params.stcTimingReg0.u32TS = NAND_TS;
140     nfc_init_params.stcTimingReg0.u32TWP = NAND_TWP;
141     nfc_init_params.stcTimingReg0.u32TRP = NAND_TRP;
142 
143     nfc_init_params.stcTimingReg0.u32TH = NAND_TH;
144 
145     nfc_init_params.stcTimingReg1.u32TWH = NAND_TWH;
146     nfc_init_params.stcTimingReg1.u32TRH = NAND_TRH;
147     nfc_init_params.stcTimingReg1.u32TRR = NAND_TRR;
148     nfc_init_params.stcTimingReg1.u32TWB = NAND_TWB;
149 
150     nfc_init_params.stcTimingReg2.u32TCCS = NAND_TCCS;
151     nfc_init_params.stcTimingReg2.u32TWTR = NAND_TWTR;
152     nfc_init_params.stcTimingReg2.u32TRTW = NAND_TRTW;
153     nfc_init_params.stcTimingReg2.u32TADL = NAND_TADL;
154     if (LL_OK == EXMC_NFC_Init(&nfc_init_params))
155     {
156         /* Reset NFC device. */
157         if (LL_OK == EXMC_NFC_Reset(hw_nand->nfc_bank, NAND_RESET_TIMEOUT))
158         {
159             EXMC_NFC_ReadId(hw_nand->nfc_bank, 0UL, au8DevId, sizeof(au8DevId), NAND_READ_TIMEOUT);
160             hw_nand->id = (((rt_uint32_t)au8DevId[3]) << 24 | ((rt_uint32_t)au8DevId[2]) << 16 | \
161                            ((rt_uint32_t)au8DevId[1]) << 8  | (rt_uint32_t)au8DevId[0]);
162 
163             LOG_D("Nand Flash ID = 0x%02X,0x%02X,0x%02X,0x%02X",
164                   au8DevId[0], au8DevId[1], au8DevId[2], au8DevId[3]);
165 
166             ret = RT_EOK;
167         }
168     }
169 
170     return ret;
171 }
172 
_nand_wait_ready(rt_uint32_t nfc_bank,rt_uint32_t timeout)173 static rt_err_t _nand_wait_ready(rt_uint32_t nfc_bank, rt_uint32_t timeout)
174 {
175     rt_err_t ret = RT_EOK;
176     rt_uint32_t to = 0UL;
177     rt_uint32_t status = 0UL;
178 
179     do
180     {
181         /* Block checking flag if timeout value is NAND_WRITE_TIMEOUT */
182         if (to++ > timeout)
183         {
184             ret = -RT_ETIMEOUT;
185             LOG_E("get nand status timeout!");
186             break;
187         }
188 
189         status = EXMC_NFC_ReadStatus(nfc_bank);
190     }
191     while (0UL == (status & NAND_READY));
192 
193     if (RT_ETIMEOUT != ret)
194     {
195         if (0UL != (status & NAND_FAIL))
196         {
197             ret = -RT_ERROR;
198             LOG_E("nand status error!");
199         }
200     }
201 
202     return ret;
203 }
204 
_nand_erase_block(struct rt_mtd_nand_device * device,rt_uint32_t block)205 rt_err_t _nand_erase_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
206 {
207     rt_err_t ret = -RT_ERROR;
208     rt_uint32_t block_num;
209     struct rthw_nand *hw_nand = (struct rthw_nand *)device;
210 
211     RT_ASSERT(device != RT_NULL);
212 
213     block = block + device->block_start;
214     block_num = block << 6;
215 
216     rt_mutex_take(&hw_nand->lock, RT_WAITING_FOREVER);
217 
218     if (LL_OK == EXMC_NFC_EraseBlock(hw_nand->nfc_bank,  block_num, NAND_ERASE_TIMEOUT))
219     {
220         if (_nand_wait_ready(hw_nand->nfc_bank, NAND_ERASE_TIMEOUT) == RT_EOK)
221         {
222             ret = RT_MTD_EOK;
223         }
224     }
225 
226     rt_mutex_release(&hw_nand->lock);
227 
228     return ret;
229 }
230 
_nand_check_block(struct rt_mtd_nand_device * device,rt_uint32_t block)231 static rt_err_t _nand_check_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
232 {
233     RT_ASSERT(device != RT_NULL);
234     return (RT_MTD_EOK);
235 }
236 
_nand_mark_badblock(struct rt_mtd_nand_device * device,rt_uint32_t block)237 static rt_err_t _nand_mark_badblock(struct rt_mtd_nand_device *device, rt_uint32_t block)
238 {
239     RT_ASSERT(device != RT_NULL);
240     return (RT_MTD_EOK);
241 }
242 
243 /* read nand flash id */
_nand_read_id(struct rt_mtd_nand_device * device)244 static rt_err_t _nand_read_id(struct rt_mtd_nand_device *device)
245 {
246     rt_uint8_t device_id[4];
247     struct rthw_nand *hw_nand = (struct rthw_nand *)device;
248 
249     RT_ASSERT(device != RT_NULL);
250 
251     EXMC_NFC_ReadId(hw_nand->nfc_bank, 0UL, device_id, sizeof(device_id), NAND_READ_TIMEOUT);
252     hw_nand->id = (((rt_uint32_t)device_id[3]) << 24 | ((rt_uint32_t)device_id[2]) << 16 | \
253                    ((rt_uint32_t)device_id[1]) << 8  | (rt_uint32_t)device_id[0]);
254 
255     LOG_D("Nand Flash ID: Manufacturer ID = 0x%02X, Device ID=[0x%02X,0x%02X,0x%02X]",
256           device_id[0], device_id[1], device_id[2], device_id[3]);
257 
258     return RT_EOK;
259 }
260 
_nand_read_page(struct rt_mtd_nand_device * device,rt_off_t page,rt_uint8_t * data,rt_uint32_t data_len,rt_uint8_t * spare,rt_uint32_t spare_len)261 static rt_err_t _nand_read_page(struct rt_mtd_nand_device *device,
262                                 rt_off_t page,
263                                 rt_uint8_t *data,
264                                 rt_uint32_t data_len,
265                                 rt_uint8_t *spare,
266                                 rt_uint32_t spare_len)
267 {
268     rt_err_t result = RT_EOK;
269     stc_exmc_nfc_column_t stcColumn;
270     struct rthw_nand *hw_nand = (struct rthw_nand *)device;
271 
272     RT_ASSERT(device != RT_NULL);
273 
274     page = page + device->block_start * device->pages_per_block;
275     if (page / device->pages_per_block > device->block_end)
276     {
277         return -RT_EIO;
278     }
279 
280     rt_mutex_take(&hw_nand->lock, RT_WAITING_FOREVER);
281 
282     if ((data != RT_NULL) && (data_len != 0UL))
283     {
284         /* not an integer multiple of NAND ECC SECTOR SIZE, no ECC checks */
285         if ((data_len % NAND_ECC_SECTOR_SIZE) != 0UL)
286         {
287             if (LL_OK != EXMC_NFC_ReadPageMeta(hw_nand->nfc_bank, page, data, data_len, NAND_READ_TIMEOUT))
288             {
289                 result = -RT_EIO;
290                 goto _exit;
291             }
292         }
293         else
294         {
295             if (LL_OK != EXMC_NFC_ReadPageHwEcc(hw_nand->nfc_bank, page, data, data_len, NAND_READ_TIMEOUT))
296             {
297                 result = -RT_EIO;
298                 goto _exit;
299             }
300             else
301             {
302                 if (SET == EXMC_NFC_GetStatus(EXMC_NFC_FLAG_ECC_UNCORRECTABLE_ERR))
303                 {
304                     EXMC_NFC_ClearStatus(EXMC_NFC_FLAG_ECC_UNCORRECTABLE_ERR);
305                     result = RT_MTD_EECC;
306                     goto _exit;
307                 }
308             }
309         }
310     }
311 
312     if ((spare != RT_NULL) && (spare_len != 0UL))
313     {
314         RT_ASSERT(spare_len <= device->oob_free);
315 
316         stcColumn.u32Bank = hw_nand->nfc_bank;
317         stcColumn.u32Page = page;
318         stcColumn.u32Column = (rt_uint32_t)device->page_size;
319         if (LL_OK != EXMC_NFC_Read(&stcColumn, (rt_uint32_t *)spare,
320                                    (spare_len >> 2), DISABLE, NAND_READ_TIMEOUT))
321         {
322             result = -RT_EIO;
323             goto _exit;
324         }
325     }
326 
327 _exit:
328     rt_mutex_release(&hw_nand->lock);
329 
330     return result;
331 }
332 
_nand_write_page(struct rt_mtd_nand_device * device,rt_off_t page,const rt_uint8_t * data,rt_uint32_t data_len,const rt_uint8_t * spare,rt_uint32_t spare_len)333 static rt_err_t _nand_write_page(struct rt_mtd_nand_device *device,
334                                  rt_off_t page,
335                                  const rt_uint8_t *data,
336                                  rt_uint32_t data_len,
337                                  const rt_uint8_t *spare,
338                                  rt_uint32_t spare_len)
339 {
340     rt_err_t result = RT_EOK;
341     stc_exmc_nfc_column_t stcColumn;
342     struct rthw_nand *hw_nand = (struct rthw_nand *)device;
343 
344     RT_ASSERT(device != RT_NULL);
345 
346     page = page + device->block_start * device->pages_per_block;
347     if (page / device->pages_per_block > device->block_end)
348     {
349         return -RT_EIO;
350     }
351 
352     rt_mutex_take(&hw_nand->lock, RT_WAITING_FOREVER);
353 
354     if ((data != RT_NULL) && (data_len != 0UL))
355     {
356         if ((data_len % NAND_ECC_SECTOR_SIZE) != 0UL)
357         {
358             if (LL_OK != EXMC_NFC_WritePageMeta(hw_nand->nfc_bank, page, data, data_len, NAND_WRITE_TIMEOUT))
359             {
360                 result = -RT_EIO;
361                 goto _exit;
362             }
363         }
364         else
365         {
366             if (LL_OK != EXMC_NFC_WritePageHwEcc(hw_nand->nfc_bank, page, data, data_len, NAND_WRITE_TIMEOUT))
367             {
368                 result = -RT_EIO;
369                 goto _exit;
370             }
371         }
372 
373         if (RT_EOK != _nand_wait_ready(hw_nand->nfc_bank, NAND_WRITE_TIMEOUT))
374         {
375             result = -RT_EIO;
376             goto _exit;
377         }
378     }
379 
380     if ((spare != RT_NULL) && (spare_len != 0UL))
381     {
382         RT_ASSERT(spare_len <= device->oob_free);
383 
384         stcColumn.u32Bank = hw_nand->nfc_bank;
385         stcColumn.u32Page = page;
386         stcColumn.u32Column = (rt_uint32_t)device->page_size;
387         if (LL_OK != EXMC_NFC_Write(&stcColumn, (rt_uint32_t *)spare,
388                                     (spare_len >> 2), DISABLE, NAND_WRITE_TIMEOUT))
389         {
390             result = -RT_EIO;
391             goto _exit;
392         }
393 
394         if (RT_EOK != _nand_wait_ready(hw_nand->nfc_bank, NAND_WRITE_TIMEOUT))
395         {
396             result = -RT_EIO;
397             goto _exit;
398         }
399     }
400 
401 _exit:
402     rt_mutex_release(&hw_nand->lock);
403 
404     return result;
405 }
406 
_nand_move_page(struct rt_mtd_nand_device * device,rt_off_t src_page,rt_off_t dst_page)407 rt_err_t _nand_move_page(struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page)
408 {
409     RT_ASSERT(device != RT_NULL);
410     return (RT_MTD_EOK);
411 }
412 
413 static const struct rt_mtd_nand_driver_ops _ops =
414 {
415     _nand_read_id,
416     _nand_read_page,
417     _nand_write_page,
418     _nand_move_page,
419     _nand_erase_block,
420     _nand_check_block,
421     _nand_mark_badblock,
422 };
423 
rt_hw_nand_init(void)424 int rt_hw_nand_init(void)
425 {
426     rt_err_t result = RT_EOK;
427     struct rt_mtd_nand_device *nand_dev = &_hw_nand.nand_dev;
428 
429     result = _nand_init(nand_dev);
430     if (result != RT_EOK)
431     {
432         LOG_D("nand flash init error!");
433         return -RT_ERROR;
434     }
435     rt_mutex_init(&_hw_nand.lock, "nand", RT_IPC_FLAG_PRIO);
436 
437     nand_dev->page_size       = NAND_BYTES_PER_PAGE;
438     nand_dev->pages_per_block = NAND_PAGES_PER_BLOCK;
439     nand_dev->plane_num       = NAND_PLANE_PER_DEVICE;
440     nand_dev->oob_size        = NAND_SPARE_AREA_SIZE;
441     nand_dev->oob_free        = (rt_uint16_t)(NAND_SPARE_AREA_SIZE - (NAND_BYTES_PER_PAGE / NAND_ECC_SECTOR_SIZE) * NAND_ECC_CODE_SIZE);
442     nand_dev->block_total     = NAND_DEVICE_BLOCKS;
443     nand_dev->block_start     = 0;
444     nand_dev->block_end       = nand_dev->block_total - 1UL;
445     nand_dev->ops = &_ops;
446 
447     result = rt_mtd_nand_register_device("nand", nand_dev);
448     if (result != RT_EOK)
449     {
450         rt_device_unregister(&nand_dev->parent);
451         return -RT_ERROR;
452     }
453 
454     return RT_EOK;
455 }
456 INIT_BOARD_EXPORT(rt_hw_nand_init);
457 
458 #ifdef DRV_DEBUG
459 #ifdef FINSH_USING_MSH
_nand_test(void)460 static int _nand_test(void)
461 {
462     rt_err_t ret;
463     rt_uint32_t i = 0;
464     rt_uint32_t err_count = 0;
465     rt_uint32_t page;
466     rt_uint32_t block;
467 
468     rt_uint8_t *page_rbuf;
469     rt_uint8_t *page_wbuf;
470     rt_uint8_t *page_oob_free_wbuf;
471     rt_uint8_t *page_oob_free_rbuf;
472 
473     static rt_device_t nand;
474     static struct rt_mtd_nand_device *mtd_nand;
475 
476     nand = rt_device_find("nand");
477     if (RT_NULL == nand)
478     {
479         LOG_E("nand device not found");
480         return -RT_ERROR;
481     }
482 
483     ret = rt_device_open(nand, RT_DEVICE_FLAG_RDWR);
484     if (ret != RT_EOK)
485     {
486         LOG_E("nand device failed to open");
487         return -RT_ERROR;
488     }
489 
490     mtd_nand = (struct rt_mtd_nand_device *)nand;
491 
492     page_rbuf = rt_malloc(mtd_nand->page_size);
493     if (page_rbuf == RT_NULL)
494     {
495         LOG_E("out of memory!");
496         return -RT_ERROR;
497     }
498 
499     page_wbuf = rt_malloc(mtd_nand->page_size);
500     if (page_wbuf == RT_NULL)
501     {
502         rt_free(page_rbuf);
503         LOG_E("out of memory!");
504         return -RT_ERROR;
505     }
506 
507     page_oob_free_rbuf = rt_malloc(mtd_nand->oob_free);
508     if (page_oob_free_rbuf == RT_NULL)
509     {
510         rt_free(page_rbuf);
511         rt_free(page_wbuf);
512         LOG_E("out of memory!");
513         return -RT_ERROR;
514     }
515 
516     page_oob_free_wbuf = rt_malloc(mtd_nand->oob_free);
517     if (page_oob_free_wbuf == RT_NULL)
518     {
519         rt_free(page_rbuf);
520         rt_free(page_wbuf);
521         rt_free(page_oob_free_rbuf);
522         LOG_E("out of memory!");
523         return -RT_ERROR;
524     }
525 
526     /* Fill the buffer to send */
527     for (i = 0; i < mtd_nand->page_size; i++)
528     {
529         page_wbuf[i] = i;
530     }
531 
532     for (i = 0; i < mtd_nand->oob_free; i++)
533     {
534         page_oob_free_wbuf[i] = i;
535     }
536 
537     /* read ID */
538     _nand_read_id(mtd_nand);
539 
540     /* test page */
541     page = 0UL;
542 
543     /* erase the NAND Block */
544     block = page >> 6;
545     ret = _nand_erase_block(mtd_nand, block);
546     if (ret == RT_EOK)
547     {
548         LOG_D("erase block%d: ok", block);
549     }
550     else
551     {
552         LOG_E("erase block%d: error", block);
553         err_count++;
554     }
555 
556     /* Write data to NAND memory page 0 */
557     ret = _nand_write_page(mtd_nand, page, page_wbuf, mtd_nand->page_size, page_oob_free_wbuf, mtd_nand->oob_free);
558     if (ret == RT_EOK)
559     {
560         LOG_D("_nand_write_page page%d(include oob free area): ok", page);
561     }
562     else
563     {
564         LOG_E("_nand_write_page page%d(include oob free area): error", page);
565         err_count++;
566     }
567 
568     /* Read data from NAND memory page 0 */
569     ret = _nand_read_page(mtd_nand, page, page_rbuf, mtd_nand->page_size, page_oob_free_rbuf, mtd_nand->oob_free);
570     if (ret == RT_EOK)
571     {
572         LOG_D("_nand_read_page page%d(include oob free area): ok", page);
573     }
574     else if (ret == -RT_MTD_EECC)
575     {
576         LOG_E("_nand_read_page page%d(include oob free area): ECC error", page);
577         err_count++;
578     }
579     else
580     {
581         LOG_E("_nand_read_page page%d(include oob free area): error", page);
582         err_count++;
583     }
584 
585     if (rt_memcmp(page_rbuf, page_wbuf, mtd_nand->page_size) == 0)
586     {
587         LOG_D("rt_memcmp page%d data consistency: ok", page);
588     }
589     else
590     {
591         LOG_E("rt_memcmp page%d data consistency: error", page);
592         err_count++;
593     }
594 
595     if (rt_memcmp(page_oob_free_rbuf, page_oob_free_wbuf, mtd_nand->oob_free) == 0)
596     {
597         LOG_D("rt_memcmp page%d oob_free data consistency: ok", page);
598     }
599     else
600     {
601         LOG_E("rt_memcmp page%d oob_free data consistency: error", page);
602         err_count++;
603     }
604 
605     ret = rt_device_close(nand);
606     if (ret != RT_EOK)
607     {
608         LOG_E("nand device failed to close");
609         err_count++;
610     }
611 
612     rt_free(page_rbuf);
613     rt_free(page_wbuf);
614     rt_free(page_oob_free_rbuf);
615     rt_free(page_oob_free_wbuf);
616 
617     return (err_count == 0UL) ? RT_EOK : -RT_ERROR;
618 }
619 MSH_CMD_EXPORT(_nand_test, nand test)
620 #endif /* FINSH_USING_MSH */
621 #endif /* DRV_DEBUG */
622 
623 #endif /* BSP_USING_NAND */
624 #endif /* BSP_USING_EXMC */
625