cmd52命令发送 mmc_Linux SD/MMC/SDIO驱动分析(新)
一、SD/MMC/SDIO概念區(qū)分
SD(SecureDigital)與?MMC(MultimediaCard)
SD?是一種?flash memory card?的標準,也就是一般常見的?SD?記憶卡,而?MMC?則是較早的一種記憶卡標準,目前已經(jīng)被?SD?標準所取代。在維基百科上有相當詳細的?SD/MMC?規(guī)格說明:[http://zh.wikipedia.org/wiki/Secure_Digital]。
SDIO(SecureDigital I/O)
SDIO?是目前我們比較關(guān)心的技術(shù),SDIO?故名思義,就是?SD?的?I/O?接口(interface)的意思,不過這樣解釋可能還有點抽像。更具體的說明,SD?本來是記憶卡的標準,但是現(xiàn)在也可以把?SD?拿來插上一些外圍接口使用,這樣的技術(shù)便是?SDIO。
所以?SDIO?本身是一種相當單純的技術(shù),透過?SD?的?I/O?接腳來連接外部外圍,并且透過?SD?上的?I/O?數(shù)據(jù)接位與這些外圍傳輸數(shù)據(jù),而且?SD?協(xié)會會員也推出很完整的?SDIO stack?驅(qū)動程序,使得?SDIO?外圍(我們稱為?SDIO?卡)的開發(fā)與應用變得相當熱門。
現(xiàn)在已經(jīng)有非常多的手機或是手持裝置都支持?SDIO?的功能(SD?標準原本就是針對?mobile device?而制定),而且許多?SDIO?外圍也都被開發(fā)出來,讓手機外接外圍更加容易,并且開發(fā)上更有彈性(不需要內(nèi)建外圍)。目前常見的?SDIO?外圍(SDIO?卡)有:
· Wi-Fi card(無線網(wǎng)絡卡)
· CMOS sensor card(照相模塊)
· GPS card
· GSM/GPRS modem card
· Bluetooth card
· ?Radio/TV card(很好玩)
SDIO?的應用將是未來嵌入式系統(tǒng)最重要的接口技術(shù)之一,并且也會取代目前?GPIO?式的?SPI?接口。
SD/SDIO?的傳輸模式
SD?傳輸模式有以下?3?種:
· SPI mode(required)
· 1-bit mode
· ?4-bit mode
SDIO?同樣也支持以上?3?種傳輸模式。依據(jù)?SD?標準,所有的?SD(記憶卡)與?SDIO(外圍)都必須支持?SPI mode,因此?SPI mode?是「required」。此外,早期的?MMC?卡(使用?SPI?傳輸)也能接到?SD?插糟(SD slot),并且使用?SPI mode?或?1-bit mode?來讀取。
Secure digital I/Ocard,pin out
SD?的?MMCMode
SD?也能讀取?MMC?內(nèi)存,雖然?MMC?標準上提到,MMC?內(nèi)存不見得要支持?SPI mode(但是一定要支持?1-bit mode),但是市面上能看到的?MMC?卡其實都有支持?SPI mode。因此,我們可以把?SD?設定成?SPI mode?的傳輸方式來讀取?MMC?記憶卡。
SD?的?MMC Mode?就是用來讀取?MMC?卡的一種傳輸模式。不過,SD?的?MMC Mode?雖然也是使用?SPI mode,但其物理特性仍是有差異的:
· MMC?的?SPI mode?最大傳輸速率為?20 Mbit/s;
· SD?的?SPI mode?最大傳輸速率為?25 Mbit/s。
為避免混淆,有時也用?SPI/MMC mode?與?SPI/SD mode?的寫法來做清楚區(qū)別
參考網(wǎng)站:https://www.sdcard.org/developers/overview/capacity/
http://www.interfacebus.com/Secure_Digital_IO_Card_Pinout.html
二、MMC子系統(tǒng)介紹
MMC代碼分布
MMC子系統(tǒng)代碼主要在drivers/mmc目錄下,共有三個目錄:
Card:存放閃存卡(塊設備)的相關(guān)驅(qū)動,如MMC/SD卡設備驅(qū)動,SDIOUART;
Host:針對不同主機端的SDHC、MMC控制器的驅(qū)動,這部分需要由驅(qū)動工程師來完成;
Core:整個MMC的核心層,這部分完成不同協(xié)議和規(guī)范的實現(xiàn),為host層和設備驅(qū)動層提供接口函數(shù)。
MMC子系統(tǒng)框架
Linux MMC子系統(tǒng)主要分成三個部分:
MMC核心層:完成不同協(xié)議和規(guī)范的實現(xiàn),為host層和設備驅(qū)動層提供接口函數(shù)。MMC核心層由三個部分組成:MMC,SD和SDIO,分別為三類設備驅(qū)動提供接口函數(shù);
Host 驅(qū)動層:針對不同主機端的SDHC、MMC控制器的驅(qū)動;
Client 驅(qū)動層:針對不同客戶端的設備驅(qū)動程序。如SD卡、T-flash卡、SDIO接口的GPS和wi-fi等設備驅(qū)動。
三、SD 總線協(xié)議
SD總線通信是基于指令和數(shù)據(jù)比特流,起始位開始和停止位結(jié)束。SD總線通信有三個元素:
Command:由host發(fā)送到卡設備,使用CMD線發(fā)送;
Response:從card端發(fā)送到host端,作為對前一個CMD的相應,通過CMD線發(fā)送;
Data:即能從host傳輸?shù)絚ard,也能從card傳輸?shù)絟ost,通過data線傳輸。
Commands
以下是四種用于控制卡設備的指令類型,每個command都是固定的48位長度:
1、broadcast commands(bc), no response:廣播類型的指令,不需要有響應;
2、broadcast commands with response(bcr):廣播類型的指令且需要響應;
3、addressed(point-to-point) commands(ac):由HOST發(fā)送到指定的卡設備,沒有數(shù)據(jù)的傳輸;
4、address(point-to-point) data transfercommands(adtc):由HOST發(fā)送到指定的卡設備且伴隨有數(shù)據(jù)傳輸。
指令格式:
Card register
幾個主要的寄存器:OCR,CID,CSD,RCA和SCR。
Operation condition register(OCR):32位的OCR包含卡設備支持的工作電壓表;
Card identification number register (CID):包含用于在卡識別階段的卡信息,包括制造商ID,產(chǎn)品名等;
Card specific data register(CSD):CSD寄存器提供了如何訪問卡設備的信息,包括定義了數(shù)據(jù)格式,錯誤校驗類型,最大訪問次數(shù),數(shù)據(jù)傳輸率等;
Relative card address register(RCA):存放在卡識別階段分配的相對卡地址,缺省相對卡地址為0000h;
SD card configuration register(SCR):SCR是一個配置寄存器,用于配置SD memory card的特殊功能。
Response
所有的response都通過CMD線發(fā)送到host端,R4和R5響應類型是SDIO中特有的:
1、R1(normal response command):用來響應常用指令;
2、R2(CID,CSD register):用來響應CMD2和CMD10或CMD9,并把CID或CSD寄存器作為響應數(shù)據(jù);
3、R3(OCR register):用來響應ACMD41指令,并把OCR寄存器作為響應數(shù)據(jù);
4、R6(published RCA response):分配相對卡地址的響應;
5、R7(card interface condition):響應CMD8,返回卡支持的電壓信息;
6、R4(CMD5):響應CMD5,并把OCR寄存器作為響應數(shù)據(jù);
7、R5(CMD52):CMD52是一個讀寫寄存器的指令,R5用于CMD52的響應;
Response 格式:
***詳情請參考spec***
四、SD初始化流程
當host上電后,使所有的卡設備處于卡識別模式,完成設置有效操作電壓范圍,卡識別和請求卡相對地址等操作。
1、發(fā)送指令CMD0使卡設備處于idle狀態(tài);
2、發(fā)送指令CMD8,如果卡設備有response,說明此卡為SD2.0以上;
3、發(fā)送指令CMD55+ACMD41,該指令是用來探測卡設備的工作電壓是否符合host端的要求;
在發(fā)送ACMD41這類指令之前需要先發(fā)送CMD55指令,在SDIO中ACMD41指令被CMD5替代。
4、發(fā)送指令CMD11轉(zhuǎn)換工作電壓到1.8V;
5、發(fā)送指令CMD2獲取CIA;
6、發(fā)送指令CMD3獲取RCA(relative card address)
SD初始化分析
系統(tǒng)上電時,SDI控制器會去掃描總線上的所有設備,然后對掛在總線上卡設備進行初始化。進行掃描和初始化工作都是由mmc_scan函數(shù)來完成,以下是Linux驅(qū)動中初始化流程圖(感謝同事Linkin的圖)。
SDIO、SD和MMC這三者的初始化流程稍有不同,是向下兼容的。
轉(zhuǎn)載:http://blog.csdn.net/paul_liao/article/details/7685869
五、SD卡調(diào)試關(guān)鍵點:
1. 上電時要延時足夠長的時間給?SD?卡一個準備過程,在我的程序里是?5?秒,根據(jù)不同的卡設置不同的延時時間。?SD?卡初始化第一步在發(fā)送?CMD?命令之前,在片選有效的情況下首先要發(fā)送至少?74?個時鐘,否則將有可能出現(xiàn)?SD?卡不能初始化的問題。
2.?SD?卡發(fā)送復位命令?CMD0?后,要發(fā)送版本查詢命令?CMD8?,返回狀態(tài)一般分兩種,若返回?0x01?表示此?SD?卡接受?CMD8,?也就是說此?SD?卡支持版本?2?;若返回?0x05?則表示此?SD?卡支持版本?1?。因為不同版本的?SD?卡操作要求有不一樣的地方,所以務必查詢?SD?卡的版本號,否則也會出現(xiàn)?SD?卡無法正常工作的問題。
3. 理論上要求發(fā)送?CMD58?獲得?SD?卡電壓參數(shù),但實際過程中由于事先都知道了?SD?卡的工作電壓,因此可省略這一步簡化程序。協(xié)議書上也建議盡量不要用這個命令。
4.?SD?卡讀寫超時時間要按照協(xié)議說明書書上的給定值?(?讀超時:?100ms?;寫超時:?250ms)?,這個值要在程序中準確計算出來,否則將會出現(xiàn)不能正常讀寫數(shù)據(jù)的問題。我自己定義了一個計算公式:超時時間?=(?8/clk?)*arg?。
5.?2GB?以內(nèi)的?SD?卡?(?標準卡?)?和?2GB?以上的?SD?卡?(?大容量卡?)?在地址訪問形式上不同,這一點尤其要注意,否則將會出現(xiàn)無法讀寫數(shù)據(jù)的問題。如標準卡在讀寫操作時,對讀或?qū)懨盍钆飘斨械牡刂酚蚍踔?0x10?,表示對第?16?個字節(jié)以后的地址單元進行操作?(?前提是此?SD?卡支持偏移讀寫操作?)?,而對大容量卡讀或?qū)懨盍钆飘斨械牡刂酚蚍踔?0x10?時,則表示對第?16?塊進行讀寫操作,而且大容量卡只支持塊讀寫操作,塊大小固定為?512?字節(jié),對其進行字節(jié)操作將會出錯。
6. 對某一塊要進行寫操作時最好先執(zhí)行擦出命令,這樣寫入的速度就能大大提高。進行擦除操作時不管是標準卡還是大容量卡都按塊操作執(zhí)行,也就是一次擦除至少?512?字節(jié)。
7. 對標準卡進行字節(jié)操作時,起始和終止必須在一個物理扇區(qū)內(nèi),否則將不能進行讀寫操作。實際操作過程中建議用塊操作以提高效率。不管是標準卡還是大容量卡一個讀寫命令只能對一個塊進行操作,不允許跨物理層地址操作。
8. 在寫數(shù)據(jù)塊前要先寫入若干個?dummy data?字節(jié),寫完一個塊數(shù)據(jù)時,主機要監(jiān)測?MISO?數(shù)據(jù)線,如果從機處于忙狀態(tài)這根數(shù)據(jù)線會保持低電平,這樣主機就可以根據(jù)這根數(shù)據(jù)線的狀態(tài)以決定是否發(fā)送下一個命令,在從機沒有釋放?MISO?數(shù)據(jù)線之前,主機絕對不能執(zhí)行其他命令,否則將會導致寫入的數(shù)據(jù)出錯,而且從機也不會響應主機的命令。
9. 在?SPI?模式下,?CRC?校驗是被忽略的,但依然要求主從機發(fā)送?CRC?碼,只是數(shù)值可以是任意值,一般主機的?CRC?碼通常設為?0x00?或?0xFF?。
讀多塊操作和寫多塊操作的傳輸停止形式不一樣,讀多塊操作時用用命令 CMD12 終止傳輸,而寫多塊操作時用 Stop Tran Token( 停止傳輸令牌,值為 0xFD) 終止傳輸。
----------------------------------------------------------------------------------------
1、初始化步驟:
(1) 延時至少 74clock,等待SD卡內(nèi)部操作完成,在MMC協(xié)議中有明確說明。
(2) CS低電平選中SD卡。
(3) 發(fā)送 CMD0 ,需要返回 0x01 ,進入 Idle 狀態(tài)
(4) 為了區(qū)別SD卡是2.0還是1.0,或是MMC卡,這里根據(jù)協(xié)議向上兼容的原理,首先發(fā)送只有SD2.0才有的命令CMD8,如果CMD8返回無錯誤,則初步判斷為2.0卡,進一步發(fā)送命令循環(huán)發(fā)送 CMD55+ACMD41 ,直到返回 0x00 ,確定SD2.0卡初始化成功,進入Ready 狀態(tài),再發(fā)送CMD58命令來判斷是HCSD還是SCSD,到此SD2.0卡初始化成功 。如果CMD8返回錯誤則進一步判斷為1.0卡還是MMC卡,循環(huán)發(fā)送CMD55+ACMD41 ,返回無錯誤,則為SD1.0卡,到此SD1.0卡初始成功,如果在一定的循環(huán)次數(shù)下,返回為錯誤,則進一步發(fā)送CMD1進行初始化,如果返回無錯誤,則確定為MMC卡,如果在一定的次數(shù)下,返回為錯誤,則不能識別該卡,初始結(jié)束。
(5)CS拉高。
2、讀步驟:
(1) 發(fā)送 CMD17 (單塊)或 CMD18 (多塊)讀命令,返回 0x00
(2) 接收數(shù)據(jù)開始令牌 0xfe (或 0xfc ) + 正式數(shù)據(jù) 512Bytes + CRC 校驗 2Bytes, 默認正式傳輸?shù)臄?shù)據(jù)長度是 512Bytes ,可用 CMD16 設置塊長度。
3、 寫步驟:
(1) 發(fā)送 CMD24 (單塊)或 CMD25 (多塊)寫命令,返回 0x00
(2) 發(fā)送數(shù)據(jù)開始令牌 0xfe (或 0xfc ) + 正式數(shù)據(jù) 512Bytes + CRC 校驗 2Bytes
4、 擦除步驟:
(1) 發(fā)送 CMD32 ,跟一個參數(shù)來指定首個要擦除的起始地址( SD 手冊上說是塊號)
(2) 發(fā)送 CMD33, ,指定最后的地址
(3) 發(fā)送 CMD38 ,擦除指定區(qū)間的內(nèi)容
此 3 步順序不能顛倒。
六、SD卡的命令格式及解析
1.SD卡命令組成
SD卡的指令由6字節(jié)(Byte)組成,如下:
Byte1:0 1 x x x x x x(命令號,由指令標志定義,如CMD39為100111即16進制0x27,那么完整的CMD39第一字節(jié)為01100111,即0x27+0x40)
Byte2-5:Command Arguments,命令參數(shù),有些命令沒有參數(shù)
Byte6:前7位為CRC(Cyclic Redundacy Check,循環(huán)冗余校驗)校驗位,最后一位為停止位0
2.SD卡的命令
SD卡命令共分為12類,分別為class0到class11,不同的SDd卡,主控根據(jù)其功能,支持不同的命令集,如下:
Class0 :(卡的識別、初始化等基本命令集)
CMD0:復位SD 卡.
CMD1:讀OCR寄存器.
CMD9:讀CSD寄存器.
CMD10:讀CID寄存器.
CMD12:停止讀多塊時的數(shù)據(jù)傳輸
CMD13:讀 Card_Status 寄存器
Class2 (讀卡命令集):
CMD16:設置塊的長度
CMD17:讀單塊.
CMD18:讀多塊,直至主機發(fā)送CMD12為止 .
Class4(寫卡命令集) :
CMD24:寫單塊.
CMD25:寫多塊.
CMD27:寫CSD寄存器 .
Class5 (擦除卡命令集):
CMD32:設置擦除塊的起始地址.
CMD33:設置擦除塊的終止地址.
CMD38: 擦除所選擇的塊.
Class6(寫保護命令集):
CMD28:設置寫保護塊的地址.
CMD29:擦除寫保護塊的地址.
CMD30: Ask the card for the status of the write protection bits
class7:卡的鎖定,解鎖功能命令集
class8:申請?zhí)囟罴?。
class10 -11 :保留
3.有關(guān)sd卡驅(qū)動和fat fs的實現(xiàn)用了3個文件來實現(xiàn)。
sdboot.c為sd的驅(qū)動(可理解為pdd)層,主要實現(xiàn)一些對sd控制器的配置以及一些基本sd命令的實現(xiàn)和對sd 卡的操作。
sdmmc.c實現(xiàn)了從sd卡讀取nk并跳到內(nèi)存去運行的代碼(基本可以理解為sd驅(qū)動的mdd層)。
sdfat.c文件就是實現(xiàn)fat fs的。mdd層通過fatfs來對pdd層操作以實現(xiàn)讀取文件。
在整個過程中遇到了很多問題,現(xiàn)在列舉如下:
1)sd卡初始化問題
配置gpio有關(guān)sd的功能:SDCMD, SDDAT[3:0]。
使能CLKCON中的SDI位。
時鐘以及計算公式:SDIPRE?? = PCLK/(CLK)-1;INICLK=300000;SDCLK=24000000; MMCCLK=?15000000
cmd0-cmd55-cmd41-cmd2-cmd3-cmd7-cmd6-cmd17
2)對sd卡操作問題
SD卡包括:一個標識寄存器CID,一個相應地址寄存器RCA,一個其他參數(shù)寄存器CSD。
對sd卡的操作是驅(qū)動通過sd controller來發(fā)相應的命令以達到讀寫等操作的:發(fā)送命令通過SDICmdCon[7:0]的除了開始2bit:CmdIndex放置要發(fā)送的命令號;SDICmdCon[8]開始發(fā)送命令來完成的。
檢測卡的插入,直接用中斷引腳的電平來判斷。
判斷插入的卡是否是sd卡,用命令cmd55和cmd41,因為mmc卡對cmd55不做回應。
命令9 就是獲取sd卡中csd寄存器的值的,該值包括很多sd卡的信息,其中就有sd卡的容量。這個值在sd卡接收到cmd9之后會以response的形式存放在sd控制器的SDI Response Register[0,1,2,3]中。在執(zhí)行cmd9,cmd10等這樣的命令的時候,卡的狀態(tài)應該是不選中的,或直接在執(zhí)行它們之前發(fā)送 cmd7(0)不選中卡,不然的話會timeout。
用cmd17 來讀取單個block的數(shù)據(jù),該命令要帶地址參數(shù)(該參數(shù)通過cmd3命令來獲取),然后根據(jù)SDIDSTA和SDIFSTA狀態(tài)值來從sd 控制器的SDIDAT寄存器中讀出要讀的數(shù)據(jù)。該命令與cmd9相反,在執(zhí)行它之前要選中卡。讀完一個block之后要做一些善后工作,為下次讀取做好準備,不然的話checkcmdend就要一直循環(huán)了。因為用的是每次都讀一個block,并地址要以block對齊,這樣就要考慮要讀取的地址是否是 block對齊的,長度是否夠一個block。
SDIDCON這個數(shù)據(jù)控制寄存器也很重要,一些對數(shù)據(jù)的操作形式就是在這里設置的。
3)fat文件系統(tǒng)問題
根據(jù)MBR找到分區(qū)表,根據(jù)分區(qū)表找到該分區(qū)MBR[446B+4個分區(qū)表(每個16B)+2B結(jié)束符)
分區(qū)表中的第9-12字節(jié)為該分區(qū)的啟始地址(單位沒sector),第13-16字節(jié)為分區(qū)的長度(單位也是sector)
http://hjx5548.blog.163.com/blog/static/563676392009111704249875/
六、實例
一、概述
最近在研究WIFI驅(qū)動,驅(qū)動模塊為broamd4330,基于SDIO接口,所以趁機研究了一下內(nèi)核中對于SDIO設備的注冊。
(我使用的linux內(nèi)核版本為3.2.0??? 硬件為samsung 4412)
在介紹內(nèi)核之前,有必要先了解一下MMC? SD? SDIO三種卡,從發(fā)展歷程來看,是先有MMC卡,后來有SD卡,這兩種都是純粹的存儲卡,而SDIO是什么呢,從字面意思理解,應該是SD+IO,也就是既有存儲功能,又有IO控制功能,不過也有純IO功能的SDIO設備(本人用到的WIFI模塊就是這種)。并且,這三種卡可以使用同一個插槽,系統(tǒng)還能正確的識別!!,可能是由于歷史原因,在開始有Linux的時候,還只存在mmc卡(不存在SD和SDIO卡),所以在linux系統(tǒng)里面關(guān)于這三種卡的名稱統(tǒng)統(tǒng)用“mmc“來命名。
下面來看一下CPU與WIFI模塊的物理連接圖
從圖上可以看出,我們的WIFI模塊接的是CPU上的mmc3,數(shù)據(jù)線,時鐘線以及命令線都一一對應。
當然在CPU一端,對于mmc3模塊,還有一個很重要的引腳--“xmmc3CDn”腳,CPU就是根據(jù)該引腳的電平高低來判斷mmc3模塊上是否有卡接入,如果電平為低,表示有卡,如果為高,表示無卡,筆者這里將該引腳固定拉低。
同時在WIFI模塊一端,也有一個很重要的引腳--“WL_SDIO_SPI_HSCI_SEL”引腳?? ,它是用來選擇模塊是工作在SD模式(低電平),還是SPI模式(高電平),筆者這里也將該引腳固定拉低。
好了,簡單的介紹了一些概念以及硬件后,還是要回歸到程序上,從大的方面來講,MMC/SD/SDIO的驅(qū)動程序主要分為兩大塊,主設備驅(qū)動和從設備驅(qū)動。對于上面的例子來說,CPU上的MMC3模塊就是主設備,而WIFI模塊就是從設備。該系列的博文就是分析MMC主設備在內(nèi)核中的注冊,以及對于同一個mmc插槽,系統(tǒng)是如何區(qū)分出MMC SD 以及SDIO設備的。
二、host注冊過程
上面說到了MMC/SD/SDIO(以下簡稱MMC)的驅(qū)動從大的方面來說分為主設備驅(qū)動和從設備驅(qū)動,那本文就來詳細的講述主設備驅(qū)動注冊的過程。
MMC主設備(也就是host)指的是集成于CPU內(nèi)部的MMC controller,筆者用的是4412芯片,從datasheet可以看出,里面集成了四個MMC controller,分別是mmc0,mmc1,mmc2,mmc3。 并且從上一篇文章我們知道,WIFI模塊是接在mmc3 這個host上面。
在linux系統(tǒng)中,將每個host設備封裝成platform_device來逐一進行注冊。
對于筆者所使用的內(nèi)核(3.2.0版本)來說,每一個host設備所對應的platform_device文件位于目錄($KERNEL_SOURCE)/arch/arm/plat-samsung下,分別為dev-hsmmc.c,dev-hsmmc1.c,dev-hsmmc2.c,dev-hsmmc3.c,為了與實際WIFI模塊對應,我們重點進入dev-hsmmc3.c文件看一看:
從上圖可以看出,該文件里面定義了一個名為s3c_device_hsmmc3的platform_device,但是定義好了的platform_device還需要有一個注冊的過程,該過程就發(fā)生在文件($KERNEL_SOURCE)/arch/arm/mach-exynos/mach-$(BOARD).c中,其中有如下的一個函數(shù)調(diào)用:
它的行為就是將數(shù)組skd4x12_devices里面的每一個platform_device項一一注冊進系統(tǒng),并且這個數(shù)組里面就包含了上面所定義的s3c_device_hsmmc3:
所以總結(jié)來說,系統(tǒng)化在初始化的時候,就已經(jīng)將s3c_device_hsmmc3(也就是那個host? mmc3)注冊進了platform總線(其他的mmc0,mmc1,mmc2都是一個道理)。
當然,對于熟悉platform機制的朋友來說,此時僅僅只是注冊了platform_device ,而對應的platform_driver還沒有注冊。
下面就來說說這個platform_driver的注冊,它是在$(KERNEL_SOURCE)/drivers/mmc/host目錄下的sdhci-s3c.c文件中進行的,該文件中有如下的一個注冊函數(shù)調(diào)用:
其中的參數(shù)sdhci_s3c_driver就是上面所說的platform_driver,它也是定義在sdhci-s3c.c文件中,來看一下:
在對sdhci_s3c_driver進行注冊的過程中,系統(tǒng)會根據(jù)sdhci_s3c_driver->driver.name成員變量(此處是“s3c-sdhci”)在platform_bus 總線上尋找同名字的platform_dvice(這個過程稱之為“探測”),通過上面對s3c_device_hsmmc3的注冊分析,發(fā)現(xiàn)s3c_device_mmc3.name也剛好是“s3c-sdhci”,所以他倆剛好可以配對,探測成功,同時當大家查閱s3c_device_hsmmc,s3c_device_hsmmc1以及s3c_device_hsmmc2的時候發(fā)現(xiàn)他們的name成員變量都是“s3c-sdhci”,,所以會有四次成功的探測,每一次探測成功,就會調(diào)用sdhci_s3c_driver.probe函數(shù)---sdhci_s3c_probe,這個函數(shù)至關(guān)重要,在整個驅(qū)動注冊過程中起著核心作用。
上面文章說到了探測函數(shù)sdhci_s3c_probe,現(xiàn)在就來仔細分析這個函數(shù)的作用:
在分析代碼之前,先簡要的概括一下這個函數(shù)的功能:
1、既然是講host的注冊,那么首先必須構(gòu)造出一個host,這個host就是通過sdhci_alloc_host函數(shù)來構(gòu)造出來的,它是一個struct sdhci_host類型的結(jié)構(gòu)體。同時,也通過mmc_alloc_host函數(shù)構(gòu)造了一個struct mmc_host的結(jié)構(gòu)體變量mmc。
2、初始化host的時鐘,設置host的gpio等等其他一些“亂七八糟”的參數(shù)初始化(需要的時候再詳細分析)。
3、通過sdhci_add_host函數(shù)來注冊host。
下面重點來看sdhci_add_host函數(shù)
該函數(shù)主要是對mmc的注冊,同樣mmc也有很多的參數(shù),先來看看他的操作函數(shù)集mmc->ops = &sdhci_ops
其中,request函數(shù)指針指向的函數(shù)用來處理host向從設備發(fā)送命令的請求,
set_ios用來設置電源、時鐘等等之類(需要重點關(guān)注),
get_ro用來判斷是否寫保護
再來看該函數(shù)里面的中斷注冊部分
我們先看一下mmc_add_host這個函數(shù),它的功能就是通過device_add函數(shù)將設備注冊進linux設備模型,最終的結(jié)果就是在sys/bus/platform/devices目錄下能見到s3c-sdhci.1,s3c-sdhci.2,s3c-sdhci.3設備節(jié)點。
中斷注冊函_irq的第一個參數(shù)中斷號就取自于s3c_device_hsmmc3.resource里面的irq參數(shù),sdhci_irq就是中斷服務程序,該中斷函數(shù)一般在插卡、拔卡或者從設備反饋給host信息時會被調(diào)用數(shù)request
中斷服務程序
程序首先讀取寄存器NORINTSTSn的值,該寄存器中有兩個bit分別來表示卡的插入與拔出過程(注意,必須是動態(tài)變化過程,才會讓相應的兩個bit置1),那么接下來的if語句就是從該寄存器的那兩個bit來判斷是否有卡的插入或拔出,并同時清除這兩個bit,準備下一次的檢測,緊接著就調(diào)用中斷的下半部分函數(shù) sdhci_tasklet_card,其實這個函數(shù)也沒做什么事情,就是判讀如果此時有卡的話就通過mmc_detect_chang函數(shù)調(diào)用mmc_rescan函數(shù)。從這個函數(shù)的名字都可以猜出個八九不離十,它的功能就是掃描所插入的卡。
掃描卡的程序
這個函數(shù)我們重點關(guān)注上述兩個地方,其實真正的掃描動作發(fā)生在函數(shù)mmc_rescan_try_freq函數(shù)里面,該函數(shù)的第二個參數(shù)表示以什么樣的頻率去進行掃描,那么可選的頻率值在那個數(shù)組freqs里面,一般當用某個頻率值掃描成功后,就直接退出了,否則,會以下一個更低的頻率值來掃描,筆者所使用的WIFI模塊就是以400KHz的頻率掃描成功的。
掃描過程
該函數(shù)首先發(fā)送復位命令(不過該命令只有SDIO類型的卡才能夠識別),然后發(fā)送CMD0,讓設備進入IDLE模式,緊接著發(fā)送CMD8,獲取該卡所支持的電壓值,最后就是重點了(從1998-2003行),從所調(diào)用的各個函數(shù)名字可以看出,它是在試探該卡是否為SDIO? SD? MMC?
那么接下來的文章就是要分析上面的三個函數(shù),看它是如何識別SDIO、SD、MMC的。
三、SDIO的識別和操作
從上面文章的最后,我們知道host在掃描卡的過程中,其識別的順序為SDIO? SD MMC,并且從它的注釋可以看出,這個順序是很重要的。那這篇文章,我們就看看SDIO的識別過程,它對應的函數(shù)就是mmc_attach_sdio(host)?(函數(shù)位于文件drivers/mmc/core/sdio.c)
這個函數(shù)大概來說做了如下的工作
1、向卡發(fā)送CMD5命令,該命令有兩個作用:
第一,通過判斷卡是否有反饋信息來判斷是否為SDIO設備(只有SDIO設備才對CMD5命令有反饋,其他卡是沒有回饋的);
第二,如果是SDIO設備,就會給host反饋電壓信息,就是說告訴host,本卡所能支持的電壓是多少多少。
2、host根據(jù)SDIO卡反饋回來的電壓要求,給其提供合適的電壓。
3、初始化該SDIO卡
4、注冊SDIO的各個功能模塊
5、注冊SDIO卡
對于以上功能的具體解釋,下面將結(jié)合程序娓娓道來
1、CMD5命令的發(fā)送
第789行的函數(shù)就是發(fā)送的CMD5命令,如果卡對該命令有回饋的話,err就是0,否則,err為非0,直接退出了;并且需要重點說明的一點就是,該函數(shù)的最后一個參數(shù)ocr,它是存儲反饋命令的,SDIO設備對CMD5的反饋命令為R4,下面來仔細分析一下這個R4,因為后面要用到這個R4命令。從SDIO spec文檔里面,我們能得到R4命令的格式
從上圖可以看出,該命令有48位,但我們的ocr變量是32位的,那怎么存儲呢?系統(tǒng)就去掉原命令的開頭8位以及結(jié)尾的8位,只保留中間的32為,也就是截短后的命令格式是如下:
具體各位的描述如下:
C?--???我還不知道
Number 0f IO functions?? --?每個SDIO設備都有功能塊,這三位就記錄了該設備有多少個功能塊,最多7個
Memory Present –?指明該設備是純粹只有功能塊的設備,還是同時包含了存儲空間,如果為0就是前者,如果是1就是后者
Stuff Bits? --?沒有實際用途一般為0
I/O OCR –?該設備所能支持的電壓范圍(具體描述見sdio spec)
2、配置電壓
ocr就是我們上面講的反饋命令R4(截短之后的32位),那么ocr&0x7f的意義是什么呢?從R4的格式就可以看出來,其低24位就代表了所能支持的電壓范圍,我們再來詳細的看一下這24位的OCR格式
現(xiàn)在應該可以知道ocr&0x7f的意義了吧,就是擯棄那些保留的電壓范圍。
重點關(guān)注mmc_select_voltage
第1080行的相與 過程就是判斷host實際所支持的電壓與card所需要的電壓是否匹配,如果匹配,那么ocr的值就非0,否則就為0
簡單介紹下第1082行的ffs函數(shù),它的作用就是返回參數(shù)中第一個為1的bit的位置(ffs(0)=0,ffs(1)=1,ffs(8)=4),那么該函數(shù)用在這里的作用就是取出card需要的實際電壓是多少;
第1090行的mmc_set_ios函數(shù)里面通過調(diào)用sdhci_set_power將host->ios.vdd所代表的電壓寫入寄存器PWRCONn中 完成那個對電壓的重新配置(想要了解更詳細的過程,請跟蹤源代碼)
3、初始化SDIO卡
第821行就是初始化SDIO卡的函數(shù)? 這個函數(shù)很長,也很重要,這里筆者就不列出其程序代碼了,只是列出其中最重要的幾條:
1、通過函數(shù)mmc_alloc_card分配一個mmc_card的變量card
2、通過讀取R4命令中的bit27(也就是Memory Present)來判斷此卡是純IO卡 ,還是同時包含存儲功能。筆者使用的WIFI模塊為純IO功能,所以card->type = MMC_TYPE_SDIO(這個很重要,以后會用到) (接下來重點分析MMC_TYPE_SDIO的情況)
3、通過發(fā)送CMD3命令獲取設備的從地址(relative addr),并且存放在變量card->rca中。筆者使用的WIFI模塊的card->rca = 1
4、通過發(fā)送CMD7,選中相應從地址的卡
5、通過調(diào)用函數(shù)mmc_set_clock設置卡工作的時鐘頻率
6、通過發(fā)送CMD52命令,設置4位數(shù)據(jù)傳輸模式
4、注冊SDIO功能模塊
847行的變量funcs存儲該SDIO卡所包含的IO功能塊的個數(shù),851行到857行就是逐一初始化各個IO功能塊,下面來重點看一下該函數(shù)的內(nèi)容:
第71行就是分配sdio_func結(jié)構(gòu)體變量,該結(jié)構(gòu)體存儲了功能塊的參數(shù)。
第75行就是給功能塊編號,編號是從1到7(因為一個SDIO設備最多只有7個功能塊),存儲在變量func->num中
第78行就是讀取SDIO卡中的FBR寄存器中關(guān)于該卡的功能類型的數(shù)據(jù),存儲在func->class變量中(具體關(guān)于FBR寄存器內(nèi)容,可以參考SDIO spec文檔)
第82行就是讀取SDIO卡中的CIS寄存器的內(nèi)容
上面的程序就是將功能模塊逐個的注冊進設備模型,這里想重點說明一下注冊的名稱(name),它是由三部分組成的,每部分之間用冒號隔開,(即 host的名稱:rca:功能塊編號)。
具體到筆者使用的WIFI模塊,因為其host名稱是mmc2? ,rca = 1,并且有兩個功能模塊(功能模塊編號分別是1和2),所以在/sys/bus/sdio/devices目錄下能見到如下兩個設備名
mmc2:0001:1
mmc2:0001:2
5、注冊SDIO卡
上面的mmc_add_card函數(shù)就是注冊card了(這個card是在第3部分,初始化SDIO卡 里面分配和定義的)
第259行就是給card命名,格式為host名字:從地址,對于筆者的WIFI模塊 就是mmc2:0001
第261到273行就是根據(jù)card->type來分辨出card的類型,給賦予相應的字符串,筆者的WIFI模塊就是"SDIO"
第275行就是打印信息,具體不解釋 筆者的打印信息為? mmc2:new high speed SDIO card at address 0001(通常可以通過查看內(nèi)核啟動信息中是否有該語句來判斷card是否被正確識別)
第283行 就是將card注冊進linux設備模型? 注冊結(jié)果就是可以在/sys/bus/mmc/devices目錄下見到card?的名字,筆者的就是mmc2:0001
總結(jié)
以上是生活随笔為你收集整理的cmd52命令发送 mmc_Linux SD/MMC/SDIO驱动分析(新)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 获取下月第一天_获取当前月 下月 下下月
- 下一篇: 你的gpu驱动程序不满足_英特尔图形驱动