块设备驱动之NAND FLASH驱动程序
轉載請注明出處:http://blog.csdn.net/ruoyunliufeng/article/details/25240909
一.框架總結
二.硬件原理
相比于nor flash。我們能夠清楚的看出引腳少了非常多,主要是輸入輸出引腳進行了復用。如今我說下各引腳的用途。
?????????? a.LDATA0~LDATA7這8個引腳為輸入輸出引腳。
命令、地址、數據的傳輸都是由這8個引腳實現的(引腳復用,節約引腳)。
?????????? b.RnB:此引腳用來判忙。由于命令、數據、地址發出去和收到時候不能立馬就完畢。須要一個時間。
此引腳為高電平時表示就緒,低電平時候表示正忙。
?????????? c.nFCE、nFWE、nFCE各自是芯片使能、寫使能、和讀使能。舉個樣例,就是說假如你想讀數據、命令、地址時候。
必須先使能nFCE、nFCE(就是這兩個引腳為低電平)。
?????????? d.CLE、ALE兩個引腳是指令鎖時能和數據鎖使能。
使用方法:當ALE為高電平時傳輸的是地址,當CLE為高電平時傳輸的是命令。當ALE和CLE都為低電平時傳輸的是數據。
三.驅動程序
/* 參考 * drivers\mtd\nand\s3c2410.c* drivers\mtd\nand\at91_nand.c*/#include <linux/module.h> #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/slab.h> #include <linux/clk.h>#include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/arch/regs-nand.h> #include <asm/arch/nand.h>/*用到的寄存器*/ struct s3c_nand_regs {unsigned long nfconf ;unsigned long nfcont ;unsigned long nfcmd ;unsigned long nfaddr ;unsigned long nfdata ;unsigned long nfeccd0 ;unsigned long nfeccd1 ;unsigned long nfeccd ;unsigned long nfstat ;unsigned long nfestat0;unsigned long nfestat1;unsigned long nfmecc0 ;unsigned long nfmecc1 ;unsigned long nfsecc ;unsigned long nfsblk ;unsigned long nfeblk ; };static struct nand_chip *s3c_nand; //nand_chip結構體 static struct mtd_info *s3c_mtd; static struct s3c_nand_regs *s3c_nand_regs;static struct mtd_partition s3c_nand_parts[] = {[0] = {.name = "bootloader", //名字.size = 0x00040000, //大小 .offset = 0, //偏移值},[1] = {.name = "params",.offset = MTDPART_OFS_APPEND, //緊跟上面分區.size = 0x00020000,},[2] = {.name = "kernel",.offset = MTDPART_OFS_APPEND,.size = 0x00200000,},[3] = {.name = "root",.offset = MTDPART_OFS_APPEND,.size = MTDPART_SIZ_FULL,} };/*推斷是否選中*/ static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr) {if (chipnr == -1){/* 取消選中: NFCONT[1]設為1 */s3c_nand_regs->nfcont |= (1<<1); }else{/* 選中: NFCONT[1]設為0 */s3c_nand_regs->nfcont &= ~(1<<1);} } /*推斷發命令,還是地址*/ static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) {if (ctrl & NAND_CLE){/* 發命令: NFCMMD=dat */s3c_nand_regs->nfcmd = dat;}else{/* 發地址: NFADDR=dat */s3c_nand_regs->nfaddr = dat;} } /*推斷狀態*/ static int s3c2440_dev_ready(struct mtd_info *mtd) {return (s3c_nand_regs->nfstat & (1<<0)); }static int s3c_nand_init(void) //入口函數 {struct clk *clk;/* 1. 分配一個nand_chip結構體 */s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs)); //映射寄存器/* 2. 設置nand_chip *//* 設置nand_chip是給nand_scan函數使用的, 假設不知道怎么設置, 先看nand_scan怎么使用 * 它應該提供:選中,發命令,發地址,發數據,讀數據,推斷狀態的功能*/s3c_nand->select_chip = s3c2440_select_chip; //推斷選中s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl; //發命令。還是地址s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata; //讀數據s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata; //寫數據s3c_nand->dev_ready = s3c2440_dev_ready; //推斷狀態s3c_nand->ecc.mode = NAND_ECC_SOFT; //設置ECC/* 3. 硬件相關的設置: 依據NAND FLASH的手冊設置時間參數 *//* 使能NAND FLASH控制器的時鐘 */clk = clk_get(NULL, "nand");clk_enable(clk); /* CLKCON'bit[4] *//* HCLK=100MHz* TACLS: 發出CLE/ALE之后多長時間才發出nWE信號, 從NAND手冊可知CLE/ALE與nWE能夠同一時候發出,所以TACLS=0* TWRPH0: nWE的脈沖寬度, HCLK x ( TWRPH0 + 1 ), 從NAND手冊可知它要>=12ns, 所以TWRPH0>=1* TWRPH1: nWE變為高電平后多長時間CLE/ALE才干變為低電平, 從NAND手冊可知它要>=5ns, 所以TWRPH1>=0*/ #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);/* NFCONT: * BIT1-設為1, 取消片選 * BIT0-設為1, 使能NAND FLASH控制器*/s3c_nand_regs->nfcont = (1<<1) | (1<<0);/* 4. 使用: nand_scan */s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);s3c_mtd->owner = THIS_MODULE;s3c_mtd->priv = s3c_nand; //設置私有數據nand_scan(s3c_mtd, 1); /* 識別NAND FLASH, 構造mtd_info *//* 5. add_mtd_partitions 加入分區*/add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);//add_mtd_device(s3c_mtd); 整個flash僅僅有一個分區return 0; }static void s3c_nand_exit(void) //出口函數 {del_mtd_partitions(s3c_mtd);kfree(s3c_mtd);iounmap(s3c_nand_regs);kfree(s3c_nand); }module_init(s3c_nand_init); module_exit(s3c_nand_exit);MODULE_LICENSE("GPL");
四.驅動分析
????? 1.總體分析
???????????? 1.1分配一個nand_chip結構體并映射相關寄存器
????????????1.2設置nand_chip(設置nand_chip是給nand_scan函數使用的, 假設不知道怎么設置, 先看nand_scan怎么使用。它應該提供:選中,發命令,發地址,發數據,讀數據,推斷狀態的功能)
????????????1.3硬件相關的設置: 依據NAND FLASH的手冊設置時間參數
????????????1.4使用: nand_scan
????????????1.5add_mtd_partitions 加入分區(分區在s3c_nand_parts結構體中進行設置)
????? 2.寄存器介紹
???????????? 2.1 NFSTAT(狀態寄存器。主要判忙)
s3c_nand->dev_ready = s3c2440_dev_ready; //推斷狀態
? ? ? ? ? ?? 2.2 NFCMMD(命令寄存器)和NFADDR(地址寄存器)
static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) {if (ctrl & NAND_CLE){/* 發命令: NFCMMD=dat */s3c_nand_regs->nfcmd = dat;}else{/* 發地址: NFADDR=dat */s3c_nand_regs->nfaddr = dat;} }
? ? ? ? ? ?? 2.3 NFCONT(控制寄存器)
/* NFCONT: BIT1-設為1, 取消片選。 BIT0-設為1, 使能NAND FLASH控制器*/s3c_nand_regs->nfcont = (1<<1) | (1<<0);
? ? ? ? ? ?? 2.4 NFCONF(配置寄存器)
/* HCLK=100MHz* TACLS: 發出CLE/ALE之后多長時間才發出nWE信號, 從NAND手冊可知CLE/ALE與nWE能夠同一時候發出,所以TACLS=0* TWRPH0: nWE的脈沖寬度, HCLK x ( TWRPH0 + 1 ), 從NAND手冊可知它要>=12ns, 所以TWRPH0>=1* TWRPH1: nWE變為高電平后多長時間CLE/ALE才干變為低電平, 從NAND手冊可知它要>=5ns, 所以TWRPH1>=0*/ #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
左圖為2440nand時序。右面為nand手冊要求時序。最后一個圖為詳細數值。
以下這三個圖計算最小值。
TACLS??? =? tCLS-tWP=12-12=0
TWRPH0=?tWP????????=12
TWRPH1=? tCLH??????? =5
? ? ?3.ECC校驗
???????????? 因為Nand flash的工藝特性。所以nand flash有一個缺點就是位反轉。所以增加了ECC校驗。
詳細怎么實現呢?
???????????? nand flash的存儲是以頁為單位的。它在每頁的后面增加了OOB(16字節),這里面存的就是ECC的值。怎樣工作?
????????????? a.寫每頁的時候生成ECC,將ECC寫入OBB
????????????? b.當讀每頁的時候先算出ECC,然后讀OBB的ECC。兩個ECC進行比較。
詳細的算法實現比較復雜,我在這里僅僅是簡單的說一下,有興趣的能夠深入研究。
參考:韋東山視頻第二期
??????????????
總結
以上是生活随笔為你收集整理的块设备驱动之NAND FLASH驱动程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 的HashMap底层数据结构
- 下一篇: hadoop中map的个数