【簡介】如何編寫linux下nand flash驅動

【簡介】如何編寫linuxnand flash驅動
Version: V0.1
Time:10/06/2008
Author[email][email protected][/email]
【編寫驅動之前要了解的知識】
1.硬件方面:
Flash的種類】
Flash主要分nand flashnor flash
除了網上最流行的這個解釋之外:
我再多說幾句,nor的成本相對高,比較適合應用於存儲少量的代碼。
Nand flash相對成本低,因此可以用來存儲大量的數據,其在嵌入式系統中的作用,相當於PC上的硬盤,用於存儲大量數據。
Nor flash,有類似於dram之類的地址總線,因此可以直接和CPU相連,CPU可以直接通過地址總線對nor flash進行訪問,而nand flash沒有這類的總線,只有IO接口,只能通過IO接口發送命令和地址,對nand flash內部數據進行訪問。相比之下,nor flash就像是並行訪問,nand flash就是串行訪問,所以相對來說,前者的速度更快些。
但是由於物理製程/製造方面的原因,導致nor nand在一些具體操作方面的特性不同:

Nand Nor Flash 的區別
 
NOR
NAND
(備註)
接口
總線
I/O接口
這個兩者最大的區別
單個cell大小
 
單個Cell成本
 
讀耗時
 
單字節的編程時間
 
多字節的編程時間
 
擦除時間
 
功耗
低,但是需要額外的RAM
 
是否可以執行代碼
不行, 但是一些新的芯片,可以在第一頁之外執行一些小的loader
位反轉Bit twiddling
幾乎無限制
1-3次,也稱作 “部分頁編程限制”
也就是數據錯誤了?
在芯片出廠時候是否允許壞塊
不允許
允許
 
 
Nand Flash的種類】
具體再分,又可以分爲
1)Bare NAND chips:裸片,單獨的nand 芯片
2)SmartMediaCards =裸片+一層薄塑料,常用於數碼相機和MP3播放器中。之所以稱smart,是由於其軟件smart,而不是硬件本身有啥smart之處。^_^
3)DiskOnChip:裸片+glue logicglue logic=硬件ECC產生器+用於靜態的nand 芯片控制的寄存器+直接訪問一小片地址窗口,那塊地址中包含了引導代碼的stub樁,其可以從nand flash中拷貝真正的引導代碼。
 
Nand flash的特點】
Nand flash的操作,和其他一些常見的設備,如硬盤等,不同,其有自己特殊的方式。
其特殊就在於:
1.Nand flash的最小單位是頁page,而不是其他很多設備所說的位bit
2.寫入數據之前必須先進行擦除erase操作
3.寫的時候,最小單位是頁page,對也進行寫操作,也稱作“頁編程”,page programming
4.擦除的最小單位是塊block
5.由於物理特性,容易出錯,所以無論是讀還是寫,都要採取檢測和校驗,即EDC
6.nand flash出廠時候,就有一定壞的塊block,成爲換塊,並且做了一定標記。
7.nand flash中有個額外的空間,叫做spare area/oob
 
spare area/oob
Nand由於最初硬件設計時候考慮到,額外的錯誤校驗等需要空間,專門對應每個頁,額外設計了叫做spare area空區域,在其他地方,比如jffs2文件系統中,也叫做oobout of band)數據。
其具體用途,總結起來有:
1.       標記是否是壞快
2.       存儲ECC數據
3.       存儲一些和文件系統相關的數據,如jffs2就會用到這些空間存儲一些特定信息
 
 
【常見Nand Flash的大小及參數】
常見的nand flash 的大小,由最開始的小於256M,到現在的常見的1G2G,甚至更大。
以前的nand flash
Pagesize頁大小,多爲512B+16Boobblock大小爲64*512B+16B=32KB+1KB
現在目前市場上見到的,絕大多數,都是新的nand falsh,其Pagesize頁大小多爲2KB+64Boobblock大小多爲64pages=64*2K+64B=128KB+4KB,一個nand flash中的芯片,一般含有4096個塊,比如samsungK9F4G08U0M,所以這個nand flash大小就是
4096 Blocks = 4096 * 64 *2K+64B=512MB
即:
1 Page = (2K + 64)Bytes
1 Block = (2K + 64)B x 64 Pages
= (128K + 4K) Bytes
1 Device = (2K+64)B x 64Pages x 4,096 Blocks
= 4,224 Mbits =512MB
 
Nand flash工作原理】
所謂工作原理,其實也就是對應對其如何操作的。
還是以上面提到的samsungK9F4G08U0Mnand flash爲例,簡單描述如下:
1.nand flash定義了一些引腳,使得你可以發送命令過去,實現對nand flash的操控:
上面這些引腳,需要解釋的主要是
CLE,使能,只有使能有效,你才能進行後續的操作。只能選中了這個nand芯片,才能進行後續的讀寫。
ALE,在發送地址時,要鎖住地址總線,纔可以操作。
REWE,在讀寫之前,要對應的引腳有效,纔可以進行讀寫的。
其他見解釋皆可。
 
