emmc擦除

Posted by 婷 on September 1, 2024 本文总阅读量

简介

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卡信息如下

image-20240831210309861

先将我们的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

image-20240831210011630

erase size

先给结论,emmc擦除的时候,是固定的擦除单位的整数倍,擦除单位的计算方法在spec中声明如下

image-20240831225311910

首先是读取CSD的寄存器的Erase group sizeErase group size multipiler

image-20240831231207196

从下面的描述可以看出第一步计算出来的擦除单位为(ERASE_GRP_SIZE + 1) * (ERASE_GRP_MULT +1)

image-20240831231129968

我们通过命令读取CSD寄存器的值

cat /sys/class/mmc_host/mmc0/mmc0\:0001/csd

image-20240901141110917

image-20240901141214375

计算可以得知擦除单位为(31+1)*(31+1)blocks,也就是1024个块

而流程图还有4.3HostHigh Cap卡的擦除单位计算,从前面的准备工作可以知道我们用的是16GBemmc卡,超过了2GB,属于是大容量卡,我们还需要看extCSD寄存器中的HC_ERASE_GRP_SIZEERASE_TIMEOUT_MULT的值是多少

image-20240901141643112

spec中对HC_ERASE_GRP_SIZE的说明如下,从描述可以看出,如果是大容量卡的擦除单位,还得看extCSD的第175byte的数值

image-20240901145257079

image-20240901145319943

extCSD的第175byte说明如下,如果bit00,则是我们前面一开始用CSD寄存器计算出来的擦除块大小,如果bit1,则擦擦除块为HC_ERASE_GRP_SIZE * 512KB

image-20240901145616640

我们对extcsd寄存器进行读取,可知并没有使能大容量擦除的方式,所以我们使用的这块卡擦除单位为1024块,也就是一次mmc erase命令就会擦掉512Kbyte

image-20240901142346725

erase cmd

mmc erase命令用法如下

image-20240831183200788

首先我们先读开头两块,读的内容放到内存空间0x80800000 - 0x80800400,确认现在其内容都是0x80

image-20240831210658466

现在我们对mmc dev 0的前两块进行擦除,执行命令可以看到警告The erase range would be change to 0x0~0x3ff

image-20240831210837074

按照前面的计算,我们应该是1024块都被擦除了,我们先读3个blocks看看,可以看到确实是被擦除了,全变为0了

image-20240831211315259

然后我们再读1025块看看,可以发现第1025块并没有受影响,确实是擦除了1024块

image-20240831211304207

再擦除1025块也是一样的,取整会擦2048块

image-20240831212915211

do_mmc_erase代码分析

从刚刚的报错信息入手,分析ubootmmc erase命令代码,执行流如下

image-20240831201337351

而最后执行擦除的动作则是在mmc_erase_t这个函数中,我们来看看这个函数

这个函数会发送三次CMD给emmc(这里暂时不讲SD卡部分的),分别是CMD35,CMD36,CMD38

image-20240831201643512

我们从spec开始查起,先看CMD具体是做什么的

image-20240831202058208

翻译一下就是

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中的寄存器决定的

image-20240831203818897

而写0还是写1则是由EXT_CSD[181]寄存器决定的,这是个只读的域

image-20240831203919541

其具体定义如下

image-20240831204031970

而前面我们擦除的卡的ERASED_MEM_CONT,在linux下用mmc命令读出来其数值为0,刚好跟前面的测试过程对上了

image-20240831204724940

思考

这里遗留个问题,从前面来看我们擦除动作是“写0”,那是mmc write写0快呢,还是mmc erase快呢?mmc write又需要几个CMD。从spec中看,其实erase动作,似乎只是解除某段地址的映射,并不是真正的内部的nand flash进行了擦除。

image-20240831214743577

参考链接