EMMC 使用开发参考

Version 1.00


1. EMMC storage & Boot PRUE LINUX介绍


1.1. 概述

EMMC boot 的作用是从EMMC flash获取boot-loader, uboot, kernel, env, rootfs, miservice和customer文件,即程序运行的bin档都来自EMMC flash。要求rom code, boot-loader, uboot和kernel都要支持并开启EMMC driver。

图 1‑1:EMMC boot 流程

EMMC storage指的是在uboot和kernel下,能对emmc进行初始化及读写等操作,这要求在uboot和kernel下支持并开启EMMC driver。不同于EMMC storage,EMMC boot 对uboot的要求是还要能从EMMC中获取并读写环境变量。


1.2. 准备条件

开发板的启动方式是EMMC启动,硬件确认连通,EMMC使用已经支持的pad,EMMC flash能够正常工作。

当使用插针式的emmc设备时(如下图),EVB板上的emmc pin脚不连通,需要硬件帮忙焊上需要的电阻,另外因为emmc大多是焊在板子上的,软件上没有设计开关电逻辑,所以使用时还需要插上电源常供电跳帽(下图蓝色跳帽)。

图 1‑2:插针式emmc展示

另一种插卡式的emmc设备(如下图),emmc的reset脚和卡槽的cdz脚是连通的,由于卡槽cdz的机械结构是当卡插入则该pin脚拉低,因此该emmc的reset脚会被一直拉低,这是不正常的。解决办法是断掉pad cdz与卡槽cdz的连接,然后从pad cdz直接飞线到emmc的reset脚。

图 1‑3:插卡式emmc展示

当前支持EMMC driver的平台有Ispahan(只支持作storage)、Pudding(即可以作storage又可以boot)。

支持的branch为stable01_i6e_i6b0_ipc。

编译工具链gcc-sigmastar-9.1.0-2019.11-x86_64_arm-linux-gnueabihf用于编译glibc版本的mi和kernel、boot。Arm-buildroot-linux-uclibcgnueabihf-4.9.4-uclibc-1.0.31用于uclibc版本。


2. 编译方法


2.1. Alkaid下project快速编译

该方法可以在alkaid project目录下,一键编译出整包支持emmc boot的image。

操作实例:

cd project

./setup_config.sh configs/ipc/i6e/emmc.glibc-ext4fs.013a.256.bga

make clean -j32; make image-nocheck -j32

得到的image烧录包的路径为:image/output/images。该image包里面即支持EMMC boot的各image。


2.2. uboot/kernel编译方法

在boot和kernel目录下可以根据需要修改配置,编译出想要的uboot/kernel image。

2.2.1. uboot 编译方法

emmc storage和emmc boot都需要开启emmc driver,开启后就能对emmc进行初始化和读写等操作。如果是需要emmc boot,那么还需要开启其他的配置选项,以下是操作示例和详细说明。

cd boot/ 
#根据需要使用相应的defconfig。 
make infinity6e_defconfig 
make menuconfig 
#开启以下配置并保存 
#Device Drivers --> 
# [*]Mstar drivers --> 
# [ ]Save environment to ISP NOR FLASH (保存env到nor flash,nor启动时需要选中) 
# [*]MSTAR emmc # [*]Support eMMC BOOT (使支持设定emmc的启动参数,emmc boot时需要选中) 
# [*]Save environment to eMMC (保存env到emmc flash,emmc boot时需要选中) 
# [ ]MSTAR sdmmc(不要选中, 与emmc冲突) 
# [ ]Save environment to NAND FLASH (保存env到nand flash,nand启动时需要选中)。 
make clean; make -j32 
# 替换image 
cp u-boot.xz.img.bin ../project/image/output/images/boot/u-boot.xz.img.bin 
# Emmc 将IPL/IPL_CUST和uboot打成了一个BOOT_PART.bin。 
cat ../project/image/output/images/boot/IPLX.bin ../project/image/output/images/boot/u-boot.xz.img.bin > ../project/image/output/images/boot/BOOT_PART.bin

2.2.2. kernel编译方法

Kernel的编译方法和uboot差不多,同样把emmc driver打开,就可以正常读写emmc设备了,即emmc storage。如果要emmc boot,首先驱动必须编译进kernel(emmc storage时可以把驱动编译成模块),然后还需要开启对应的文件系统和emmc partition以挂载rootfs。

