drv_nand.c 18 KB

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