目錄
初始化
1.cmd 0
/* Reset the Card */
err = mmc_go_idle(mmc);
static int mmc_go_idle(struct mmc *mmc)
{
struct mmc_cmd cmd;
int err;
usleep(1000);
cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_NONE;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
usleep(2000);
return 0;
}
2.cmd8
R7:
/* Test for SD version 2 */
err = mmc_send_if_cond(mmc);
static int mmc_send_if_cond(struct mmc *mmc)
{
struct mmc_cmd cmd;
int err;
cmd.cmdidx = SD_CMD_SEND_IF_COND;
/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
cmd.resp_type = MMC_RSP_R7;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
if ((cmd.response[0] & 0xff) != 0xaa)
{
debug("UNUSABLE_ERR mmc_send_if_cond\n");
return UNUSABLE_ERR;
}
else
mmc->version = SD_VERSION_2;
return 0;
}
3.cmd55
ACMD:SD card application-specific commands.
在發所有的ACMD之前,需要先發APP_CMD(CMD55)通知SD卡下一個指令爲ACMD。SD卡應答R1,然後才能發送ACMD。
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
4.acmd41
卡片的初始化將在主機發送ACMD41命令後開始,主機每間隔1秒就發送一次 ACMD41 命令,直到初始化完成(OCR 寄存器的 bit31 置位)。
(bit 31)指示卡片的上電操作是否完成
(bit 30)指示卡片的容量狀態(0代表SDSC、1代表SDHC或者SDXC)
上圖OCR (bit 31)爲0,即爲卡busy
上圖OCR (bit 31)爲1,即爲卡初始化完成
static int sd_send_op_cond(struct mmc *mmc) //send acmd41-- get ocr data
{
int timeout = 1000;
int err;
struct mmc_cmd cmd;
while (1)
{
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
/*
* Most cards do not answer if some reserved bits
* in the ocr are set. However, Some controller
* can set bit 7 (reserved for low voltages), but
* how to manage low voltages SD card is not yet
* specified.
*/
cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
(mmc->voltages & 0xff8000);
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
if (cmd.response[0] & OCR_BUSY)//等待OCR[31]置1後跳出循環,完成初始化。
break;
if (timeout-- <= 0)
return -EOPNOTSUPP;
usleep(1000);
}
5.cmd2
CMD2,驗證SD卡是否接入,獲取(CID)
/* Put the Card in Identify Mode */
cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
memcpy((void*)mmc->cid, (void*)cmd.response, 16);
6.cmd3
讀取卡相對地址RCA, 當卡收到RCA(CMD3)後,卡就會進入數據傳輸模式。
/*
* For MMC cards, set the Relative Address.
* For SD cards, get the Relatvie Address.
* This also puts the cards into Standby State
*/
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
cmd.cmdarg = mmc->rca << 16;
cmd.resp_type = MMC_RSP_R6;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
if (IS_SD(mmc))
mmc->rca = (cmd.response[0] >> 16) & 0xffff;
}
7.cmd9
CMD9,讀取CSD寄存器獲取卡的相關信息
RCA是之前CMD3讀取到的卡RCA
PS:R2回覆CMD9時爲CSD,回覆CMD2時爲CID
CSD(具體信息)寄存器也是 128 bits,提供了訪問卡片內容的一些信息如:傳輸速率、數據格式、錯誤類型、最大是數據訪問時間、DSR 寄存器是否啓用的。其中 bit[126:127] 記錄了 CSD 的版本號,CSD version 1.0 爲標準容量卡所用,CSD version 2.0 爲大容量或超大容量卡所用
---------------------
8.cmd13
讀取卡狀態
RCA是之前CMD3讀取到的卡RCA
9.cmd7
發送CMD7+RCA選中卡片, 發送CMD7+0不選中卡片,RCA是之前CMD3讀取到的卡RCA
/* Select the card, and put it into Transfer Mode */
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = MMC_CMD_SELECT_CARD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
}
10.ACMD51
發送CMD55+ACMD51讀取SCR寄存器,SD卡可以通過該值獲得位寬,如果是MMC卡則需要使用主線測試來確定卡的位寬。
PS:slave回覆ACMD51是R1+data。SCR 是放在data中的,一共8個字節。
cmd.cmdidx = SD_CMD_APP_SEND_SCR;//51
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
timeout = 3;
retry_scr:
data.dest = (char *)mmc->scr;
data.blocksize = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err) {
if (timeout--)
goto retry_scr;
return err;
}
mmc->scr[0] = __be32_to_cpu(mmc->scr[0]);
mmc->scr[1] = __be32_to_cpu(mmc->scr[1]);
// debug("scr_0=0x%x scr_1=0x%x\n",mmc->scr[0],mmc->scr[1]);
switch ((mmc->scr[0] >> 24) & 0xf) {//SD_SPEC
case 0:
mmc->version = SD_VERSION_1_0;
break;
case 1:
mmc->version = SD_VERSION_1_10;
break;
case 2:
mmc->version = SD_VERSION_2;
if ((mmc->scr[0] >> 15) & 0x1)
mmc->version = SD_VERSION_3;
break;
default:
mmc->version = SD_VERSION_1_0;
break;
}
if (mmc->scr[0] & SD_DATA_4BIT)
mmc->card_caps |= MMC_MODE_4BIT;
11.CMD6
CMD6是SD卡速度模式切換的一個重要命令,它定義了4種不同的功能組:
- 訪問模式:SD總線接口速度模式的選擇;
- 命令系統:通過一套莫共有的命令來擴展和控制特定的功能;
- 驅動強度:在UHS-I模式下等選擇合適的輸出驅動強度,和主機環境相關;
- 電流/功率限制:UHS-I卡在UHS-I模式選擇,和主機環境相關;
MODE0: 查詢模式,卡返回R1 + data[511:0]
data中存放了卡對每種功能的支持情況及當前選中的功能狀態,及忙狀態。
MODE1: 切換模式
每次發送切換隻能選中一個功能組進行切換,其他功能組全部爲1.
static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
{
struct mmc_cmd cmd;
struct mmc_data data;
/* Switch the frequency */
cmd.cmdidx = SD_CMD_SWITCH_FUNC;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = (mode << 31) | 0xffffff;
cmd.cmdarg &= ~(0xf << (group << 2));
cmd.cmdarg |= value << (group << 2);
data.dest = (char *)resp;
data.blocksize = 64;
data.blocks = 1;
data.flags = MMC_DATA_READ;
return mmc_send_cmd(mmc, &cmd, &data);
}
12.CMD16
設置塊大小
13.CMD17
讀單個塊參數爲block地址
卡回覆R1 +DATA
14.CMD18
讀多塊
15.CMD12
停止傳輸
tuning
CMD19
發送tuning block
host發送CMD19,卡回覆R1+data,tuning data 的數據長度及內容是固定的,host可以根據收到的數據調整採樣的timing。