示例和配置项展示如下:

cd kernel/ 
#根据需要使用相应的defconfig。 
make infinity6e_ssc013a_s01a_defconfig 
make menuconfig #开启以下配置并保存 #Enable the block layer --> 
# [*]Support for large (2TB+) block devices and files (以ext4格式挂载rootfs需要开启大block支持) 
# Partition Types --> 
# [*]EMMC PARTITION table support (支持识别uboot下emmc 命令创建的分区) 
#Device Drivers --> 
# [*]MMC/SD/SDIO card support --> (mmc子系统中block和core层驱动) 
# [*]HW reset support for eMMC 
# [*]Simple HW reset support for MMC 
# [*]MMC block device driver 
# [*]SStar SoC platform drivers --> 
# <*>EMMC driver (emmc 驱动,依赖“MMC/SD/SDIO card support”) 
# [*]UNIFY EMMC DRIVER 
# < >SStar SD/MMC Card Interface Support (不要选中) 
#File systems --> 
#[*]The Extended 4 (ext4) filesystem (子选项保持默认) make clean; make -j32 
#替换image: cp arch/arm/boot/uImage.xz ../project/image/output/images/kernel

2.3. 其他方式启动

2.3.1. 进入project 目录编译alkaid

以SSC009A-S01B-S开发板,spinand启动为例。

注意:在开发板上,emmc和sdmmc的pad存在冲突,且sdmmc的pad优先级高于emmc,所以不能把sdmmc编进rootfs(spinand或者spinor的project是默认把sdmmc编进来的,需要手动关掉)。

cd project/ 
# 编辑kernel_mode_list,删除”kdrv_sdmmc.ko”。 
vi kbuild/4.9.84/i6b0/configs/ipc/009A/ulibc/4.9.4/spinand/modules/kernel_mod_list

./setup_config.sh configs/ipc/i6b0/nor.uclibc-squashfs.009a.64.qfn88 make clean; 
make image-nocheck j32;

得到的image烧录包的路径为:image/output/images。这里编译出来的bin档都不支持emmc driver。

注意:Ispahan使用的config的工具链为uclibc,而Pudding为glibc,这两者使用的工具链是不一样的。

2.3.2. 进入boot目录,编译uboot。

cd boot/ 
make infinity6b0_spinand_defconfig 
make menuconfig 
#开启以下配置并保存 #Device Drivers --> 
# [*]Mstar drivers -->
# [*]MSTAR emmc 
# [ ]MSTAR sdmmc(不要选中, 与emmc冲突)。 
make clean; make -j32 
#替换project下编译出来的uboot bin档 
cp u-boot_spinand.xz.img.bin ../project/image/output/images/uboot_s.bin

此时,project的image包中的uboot是支持emmc driver了。

2.3.3. 进入kernel目录编译kernel

cd kernel/
make infinity6b0_ssc009a_s01a_spinand_defconfig
make menuconfig
#开启以下配置并保存
#Enable the block layer -->
# Partition Types -->
# [*]EMMC PARTITION table support  (该项可支持识别uboot下emmc命令创建的分区,根据需要选择是否打开)
#Device Drivers -->
# [*]MMC/SD/SDIO card support -->  (mmc子系统中block和core层驱动)
# [*]HW reset support for eMMC
# [*]Simple HW reset support for MMC
# [*]MMC block device driver
# [*]SStar SoC platform drivers -->
# <*>EMMC driver   (emmc 驱动,依赖“MMC/SD/SDIO card support”)
# [*]UNIFY EMMC DRIVER
# < >SStar SD/MMC Card Interface Support (不要选中)
make clean; make -j32
#替换project下编译出来的kernel bin档
cp arch/arm/boot/uImage.xz ../project/image/output/images/kernel

现在project下编译出的的image包里uboot和kernel都支持emmc driver了,即支持emmc做storage。

使用该image按照第3章烧录方法操作即可实现emmc storage。

2.4. Emmc boot 编译示例

stable01_i6e_i6b0_ipc分支下,可以在alkaid下可以编译Pudding平台支持emmc boot的image。在做这一节的操作前最好保留2.3节其他方式启动编译出的image包。

2.4.1. Project 编译

