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