Bootstrapping a board
A board running its on-chip boot code serves no flash commands. The commands on this page upload
code that does serve them, over the vendor’s own download protocol. db uploads to a Rockchip
BootROM, and usbboot to an Ingenic boot ROM. Neither command writes flash. A StarFive board’s
BootROM has no USB, and uartboot boots it into U-Boot over its serial line instead, as
Serial lines describes.
Bringing a maskrom board to loader mode
db brings a Rockchip board from maskrom mode, where the BootROM runs, to loader mode. It takes
a Rockchip loader container for the SoC, and uploads it over the maskrom download-boot protocol.
rkbin ships one as *_loader.bin, and board vendors ship one as MiniLoaderAll.bin.
list shows the board in maskrom mode:
pyrographer list
2207:350e maskrom bus 003 address 12 (bcdUSB 0200)
db uploads the loader, and the board comes back in loader mode:
pyrographer db --soc rk3576 --loader rk3576_spl_loader_v1.12.108.bin
This loader's chip field holds 36 37 35 33 "6753" (rk3576).
Uploading 420.01 KiB...
100.0% 420.01 KiB of 420.01 KiB 455.10 KiB/s
Uploaded 420.01 KiB in 0.9s.
Loader uploaded. A new Rockchip device appeared at 003:13. `list` can still report it as
maskrom, because this loader keeps the bcdUSB flag even. The next command sent to it checks
that a loader answers.
db parses the file before it opens any device, and refuses a file that is not an RKBOOT
loader. It also refuses a board that is not in maskrom mode. A Rockchip firmware package
(update.img) carries a loader, and --loader takes the package itself, as
A board in maskrom shows.
The container names the SoC it was built for, and db prints that claim first. With --soc,
db checks the claim, and refuses a file built for another SoC before it uploads a byte.
Without --soc, db prints the claim and checks nothing.
This check is weaker than the wrong-loader gate on a write.
Whoever built the file wrote the claim, so the check catches a wrong file chosen by mistake, and
not a false claim. It is the only check available, because a maskrom board does not answer chipver.
When an upload appears to go wrong, three behaviors matter:
- A corrupt upload fails silently. Measured on an RK3576, the BootROM acknowledges every transfer of a bad section. It checks the section’s trailing CRC after the last chunk, and discards a bad section without reporting an error. The failure surfaces one stage later, as an upload that stalls. A BootROM left with a partial upload also refuses a fresh one. Power-cycle the board and put it back into maskrom before you retry.
- The board comes back at a new address. After the final stage, the loader tears down the
maskrom USB device and re-enumerates. An RK3576 takes somewhat over three seconds, and an
RK3588S takes under one.
dbwatches for the board for ten seconds. If the board has not reappeared by then,dbtells you to runlist, and reports no error. - A loader can stop answering. Seen once on an RK3588S, the loader enumerated and then answered nothing until the board was power-cycled. Every command then reports maskrom. Power-cycle the board into maskrom and upload again.
The board that comes back can still carry an even bcdUSB flag, because the RK3576 SPL loader
and the RK3588 usbplug loader never set it. The verbs resolve that by asking, as
Listing devices describes.
Raw stages
Mainline U-Boot’s CONFIG_ROCKCHIP_MASKROM_IMAGE has binman emit the download-boot stages as
two bare files:
u-boot-rockchip-usb471.bin, the DRAM initu-boot-rockchip-usb472.bin, the SPL and the full FIT after it
db sends those in place of a container:
pyrographer db --code471 u-boot-rockchip-usb471.bin --code472 u-boot-rockchip-usb472.bin
The result is a mainline U-Boot running entirely from RAM. Because nothing is written to flash, the board’s storage can be untouched, broken or not yet trusted. From that prompt, U-Boot’s gadgets hand the flash to the host, and its distro boot can test-boot a system before it is installed.
You can give one stage or both, and db always sends stage 471 first. The chunking, the pad rule
and the trailing CRC are the same as for a container. A container’s sections are these same
payloads, each under a name. Bare stages carry no container, so they name no SoC. db reports
that nothing checks which board they are for.
On an RK3576, a 3 MiB 472 stage packed in a boot_merger container and sent with --loader
RAM-boots to a U-Boot prompt. The raw form sends the same payloads, and is [UNVERIFIED]
against hardware. RAM-booting U-Boot from maskrom gives the
whole procedure. It includes the load-address check that catches a 472 stage the BootROM will
not run.
A board booted this way answers on its serial console, and does not return to the USB bus by
itself. At its U-Boot prompt, uboot tells it to start a
gadget. The board then appears in list as a loader, or its flash appears in list --blocks
as a disk.
Bringing an Ingenic board to DFU
usbboot brings an Ingenic XBurst board from its boot ROM to DFU mode. The Ingenic backend
targets the XBurst2 camera SoCs: the T31, T40 and T41. These SoCs are found in IP cameras such
as the Wyze Cam v3, which is built on a T31. The whole upload sequence is [UNVERIFIED] against
hardware.
usbboot uploads two stages: a DRAM-init SPL, then a DFU-capable U-Boot.
pyrographer usbboot --stage1 spl.bin --stage1-addr "$SPL_ADDR" \
--stage2 u-boot.bin --stage2-addr "$UBOOT_ADDR"
Supply the two stages and their load addresses for your board. usbboot has no default
addresses. --dram-settle-ms sets how long usbboot waits
after stage 1 for DRAM to come up. The default is 2000 ms, a community figure. [COMMUNITY]
On success, usbboot prints the CPU info the boot ROM reported. The board then re-enumerates as
a DFU device, a108:4d44.
A DFU board addresses named regions, its DFU alt-settings, rather than a device-wide LBA.
partitions lists those regions, and dump, verify and flash aim at one with --partition.
They refuse a raw LBA. clone and the partition-table commands refuse a DFU board outright,
because each addresses a device-wide LBA. All three reads are [UNVERIFIED] on a DFU board. A
DFU write is built, and refuses at the wrong-loader gate
because no Ingenic SoC is pinned.