在調試emmc的過程,我們需要用到命令讀寫emmc,燒錄,查看emmc寄存器,設置寄存器等功能,所以uboot和linux下都有各自的命令可以使用。
1、 uboot下mmc命令
1.1、mmc信息
查看mmc信息:mmc info
描述了emmc的速率、大小、塊大小等
MT7622> mmc info
Device: mmc@11230000
Manufacturer ID: 1
OEM: 100
Name: S4000
Bus Speed: 48000000
Mode: MMC DDR52 (52MHz)
Rd Block Len: 512
MMC version 5.1
High Capacity: Yes
Capacity: 3.6 GiB
Bus Width: 8-bit DDR
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 3.6 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
Boot area 0 is not write protected
Boot area 1 is not write protected
如果有多個mmc設備的時候,比如一個emmc、一個SD卡,這時候我們操作emmc之前需要先選擇emmc設備
MT7622> mmc dev 0
mtk_sd mmc@11230000: sclk: 255319, timing: 0
mtk_sd mmc@11230000: sclk: 24000000, timing: 0
mtk_sd mmc@11230000: sclk: 12000000, timing: 4
switch to partitions #0, OK
mmc0(part 0) is current device
1.2、GPT分區表讀取
查看gpt的分區地址后,這樣我們收到操作emmc的時候,也知道每個分區的內容,避免寫錯。
MT7622> mmc part
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00001000 0x00001fff "fip"
attrs: 0x0000000000000005
type: c12a7328-f81f-11d2-ba4b-00a0c93ec93b
guid: 5452574f-2211-4433-5566-778899aabb01
2 0x00002000 0x000027ff "ubootenv"
attrs: 0x0000000000000001
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
guid: 5452574f-2211-4433-5566-778899aabb02
3 0x00003000 0x0001afff "firmware"
attrs: 0x0000000000000000
type: cae9be83-b15f-49cc-863f-081b744a2d93
guid: 5452574f-2211-4433-5566-778899aabb03
4 0x0001b000 0x00032fff "firmware2"
attrs: 0x0000000000000000
type: cae9be83-b15f-49cc-863f-081b744a2d93
guid: 5452574f-2211-4433-5566-778899aabb04
5 0x00033000 0x000333ff "zbootconfig"
attrs: 0x0000000000000000
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
guid: 5452574f-2211-4433-5566-778899aabb05
燒錄的時候可以直接解析gpt中的firmware地址進行燒錄
gpt_partition_list=fip ubootenv firmware firmware2 zbootconfig mmcsda1
1.3、讀、寫、擦
mmc 的讀寫擦都是使用塊為單位,上面的mmc info可以知道一個block的大小是512KB
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
mmc讀操作:
mmc read 0x4007FF28 0x600 0x10
讀操作說明:從mmc設備塊上1536*512個字節處開始(1536是0x600的十進制),讀取16×512個字節(16是10的10進制)到內存0x10800000 處。
這邊的512是根據mmc的塊特性決定,上面mmcinfo里面的Block Len:512
以kernel為例,若前面的分區為94M(也就是kernel的分區從94M的地方開始),那么,0x600的地方的值應為:9421024的十六進制0x2F000。
讀到這個地址后,可以用md.b打印內存信息 md 內存地址 長度
md.b 0x4007FF28 0x1000
MT7622> md.b 0x4007FF28
4007ff28: 88 16 88 58 90 29 04 00 55 2d 42 6f 6f 74 00 00 ...X.)..U-Boot..
4007ff38: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
4007ff48: 00 00 00 00 00 00 00 00 00 00 e0 41 ff ff ff ff ...........A....
4007ff58: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ff68: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ff78: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ff88: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ff98: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ffa8: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ffb8: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ffc8: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ffd8: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007ffe8: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
4007fff8: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
40080008: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
40080018: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
寫操作:
mmc write 0x90000000 0x600 0x10
寫操作說明:把內存0x90000000開始,長度為16x512大小的數據,寫入到mmc設備塊偏移位置為0x600處。
擦除操作:
mmc erase 0x600 0x10
擦除操作說明:從mmc設備塊上1536*512個字節處開始(1536是0x600的十進制),擦除16×512個字節(16是10的10進制)。
1.4、固件升級
環境參數里面有很多命令參數
MT7622> printenv
boot_default=run boot_firmware
boot_firmware=led $bootled_pwr on ; run emmc_read_firmware && bootm $loadaddr#$bootconf ; led $bootled_pwr off
boot_tftp_firmware=tftpboot $loadaddr $bootfile_firmware && env exists replacevol && iminfo $loadaddr && run emmc_write_firmware ; if env exists noboot ; then else bootm $loadaddr#$bootconf ; fi
boot_tftp_write_bl2=tftpboot $loadaddr $bootfile_bl2 && run emmc_write_bl2
boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip
bootcmd=run boot_firmware
bootconf=config@1
bootdelay=3
bootfile_bl2=openwrt-mediatek-mt7622-ZH-A0501-EMMC-squashfs-emmc-1ddr-preloader.bin
bootfile_fip=ZH-A0501-u-boot.fip
bootfile_firmware=openwrt-mediatek-mt7622-ZH-A0501-EMMC-squashfs-sysupgrade.bin
bootled_pwr=zihome:blue
bootled_rec=zihome:yellow
bootmenu_0=Default boot command.=run boot_default
bootmenu_1=Boot firmware system from eMMC.=run boot_firmware ; run bootmenu_confirm_return
bootmenu_2=Load firmware system via TFTP then write to eMMC.=setenv noboot 1 ; setenv replacevol 1 ; run boot_tftp_firmware ; setenv noboot ; setenv replacevol ; run bootmenu_confirm_return
bootmenu_3=Load BL31+U-Boot FIP via TFTP then write to eMMC.=run boot_tftp_write_fip ; run bootmenu_confirm_return
bootmenu_4=Load BL2 preloader via TFTP then write to eMMC.=run boot_tftp_write_bl2 ; run bootmenu_confirm_return
bootmenu_5=Reboot.=reset
bootmenu_6=Reset all settings to factory defaults.=run reset_factory ; reset
bootmenu_confirm_return=askenv - Press ENTER to return to menu ; bootmenu 60
bootmenu_delay=3
bootmenu_title= ( ( ( OpenWrt ) ) ) [eMMC]
emmc_read_firmware=mmc dev 0 && part start mmc 0 $part_firmware part_addr && part size mmc 0 $part_firmware part_size && run mmc_read_vol
emmc_write_bl2=mmc dev 0 1 && mmc partconf 0 1 1 1 && mmc erase 0x0 0x400 && mmc write $loadaddr 0x0 0x100 ; mmc partconf 0 1 1 0
emmc_write_fip=mmc dev 0 0 && mmc erase 0x1000 0x1000 && mmc write $loadaddr 0x1000 0x1000 && mmc erase 0x2000 0x800
emmc_write_firmware=mmc dev 0 && part start mmc 0 $part_firmware part_addr && part size mmc 0 $part_firmware part_size && run mmc_write_vol
ethact=ethernet@1b100000
gpt_partition_list=fip ubootenv firmware firmware2 zbootconfig mmcsda1
ipaddr=192.168.2.119
loadaddr=0x4007ff28
mmc_read_vol=mmc read $loadaddr $part_addr 0x8 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr 0x$part_addr 0x$image_size
mmc_write_vol=imszb $fileaddr image_size && test 0x$image_size -le 0x$part_size && mmc erase 0x$part_addr 0x$part_size && mmc write $fileaddr 0x$part_addr 0x$fileblk
part_firmware=firmware
reset_factory=eraseenv && reset
reset_type=0
serverip=192.168.2.88
ver=U-Boot 2021.10 (Feb 18 2022 - 06:51:54 +0000)
Environment size: 2778/524283 bytes
升級的話我們可以使用上訴命令拆解,比如要升級fip文件。
正常我們是選擇3進行升級
bootmenu_3=Load BL31+U-Boot FIP via TFTP then write to eMMC.=run boot_tftp_write_fip ; run bootmenu_confirm_return
3的實際命令就是boot_tftp_write_fip命令,這個命令實際又是兩個命令組成
boot_tftp_write_fip=tftpboot $loadaddr $bootfile_fip && run emmc_write_fip
emmc_write_fip命令實際又是多個命令組成,所以我們可以一步一步自己執行
emmc_write_fip=mmc dev 0 0 && mmc erase 0x1000 0x1000 && mmc write $loadaddr 0x1000 0x1000 && mmc erase 0x2000 0x800
2、 linux下mmc命令
2.1、設備生成
內核啟動后,驅動會將MMC的幾個物理分區分別掛載成對應的設備
- mmcblk0boot0、mmcblk0boot1、mmcblk0rpmb這是三個獨立的分區,內核mtd不會使用到
- mmcblk0分區就用用戶分區,給內核mtd使用,只要再根據實際應用軟件mtd分區
[ 1.726828] mmc0: new DDR MMC card at address 0001
[ 1.736013] mmcblk0: mmc0:0001 S40004 3.64 GiB
[ 1.741029] mmcblk0boot0: mmc0:0001 S40004 partition 1 4.00 MiB
[ 1.747099] mmcblk0boot1: mmc0:0001 S40004 partition 2 4.00 MiB
[ 1.753180] mmcblk0rpmb: mmc0:0001 S40004 partition 3 4.00 MiB
[ 1.764627] Alternate GPT is invalid, using primary GPT.
[ 1.769988] mmcblk0: p1 p2 p3 p4 p5 p128
[ 2.704843] 13 cmdlinepart partitions found on MTD device EMMC
[ 2.710693] Creating 13 MTD partitions on "EMMC":
[ 2.715400] 0x000000000000-0x000000200000 : "gpt"
[ 2.720864] 0x000000200000-0x000000400000 : "fip"
[ 2.726225] 0x000000400000-0x000000600000 : "uboot-env"
[ 2.732165] 0x000000600000-0x000003600000 : "firmware"
[ 2.742601] 2 fit-fw partitions found on MTD device firmware
[ 2.748319] 0x000000600000-0x0000008d0000 : "kernel"
[ 2.757981] 0x0000008e0000-0x000003600000 : "rootfs"
[ 2.763555] mtd: device 5 (rootfs) set to be root filesystem
[ 2.769277] 0x000003600000-0x000006600000 : "firmware2"
[ 2.779141] 0x000006600000-0x000006680000 : "zbootconfig"
在設備管理下可以看到mmc的塊設備和mtd的塊設備
oot@openwrt:~# cat /proc/partitions
major minor #blocks name
179 0 3817472 mmcblk0
179 1 2048 mmcblk0p1
179 2 1024 mmcblk0p2
179 3 49152 mmcblk0p3
179 4 49152 mmcblk0p4
179 5 512 mmcblk0p5
259 0 2031 mmcblk0p128
179 24 4096 mmcblk0rpmb
179 16 4096 mmcblk0boot1
179 8 4096 mmcblk0boot0
31 0 2048 mtdblock0
31 1 2048 mtdblock1
31 2 2048 mtdblock2
31 3 49152 mtdblock3
31 4 2880 mtdblock4
31 5 46208 mtdblock5
31 6 49152 mtdblock6
mmc的操作命令在mmc-utils包中,支持很多命令,下面只介紹常用的幾個命令
2.2、讀取寄存器值
mmc有很多寄存器,所以有專門的寄存器查看命令
root@openwrt:~# mmc extcsd read /dev/mmcblk0
=============================================
Extended CSD rev 1.8 (MMC 5.1)
=============================================
Card Supported Command sets [S_CMD_SET: 0x01]
HPI Features [HPI_FEATURE: 0x01]: implementation based on CMD13
Background operations support [BKOPS_SUPPORT: 0x01]
Max Packet Read Cmd [MAX_PACKED_READS: 0x3f]
Max Packet Write Cmd [MAX_PACKED_WRITES: 0x3f]
Data TAG support [DATA_TAG_SUPPORT: 0x01]
Data TAG Unit Size [TAG_UNIT_SIZE: 0x00]
Tag Resources Size [TAG_RES_SIZE: 0x00]
Context Management Capabilities [CONTEXT_CAPABILITIES: 0x78]
Large Unit Size [LARGE_UNIT_SIZE_M1: 0x01]
Extended partition attribute support [EXT_SUPPORT: 0x03]
Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x05]
Power off notification [POWER_OFF_LONG_TIME: 0x64]
Cache Size [CACHE_SIZE] is 1024 KiB
Background operations status [BKOPS_STATUS: 0x00]
1st Initialisation Time after programmed sector [INI_TIMEOUT_AP: 0x0a]
Power class for 52MHz, DDR at 3.6V [PWR_CL_DDR_52_360: 0x00]
Power class for 52MHz, DDR at 1.95V [PWR_CL_DDR_52_195: 0x00]
Power class for 200MHz at 3.6V [PWR_CL_200_360: 0x00]
Power class for 200MHz, at 1.95V [PWR_CL_200_195: 0x00]
Minimum Performance for 8bit at 52MHz in DDR mode:
[MIN_PERF_DDR_W_8_52: 0x00]
[MIN_PERF_DDR_R_8_52: 0x00]
TRIM Multiplier [TRIM_MULT: 0x02]
Secure Feature support [SEC_FEATURE_SUPPORT: 0x55]
Boot Information [BOOT_INFO: 0x07]
Device supports alternative boot method
Device supports dual data rate during boot
Device supports high speed timing during boot
Boot partition size [BOOT_SIZE_MULTI: 0x20]
...
比如我們最常用的PARTITION_CONFIG值
root@Openwrt:/# mmc extcsd read /dev/mmcblk0 | grep PARTITION_CONFIG
Boot configuration bytes [PARTITION_CONFIG: 0x48]
2.3、修改啟動使能位
如下介紹:
mmc bootpart enable <boot_partition> <send_ack> <device>
Enable the boot partition for the <device>.
Disable the boot partition for the <device> if <boot_partition> is set to 0.
To receive acknowledgment of boot from the card set <send_ack>
to 1, else set it to 0
該接口就可以設置前面提到的BOOT_PARTITION_ENABLE的值,設置啟動分區。
方法1:使能boot1,將BOOT_PARTITION_ENABLE設置為1,設置完再讀出寄存器PARTITION_CONFIG的值看是否改變。
root@Openwrt:/# mmc bootpart enable 1 1 /dev/mmcblk0
root@Openwrt:/# mmc extcsd read /dev/mmcblk0 | grep PARTITION_CONFIG
Boot configuration bytes [PARTITION_CONFIG: 0x48]
方法2:使能UDA,將BOOT_PARTITION_ENABLE設置為7,設置完再讀出寄存器PARTITION_CONFIG的值看是否改變。
root@Openwrt:/# mmc bootpart enable 7 1 /dev/mmcblk0
root@Openwrt:/# mmc extcsd read /dev/mmcblk0 | grep PARTITION_CONFIG
Boot configuration bytes [PARTITION_CONFIG: 0x78]
2.4、允許寫入Boot分區
正常情況下,我們沒辦法往boot1和boot2分區寫內容,有寫保護;所以當我們要燒錄preloader的時候就需要去掉寫保護。
echo 0 > /sys/block/mmcblk0boot0/force_ro #將boot1的寫保護去掉
dd if=mtk-bpi-r64-preloader-emmc.bin of=/dev/mmcblk0boot0
mmc bootpart enable 1 1 /dev/mmcblk0