mmc_sd_init_card剩下的關於UHS-I的分支結構。linux
uhs-I的初始化流程圖如圖:app
紅線標出的部分是已經作了的事,與上一篇那個流程圖是一致的,以後就是if分支中作的事。函數
if分支中的函數mmc_sd_init_uhs_card:ui
/* * UHS-I specific initialization procedure */ static int mmc_sd_init_uhs_card(struct mmc_card *card) { int err; u8 *status; if (!card->scr.sda_spec3)//sd卡3.0版本才加入的UHS-I return 0; if (!(card->csd.cmdclass & CCC_SWITCH))//判斷是否支持class10命令,CMD6屬於該類 return 0; status = kmalloc(64, GFP_KERNEL);//CMD6的應答 if (!status) { pr_err("%s: could not allocate a buffer for " "switch capabilities.\n", mmc_hostname(card->host)); return -ENOMEM; } /* Set 4-bit bus width */ if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&//host是否支持4位數據線寬度 (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {//卡是否支持4位數據線寬度模式 err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);//發送ACMD6切換. if (err) goto out; mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);//host端的設置. } /* * Select the bus speed mode depending on host * and card capability. */ sd_update_bus_speed_mode(card);/*這個函數是找一個card和host都支持的速度,相似上面對數據線寬度的操做,spec上有定義: Bus Speed Mode (using 4 parallel data lines) (1) Default Speed mode: 3.3V signaling, Frequency up to 25 MHz, up to 12.5 MB/sec (2) High Speed mode: 3.3V signaling, Frequency up to 50 MHz, up to 25 MB/sec (3) SDR12: UHS-I 1.8V signaling, Frequency up to 25 MHz, up to 12.5MB/sec (4) SDR25: UHS-I 1.8V signaling, Frequency up to 50 MHz, up to 25MB/sec (5) SDR50: UHS-I 1.8V signaling, Frequency up to 100 MHz, up to 50MB/sec (6) SDR104: UHS-I 1.8V signaling, Frequency up to 208 MHz, up to 104MB/sec (7) DDR50: UHS-I 1.8V signaling, Frequency up to 50 MHz, sampled on both clock edges, up to 50MB/sec 指望找到一個host和card支持的最快的速度. */ /* Set the driver strength for the card */ err = sd_select_driver_type(card, status);/*driver strength在spec中沒找到詳細的說明, spec中流程圖裏有這個步驟.這個也是3.0才增長的,sd卡這邊切換用的是CMD6, driver strength屬於CMD6的function group 3*/ if (err) goto out; /* Set current limit for the card */ err = sd_set_current_limit(card, status);/*這個函數裏面註釋比較清楚了,根據電壓和速度模式,設置卡的最大功率,屬於CMD6的function group 4*/ if (err) goto out; /* Set bus speed mode of the card */ err = sd_set_bus_speed_mode(card, status);/*設置速度,屬於CMD6的function group 1*/ if (err) goto out; /* SPI mode doesn't define CMD19 */ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) { mmc_host_clk_hold(card->host); err = card->host->ops->execute_tuning(card->host, MMC_SEND_TUNING_BLOCK); mmc_host_clk_release(card->host); } out: kfree(status); return err; }
linux並無發送CMD42,spec上原話:spa
「When entering tran state, CARD_IS_LOCKED status in the R1 response should be checked (it is indicated in the response of CMD7). If the card is locked, CMD42 is required to unlock the card. If the card is unlocked, CMD42 can be skipped.」3d
但linux好像並無檢查,CMD7的返回值。沒有搞懂,望知道的朋友指點一下。code
還有最後發送CMD19的步驟,Tuning,我簡單理解爲調整時鐘讓時序穩定。blog
if分支中還有幾條語句,都是主機或驅動的操做,沒有涉及到卡的操做。ip
關於UHS-I,linux中的初始化就到這裏。ci
下面說說CMD6。這些內容都是spec中的,這裏只是按個人理解簡單整理。
在3.0以後的協議中,該命令功能增長了不少。CMD6是這個樣子的:
共有6組function group ,須要操做哪一個功能就把相應goup 的相應 bit置1。 各個group的bit定義以下:
例如上面函數,要設置driver strenth
static int sd_select_driver_type(struct mmc_card *card, u8 *status) { 。。。。。。 。。。。。。 err = mmc_sd_switch(card, 1, 2, drive_strength, status); if (err) return err; if ((status[15] & 0xF) != drive_strength) { pr_warning("%s: Problem setting drive strength!\n", mmc_hostname(card->host)); return mmc_set_driver_type(card->host, drive_strength); 0; } return 0; }
調用mmc_sd_switch(card, 1, 2, drive_strength, status)函數,傳入參數mode=1 group=2與表中相符(group參數從0開始),drive_strength就表示group 3的值,與表中相對應。
而後檢查返回值,判斷是否設置成功。 CMD6命令會從數據線而不是命令先接受一個512bit的應答值,這個值的具體定義在spec
Table 4-13: Status Data Structure。 這個表太大就不貼了。 須要注意的是表中定義與linux中收的數據字節順序相反。status[0]是spec中的第504~511位。
mode 0和 mode 1
CMD6第31位表示該命令的兩種模式,mode 0用來檢查卡支持那些function group。 mode 1用來設置具體的function group的值。
發送mode 0 CMD6 ,可參考linux中mmc_read_switch()函數。