- NAND Block의 상태종류
- 1st block : Chip Vendor는 1st Block은 Bad Block이 되지 않게 유지해줌
- Factory-Default bad blocks: Chip Vendor는 Block 의 1st or 2nd Page의 OOB 정보표시
- Worn-out bad blocks : NAND 를 Erase or Write할 경우 BAD Block이 발생한 경우
- Good blocks : 현재 좋은 상태의 Block
- Factory-Default Bad Block
다를 수 있으므로 Datasheet를 참고 해야한다.
- Samsung 인경우,
각 Block의 1st or 2nd page의 6th OOB의 값이 0xFF 아닐 경우, BAD
이 정보는 Large page or Small page, bus width 에 따라 달라질 수 있다.
(Chip vendor 정보 반드시 참고)
아래 link에 macronix를 정보를 소개.
이 정보를 BBI ( Bad block indication ) 라고도 호칭하기도 한다.
- 1st Block
약 1000 write 까지보증한다고 한다, 이부분도 각각의 Datasheet를 참고를 해야겠다.
하지만, 보통 1st Block에서 문제생기는 일은 거의 없기에 구지 자세히 알필요까지는 없을 것 같다.
- Worn-out bad blocks
사용도중 Program or Erase 도중 fail 이나서 STATUS를 읽어서 ERROR 읽어 경우도
Bad block으로 처리한다.
1.2 NAND의 Bad Block 숙지사항
UBOOT기준으로 설명을 하면, 이전 Version에는 아래의 사이트 처럼 U-Boot 에서
Bad Block을 만들어주는 Command가 존재했지만, 최신 Version으로 가면 없어진다.
NAND처리는 지속적으로 변화고 있으며, 본인의 BSP 를 비롯하여, U-BOOT, Kernel의
MTD관련부분을 어느정도 정확하게 알아야 동작원리를 알아야 겠다.
기본적인 BBT(Bad Block Table) 원리와 BBM(Bad Block Management) 부분을 정확하게
알아야 나중에 에러가 발생을 하여도 문제진단이 빠를 것 같다.
- U-BOOT의 NAND관련 Command (오래된 Version)
- U-BOOT의 NAND관련 Command
https://www.denx.de/wiki/DULG/UBootCmdGroupNand
1.3 BSP의 NAND의 구성
- AM35x-OMAP35x 관련 내용
http://processors.wiki.ti.com/index.php/AM35x-OMAP35x-PSP_04.02.00.07_UserGuide
- i.M28과 BBT와 BBI설명
2K page 64 OOB 구성을 512+16 매번 쪼깨서 사용하며, 이것은 정말 신선하게 느껴졌다.
매번 느끼는 것이지만, Bad block 의 관리와 NAND관리는 MPU와도 밀접한 것 같다.
Freescale-i.MX28-MCIMX281AVM4B-Learning Centre MCU-Application Notes-Freescale.Application_Notes_5.pdf
https://www.element14.com/community/docs/DOC-31589/l/freescale-application-note-for-nand-flash-bad-block-management-for-linux-bsp
2. Linux의 NAND BBM(Bad Block Management)
2.1 Bad Block Table 생성
Bad Block Table은 2bit 정보로 각 Block을 관리하며, 보통은 BBT은 2개의 Block을 사용을 하며, 하나는 Back-up용으로 생각하면 된다.
MPU-Nand Driver에서 static struct nand_bbt_descr을 선언하여 사용.
기본적 Last 2 Block or 1st Block을 사용하며, 아래와 같은 가지고 사용을 한다.
Nand에서 사용하는 BBT
* The table uses 2 bits per block
* 11b: block is good
* 00b: block is factory marked bad
* 01b, 10b: block is marked bad due to wear
Memory에서 사용하는 임시 BBT
* The memory bad block table uses the following scheme:
* 00b: block is good
* 01b: block is marked bad due to wear
* 10b: block is reserved (to protect the bbt area)
* 11b: block is factory marked bad
Bad block table
http://www.linux-mtd.infradead.org/tech/mtdnand/x144.html
- BBT의 생성되는 Flowchart
Factory-Default bad block 정보이용하여 Bad block Table에 만드는 방법
현재 Linux BBT 역시 이와 같은 방식으로 동작하지만, 옵션에 따라 미세하게 다르게 동작.
http://bbs.ednchina.com/FORUM_POST_17_89328_0.HTM |
http://www.macronix.com/Lists/ApplicationNote/Attachments/729/AN0278V1%20-%20BB%20information%20introduction.pdf
https://www.micron.com/resource-details/8e059ff2-fb4f-4e05-974c-e205226d2318
Uboot 와 Kernel은 NAND를 사용시에는 BBT를 사용하며, 이에 관련된 부분을 알아보자.
http://lxr.free-electrons.com/source/drivers/mtd/nand/Makefile
nand-objs := nand_base.o nand_bbt.o nand_timings.o
http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_bbt.c
nand_scan_bbt
Search
-> check_create
-> mark_bbt_region
->nand_update_bbt
* check_create
read_abs_bbt
read_bbt
http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_base.c
/* Fill in remaining MTD driver data */
mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
MTD_CAP_NANDFLASH;
mtd->_erase = nand_erase;
mtd->_point = NULL;
mtd->_unpoint = NULL;
mtd->_read = nand_read;
mtd->_write = nand_write;
mtd->_panic_write = panic_nand_write;
mtd->_read_oob = nand_read_oob;
mtd->_write_oob = nand_write_oob;
mtd->_sync = nand_sync;
mtd->_lock = NULL;
mtd->_unlock = NULL;
mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume;
mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad;
mtd->writebufsize = mtd->writesize;
nand_block_markbad
-> nand_block_markbad_lowlevel
-> nand_markbad_bbt
http://lxr.free-electrons.com/source/drivers/mtd/mtdcore.c
mtd_block_isbad
-> mtd->_block_isbad
mtd_block_markbad
-> mtd->_block_markbad
http://lxr.free-electrons.com/source/drivers/mtd/nand/davinci_nand.c
https://www.micron.com/resource-details/8e059ff2-fb4f-4e05-974c-e205226d2318
3. U-BOOT 와 Kernel BBT 분석
Uboot 와 Kernel은 NAND를 사용시에는 BBT를 사용하며, 이에 관련된 부분을 알아보자.
- U-BOOT
$ vi ./drivers/mtd/nand/davinci_nand.c void davinci_nand_init(struct nand_chip *nand) { nand->chip_delay = 0; #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT nand->bbt_options |= NAND_BBT_USE_FLASH; #endif #ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE nand->options |= NAND_NO_SUBPAGE_WRITE; #endif #ifdef CONFIG_SYS_NAND_HW_ECC nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = 512; nand->ecc.bytes = 3; nand->ecc.strength = 1; nand->ecc.calculate = nand_davinci_calculate_ecc; nand->ecc.correct = nand_davinci_correct_data; nand->ecc.hwctl = nand_davinci_enable_hwecc; #else nand->ecc.mode = NAND_ECC_SOFT; #endif /* CONFIG_SYS_NAND_HW_ECC */ #ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; nand->ecc.size = 512; nand->ecc.bytes = 10; nand->ecc.strength = 4; nand->ecc.calculate = nand_davinci_4bit_calculate_ecc; nand->ecc.correct = nand_davinci_4bit_correct_data; nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc; nand->ecc.layout = &nand_davinci_4bit_layout_oobfirst; #endif $ vi ./drivers/mtd/nand/nand_bbt.c nand_default_bbt -> 1.bbt_main_descr,bbt_mirror_descr //NAND_BBT_USE_FLASH 때문에 default BBT옵션설정 -> 2.nand_scan_bbt -> check_create -> create_bbt -> scan_block_full or scan_block_fast $ vi ./include/linux/mtd/bbm.h // BBT 관련옵션 확인
- bbt_md(bbt_mirror_descr) or bbt_td(bbt_main_descr) 설정분석
- NAND_BBT_LASTBLOCK : NAND 마지막 Block BBT 존재여부 확인
- NAND_BBT_CREATE : NAND BBT가 없다면 생성
- NAND_BBT_WRITE : NAND BBT에 WRITE 가능
- NAND_BBT_2BIT : 각 Bblock 당 정보를 2bit식 할당
- NAND_BBT_VERSION : BBT Version 정보 표시
- NAND_BBT_PERCHIP : NAND Chip 마다 BBT 생성
$ vi ./drivers/mtd/nand/nand_bbt.c /* Generic flash bbt descriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; static struct nand_bbt_descr bbt_main_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, .offs = 8, //offset of the pattern in the oob area of the page .len = 4, //length of the pattern .veroffs = 12, //offset of the bbt version counter in the oob are of the page .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, //maximum number of blocks to search for a bbt .pattern = bbt_pattern //pattern to identify bad block table or factory marked }; static struct nand_bbt_descr bbt_mirror_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, .offs = 8, .len = 4, .veroffs = 12, .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = mirror_pattern }; static struct nand_bbt_descr bbt_main_no_oob_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB, .len = 4, .veroffs = 4, .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = bbt_pattern }; static struct nand_bbt_descr bbt_mirror_no_oob_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB, .len = 4, .veroffs = 4, .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = mirror_pattern };
- Kernel Source
http://lxr.free-electrons.com/source/drivers/mtd/nand/Makefile
nand-objs := nand_base.o nand_bbt.o nand_timings.o
http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_bbt.c
- drivers/mtd/nand/nand_bbt.c
nand_scan_bbt
Search
-> check_create
-> mark_bbt_region
->nand_update_bbt
* check_create
read_abs_bbt
read_bbt
http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_base.c
- drivers/mtd/nand/nand_base.c
/* Fill in remaining MTD driver data */
mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
MTD_CAP_NANDFLASH;
mtd->_erase = nand_erase;
mtd->_point = NULL;
mtd->_unpoint = NULL;
mtd->_read = nand_read;
mtd->_write = nand_write;
mtd->_panic_write = panic_nand_write;
mtd->_read_oob = nand_read_oob;
mtd->_write_oob = nand_write_oob;
mtd->_sync = nand_sync;
mtd->_lock = NULL;
mtd->_unlock = NULL;
mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume;
mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad;
mtd->writebufsize = mtd->writesize;
nand_block_markbad
-> nand_block_markbad_lowlevel
-> nand_markbad_bbt
http://lxr.free-electrons.com/source/drivers/mtd/mtdcore.c
- drivers/mtd/mtdcore.c
mtd_block_isbad
-> mtd->_block_isbad
mtd_block_markbad
-> mtd->_block_markbad
http://lxr.free-electrons.com/source/drivers/mtd/nand/davinci_nand.c