uboot环境下mmc操作_【记录】将Uboot 2011.06中mmc驱动移植到uboot 1.1.6的过程
【記錄】將Uboot 2011.06中mmc驅動移植到uboot 1.1.6的過程
時間:2011-8-14
作者:crifan
聯系方式:green-waste (at) 163.com
附上代碼:
【背景】
硬件:
(1)TQ2440,CPU是S3C2440,帶SD/MMC控制器。
(2)自己的金士頓的1GB的SD卡
軟件:
(1)TQ2440的uboot 1.1.6
(2)自己已經移植舊的mmc的驅動成功,可以實現mmcinfo, fatls mmc 0, fatload mmc 0 addr file,但是舊的mmc中檢測出來的sd卡的容量不對,原因是由于READ_BL_LEN是15,大于12了,用的計算方法是錯誤的。
詳情參見:
【記錄】在TQ2440的uboot中添加SD/MMC支持+添加USB Mass Storage支持+解決fatls亂碼問題
【目的】
想要實現正確檢測我的1GB的SD卡的容量,所以要把正確的mmc驅動移植過來。
而目前最新的uboot 2011.06版本的中,已經有最新的mmc驅動,但是和uboot 1.1.6比,mmc的整個架構都變了,需要把mmc部分,整個都改了,再添加對應的底層函數,才可以。
【將Uboot 2011.06中mmc驅動移植到uboot 1.1.6的全過程】
1.添加文件,修改makefile等準備工作
先是把mmc最直接相關的cmd_mmc.c,整個替換了
這樣就支持了更多的mmc相關的命令了:
mmcinfo
mmc rescan
mmc part
mmc list
mmc dev
fatls mmc 0
fatload mmc 0 addr filename
同時,替換了最新的mmc.h頭文件,該文件包含了對應的sd/mmc所有的命令等定義。
由于舊的uboot中在board.c的start_armboot()中沒有mmc初始化部分,所以也要填上對應內容:#ifdef CONFIG_GENERIC_MMC
puts(“MMC:“);
mmc_initialize(gd->bd);
#endif
而后再去添加對應的makefile等,使得編譯通過,不多細說。
2. s3c_mmc_init()
用beyondcompare,將uboot 2011.06和uboot 1.1.6相比較,發現新的mmc驅動框架中,主要實現幾個核心函數即可,此處我的sd/mmc控制器是三星的S3C2440的,所以簡稱為s3c,對應的第一個要實現的函數為:/* this is a weak define that we are overriding */
int board_mmc_init(bd_t *bd)
{
return s3c_mmc_init(bd);
}
中的:s3c_mmc_init()
其中,主要是初始化mmc中一些核心的參數,主要代碼是:mmc->send_cmd = s3cmmc_send_cmd;
mmc->set_ios = s3cmmc_set_ios;
mmc->init = s3cmmc_init;
將掛上發送命令,設置總線寬度/頻率等,初始化三個函數的指針
mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS;
告訴sd host支持4bit模式 即High Speed即50MHz模式
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
此處電壓是參考其他驅動寫上的,具體含義沒有深入去了解
mmc->f_max = get_PCLK();
mmc->f_min = 400*1000;
設置所支持的最大和最小頻率
mmc->block_dev.part_type = PART_TYPE_DOS;
設置sd卡分區的類型是DOS,即常見的FAT分區
mmc->b_max = 0;
設置最大的block數目,0為沒限制,mmc系統會自動初始化
都設置好了,再去調用
mmc_register(mmc);
上述內容都設置好了,然后就是分別去實現上述三個核心的函數:
3. s3cmmc_init()
init函數中,主要就是初始化sd的硬件相關的部分
其主要代碼和之前舊的差不多,只是把blocksize設置,頻率設置,等等,都放到了setios函數或者send_cmd函數中了而已,沒有太多需要解釋的,參考之前代碼即可。
4. s3cmmc_set_ios()
set_ios中,主要就是兩個:
(1)當傳入的參數中clock不為0時候,去根據所需要的頻率去設置對應的SDIPRE寄存器即可;
(2) 根據傳入的總線寬度,此處即1或者4,1就是最開始的默認的,4就是對應的wide bus,設置對應的SDIDCON寄存器即可。
5. s3cmmc_send_cmd()
發送命令,這個函數可以個大頭,需要花不少精力的。
通過看uboot 2011.06中其他mmc驅動的實現,大概看懂了此處,mmc發送命令的函數,其實處理了兩個事情,一個是發送普通命令,二是對于數據的讀寫,其實也是通過發送對應對應的命令,然后讀寫對應數據的。
即普通的發送命令,只需要發送命令即可;
而包括數據讀寫的命令,參數是放在data中的,data不為空的時候,就不僅僅要發送對應的命令,還要接著讀寫數據的。
此處暫時不去實現數據的write,只考慮read的情況,目的是實現相關的命令fatls mmc 0和fatload mmc 0 addr file。
(1)單純的發送命令
關于發送命令,之前也已經有了對應的函數send_cmd,把舊函數,拿過來,改一下,也基本就實現了。
【關于發送命令之后的response】
另外需要提及一點的是,如果發送命令需要反饋response的,對于
cmd->resp_type中有MMC_RSP_PRESENT的,那么至少要返回一個response,而如果是長的response,即MMC_RSP_136,是需要返回四個response的,詳情參考代碼。
【使用readl/writel時候,需要傳入寄存器的地址而不是寄存器的值】
另外還有點要說明的,對于用writel/readl,readb/writeb等函數來代替直接寄存器操作的,傳入的寄存器地址,是需要是地址的,而不能是寄存器的值,即:
原先讀一個寄存器:csta = sdi->SDICSTA;
現在用readl時,要傳入寄存器的地址,要這樣調用:csta = readl(&sdi->SDICSTA);
而不能是csta = readl(sdi->SDICSTA);
關于這點,也是參考了別的代碼和調試,才發現這點的。
【詭異問題:S3C2410_SDICMDCON_SENDERHOST的含義】
不過,這里在調試代碼過程中,發現一個有點詭異的問題,那就是,對于設置command control寄存器的時候,原先代碼是:
ccon |=S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
其中
#define S3C2410_SDICMDCON_SENDERHOST(1<<6)
但是對應的S3C2410和S3C2440的datasheet中,都沒有提到這一點,而只是網上這些S3C2410和S3C2440的sd卡驅動的參考代碼,包括uboot和kernel中的,卻有這個位的設置,而如果去掉這一位的設置,命令就無法正常發送。
雖然看名字S3C2410_SDICMDCON_SENDERHOST知道大概是host是sender,但是對于這一位的具體含義是什么,還是不懂,希望如果有知情的可以解釋一下。
(2)帶讀數據的命令的發送和之后的數據讀取
但是對于帶讀數據的命令的發送,包括MMC_CMD_READ_MULTIPLE_BLOCK=CMD17讀塊數據和MMC_CMD_SEND_EXT_CSD=CMD8讀擴展CSD等等,就不僅僅要先發送命令,還要接著讀對應的數據才可以的。
對于read block等命令,其處理的時候,要先設置好datasize寄存器,
再根據之前設置的SDIDCON中的bus width是1還是4,決定設置數據控制寄存器中是S3C2440_SDIDCON_DS_WORD還是S3C2440_SDIDCON_DS_BYTE,
等設置好了SDIDCON之后,接著再去發送對應的帶數據讀的命令,然后接著處理的流程和之前舊的代碼是一樣的,即先去fifosta中找到fifo中有多少個數據,然后一個個讀取,每次讀取1個字節還是4個字節,由之前的bus width決定。
等讀完當前fifo了再去重復讀取fifosta,再去判斷有多少個字節數據需要讀取,
這樣一點點把數據讀出來即可。
讀數據的過程中,需要通過讀取SDIDSTA得知數據的狀態是否正常,如果有錯誤,比如超時,CRC錯誤等,就退出。
此部分流程,基本和舊的代碼沒太大區別。
但是代碼調試過程中,這部分代碼,在讀取數據部分,始終出錯,讓我調試了很久,最后找到原因,竟然是自己不小心,在讀取了SDIDCON的值后,忘了把原來的bus width那一位給設置回去,所以再之前去設置bus width=4=word之后,此處還是用bus width=1=byte的模式來讀數據,所以出現第一次讀SDIFSTA而獲得的FIFO中的字節數,竟然是有奇數的,比如0x1c7,而不是期望的64啊之類的,應該是4的倍數的,最后加上對應的正確的設置后,后面的讀取數據就都對了。
【未解決的疑問:CMD8和CMD13超時】
在最后可以成功讀數據之后,卻也還是發現有兩個命令會超時:
MMC CMD8 Timeout
MMC CMD13 Timeout
具體原因未知。有待后期再去找原因,或者哪個高手告知一下原因。
最后貼上可以成功檢測出我的1GB的SD卡的log信息:EmbedSky> help mmc
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc rescan
mmc part – lists available partition on current mmc device
mmc dev [dev] [part] – show or set current mmc device [partition]
mmc list – lists available devices
EmbedSky> mmcinfo
MMC CMD8 Timeout
MMC CMD13 Timeout
Status Error: 0x002D0032
Device: TQ2440 SD/MMC
Manufacturer ID: 2
OEM: 544d
Name: SD01G
Tran Speed: 25000000
Rd Block Len: 512
SD version 1.10
High Capacity: No
Capacity: 982.5 MB
Bus Width: 4-bit
EmbedSky> mmc rescan
MMC CMD8 Timeout
MMC CMD13 Timeout
Status Error: 0x002D0032
EmbedSky> mmc part
Partition Map for UNKNOWN device 0—Partition Type: DOS
PartitionStart SectorNum SectorsType
124320119176
EmbedSky> mmc dev
mmc0 is current device
EmbedSky> mmc list
TQ2440 SD/MMC: 0
EmbedSky> fatls mmc 0
MMC CMD13 Timeout
512nikon001.dsc
misc/
dcim/
3701fisrttest.html
2 file(s), 2 dir(s)
總結
以上是生活随笔為你收集整理的uboot环境下mmc操作_【记录】将Uboot 2011.06中mmc驱动移植到uboot 1.1.6的过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue 导入excel解析_【Vue 笔
- 下一篇: js 对一个字段去重_JS单行、多行文本