eMMC使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/15/2025

    1. 概述

    Kernel下MMC采用标准的Linux框架,能够使用标准接口驱动MMC Device(eMMC card,SD card或SDIO device)。

    MMC子系统由card层,core层和host层构成。Card层将整个MMC Device注册成MMC Block Device,可支持上层的数据请求工作;Core层实现MMC/SD/SDIO协议中初始化流程和读写等工作。Host层可以调动硬件,把core层传下来的cmd或data request通过FCIE/SDIO Engine与eMMC/SD/SDIO card进行数据通信。

    图1-1 eMMC Host层框架

    eMMC host层的整体框架共有三层,分别是MDrv层,Hal层和Support层,以及接在Support层上的MMC设备,各个层次的作用如下:

    Drv层:

    eMMC的Drv层主要完成向core层注册Host的操作,也会额外提供一些封装接口来给用户层设置或获得Engine和卡的状态,比如:eMMC_bootbus,set_sdmmc_driving_control,并完成保证后续信号正常接收发送的MIE中断注册等。

    Hal层:

    eMMC的Hal层中通过读写寄存器来实现信号传输的文件是hal_sdmmc_v5.c,决定Host Engine接哪组pad pin,并对其进行上下拉操作的在hal_sdmmc_platform_common.c文件,中断和时间处理相关的接口在hal_sdmmc_intr.c文件。

    Support层:

    该层属于硬件支持层,驱动相关的最终实现都需要硬件的支持。

    MMC device:

    MMC设备,比如eMMC卡,直接接在驱动的硬件支持上,是驱动的最终操作对象。


    2. 关键字说明

    IP:连接eMMC设备的Host Engine

    IP bank:驱动访问eMMC设备所使用的Host Engine的寄存器地址

    HS: 可达25MB/S的高速接口时序模式,50MHz单数据速率总线,需要3.3V电压支持。

    HS200:高达200MB/S的高速接口时序模式,200MHz单数据速率总线,需要1.8V电压支持。

    HS400:高达400MB/s的高速DDR接口时序模式,200MHz双数据速率总线,需要1.8V电压支持。


    3. 功能描述

    封装 EMMC数量 总线带宽 时钟范围 uboot数据传输模式 Kernel数据传输模式 IP bank 产品
    BGA14 1 1,4,8 300k-200M DMA ADMA 0x1410 Pcupid

    总线带宽设置:

    eMMC支持配置1 -1bit mode/4 – 4bit mode / 8 – 8bit mode三种总线带宽,配置方式是通过修改设备树bus-width参数。

    时钟设置:

    eMMC驱动支持配置300KHz-200MHz范围内的时钟频率,可以通过修改设备树中的max-frequency参数来设置最大时钟大小,最终设置的clock频率是当前bus speed支持的最大频率。

    图3-1 eMMC 总线速率模式

    配置不同的总线带宽及时钟频率会影响数据传输速率,eMMC 5.0支持使用HS200和HS400速率模式,时钟频率默认使用200M,若要使用需要在设备树中使能mmc-hs200-1_8v/mmc-hs400-1_8v;

    配置使用High Speed SDR速率模式时,硬件上支持的时钟频率及理论速度参考下列表格(x8 总线宽度)。

    No 时钟频率(Hz) 传输速率(MB/s)
    0 300000 3
    1 12000000 12
    2 20000000 20
    3 32000000 32
    4 36000000 36
    5 40000000 40
    6 43200000 43.2
    7 48000000 48

    配置使用HS200或HS400速率模式时,软件设定默认使用200MHz的时钟频率(x8 总线宽度)。

    No 时钟频率(Hz) 传输速率(MB/s)
    0 200000000 (HS200) 200
    1 200000000 (HS400) 400

    注意,实际读写速率受读写过程中的cmd传输消耗,mmc设备性能等因素影响,达不到理论速度,测试性能建议使用fio工具读写大文件进行测试。

    数据传输模式设置:

    eMMC在kernel下支持配置DMA和ADMA两种数据传输模式,默认使用ADMA模式。


    4. 硬件连接介绍

    4.1. pcupid

    图4-1 EMMC 硬件原理图

    硬件连接对应的软件padmux设定如下:

    1.    padmux {
    2.        compatible = "sstar-padmux";
    3.        schematic =
    4.            // SDMMC0
    5.            <PAD_EMMC_RST            PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_RST>,
    6.            <PAD_EMMC_CLK            PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_CLK>,
    7.            <PAD_EMMC_CMD            PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_CMD>,
    8.            <PAD_EMMC_D0             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D0>,
    9.            <PAD_EMMC_D1             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D1>,
    10.           <PAD_EMMC_D2             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D2>,
    11.           <PAD_EMMC_D3             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D3>,
    12.           <PAD_EMMC_D4             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D4>,
    13.           <PAD_EMMC_D5             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D5>,
    14.           <PAD_EMMC_D6             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D6>,
    15.           <PAD_EMMC_D7             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_D7>,
    16.           <PAD_EMMC_DS             PINMUX_FOR_EMMC8B_BOOT_MODE_1    MDRV_PUSE_EMMC_DS>,
    17.    };
    

    第一列表示EMMC的pad名称,第二列表示pad mode,根据pad的使用情况设定,第三列是驱动程序使用的标识 使用八根数据线时候使用PINMUX_FOR_EMMC8B_BOOT_MODE_1,使用四根数据线时使用PINMUX_FOR_EMMC4B_BOOT_MODE_1


    5. Uboot用法介绍

    5.1. uboot config配置

    1. make menuconfig
    2. # SigmaStar drivers -->
    3. #    <*> SigmaStar mmc host
    4. #    [*]     SELECT EMMC
    

    uboot下eMMC驱动所在目录为drivers/sstar/mmc_host/,编译需要开启SSTAR_MMC_HOST和SELECT EMMC编译选项,打开方式如上。

    5.2. Dts参数配置说明

    使用EMMC可以通过配置dtsi中sstar_mmc0设备节点设定Host层driver的基本参数。dtsi的参数展示如下:

            sstar_mmc0: sstar_mmc0 {
                compatible = "sstar-mmc";
    
                bus-width = <8>;
                max-frequency = <200000000>;
                cap-mmc-highspeed = <1>;
                mmc-hs400-1_8v = <1>;
                mmc-hs200-1_8v = <1>;
                ip-order = <2>;
                pad-order = <0>;
                pwr-on-delay = <10>;
                pwr-off-delay = <50>;
                fake-cdz = <0>;
                rev-cdz = <0>;
                clk-driving = <2>;
                cmd-driving = <2>;
                data-driving = <2>;
                en-clk-phase = <0>;
                rx-clk-phase = <0>;
                tx-clk-phase = <0>;
    
                non-removable = <1>;
                status = "okay";
            };
    

    释义如下:

    参数 释义 备注
    bus-width 配置卡槽的buswidth 8 – 8bit mode
    max-frequency 配置对应卡槽支持的最大时钟频率 uboot支持200MHz
    cap-mmc-highspeed 配置支持EMMC high speed mode 禁止修改
    mmc-hs400-1_8v 配置支持EMMC hs400 mode UBOOT支持EMMC hs400 mode,使用需要打开CONFIG_MMC_HS400_SUPPORT
    mmc-hs200-1_8v 配置支持EMMC hs200 mode UBOOT支持EMMC hs200 mode,使用需要打开CONFIG_MMC_HS200_SUPPORT
    ip-order 配置对应卡槽的IP编号 禁止修改
    pad-order 指定卡接哪组pad 公版软件未使用,不需要修改
    pwr-on-delay 配置卡槽上电后软件的延时时间,延时后再去识别卡,以ms为单位 SDIO设备一般需要配置delay时间以便SDIO设备加载固件及状态ready,具体时间以SDIO设备厂家的建议为准(EMMC/SD设备节点无需修改)
    pwr-off-delay 配置卡槽下电后软件的延时时间,卡识别前会重新下电再上电卡槽,以ms为单位 SDIO设备一般需要配置delay时间以便SDIO设备加载固件及状态ready,具体时间以SDIO设备厂家的建议为准(EMMC/SD设备节点无需修改)
    fake-cdz 配置是否忽视Card detect,置1表示默认认为该槽有卡接入 针对固定在板上的设备,如部分SDIO设备,应该将卡槽对应项配置为1
    rev-cdz 该参数可配置是否颠倒当前Board的Card detect条件 默认低电平检查到卡,若硬件设计卡插入后CDZ电平为高电平,则将此项配置为1
    clk-driving 配置对应卡槽的clock pad pin的driving能力 档位:0-7,该项一般不需要修改,若遇到信号质量问题可以结合波形调整此项
    cmd-driving 配置对应卡槽的command pad pin的driving能力 档位:0-7,该项一般不需要修改,若遇到信号质量问题可以结合波形调整此项
    data-driving 配置对应卡槽的data[3:0] pad pin的driving能力 档位:0-7,该项一般不需要修改,若遇到信号质量问题可以结合波形调整此项
    en-clk_phase 配置对应卡槽是否使能 clock phase tuning 当设备读写通信出现CRC问题时候,可以通过改变rx,tx的采样点来解决
    rx-clk_phase 配置对应卡槽的clock tx相位 档位:0-3,需en-clk_phase置1此参数才有效,每个挡位相位间隔90°
    tx-clk_phase 配置对应卡槽的clock rx相位 档位:0-3,需en-clk_phase置1此参数才有效,每个挡位相位间隔90°
    non-removable 配置是否不可移除设备 无需修改,EMMC设备需要配置此项

    注意:config需要开启CONFIG_SSTAR_SELECT_EMMC

    5.3. Uboot cmd参数说明

    (1) emmc create

    格式:

    emmc create [name] [size]
    

    说明:创建分区,name 表示分区名称,size 代表大小(Bytes)

    示例:创建名为 p1 的分区,大小为 10M

    emmc create p1 0xA00000
    

    (2) emmc part

    说明:显示分区,格式如下: #分区名# #分区号# #大小@偏移 (占用空间),大小和偏移的单位为 block # #占用空间,单位为 MBytes#

    示例:

    SigmaStar # emmc part
                  U-Boot kernela               1       20480 @ 615200     ( 10M)
                  U-Boot rootfsa               2      409600 @ 635680     (200M)
                  U-Boot usera                 3      614400 @ 1045280    (300M)
                  U-Boot data                  4     4298752 @ 1659680    (  2G)
    

    (3) emmc remove

    格式:

    emmc remove [name]
    

    说明:删除指定名称的分区

    示例:删除 p1 分区

    emmc remove p1
    

    (4) emmc rmgpt

    格式:

    emmc rmgpt
    

    说明:删除 UDA 的所有分区,从分区表去除分区信息,不会擦除 UDA 分区

    (5) emmc read.p

    格式:

    emmc read.p [addr][partition_name][size]
    

    说明:把分区数据读到内存,addr 为内存地址,partition_nam 为分区名称,size 为拷贝的数据大小(Bytes)

    示例:把 p1 起始处的 0x1000Bytes 数据拷贝到内存 0x21000000

    emmc read.p 0x21000000 p1 0x1000
    

    (6) emmc write.p

    格式:

    emmc write.p [addr][partition_name][size]
    

    说明:把内存数据写到eMMC分区中,addr 为内存地址,partition_nam 为分区名称,size 为拷贝的数据大小(Bytes)

    示例:把内存 0x21000000起始处的0x1000Bytes的数据拷贝到eMMC p1分区

    emmc write.p 0x21000000 p1 0x1000
    

    (7) emmc write.p.continue

    格式:

    emmc write.p.continue [addr] [partition_name] [offset] [size]
    

    说明:把内存数据写到分区的偏移地址处,offset 为分区偏移地址(block 单位),size 为拷贝数据大小(Bytes)

    示例:把分割的三个文件(分别为 10M,20M,10M)连续地拷贝到分区 p1

    emmc write.p.continue 0x21000000 p1 0x0 0xA00000 //拷贝0xA00000 Bytes数据到p1的起始地址
    emmc write.p.continue 0x21000000 p1 0x5000 0x1400000 //0x5000=0xA00000/512
    emmc write.p.continue 0x21000000 p1 0xF000 0xA00000 //0xF000=0x5000+0x1400000/512
    

    (8) emmc read.p.continue

    格式:

    emmc read.p.continue [addr] [partition_name] [offset] [size]
    

    说明:把分区偏移 offset 处的数据拷贝到内存

    emmc read.p.continue 0x21000000 p1 0x0 0xA00000
    

    (9) emmc erase.p

    格式:

    emmc erase.p [name]
    

    说明:格式化指定分区

    示例:格式化 p1 分区的数据,格式化后分区数据都为 0

    emmc erase.p p1
    

    (10) emmc erase

    格式:

    emmc erase
    

    说明:擦除当前整个分区,例如当前在 UDA 分区,则擦除整个 UDA 分区,慎用!

    (10) mmc dev

    格式:

    mmc dev [dev] [part] [mode]
    

    说明:显示或设置当前 mmc 设备 [硬件分区] 并设置模式

    示例1:切换到UDA分区

    mmc dev 0 0
    

    示例2:切换到BOOT1分区

    mmc dev 0 1
    

    示例3:切换到BOOT2分区

    mmc dev 0 2
    

    (11) mmc erase

    格式:

    mmc erase blk# cnt
    

    说明:擦除数据

    示例1:擦除用户区所有块

    mmc dev 0 0
    mmc erase
    

    示例2:擦除第0个block开始的0x800个block数据(UDA分区下使用该指令擦除ENV)

    mmc dev 0 0
    mmc erase 0 0x800
    

    5.4. Uboot cmd使用实例

    (1) 创建一个新分区p1,大小为10M

    (2) 把 p1 起始处的 0x1000Bytes 数据拷贝到内存 0x21000000

    (3) 把分区p1偏移 0x0 处的数据拷贝0xA00000字节到内存0x21000000

    (4) 擦除分区p1的数据

    (5) 删除分区p1


    6. Kernel用法介绍

    6.1. Kernel Config配置

    1. 关联到的驱动模块

    Card层(mmc_block.ko)与Core层(mmc_host.ko)使用linux标准code,Host层(kdrv_sdmmc.ko)由Sigmastar维护,在menuconfig可将它们选择编译进kernel或编译为ko。

    2. enable 对应的驱动模块

    1. make menuconfig
    2. # Device Drivers -->
    3. #    <*> MMC/SD/SDIO card support -->                   (mmc_core.ko)
    4. #        <*> MMC block device driver                    (mmc_block.ko)
    5. #    [*] SStar SoC platform drivers -->
    6. #        <*> SStar SD/MMC Card Interface Support        (kdrv_sdmmc.ko)
    7. #        [ ]     Support SD30
    8. #        [*]     Support EMMC50
    9. #        [*]     Support SDMMC Command
    10.#        [*]       Support SDMMC UT verify
    11.#        [*]     SELECT EMMC
    

    6.2. Dts配置参数说明

    可以通过配置dtsi中sstar_sdmmc0项设定Host层driver的基本参数。dtsi的参数展示如下:

            sstar_sdmmc0: sstar_sdmmc0 {
                compatible = "sstar,sdmmc";
    
                bus-width = <8>;
                max-frequency = <200000000>;
                non-removable;
                broken-cd;
                cap-mmc-highspeed;
                mmc-hs200-1_8v;
                mmc-hs400-1_8v;
                no-sdio;
                no-sd;
                //no-mmc;
                reg = <0x0 0x1F282000 0x0 0x200>;//1410
                pll-reg = <0x1F283400 0x200>;//141A
                cifd-reg = <0x1F282200 0x200>;//1411
                pwr-save-reg = <0x1F282400 0x200>;//1412
                ip-order = /bits/ 8 <2>;
                pad-order = /bits/ 8 <0>;
                trans-mode = /bits/ 8 <1>;
                cifd-mcg-off = /bits/ 8 <0>; // mcg on/off in cifd
                ssc-switch =  /bits/ 8 <0>;
                support-cmd23 = /bits/ 8 <1>;
                //support-runtime-pm = /bits/ 8 <0>;
                fake-cdz = <1>;
                rev-cdz = /bits/ 8 <0>;
                rev-pwr = /bits/ 8 <0>;
                rev-ctrl = /bits/ 8 <0>;
                cdz-pad = <PAD_GPIOE_06>;
                pwr-pad = <PAD_GPIOE_07>;
                pwr-on-delay = <1>;
                pwr-off-delay = <30>;
                dev-ctrl-delay = <1>;
                sdio-use-1bit = /bits/ 8 <0>;
                clk-driving = <2>;
                cmd-driving = <2>;
                data-driving = <2>;
                en-clk-phase = /bits/ 8 <0>; //0/1
                rx-clk-phase = <0>; //0-3
                tx-clk-phase = <0>; //0-3
                en-eight-phase = /bits/ 8 <0>; //0/1
                rx-eight-phase = /bits/ 8 <0>; //0/1
                tx-eight-phase = /bits/ 8 <0>; //0/1
                interrupts = <GIC_SPI INT_IRQ_FCIE IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI INT_FIQ_PAD2FCIE_SD_CDZ IRQ_TYPE_LEVEL_HIGH>;
                interrupt-names = "mie2_irq", "cdz_slot2_irq";
                clocks = <&CLK_fcie>,<&CLK_fcie_syn>;
                clock-names = "clk_sdmmc2", "syn_clk_sdmmc2";
                status = "ok";
            };
    

    如上图所示,eMMC设备树配置节点释义分别为:

    参数 释义 备注
    bus-width 配置对应卡槽的buswidth 8 - 8bit mode
    max-frequency 配置对应卡槽支持的最大时钟频率
    non-removable 配置是否不可移除设备,置1表示默认该设备不可移除 eMMC/SDIO设备一般设置为不可移除属性
    broken-cd 配置是否使用cdz中断 eMMC设备不使用
    cap-mmc-highspeed 配置设备是否支持highspeed总线速率模式 默认开启支持highspeed mode
    mmc-hs200-1_8v 配置是否启用hs200总线速率模式
    mmc-hs400-1_8v 配置是否启用hs400总线速率模式
    no-sdio 配置设备不支持SDIO协议 eMMC设备不支持SDIO协议
    no-sd 配置设备不支持SD协议 eMMC设备不支持SD协议
    reg 配置eMMC Host Engine Bank地址 禁止修改
    pll-reg 配置eMMC Host Engine PLL Bank地址 禁止修改
    cifd-reg 配置eMMC Host Engine CIFD Bank地址 禁止修改
    pwr-save-reg 配置eMMC Host Engine PSM Bank地址 禁止修改
    ip-order 配置对应卡槽的IP编号 禁止修改
    pad-order 配置对应卡槽的padmux mode编号 公版软件未使用,无需修改
    trans-mode 配置对应的卡槽的数据传输模式 无需修改
    fake-cdz 配置对应卡槽是否忽视Card Detect eMMC未使用,保持默认值即可
    rev-cdz 配置CDZ检测方向 eMMC未使用,保持默认值即可
    rev-pwr 配置power控制方向 eMMC未使用,保持默认值即可
    rev-ctrl 配置ctrl pin控制方向 eMMC未使用,保持默认值即可
    pwr-on-delay 配置对应卡槽的上电延迟时间 eMMC未使用,保持默认值即可
    pwr-off-delay 配置对应卡槽的下电延迟时间 eMMC未使用,保持默认值即可
    dev-ctrl-delay 配置ctrl pin极性翻转前后的延时时间,以ms为单位 eMMC未使用,保持默认值即可
    ssc-switch 配置是否开启展频 根据需要开启
    support-cmd23 配置是否支持预设传输Block数功能 默认开启支持cmd23
    support-runtime-pm 配置是否支持运行时电源管理 根据需要开启
    clk-driving 配置对应卡槽的clock line的driving 档位:0-7,该项一般不需要修改,若遇到信号质量问题可以结合波形调整此项
    cmd-driving 配置对应卡槽的cmd line的driving 档位:0-7,该项一般不需要修改,若遇到信号质量问题可以结合波形调整此项
    data-driving 配置对应卡槽的data line的driving 档位:0-7,该项一般不需要修改,若遇到信号质量问题可以结合波形调整此项
    en-clk-phase 配置对应卡槽是否使能clock phase tuning 0 - 禁用 / 1 - 使能
    rx-clk-phase 四相位模式时配置对应卡槽的clock rx phase 详情使用见clk phase使用说明
    tx-clk-phase 四相位模式时配置对应卡槽的clock tx phase 详情使用见clk phase使用说明
    en-eight-phase 配置对应卡槽是否使能clock 8 phase tuning 0 - 禁用 / 1 - 使能
    rx-eight-phase 八相位模式时配置对应卡槽的clock rx phase 详情使用见clk phase使用说明
    tx-eight-phase 八相位模式时配置对应卡槽的clock tx phase 详情使用见clk phase使用说明
    interrupts 配置中断信息 禁止修改
    interrupt-names 配置中断名称 禁止修改
    clocks 配置eMMC Host Engine时钟源 禁止修改
    clock-names 配置时钟源名称 禁止修改

    注意:config需要开启CONFIG_SSTAR_SELECT_EMMC

    clk phase使用说明:

    当使用四相位模式时候,en-clk-phase需要设置为1,然后根据需要设定的相位设置rx-clk-phase和tx-clk-phase的值,相位间隔90°。 当使用八相位模式时候,en-clk-phase和en-eight-phase需要设置为1,然后根据需要设定的相位设置rx-clk-phase,tx-clk-phase,rx-eight-phase和tx-eight-phase的值,相位间隔45°。

    不同相位对应的phase值

    • 四相位模式

      相位 rx-clk-phase tx-clk-phase
      0 0
      90° 1 1
      180° 2 2
      270° 3 3
    • 八相位模式

      相位 rx-clk-phase rx-eight-phase tx-clk-phase tx-eight-phase
      0 0 0 0
      45° 1 0 1 0
      90° 2 0 2 0
      135° 3 0 3 0
      180° 0 1 0 1
      225° 1 1 1 1
      270° 2 1 2 1
      315° 3 1 3 1
    • 注1:硬件设定tx phase默认已经是180°,所以相位设置180°时候,测量tx的波形会和没开启phase时候一样,设置0°时候会和没开启phase时候相位相差180°。

    • 注2:rx和tx可以单独设定。

    6.3. Sample code

    无。

    6.4. 模块使用介绍

    linux系统启动后,正常加载eMMC驱动,并识别eMMC Card后,会创建对应的块设备节点/dev/mmcblk*。使用fdisk、mkfs、mount、dd工具可对MMC设备申请分区、格式化分区、挂载分区并对挂载分区进行读写等操作。

    另外驱动提供sysfs进行debug,进入/sys/class/mmc_host/mmc0/device/目录下可进行操作:

    1.  cd /sys/class/mmc_host/mmc0/device/
    2.
    3.  # 查看eMMC Host时钟频率
    4.  cat debug_get_sdmmc_clock
    5.
    6.  # 查看eMMC Host与Device上一次通信状态
    7.  cat debug_get_sdmmc_status
    8.
    9.  # 设置[slotNo] emmc的bootbus值
    10. echo [slotNo] [bootbus] > eMMC_bootbus
    11. # 查看所有slot的emmc的bootbus值。
    12. cat eMMC_bootbus
    13.
    14. # 指定起始位置和Block数对eMMC Device进行擦除
    15. echo [startblkAddr] [blkcnt] > eMMC_erase
    16.
    17. # 设置[slotNo] eMMC Device支持HW reset
    18. echo [slotNo] > eMMC_hwreset
    19. # 查看eMMC Device是否开启HW reset支持
    20. cat eMMC_hwreset
    21.
    22. # 设置 eMMC Device的boot启动分区
    23. echo [partconf] > eMMC_partconf
    24. #[partconf] -0: don't support boot
    25. #           -1: boot0 partition
    26. #           -2: boot1 partition
    27. #           -7: UDA
    28. # 查看eMMC Device的boot启动分区
    29. cat eMMC_partconf
    30.
    31. # 设置eMMC 写保护范围(按group设置)
    32. echo [otption] [address] <size> > eMMC_write_protect
    33. #[option] -0: Set the eMMC address of the group to be 'write protect'
    34. #         -1: Clear the eMMC address of the group remove 'write protect'
    35. #         -2: Ask the eMMC address of the group whether it's in 'write protect'?
    36. #         -3: ASK the eMMC address of the group about the 'write protect' type
    37. #[address]  单位:block
    38. #[size]     单位: block
    39.
    40.
    41. # 对[slotNo] eMMC Device进行硬复位
    42. echo [slotNo] > sdmmc_reset
    43.
    44.
    45. # 设置eMMC pin的驱动能力
    46. echo [slotIndex] [signalLine] [drvLevel] > set_sdmmc_driving_control
    47. echo [slotIndex]  [drvLevel] > set_sdmmc_driving_control
    48. echo [signalLine] [drvLevel] > set_sdmmc_driving_control
    49. echo [drvLevel] > set_sdmmc_driving_control
    50. #[slotIndex]: 0-1
    51. #[signalLine]: "clk"/"cmd"/"data"/"all"
    52. #[drvLevel]: 0-7
    53.
    54. # 设置展频参数
    55. ssc set param usage:
    56. 1. echo [slotIndex] [modulation] [deviation] > sdmmc_setssc
    57.     operation [slotIndex]   is slot number:0-2.
    58.     operation [modulation]  value is between [20, 40], origin default is 20
    59.     operation [deviation]   value is between [1000, 3001], origin default is 3001
    60.     e.g. echo 0 20 1001 > sdmmc_setssc
    61. 2. echo [slotIndex] [disable ssc] > sdmmc_setssc
    62.     disable: e.g. echo 0 0 > sdmmc_setssc
    63.     enable: e.g. echo 0 1 > sdmmc_setssc
    64.
    65. # 设置clock phase
    66. set phase param usage:
    67. 1. echo [mode] [tx-clk-phase] [rx-clk-phase] [tx-eight-phase] [rx-eight-phase] > sdmmc_clk_phase
    68.     operation [mode]               is phase mode:4 or 8
    69.     operation [tx/rx-clk-phase]    value is between [0, 3]
    70.     operation [tx/rx-eight-phase]  value is between [0, 1]
    71.     e.g. Four-phase mode(180°):
    72.         echo 4 2 2 > sdmmc_clk_phase
    73.     e.g. Eight-phase mode(180°):
    74.         echo 8 0 0 1 1 > sdmmc_clk_phase
    75. 2. echo [enable/disable clk phase] > sdmmc_clk_phase
    76.     disable: e.g. echo 0 > sdmmc_clk_phase
    77.     enable: e.g. echo [4/8] > sdmmc_clk_phase
    

    展频参数使用说明:

    有三个参数可能会影响SSC功能的调制速率:SET,SPAN和STEP。

    • PLL_SET = (MPLL*524288)/(SYN_CLK)

      SPAN (14 bits)

      STEP (12 bits)

      SPAN = (MPLL * 131072) / (PLL_SET * Fmodulation)

      STEP = (PLL_SET * Rdeviation) / SPAN

    Fmodulation为SSC的调制频率,范围为(20KHz~40KHz)

    Rdeviation 是 SSC 的偏差(最大偏差为 +-3%)

    示例:

    设置展频调制频率为40KHz,偏差为+-1%

    echo 0 40 1000 > sdmmc_setssc

    • SYN_CLK = 75Mhz

      ref_clk = 432Mhz

      Modulation is 40KHz

      Deviation is 1%

      SET = ( 432MHz * 524288) / (75MHz ) = 3019899 = 0x2E147B

      SPAN = (432MHz * 131072)/ ( 3019899 * 40KHz) = 468 = 0x1D4

      STEP = (3019899 * 1%) /468 = 64 = 0x40


    7. API参考

    该功能模块需打开CONFIG_SUPPORT_SDMMC_COMMAND配置项,提供以下接口:

    API名称 功能
    SDMMC_Init 初始化eMMC驱动并识别设备
    SDMMC_WriteData 写数据到eMMC设备
    SDMMC_ReadData 从eMMC设备读取数据
    eMMC_EraseBlock 擦除eMMC设备中的指定数据
    eMMC_GetExtCSD 获取eMMC设备的ExtCSD寄存器内容

    7.1. SDMMC_Init

    • 目的

      初始化eMMC驱动并识别设备

    • 语法

      U16_T SDMMC_Init(struct sstar_sdmmc_slot *p_sdmmc_slot)

    • 参数

      参数名称 描述
      p_sdmmc_slot eMMC对应的控制块,驱动注册时生成并添加到mmc_host私有变量中
    • 返回值

      返回值 描述
      0 成功
      other 失败

    7.2. SDMMC_WriteData

    • 目的

      写数据到eMMC设备

    • 语法

      U16_T SDMMC_WriteData(struct sstar_sdmmc_slot *p_sdmmc_slot, U32_T u32CardBlkAddr, U16_T u16BlkCnt, U8_T *pu8DataBuf)

    • 参数

      参数名称 描述
      p_sdmmc_slot eMMC对应的控制块,驱动注册时生成并添加到mmc_host私有变量中
      u32CardBlkAddr 写入eMMC的Block地址
      u16BlkCnt 写入的Block数
      pu8DataBuf 待写入的数据缓存地址
    • 返回值

      返回值 描述
      0 成功
      other 失败

    7.3. SDMMC_ReadData

    • 目的

      读EMMC中的数据。

    • 语法

      U16_T SDMMC_ReadData(struct sstar_sdmmc_slot *p_sdmmc_slot, U32_T u32CardBlkAddr, U16_T u16BlkCnt, U8_T *pu8DataBuf)

    • 参数

      参数名称 描述
      p_sdmmc_slot eMMC对应的控制块,驱动注册时生成并添加到mmc_host私有变量中
      u32CardBlkAddr 读取eMMC的Block地址
      u16BlkCnt 读取的Block数
      pu8DataBuf 存放数据的缓存地址
    • 返回值

      返回值 描述
      0 成功
      other 失败

    7.4. eMMC_EraseBlock

    • 目的

      擦除eMMC中指定地址的数据。

    • 语法

      U16_T eMMC_EraseBlock(struct sstar_sdmmc_slot *p_sdmmc_slot, U32_T u32BlkAddrStart, U32_T u32BlkAddrEnd)

    • 参数

      参数名称 描述
      p_sdmmc_slot eMMC对应的控制块,驱动注册时生成并添加到mmc_host私有变量中
      u32BlkAddrStart 擦除的起始地址
      u32BlkAddrEnd 擦除的结束地址
    • 返回值

      返回值 描述
      0 成功
      other 失败

    7.5. eMMC_GetExtCSD

    • 目的

      获取eMMC设备的ExtCSD寄存器内容。

    • 语法

      U16_T eMMC_GetExtCSD(struct sstar_sdmmc_slot *p_sdmmc_slot, U8_T *pu8DataBuf)

    • 参数

      参数名称 描述
      p_sdmmc_slot eMMC对应的控制块,驱动注册时生成并添加到mmc_host私有变量中
      pu8DataBuf 保存ExtCSD内容的缓存地址
    • 返回值

      返回值 描述
      0 成功
      other 失败

    8. Debug & FAQ

    出现异常时log打印的错误码类型有:

    (1)SD_STS:0xFF01 读CRC错误

    (2)SD_STS:0xFF02 写CRC错误

    (3)SD_STS:0xFF04 写数据超时

    (4)SD_STS:0xFF08 命令发送未响应

    (5)SD_STS:0xFF10 命令响应存在CRC错误

    (6)SD_STS:0xFF20 读数据超时

    (7)SD_STS:0xFF40 设备处于忙状态

    根据eMMC卡实际可能遇到的问题,分为以下几个类型:

    1. 识别卡失败

    若卡识别失败,需要确定是响应获取失败还是传输信号不好有CRC问题,区分问题可以通过抓波形确定,具体区别以及debug方法如下:

    • 响应获取失败

      现象:波形上只有host发出去的command,没有device返回的response

      debug方法:首先确定电压和clock是否正常,其次看波形上是否有command发出去,若前面两个都没有问题,再确定卡是否有回复响应,若没有响应检查device状态。

    • 信号不好有CRC问题

      现象:从波形看command和response都正常,则考虑CRC问题

      debug方法:若有CRC问题,先需要排除硬件问题,比如:device接触是否良好,是否有外接干扰等。然后再尝试更改dts里的driving档位,若还有问题则需要考虑调整clock phase。

    2. 读写失败

    若是在正常读写过程中遇到问题,需要确定是读写超时问题,还是信号不好有CRC问题,区分问题可以通过log确定,超时问题有timeout的字眼,debug方法如下:

    • 读写超时

      现象:报错log里有timeout的字眼

      debug方法:首先需要确定当前clock频率以及bus width是否是期望配置的值,其次可以将驱动里的超时时间再加大试试,若还有超时问题,则需要抓波形详细分析。

    • 信号不好有CRC问题

      现象:排除以上问题,则可能是CRC问题

      debug方法:debug方法见前文,另外读写过程中的CRC问题,若对速率要求不是很高,可以考虑降频或者降bus width。

    9. EMMC母片制作和烧录说明

    9.1 介绍

    emmcnize是制作emmc母片镜像的工具,用于把kernel、rootfs、文件系统、用户数据、环境变量等镜像合并成一个可以直接通过烧录器烧录到空片的镜像。

    emmcnize工具:

    emmcnize

    9.2 使用方法

    把需要打包的镜像(env.bin、kernel、rootfs.ext4、data.ext4等)及UDA分区配置文件(part.ini)与emmcnize工具放在同一个目录下,指定配置文件作为输入,指定输出文件,格式:./emmcnize (input ini file) (output image file),例如:

    ./emmcnize part.ini image.bin -b 0x2000
    

    其中part.ini为分区配置文件,image.bin为输出的完整镜像, 0x2000是用户分区的起始地址。

    9.2.1 part.ini配置文件格式

    [env]
    image=env.bin
    vol_id=0
    vol_size=0x3B1000
    vol_name=""
    
    [kernel-volume]
    image=kernel
    vol_id=1
    vol_size=0xA00000
    vol_name=kernel
    
    [rootfs-volume]
    image=rootfs.ext4
    vol_id=2
    vol_size=0xC800000
    vol_name=rootfs
    
    [MISC-volume]
    image=misc.fwfs
    vol_id=3
    vol_size=0xA00000
    vol_name=MISC
    
    [miservice-volume]
    image=miservice.ext4
    vol_id=4
    vol_size=0x12C00000
    vol_name=miservice
    
    [customer-volume]
    image=customer.ext4
    vol_id=5
    vol_size=0x82900000
    vol_name=customer
    

    image=XX,定义分区镜像名,必须与已有镜像名相同。

    vol_id=X,定义分区id,从1开始标识是第几个分区,为0表示不纳入分区管理。

    vol_size=XX,定义分区大小(Bytes单位),必须不小于对应镜像大小。

    vol_name=XX,定义分区名,uboot下通过emmc part看到的分区名。

    [XXX-volume] section是真正的用户分区,它们的image、vol_size、vol_name都可以根据实际分区情况进行更改。vol_id从1开始编号,最大支持64个分区。

    9.2.2 制作环境变量镜像

    除了env.bin之外其他的镜像都是编译生成的,env.bin的制作是把需要设置的环境变量按照uboot printenv命令打印出来的格式写入到一个txt文件,例如:

    #env.txt
    baudrate=115200
    bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rootfstype=ext4 rw init=/linuxrc cma=64M
    bootcmd=emmc read.p 0x21000000 kernela 0x1C61E8;bootm 0x21000000;
    bootdelay=0
    ethact=sstar_emac
    ethaddr=00:30:1b:ba:02:db
    fileaddr=23b2ef00
    filesize=101
    stderr=serial
    stdin=serial
    stdout=serial
    

    uboot编译后在tool目录下有一个mkenvimage工具,命令参数如下:

    ./tools/mkenvimage
    Please specify the size of the environment partition.
    mkenvimage [-h] [-r] [-b] [-p <byte>] -s <environment partition size> -o <output> <input file>
    
    This tool takes a key=value input file (same as would a `printenv' show) and generates the corresponding environment image, ready to be flashed.
    
        The input file is in format:
            key1=value1
            key2=value2
            ...
        Empty lines are skipped, and lines with a # in the first
        column are treated as comments (also skipped).
        -r : the environment has multiple copies in flash
        -b : the target is big endian (default is little endian)
        -p <byte> : fill the image with <byte> bytes instead of 0xff bytes
        -V : print version information and exit
    
    If the input file is "-", data is read from standard input
    

    执行./mkenvimage -s 0x1000 -o env.bin env.txt生成环境变量镜像。其中size的单位是byte,且其大小应该和uboot的CONFIG_ENV_SIZE一样大,否则会有CRC校验失败的问题

    9.2.3 说明

    part.ini文件中env的size比实际env.bin的size大,这是因为母片工具制作母片时会从env的起始地址0x278开始补充镜像文件,直至补充完当前分区的size,如果按照env.bin的实际size烧录,0x278*512+0x1000=327680 byte=640 blk就会是用户分区数据开始存储的地方,这与我们uboot下读取用户数据的实际起始地址不同,uboot下读取相应数据的地址如下图:

    如上图,UDA的分区1的start地址是0x2000(实际地址应该是根据用户设定的分区地址,这里分区一是riscv),为了保证uboot下可以正确读到相应的数据,所以part.ini中env的size需要设置为 0x2000-0x278=0x1D88 blk=0x3B1000 byte。

    9.2.4 其他

    emmcnize的其他功能可以输入emmcnize -h查看

    ./emmcnize -h

    emmcnize This tool takes a ini image layout input file and generates the corresponding image that ready to be flashed.
        ./emmcnize <input ini file> <output image file> [b|p|v|h]
        The input file is in format:
            [<name>-volume]
            image=<bin file name>
            vol_id=XX
            vol_size=<partition size in bytes in hex>
            vol_name=<partition name>
        -p :only generate partition table image:
        -b :redefine the start offset block of user's partition(unit: blk)
        -h :help
        -v :print version information and exit
    

    9.3 母片烧录

    将emmc分区切至UDA分区,然后将image.bin(上一节生成)烧入到0地址处。

    如果觉得母片太大烧录太慢,也可以将母片按照一定的size切割成小文件,脚本如下:

    #!/bin/sh
    FLASH_BLK_SIZE=$((512))
    SPLIT_SIZE=$((0x1400000))
    #split_size_16=0x`echo "obase=16;$SPLIT_SIZE" |bc `
    split_size_16=0xA000
    echo "split size:" $SPLIT_SIZE
    
    SRC_FILE=$1
    BURN_SCPT=burn.es
    OUT_DIR=output
    
    rm -rf $OUT_DIR
    mkdir $OUT_DIR
    
    IMAGE_SIZE=`stat --format=%s $SRC_FILE`
    echo "image size: " $IMAGE_SIZE
    
    if [ $IMAGE_SIZE -gt $SPLIT_SIZE ]; then
        echo -e "\e[1;32m $SRC_FILE too large, size($IMAGE_SIZE) do split($SPLIT_SIZE)! \e[0m"
        offset_blk=0
        split -b $SPLIT_SIZE $SRC_FILE $OUT_DIR/${SRC_FILE}_
        for i in `ls  $OUT_DIR/$SRC_FILE_*`
        do
            offset_blk_16=0x`echo "obase=16;$offset_blk"|bc`
            file=`basename $i`
            echo "tftp 0x21000000 $file" >> $OUT_DIR/$BURN_SCPT
            #echo "emmc write 0x21000000 $offset_blk_16 $split_size_16" >> $OUT_DIR/$BURN_SCPT
            file_size=`stat --format=%s $i`
            if [ $SPLIT_SIZE -gt $file_size ]; then
                file_size=$(($file_size/$FLASH_BLK_SIZE))
                split_size_16=0x`echo "obase=16;$file_size" |bc `
            else
                split_size_16=0xA000
            fi
            echo "mmc write 0x21000000 $offset_blk_16 $split_size_16" >> $OUT_DIR/$BURN_SCPT
            IMAGE_BLK_SIZE=$(($SPLIT_SIZE/$FLASH_BLK_SIZE))
            offset_blk=$(($offset_blk + $IMAGE_BLK_SIZE))
        done
        echo "% <- this is end of file symbol" >> $OUT_DIR/$BURN_SCPT
    fi
    

    执行命令格式:./split_burn_emmc.sh image.bin,其中image.bin是制作的母片,最终切割生成的文件在output目录下

    9.4 配置EMMC ECSD寄存器

    注:相关读写操作需要专门的tool,请联络对应的emmc厂商提供

    1、配置erase group define,reliable write,即

    EXT-CSD位址 设定值
    [175] 0x01
    [167] 0x1F
    [155] 0x01

    设置完成后需要对emmc断电再重新上电,否则配置不生效。

    2、烧录boot1分区,且boot数据存储在boot1分区时,需要配置

    EXT-CSD位址 设定值
    [162] 0x01
    [177] 必须根据实际启动方式配置
    [179] 0x09

    3、烧录UDA分区,且boot数据存储在boot1分区时,需要配置

    EXT-CSD位址 设定值
    [162] 0x01
    [177] 必须根据实际启动方式配置
    [179] 0x08

    4、EXT-CSD配置说明

    1) reliable write 必须设置,如不设置则断电时emmc 上已经写好的数据也有可能损坏。但是,有的emmc出厂默认就开启了reliable write,如果ecsd[167]本身就是0x1f,则reliable write 无需再设置。如出现reliable write 无法设置的情况,请咨询emmc 厂商。

    2) EXT-CSD[179] = 0x8,boot数据存储在boot1,设置boot1 分区为启动分区,如果不选择boot1分区为启动分区,则务必将boot数据存储分区选择为启动分区,例如:boot数据存储在boot2,则应该配置为0x10,若boot数据存储在UDA,则应该配置为0x38。

    3) EXT-CSD[177]的值必须根据实际启动方式配置,比如,如果boot type是emmc 8 bit启动,需要配置为0x02,如果boot type是emmc 4 bit启动,需要配置为0x01

    4) 某些emmc的EXT-CSD[162]不设置为1 的话会出现不开机的问题,因此必须设置。ECSD[162]=1 是要eMMC 去看HW reset pin,默认为0 是不看的。