这里以基于 IMX6_L4.1.15_2.1.0_MFG_TOOL 修改后的文件为说明,官方下载可以去 NXP 官网直接搜。
# mfgtool 工具
mfgtool 工具是 freescale 为 i.MX 系列处理器打造的 Linux Firmware (uboot/kernel) 烧录工具,被收购后由 NXP 维护,其工具支持单独烧录某一系统分区,支持烧录 spi flash、 nor flash、sd card、nand flash、emmc 等存储介质,只需简单的配置,即可将编译好的镜像文件和文件系统烧录到完整的板上。同时 mfgtool 工具也作为一个可量产性的工具,它支持多通道的烧录。
最新版的 mfgtool 工具可看:https://github.com/nxp-imx/mfgtools
对于官方 L4.1.15_2.1.0 版本,解压后里面有两个压缩包,两个压缩包的区别在名字上已经写的很详细了。 “without-rootfs” 和 “with-rootfs”,一个是没有文件系统和一个是具有文件系统,对比可以看到 without-rootfs 中的 rootfs 是个空的包。
# 配置文件
在该版本中,主要用到的配置 UICfg.ini、cfg.ini 以及 ucl2.xml。
# UICfg.ini
UICfg.ini 文件用于配置端口数量,表示同时支持多少个单板。
UICfg.ini 文件的格式如下:
[UICfg] | |
PortMgrDlg=1 |
例如,如果一次只支持一个单板,则应该设置 PortMgrDlg=1
。目前最多支持 4 块单板,所以 PortMgrDlg
可以设置为 1 - 4,默认为 1。
# cfg.ini
cfg.ini 文件用于配置目标芯片配置文件和目标操作列表。
该文件的格式如下所示:
[profiles] | |
chip = Linux | |
[platform] | |
board = SabreSD | |
[LIST] | |
name = SDCard | |
[variable] | |
board = sabresd | |
mmc = 0 | |
6uluboot = 14x14ddr3arm2 | |
6uldtb = 14x14-ddr3-arm2 | |
lite = | |
initramfs = fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.gz.u-boot | |
seek = 1 | |
rootfs = rootfs | |
6ulnor = qspi1 | |
part_nor = 0 | |
part_uboot = 0 | |
part_kernel = 1 | |
part_dtb = 2 | |
part_rootfs = 3 |
profiles/chip
为目标配置文件名称(不区分大小写)。LIST/name
为目标操作列表名称(区分大小写),可在profiles/CHIP_PROFILE/OS Firmware/ucl2.xml
文件中找到。ucl2.xml
内容在后续说明。platform/board
目前预留,未使用,请忽略。variable
为ucl2.xml
文件中的引用变量,其引用的方式为%…%
。
# ucl2.xml
以下为个人自用修改后的版本,适用于 6UL 和 6ULL:
<!-- | |
* Copyright (C) 2012, Freescale Semiconductor, Inc. All Rights Reserved. | |
* The CFG element contains a list of recognized usb devices. | |
* DEV elements provide a name, class, vid and pid for each device. | |
* | |
* Each LIST element contains a list of update instructions. | |
* "Install" - Erase media and install firmware. | |
* "Update" - Update firmware only. | |
* | |
* Each CMD element contains one update instruction of attribute type. | |
* "pull" - Does UtpRead(body, file) transaction. | |
* "push" - Does UtpWrite(body, file) transaction. | |
* "drop" - Does UtpCommand(body) then waits for device to disconnect. | |
* "boot" - Finds configured device, forces it to "body" device and downloads "file". | |
* "find" - Waits for "timeout" seconds for the "body" device to connect. | |
* "show" - Parse and show device info in "file". | |
--> | |
<UCL> | |
<CFG> | |
<STATE name="BootStrap" dev="MX6UL" vid="15A2" pid="007D"/> | |
<STATE name="BootStrap" dev="MX6ULL" vid="15A2" pid="0080"/> | |
<STATE name="Updater" dev="MSC" vid="066F" pid="37FF"/> | |
</CFG> | |
<LIST name="eMMC" desc="Choose eMMC as media"> | |
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%lite%%6uluboot%_emmc.imx" ifdev="MX6UL MX6ULL">Loading U-boot</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Kernel.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/%initramfs%" address="0x83800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Initramfs.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul%lite%-%6uldtb%-emmc.dtb" address="0x83000000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading device tree.</CMD> | |
<CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD> | |
<!-- create partition --> | |
<CMD state="Updater" type="push" body="send" file="mksdcard.sh.tar">Sending partition shell</CMD> | |
<CMD state="Updater" type="push" body="$ tar xf $FILE "> Partitioning...</CMD> | |
<CMD state="Updater" type="push" body="$ sh mksdcard.sh /dev/mmcblk%mmc%"> Partitioning...</CMD> | |
<!-- burn uboot --> | |
<CMD state="Updater" type="push" body="$ dd if=/dev/zero of=/dev/mmcblk%mmc% bs=1k seek=768 conv=fsync count=8">clear u-boot arg</CMD> | |
<!-- access boot partition --> | |
<CMD state="Updater" type="push" body="$ echo 0 > /sys/block/mmcblk%mmc%boot0/force_ro">access boot partition 1</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6ul%lite%%6uluboot%_emmc.imx" ifdev="MX6UL MX6ULL">Sending u-boot.bin</CMD> | |
<CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mmcblk%mmc%boot0 bs=512 seek=2">write U-Boot to sd card</CMD> | |
<CMD state="Updater" type="push" body="$ echo 1 > /sys/block/mmcblk%mmc%boot0/force_ro"> re-enable read-only access </CMD> | |
<CMD state="Updater" type="push" body="$ mmc bootpart enable 1 1 /dev/mmcblk%mmc%">enable boot partion 1 to boot</CMD> | |
<!-- create fat partition --> | |
<CMD state="Updater" type="push" body="$ while [ ! -e /dev/mmcblk%mmc%p1 ]; do sleep 1; echo \"waiting...\"; done ">Waiting for the partition ready</CMD> | |
<CMD state="Updater" type="push" body="$ mkfs.vfat /dev/mmcblk%mmc%p1">Formatting rootfs partition</CMD> | |
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk%mmc%p1"/> | |
<CMD state="Updater" type="push" body="$ mount -t vfat /dev/mmcblk%mmc%p1 /mnt/mmcblk%mmc%p1"/> | |
<!-- burn kernel --> | |
<CMD state="Updater" type="push" body="send" file="files/zImage">Sending kernel zImage</CMD> | |
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk%mmc%p1/zImage">write kernel image to sd card</CMD> | |
<!-- burn dtb --> | |
<CMD state="Updater" type="push" body="send" file="files/zImage-imx6ul%lite%-%6uldtb%-emmc.dtb" ifdev="MX6UL MX6ULL">Sending Device Tree file</CMD> | |
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk%mmc%p1/imx6ul%lite%-%6uldtb%.dtb" ifdev="MX6UL MX6ULL">write device tree to sd card</CMD> | |
<!-- burn rootfs --> | |
<CMD state="Updater" type="push" body="$ mkfs.ext3 -F -E nodiscard /dev/mmcblk%mmc%p2">Formatting rootfs partition</CMD> | |
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk%mmc%p2"/> | |
<CMD state="Updater" type="push" body="$ mount -t ext3 /dev/mmcblk%mmc%p2 /mnt/mmcblk%mmc%p2"/> | |
<CMD state="Updater" type="push" body="pipe tar -jxv -C /mnt/mmcblk%mmc%p2" file="files/%rootfs%.tar.bz2" ifdev="MX6UL MX6ULL">Sending and writting rootfs</CMD> | |
<CMD state="Updater" type="push" body="frf">Finishing rootfs write</CMD> | |
<CMD state="Updater" type="push" body="$ umount /mnt/mmcblk%mmc%p2">Unmounting rootfs partition</CMD> | |
<CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD> | |
</LIST> | |
<!-- burn uboot only because spi-nor flash is small (4M). kernel is beyond 5M now --> | |
<LIST name="Nor Flash" desc="Choose Nor flash as media"> | |
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%lite%%6uluboot%_sd.imx" ifdev="MX6UL MX6ULL">Loading U-boot</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Kernel.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/%initramfs%" address="0x83800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Initramfs.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul%lite%-%6uldtb%.dtb" address="0x83000000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading device tree.</CMD> | |
<CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD> | |
<CMD state="Updater" type="push" body="$ flash_erase /dev/mtd%part_nor% 0 0">Erasing Boot partition</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6ul%lite%%6uluboot%_%nor%.imx" ifdev="MX6UL MX6ULL">Sending u-boot.bin</CMD> | |
<CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mtd%part_nor% bs=1k seek=%seek%" ifdev="MX6UL MX6ULL">write U-Boot to NOR flash</CMD> | |
<CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD> | |
</LIST> | |
<LIST name="Quad Nor Flash" desc="Choose Quad Nor flash as media"> | |
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%lite%%6uluboot%_%6ulnor%.imx" ifdev="MX6UL MX6ULL">Loading U-boot</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Kernel.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/%initramfs%" address="0x83800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Initramfs.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul%lite%-%6uldtb%.dtb" address="0x83000000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading device tree.</CMD> | |
<CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD> | |
<CMD state="Updater" type="push" body="$ flash_erase /dev/mtd0 0 20">Erasing Boot partition</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6ul%lite%%6uluboot%_%6ulnor%.imx" ifdev="MX6UL MX6ULL">Sending u-boot.bin</CMD> | |
<CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mtd0 bs=1k seek=4" ifdev="MX6UL MX6ULL">write U-Boot to NOR flash</CMD> | |
<!--QSPI header--> | |
<CMD state="Updater" type="push" body="send" file="qspi-header.sh.tar">Sending qspi header shell</CMD> | |
<CMD state="Updater" type="push" body="$ tar xf $FILE "> Extracting...</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/%norconfig%">Sending QSPI header config file</CMD> | |
<CMD state="Updater" type="push" body="$ sh qspi-header.sh $FILE"> Generating the ascii value header</CMD> | |
<!--hexdump to convert ascii value to hex file--> | |
<CMD state="Updater" type="push" body="$ busybox hexdump -R qspi-tmp > qspi-header">Converting ascii value to hex file</CMD> | |
<CMD state="Updater" type="push" body="$ dd if=qspi-header of=/dev/mtd0 bs=1k seek=1" ifdev="MX6UL MX6ULL">Writing header to NOR flash</CMD> | |
<!--delete temporary files--> | |
<CMD state="Updater" type="push" body="$ rm qspi-tmp">Deleting temporary file</CMD> | |
<CMD state="Updater" type="push" body="$ rm qspi-header">Deleting temporary file</CMD> | |
<CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD> | |
</LIST> | |
<LIST name="NAND Flash" desc="Choose NAND as media"> | |
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%lite%%6uluboot%_%nand%.imx" ifdev="MX6UL MX6ULL">Loading U-boot</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Kernel.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/%initramfs%" address="0x83800000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading Initramfs.</CMD> | |
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul%lite%-%6uldtb%-%nanddtb%.dtb" address="0x83000000" | |
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL MX6ULL">Loading device tree.</CMD> | |
<CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD> | |
<!--burn the uboot to NAND: --> | |
<CMD state="Updater" type="push" body="$ mount -t debugfs debugfs /sys/kernel/debug">Mounting debugfs</CMD> | |
<CMD state="Updater" type="push" body="$ flash_erase /dev/mtd%part_uboot% 0 0">Erasing Boot partition</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6ul%lite%%6uluboot%_%nand%.imx" ifdev="MX6UL MX6ULL">Sending u-boot.bin</CMD> | |
<CMD state="Updater" type="push" body="$ kobs-ng init -x -v --chip_0_device_path=/dev/mtd%part_uboot% $FILE">Flashing Bootloader</CMD> | |
<!--burn the kernel to NAND: --> | |
<CMD state="Updater" type="push" body="$ flash_erase /dev/mtd%part_kernel% 0 0">Erasing Kernel partition</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/zImage">Sending kernel zImage</CMD> | |
<CMD state="Updater" type="push" body="$ nandwrite -p /dev/mtd%part_kernel% -p $FILE">Flashing Kernel</CMD> | |
<!--burn the dtb to NAND: --> | |
<CMD state="Updater" type="push" body="$ flash_erase /dev/mtd%part_dtb% 0 0">Erasing dtb partition</CMD> | |
<CMD state="Updater" type="push" body="send" file="files/zImage-imx6ul%lite%-%6uldtb%-%nanddtb%.dtb" ifdev="MX6UL MX6ULL">Sending Device Tree file</CMD> | |
<CMD state="Updater" type="push" body="$ nandwrite -p /dev/mtd%part_dtb% -p $FILE">Flashing dtb</CMD> | |
<!--burn the rootfs to NAND: --> | |
<CMD state="Updater" type="push" body="$ flash_erase /dev/mtd%part_rootfs% 0 0">Erasing rootfs partition</CMD> | |
<CMD state="Updater" type="push" body="$ ubiformat /dev/mtd%part_rootfs%"/> | |
<CMD state="Updater" type="push" body="$ ubiattach /dev/ubi_ctrl -m %part_rootfs%">Attaching UBI partition</CMD> | |
<CMD state="Updater" type="push" body="$ ubimkvol /dev/ubi0 -Nrootfs -m"/> | |
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mtd%part_rootfs%"/> | |
<CMD state="Updater" type="push" body="$ mount -t ubifs ubi0:rootfs /mnt/mtd%part_rootfs%"/> | |
<CMD state="Updater" type="push" body="pipe tar -jxv -C /mnt/mtd%part_rootfs%" file="files/%rootfs%.tar.bz2" ifdev="MX6UL MX6ULL">Sending and writting rootfs</CMD> | |
<CMD state="Updater" type="push" body="frf">Finishing rootfs write</CMD> | |
<CMD state="Updater" type="push" body="$ umount /mnt/mtd%part_rootfs%">Unmounting rootfs partition</CMD> | |
<CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD> | |
</LIST> | |
</UCL> |
这是一个 xml 文件,所以遵循 xml 语法,根元素 <UCL> <UCL/>
,它表示更新命令列表(Update Command List,UCL);标签 <CFG> </CFG>
,元素中包含可识别 usb 设备的列表;标签 <LIST> </LIST>
,元素 name
用于匹配 cfg.ini
文件中的 LIST/name
参数或脚本输入参数,元素 desc
用于描述说明;标签 <CMD> </CMD>
嵌套于 <LIST> </LIST>
下,属于命令标签,在不同的阶段下命令是不一样的(大致分为两个阶段 BootStrap 和 Updater),mfgtool 工具的命令分为主机特定命令(Host Specific Commands)与固件特定命令(Firmware Specific Commands),其中主机特定命令是由 mfgtool 工具解析和执行,而固件特定命令由目标设备上的固件运行解析和执行。
# 烧录文件
mfgtool 文件目录下的文件夹和文件非常多,除了上面的配置文件外,还有烧录脚本文件(.vbs)和烧录所需文件(uboot、kernel、dtb、rootfs)
# 烧录脚本文件
在 win 平台下,目录下的 MfgTool2.exe
就是烧写工具,以 .vbs
结尾的文件就是烧写的配置文件;而在 Linux 平台下, mfgtoolcli
是该平台的烧写工具,可以通过执行 linux-cvbs.sh
脚本转换 .vbs
文件为 Linux 平台下的脚本。
该烧写工具能支持多款 i.MX 系统的 SoC 系统烧写,还能支持 Nand Flash、eMMC 和 SD 卡等存储介质的烧写;因此,在对每一款 SoC 进行系统烧写之前,需要进行配置并指定好需要烧写的芯片以及存储介质等,然后通过执行相应的脚本文件运行;一般常用的脚本有如下几个:
脚本文件名 | 描述 |
---|---|
mfgtool2-yocto-mx-evk-emmc | EMMC 烧写脚本 |
mfgtool2-yocto-mx-evk-nand | Nand 烧写脚本 |
mfgtool2-yocto-mx-evk-qspi-nor-n25q256a | QSPI Flash 烧写脚本,型号为 n25q256a |
关于烧写脚本命令参数,其烧写工具命令行的格式如下:
MfgTool2.exe [-c] [chip profile folder name] [-l] [list name] [-p] [number] [-s] [variable=value]
一般我们只用到:
- -c:指定目标配置文件的名称。如果不指定则读取
cfg.ini
中profiles/chip
的值。 - -l:指示目标操作列表名称。如果不指定则读取
cfg.ini
中LIST/name
的值。 - -p:表示同时支持的单板数量。如果不指定则读取
UICfg.ini
中UICfg/PortMgrDlg
的值。 - -s:设置
ucl2.xml
中的变量值;支持多变量配置。如果不指定则读取cfg.ini
中所需的variable
引用变量值。
更多格式可看目录下的 ~\Document\V2\Manufacturing Tool V2 Quick Start Guide.docx
文档。
note:
可能会想,为什么没有列出 SD Card 烧写脚本,是因为用 SD Card 作烧写,用命令操作会好一点。
# 烧录所需文件
前面说到,在执行 ucl2.xml
的一系列操作中,存在两个阶段:
第一阶段(把系统烧写到 DRAM 中,然后 Jumping to OS image,以此为运行平台)
其所需的文件有:(以
ucl2.xml
中eMMC
标签为例)运行固件 下载文件 uboot firmware/u-boot-imx6ul%lite%%6uluboot%_emmc.imx kernel firmware/zImage initramfs firmware/%initramfs% dtb firmware/zImage-imx6ul%lite%-%6uldtb%-emmc.dtb 结合上面图表中可以看出来,存放第一阶段所需的固件路径是
profiles/CHIP_PROFILE/OS Firmware/firmware
,CHIP_PROFILE
是由cfg.ini
中的profiles/chip
参数或mfgtool2-yocto-mx-evk-emmc
脚本里-c
所带参数决定,不区分大小写;对应的文件也依据ucl2.xml
中BootStrap
状态下的file
元素定义的文件名为基准。tips:一般这里是不需要改动了,因为只是为了引导实际烧写而提供一个运行平台而已。
第二阶段(通过从 DRAM 中启动的运行平台将目标镜像固化到存储介质中)
其所需的文件有:(以
ucl2.xml
中eMMC
标签为例)目标固件 下载文件 uboot files/u-boot-imx6ul%lite%%6uluboot%_emmc.imx kernel files/zImage dtb files/zImage-imx6ul%lite%-%6uldtb%-emmc.dtb rootfs files/%rootfs%.tar.bz2 同样的,在第二阶段存放所需的固件路径是
profiles/CHIP_PROFILE/OS Firmware/files
,对应的文件则依据ucl2.xml
中Updater
状态下的file
元素定义的文件名为基准。
总结一下烧录流程:
第一步:烧录 profiles/CHIP_PROFILE/OS Firmware/firmware
路径下的 uboot、kernel、initramfs、dtb 到 DRAM 中;然后执行 Jumping to OS image,这时候在已运行的系统中去执行第二个步骤。
第二步:通过从 DRAM 中已经启动的系统上,将 profiles/CHIP_PROFILE/OS Firmware/files
路径下的目标固件 uboot、kernel、dtb、rootfs 烧写到存储介质中上,如 eMMC、Nand 等。因此在实际使用中,当需要更新系统或设备树时,真正需要更改的是这几个文件。