Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ Arguments:

Used by:
- `RKUSBDriver`_
- `RKUSBMaskromDriver`_

NetworkMXSUSBLoader
~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -2647,6 +2648,42 @@ Arguments:
- usb_loader (str): optional, key in :ref:`images <labgrid-device-config-images>` containing the path
of a first-stage bootloader image to write

RKUSBMaskromDriver
~~~~~~~~~~~~~~~~~~
An :any:`RKUSBMaskromDriver` is used to upload an image into a device in the
*Rockchip USB Maskrom state*.
This is useful to bootstrap a bootloader onto a device.

Binds to:
loader:
- `RKUSBLoader`_
- `NetworkRKUSBLoader`_

Implements:
- :any:`BootstrapProtocol`

.. code-block:: yaml

targets:
main:
drivers:
RKUSBMaskromDriver:
initial: 'rkmaskrom471'
image: 'rkmaskrom472'
Comment on lines +2670 to +2672
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: is this compatible with Barebox?

Barebox seems to be generating only one binary which contains both "files". I think it'd make sense to support Barebox file format as well, which likely differs from U-Boot's (currently two separate files IIRC) or the binary generated by Rockchip's boot_merger?

@a3f any opinion on that maybe?

EDIT: I see that the next patch adds the implementation for reading the file from boot_merger, so I guess if we have a unique way of identifying Barebox's implementation that would work too. Still, wondering if we shouldn't simply use snagboot and implement stuff there if necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Barebox seems to be generating only one binary which contains both "files". I think it'd make sense to support Barebox file format as well, which likely differs from U-Boot's (currently two separate files IIRC)

Barebox uses the IDBlock v2 format, i.e. same format that mkimage produce for TPL and SPL in U-Boot for RK35xx.
Will add an implementation for extracting images from the IDBlock v1 and v2 formats, thanks!

or the binary generated by Rockchip's boot_merger?

This format is supported with the second commit, one special thing that boot_merger does differently for RK35xx is that it adds an IDBlock v2 header for the 471 and 472 files referenced in the rkboot .ini-files.
However, this extra header does not seem to be required on all RK35xx SoCs I have tested.

Also the BootROM seem to use a much slower crc16 implementation, so validating a huge blob for i.e. U-Boot RAM boot can take several seconds.
Will send an updated Rockchip U-Boot RAM-boot series that take advantage of FIT compression along with relocation the FIT to the 2 MiB offset to help speed up RAM-boot.

Still, wondering if we shouldn't simply use snagboot and implement stuff there if necessary?

Feel free to implement and use a snagboot driver, I will be using this for my personal lab ;-)

Copy link
Contributor Author

@Kwiboo Kwiboo Sep 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now added a new commit with support for decoding the IDBlock v2 image format (both unsigned and signed) in addition to the loader image format.

With that added we should be able to use the Barebox output image or u-boot-rockchip.bin to at least boot into SPL on newer Rockchip SoCs.

Will run some more tests and add one more commit to add support for the legacy IDBlock image format to make this fully featured.

This will need to be tested some more on e.g. RK3576 where more than two idblock images is typically used to e.g. fixup booting from SD-card.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now pushed one more commit with support for decoding the legacy IDBlock image format, the boot image format used for Rockchip SoCs prior to the RK35xx line.

With this I can now use something like the following labgrid-client command on my Rockchip boards:

labgrid-client -v -c remote.yaml -p rk3399-rock-4 bootstrap u-boot-rockchip.bin

And as expected, without a proper FIT available or SPL DFU working, U-Boot SPL will fail trying to bootstrap a plain U-Boot u-boot-rockchip.bin image:

U-Boot TPL 2025.10-rc5 (Sep 29 2025 - 19:04:10)
lpddr4_set_rate: change freq to 400MHz 0, 1
Channel 0: LPDDR4, 400MHz
BW=32 Col=10 Bk=8 CS0 Row=15 CS=1 Die BW=16 Size=1024MB
Channel 1: LPDDR4, 400MHz
BW=32 Col=10 Bk=8 CS0 Row=15 CS=1 Die BW=16 Size=1024MB
256B stride
lpddr4_set_rate: change freq to 800MHz 1, 0
Trying to boot from BOOTROM
Returning to boot ROM...

