On Fri, Jul 24, 2026 at 4:30 PM Jonas Karlman <[email protected]> wrote:
>
> Hi Alexey,
>
> On 7/24/2026 11:48 AM, Alexey Charkov wrote:
> > On Wed, Jun 10, 2026 at 2:06 AM Jonas Karlman <[email protected]> wrote:
> >>
> >> Hi Alexey,
> >>
> >> On 6/9/2026 8:26 PM, Alexey Charkov wrote:
> >>> Hi Jonas,
> >>>
> >>> On Tue, Jun 9, 2026 at 9:54 PM Jonas Karlman <[email protected]> wrote:
> >>>>
> >>>> Hi Alexey,
> >>>>
> >>>> On 6/9/2026 6:52 PM, Alexey Charkov wrote:
> >>>>> Modern Rockchip SoCs such as RK3576 require ATF to be running to provide
> >>>>> firmware services to the OS. To enable booting Linux in Falcon mode on
> >>>>> such SoCs, add binman support for generation of FIT images containing
> >>>>> appropriately split ATF raw binaries (as is currently done by binman for
> >>>>> U-boot proper images), externally preprocessed DTB and a Linux kernel.
> >>>>>
> >>>>> Signed-off-by: Alexey Charkov <[email protected]>
> >>>>> ---
> >>>>>  Makefile                           |   2 +
> >>>>>  arch/arm/dts/rockchip-u-boot.dtsi  | 109 
> >>>>> +++++++++++++++++++++++++++++++++++++
> >>>>>  tools/binman/etype/falcon_fdt.py   |  26 +++++++++
> >>>>>  tools/binman/etype/linux_kernel.py |  22 ++++++++
> >>>>>  4 files changed, 159 insertions(+)
> >>>>>
> >>>>> diff --git a/Makefile b/Makefile
> >>>>> index 4e5c1dd6a1c4..844e5adb7b31 100644
> >>>>> --- a/Makefile
> >>>>> +++ b/Makefile
> >>>>> @@ -1690,6 +1690,8 @@ cmd_binman = $(srctree)/tools/binman/binman $(if 
> >>>>> $(BINMAN_DEBUG),-D) \
> >>>>>               $(foreach f,$(BINMAN_INDIRS),-I $(f)) \
> >>>>>               -a atf-bl1-path=${BL1} \
> >>>>>               -a atf-bl31-path=${BL31} \
> >>>>> +             -a linux-kernel-path=${LINUX_KERNEL} \
> >>>>> +             -a falcon-fdt-path=${FALCON_FDT} \
> >>>>>               -a tee-os-path=${TEE} \
> >>>>>               -a ti-dm-path=${TI_DM} \
> >>>>>               -a opensbi-path=${OPENSBI} \
> >>>>> diff --git a/arch/arm/dts/rockchip-u-boot.dtsi 
> >>>>> b/arch/arm/dts/rockchip-u-boot.dtsi
> >>>>> index 4ba6a87e78ab..866a6ab654ca 100644
> >>>>> --- a/arch/arm/dts/rockchip-u-boot.dtsi
> >>>>> +++ b/arch/arm/dts/rockchip-u-boot.dtsi
> >>>>> @@ -161,6 +161,96 @@
> >>>>>                       };
> >>>>>               };
> >>>>>       };
> >>>>> +
> >>>>> +#ifdef CONFIG_SPL_OS_BOOT
> >>>>> +     fit_falcon_template: template-falcon {
> >>>>
> >>>> Not sure it is possible, but this looks to add lots of duplicated
> >>>> content. Could we try to re-use more, e.g. is it possible to extract
> >>>> @atf-SEQ, and I also think we may want to support loading of TEE-OS?
> >>>
> >>> Makes sense, will try to refactor a bit to reduce duplication.
> >>>
> >>>>> +             type = "fit";
> >>>>> +             description = "FIT image for Falcon Linux with bl31 
> >>>>> (TF-A)";
> >>>>> +             #address-cells = <1>;
> >>>>> +             fit,fdt-list-val = "u-boot";
> >>>>> +             fit,external-offset = <CONFIG_FIT_EXTERNAL_OFFSET>;
> >>>>> +             fit,align = <512>;
> >>>>> +
> >>>>> +             images {
> >>>>> +                     @atf-SEQ {
> >>>>> +                             fit,operation = "split-elf";
> >>>>> +                             description = "ARM Trusted Firmware";
> >>>>> +                             type = "firmware";
> >>>>> +                             arch = FIT_ARCH;
> >>>>> +                             os = "arm-trusted-firmware";
> >>>>> +                             compression = "none";
> >>>>> +                             fit,load;
> >>>>> +                             fit,entry;
> >>>>> +                             fit,data;
> >>>>> +
> >>>>> +                             atf-bl31 {
> >>>>> +                             };
> >>>>> +#ifdef FIT_HASH_ALGO
> >>>>> +                             hash {
> >>>>> +                                     algo = FIT_HASH_ALGO;
> >>>>> +                             };
> >>>>> +#endif
> >>>>> +                     };
> >>>>> +
> >>>>> +                     kernel {
> >>>>> +                             description = "Linux kernel";
> >>>>> +                             type = "kernel";
> >>>>> +                             arch = FIT_ARCH;
> >>>>> +                             os = "linux";
> >>>>> +                             compression = "none";
> >>>>> +                             load = <0x48000000>;
> >>>>> +                             entry = <0x48000000>;
> >>>>
> >>>> We should not hard-code these here, they seem to be RK3576 specific.
> >>>
> >>> Fair enough. Should probably come from configs.
> >>>
> >>>>> +
> >>>>> +                             linux-kernel {
> >>>>> +                             };
> >>>>> +#ifdef FIT_HASH_ALGO
> >>>>> +                             hash {
> >>>>> +                                     algo = FIT_HASH_ALGO;
> >>>>> +                             };
> >>>>> +#endif
> >>>>> +                     };
> >>>>> +
> >>>>> +                     fdt-1 {
> >>>>> +                             description = "falcon-fdt";
> >>>>> +                             type = "flat_dt";
> >>>>> +                             arch = FIT_ARCH;
> >>>>> +                             compression = "none";
> >>>>> +                             load = <0x52000000>;
> >>>>
> >>>> Same here.
> >>>
> >>> Ack
> >>>
> >>>>> +
> >>>>> +                             falcon-fdt {
> >>>>> +                             };
> >>>>
> >>>> If I am not mistaken we can already inject an external DT to be used as
> >>>> control fdt during U-Boot build using EXT_DTB env, maybe it is better to
> >>>> use that instead of passing in a new FDT?
> >>>>
> >>>> We probably also want to use @fdt-SEQ and @config-SEQ to be able to
> >>>> dynamically load a config based on e.g. board_fit_config_name_match()
> >>>> that some boards already use to select config/fdt for U-Boot proper.
> >>>
> >>> Indeed, that would be quite interesting to have to make it all less
> >>> hardcoded. Does board_fit_config_name_match() also work in SPL?
> >>
> >> Yes, that is where I know it is currently being used for Rockchip on
> >> such boards, e.g. rk3566-zero3 and similar.
> >>
> >> spl_load_simple_fit()
> >> - spl_simple_fit_parse()
> >>    - fit_find_config_node()
> >>       - board_fit_config_name_match()
> >>
> >> And in U-Boot proper the board model/variant is mostly used to set
> >> correct fdtfile env var so that correct FDT can be loaded from e.g.
> >> fdtdir when doing pxe_utils booting.
> >>
> >>>
> >>>>> +#ifdef FIT_HASH_ALGO
> >>>>> +                             hash {
> >>>>> +                                     algo = FIT_HASH_ALGO;
> >>>>> +                             };
> >>>>> +#endif
> >>>>> +                     };
> >>>>> +             };
> >>>>> +
> >>>>> +             configurations {
> >>>>> +                     default = "config-1";
> >>>>> +                     @config-SEQ {
> >>>>> +                             description = "RK3576 Falcon Linux via 
> >>>>> ATF";
> >>>>
> >>>> This is rockchip-u-boot.dtsi, drop RK3576 specific parts :-)
> >>>
> >>> RK3576 is the whole world to me! :-D
> >>>
> >>> Will do, thanks for pointing out
> >>>
> >>>>> +                             fit,firmware = "atf-1", "kernel";
> >>>>> +                             fit,loadables;
> >>>>> +                             fdt = "fdt-SEQ";
> >>>>> +#ifdef FIT_HASH_ALGO
> >>>>> +                             hash {
> >>>>> +                                     algo = FIT_HASH_ALGO;
> >>>>> +                             };
> >>>>> +#endif
> >>>>> +                     };
> >>>>> +             };
> >>>>> +     };
> >>>>> +
> >>>>> +     falcon-fit {
> >>>>> +             filename = "u-boot-rockchip-falcon.itb";
> >>>>
> >>>> Do we need to export this file? the old .itb-file is exported because
> >>>> some distro build scripts or flash instructions still use the older
> >>>> files instead of the preferred u-boot-rockchip.bin.
> >>>
> >>> Yes, this is the file you would actually flash onto, say, dedicated
> >>> UFS LUN to preserve Linux-to-U-boot fallback path.
> >>>
> >>> I'm currently overwriting my main U-boot by `rockusb write-file 16384
> >>> u-boot-rockchip-falcon.itb` but in a normally working setup one
> >>> wouldn't want to do that, so a pre-packed image with the SPL and the
> >>> rest is less helpful in Falcon mode. The combo of
> >>> `idbloader.img`+`u-boot-rockchip-falcon.itb` is what I believe should
> >>> be used, with the former going to W-LU-A and the latter going wherever
> >>> there's enough space for a Linux image.
> >>>
> >>>>> +
> >>>>> +             fit {
> >>>>> +                     insert-template = <&fit_falcon_template>;
> >>>>> +             };
> >>>>> +     };
> >>>>> +#endif
> >>>>>  #endif /* HAS_FIT */
> >>>>>
> >>>>>       simple-bin {
> >>>>> @@ -260,6 +350,25 @@
> >>>>>               };
> >>>>>               };
> >>>>>       };
> >>>>> +
> >>>>> +#ifdef CONFIG_SPL_OS_BOOT
> >>>>> +     simple-bin-usb472-falcon {
> >>>>
> >>>> Do we really need this? As you notice the BootROM loader is not really
> >>>> optimized for large payloads, I thought using a 1-2 MiB payload with
> >>>> TF-A + U-Boot proper was stretching it, sending a full Linux kernel seem
> >>>> like a big stretch, as evidenced by the 6 minute load time?
> >>>
> >>> It's neat for CI workloads and quick testing to jump straight to Linux
> >>> without persistent storage or TFTP servers. I'm hoping to resolve the
> >>> slow boot ROM execution one way or another, maybe by poking some CRU
> >>> registers from boost.bin.
> >>
> >> On RK3576 the extra long load time could likely be improved by adjusting
> >> core clocks before/after DRAM init runs. I have not tried to figure out
> >> what boost.bin v1.03 does to improve UFS boot speeds but likely some
> >> clock tuning is going on.
> >>
> >>>
> >>> There have also been attempts at enabling opensource TPL on RK3576 and
> >>> RK356x, so if/when they land we would be free to adjust clocks much
> >>> earlier, hopefully making the boot faster. After all, it works
> >>> brilliantly when booting from fixed storage, so there isn't much
> >>> reason for it not to work from Maskrom, apart from the particular boot
> >>> ROM on RK3576 being capricious (not sure if it applies to other RK
> >>> SoCs).
> >>
> >> Based on testing on quite a few RK SoCs there seem to be a mix of fast
> >> and slow crc16 implementations, possible some can be due to slow clock
> >> speed, but I also fear a few are using a very basic implementation that
> >> starves even cores running at full rates.
> >>
> >> E.g. on my decent x86 labgrid exporter using similar basic crc16
> >> implementation loading 472 image of about 2-3 MiB could take 30-60
> >> seconds, and using table lookup, it went down to a few seconds.
> >> I can only imagine load times on some of the weaker SoCs :-)
> >>
> >> This is the main reason behind commit 9d3d4d619252 ("rockchip: Reduce
> >> size of ramboot usb472 payload"), removing 1-2 MiB zero-padding could
> >> help load time by several seconds, even on faster SoCs that normally
> >> does not have core clocks adjusted in SPL/proper.
> >
> > Hi Jonas,
> >
> > I've done some further investigation into why usb472 takes so long
> > (with my trusty SWD probe). Turns out the boot ROM runs a bit-by-bit
> > CRC calculation on the usb472 payload, which is not done for any other
> > boot mode. Since the sole core runs with the MMU and caches off, it
> > effectively hits full DRAM latency on every byte, and then it spends
> > dozens of instructions on every byte performing unoptimized bit-by-bit
> > arithmetic for the checksum.
> >
> > The throughput I measured for this calculation is around 124 kB/s on
> > my RK3576 based Flipper One dev prototype. That's 5.47 min for my 39
> > MB Falcon Linux + initrd payload.
> >
> > On a bright side: if the checksum (last two bytes) in the uploaded
> > image is set to zero, it skips the whole CRC routine and jumps right
> > into the uploaded image with no delay.
> >
> > Thought this is worth sharing in case more people want to take the shortcut.
>
> Nice find!
>
> I did some quick remote tests with setting crc=0 and can confirm this
> works on rk3506, rk3528, rk3576 and rv1106, so likely also on following
> RK SoCs:
>
>   ("2207", "110c"),  # RV1106
>   ("2207", "110e"),  # RV1103B
>   ("2207", "110f"),  # RV1126B
>
>   ("2207", "350c"),  # RK3528
>   ("2207", "350d"),  # RK3562
>   ("2207", "350e"),  # RK3576
>   ("2207", "350f"),  # RK3506
>   ("2207", "351a"),  # RK3572
>   ("2207", "351b"),  # RK3538
>
> Using crc=0 does not work on RK3568 or RK3588, will test more once I am
> closer to all my boards sometime next week :-)
>
> I tested using labgrid PR1721 and something like following diff:
>
> @@ -261,7 +262,12 @@ class RKUSBMaskrom:
>              data.append(0)
>
>          # append crc16 of data
> -        crc = crc16_ccitt_false(data)
> +        if self._dev.idProduct in (0x110c, 0x350c, 0x350e, 0x350f) and \
> +           len(data) > 0x40000:
> +            crc = 0
> +        else:
> +            crc = crc16_ccitt_false(data)
> +        print(f"Loading {code:x} image of size {len(data)} and crc 
> {crc:04x}")
>          data.append(crc >> 8)
>          data.append(crc & 0xff)

Looks great, thanks for sharing!

In the meantime, I've also found another speedup. If I extend the
from-source boost.bin which we discussed in the separate thread to
also enable I-cache in EL3, and send it as usb471 before or after the
DDR init blob, then the CRC routine speeds up from 124 kB/s to 2 MB/s,
making it way more tolerable!

diff --git a/arch/arm/mach-rockchip/rk3576/rk3576-boost.c
b/arch/arm/mach-rockchip/rk3576/rk3576-boost.c
index abccf4cb1b9e..6f42109ec788 100644
--- a/arch/arm/mach-rockchip/rk3576/rk3576-boost.c
+++ b/arch/arm/mach-rockchip/rk3576/rk3576-boost.c
@@ -27,5 +27,25 @@ int _start(void)
         */
        *(sram) = 0x3ffff800;

+       /*
+        * Enable the EL3 instruction cache before returning to the BootROM.
+        *
+        * The ROM runs with MMU and caches off. After a Maskrom USB download
+        * to DRAM (command 0x472) it verifies the *entire* image with a
+        * bit-serial CRC-16 executed from slow, non-cacheable on-chip ROM.
+        * With the I-cache off, every byte costs ~101 uncached ROM instruction
+        * fetches, so image verification can take noticeable time (~124 KB/s).
+        * Turning on the EL3 I-cache lets the tiny CRC loop run from L1I,
+        * measured ~2 MB/s (~16x speedup). The bit persists into the ROM's
+        * 0x472/CRC path. Harmless for the SD/storage path (small 2nd stage).
+        */
+       {
+               uint64_t sctlr;
+
+               asm volatile("mrs %0, sctlr_el3" : "=r"(sctlr));
+               sctlr |= (1UL << 12);           /* SCTLR_EL3.I:
I-cache enable */
+               asm volatile("msr sctlr_el3, %0; isb" :: "r"(sctlr) : "memory");
+       }
+
        return 0;
 }

Best regards,
Alexey

Reply via email to