Hello community
I will leave here this guide to flash your iMX6 board if you are working on a Linux PC and don't have access to a computer with Windows or you just simply don't want to use windows and the Freescale Manufacturing Tool. It is also useful for stop using the windows manufacturing tool and to work completely from Linux.
To achieve this we will use two very important utilities, theimx_usb_loader
and theutp_com
utilities. Also, it is assumed that you know how to create your board images with yocto and you have done so. Also, it is recommended that you download the windows Mfg tool and have the ucl2.xml file at hand because this file is a good reference about how to flash the board.
If you are familiar with and know how to use the Windows Manufacturing tool then I recommend you to open the ucl2.xml file and compare this guide with that file for you to see how this works.
The imx_usb_loader is a utility that will take the Mfg images created by yocto and transfer them to the board RAM using the Serial Downloader Protocol (SDP). After this utility transfers the manufacturing image to the board, then the board will boot into this Mfg Linux image in RAM and then the board will enumerate as a SCSI generic device in your Linux machine. The board can be found under the /dev/ folder with the name sg* (/dev/sg0 in my case). Nevertheless, this name could be different on your system so I recommend that you analyze your /dev folder looking for changes before and after you run the imx_usb_loader to identify what name does your system give to the board.
What the imx_usb_loader utility does is equivalent to what the Mfg tool does with all the CMD state="BootStrap" commands found in the ucl2.xml file.
Once the board has booted into the Mfg Linux image then it will start accepting UTP commands and here comes the second part, the actual images flashing. With the utp_com utility, you can manipulate the board seen as a USB SCSI device on your Linux machine. You can run bash commands from your terminal without having to actually type anything directly on the board, and the board won't let you anyways. This way you can run sfdisk for example to see your board's flash partitions and to partition your flash. You run UTP commands on the board typing them on your Linux PC as follows:
./utp_com -d /dev/sg0 -c "$ sfdisk -l /dev/mmcblk3"
Assuming that your board flash is named mmcblk3. And you'll see the result of running this command on the serial terminal attached to your board. It is a bit awkward to type on your PC and having to see the results on the board terminal but it is what it is.
What the utp_com utility does is equivalent to what the Mfg tool does with all the CMD state="Updater" commands found in the ucl2.xml file.
The first you have to do is get and compile the utilities. For that, you just run the following commands. For the imx_usb_loader utility:
sudo apt-get install libusb-1.0-0-dev -y
git clone https://github.com/boundarydevices/imx_usb_loader.git
cd imx_usb_loader
make
And for the utp_com utility:
sudo apt-get install libsgutils2-dev -y
git clone https://github.com/ixonos/utp_com.git
cd utp_com
make
I recommend you to do this in your home directory for you to have the folders "~/imx_usb_loader" and "~/utp_com" at the end. This will facilitate the creation of a script for flashing the board and not having to type all of this manually.
Inside the imx_usb_loader folder, it is a file called mx6_usb_work.conf that is used by the utility to transfer the Mfg Linux image to the board. The following modifications are what I ended up doing after experimenting because the actual utility documentation does not contain any information about this and the little information on the README is very unclear and incomplete. The thing is that the imx_usb_loader utility knows what config file to use according to the configurations found in the imx_usb.conf file using a configured VID:PID pair. On this file, you should see a line with your board's VID:PID and a related "mx6_usb_work.conf" file. If you don't see your VID:PID pair then add it. Actually, you can name the .conf file whatever you want as long as you configure the imx_usb.conf file correctly but we'll use the one that comes with the tool because that makes things easier.
The original mx6_usb_work.conf file contents are very confusing, so I recommend you to erase everything because not all is needed. After erasing all the contents the following should be placed on the file. These are the contents if you are working with the iMX6 Solo X sabre board sd:
imx6-sabresd
#hid/bulk,[old_header,]max packet size, {ram start, ram size}(repeat valid ram areas)
hid,1024,0x10000000,1G,0x00907000,0x31000
# Note; only dcd as first step (setup ram)
firmware/u-boot-imx6sxsabresd-mfgtool.imx:dcd
# Then load a kernel with initramfs (self contained linux) at known address
firmware/zImage-mfgtool-imx6sxsabresd.bin:load 0x80800000
firmware/fsl-image-mfgtool-initramfs-imx6sxsabresd.cpio.gz.u-boot: load 0x83800000
firmware/zImage-mfgtool-imx6sx-sdb.dtb: load 0x83000000
# Now, we load a u-boot that expects preloaded software at known adress
# Note, to make this boot, the clear_dcd field seems necessary
firmware/u-boot-imx6sxsabresd-mfgtool.imx:clear_dcd,load,plug,jump header
The "load" addresses are taken from the ucl2.xml file. As you can see in the code above is that the files are specified to be in a folder called "firmware". This means that we have to copy the Mfg files from the build/tmp/deploy/images/imx6sxsabresd to a file called firmware inside the imx_usb_loader folder on home. This because when I tried this I realized that for some reason the imx_usb_loader was not able to grab the files from their original folder, I don't know if it's something to do with the length of the path but it seems that that is the reason. Anyways, copying the files solves the problem.
The final step is to create a couple of scripts to flash the board. This step is very helpful for not having to manually run all the commands and copying the files from the images folder to the firmware folder and so forth. Therefore the next scripts are very helpful to do all that automatically. Place both scripts in your project root folder, for example for the imx6 sabre sd board I have the folder fsl-release-bsp, therefore I would place both scripts into this folder.
This script verifies that both the imx_usb_loader and the upt_com utilities are present on the system. It also helps to copy the Mfg files from the original "images" folder to a "firmware" folder created inside the imx_usb_loader folder. It copies the files and after their transfer to the board, it deletes the folder. Finally, the script runs another script that has all the operations to be done on the board flash using UTP commands.
It is better to have the utp commands script as a separate set of commands from the imx_usb_loader script because you will be needing several versions of this UTP commands file to achieve different results. The following file I will call it "board-flash.sh"
#!/bin/bash
# p1.- imx_loader and utp_com path
# p2.- Flashing script with the UTP commands
RED='\e[1;37;41m'
GREEN='\e[1;37;42m'
YELLOW='\e[1;33m'
NC='\e[0m'
WORKING_DIR=`pwd`
IMX_USB_LOADER_NAME=imx_usb
UTP_COM_NAME=utp_com
# Search for the paths where imx USB loader and UTP com apps are located
IMX_USB_PATH=$1/imx_usb_loader
if [ ! -x $IMX_USB_PATH/$IMX_USB_LOADER_NAME ]
then
echo -e "${RED}-imx_usb_loader- application not found!${NC}"
echo -e "${YELLOW}Make sure that the <imx_usb_loader/imx_usb> app exists in the specified path${NC}"
exit 1 # fail
fi
UTP_COM_PATH=$1/utp_com
if [ ! -x $UTP_COM_PATH/$UTP_COM_NAME ]
then
echo -e "${RED}-utp_com- application not found!${NC}"
echo -e "${YELLOW}Make sure that the <utp_com/utp_com> app exists in the specified path${NC}"
exit 1 # fail
fi
# Establish the location of the files that will be flashed to the board
FLASH_IMAGE_DIR=$WORKING_DIR/build/tmp/deploy/images/imx6sxsabresd
MFG_IMAGE_DIR=$FLASH_IMAGE_DIR
if [[ -x ./$2 ]]
then
APP_FLASHING_SCRIPT=$2
else
echo -e "${RED}Invalid second input parameter${NC}"
echo -e "${YELLOW}It should be the name of the flashing script to execute${NC}"
echo -e "${YELLOW}Check that the second parameter is an executable bash script${NC}"
exit 1 # fail
fi
# Go to the imx_usb_loader folder
cd $IMX_USB_PATH
# Create the folder to transfer the Mfg files from their original location
mkdir firmware
# Here we get a copy of the /dev folder looking for "sg" devices (SCSI devices)
ls /dev/sg* | grep "sg" > firmware/dev-temp1.txt
IMX_USB_PRINT=`./imx_usb 2>&1`
if `echo "$IMX_USB_PRINT" | grep -q "Could not open device"`; then
echo -e "${RED}imx_usb returned error: Could not open device${NC}"
echo -e "${YELLOW}Try disconnecting and reconnecting the device and run this script again${NC}"
exit 1
fi
if `echo "$IMX_USB_PRINT" | grep -q "no matching USB device found"`; then
echo -e "${RED}imx_usb returned error: No matching USB device found${NC}"
echo -e "${YELLOW}Please make sure the board is connected to the USB port and the jumper is set to 'serial downloader mode'${NC}"
exit 1
fi
if `echo "$IMX_USB_PRINT" | grep -q "err=-"`; then
echo -e "${RED}imx_usb returned error:${NC}"
echo $IMX_USB_PRINT
exit 1
fi
# Copy the mfg files from the 'images' folder to the imx_usb_loader folder.
cp $MFG_IMAGE_DIR/u-boot-imx6sxsabresd-mfgtool.imx firmware/u-boot-imx6sxsabresd-mfgtool.imx
cp $MFG_IMAGE_DIR/zImage_mfgtool firmware/zImage-mfgtool-imx6sxsabresd.bin
cp $MFG_IMAGE_DIR/zImage-mfgtool-imx6sx-sdb.dtb firmware/zImage-mfgtool-imx6sx-sdb.dtb
cp $MFG_IMAGE_DIR/fsl-image-mfgtool-initramfs-imx6sxsabresd.cpio.gz.u-boot firmware/fsl-image-mfgtool-initramfs-imx6sxsabresd.cpio.gz.u-boot
# Execute imx_usb_loader to load into the board RAM the flashing OS
./imx_usb
echo "Getting the SG devices to obtain the SG device name of the board in UTP mode"
sleep 6
ls /dev/sg* | grep "sg" > firmware/dev-temp2.txt
# Get the SG device corresponding to the board by comparing the contents of /dev before
# and after our board is enumerated as a SCSI device.
DEVICE=`diff firmware/dev-temp1.txt firmware/dev-temp2.txt | grep '/dev/sg' | cut -c 3-`
# Delete the temporary files used
rm -rf firmware/
# Return to the project folder and call the script with the UTP commands
cd $WORKING_DIR
./$APP_FLASHING_SCRIPT $UTP_COM_PATH $DEVICE $WORKING_DIR $FLASH_IMAGE_DIR
The contents of the script are self-explanatory but in a nutshell, it does the following:
As you can see there are a couple of hard-coded items on the script that can be optimized, also, it's not very robust. Feel free to adapt the script however you want, or if you think about creating a better one, more universal, be my guest and please share if you do so.
The final script contains all the UTP commands that will be executed on the board to achieve your image flashing. I'll be using the commands for the iMX6SX found in the ucl2.xml file that comes originally with the windows Mfg tool as an example of how to create this file. If you already have a .xml file you are using that will help a lot because you just have to adapt it. The script contents are as follows and I will call the file "utp-flash-commands.sh"
#!/bin/bash
RED='\e[1;37;41m'
GREEN='\e[1;37;42m'
YELLOW='\e[1;33m'
NC='\e[0m'
# Use the UTP_COM utility to flash the application images
cd $1
# Create Partition
echo -e "${YELLOW}-> Sending partitioning shell script${NC}"
./utp_com -d $2 -c "send" -f ${3}/mksdcard.sh.tar
echo -e "${YELLOW}-> Decompresing script...${NC}"
./utp_com -d $2 -c "$ tar xf \$FILE"
echo -e "${YELLOW}-> Partitioning eMMC${NC}"
./utp_com -d $2 -c "$ sh mksdcard.sh /dev/mmcblk3"
# Setup u-boot partition
echo -e "${YELLOW}-> Access boot partition${NC}"
./utp_com -d $2 -c "$ echo 0 > /sys/block/mmcblk3boot0/force_ro"
echo -e "${YELLOW}-> Sending u-boot.bin${NC}"
./utp_com -d $2 -c "send" -f ${4}/u-boot-imx6sxsabresd.imx
echo -e "${YELLOW}-> Write u-boot into eMMC${NC}"
./utp_com -d $2 -c "$ dd if=\$FILE of=/dev/mmcblk3boot0 bs=512 seek=2"
echo -e "${YELLOW}-> Re-enable read-only${NC}"
./utp_com -d $2 -c "$ echo 1 > /sys/block/mmcblk3boot0/force_ro"
echo -e "${YELLOW}-> Enable boot partion 1 to boot${NC}"
./utp_com -d $2 -c "$ mmc bootpart enable 1 1 /dev/mmcblk3"
# Create FAT partition
echo -e "${YELLOW}-> Waiting for the partition ready${NC}"
./utp_com -d $2 -c "$ while [ ! -e /dev/mmcblk3p1 ]; do sleep 1; echo \"waiting...\"; done "
echo -e "${YELLOW}-> Formatting zImage partition p1${NC}"
./utp_com -d $2 -c "$ mkfs.vfat /dev/mmcblk3p1"
./utp_com -d $2 -c "$ mkdir -p /mnt/mmcblk3p1"
./utp_com -d $2 -c "$ mount -t vfat /dev/mmcblk3p1 /mnt/mmcblk3p1"
# Burn zImage (Kernel) on p1
echo -e "${YELLOW}-> Sending kernel zImage${NC}"
./utp_com -d $2 -c "send" -f ${4}/zImage
echo -e "${YELLOW}-> Write kernel image to eMMC card @ p1${NC}"
./utp_com -d $2 -c "$ cp \$FILE /mnt/mmcblk3p1/zImage"
# Burn dtb on p1
echo -e "${YELLOW}-> Sending Device Tree file${NC}"
./utp_com -d $2 -c "send" -f ${4}/zImage-imx6sx-sdb.dtb
echo -e "${YELLOW}-> Writing device tree file to sd card @ p1${NC}"
./utp_com -d $2 -c "$ cp \$FILE /mnt/mmcblk3p1/zImage-imx6sx-sdb.dtb"
echo -e "${YELLOW}-> Unmounting vfat partition${NC}"
./utp_com -d $2 -c "$ umount /mnt/mmcblk3p1"
# Populate default rootfs on p2
echo -e "${YELLOW}-> Formatting rootfs partition @ p2${NC}"
./utp_com -d $2 -c " mkfs.ext3 -F -E nodiscard /dev/mmcblk3p2"
./utp_com -d $2 -c " mkdir -p /mnt/mmcblk3p2"
./utp_com -d $2 -c " mount -t ext3 /dev/mmcblk3p2 /mnt/mmcblk3p2"
echo -e "${YELLOW}-> Sending and Flashing rootfs partition to sd card @ p2${NC}"
./utp_com -d $2 -c "pipe dd of=/dev/mmcblk3p2 bs=1M" -f ${4}/core-image-minimal-imx6sxsabresd.ext4
echo -e "${YELLOW}-> Finishing rootfs image write on p2${NC}"
./utp_com -d $2 -c "frf"
echo -e "${YELLOW}-> Unmounting rootfs partition${NC}"
./utp_com -d $2 -c "$ umount /mnt/mmcblk3p2"
# Done
echo " "
echo -e "${GREEN} ${NC}"
echo -e "${GREEN} -> Board Setup Complete <- ${NC}"
echo -e "${GREEN} ${NC}"
echo " "
./utp_com -d $2 -c "$ echo Update Ready"
That file is the equivalent to the following .xml file
<LIST name="eMMC" desc="Choose eMMC as media">
<!-- Create partition -->
<CMD state="Updater" type="push" body="send" file="mksdcard.sh.tar">Sending partition shell script</CMD>
<CMD state="Updater" type="push" body="$ tar xf $FILE "> Decompresing script...</CMD>
<CMD state="Updater" type="push" body="$ sh mksdcard.sh /dev/mmcblk3"> Partitioning eMMC</CMD>
<!-- Setup boot partition -->
<CMD state="Updater" type="push" body="$ echo 0 > /sys/block/mmcblk3boot0/force_ro">Access boot partition</CMD>
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6sx%board%_emmc.imx" ifdev="MX6SX">Sending u-boot.bin</CMD>
<CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mmcblk3boot0 bs=512 seek=2">Write u-boot into eMMC</CMD>
<CMD state="Updater" type="push" body="$ echo 1 > /sys/block/mmcblk3boot0/force_ro"> Re-enable read-only </CMD>
<CMD state="Updater" type="push" body="$ mmc bootpart enable 1 1 /dev/mmcblk3">Enable boot partion 1 to boot</CMD>
<!-- Create fat partition -->
<CMD state="Updater" type="push" body="$ while [ ! -e /dev/mmcblk3p1 ]; do sleep 1; echo \"waiting...\"; done ">Waiting for the partition ready</CMD>
<CMD state="Updater" type="push" body="$ mkfs.vfat /dev/mmcblk3p1">Formatting rootfs partition</CMD>
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk3p1"/>
<CMD state="Updater" type="push" body="$ mount -t vfat /dev/mmcblk3p1 /mnt/mmcblk3p1"/>
<!-- Burn zImage (Kernel) on p1 -->
<CMD state="Updater" type="push" body="send" file="files/zImage">Sending kernel zImage</CMD>
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk3p1/zImage">Write kernel image to eMMC card @ p1</CMD>
<!-- Burn dtb on p1 -->
<CMD state="Updater" type="push" body="send" file="files/zImage-imx6sx-%sxdtb%-emmc.dtb" ifdev="MX6SX">Sending Device Tree file</CMD>
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk3p1/imx6sx-%sxdtb%.dtb" ifdev="MX6SX">Writing device tree file to sd card @ p1</CMD>
<CMD state="Updater" type="push" body="$ umount /mnt/mmcblk3p1">Unmounting vfat partition</CMD>
<!-- Populate default rootfs on p2 -->
<CMD state="Updater" type="push" body="$ mkfs.ext3 -F -E nodiscard /dev/mmcblk3p2">Formatting rootfs partition</CMD>
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk3p2"/>
<CMD state="Updater" type="push" body="$ mount -t ext3 /dev/mmcblk3p2 /mnt/mmcblk3p2"/>
<CMD state="Updater" type="push" body="pipe tar -jxv -C /mnt/mmcblk3p2" file="files/rootfs.tar.bz2" ifdev="MX6SL MX6D MX6Q MX6SX">Sending and Flashing rootfs partition to sd card @ p2</CMD>
<CMD state="Updater" type="push" body="frf">Finishing rootfs image write on p2</CMD>
<CMD state="Updater" type="push" body="$ umount /mnt/mmcblk3p2">Unmounting rootfs partition</CMD>
<CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD>
</LIST>
I included the XML file for you to see the similitude between the two files. This way you can adapt your XML file if you have one already. If not, you just copy paste the utp-flash-commands.sh and modify it according to your needs.
In order to flash the board you should do the following:
user@linux-machine ~ $ cd fsl-release-bsp
user@linux-machine ~/fsl-release-bsp $ sudo ./board-flash ~/ utp-flash-commands.sh
This is it!!!
Following these instructions, you will be able to flash your board from a Linux machine without having to rely on the Freescale manufacturing tool that runs on windows. Please try these out and let me know in the comments if there is something to be changed, added or removed.
Hi Manuel and thanks for that post it helped a lot !
I have one problem, my device does not report as SG device, so my DEVICE is null. There is some option in uboot to run as sg device ??
I work on i.MX6UL.
Regards,
Adrian
Thanks Manuel. A great guide - got me up-and-running reasonably easily, after days spent struggling to migrate from (a working) Windows MfgTool over to the Linux version.
Once you get to grips with it, configuring imx_usb_loader and the utp_com script are also much easier - so thanks too to the authors :smileyhappy:
Might be worth mentioning for Step 2 that the steps needed in the .conf file are pretty much (I believe?) equivalent to the 'BootStrap' steps from the MfgTool .xml file
Hi together,
i want to use the Serial Download via UART1 of the i.MX6UL. I tested it with my own HW and with the imx6ulevk Board from NXP.
i used the imx_usb_loader --> the UART version without HW flow control option: imx_uart -n
Did someone get the serial download via UART work?
Regards,
Jochen
Hi # Manuel Malagon
This is regarding imx6q based custom hardware design.
I’m using>>. /imx_usb u-boot.imx command to burn spi flash of fresh hardware via usb loader. (I mean this custom boards didn’t burn any uboot in spi flash previously and they are fresh)
To accselorate this process I need to burn flash of multiple boards using one PC. Is there any method to do this using usb loader? Or else any other method to burn uboot for multiple boards using one pc?
Regards,
Peter.
Yeah, in theory, it can be done on multiple boards at the same time. You just need to change line 92 of the "board-flash.sh" script to be able to detect more than one SG device. And then perform line 99 as many times as SG devices are found.
The script "as is" just identifies 1 board (SG0) and executes the APP_FLASHING_SCRIPT once for that board. The present solution is somehow "hard coded" for just one board. But if you are able to get all the SG devices from /dev/ and then run APP_FLASHING_SCRIPT for each SG device found then you should be able to flash all the boards you want at the same time.
I haven't actually tried this, this is just a theory but it sounds 100 accurate to me. Maybe you can make the changes and try. I would do it but I have a lot on my plate right now and I can't make the changes and try.
Good luck!
Please let me know if you are able to successfully implement this, I would appreciate it!
Hi #Manuel Malagon
Many thanks for your response.
Could you please guide me how should I change this line to execute many SG devices ?
DEVICE=`diff firmware/dev-temp1.txt firmware/dev-temp2.txt | grep '/dev/sg' | cut -c 3-`
Yes sure I'll inform you when I get it done.
Regards..