在vivi中使用的flash有nor和nand,而mtd的作用就是提供一箇中間層的驅動,實現接口函數的統一管理,這裏首先介紹nand flash在mtd中的實現。
在vivi bootloader中,第6步的時候就是實現mtd中間驅動的實現,MTD驅動的函數調用關係如下:
mtd_dev_init()---->mtd_init()---->smc_init()在這裏需要說明,mtd_init()函數可以按照配置調用不同的函數,包括cfi_init(),smc_init(),amd_init(),這裏不同的函數對應不同的flash設備的初始化。
其中cfi_init()是intel發起的nor flash的接口標準。
smc_init()是smc智能卡接口,我們使用的nand flash使用的就是這個接口
amd_init()是AMD flash接口
在完成上面初始化以後則是增加flash命令,這部分於後面的增加命令相似(關於命令的部分在後面的章節會有專門的說明)
---->add_command(&flash_command)
下面來具體看看函數的實現,首先我們要注意到的是兩個數據結構,分別是mtd_info(mtd_info是表示MTD設備的結構,每個分區也被表示爲一個mtd_info,如果有兩個MTD設備,每個設備有三個分區,那麼在系統中就一共有6個mtd_info結構),一下是vivi中mtd_info結構
|
還有一個重要的結構nand_chip,這個結構中包含了nand flash所有的信息
|
|
首先看看上面三個結構,瞭解結構中包含的信息
在回來繼續分析smc_init()函數,首先函數需要申請一個地址空間用來存放struct mtd_info和struct nand_chip,返回地址給mymtd
mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
定義一個nand_chip結構的變量this; struct nand_chip *this
this = (struct nand_chip *)(&mymtd[1])這個地方有必要解釋一下:
其中,mymtd是指向struct mtd_info的指針,那麼mymtd[1]實際上是等效於*(mymtd + 1)的數學計算模式,注意mymtd並非數組,這裏僅僅利用了編譯器翻譯的特點。對於指針而言,加1實際上增加的指針對應類型的值,在這裏地址實際上增加了sizeof(struct mtd_info),因爲前面分配了兩塊連續的地址空間,所以&(*(mymtd + 1))實際上就是mtd_info數據結構結束的下一個地址,然後實現強制轉換,於是this就成爲了nand_chip的入口指針了。但是,這裏必須要把握好,因爲這個地方是不會進行內存的檢查的,也就是說,如果你使用了mymtd[2],那麼仍然按照上述公式解析,雖然可以運算,可是就是明顯的指針泄漏了,可能會出現意料不到的結果。寫了一個測試程序,對這點進行了探討,要小心內存問題。(參考了CalmArrow的解釋)
|
緊接着就是初始兩個結構
memset((char *)mymtd, 0, sizeof(struct mtd_info));
memset((char *)this, 0, sizeof(struct nand_chip));
使得mymtd->priv指向this結構。也就是使得這兩部分聯繫起來
設置nand flash的寄存器
NFCONT |= ((1<<0) & (1 << 4) & (1 << 5));
由於nand_chip是直接於nanf flash掛鉤的,應此在此定義一些函數直接對nand flash進行操作
先看整體,再對每個細節進行分析:
this->hwcontrol = smc_hwcontrol;
this->write_cmd = write_cmd;
this->write_addr = write_addr;
this->read_data = read_data;
this->write_data = write_data;
this->wait_for_ready = wait_for_ready;
我們首先來看smc_hwcontrol函數,也就是nand flash的硬件控制,實現很簡單,根據vivi中定義的情況之處理3中情況(1,2,10,其他的命令只是簡單的退出)
|
寫命令:
|
|
|
|
等待準備好:
|