进入project 目录,编译alkaid。以Pudding, SSC013A-S01A-S开发板为例。

cd project/
./setup_config.sh configs/ipc/i6e/emmc.glibc-ext4fs.013a.256.bga
make clean; make image-nocheck –j32;

得到的image烧录包的路径为:image/output/images。可以直接使用该image包到下一章进行烧录操作。

2.4.2. Boot & kernel 编译

使用上述方法可以得到支持emmc boot的image,但是它的配置是固定的,如果需要改配置,要在uboot/kernel下根据需要编译出符合要求的image,然后再将这些image替换到image烧录包中。编译方法参见2.2节uboot/kernel编译方法。


2.5. EMMC 和 SD共存问题

如果芯片内部包含两颗SD IP,在kernel下可以实现SD和EMMC共存。

2.5.1. 配置dts sd驱动切换IP

SD配置相关的dts文件一般有两个,一个是公共dtsi文件(如:infinity6b0.dtsi),另一个为芯片特有dts文件(如:infinity6b0-ssc009b-s01a.dts)。如下图所示:

图 2‑1: infinity6b0.dtsi sdmmc dts展示

图 2‑2:infinity6b0-ssc00b-s01a.dts sdmmc dts展示

设置slotnum为1则表示使用1个IP(即只有一个slot有效)。而当slotnum为1时,使用的属性为图2‑1中各属性的第一项。如果希望只使用一个slot并且是IP SDIO对应的那个slot,则需要把所有除了interrupt-name, interrupt-extended和clock以外的所有属性的第二项的值移至第一项去。再把源码该变量中的第二项成员移至第一项:

图 2‑3:driver/sstar/sdmmc/ms_sdmmc_lnx.c源码展示

这样就实现了只使用IP SDIO的那个一个slot了。

2.5.2. 配置dts emmc驱动切换IP

Ispahan的IP SD和IP SDIO均支持emmc,可以通过dts配置emmc使用哪个IP。

图 2‑4:infinity6b0.dtsi emmc dts展示

如上图所示,图上dts配置着emmc使用IP SD,可如注释所示改变属性,可配置emmc使用IP SDIO。

注意:Ispahan的uboot也可以配置使用IP SD或是IP SDIO。

代码位置:

drivers/mstar/emmc/inc/config/eMMC_infinity6b0_uboot.h

图 2‑5:Ispahan EMMC IP选择

如上图所示,宏IP_SELECT定义为IP_SD时,emmc使用IP SD,即slot0;定义为IP_SDIO时,emmc使用IP SDIO,即slot1。

2.5.3. 配置dts使sd驱动用作sdio

当需要把sd slot用作sdio wifi时,可以通过配置dts实现,以Pudding SSC013A-S01A为例。

图 2‑6:infinity6e.dtsi sdmmc dts展示

图 2‑7:infinity6e-ssc013a-s01a.dts sdmmc dts展示

把sdmmc驱动配置为sdio,需要改变以下属性:

  1. slot-sdio-use对应位置的值设为1,表示该slot用作sdio;

  2. slot-removable对应位置的值设为0,表示不可移除;

  3. slot-fakecdzs对应位置的值设为1,表示认为卡始终存在。

2.5.4. sdmmc与emmc共存配置选项

根据需求把dts文件修改完成后,再make menuconfig将emmc与sdmmc驱动选项都选中打开,这样编译出来的kernel就同时支持使用sdmmc和emmc了。以Pudding SSC013A-S01A为例。

cd kernel/
make infinity6e_ssc013a_s01a_defconfig
make menuconfig
#开启以下配置并保存
#Enable the block layer -->
# Partition Types -->
# [*]EMMC PARTITION table support  (该项可支持识别uboot下emmc命令创建的分区,根据需要选择是否打开)
#Device Drivers -->
# [*]MMC/SD/SDIO card support -->  (mmc子系统中block和core层驱动)
# [*]HW reset support for eMMC
# [*]Simple HW reset support for MMC
# [*]MMC block device driver
# [*]SStar SoC platform drivers -->
# <*>EMMC driver   (emmc 驱动,依赖“MMC/SD/SDIO card support”)
# [*]UNIFY EMMC DRIVER
# <*>SStar SD/MMC Card Interface Support (不要选中)
make clean; make -j32
#替换project下编译出来的kernel bin档
cp arch/arm/boot/uImage.xz ../project/image/output/images/kerne;

