<kernel v4.14>
NAND 디바이스 트리
NAND 호스트 컨트롤러 관련 기본 속성들
- compatible
- 드라이버 compatiblity 문자열
- 예) “brcm,brcmnand-v6.1”
- reg
- 첫 번째 기재된 주소는 NAND 레지스터 시작 물리 주소
- 그외 옵션
- DMA를 사용하는 경우 Flash DMA 레지스터 시작 물리 주소
- NAND 캐시를 사용하는 경우 캐시 레지스터 시작 물리 주소
- reg-names
- 위의 주어진 레지스터를 설명하는 문자열
- 예) “nand”, “flash-dma”, nand-cache”
- interrupts
- NAND 컨트롤러와 연결될 인터럽트 컨트롤러와 인터럽트 번호
- interrupt-names
- 위의 인터럽트를 설명하는 문자열
- 예) “nand-ctlrdy”, “flash_dma_done” 등
- interrupt-parent
- #address-cells
- #size-cells
NAND 칩 관련 서브 노드 속성들
- compatible
- reg
- #address-calls
- 하위 노드인 파티션 노드의 주소 표현에 필요한 4바이트 수
- 1 = 32bit 주소(4 바이트)
- 2 = 64bit 주소(8 바이트)
- #size-cells
- 하위 노드인 파티션 노드의 사이즈 표현에 필요한 4바이트 수
- 1 = 32bit 주소(4 바이트)
- 2 = 64bit 주소(8 바이트)
- nand-on-flash-bbt
- NAND에 BBT(Bad Block Table)를 지원하는지 여부
- nand-ecc-mode
- NAND ECC 모드 문자열로 다음과 같다.
- “none”
- “soft”
- 부트로더 또는 커널 드라이버 software가 관리
- “hw”
- “hw_syndrome”
- sunxi 사의 sun7i에 탑재된 nand 호스트 컨트롤러에서 관리
- “hw_oob_first”
- “on-die”
- 퓨젼 NAND 칩에 내장된 ECC 컨트롤러가 관리
- “soft_bch”
- nand-ecc-algo
- NAND ECC 알고리즘 문자열로 다음과 같다.
- nand-bus-width
- nand-ecc-strength
- ECC 한 스텝당 correction 가능한 비트 수
- 1, 5, 6, 8, 10, 12, 14, 16, …
- nand-ecc-step-size
- nand-ecc-maximize
- ECC strength를 최대치로 사용할지의 여부
- “true” or “false”
파티션 관련 서브 노드 속성들
옵션 속성들
Broadcom
Case 1)
nand@f0442800 {
compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand";
reg = <0xF0442800 0x600>,
<0xF0443000 0x100>;
reg-names = "nand", "flash-dma";
interrupt-parent = <&hif_intr2_intc>;
interrupts = <24>, <4>;
#address-cells = <1>;
#size-cells = <0>;
nandcs@1 {
compatible = "brcm,nandcs";
reg = <1>; // Chip select 1
nand-on-flash-bbt;
nand-ecc-strength = <12>;
nand-ecc-step-size = <512>;
// Partitions
#address-cells = <1>; // <2>, for 64-bit offset
#size-cells = <1>; // <2>, for 64-bit length
flash0.rootfs@0 {
reg = <0 0x10000000>;
};
flash0@0 {
reg = <0 0>; // MTDPART_SIZ_FULL
};
flash0.kernel@10000000 {
reg = <0x10000000 0x400000>;
};
};
};
- BBT가 지원되며, 512바이트 당 12bit의 ECC(BCH-12)
Case 2)
nand@10000200 {
compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368",
"brcm,brcmnand-v4.0", "brcm,brcmnand";
reg = <0x10000200 0x180>,
<0x10000600 0x200>,
<0x100000b0 0x10>;
reg-names = "nand", "nand-cache", "nand-int-base";
interrupt-parent = <&periph_intc>;
interrupts = <50>;
clocks = <&periph_clk 20>;
clock-names = "nand";
#address-cells = <1>;
#size-cells = <0>;
nand0: nandcs@0 {
compatible = "brcm,nandcs";
reg = <0>;
nand-on-flash-bbt;
nand-ecc-strength = <1>;
nand-ecc-step-size = <512>;
};
};
- brcm,nand-oob-sector-size
- BBT가 지원되며, 512바이트 당 1bit의 ECC
파티션
부팅 시 표현되는 mtd 정보
다음 두 가지의 디바이스가 탑재된 사례이다.
- Micron NAND 플래시: MT29F16G08ABABAWP
- Micron NOR 플래시: m25p80
nand: device found, Manufacturer ID: 0x2c, Chip ID: 0x48
nand: Micron MT29F16G08ABABAWP
nand: 2048 MiB, SLC, erase size: 512 KiB, page size: 4096, OOB size: 224
iproc_nand 66460000.nand: detected 2048MiB total, 512KiB blocks, 4KiB pages, 27B OOB, 8-bit, BCH-8
Scanning device for bad blocks
random: nonblocking pool is initialized
6 ofpart partitions found on MTD device brcmnand.0
Creating 6 MTD partitions on "brcmnand.0":
0x000000000000-0x000000700000 : "nboot"
0x000000700000-0x000000800000 : "nenv"
0x000000800000-0x000001000000 : "bootconf"
0x000001000000-0x000011000000 : "os1"
0x000011000000-0x000021000000 : "os2"
0x000021000000-0x00003f000000 : "ndata"
bcmspi_setup:628 cru_control 0x6010000
m25p80 spi1.0: n25q256a (32768 Kbytes)
4 ofpart partitions found on MTD device spi1.0
Creating 4 MTD partitions on "spi1.0":
0x000000000000-0x0000001d0000 : "bootloader"
0x0000001d0000-0x0000001f0000 : "env"
0x000000200000-0x000002000000 : "reserved"
0x000001000000-0x000002000000 : "data"
proc 인터페이스
다음과 같이 구성되어 있다.
# cat /proc/mtd
dev: size erasesize name
mtd0: 00700000 00080000 "nboot"
mtd1: 00100000 00080000 "nenv"
mtd2: 00800000 00080000 "bootconf"
mtd3: 10000000 00080000 "os1"
mtd4: 10000000 00080000 "os2"
mtd5: 1e000000 00080000 "ndata"
mtd6: 001d0000 00001000 "bootloader"
mtd7: 00020000 00001000 "env"
mtd8: 01e00000 00001000 "reserved"
mtd9: 01000000 00001000 "data"
device 파일
아래와 같이 디바이스 파일들이 생성된다.
# ls /dev/mtd?
mtd0 mtd1 mtd2 mtd3 mtd4 mtd5 mtd6 mtd7 mtd8 mtd9
# ls /dev/mtd?ro
mtd0ro mtd1ro mtd2ro mtd3ro mtd4ro mtd5ro mtd6ro mtd7ro mtd8ro mtd9ro
# ls /dev/mtdblock*
mtdblock0 mtdblock1 mtdblock10 mtdblock2 mtdblock3 mtdblock4 mtdblock5 mtdblock6 mtdblock7 mtdblock8 mtdblock9
mtd-utils
파티션 정보 확인
# mtdinfo
Count of MTD devices: 10
Present MTD devices: mtd0, mtd1, mtd2, mtd3, mtd4, mtd5, mtd6, mtd7, mtd8, mtd9
Sysfs interface supported: yes
- -a 옵션을 사용하는 경우 전체 파티션에 대한 세부 정보를 볼 수 있다.
특정 파티션에 대한 세부 정보를 보려면 다음과 같이한다.
# mtdinfo /dev/mtd0
mtd0
Name: nboot
Type: nand
Eraseblock size: 262144 bytes, 256.0 KiB
Amount of eraseblocks: 28 (7340032 bytes, 7.0 MiB)
Minimum input/output unit size: 4096 bytes
Sub-page size: 4096 bytes
OOB size: 216 bytes
Character device major/minor: 90:0
Bad blocks are allowed: true
Device is writable: false
nanddump
# nanddump
Usage: nanddump [OPTIONS] MTD-device
Dumps the contents of a nand mtd partition.
--help Display this help and exit
--version Output version information and exit
--bb=METHOD Choose bad block handling method (see below).
-a --forcebinary Force printing of binary data to tty
-c --canonicalprint Print canonical Hex+ASCII dump
-f file --file=file Dump to file
-l length --length=length Length
-n --noecc Read without error correction
--omitoob Omit OOB data (default)
-o --oob Dump OOB data
-p --prettyprint Print nice (hexdump)
-q --quiet Don't display progress and status messages
-s addr --startaddress=addr Start address
-b --checkbadblock Check bad blocks from the start of device
--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':
padbad: dump flash data, substituting 0xFF for any bad blocks
dumpbad: dump flash data, including any bad blocks
skipbad: dump good data, completely skipping any bad blocks (default)
nanddump 유틸리티를 사용하여 0번 파티션을 파일로 Backup
- -o 옵션을 사용하는 경우 oob까지 같이 dump
# nanddump /dev/mtd0 -f /tmp/bios.bak
ECC failed: 0
ECC corrected: 0
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 262144, page size 4096, OOB size 216
Dumping data starting at 0x00000000 and ending at 0x00700000...
또는 다음과 같이 dd 명령으로도 백업을 받을 수 있다. 단 nanddump와 달리 배드 블럭이 있는 경우 포함되어 dump된다.
# dd if=/dev/mtd0ro of=bios.bak
16384+0 records in
16384+0 records out
8388608 bytes (8.4 MB) copied, 10.0269 s, 837 kB/s
Verify
0번 파티션과 피일간 비교
sha1sum /dev/mtd0ro bios.bak
fdbb011920572ca6c991377c4b418a0502668b73 /dev/mtd0ro
fdbb011920572ca6c991377c4b418a0502668b73 bios.bak
Erase
0번 파티션 erase
# flash_erase /dev/mtd0 0 0
Erasing 4 Kibyte @ 7ff000 -- 100 % complete
Write
0번 파티션에 파일을 기록
$ sudo nandwrite /dev/mtd0 nand.img
Writing data to block 0 at offset 0x0
Writing data to block 1 at offset 0x4000
Writing data to block 2 at offset 0x8000
Writing data to block 3 at offset 0xc000
...
또는 다음과 같이 dd 명령으로도 백업을 받을 수 있다. 단 nandwrite와 달리 배드 블럭을 무시하고 기록된다.
# dd if=MNW2MAX1.X64.0092.R01.1605221712.bin of=/dev/mtd0
/sys/class/mtd 사용
다음과 같이 mtd 파티션 중 nand 파티션 하나를 골라 출력을 하였다.
# ls /sys/class/mtd/mtd1
bad_blocks dev ecc_strength numeraseregions subpagesize writesize
bbt_blocks device erasesize offset subsystem
bitflip_threshold ecc_failures flags oobsize type
corrected_bits ecc_step_size name size uevent
한 번의 Erase 에 사용되는 바이트 수 (= 1 블럭)
# cat erasesize
262144
한 번의 Write에 사용되는 바이트 수 (= 1 페이지)
# cat writesize
4096
이 파티션 내의 배드 블럭 수
# cat bad_blocks
0
이 파티션 내에 존재하는 bbt 블럭 수
# cat bbt_blocks
0
이 디바이스에서 읽기 동작 시 ECC 에러 발생 수 확인
# cat ecc_failures
0
이 디바이스에서 ECC correction한 비트 수
# cat corrected_bits
0
ECC 스텝이 사용할 바이트 수
# cat ecc_step_size
512
한 번의 ECC 스텝당 coreection 가능한 비트 수
# cat ecc_strength
8
한 번의 ECC 스텝에서 사용할 OOB 사이즈
# cat oobsize
216
그 외 offset 및 size에 시작 위치와 사이즈가 담긴다.
NAND 드라이버
Broadcom iproc-nand driver
drivers/mtd/nand/brcmnand/iproc_nand.c
01 | static const struct of_device_id iproc_nand_of_match[] = { |
02 | { .compatible = "brcm,nand-iproc" }, |
05 | MODULE_DEVICE_TABLE(of, iproc_nand_of_match); |
07 | static struct platform_driver iproc_nand_driver = { |
08 | .probe = iproc_nand_probe, |
09 | . remove = brcmnand_remove, |
12 | .pm = &brcmnand_pm_ops, |
13 | .of_match_table = iproc_nand_of_match, |
16 | module_platform_driver(iproc_nand_driver); |
이 플랫폼 드라이버에서는 Device Tree의 “brcm,nand-iproc” compatible 명으로 등록된 nand 드라이버의 probe 함수인 iproc_nand_probe()을 호출한다.
iproc_nand_probe()
drivers/mtd/nand/brcmnand/iproc_nand.c
01 | static int iproc_nand_probe( struct platform_device *pdev) |
03 | struct device *dev = &pdev->dev; |
04 | struct iproc_nand_soc *priv; |
05 | struct brcmnand_soc *soc; |
08 | priv = devm_kzalloc(dev, sizeof (*priv), GFP_KERNEL); |
13 | spin_lock_init(&priv->idm_lock); |
15 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm" ); |
16 | priv->idm_base = devm_ioremap_resource(dev, res); |
17 | if (IS_ERR(priv->idm_base)) |
18 | return PTR_ERR(priv->idm_base); |
20 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext" ); |
21 | priv->ext_base = devm_ioremap_resource(dev, res); |
22 | if (IS_ERR(priv->ext_base)) |
23 | return PTR_ERR(priv->ext_base); |
25 | soc->ctlrdy_ack = iproc_nand_intc_ack; |
26 | soc->ctlrdy_set_enabled = iproc_nand_intc_set; |
27 | soc->prepare_data_bus = iproc_nand_apb_access; |
29 | return brcmnand_probe(pdev, soc); |
iproc 낸드 드라이버를 probe한다.
- 코드 라인 8~10에서 iproc 낸드 드라이버 정보를 담을 구조체를 할당받는다.
- 코드 라인 15~18에서 플랫폼 리소스에 “iproc-idm” 리소스가 있는 경우 idm 레지스터들 물리 주소 범위를 가상 주소에 매핑한다.
- 예) reg = <0x66460000 0x600>, <0x67015408 0x600>, <0x66460f00 0x20>;
- reg-names = “nand”, “iproc-idm”, “iproc-ext”;
- 코드 라인 20~23에서 플랫폼 리소스에 “iproc-ext” 리소스가 있는 경우 ext 레지스터들 물리 주소 범위를 가상 주소에 매핑한다.
- 코드 라인 25~29에 낸드 인터럽트 처리 및 ARM APB 버스 접근관련 후크 함수를 준비하고 broadcom의 nand probe 함수를 호출한다.
아래 broadcom nand 드라이버 다음 버전들을 지원한다.
01 | static const struct of_device_id brcmnand_of_match[] = { |
02 | { .compatible = "brcm,brcmnand-v4.0" }, |
03 | { .compatible = "brcm,brcmnand-v5.0" }, |
04 | { .compatible = "brcm,brcmnand-v6.0" }, |
05 | { .compatible = "brcm,brcmnand-v6.1" }, |
06 | { .compatible = "brcm,brcmnand-v6.2" }, |
07 | { .compatible = "brcm,brcmnand-v7.0" }, |
08 | { .compatible = "brcm,brcmnand-v7.1" }, |
09 | { .compatible = "brcm,brcmnand-v7.2" }, |
12 | MODULE_DEVICE_TABLE(of, brcmnand_of_match); |
brcmnand_probe()
drivers/mtd/nand/brcmnand/brcmnand.c -1/3-
01 | int brcmnand_probe( struct platform_device *pdev, struct brcmnand_soc *soc) |
03 | struct device *dev = &pdev->dev; |
04 | struct device_node *dn = dev->of_node, *child; |
05 | struct brcmnand_controller *ctrl; |
13 | if (!of_match_node(brcmnand_of_match, dn)) |
16 | ctrl = devm_kzalloc(dev, sizeof (*ctrl), GFP_KERNEL); |
20 | dev_set_drvdata(dev, ctrl); |
23 | init_completion(&ctrl->done); |
24 | init_completion(&ctrl->dma_done); |
25 | nand_hw_control_init(&ctrl->controller); |
26 | INIT_LIST_HEAD(&ctrl->host_list); |
29 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
30 | ctrl->nand_base = devm_ioremap_resource(dev, res); |
31 | if (IS_ERR(ctrl->nand_base)) |
32 | return PTR_ERR(ctrl->nand_base); |
35 | ctrl->clk = devm_clk_get(dev, "nand" ); |
36 | if (!IS_ERR(ctrl->clk)) { |
37 | ret = clk_prepare_enable(ctrl->clk); |
41 | ret = PTR_ERR(ctrl->clk); |
42 | if (ret == -EPROBE_DEFER) |
49 | ret = brcmnand_revision_init(ctrl); |
57 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache" ); |
59 | ctrl->nand_fc = devm_ioremap_resource(dev, res); |
60 | if (IS_ERR(ctrl->nand_fc)) { |
61 | ret = PTR_ERR(ctrl->nand_fc); |
65 | ctrl->nand_fc = ctrl->nand_base + |
66 | ctrl->reg_offsets[BRCMNAND_FC_BASE]; |
broadcom 낸드 드라이버를 probe한다.
- 코드 라인 10~11에서 디바이스 트리 노드가 없는 경우 지원하지 않는다.
- 코드 라인 13~14에서 매치되는 nand 디바이스 버전을 체크한다.
- 코드 라인 16~18에서 broadcom 낸드 컨트롤러 구조체를 할당한다.
- 코드 라인 29~32에서 NAND 레지스터 정보가 담긴 플랫폼 리소스를 얻어와서 가상 주소에 매핑한다.
- 코드 라인 35~46에서 디바이스 트리에 “nand” 클럭 정보가 있는 경우 클럭을 준비하고 없으면 null 인채로 진행한다.
- 코드 라인 49~51에서 broadcom 낸드 컨트롤러 버전에 맞는 정보를 알아온다.
- reg_offsets
- reg_spacing
- cs_offsets
- max_page_size
- 컨트롤러가 처리할 수 있는 최대 페이지 사이즈
- max_block_size
- cs_offsets & cs0_offsets
- max_oob
- 컨트롤러가 처리할 수 있는 최대 OOB 사이즈
- features
- BRCMNAND_HAS_1K_SECTORS
- ECC의 1K 섹터 지원 여부
- v5.0 이상(v6.1은 제외)
- BRCMNAND_HAS_PREFETCH
- prefetch 지원 여부
- v6.0 이상(v6.1은 제외)
- BRCMNAND_HAS_CACHE_MODE
- BRCMNAND_HAS_WP
- write protect 지원 여부
- v7.0 이상 또는 “brcm,nand-has-wp” 속성이 있는 경우
- 코드 라인 57~67에서 디바이스 트리에 “nand-cache”에 대한 레지스터 범위가 있는 경우 이를 가상 주소에 매핑한다.
drivers/mtd/nand/brcmnand/brcmnand.c -2/3-
02 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma" ); |
04 | ctrl->flash_dma_base = devm_ioremap_resource(dev, res); |
05 | if (IS_ERR(ctrl->flash_dma_base)) { |
06 | ret = PTR_ERR(ctrl->flash_dma_base); |
10 | flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); |
11 | flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0); |
14 | ctrl->dma_desc = dmam_alloc_coherent(dev, |
15 | sizeof (*ctrl->dma_desc), |
16 | &ctrl->dma_pa, GFP_KERNEL); |
17 | if (!ctrl->dma_desc) { |
22 | ctrl->dma_irq = platform_get_irq(pdev, 1); |
23 | if (( int )ctrl->dma_irq < 0) { |
24 | dev_err(dev, "missing FLASH_DMA IRQ\n" ); |
29 | ret = devm_request_irq(dev, ctrl->dma_irq, |
30 | brcmnand_dma_irq, 0, DRV_NAME, |
33 | dev_err(dev, "can't allocate IRQ %d: error %d\n" , |
38 | dev_info(dev, "enabling FLASH_DMA\n" ); |
42 | brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, |
43 | CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0); |
45 | brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0); |
47 | if (ctrl->features & BRCMNAND_HAS_WP) { |
50 | brcmnand_set_wp(ctrl, false ); |
56 | ctrl->irq = platform_get_irq(pdev, 0); |
57 | if (( int )ctrl->irq < 0) { |
58 | dev_err(dev, "no IRQ defined\n" ); |
- 코드 라인 2~39에서 디바이스 트리에서 “flash-dma” 속성이 있는 경우 dma를 준비한다. 이 때 dma에 사용할 인터럽트와 핸들러를 준비한다.
- 디바이스 트리에서 인터럽트는 두 번째 항목에 있는 것을 사용한다.
- 코드 라인 42~43에서 기본 설정으로 낸드 칩을 선택하지 않고 disable 상태로 둔다.
- 코드 라인 45에서 XOR 어드레싱을 disable한다.
- 코드 라인 47~53에서 write protect 기능이 있고 모듈 파라메터 “wp_on”의 값이 2인 경우 write protection 처리한다.
- 코드 라인 56~61에서 NAND 컨트롤러에서 사용할 인터럽트를 준비한다.
drivers/mtd/nand/brcmnand/brcmnand.c -3/3-
08 | ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0, |
12 | ctrl->soc->ctlrdy_ack(ctrl->soc); |
13 | ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true ); |
16 | ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0, |
20 | dev_err(dev, "can't allocate IRQ %d: error %d\n" , |
25 | for_each_available_child_of_node(dn, child) { |
26 | if (of_device_is_compatible(child, "brcm,nandcs" )) { |
27 | struct brcmnand_host *host; |
29 | host = devm_kzalloc(dev, sizeof (*host), GFP_KERNEL); |
38 | ret = brcmnand_init_cs(host, child); |
40 | devm_kfree(dev, host); |
44 | list_add_tail(&host->node, &ctrl->host_list); |
49 | if (list_empty(&ctrl->host_list)) { |
57 | clk_disable_unprepare(ctrl->clk); |
61 | EXPORT_SYMBOL_GPL(brcmnand_probe); |
- 코드 라인 5~23에서 broadcom nand driver가 독립된 표준 모드로 동작하거나 iproc과 같이 인터럽트를 enable하기 위해 추가로 후크 함수들을 준비하는 soc 모드 등 두 가지 모드가 있다.
- 표준 모드
- brcmnand_ctlrdy_irq() 인터럽트 핸들러를 사용하도록 준비한다.
- soc 모드
- brcmnand_irq() 인터럽트 핸들러를 사용하도록 준비한다.
- 인터럽트를 enable하기 위해 해당 soc에서 준비한 후크 함수들을 호출한다.
- 코드 라인 25~46에서 nand 노드의 하위 노드에 “brcm,nandcs” compatible 명이 있는 경우 해당 칩셀렉트 번호에 해당하는 NAND 호스트 컨트롤러의 operation과 ecc에 대한 operation 후크 함수들을 준비하고 nand 컨트롤러를 설정한 후 mtd 디바이스로 등록한다.
- 코드 라인 49~54에서 등록된 NAND 호스트 컨트롤러가 없는 경우 함수를 빠져나간다.
brcmnand_init_cs()
drivers/mtd/nand/brcmnand/brcmnand.c -1/2-
01 | static int brcmnand_init_cs( struct brcmnand_host *host, struct device_node *dn) |
03 | struct brcmnand_controller *ctrl = host->ctrl; |
04 | struct platform_device *pdev = host->pdev; |
06 | struct nand_chip *chip; |
10 | ret = of_property_read_u32(dn, "reg" , &host->cs); |
12 | dev_err(&pdev->dev, "can't get chip-select\n" ); |
16 | mtd = nand_to_mtd(&host->chip); |
19 | nand_set_flash_node(chip, dn); |
20 | nand_set_controller_data(chip, host); |
21 | mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d" , |
23 | mtd->owner = THIS_MODULE; |
24 | mtd->dev.parent = &pdev->dev; |
26 | chip->IO_ADDR_R = ( void __iomem *)0xdeadbeef; |
27 | chip->IO_ADDR_W = ( void __iomem *)0xdeadbeef; |
29 | chip->cmd_ctrl = brcmnand_cmd_ctrl; |
30 | chip->cmdfunc = brcmnand_cmdfunc; |
31 | chip->waitfunc = brcmnand_waitfunc; |
32 | chip->read_byte = brcmnand_read_byte; |
33 | chip->read_buf = brcmnand_read_buf; |
34 | chip->write_buf = brcmnand_write_buf; |
36 | chip->ecc.mode = NAND_ECC_HW; |
37 | chip->ecc.read_page = brcmnand_read_page; |
38 | chip->ecc.write_page = brcmnand_write_page; |
39 | chip->ecc.read_page_raw = brcmnand_read_page_raw; |
40 | chip->ecc.write_page_raw = brcmnand_write_page_raw; |
41 | chip->ecc.write_oob_raw = brcmnand_write_oob_raw; |
42 | chip->ecc.read_oob_raw = brcmnand_read_oob_raw; |
43 | chip->ecc.read_oob = brcmnand_read_oob; |
44 | chip->ecc.write_oob = brcmnand_write_oob; |
46 | chip->controller = &ctrl->controller; |
- 코드 라인 10~14에서 nand 노드에서 reg 속성값을 읽어온다.
- 코드 라인 16~46에서 nand chip 드라이버에서 사용할 멤버들을 초기화하고, 호출될 후크 함수들을 준비한다.
drivers/mtd/nand/brcmnand/brcmnand.c -2/2-
06 | cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG); |
07 | nand_writereg(ctrl, cfg_offs, |
08 | nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH); |
10 | ret = nand_scan_ident(mtd, 1, NULL); |
14 | chip->options |= NAND_NO_SUBPAGE_WRITE; |
20 | chip->options |= NAND_USE_BOUNCE_BUFFER; |
22 | if (chip->bbt_options & NAND_BBT_USE_FLASH) |
23 | chip->bbt_options |= NAND_BBT_NO_OOB; |
25 | if (brcmnand_setup_dev(host)) |
28 | chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512; |
30 | mtd->bitflip_threshold = 1; |
32 | ret = brcmstb_choose_ecc_layout(host); |
36 | ret = nand_scan_tail(mtd); |
40 | return mtd_device_register(mtd, NULL, 0); |
- 코드 라인 6~8에서 부트로더에서 16bit 모드로 설정되어 있을 수도 있다. NAND READID 명령은 8bit 모드에서 동작해야 하므로 8비트 모드로 변경한다.
- 코드 라인 10~12에서 nand 디바이스를 스캔하는 1st phase이다.
- 코드 라인 14~26에서 broadcom nand 호스트 컨트롤러를 설정한다.
- 코드 라인 28~34에서 ecc가 저장되는 oob layout을 결정한다.
- 코드 라인 36~38에서 nand 디바이스를 스캔하는 2nd phase이다.
- 코드 라인 40에서 mtd 디바이스로 등록한다.
다음 그림은 broadcom사의 nand_chip 구조체에 설정된 후크함수들을 보여준다.

참고