/*
* Starting point for SDIO card init.
*/
int mmc_attach_sdio(struct mmc_host *host)
{
int err, i, funcs;
u32 ocr;
struct mmc_card *card;
BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_send_io_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_attach_bus(host, &mmc_sdio_ops);
if (host->ocr_avail_sdio)
host->ocr_avail = host->ocr_avail_sdio;
/*
* Sanity check the voltages that the card claims to
* support.
*/
if (ocr & 0x7F) {
printk(KERN_WARNING "%s: card claims to support voltages "
"below the defined range. These will be ignored.\n",
mmc_hostname(host));
ocr &= ~0x7F;
}
host->ocr = mmc_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
if (!host->ocr) {
err = -EINVAL;
goto err;
}
/*
* Detect and init the card.
*/
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
if (err)
goto err;
card = host->card;
/*
* Enable runtime PM only if supported by host+card+board
*/
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
/*
* Let runtime PM core know our card is active
*/
err = pm_runtime_set_active(&card->dev);
if (err)
goto remove;
/*
* Enable runtime PM for this card
*/
pm_runtime_enable(&card->dev);
}
/*
* The number of functions on the card is encoded inside
* the ocr.
*/
funcs = (ocr & 0x70000000) >> 28;
card->sdio_funcs = 0;
/*
* Initialize (but don't add) all present functions.
*/
for (i = 0; i < funcs; i++, card->sdio_funcs++) {
err = sdio_init_func(host->card, i + 1);
if (err)
goto remove;
/*
* Enable Runtime PM for this func (if supported)
*/
if (host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_enable(&card->sdio_func[i]->dev);
}
/*
* First add the card to the driver model...
*/
mmc_release_host(host);
err = mmc_add_card(host->card);
if (err)
goto remove_added;
/*
* ...then the SDIO functions.
*/
for (i = 0;i < funcs;i++) {
err = sdio_add_func(host->card->sdio_func[i]);
if (err)
goto remove_added;
}
mmc_claim_host(host);
return 0;
remove_added:
/* Remove without lock if the device has been added. */
mmc_sdio_remove(host);
mmc_claim_host(host);
remove:
/* And with lock if it hasn't been added. */
mmc_release_host(host);
if (host->card)
mmc_sdio_remove(host);
mmc_claim_host(host);
err:
mmc_detach_bus(host);
printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
mmc_hostname(host), err);
return err;
}
13行mmc_send_io_op_cond,通過CMD5查詢card支持的操作電壓,CMD5是sdio特有的,所以如果對該命令沒有反應說明卡槽裏的是sd/mmc卡。由於命令發送函數結構大體差不離,所以就不列出mmc_send_io_op_cond函數的具體內容,來看CMD5:
OCR-Operation Conditions Register,card支持的最小和最低電壓,這24bits的定義在“SDIO驅動(12)card的掃描流程”有詳細列出。mmc_send_io_op_cond執行過後,變量ocr的內容爲:
C:如果爲1的話,說明卡已經準備就緒ready。
Number of I/O functions:card支持的I/O總數,範圍0~7。
Memory Present:如果爲0說明card僅僅是一個I/O卡;1說明card還支持SD memory。
Stuff bits:保留,值爲0。
I/O OCR:card返回的Voltage support list。
17行mmc_attach_bus,爲每一個host分配獨有的總線handler:
/*
* Assign a mmc bus handler to a host. Only one bus handler may control a
* host at any given time.
*/
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
BUG_ON(!host);
BUG_ON(!ops);
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
BUG_ON(host->bus_ops);
BUG_ON(host->bus_refs);
host->bus_ops = ops;
host->bus_refs = 1;
host->bus_dead = 0;
spin_unlock_irqrestore(&host->lock, flags);
}
9、10行的檢測是防止NULL指針,16、17行防止對host重複執行attach bus,之前說過如果檢測出現異常系統會panic。
12行,記得吧在進入之前可是執行過獨佔訪問設置的:
mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
break;
if (freqs[i] < host->f_min)
break;
}
mmc_release_host(host);
關於sdio總線的mmc_sdio_ops,之前分析過它的detect函數實現,其他成員實現就略過不提了。
25~30行,card返回的ocr參數檢測,防止出現不支持的電壓值。不過按照spec,保留位佔8個bits,難道不是應該if (ocr & 0xFF) {}嗎?
32行mmc_select_voltage,選擇host和card都支持的最低操作電壓:
/*
* Mask off any voltages we don't support and select
* the lowest voltage
*/
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{
int bit;
ocr &= host->ocr_avail;
bit = ffs(ocr);
if (bit) {
bit -= 1;
ocr &= 3 << bit;
host->ios.vdd = bit;
mmc_set_ios(host);
} else {
pr_warning("%s: host doesn't support card's voltages\n",
mmc_hostname(host));
ocr = 0;
}
return ocr;
}
9行與過之後就是host、card都支持的電壓設置,11行返回ocr中第一個bit是1的位置,注意範圍計算方式[1,32]所以需要減去1,15行過後將mask off其他電壓,不過這裏3<<bit的話,如果ocr[bit+1]不爲零,那麼ocr[bit+1, bit]=0b11即bit+1位不被mask off。這是基於何種考慮?
45行正式開始card的初始化,複雜的函數:
/*
* Handle the detection and initialisation of a card.
*
* In the case of a resume, "oldcard" will contain the card
* we're trying to reinitialise.
*/
static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard, int powered_resume)
{
struct mmc_card *card;
int err;
BUG_ON(!host);
WARN_ON(!host->claimed);
/*
* Inform the card of the voltage
*/
if (!powered_resume) {
err = mmc_send_io_op_cond(host, host->ocr, &ocr);
if (err)
goto err;
}
/*
* For SPI, enable CRC as appropriate.
*/
if (mmc_host_is_spi(host)) {
err = mmc_spi_set_crc(host, use_spi_crc);
if (err)
goto err;
}
/*
* Allocate card structure.
*/
card = mmc_alloc_card(host, NULL);
if (IS_ERR(card)) {
err = PTR_ERR(card);
goto err;
}
if (ocr & R4_MEMORY_PRESENT
&& mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) {
card->type = MMC_TYPE_SD_COMBO;
if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
mmc_remove_card(card);
return -ENOENT;
}
} else {
card->type = MMC_TYPE_SDIO;
if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
mmc_remove_card(card);
return -ENOENT;
}
}
/*
* Call the optional HC's init_card function to handle quirks.
*/
if (host->ops->init_card)
host->ops->init_card(host, card);
/*
* For native busses: set card RCA and quit open drain mode.
*/
if (!powered_resume && !mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca);
if (err)
goto remove;
/*
* Update oldcard with the new RCA received from the SDIO
* device -- we're doing this so that it's updated in the
* "card" struct when oldcard overwrites that later.
*/
if (oldcard)
oldcard->rca = card->rca;
mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
}
/*
* Read CSD, before selecting the card
*/
if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
err = mmc_sd_get_csd(host, card);
if (err)
return err;
mmc_decode_cid(card);
}
/*
* Select card, as all following commands rely on that.
*/
if (!powered_resume && !mmc_host_is_spi(host)) {
err = mmc_select_card(card);
if (err)
goto remove;
}
if (card->quirks & MMC_QUIRK_NONSTD_SDIO) {
/*
* This is non-standard SDIO device, meaning it doesn't
* have any CIA (Common I/O area) registers present.
* It's host's responsibility to fill cccr and cis
* structures in init_card().
*/
mmc_set_clock(host, card->cis.max_dtr);
if (card->cccr.high_speed) {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
}
goto finish;
}
/*
* Read the common registers.
*/
err = sdio_read_cccr(card);
if (err)
goto remove;
/*
* Read the common CIS tuples.
*/
err = sdio_read_common_cis(card);
if (err)
goto remove;
if (oldcard) {
int same = (card->cis.vendor == oldcard->cis.vendor &&
card->cis.device == oldcard->cis.device);
mmc_remove_card(card);
if (!same)
return -ENOENT;
card = oldcard;
}
if (card->type == MMC_TYPE_SD_COMBO) {
err = mmc_sd_setup_card(host, card, oldcard != NULL);
/* handle as SDIO-only card if memory init failed */
if (err) {
mmc_go_idle(host);
if (mmc_host_is_spi(host))
/* should not fail, as it worked previously */
mmc_spi_set_crc(host, use_spi_crc);
card->type = MMC_TYPE_SDIO;
} else
card->dev.type = &sd_type;
}
/*
* If needed, disconnect card detection pull-up resistor.
*/
err = sdio_disable_cd(card);
if (err)
goto remove;
/*
* Switch to high-speed (if supported).
*/
err = sdio_enable_hs(card);
if (err > 0)
mmc_sd_go_highspeed(card);
else if (err)
goto remove;
/*
* Change to the card's maximum speed.
*/
mmc_set_clock(host, mmc_sdio_get_max_clock(card));
/*
* Switch to wider bus (if supported).
*/
err = sdio_enable_4bit_bus(card);
if (err > 0)
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
else if (err)
goto remove;
finish:
if (!oldcard)
host->card = card;
return 0;
remove:
if (!oldcard)
mmc_remove_card(card);
err:
return err;
}
20行,之前的mmc_send_io_op_cond動作第二個參數爲0,所以僅僅是探測一下;這裏傳入了ocr參數,那麼將等待card狀態ready後才返回。28~32行的SPI接口操作方式不予關注。
37~41行,mmc_alloc_card創建一個card設備
43~51行,即上面提到的sdio+memory混合的卡,MMC框架對其定義的類型爲MMC_TYPE_SD_COMBO。純粹的sdio卡的類型爲MMC_TYPE_SDIO。
64、65行,host controller提供了init_card回調的話則調用之,用來執行controller特定的card初始話。如果硬件廠商按照標準來的話自然不需要,但林子這麼大難免有不按套路出牌的,無論怎麼說該支持還得支持。
71行,通過CMD3獲取card的地址(RCA),CMD3的響應爲R6:
83行,bus有兩種模式:
MMC_BUSMODE_OPENDRAIN: 該模式用於card的初始化。
MMC_BUSMODE_PUSHPULL: 進入傳輸狀態前,設置bus模式爲pushpull模式。
89~95行,sdio卡不支持該操作。
101行,發送CMD7選中card,在standby和transfer狀態之間進行轉換,此處轉換到transfer狀態。
106~121行,說的就是那些不按套路設計硬件的廠商的產品,由host填充時序參數。
126行,sdio_read_cccr讀取CCCR(Card Common Control Registers)寄存器的值,這裏有個關係需要知道:
1、CCCR位於卡的CIA區域;
2、CIA區域訪問方式:host通過sdio專屬命令CMD52、功能號0訪問。
所以,看sdio_read_cccr函數:
static int sdio_read_cccr(struct mmc_card *card)
{
int ret;
int cccr_vsn;
unsigned char data;
memset(&card->cccr, 0, sizeof(struct sdio_cccr));
// SDIO_CCCR_CCCR = 0
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
if (ret)
goto out;
cccr_vsn = data & 0x0f;
if (cccr_vsn > SDIO_CCCR_REV_1_20) {
printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n",
mmc_hostname(card->host), cccr_vsn);
return -EINVAL;
}
card->cccr.sdio_vsn = (data & 0xf0) >> 4;
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
if (ret)
goto out;
if (data & SDIO_CCCR_CAP_SMB)
card->cccr.multi_block = 1;
if (data & SDIO_CCCR_CAP_LSC)
card->cccr.low_speed = 1;
if (data & SDIO_CCCR_CAP_4BLS)
card->cccr.wide_bus = 1;
if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data);
if (ret)
goto out;
if (data & SDIO_POWER_SMPC)
card->cccr.high_power = 1;
}
if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
if (ret)
goto out;
if (data & SDIO_SPEED_SHS)
card->cccr.high_speed = 1;
}
out:
return ret;
}
9行,mmc_io_rw_direct是CMD52的實現函數,其原型:
int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8 *out)
通過設置不同addr參數就可以讀取相應寄存器信息。這部分內容完全就是spec的實現,參照spec即可理解。
133行,sdio_read_common_cis讀取CIS(Card Information Structure)信息。這部分內容較多,只能單獨列出,參見“SDIO驅動(14)card的CIS讀取”。
137~145行,參數oldcard傳進來的是NULL,所以不予關心。147~158行,MMC_TYPE_SD_COMBO混合卡也不關心。
163~185行,這部分函數作用及原理參考spec都很容易理解。
至此,mmc_sdio_init_card函數就分析完了。
接着看mmc_attach_sdio函數,53~65行,又是PM的東西,71~72行,解析出function numbers。
77~87行,每一個function作爲一個device,由結構體sdio_func表徵,掛在sdio總線下面;sdio_init_func函數用來完成創建並初始化它。
93行,添加card到系統中(device_add)並標誌card爲Present狀態;101行,做同樣的事情。