3. 烧录方法


3.1. 常见问题及解决方法

3.1.1. Uboot启动阶段,emmc初始化失败

图 3‑1:emmc初始化无回复

如图,该打印表示cmd1没有回复,即emmc不回复。一般是硬件连接导致的,排查思路是:

  1. 确认一下emmc有没有连接正确;

  2. 用万用表测量上电后的emmc各pin脚电压是否正常,正常情况下,emmc各pin脚电压分别为:CLK – 1.65V, CMD&DAT[3:0]&RST – 3.3V。

3.1.2. emmc rmgpt报错

执行estar报rmgpt错误,没有该分区, estar之前先执行“emmc create test 0x200"。

图 3‑2:emmc rmgpt报错

3.1.3. emmc 命令报错

estar烧写过程报kernela分区不存在,可能是boot本身问题,需要更新下版本。

图 3‑3:emmc 命令报错

3.1.4. Kernel镜像识别错误

这是因为替换了emmc的kernel后size变大了,需要修改set_config:跟进kernel的大小,如当前编译出来的为1956Kb,设定如下:

原来:setenv bootcmd ' emmc read.p 0x21000000 kernela 0x1D0594;bootm 0x21000000;

修改后:setenv bootcmd ' emmc read.p 0x21000000 kernela 0x1E9000;bootm 0x21000000;

图 3‑4:kernel load失败

3.1.5. insmod报错

estar烧写完后,报insmod错误,版本差异问题。

图 3‑5:kenel驱动模块insmod报错

3.1.6. kernel下emmc无回复

进入kernel,发现ls /dev/mmcblk0*已产生emmc 设备节点,但是使用dd等命令操作emmc时,报emmc无回复 error。使用lsmod命令,发现kdrv_sdmmc.ko已经被加载,说明ip已被sdmmc驱动抢占。需要返回2.3节其他方式启动,确认是否有在编译之前有成功关掉sdmmc。

图 3‑6:kernel下emmc无回复

图 3‑7:已加载模块展示

3.1.7. emmc load uboot失败报错

可以正常进入kernel,但跳帽到emmc,4bit启动就报错了,这个打印Boot TMO!就是复位失败了,可能是emmc不支持软复位,需要替换使用硬复位的image。最后一句报错是硬件emmc状态异常,需要检测硬件问题。

图 3‑8:emmc load uboot失败报错


3.2. 在UBOOT下使用estar自动烧录

如果开发板支持多种启动方式(如EVB板)就可以使用该方式烧录emmc boot。

3.2.1. spinand或者spinor启动,emmc做存储器

进入uboot命令行。