所有如上的引腳,都是驅動中,通過發送命令,具體內部控制邏輯去實現的。
而驅動開發者要關心的,是何時去發送對應的命令。具體想要實現一操作,要何時發送什麼命令才能實現,要繼續看下面的datasheet中的解釋:
 
如果想要對nand flash操作,就要根據datasheet中的規範進行,比如對頁的寫操作/寫編程要根據這個順序去操作:
其具體的細節,包含了哪些操作,可以看這個時序圖:
從上圖可以看出來,要先發80h的命令,再繼續後面的操作。
這裏的80h命令的含義,參考這個圖表:
從這個圖表,可以看到,80h就是page program的第一個命令。
而時序圖中的先兩個col列地址,後三個row行地址,是根據下面這個圖得來的:
此時才能定位到你所要操作的頁,才能進行寫操作。
再多說幾句,上圖表示了,如果想要對這個nand flash操作,讀或寫,需要進行3次列地址和三次的行地址,才能定位到你所要操作的地方,才能讀寫。同時顯示了,每次每個位,對應代表的地址位。
此處的2個列地址和3個行地址,是由硬件設計決定的。
老的nand flash由於每個頁只有512B,所以,最後的操作,只需要1個列地址和3個行地址就可以定位了。感興趣的可以去網上下載samsung一些老的nand flash,可以對比着看,更明白些。
 
而每個操作,比如上面的寫操作,都是需要一定時間的,其具體硬件操作所需的時間,見這個圖:
此處可以看到,寫一個頁,即頁編程,一般需要200us,最大需要700us,所以驅動開發者在開發的時候,要知道這個細節,要等待對應的時間,再去判斷,是否寫操作順利完成了,才能接下來繼續後面其他的操作的。
 
上述的具體代碼實現,可以去看
drivers\mtd\nand\nand_base.c中的nand_command_lp()函數中的代碼:
 
/* Command latch cycle */
//對命令鎖存,然後才能發送命令
       chip->cmd_ctrl(mtd, command & 0xff,
                     NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
 
       if (column != -1 || page_addr != -1) {
              int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
 
//先發送2col地址,構成整個列地址
              /* Serially input address */
              if (column != -1) {
                     /* Adjust columns for 16 bit buswidth */
                     if (chip->options & NAND_BUSWIDTH_16)
                            column >>= 1;
                     chip->cmd_ctrl(mtd, column, ctrl);
                     ctrl &= ~NAND_CTRL_CHANGE;
                     chip->cmd_ctrl(mtd, column >> 8, ctrl);
              }
//再發送3row地址,構成整個行地址
              if (page_addr != -1) {
                     chip->cmd_ctrl(mtd, page_addr, ctrl);
                     chip->cmd_ctrl(mtd, page_addr >> 8,
                                   NAND_NCE | NAND_ALE);
                     /* One more address cycle for devices > 128MiB */
                     if (chip->chipsize > (128 << 20))
                            chip->cmd_ctrl(mtd, page_addr >> 16,
                                          NAND_NCE | NAND_ALE);
              }
       }
這樣就可以定位到我們要操作的位置,進行操作了。
 
2.軟件方面:
Linux驅動原理
具體內部很多實現,已經包含在drivers\mtd\nand\nand_base.c中了
nand flash驅動加載識別nand類型過程】
在驅動加載的時候,會去調用:
nand_get_flash_type()
其中,就會對nand的類型和其他相關參數進行檢查。
1)  選中對應設備,如果此時只有一個nand 芯片,則此步可以省略
       /* Select the device */
       chip->select_chip(mtd, 0);
x
2)  發讀命令,去讀取設備類型代碼
       /* Send the command for reading device ID */
       chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
3)  判斷是哪個廠商的,哪個類型的flash
       /* Read manufacturer and device IDs */
       *maf_id = chip->read_byte(mtd);
       dev_id = chip->read_byte(mtd);
 
4)  在事先已經定義好的nand flash類型中查找屬於何種廠商和型號
       /* Lookup the flash id */
       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
              if (dev_id == nand_flash_ids[i].id) {
                     type =  &nand_flash_ids[i];
                     break;
              }
       }
 
5)  繼續判斷具體nand flash的各個參數,包括
芯片信息,Pagesize頁大小,oobsizeoob的大小,blocksize塊大小,buswidth總線寬度是8位還是16位。
 
