uboot环境下mmc操作_【记录】将Uboot 2011.06中mmc驱动移植到uboot 1.1.6的过程
【記錄】將Uboot 2011.06中mmc驅(qū)動移植到uboot 1.1.6的過程
時間:2011-8-14
作者:crifan
聯(lián)系方式:green-waste (at) 163.com
附上代碼:
【背景】
硬件:
(1)TQ2440,CPU是S3C2440,帶SD/MMC控制器。
(2)自己的金士頓的1GB的SD卡
軟件:
(1)TQ2440的uboot 1.1.6
(2)自己已經(jīng)移植舊的mmc的驅(qū)動成功,可以實現(xiàn)mmcinfo, fatls mmc 0, fatload mmc 0 addr file,但是舊的mmc中檢測出來的sd卡的容量不對,原因是由于READ_BL_LEN是15,大于12了,用的計算方法是錯誤的。
詳情參見:
【記錄】在TQ2440的uboot中添加SD/MMC支持+添加USB Mass Storage支持+解決fatls亂碼問題
【目的】
想要實現(xiàn)正確檢測我的1GB的SD卡的容量,所以要把正確的mmc驅(qū)動移植過來。
而目前最新的uboot 2011.06版本的中,已經(jīng)有最新的mmc驅(qū)動,但是和uboot 1.1.6比,mmc的整個架構(gòu)都變了,需要把mmc部分,整個都改了,再添加對應(yīng)的底層函數(shù),才可以。
【將Uboot 2011.06中mmc驅(qū)動移植到uboot 1.1.6的全過程】
1.添加文件,修改makefile等準(zhǔn)備工作
先是把mmc最直接相關(guān)的cmd_mmc.c,整個替換了
這樣就支持了更多的mmc相關(guān)的命令了:
mmcinfo
mmc rescan
mmc part
mmc list
mmc dev
fatls mmc 0
fatload mmc 0 addr filename
同時,替換了最新的mmc.h頭文件,該文件包含了對應(yīng)的sd/mmc所有的命令等定義。
由于舊的uboot中在board.c的start_armboot()中沒有mmc初始化部分,所以也要填上對應(yīng)內(nèi)容:#ifdef CONFIG_GENERIC_MMC
puts(“MMC:“);
mmc_initialize(gd->bd);
#endif
而后再去添加對應(yīng)的makefile等,使得編譯通過,不多細說。
2. s3c_mmc_init()
用beyondcompare,將uboot 2011.06和uboot 1.1.6相比較,發(fā)現(xiàn)新的mmc驅(qū)動框架中,主要實現(xiàn)幾個核心函數(shù)即可,此處我的sd/mmc控制器是三星的S3C2440的,所以簡稱為s3c,對應(yīng)的第一個要實現(xiàn)的函數(shù)為:/* 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中一些核心的參數(shù),主要代碼是:mmc->send_cmd = s3cmmc_send_cmd;
mmc->set_ios = s3cmmc_set_ios;
mmc->init = s3cmmc_init;
將掛上發(fā)送命令,設(shè)置總線寬度/頻率等,初始化三個函數(shù)的指針
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;
此處電壓是參考其他驅(qū)動寫上的,具體含義沒有深入去了解
mmc->f_max = get_PCLK();
mmc->f_min = 400*1000;
設(shè)置所支持的最大和最小頻率
mmc->block_dev.part_type = PART_TYPE_DOS;
設(shè)置sd卡分區(qū)的類型是DOS,即常見的FAT分區(qū)
mmc->b_max = 0;
設(shè)置最大的block數(shù)目,0為沒限制,mmc系統(tǒng)會自動初始化
都設(shè)置好了,再去調(diào)用
mmc_register(mmc);
上述內(nèi)容都設(shè)置好了,然后就是分別去實現(xiàn)上述三個核心的函數(shù):
3. s3cmmc_init()
init函數(shù)中,主要就是初始化sd的硬件相關(guān)的部分
其主要代碼和之前舊的差不多,只是把blocksize設(shè)置,頻率設(shè)置,等等,都放到了setios函數(shù)或者send_cmd函數(shù)中了而已,沒有太多需要解釋的,參考之前代碼即可。
4. s3cmmc_set_ios()
set_ios中,主要就是兩個:
(1)當(dāng)傳入的參數(shù)中clock不為0時候,去根據(jù)所需要的頻率去設(shè)置對應(yīng)的SDIPRE寄存器即可;
(2) 根據(jù)傳入的總線寬度,此處即1或者4,1就是最開始的默認的,4就是對應(yīng)的wide bus,設(shè)置對應(yīng)的SDIDCON寄存器即可。
5. s3cmmc_send_cmd()
發(fā)送命令,這個函數(shù)可以個大頭,需要花不少精力的。
通過看uboot 2011.06中其他mmc驅(qū)動的實現(xiàn),大概看懂了此處,mmc發(fā)送命令的函數(shù),其實處理了兩個事情,一個是發(fā)送普通命令,二是對于數(shù)據(jù)的讀寫,其實也是通過發(fā)送對應(yīng)對應(yīng)的命令,然后讀寫對應(yīng)數(shù)據(jù)的。
即普通的發(fā)送命令,只需要發(fā)送命令即可;
而包括數(shù)據(jù)讀寫的命令,參數(shù)是放在data中的,data不為空的時候,就不僅僅要發(fā)送對應(yīng)的命令,還要接著讀寫數(shù)據(jù)的。
此處暫時不去實現(xiàn)數(shù)據(jù)的write,只考慮read的情況,目的是實現(xiàn)相關(guān)的命令fatls mmc 0和fatload mmc 0 addr file。
(1)單純的發(fā)送命令
關(guān)于發(fā)送命令,之前也已經(jīng)有了對應(yīng)的函數(shù)send_cmd,把舊函數(shù),拿過來,改一下,也基本就實現(xiàn)了。
【關(guān)于發(fā)送命令之后的response】
另外需要提及一點的是,如果發(fā)送命令需要反饋response的,對于
cmd->resp_type中有MMC_RSP_PRESENT的,那么至少要返回一個response,而如果是長的response,即MMC_RSP_136,是需要返回四個response的,詳情參考代碼。
【使用readl/writel時候,需要傳入寄存器的地址而不是寄存器的值】
另外還有點要說明的,對于用writel/readl,readb/writeb等函數(shù)來代替直接寄存器操作的,傳入的寄存器地址,是需要是地址的,而不能是寄存器的值,即:
原先讀一個寄存器:csta = sdi->SDICSTA;
現(xiàn)在用readl時,要傳入寄存器的地址,要這樣調(diào)用:csta = readl(&sdi->SDICSTA);
而不能是csta = readl(sdi->SDICSTA);
關(guān)于這點,也是參考了別的代碼和調(diào)試,才發(fā)現(xiàn)這點的。
【詭異問題:S3C2410_SDICMDCON_SENDERHOST的含義】
不過,這里在調(diào)試代碼過程中,發(fā)現(xiàn)一個有點詭異的問題,那就是,對于設(shè)置command control寄存器的時候,原先代碼是:
ccon |=S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
其中
#define S3C2410_SDICMDCON_SENDERHOST(1<<6)
但是對應(yīng)的S3C2410和S3C2440的datasheet中,都沒有提到這一點,而只是網(wǎng)上這些S3C2410和S3C2440的sd卡驅(qū)動的參考代碼,包括uboot和kernel中的,卻有這個位的設(shè)置,而如果去掉這一位的設(shè)置,命令就無法正常發(fā)送。
雖然看名字S3C2410_SDICMDCON_SENDERHOST知道大概是host是sender,但是對于這一位的具體含義是什么,還是不懂,希望如果有知情的可以解釋一下。
(2)帶讀數(shù)據(jù)的命令的發(fā)送和之后的數(shù)據(jù)讀取
但是對于帶讀數(shù)據(jù)的命令的發(fā)送,包括MMC_CMD_READ_MULTIPLE_BLOCK=CMD17讀塊數(shù)據(jù)和MMC_CMD_SEND_EXT_CSD=CMD8讀擴展CSD等等,就不僅僅要先發(fā)送命令,還要接著讀對應(yīng)的數(shù)據(jù)才可以的。
對于read block等命令,其處理的時候,要先設(shè)置好datasize寄存器,
再根據(jù)之前設(shè)置的SDIDCON中的bus width是1還是4,決定設(shè)置數(shù)據(jù)控制寄存器中是S3C2440_SDIDCON_DS_WORD還是S3C2440_SDIDCON_DS_BYTE,
等設(shè)置好了SDIDCON之后,接著再去發(fā)送對應(yīng)的帶數(shù)據(jù)讀的命令,然后接著處理的流程和之前舊的代碼是一樣的,即先去fifosta中找到fifo中有多少個數(shù)據(jù),然后一個個讀取,每次讀取1個字節(jié)還是4個字節(jié),由之前的bus width決定。
等讀完當(dāng)前fifo了再去重復(fù)讀取fifosta,再去判斷有多少個字節(jié)數(shù)據(jù)需要讀取,
這樣一點點把數(shù)據(jù)讀出來即可。
讀數(shù)據(jù)的過程中,需要通過讀取SDIDSTA得知數(shù)據(jù)的狀態(tài)是否正常,如果有錯誤,比如超時,CRC錯誤等,就退出。
此部分流程,基本和舊的代碼沒太大區(qū)別。
但是代碼調(diào)試過程中,這部分代碼,在讀取數(shù)據(jù)部分,始終出錯,讓我調(diào)試了很久,最后找到原因,竟然是自己不小心,在讀取了SDIDCON的值后,忘了把原來的bus width那一位給設(shè)置回去,所以再之前去設(shè)置bus width=4=word之后,此處還是用bus width=1=byte的模式來讀數(shù)據(jù),所以出現(xiàn)第一次讀SDIFSTA而獲得的FIFO中的字節(jié)數(shù),竟然是有奇數(shù)的,比如0x1c7,而不是期望的64啊之類的,應(yīng)該是4的倍數(shù)的,最后加上對應(yīng)的正確的設(shè)置后,后面的讀取數(shù)據(jù)就都對了。
【未解決的疑問:CMD8和CMD13超時】
在最后可以成功讀數(shù)據(jù)之后,卻也還是發(fā)現(xiàn)有兩個命令會超時:
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)
總結(jié)
以上是生活随笔為你收集整理的uboot环境下mmc操作_【记录】将Uboot 2011.06中mmc驱动移植到uboot 1.1.6的过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue 导入excel解析_【Vue 笔
- 下一篇: bootstraptable 加载完成_