确认已经设置好了tftp软件路径(指向2.2节#uboot/kernel编译方法 project编译出的image包)和IP,设置好了开发板的IP。

设置serverip实例:

set -f gatewayip 172.19.32.254  
set -f ipaddr 172.19.32.80  
set -f netmask 255.255.255.0  
set -f serverip 172.19.32.89  
saveenv

在uboot命令行下键入estar,等待烧录完成。

烧录完成后,重启进入uboot,发现能使用emmc命令,在kernel下能识别和读写emmc分区,进入系统后查看是否存在节点/dev/mmcblk*, 能使用dd或hexdump命令读写/dev/mmcblk*, 则说明emmc作存储成功了。关于uboot下emmc操作命令和kernel下读写操作,下一章详细叙述。

烧录完成后重启之前,注意:

  1. boot strapping要跳过sd卡。emmc和sd共pad,如果不跳过,rom code中会检测sd卡,检测不到或启动失败都会关掉电源,emmc将不能正常使用。

  2. 插上电源常供电跳帽。

3.2.2. emmc启动及emmc做存储器

完成上一节操作,此时在uboot命令行下支持emmc命令。

将tftp软件路径指向2.1节project编译出的的image包。

键入estar命令,这时候image包中的自动烧录脚本会把启动需要用到的image包烧录到emmc设备中。

estar完成后,将boot strapping改为emmc 4bit启动,上电却发现不能进入kernel,这是因为刚刚estar时,环境变量没有烧入到emmc中,而是烧到nand flash里了。这时候只需要再设置一遍环境变量就好了:

注释:环境变量能否烧入到emmc中与当前使用的Uboot有关。

set -f gatewayip 172.19.32.254  
set -f ipaddr 172.19.32.80  
set -f netmask 255.255.255.0  
set -f serverip 172.19.32.89  
saveenv  
estar scripts/set_config

然后重启,就会发现可以进入到kernel了。


3.3. 制作ext4镜像与烧录

  1. 制作ext4测试镜像。

    image/output/images/目录下创建一测试目录data_test,在目录里放上测试文件。

    cd project/image
    ./build/mke2fs –d {input_folder} –t ext4 {output_folder} {image_size}M
    #例如: ./build/mke2fs –d ./output/images/data_test –t ext4 ./output/images/data_test.ext4 60M
    #注意: {image_size}不能小于{input_folder}size,否则数据会丢失。
    #在 ./output/images目录下发现已生成data_test.ext4,但它size过大,使用tftp传输有size限制,于是我们需要用split命令把data_test.ext4切割成几个小文件。关于大文件的分割下载与升级介绍见6.6.1。
    cd output/images
    split –b 20971520 data_test.ext4 data_test.ext4_
    #发现data_test.ext4已被分割为三个size为20M的镜像:data_test.ext4_aa, data_test.ext4_ab和data_test.ext4_ac。
    
  2. 重启开发板,进入uboot,创建data_test分区用于存放data_test.ext4镜像。

    emmc create data_test 0x40000000
    

    data_test.ext4镜像烧录进emmc data_test分区中。

    tftp 0x21000000 data_test.ext4_aa
    #在emmc write.p.continue命令详细介绍见4.1.7
    emmc write.p.continue 0x21000000 data_test 0x0 0x1400000
    tftp 0x21000000 data_test.ext4_ab
    emmc write.p.continue 0x21000000 data_test 0xA000 0x1400000
    tftp 0x21000000 data_test.ext4_ac
    emmc write.p.continue 0x21000000 data_test 0x14000 0x1400000
    
  3. 镜像烧录完成,重启开发板进入kernel,发现已有/dev/mmcblk0p5节点,挂载mount –t ext4 /dev/mmcblk0p5/mnt。检查/mnt目录中是否有data_test中预先放置的测试文件。

  4. 键入df –h dev/mmcblk0p5查看/dev/mmcblk0p5发现其size仅为data_test.ext4的size大小,而非emmc命令创建data_test分区时设定的size。扩容:resize2fs /dev/mmcblk0p5;


3.4. USB空片烧录

3.4.1. 准备工具

编译好的image烧录包、USBDownloadTool及配套文件、一根USB线。

3.4.2. 烧录流程

打开开发板电源,此时是空片所以无法启动。

用USB连接把开发板和PC,等待设备管理器中的磁盘驱动器识别到USB device即识别成功。这个过程可能需要几分钟。

图 3‑9:pc识别usb设备展示

将USBDownloadTool及配套文件拷贝到images/路径下(即和auto_update.txt为同一级)。等待USB识别成功后,双击运行USBDownloadTool-nopad.exe。

图 3‑10:usb空片烧录目录展示

程序运行后点击Upgrade Firmware,然后等待烧录完成。

图 3‑11:usb烧录展示

USB烧录完成。


3.5. 使用烧录器空片烧录

3.5.1. 烧入BOOT_PART.bin

将emmc分区切至boot0分区(或boot1),然后将BOOT_PART.bin文件烧入到0地址处。

3.5.2. 制作system母片镜像

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

3.5.2.1. 环境变量镜像

把需要设置的环境变量按照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工具,命令参数如下:

jz.xiang@xmbc6405:/home/jz.xiang/workspace/i6e/boot$ cd tools/
jz.xiang@xmbc6405:/home/jz.xiang/workspace/i6e/boot/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生成环境变量镜像
3.5.2.2. UDA分区配置文件

emmcnize工具通过读取ini配置文件来建立分区表和打包镜像。配置文件格式如下:

[env]
inmage=env.bin
vol_id=0
vol_size=0x15000
vol_name=""

[kernela-volume]
image=kernel
vol_id=1
vol_size=0x300000
vol_name=kernela

[rootfsa-volume]
image=rootfs.ext4
vol_id=2
vol_size=0x2000000
vol_name=rootfsa

[usera-volume]
image=miservice.ext4
vol_id=3
vol_size=0x2000000
vol_name=usera

[data-volume]
image=customer.ext4
vol_id=4
vol_size=0x4000000
vol_name=data

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

vol_id=X,定义分区id,目前用于标识而已。

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

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

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

3.5.2.3. 打包母片镜像

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

./emmcnize part.ini image.bin

其中part.ini为分区配置文件,image.bin为输出的完整镜像。

正常情况下,完成操作会打印如下所述的“done”信息。

parsing section "data-volume"  
volume id: 4  
volume size: 67108864 bytes  
volume name: data  

write to volume4 from image file customer.ext4


done

若配置文件指定了某个文件,但是没有放入指定镜像文件,那么会提示空文件,不影响完整镜像的生成,但是生成的镜像不会包含需要部分镜像可能导致无法启动。


4. uboot 下的 eMMC 命令操作

emmc在硬件层面上已经有分区:UDA, boot0, boot1以及其他我们没有用到的分区如RPMB, GPP分区。uboot下的mmc命令能够识别并操作上述分区。

将emmc作为启动时,为了更好的利用emmc资源,我们从UDA分区再划分出kernel(p1),rootfs(p2),user(p3),data(p4)这四个分区。uboot下的emmc命令能够识别并操作上述分区。


4.1. EMMC 命令说明

以下指令专门用于操作 UDA 分区自定义分区表:

4.1.1. emmc create

  • 格式

    emmc create [name] [size]
    
  • 说明

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

  • 示例

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

    emmc create p1 0xA00000

4.1.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)
    SigmaStar #
    

