目录

初始化

1.cmd 0

2.cmd8

3.cmd55

4.acmd41

5.cmd2

6.cmd3

7.cmd9

8.cmd13

9.cmd7

10.ACMD51

11.CMD6

12.CMD16

13.CMD17

14.CMD18

15.CMD12

tuning

CMD19

DW_SDHCI的tuning流程


初始化

1.cmd 0

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器

/* 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;
}

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_02

 

 

2.cmd8

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_03

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_04

R7:

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_05

/* 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;
}

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_06

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_07

 

3.cmd55

 

ACMD:SD card application-specific commands.

在发所有的ACMD之前,需要先发APP_CMD(CMD55)通知SD卡下一个指令为ACMD。SD卡应答R1,然后才能发送ACMD。

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_08

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_09

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 置位)。

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_10

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_11

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_d3_12

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_13

bit 31)指示卡片的上电操作是否完成

bit 30)指示卡片的容量状态(0代表SDSC、1代表SDHC或者SDXC)

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_14

上图OCR (bit 31)为0,即为卡busy

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_15

上图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)

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_16


RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_17

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_18

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_d3_19

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_20

/* 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)后,卡就会进入数据传输模式。

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_21

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_22

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_23

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_24

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_d3_25

/*
        * 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

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_26

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_27

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_28

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

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_29

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_30

 

 

 

9.cmd7

发送CMD7+RCA选中卡片, 发送CMD7+0不选中卡片,RCA是之前CMD3读取到的卡RCA

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_31

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_32

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_33

/* 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卡则需要使用主线测试来确定卡的位宽。

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_d3_34

PS:slave回复ACMD51是R1+data。SCR 是放在data中的,一共8个字节。

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_d3_35

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_36

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_37

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种不同的功能组:

  1. 访问模式:SD总线接口速度模式的选择;
  2. 命令系统:通过一套莫共有的命令来扩展和控制特定的功能;
  3. 驱动强度:在UHS-I模式下等选择合适的输出驱动强度,和主机环境相关;
  4. 电流/功率限制:UHS-I卡在UHS-I模式选择,和主机环境相关;

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_38

 

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_d3_39

 

MODE0: 查询模式,卡返回R1 + data[511:0]

data中存放了卡对每种功能的支持情况及当前选中的功能状态,及忙状态。

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_40

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_41

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_初始化_42

 

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

设置块大小

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_43

 

13.CMD17

读单个块参数为block地址

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_44

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_45

卡回复R1 +DATA

14.CMD18

读多块

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_46

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_47

 

15.CMD12

停止传输

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_48

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_49

 

tuning

CMD19

发送tuning block

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_嵌入式_50

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_51

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_52

host发送CMD19,卡回复R1+data,tuning data 的数据长度及内容是固定的,host可以根据收到的数据调整采样的timing。

 

DW_SDHCI的tuning流程

RK3568怎么判断emmc驱动已经初始化完成 emmc初始化代码_寄存器_53