drv_nand.c 18 KB

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