1 nand flash的操作 目的:讀地址A的數據,把數據B寫到地址A。 問1. 原理圖上NAND FLASH和S3C2440之間只有數據線,怎麼傳輸地址?答1.在DATA0~DATA7上既傳輸數據,又傳輸地址,當ALE為高電平時傳輸的是地址。 問2. 從NAND FLASH晶元手冊可知,要操作N ...
1 nand flash的操作
目的:讀地址A的數據,把數據B寫到地址A。
問1. 原理圖上NAND FLASH和S3C2440之間只有數據線,怎麼傳輸地址?
答1.在DATA0~DATA7上既傳輸數據,又傳輸地址,當ALE為高電平時傳輸的是地址。
問2. 從NAND FLASH晶元手冊可知,要操作NAND FLASH需要先發出命令
怎麼傳入命令?
答2.在DATA0~DATA7上既傳輸數據,又傳輸地址,也傳輸命令
當ALE為高電平時傳輸的是地址,
當CLE為高電平時傳輸的是命令
當ALE和CLE都為低電平時傳輸的是數據
問3. 數據線既接到NAND FLASH,也接到NOR FLASH,還接到SDRAM、DM9000等等,那麼怎麼避免干擾?
答3. 這些設備,要訪問之必須"選中",沒有選中的晶元不會工作,相當於沒接一樣。(記憶體控制器)
問4. 假設燒寫NAND FLASH,把命令、地址、數據發給它之後,
NAND FLASH肯定不可能瞬間完成燒寫的,怎麼判斷燒寫完成?
答4. 通過狀態引腳RnB來判斷:它為高電平表示就緒,它為低電平表示正忙
問5. 怎麼操作NAND FLASH呢?
答5. 根據NAND FLASH的晶元手冊,一般的過程是:
發出命令
發出地址
發出數據/讀數據
2 分析nand flash的啟動過程
搜"S3C24XX NAND Driver"
S3c2410.c (drivers\mtd\nand)
s3c2410_nand_inithw
s3c2410_nand_init_chip
nand_scan // 根據nand_chip的底層操作函數識別NAND FLASH,構造mtd_info
nand_scan_ident
nand_set_defaults
if (!chip->select_chip)
chip->select_chip = nand_select_chip; // 預設值不適用
if (chip->cmdfunc == NULL)
chip->cmdfunc = nand_command;
chip->cmd_ctrl(mtd, command, ctrl);
if (!chip->read_byte)
chip->read_byte = nand_read_byte;
readb(chip->IO_ADDR_R);
if (chip->waitfunc == NULL)
chip->waitfunc = nand_wait;
chip->dev_ready
nand_get_flash_type
chip->select_chip(mtd, 0);
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
*maf_id = chip->read_byte(mtd);
dev_id = chip->read_byte(mtd);
nand_scan_tail
mtd->erase = nand_erase;
mtd->read = nand_read;
mtd->write = nand_write;
s3c2410_nand_add_partition
add_mtd_partitions
add_mtd_device
list_for_each(this, &mtd_notifiers) { // 問. mtd_notifiers在哪設置
// 答. drivers/mtd/mtdchar.c,mtd_blkdev.c調用register_mtd_user
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
not->add(mtd);
// mtd_notify_add 和 blktrans_notify_add
先看字元設備的mtd_notify_add
class_device_create
class_device_create
再看塊設備的blktrans_notify_add
list_for_each(this, &blktrans_majors) { // 問. blktrans_majors在哪設置
// 答. drivers\mtd\mdblock.c或mtdblock_ro.c register_mtd_blktrans
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
tr->add_mtd(tr, mtd);
mtdblock_add_mtd (drivers\mtd\mdblock.c)
add_mtd_blktrans_dev
alloc_disk
gd->queue = tr->blkcore_priv->rq; // tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
add_disk
3 nand flash驅動程式框架
(1)分配一個nand_chip/mtd_info結構體
(2)設置
(3)硬體相關的操作
(4)使用nand_scan/add_mtd_partitions
4 寫代碼
參考drivers\mtd\nand\s3c2410.c
1 /*參考drivers\mtd\nand\at91_nand.c*/ 2 3 4 #include <linux/module.h> 5 #include <linux/types.h> 6 #include <linux/init.h> 7 #include <linux/kernel.h> 8 #include <linux/string.h> 9 #include <linux/ioport.h> 10 #include <linux/platform_device.h> 11 #include <linux/delay.h> 12 #include <linux/err.h> 13 #include <linux/slab.h> 14 #include <linux/clk.h> 15 16 #include <linux/mtd/mtd.h> 17 #include <linux/mtd/nand.h> 18 #include <linux/mtd/nand_ecc.h> 19 #include <linux/mtd/partitions.h> 20 21 #include <asm/io.h> 22 23 #include <asm/arch/regs-nand.h> 24 #include <asm/arch/nand.h> 25 26 27 struct s3c_nand_regs { 28 unsigned long nfconf ; 29 unsigned long nfcont ; 30 unsigned long nfcmd ; 31 unsigned long nfaddr ; 32 unsigned long nfdata ; 33 unsigned long nfeccd0 ; 34 unsigned long nfeccd1 ; 35 unsigned long nfeccd ; 36 unsigned long nfstat ; 37 unsigned long nfestat0; 38 unsigned long nfestat1; 39 unsigned long nfmecc0 ; 40 unsigned long nfmecc1 ; 41 unsigned long nfsecc ; 42 unsigned long nfsblk ; 43 unsigned long nfeblk ; 44 }; 45 46 static struct mtd_info *s3c_mtd; 47 static struct nand_chip *s3c_nand; 48 49 50 static struct mtd_partition s3c_nand_parts[] = { 51 [0] = { 52 .name = "bootloader", 53 .size = 0x00040000, 54 .offset = 0, 55 }, 56 [1] = { 57 .name = "params", 58 .offset = MTDPART_OFS_APPEND, 59 .size = 0x00020000, 60 }, 61 [2] = { 62 .name = "kernel", 63 .offset = MTDPART_OFS_APPEND, 64 .size = 0x00200000, 65 }, 66 [3] = { 67 .name = "root", 68 .offset = MTDPART_OFS_APPEND, 69 .size = MTDPART_SIZ_FULL, 70 } 71 }; 72 73 static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr) 74 { 75 if (chipnr == -1) 76 { 77 /* 取消選中: NFCONT[1]設為1 */ 78 s3c_nand_regs->nfcont |= (1<<1); 79 } 80 else 81 { 82 /* 選中: NFCONT[1]設為0 */ 83 s3c_nand_regs->nfcont &= ~(1<<1); 84 } 85 } 86 87 static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) 88 { 89 if (ctrl & NAND_CLE) 90 { 91 /* 發命令: NFCMMD=dat */ 92 s3c_nand_regs->nfcmd = dat; 93 } 94 else 95 { 96 /* 發地址: NFADDR=dat */ 97 s3c_nand_regs->nfaddr = dat; 98 } 99 } 100 101 static int s3c2440_dev_ready(struct mtd_info *mtd) 102 { 103 return (s3c_nand_regs->nfstat & (1<<0)); 104 } 105 106 107 static int s3c_nand_init(void) 108 { 109 struct clk *clk; 110 s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); 111 112 s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs)); 113 114 s3c_nand->select_chip = s3c2440_select_chip; 115 s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl; 116 s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata; 117 s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata; 118 s3c_nand->dev_ready = s3c2440_dev_ready; 119 s3c_nand->ecc.mode = NAND_ECC_SOFT;//enable ECC 120 121 clk = clk_get(NULL, "nand"); 122 clk_enable(clk); 123 124 #define TACLS 0 125 #define TWRPH0 1 126 #define TWRPH1 0 127 s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); 128 s3c_nand_regs->nfcont = (1<<1) | (1<<0); 129 130 s3c_mtd = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); 131 s3c_mtd->owner = THIS_MODULE; 132 s3c_mtd->priv = s3c_nand; 133 nand_scan(s3c_mtd, 1);//識別nand falsh,構造mtd_info 134 135 add_mtd_partitions(s3c_mtd, s3c_nand_parts,4); 136 137 return 0; 138 } 139 140 141 static void s3c_nand_exit(void) 142 { 143 del_mtd_partitions(s3c_mtd); 144 kfree(s3c_mtd); 145 iounmap(s3c_nand_regs); 146 kfree(s3c_nand); 147 } 148 149 module_init(s3c_nand_init); 150 module_exit(s3c_nand_exit); 151 152 MODULE_LICENSE("GPL");s3c_nand.c