spl:init dram

U-Boot SPL 2025.10-rc5 (Sep 29 2025 - 19:04:10 +0000)
board_spl_was_booted_from: failed to resolve brom_bootdevice_id a
Trying to boot from MMC1
mmc_load_image_raw_sector: mmc block read error
Error: -38
Trying to boot from MMC2
Card did not respond to voltage select! : -110
spl: mmc init failed with error: -95
Error: -95
SPL: failed to boot from all boot devices
### ERROR ### Please RESET the board ###


images:
rkmaskrom471: 'path/to/u-boot-rockchip-usb471.bin'
rkmaskrom472: 'path/to/u-boot-rockchip-usb472.bin'

Arguments:
- initial (str): optional, key in :ref:`images <labgrid-device-config-images>` containing the path
of an image that typically initializes DRAM of the target
- image (str): optional, key in :ref:`images <labgrid-device-config-images>` containing the path
of a bootloader image to load to start of DRAM, or to SRAM when an initial image is unused, or
the path to a vendor loader image typically created using the vendor boot_merger tool, or the
path to an idblock image typically created using the U-Boot mkimage or Barebox rkimage tools
- delay (float, default=0.001): delay in seconds between loading initial and secondary image

UUUDriver
~~~~~~~~~
A :any:`UUUDriver` is used to upload an image into a device in the *NXP USB
Expand Down
3 changes: 2 additions & 1 deletion labgrid/driver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
DigitalOutputPowerDriver, YKUSHPowerDriver, \
USBPowerDriver, SiSPMPowerDriver, NetworkPowerDriver, \
PDUDaemonDriver
from .usbloader import MXSUSBDriver, IMXUSBDriver, BDIMXUSBDriver, RKUSBDriver, UUUDriver
from .usbloader import MXSUSBDriver, IMXUSBDriver, BDIMXUSBDriver, RKUSBDriver, \
RKUSBMaskromDriver, UUUDriver
from .usbsdmuxdriver import USBSDMuxDriver
from .usbsdwiredriver import USBSDWireDriver
from .common import Driver
Expand Down
49 changes: 49 additions & 0 deletions labgrid/driver/usbloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

from ..factory import target_factory
from ..protocol import BootstrapProtocol
from ..resource.remote import NetworkRKUSBLoader
from ..step import step
from .common import Driver
from ..util.agentwrapper import AgentWrapper
from ..util.managedfile import ManagedFile
from ..util.timeout import Timeout
from ..util.helper import processwrapper
Expand Down Expand Up @@ -154,6 +156,53 @@ def load(self, filename=None):
raise


@target_factory.reg_driver
@attr.s(eq=False)
class RKUSBMaskromDriver(Driver, BootstrapProtocol):
bindings = {"loader": {"RKUSBLoader", NetworkRKUSBLoader}}
initial = attr.ib(default=None)
image = attr.ib(default=None)
delay = attr.ib(default=0.001, validator=attr.validators.instance_of(float))

def __attrs_post_init__(self):
super().__attrs_post_init__()
self.wrapper = None

def on_activate(self):
if isinstance(self.loader, NetworkRKUSBLoader):
host = self.loader.host
else:
host = None
self.wrapper = AgentWrapper(host)
self.proxy = self.wrapper.load('rkusbmaskrom')

def on_deactivate(self):
self.proxy = None
if self.wrapper:
self.wrapper.close()
self.wrapper = None

@Driver.check_active
@step(args=['filename'])
def load(self, filename=None):
images = []
if self.initial:
images.append(self.target.env.config.get_image_path(self.initial))
if not filename and self.image:
filename = self.target.env.config.get_image_path(self.image)
if filename:
images.append(filename)
if not images:
raise Exception("No images to load")

args = [self.loader.busnum, self.loader.devnum]
for path in images:
mf = ManagedFile(path, self.loader)
mf.sync_to_resource()
args.append(mf.get_remote_path())
self.proxy.load(*args, delay=self.delay)


@target_factory.reg_driver
@attr.s(eq=False)
class UUUDriver(Driver, BootstrapProtocol):
Expand Down
Loading