4.1.3. emmc remove

  • 格式

    emmc remove [name]
    
  • 说明

    删除指定名称的分区

  • 示例

    删除 p1 分区

    emmc remove p1

4.1.4. emmc rmgpt

  • 格式

    emmc rmgpt

  • 说明

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

4.1.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

4.1.6. emmc write.p

  • 格式

    emmc write.p [addr][partition_name][size]
    
  • 说明

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

  • 示例

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

    emmc read.p 0x21000000 p1 0x1000

4.1.7. mmc write.p.continue

  • 格式

    emmc write.p.continue [addr] [partition_name] [offset] [size]
    
  • 说明

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

  • 示例

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

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

4.1.8. emmc read.p.continue

  • 格式

    emmc read.p.continue [addr] [partition_name] [offset] [size]
    
  • 说明

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

4.1.9. emmc erase.p

  • 格式

    emmc erase.p [name]
    
  • 说明

    格式化指定分区

  • 示例

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

    emmc erase.p p1

4.1.10. emmc erase

  • 格式

    emmc erase

  • 说明

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


4.2. mmc 命令说明

eMMC 的每一个硬件分区的存储空间都是独立编址的,即访问地址为 0 - partition size。

具体的数据读写操作实际访问哪一个硬件分区,由 eMMC 的 Extended CSD register 的 PARTITION_CONFIG Field 中的Bit[2:0]: PARTITION_ACCESS 决定,用户可以通过配置 PARTITION_ACCESS 来切换硬件分区的访问。也就是说,用户在访问特定的分区前,需要先发送命令,配置 PARTITION_ACCESS,然后再发送相关的数据访问请求。

更多数据读写相关的细节,请参考EMMC总线协议。

下面截取相关寄存器定义:

图 4‑1:BOOT_BUS寄存器位展示

图 4‑2:PART_CONF 寄存器展示

4.2.1. mmc dev

  • 格式

    mmc dev [dev] [part]
    
  • 说明

    切换物理分区 dev:mmc 设备编号,第一个为 0 part: 0 表示不访问引导分区 1 表示访问引导分区 1(boot0) 2 表示访问引导分区 2(boot1)

  • 示例

    切换到引导分区 1

    mmc dev 0 1

4.2.2. mmc bootbus

  • 格式

    mmc bootbus [dev] [boot_bus_width] [reset_boot_bus_width] [boot_mode]
    
  • 说明

    设置总线位宽

    dev:mmc 设备编号

    boot_bus_width:总线宽度,1-4bit

    reset_boot_bus_width:在启动完成后是否仍保持bus width?1:是,0:否。默认为0即可。

    boot_mode:传输模式,0:sdr(单边沿)+默认速率(12.5M),1:sdr+高速模式(48M),2:ddr(双边沿)。默认为0即可。

  • 示例

    设置总线位宽为 4

    mmc bootbus 0 1 0 0