如果頁大小不是之前老的nand512B,而是新的nand2K或更大,則後面對應的發送給nand flash命令的的時候,調用的函數就由nand_command()變成nand_command_lp()了。
後者主要比前者多一發個命令:
chip->cmd_ctrl(mtd, column >> 8, ctrl);
即,多發一個列地址命令。
因爲大頁面(>2KB)的尋址需要2column,而小頁面(512B)只需要1次的列地址。
具體可以參考nand flashdatasheet
 
6)  接着會做一些其他初始化操作,包括最後調用nand_set_defaults()去實現的默認函數的掛載,如果你的nand flash驅動沒有實現的話,就是掛載默認的了。
 
 
【模塊加載原理】
這個內容太大,此處只是簡單說說。
驅動加載的功能主要是probe函數實現的,主要去識別設備的類型和各個參數,並且爲設備的使用進行正常的初始化。
對應卸載時候執行的remove函數,施放對應的,之前申請的一些資源。
 
MTD設備】
Linux下,將nand Flash等設備歸屬到MTD設備下進行統一管理。
Mtd,即memory technology deveice,即將nand看出是存儲設備來管理。
之所以會這麼說和這麼做,是因爲前面提高的nand flash和普通硬盤等設備的特殊性:
IO接口,最小單位是頁,寫前需擦除等,導致了,不能像平常對待硬盤等操作一樣去操作nand flash,只能採取一些特殊方法,這就誕生了mtd設備的統一抽象層,將nand flashnor flash和其他類型的flash等設備,統一抽象成mtd設備來管理,根據這些設備的特點,上層實現了常見的操作函數封裝,底層具體的內部實現,就需要驅動設計者自己來實現了。
 
MTD設備和硬盤設備之前的區別
HARD drives
MTD device
連續的扇區
連續的可擦除塊
扇區都很小(512B,1024B)
可擦除塊比較大 (32KB,128KB)
主要通過兩個操作對其維護操作:讀扇區,寫扇區
主要通過三個操作對其維護操作:從擦除塊中讀,寫入擦除塊,擦寫可擦除塊
壞快被重新映射,並且被硬件隱藏起來了(至少是在如今常見的LBA硬盤設備中是如此)
壞的可擦除塊沒有被隱藏,軟件中要處理對應的壞塊問題。
HDD扇區沒有擦寫壽命超出的問題。
可擦除塊是有擦除次數限制的,大概是104-105.
 
Linuxnand flash驅動編寫步驟簡介】
1.       瞭解硬件的nand flash的各個參數和工作原理
具體參考nand flashdatasheet,主要包括,自己nand flash的廠商,型號等。
Nand flash的頁大小,oob大小,塊大小,位寬8bit還是16bit
工作原理,上面已經做了一定描述,不清楚的,可以參考datasheet,多看看,就會明白很多。
 
2.       按照linux下驅動編寫規範編寫nand flash驅動,
可以參考其他已經有的驅動,比如內核源碼中已經有的
drivers\mtd\nand\s3c2410.c
就是個很好的例子。
自己以其爲模板,實現自己板子的nand flash驅動。
其實主要工作就是,實現
static struct platform_driver s3c2410_nand_driver = {
       .probe            = s3c2410_nand_probe,
       .remove          = s3c2410_nand_remove,
       .suspend  = s3c24xx_nand_suspend,
       .resume          = s3c24xx_nand_resume,
       .driver            = {
              .name      = "s3c2410-nand",
              .owner    = THIS_MODULE,
       },
};
中的
XXX_nand_probe函數
XXX_nand_remove函數
XXX_nand_enable_hwecc,如果支持硬件ecc的話。
nand flash的讀寫,這兩個函數,實現了對nand的具體操作。
 
LinuxNand Flash驅動編寫簡單步驟】
軟件和硬件知識,都已經瞭解的話,由於上層的linux mtd框架中,已經完全封裝好了,對nand flashwrite pagewrite oob等相關函數的實現,那麼剩下的只是相對來說已經是很少量的,關於nand 驅動具體內部操作方面的工作:
1.初始化
先是在nand 芯片初始化的時候,對其
XXX_nand_init_chip()
給對應的芯片chip賦給對應的
XXX_nand_read_bufXXX_nand_write_buf等函數:
              chip->cmd_ctrl  = XXX_nand_hwcontrol;
              chip->dev_ready = XXX_nand_devready;
              chip->read_buf  = XXX_nand_read_buf;
              chip->write_buf  = XXX_nand_write_buf;
以實現後續的對nand芯片的操作。
 
然後根據ecc類型,賦給對應的ecc的校驗與糾錯函數:
                    chip->ecc.hwctl     = XXX_nand_enable_hwecc;
                    chip->ecc.calculate = XXX _nand_calculate_ecc;
 
3.       實現上面提到的對應的各個函數,關於如何實現,參考一下其他nand驅動,就會理解很多了。
4.       驅動測試,參考具體的 ldd3Linux Device Driver version 3)的測試相關部分內容。
 
說得很亂,希望對大家有些幫助。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章