RK3576 boot ROM
the rk3576 soc uses an on chip non modifiable piece of code to initialize key hardware blocks required for early boot and load early stage bootloader code it is called the boot rom, and it is always available, impossible to erase without physically damaging the chip, and it defines where and how the rk3576 can grab the first user provided code to run at power up, before anything else runs, the boot rom gets mapped at the physical memory address 0x0 , and it is 43033 bytes long, executing in place it is aarch64, runs at el3, sp = 0x3ff81000 , vbar = 0x3ff80xxx relative vectors at 0xa000 iram is 0x3ff80000 when the boot rom first executes, it zeroes out the iram, selects the boot order mode and tries each available boot source until one works the boot order mode selection is as follows, in order check for a boot mode requested before soft reboot via the pmu1 grf os reg0 register (mmio address 0x26026200 ) this allows a "reboot to x" action from a running os register value 0xef08a53c = mode 1 (maskrom only) register value 0xef085a3x = mode x, where x is the number of the boot mode requested, 0x1 0xb check the forced boot mode value in the otp cell 0x64 bits \[3 0] selected boot mode, 0x1 0xb bits \[7 4] one's complement of the selected boot mode (to check validity of the fused value) bits \[17 16] force boot mode 9 check the board strapping of saradc channel 0 (one shot single channel reading, polling for the completion interrupt) the value that has been read is also stored at 0x3ff80008 in the upper 16 bits of the 32 bit value, where it can be read by early stage bootloader code boot modes mode adc code decimal voltage @1 8 vref boot order 1 0x000β0x0cf 0β207 0 000β0 091 usb 2 0x0d0β0x267 208β615 0 091β0 271 spinor, spinand, usb 3 0x268β0x3fe 616β1022 0 271β0 450 spinor m1, spinand m1, emmc, usb 4 0x3ffβ0x5a3 1023β1443 0 450β0 635 spinor m2, spinand m2, emmc, usb 5 0x5a4β0x73c 1444β1852 0 635β0 814 spinor, spinand, ufs, usb 6 0x73dβ0x8c2 1853β2242 0 814β0 986 spinor m1, spinand m1, ufs, usb 7 0x8c3β0xa5a 2243β2650 0 986β1 165 ufs, usb 8 0xa5bβ0xbfe 2651β3070 1 165β1 350 ufs, sd, usb 9 0xbffβ0xd96 3071β3478 1 350β1 529 spinor m2, spinand m2, spinor m1, spinand m1, spinor, spinand, emmc, sd, usb 10 0xd97β0xf2e 3479β3886 1 529β1 708 emmc, sd, usb 11 0xf2fβ0xfff 3887β4095 1 708β1 800 emmc, usb usb boot (maskrom) whenever boot mode 1 is selected, or any of the other modes exhausts all storage based options and falls back, the boot rom enters the usb download mode which rockchip tools call maskrom in this mode it initializes the usb0 controller and its phy in a device mode, so that the board can be connected to a host computer with a usb cable, and it shows up as id 2207 350e fuzhou rockchip electronics company at this point it can be accessed using rockchip's maskrom protocol, as implemented by various tools such as rkdeveloptool https //github com/rockchip linux/rkdeveloptool , rockusb https //github com/collabora/rockchiprs/ or the windows based closed source rkdevtool the maskrom protocol only uploads binaries to the device, and their processing is fully driven by the boot rom two payload types are envisaged code 0x471 this is meant for small early stage binaries which the boot rom places in sram and executes more than one can be submitted, and they normally return control to the boot rom upon completion this is what is used for boost bin and the ddr initialization blob the binaries here are raw aarch64 executable code, normally with only pc relative addresses, and the execution starts at the beginning address of the binary code 0x472 this is meant for the code which relies on normal system ram already up and running, such as the u boot spl binary note that the boot rom enters the 0x471 phase with mmu and caches off and with a single cpu "little" core running this makes both instruction and data fetches very slow any payload gets verified against a crc16 ccitt checksum which all maskrom tools append after the binary body itself rk3576 uses an extremely slow bitwise implementation of the checksum routine with a throughput of about 124 kb/s this makes uploading larger payloads (such as a full spl+u boot image, or an spl+falcon linux image) as 0x472 unbearably slow there are two tricks to make it more reasonable skip the crc check rk3576 first checks if both crc bytes are zero, and if they are it silently accepts the binary without calculating its checksum at all this can be achieved either by patching the host side maskrom tool to send zeros where it would have normally written the checksum, or by appending a checksum to the uploaded binary itself, in which case the crc the maskrom tool calculates cancels out arithmetically and becomes all zero, due to the way the algorithm works enable i cache from a tiny custom 0x471 payload before loading anything larger one major factor for the slow performance of the rk3576 crc routine is having to fetch 100 instructions per byte from slow uncached rom storage this is even slower than fetching payload data from uncached ram byte by byte with the i cache on, the whole code of the crc routine stays in the cpu's l1 instruction cache, which increases throughput from 124 kb/s to about 2 mb/s / enable the el3 instruction cache before returning to the bootrom / asm volatile("mrs %0, sctlr el3" "=r"(sctlr)); sctlr |= (1ul << 12); asm volatile("msr sctlr el3, %0; isb" "r"(sctlr) "memory"); normal boot from persistent storage when the boot rom tries to boot from persistent storage (as prescribed by the active boot mode), it is looking for a valid loadable image at fixed offsets from the start of the storage device being considered a valid loadable image can be either an rkns (for non secure boot) or an rkss one (for secure boot), and the boot rom checks that the rkns/rkss header is valid and that all image components match the digest recorded in the header for each for each storage device, the boot rom starts searching for the rkns/rkss header at the 512 byte sector 64 (or equivalently at the 4096 byte sector 8 in case of ufs) if not found, it proceeds to look for the same header at further locations on the same device in 512 kb strides for up to 16 copies in case of spi flash, or up to 5 copies in case of ufs and sd/mmc if none of those addresses hold a valid rkns/rkss header with matching data, the next storage device is tried according to the active boot mode if no storage device contains a valid image, the boot rom falls back to maskrom loop n = 0 copy count 1 check magic rkns or rkss at the buffer start publish to iram 0x3ff80010 = bootsource id ( brom bootsource id addr ) and 0x3ff80014 = lba512 of the copy that was accepted copy the header to 0x3ff80400 secure path ( iram+0xc != 0 ) requires rkss image and does rsa verification non secure path ( iram+0xc == 0 and iram+0x8c == 0xffffffff , a redundant anti glitch check) rkns accepted without an rsa signature but each component is still digest checked digest verification for each component, its 32 byte digest is stored at component entry + 0x18 in the image digest algorithm is controlled by hdr+0x0c bit 14 set disables verification entirely; otherwise bits \[3 0] select the algorithm (0 or 1 β sha 256, 3 β sm3, anything else rejected) the boot rom uses the hardware crypto engine at 0x2a430000 ( crypto hash ctl 0x24 / 0x64 ) to calculate the digest over the sector aligned length of the component payload (sector count is taken from the component header) a torn or partial payload write is therefore caught by the rom even without secure boot component table hdr\[0x0a] & 0xf entries (β€ 4) at hdr+0x78 , stride 0x58 +0x00 u16 sector offset # 512 byte units, relative to the id block lba +0x02 u16 sector count # 512 byte units +0x04 u32 load addr # 0xffffffff => 0x3ff81000 for entry 0, else 0x40000000 +0x08 u8 flags # if bits \[3 0] are 0x3, then the component is rejected unless pmu1 grf os reg8 bits \[3 0] are 0xf validation load addr >= 0x3ff81000 , and end must be < 0x40000001 (sram) or <= 0x50000000 (dram window) any failure (bad magic, bad header, failed read, failed signature) falls through to the next copy n+1 after all copies fail, the rom moves to the next entry of the boot order list (eventually usb maskrom) ufs boot specifics ufs devices can be provisioned with multiple logical units (lus), and the boot rom can boot from different lus depending on its configuration by default, the jedec boot well known lun is used, as configured in the ufs descriptors on the device itself this can be overridden by setting bit 14 in the otp configuration word 0x65 and selecting an arbitrary lun in bits \[23 16] there bits coding effect when set default (unfused) \[1 0] pair, both=1 iram+0x54 = 0x1a (26) xin is 26 mhz iram+0x54 = 0x18 (24 mhz) \[3 2] β unused β \[5 4] pair, both=1 iram+0xb8 = 1 β usb2phy grf+0xe008 = 0x4000 0000 (usb2 phy, not related to ufs) 0 \[7 6] pair, both=1 extra pad config skipped \[11 8] 4 bit index copied into iram+0xb4\[3 0] ; indexes a 15 entry Γ 4 byte mphy rx trim table entry bytes program, for both lanes b0 βmphy 0x134 / 0x274 (trsv reg15), b1 β 0xe0 / 0x220 (reg08), b2 β 0x164 / 0x2a4 (reg29), b3 β 0x178 / 0x2b8 (reg2e) index 0 β {03,38,50,80} \[12] single bit iram+0xb4 bit 4 β run vops\[1] = 0x620c after link startup pa txgear=3, pa hsseries=2 (rate b), pa pwrmode=0x44 β hs g3 rate b, 2 lanes off β link stays at pwm g1 \[13] single bit iram+0xb4 bit 5 β issue set flag fdeviceinit (idn 0x01 ) and poll read flag fdeviceinit up to 15001 Γ 100 Β΅s off β no device init handshake \[14] single bit enables the lun override iram+0xb0 = bits\[23 16] off β iram+0xb0 = 0xb0 ( ufs upiu boot wlun ) \[23 16] u8 the lun used for every ufs command, when bit 14 is set n/a \[31 24] β unused on this path β sd card boot specifics the boot rom uses the dma engine built into the sd/mmc controller to boot from sd cards, but it has a bug in where it places the dma descriptor buffer it is by default intermixed with boot rom's own global state data in sram, and any meaningfully sized dma transfers cause the buffer to grow and overwrite boot rom state, rendering it unusable the observed result is simply nothing happening in the console when trying to boot from sd even the ddr init messages don't print, and the system hangs this bug can be mitigated by first loading a very small payload from the sd card to sram and using it to relocate the dma descriptor buffer higher up in sram, where it won't collide with other boot rom variables this is the key part of what rockchip's boost bin does on rk3576, and it's effectively this \#include \<stdint h> \#define sys sram base 0x3ff80000 \#define offset 0x03b0 int start(void) { uint32 t sram = (void )(sys sram base + offset); (sram) = 0x3ffff800; return 0; } compiling the above into a standalone aarch64 executable as a raw binary and loading it as the first payload of an rkns image (before ddr init) enables normal boot from sd cards note that this means boost bin is not strictly required for booting from anything else than sd cards, even though it doesn't hurt to include unconditionally
Have a question?
Our support team and an awesome community will get you an answer in a flash. Please leave your questions in English.
To ask a question or participate in discussions, you'll need to authenticate first.