4.2.3. mmc partconf

  • 格式

    mmc partconf [dev ] [boot_ack ] [boot_partition ] [partition_access]
    
  • 说明

    设置启动分区

    dev:mmc 设备编号

    boot_ack:是否应答

    boot_partition:用户选择发送到主机的引导数据

    partition_access:用户选择要访问的分区

  • 示例

    设置从引导分区 1 为启动分区

    mmc partconf 0 1 1 1

4.2.4. mmc read

  • 格式

    mmc read [addr] [blk] [cnt]

  • 说明

    从指定块偏移地址读取数据

    addr:读取到内存地址

    blk:块偏移地址(单位 block)

    cnt:多少块

  • 示例

    把 eMMC 的 0x0 地址共 0x200 块数据写到内存 0x21000000 处

    mmc read 0x21000000 0x0 0x200

4.2.5. mmc write

  • 格式

    mmc write [addr] [blk] [cnt]

  • 说明

    把内存数据写到指定块偏移地址

    addr:读取到内存地址 blk:块偏移地址(单位 block)

    cnt:多少块

  • 示例

    把内存 0x21000000 的数据写到块地址 0x0,0x200 个块数据

    mmc write 0x21000000 0x0 0x200

  • 注意

    (1) 用 尝试用mmc read write去访问 eMMC 的 的 UDA 分区,读写会破坏分区表,如果要支 持,需要修改相应代码。

    (2) 到 切换到 boot 区后需要再执行下 mmc partconf 设置,否则会导致无法从 boot 区启动


4.3. fat命令对emmc storage的支持

emmc分区在格式化为fat文件系统后,可以支持fatls和fatload命令。

4.3.1. fatls

  • 格式

    fatls <interface> [<dev[:part]>] [directory]
    
  • 说明

    读取某接口下第n个设备的第n个分区中的某目录下的所以文件内容。

    interface:sd卡和emmc卡都属于mmc设备

    dev: 设备编号,根据IP编号,缺省为0

    part:与emmc part命令下的分区号对应。

    directory:目录,使用绝对路径。

  • 示例

    打印出emmc第一个分区内,根目录的内容

    fatls mmc 0:1 /

4.3.2. fatload

  • 格式

    fatload <interface> [<dev[:part]> [<addr\> [<filename> [bytes[pos]]]]]
    
  • 说明

    读取某接口下第n个设备的第n个分区中的某个文件读取特定大小数据到指定地址的ddr中。

    addr:目标内存地址,ddr地址,使用真实物理地址。

    filename:需要load的文件名,使用绝对路径文件名。

    bytes:load的数据大小,以byte为单位,16进制数,若为0则读取整份文件。

    pos:目标文件中的偏移量。如目标文件数据"123456", 若pos为1,则load文件时从‘1’位置开始读取。

  • 示例

    将emmc第一个分区内根目录下的demo.sh文件读取512个byte到ddr的0x21000000处

    fatload mmc 0:1 0x21000000 /demo.sh 0x200


5. kernel下操作emmc的方法

kernel可以识别uboot下用emmc create创建出的分区,但是不会显示其分区名,而是根据顺序显示为mmcblk0p1, mmcblk0p2.....

上述启动用的分区p1,p2,p3,p4是不支持烧入文件系统的,如果强行将它们烧入文件系统,那下次启动时将无法启动。

非启动分区和平常的分区无异,可以烧入文件系统并挂载等等。注意:kernel下使用fdisk命令新建的分区在UBOOT下,emmc命令是识别不了的。

在kernel启动后,ls /dev/mmc*可以看到kernel已识别出的emmc的分区。这里重点就说明一下启动分区的操作。


5.1. 启动分区操作

启动分区不支持文件系统,如果强行制作文件系统,则启动时会找不到image,所以读写只能支持二进制数据流方式。

5.1.1. boot分区权限控制

# boot1分区允许写入
echo 0 > /sys/block/mmcblk0boot1/force_ro
# boot0分区禁止写入
echo 1 > /sys/block/mmcblk0boot0/force_ro

5.2. 设置默认引导分区

