Flashing without the vendor's flashing tool
NXP's uuu dies at 8% on an Apple Silicon Mac. The board's own U-Boot has ums and fastboot, and those use bulk USB, which works fine.
The documented way to flash a blank i.MX8M board is NXP's uuu, over the USB programming
port, with the SoC boot ROM in Serial Download Protocol mode. CompuLab's recovery page says
so, and it is the right answer on most hosts.
On my Apple Silicon MacBook it fails at 8%, every time.
Start Cmd:SDPS: boot -scanterm -f imx-boot -scanlimited 0x800000
8% ... Fail HID(W): LIBUSB_ERROR_IO (-1)
New USB Device Attached ... (loops)
The board is fine. It genuinely enters serial-download mode — uuu sees the device attach and
starts pushing. The USB physical link drops partway through the transfer, during SDP's HID
phase. This is a known uuu-on-Apple-Silicon problem and has nothing to do with my image or
my build.
What I tried first, and why it didn't help
The usual fix for this exact error is to put a cheap USB 2.0 hub between host and board. I tried going through my monitor's hub, which did nothing — and that is worth flagging, because a USB-3 / Thunderbolt dock is not the same thing as a USB-2 hub. I never had a plain USB-2 hub to hand to test properly.
Short known-good data cable, no adapters: no change. The honest recommendation at that point
was to run uuu from any Linux or Windows machine, where it is reliable. An old laptop or a
Raspberry Pi would have done.
I did not want to do that, and thinking about why produced a better answer.
The realisation: SDP isn't needed
SDP exists to push a bootloader into RAM on a board that has no working bootloader. This board has a working bootloader. The factory unit boots CompuLab's U-Boot; after provisioning it boots mine. Either way, at power-on I can stop at a U-Boot prompt.
And U-Boot has two commands that are exactly what I need:
ums— expose an eMMC device to the host as USB mass storagefastboot— the Android flashing protocol
Both use bulk USB transfers. Only the SDP handshake uses HID. And bulk transfers work perfectly on this Mac — which makes sense, since bulk is what every external disk in the world uses.
So: don't fix the tool. Use the link that already works.
The two-port trap
Before the procedure, the single biggest time sink of this entire project, and it is not subtle once you know it.
There are two micro-USB ports and they do completely different things.
- DBG — the serial console. Appears as
/dev/cu.usbserial-*. Stable, and it does not re-enumerate when the board resets, which is what makes it usable. - OTG, labelled UART/USB — the USB gadget. This is SDP,
umsandfastboot.
Both cables go to the Mac. If only DBG is connected, ums registers happily on the board and
prints its banner, and the Mac sees nothing at all. I lost a long time to that, because
the board's output gives you no hint that the host is not listening.
There is a worse version of the same trap. If the OTG port is connected at power-on, the board enters SDP — silently. No eMMC boot, no console output, nothing. It looks dead. So:
Unplug OTG to boot and get a console. Plug it back in only after U-Boot is up.
Go straight into the laptop with the OTG cable. Skip docks and hubs.
The procedure that worked
First, confirm the board's own view of itself at the U-Boot prompt, because two of these
values need to match what is in fwup.conf:
bdinfo # DRAM ~4 GB — confirms the 4 GB SOM
mmc list # eMMC is mmc device 2, i.e. mmcblk2
help # confirms ums, fastboot, gpt, mmc, gzwrite are all present
Firmware to the user area, via ums
At the U-Boot prompt:
ums 0 mmc 2
Controller 0 is the only USB device controller on this board; ums 1 returns "couldn't find
an available UDC". U-Boot prints UMS: LUN 0, dev mmc 2, ... count 0x3a63e00 and spins.
Now plug in the OTG cable. On the Mac:
diskutil list # find the ~29-31 GB EXTERNAL physical disk
diskutil unmountDisk /dev/diskN
sudo fwup -a -d /dev/rdiskN -i compulab_cs_gw.fw -t complete
Identify the disk by its size, and check it twice. Everything about this step is
irreversible if you get the wrong /dev/diskN, and the wrong one is your own machine's disk.
This is the only part of the process where I stop and read the output properly before pressing
return.
rdiskN rather than diskN is the raw device node, and it is substantially faster.
fwup prints Success! after writing about 49 MB. Then Ctrl-C the ums on the board.
Bootloader to boot0, via fastboot
At the U-Boot prompt:
fastboot usb 0
On the Mac (brew install android-platform-tools):
fastboot devices
fastboot flash bootloader imx-boot
fastboot reboot
The board's log confirms what happened:
switch to partitions #1, OK
mmc2(part 1) is current device
block # 0 ... blocks written: OK
Two things I had expected to be difficult and were not. No offset guessing — fastboot flash bootloader writes to block 0 of the boot partition, which is where the boot ROM looks.
And no mmc partconf — the factory ext_csd already boot-enables boot0, and I am
overwriting it in place rather than changing which partition boots. CompuLab's own recovery
flow ends in FB: flash bootloader too, so the factory U-Boot supports this deliberately.
I had a note in my plan reading "confirm the boot0 imx-boot offset from the factory backup
first — this is the one value we won't guess." It turned out not to be a value at all.
fastboot knows.
One quirk: reset and fastboot reboot sometimes leave the console printing resetting ...
and hanging. Do a real power-cycle, so the ROM definitely re-reads boot0.
Getting a console you can trust
screen works but is unpleasant when the board resets. I switched to tio:
brew install tio
tio /dev/cu.usbserial-XXXX
It reconnects automatically, which matters when you are power-cycling repeatedly.
This is also where I have to admit to a genuinely stupid detour. Before I had a reliable
console, I concluded from the network that the board had booted — there was a device
answering at an address I expected. It was a different machine entirely. A sibling
CompuLab box on the same subnet, with a very similar MAC prefix, because they share the
vendor's OUI 00:01:c0.
I wrote "it boots" in my notes on the strength of that. It did not boot. The moment I had a real serial console with the OTG port unplugged, the board told me exactly what was wrong, in five words, and had presumably been saying it all along to nobody.
I now record the MACs of anything I am bringing up, before I start looking for it:
eth0 00:01:c0:3e:81:66
eth1 00:01:c0:3e:81:73
Never identify a board by "something responded". Identify it by its console.
What this proved, and what it did not
The flash mechanics work end to end: ums plus fwup writes the user area, fastboot flash bootloader writes imx-boot to boot0. Both over a link the laptop is happy with. uuu is
not required to provision a board that already has a working U-Boot, which — after the first
time — is every board.
It does not boot.
That is the next part, and it is the most interesting failure in the series.