简介
在uboot
下烧写emmc
的时候,用mmc write
命令把内存地址中的数据写到emmc
中,有时候对镜像内容有要求,会进行一遍内存的擦除,全写1
。
mw.b 0x42000000 0xff 0xb00000
tftp 0x42000000 uImage
mmc write 0 0x42000000 0x800 0x5800
刚好想起uboot
下不是有mmc erase
命令吗,以之前flash
擦除的惯性思维带入,不是执行mmc erase
对要写入的块更方便么?
但其实不用mmc erase
是有两个原因的,一个是mmc erase
擦除的大小是擦除单位的整数倍,一个是mmc erase
并不一定是将指定的块全写1
准备工作
我们使用的emmc
卡信息如下
先将我们的emmc
的前20MB
内容全用0x80
填充
dd if=/dev/zero bs=1M count=20 | tr '\0' '\200' > hex80.bin
hexdump -C hex80.bin -n 0x10
dd if=hex80.bin of=/dev/mmcblk0 bs=1M count=20
erase size
先给结论,emmc
擦除的时候,是固定的擦除单位的整数倍,擦除单位的计算方法在spec
中声明如下
首先是读取CSD
的寄存器的Erase group size
跟Erase group size multipiler
从下面的描述可以看出第一步计算出来的擦除单位为(ERASE_GRP_SIZE + 1) * (ERASE_GRP_MULT +1)
我们通过命令读取CSD
寄存器的值
cat /sys/class/mmc_host/mmc0/mmc0\:0001/csd
计算可以得知擦除单位为(31+1)*(31+1)
个blocks
,也就是1024个块
而流程图还有4.3Host
跟High Cap
卡的擦除单位计算,从前面的准备工作可以知道我们用的是16GB
的emmc
卡,超过了2GB
,属于是大容量卡,我们还需要看extCSD
寄存器中的HC_ERASE_GRP_SIZE
跟ERASE_TIMEOUT_MULT
的值是多少
spec
中对HC_ERASE_GRP_SIZE
的说明如下,从描述可以看出,如果是大容量卡的擦除单位,还得看extCSD
的第175
byte的数值
而extCSD
的第175byte
说明如下,如果bit0
为0
,则是我们前面一开始用CSD
寄存器计算出来的擦除块大小,如果bit
为1
,则擦擦除块为HC_ERASE_GRP_SIZE * 512KB
我们对extcsd
寄存器进行读取,可知并没有使能大容量擦除的方式,所以我们使用的这块卡擦除单位为1024块,也就是一次mmc erase
命令就会擦掉512Kbyte
erase cmd
mmc erase
命令用法如下
首先我们先读开头两块,读的内容放到内存空间0x80800000 - 0x80800400
,确认现在其内容都是0x80
现在我们对mmc dev 0
的前两块进行擦除,执行命令可以看到警告The erase range would be change to 0x0~0x3ff
按照前面的计算,我们应该是1024块
都被擦除了,我们先读3个blocks看看,可以看到确实是被擦除了,全变为0了
然后我们再读1025块看看,可以发现第1025块并没有受影响,确实是擦除了1024块
再擦除1025块也是一样的,取整会擦2048块
do_mmc_erase代码分析
从刚刚的报错信息入手,分析uboot
的mmc erase
命令代码,执行流如下
而最后执行擦除的动作则是在mmc_erase_t
这个函数中,我们来看看这个函数
这个函数会发送三次CMD给emmc(这里暂时不讲SD卡部分的),分别是CMD35,CMD36,CMD38
我们从spec
开始查起,先看CMD具体是做什么的
翻译一下就是
CMD序号 | 参数 | 描述 |
---|---|---|
CMD35 | 如果是小于2GB的卡,则是以字节为地址,如果是大于2GB的卡,则是以块为地址 | 设置要开始擦除的第一组地址 |
CMD36 | 如果是小于2GB的卡,则是以字节为地址,如果是大于2GB的卡,则是以块为地址 | 设置擦除的最后一组地址 |
CMD38 | 参数为0则是发起erase动作,而其他情况可能是TRIM跟DISCARD,这里可以看上面的参数说明 |
至于参数中的地址,spec是如此说明的
The address field in the erase commands is an Erase Group address, in byte units for densities up to 2GB, and in sector units for densities greater than 2GB.
擦除的大小也是按照擦除单位进行取整,spec说明如下,跟前面的实验结果都是能对的上的
The Device will ignore all LSB’s below the Erase Group size, effectively rounding the address down to the Erase Group boundary.
总结起来就是,每次mmc erase
需要发送三个CMD,而且每次擦除的大小都是擦除单位的整数倍,所以还是慎用。
erase content
那erase命令弄清楚了,那擦除是全写1还是全写0呢?在Spec的6.6.9小节中提到擦除是写0还是写1是由具体的emmc卡的EXT_CSD中的寄存器决定的
而写0还是写1则是由EXT_CSD[181]
寄存器决定的,这是个只读的域
其具体定义如下
而前面我们擦除的卡的ERASED_MEM_CONT
,在linux下用mmc命令读出来其数值为0,刚好跟前面的测试过程对上了
思考
这里遗留个问题,从前面来看我们擦除动作是“写0”,那是mmc write
写0快呢,还是mmc erase
快呢?mmc write
又需要几个CMD。从spec中看,其实erase动作,似乎只是解除某段地址的映射,并不是真正的内部的nand flash进行了擦除。