# 设置boot0分区为默认引导分区
echo 1 > /sys/devices/soc0/soc/soc:emmc/eMMC_set_partconf
# 设置boot1分区为默认引导分区
echo 2 > /sys/devices/soc0/soc/soc:emmc/eMMC_set_partconf

5.2.1. 读

hexdump -v -n 255 -s 0 /dev/mmcblk0boot0

如上,最后一个参数/dev/mmcblk0/boot0表示要读的分区,-n后跟要打印的size,-s后是读取的首地址。

5.2.2. 写

dd count=20 bs=10k of=/dev/mmcblk0boot1 if=./BOOT_PART.bin

of后跟目标分区,if后跟要写入的文件,count x bs为写入的数据大小。写入分区0地址处。


5.3. emmc storage操作

当emmc做存储器时,它可以像普通存储器一样,制作文件系统,支持文件操作命令。此时boot0,boot1分区由于容量小,可忽略。P1~4分别为kernel、rootfs、misc和data启动分区,不能使用,我们需要先在uboot下使用emmc create test 0x2000000创建分区,该分区将在kernel下被识别为/dev/mmcblk0p5。

5.3.1. 制作文件系统

mkfs.vfat /dev/mmcblk0p5

还可以是其他文件系统。

5.3.2. 挂载设备

mount -t vfat /dev/mmcblk0p1 /mnt

挂载完之后就可以进行常规读写操作了。


6. 单系统操作示例


6.1. 分区设计

图 6‑1:分区设计图

Partition中的分区可以根据需要自行调整。调整的位置为/project/image/configs/m6/emmc.ext4fs.partition_signal_system.config

图 6‑2:分区表设计配置

如上图所示,“#user partition name and size(byte unit)”前面定义了生成的image包里的rootfs、miservices和customer文件的信息,之后定义了其对应分区的相关信息。这些都是根据需要进行调整的。


6.2. 设置环境变量

环境变量 参数 说明
bootcmd 正常启动的参数
bootargs 正常启动的参数

下面为具体的环境变量设置:

setenv bootargs ' console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rootfstype=ext4 rw init=/linuxrc LX_MEM=0xffff0000 mma_heap=mma_heap_name0,miu=0,sz=0x9E9C000 cma=64M
setenv bootcmd ' emmc read.p 0x21000000 kernela 0x1C61E8;bootm 0x21000000;
saveenv

6.3. 删除所有分区

emmc rmgpt //emmc erase 也可以,只不过这个操作会擦除所有 UDA 数据(包括表头和环境变量)


6.4. 创建分区

emmc create kernela 0xA00000  
emmc create rootfsa 0xC800000  
emmc create usera 0x12C00000  
emmc create data 0x83300000

图 6‑3:显示创建的分区

注意:创建分区并不会格式化为ext4,需要写入ext4格式文件,或者在linux下通过mkfs.ext4工具自行格式化才能正常挂载。


6.5. 写入boot0分区数据

mmc dev 0 1  
mmc bootbus 0 1 0 0  
tftp 0x21000000 boot/BOOT_PART.bin  
mmc write 0x21000000 0x0 0x200  
mmc partconf 0 1 1 0 #升级之后从 boot0 启动

6.6. 写入system分区数据

tftp 0x21000000 kernel  
emmc erase.p kernela  
emmc write.p 0x21000000 kernela 0x400000  
tftp 0x21000000 rootfs.ext4  
emmc erase.p rootfsa  
emmc write.p 0x21000000 rootfsa 0x1400000  
tftp 0x21000000 miservice.ext4  
emmc erase.p usera  
emmc write.p 0x21000000 usera 0x1400000

6.6.1. 大文件分割下载和升级

# 写到 user 区的 customer_aX 文件是一个 ext4 文件通过分割指令
# 把约 50M 的文件分割为等份 20M(最后一个可能达不到),生成的文件分别名为 customer_aa,customer_ab,customer_ac
split -b 20971520 customer.ext4 customer_ 
tftp 0x21000000 customer_aa
emmc write.p.continue 0x21000000 usera 0x0 0x1400000
tftp 0x21000000 customer_ab
emmc write.p.continue 0x21000000 usera 0xA000 0x1400000
tftp 0x21000000 customer_ac
emmc write.p.continue 0x21000000 usera 0x14000 0xA00000

至此,启动所需要的image都已示范完成。