]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
uboot-rockchip: fix boot from SD card for rk3576
authorRyan Leung <untilscour@protonmail.com>
Sat, 9 May 2026 00:42:50 +0000 (10:42 +1000)
committerHauke Mehrtens <hauke@hauke-m.de>
Thu, 14 May 2026 15:52:56 +0000 (17:52 +0200)
Apply pending U-Boot patches so that Rockchip RK3576 devices can boot from SD card. The problem:
"The BootROM on RK3576 has an issue loading boot images from an SD-card. This issue can be worked
around by injecting an initial boot image before TPL…and return to BootROM to load next image, TPL"

Compilation of the initial boot image has been added to the U-Boot build recipe.

Tested on FriendlyELEC NanoPi M5

Signed-off-by: Ryan Leung <untilscour@protonmail.com>
Link: https://github.com/openwrt/openwrt/pull/23008
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
package/boot/uboot-rockchip/Makefile
package/boot/uboot-rockchip/patches/108-01-rockchip-mkimage-Split-size_and_off-and-size_and_nim.patch [new file with mode: 0644]
package/boot/uboot-rockchip/patches/108-02-rockchip-mkimage-Print-image-information-for-all-emb.patch [new file with mode: 0644]
package/boot/uboot-rockchip/patches/108-03-rockchip-mkimage-Print-boot0-and-boot1-parameters.patch [new file with mode: 0644]
package/boot/uboot-rockchip/patches/108-04-rockchip-mkimage-Add-option-to-change-image-offset-a.patch [new file with mode: 0644]
package/boot/uboot-rockchip/patches/108-05-rockchip-mkimage-Add-support-for-up-to-4-input-files.patch [new file with mode: 0644]
package/boot/uboot-rockchip/patches/108-06-rockchip-mkimage-Add-option-for-image-load-address-a.patch [new file with mode: 0644]
package/boot/uboot-rockchip/patches/108-07-WIP-rockchip-mkimage-Add-rk3576-align-and-sd-card-wo.patch [new file with mode: 0644]

index c43c0fef4fcb4abd180268b9b4aa302ec983334d..e94f058998d6defe3404809928893bd48fd6afa8 100644 (file)
@@ -480,6 +480,16 @@ UBOOT_MAKE_FLAGS += \
   BL31=$(STAGING_DIR_IMAGE)/$(ATF) \
   $(if $(TPL),ROCKCHIP_TPL=$(STAGING_DIR_IMAGE)/$(TPL))
 
+define Build/Configure
+       $(call Build/Configure/U-Boot)
+
+ifneq ($(filter %rk3576,$(BUILD_VARIANT)),)
+       $(TARGET_CC) -nostdlib -ffreestanding -Os -S -o $(PKG_BUILD_DIR)/rk3576-boost.S $(PKG_BUILD_DIR)/rk3576-boost.c
+       $(TARGET_CROSS)as -o $(PKG_BUILD_DIR)/rk3576-boost.o $(PKG_BUILD_DIR)/rk3576-boost.S
+       $(TARGET_CROSS)objcopy -O binary -j .text $(PKG_BUILD_DIR)/rk3576-boost.o $(PKG_BUILD_DIR)/rk3576-boost.bin
+endif
+endef
+
 define Build/InstallDev
        $(INSTALL_DIR) $(STAGING_DIR_IMAGE)
        $(CP) $(PKG_BUILD_DIR)/u-boot-rockchip.bin $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-u-boot-rockchip.bin
diff --git a/package/boot/uboot-rockchip/patches/108-01-rockchip-mkimage-Split-size_and_off-and-size_and_nim.patch b/package/boot/uboot-rockchip/patches/108-01-rockchip-mkimage-Split-size_and_off-and-size_and_nim.patch
new file mode 100644 (file)
index 0000000..b69d95e
--- /dev/null
@@ -0,0 +1,119 @@
+From cb682b364eb2d49c3ee2a1f7f33258919f5da688 Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Wed, 29 Jan 2025 22:36:27 +0000
+Subject: [PATCH 1/7] rockchip: mkimage: Split size_and_off and size_and_nimage
+
+Split 32-bit size_and_off and size_and_nimage fields of the v2 image
+format header into their own 16-bit size, offset and num_images fields.
+
+Set num_images based on number of images passed by the datafile
+parameter and size based on the offset to the hash field to fix using a
+single init data file and no boot data file for the v2 image format.
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -34,15 +34,16 @@ enum hash_type {
+ /**
+  * struct image_entry
+  *
+- * @size_and_off:     [31:16]image size;[15:0]image offset
+- * @address:  default as 0xFFFFFFFF
++ * @offset:   image offset (unit as 512 byte blocks)
++ * @size:     image size (unit as 512 byte blocks)
++ * @address:  load address (default as 0xFFFFFFFF)
+  * @flag:     no use
+  * @counter:  no use
+  * @hash:     hash of image
+- *
+  */
+ struct image_entry {
+-      uint32_t size_and_off;
++      uint16_t offset;
++      uint16_t size;
+       uint32_t address;
+       uint32_t flag;
+       uint32_t counter;
+@@ -56,16 +57,17 @@ struct image_entry {
+  * This is stored at SD card block 64 (where each block is 512 bytes)
+  *
+  * @magic:    Magic (must be RK_MAGIC_V2)
+- * @size_and_nimage:  [31:16]number of images;[15:0]
+- *                    offset to hash field of header(unit as 4Byte)
+- * @boot_flag:        [3:0]hash type(0:none,1:sha256,2:sha512)
+- * @signature:        hash or signature for header info
+- *
++ * @size:     offset to hash field of header (unit as 4 bytes)
++ * @num_images:       number of images
++ * @boot_flag:        [3:0] hash type (0:none, 1:sha256, 2:sha512)
++ * @images:   images
++ * @hash:     hash or signature for header info
+  */
+ struct header0_info_v2 {
+       uint32_t magic;
+       uint8_t reserved[4];
+-      uint32_t size_and_nimage;
++      uint16_t size;
++      uint16_t num_images;
+       uint32_t boot_flag;
+       uint8_t reserved1[104];
+       struct image_entry images[4];
+@@ -350,17 +352,18 @@ static void rkcommon_set_header0_v2(void
+       printf("Image Type:   Rockchip %s boot image\n",
+               rkcommon_get_spl_hdr(params));
+       memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE);
+-      hdr->magic   = cpu_to_le32(RK_MAGIC_V2);
+-      hdr->size_and_nimage = cpu_to_le32((2 << 16) + 384);
++      hdr->magic = cpu_to_le32(RK_MAGIC_V2);
+       hdr->boot_flag = cpu_to_le32(HASH_SHA256);
+       sector_offset = 4;
+       image_size_array[0] = spl_params.init_size;
+       image_size_array[1] = spl_params.boot_size;
+       for (i = 0; i < 2; i++) {
++              if (!image_size_array[i])
++                      break;
+               image_sector_count = image_size_array[i] / RK_BLK_SIZE;
+-              hdr->images[i].size_and_off = cpu_to_le32((image_sector_count
+-                                                      << 16) + sector_offset);
++              hdr->images[i].offset = cpu_to_le16(sector_offset);
++              hdr->images[i].size = cpu_to_le16(image_sector_count);
+               hdr->images[i].address = 0xFFFFFFFF;
+               hdr->images[i].counter = cpu_to_le32(i + 1);
+               image_ptr = buf + sector_offset * RK_BLK_SIZE;
+@@ -369,6 +372,8 @@ static void rkcommon_set_header0_v2(void
+               sector_offset = sector_offset + image_sector_count;
+       }
++      hdr->num_images = cpu_to_le16(i);
++      hdr->size = cpu_to_le16(offsetof(typeof(*hdr), hash) / sizeof(uint32_t));
+       do_sha256_hash(buf, (void *)hdr->hash - buf, hdr->hash);
+ }
+@@ -515,10 +520,8 @@ void rkcommon_print_header(const void *b
+                       return;
+               }
+-              init_size = header0_v2.images[0].size_and_off >> 16;
+-              init_size = init_size * RK_BLK_SIZE;
+-              boot_size = header0_v2.images[1].size_and_off >> 16;
+-              boot_size = boot_size * RK_BLK_SIZE;
++              init_size = le16_to_cpu(header0_v2.images[0].size) * RK_BLK_SIZE;
++              boot_size = le16_to_cpu(header0_v2.images[1].size) * RK_BLK_SIZE;
+       } else {
+               ret = rkcommon_parse_header(buf, &header0, &spl_info);
+@@ -532,8 +535,9 @@ void rkcommon_print_header(const void *b
+               }
+               image_type = ret;
+-              init_size = header0.init_size * RK_BLK_SIZE;
+-              boot_size = header0.init_boot_size * RK_BLK_SIZE - init_size;
++              init_size = le16_to_cpu(header0.init_size) * RK_BLK_SIZE;
++              boot_size = le16_to_cpu(header0.init_boot_size) * RK_BLK_SIZE -
++                          init_size;
+               printf("Image Type:   Rockchip %s (%s) boot image\n",
+                      spl_info->spl_hdr,
diff --git a/package/boot/uboot-rockchip/patches/108-02-rockchip-mkimage-Print-image-information-for-all-emb.patch b/package/boot/uboot-rockchip/patches/108-02-rockchip-mkimage-Print-image-information-for-all-emb.patch
new file mode 100644 (file)
index 0000000..b9bd694
--- /dev/null
@@ -0,0 +1,106 @@
+From 0085f8509d62591560901c11fa9d63e34da4fa62 Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Wed, 29 Jan 2025 22:36:28 +0000
+Subject: [PATCH 2/7] rockchip: mkimage: Print image information for all
+ embedded images
+
+The v2 image format can embed up to 4 data files compared to the two
+init and boot data files using the older image format.
+
+Add support for displaying more of the image header information that
+exists in the v2 image format, e.g. image load address and flag.
+
+Example for v2 image format:
+
+  > tools/mkimage -l rk3576_idblock_v1.09.107.img
+  Rockchip Boot Image (v2)
+  Image 1: 4096 @ 0x1000
+  - Load address: 0x3ffc0000
+  Image 2: 77824 @ 0x2000
+  - Load address: 0x3ff81000
+  Image 3: 262144 @ 0x15000
+
+Example for older image format:
+
+  > tools/mkimage -l u-boot-rockchip.bin
+  Rockchip RK32 (SD/MMC) Boot Image
+  Init Data: 20480 @ 0x800
+  Boot Data: 112640 @ 0x5800
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -349,8 +349,6 @@ static void rkcommon_set_header0_v2(void
+       uint8_t *image_ptr = NULL;
+       int i;
+-      printf("Image Type:   Rockchip %s boot image\n",
+-              rkcommon_get_spl_hdr(params));
+       memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE);
+       hdr->magic = cpu_to_le32(RK_MAGIC_V2);
+       hdr->boot_flag = cpu_to_le32(HASH_SHA256);
+@@ -504,6 +502,29 @@ int rkcommon_verify_header(unsigned char
+       return -ENOENT;
+ }
++static void rkcommon_print_header_v2(const struct header0_info_v2 *hdr)
++{
++      uint32_t val;
++      int i;
++
++      printf("Rockchip Boot Image (v2)\n");
++
++      for (i = 0; i < le16_to_cpu(hdr->num_images); i++) {
++              printf("Image %u: %u @ 0x%x\n",
++                     le32_to_cpu(hdr->images[i].counter),
++                     le16_to_cpu(hdr->images[i].size) * RK_BLK_SIZE,
++                     le16_to_cpu(hdr->images[i].offset) * RK_BLK_SIZE);
++
++              val = le32_to_cpu(hdr->images[i].address);
++              if (val != 0xFFFFFFFF)
++                      printf("- Load address: 0x%x\n", val);
++
++              val = le32_to_cpu(hdr->images[i].flag);
++              if (val)
++                      printf("- Flag: 0x%x\n", val);
++      }
++}
++
+ void rkcommon_print_header(const void *buf, struct image_tool_params *params)
+ {
+       struct header0_info header0;
+@@ -520,8 +541,7 @@ void rkcommon_print_header(const void *b
+                       return;
+               }
+-              init_size = le16_to_cpu(header0_v2.images[0].size) * RK_BLK_SIZE;
+-              boot_size = le16_to_cpu(header0_v2.images[1].size) * RK_BLK_SIZE;
++              rkcommon_print_header_v2(&header0_v2);
+       } else {
+               ret = rkcommon_parse_header(buf, &header0, &spl_info);
+@@ -539,15 +559,16 @@ void rkcommon_print_header(const void *b
+               boot_size = le16_to_cpu(header0.init_boot_size) * RK_BLK_SIZE -
+                           init_size;
+-              printf("Image Type:   Rockchip %s (%s) boot image\n",
+-                     spl_info->spl_hdr,
++              printf("Rockchip %s (%s) Boot Image\n", spl_info->spl_hdr,
+                      (image_type == IH_TYPE_RKSD) ? "SD/MMC" : "SPI");
+-      }
+-      printf("Init Data Size: %d bytes\n", init_size);
++              printf("Init Data: %d @ 0x%x\n", init_size,
++                     le16_to_cpu(header0.init_offset) * RK_BLK_SIZE);
+-      if (boot_size != RK_MAX_BOOT_SIZE)
+-              printf("Boot Data Size: %d bytes\n", boot_size);
++              if (boot_size != RK_MAX_BOOT_SIZE)
++                      printf("Boot Data: %d @ 0x%x\n", boot_size, init_size +
++                             le16_to_cpu(header0.init_offset) * RK_BLK_SIZE);
++      }
+ }
+ void rkcommon_rc4_encode_spl(void *buf, unsigned int offset, unsigned int size)
diff --git a/package/boot/uboot-rockchip/patches/108-03-rockchip-mkimage-Print-boot0-and-boot1-parameters.patch b/package/boot/uboot-rockchip/patches/108-03-rockchip-mkimage-Print-boot0-and-boot1-parameters.patch
new file mode 100644 (file)
index 0000000..bd90708
--- /dev/null
@@ -0,0 +1,68 @@
+From 83326e18d15be1ac9b7daf7b472d0bcb8074da2b Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Wed, 29 Jan 2025 22:36:29 +0000
+Subject: [PATCH 3/7] rockchip: mkimage: Print boot0 and boot1 parameters
+
+The v2 image format embeds boot0 and boot1 parameters, the vendor tool
+boot_merger may write these parameters based on the rkboot miniall.ini
+files.
+
+E.g. a RK3576 boot image may contain a boot1 parameter that signals
+BootROM or vendor blobs to use 1 GHz instead of the regular 24 MHz rate
+for the high precision timer.
+
+Add support for printing boot0 and boot1 parameters, e.g.:
+
+  > tools/mkimage -l rk3576_idblock_v1.09.107.img
+  Rockchip Boot Image (v2)
+  Boot1 2: 0x100
+  Image 1: 4096 @ 0x1000
+  - Load address: 0x3ffc0000
+  Image 2: 77824 @ 0x2000
+  - Load address: 0x3ff81000
+  Image 3: 262144 @ 0x15000
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -62,6 +62,8 @@ struct image_entry {
+  * @boot_flag:        [3:0] hash type (0:none, 1:sha256, 2:sha512)
+  * @images:   images
+  * @hash:     hash or signature for header info
++ *
++ * Other fields are not used by U-Boot
+  */
+ struct header0_info_v2 {
+       uint32_t magic;
+@@ -69,7 +71,9 @@ struct header0_info_v2 {
+       uint16_t size;
+       uint16_t num_images;
+       uint32_t boot_flag;
+-      uint8_t reserved1[104];
++      uint8_t reserved1[32];
++      uint32_t boot0_param[10];
++      uint32_t boot1_param[8];
+       struct image_entry images[4];
+       uint8_t reserved2[1064];
+       uint8_t hash[512];
+@@ -509,6 +513,18 @@ static void rkcommon_print_header_v2(con
+       printf("Rockchip Boot Image (v2)\n");
++      for (i = 0; i < ARRAY_SIZE(hdr->boot0_param); i++) {
++              val = le32_to_cpu(hdr->boot0_param[i]);
++              if (val)
++                      printf("Boot0 %d: 0x%x\n", i, val);
++      }
++
++      for (i = 0; i < ARRAY_SIZE(hdr->boot1_param); i++) {
++              val = le32_to_cpu(hdr->boot1_param[i]);
++              if (val)
++                      printf("Boot1 %d: 0x%x\n", i, val);
++      }
++
+       for (i = 0; i < le16_to_cpu(hdr->num_images); i++) {
+               printf("Image %u: %u @ 0x%x\n",
+                      le32_to_cpu(hdr->images[i].counter),
diff --git a/package/boot/uboot-rockchip/patches/108-04-rockchip-mkimage-Add-option-to-change-image-offset-a.patch b/package/boot/uboot-rockchip/patches/108-04-rockchip-mkimage-Add-option-to-change-image-offset-a.patch
new file mode 100644 (file)
index 0000000..ba0bec8
--- /dev/null
@@ -0,0 +1,205 @@
+From a9a5d21d926594a87e8db877d4b9261200c3f8fd Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Wed, 29 Jan 2025 22:36:30 +0000
+Subject: [PATCH 4/7] rockchip: mkimage: Add option to change image offset
+ alignment
+
+The vendor boot_merger tool support a ALIGN parameter that is used to
+define offset alignment of the embedded images.
+
+Vendor use this for RK3576 to change offset alignment from the common
+2 KiB to 4 KiB, presumably it may have something to do with UFS.
+Testing with eMMC has shown that using a 512-byte alignment also work.
+
+Add support for overriding offset alignment in case this is needed for
+e.g. RK3576 in the future.
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -140,6 +140,7 @@ struct spl_info {
+       const uint32_t spl_size;
+       const bool spl_rc4;
+       const uint32_t header_ver;
++      const uint32_t align;
+ };
+ static struct spl_info spl_infos[] = {
+@@ -199,14 +200,19 @@ static struct spl_info *rkcommon_get_spl
+       return NULL;
+ }
+-static int rkcommon_get_aligned_size(struct image_tool_params *params,
+-                                   const char *fname)
++static bool rkcommon_is_header_v2(struct image_tool_params *params)
+ {
+-      int size;
++      struct spl_info *info = rkcommon_get_spl_info(params->imagename);
+-      size = imagetool_get_filesize(params, fname);
+-      if (size < 0)
+-              return -1;
++      return (info->header_ver == RK_HEADER_V2);
++}
++
++static int rkcommon_get_aligned_size(struct image_tool_params *params, int size)
++{
++      struct spl_info *info = rkcommon_get_spl_info(params->imagename);
++
++      if (info->align)
++              return ROUND(size, info->align * RK_BLK_SIZE);
+       /*
+        * Pad to a 2KB alignment, as required for init/boot size by the ROM
+@@ -215,6 +221,27 @@ static int rkcommon_get_aligned_size(str
+       return ROUND(size, RK_SIZE_ALIGN);
+ }
++static int rkcommon_get_header_size(struct image_tool_params *params)
++{
++      int header_size = rkcommon_is_header_v2(params) ?
++                        sizeof(struct header0_info_v2) :
++                        sizeof(struct header0_info);
++
++      return rkcommon_get_aligned_size(params, header_size);
++}
++
++static int rkcommon_get_aligned_filesize(struct image_tool_params *params,
++                                       const char *fname)
++{
++      int size;
++
++      size = imagetool_get_filesize(params, fname);
++      if (size < 0)
++              return -1;
++
++      return rkcommon_get_aligned_size(params, size);
++}
++
+ int rkcommon_check_params(struct image_tool_params *params)
+ {
+       int i, size;
+@@ -237,14 +264,14 @@ int rkcommon_check_params(struct image_t
+               spl_params.boot_file += 1;
+       }
+-      size = rkcommon_get_aligned_size(params, spl_params.init_file);
++      size = rkcommon_get_aligned_filesize(params, spl_params.init_file);
+       if (size < 0)
+               return EXIT_FAILURE;
+       spl_params.init_size = size;
+       /* Boot file is optional, and only for back-to-bootrom functionality. */
+       if (spl_params.boot_file) {
+-              size = rkcommon_get_aligned_size(params, spl_params.boot_file);
++              size = rkcommon_get_aligned_filesize(params, spl_params.boot_file);
+               if (size < 0)
+                       return EXIT_FAILURE;
+               spl_params.boot_size = size;
+@@ -301,13 +328,6 @@ bool rkcommon_need_rc4_spl(struct image_
+       return info->spl_rc4;
+ }
+-static bool rkcommon_is_header_v2(struct image_tool_params *params)
+-{
+-      struct spl_info *info = rkcommon_get_spl_info(params->imagename);
+-
+-      return (info->header_ver == RK_HEADER_V2);
+-}
+-
+ static void do_sha256_hash(uint8_t *buf, uint32_t size, uint8_t *out)
+ {
+       sha256_context ctx;
+@@ -320,12 +340,13 @@ static void do_sha256_hash(uint8_t *buf,
+ static void rkcommon_set_header0(void *buf, struct image_tool_params *params)
+ {
+       struct header0_info *hdr = buf;
+-      uint32_t init_boot_size;
++      uint32_t init_boot_size, init_offset;
+-      memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE);
++      init_offset = rkcommon_get_header_size(params) / RK_BLK_SIZE;
++      memset(buf, '\0', init_offset * RK_BLK_SIZE);
+       hdr->magic = cpu_to_le32(RK_MAGIC);
+       hdr->disable_rc4 = cpu_to_le32(!rkcommon_need_rc4_spl(params));
+-      hdr->init_offset = cpu_to_le16(RK_INIT_OFFSET);
++      hdr->init_offset = cpu_to_le16(init_offset);
+       hdr->init_size   = cpu_to_le16(spl_params.init_size / RK_BLK_SIZE);
+       /*
+@@ -353,10 +374,10 @@ static void rkcommon_set_header0_v2(void
+       uint8_t *image_ptr = NULL;
+       int i;
+-      memset(buf, '\0', RK_INIT_OFFSET * RK_BLK_SIZE);
++      sector_offset = rkcommon_get_header_size(params) / RK_BLK_SIZE;
++      memset(buf, '\0', sector_offset * RK_BLK_SIZE);
+       hdr->magic = cpu_to_le32(RK_MAGIC_V2);
+       hdr->boot_flag = cpu_to_le32(HASH_SHA256);
+-      sector_offset = 4;
+       image_size_array[0] = spl_params.init_size;
+       image_size_array[1] = spl_params.boot_size;
+@@ -382,11 +403,12 @@ static void rkcommon_set_header0_v2(void
+ void rkcommon_set_header(void *buf,  struct stat *sbuf,  int ifd,
+                        struct image_tool_params *params)
+ {
+-      struct header1_info *hdr = buf + RK_SPL_HDR_START;
+-
+       if (rkcommon_is_header_v2(params)) {
+               rkcommon_set_header0_v2(buf, params);
+       } else {
++              int header_size = rkcommon_get_header_size(params);
++              struct header1_info *hdr = buf + header_size;
++
+               rkcommon_set_header0(buf, params);
+               /* Set up the SPL name (i.e. copy spl_hdr over) */
+@@ -394,12 +416,12 @@ void rkcommon_set_header(void *buf,  str
+                       memcpy(&hdr->magic, rkcommon_get_spl_hdr(params), RK_SPL_HDR_SIZE);
+               if (rkcommon_need_rc4_spl(params))
+-                      rkcommon_rc4_encode_spl(buf, RK_SPL_HDR_START,
++                      rkcommon_rc4_encode_spl(buf, header_size,
+                                               spl_params.init_size);
+               if (spl_params.boot_file) {
+                       if (rkcommon_need_rc4_spl(params))
+-                              rkcommon_rc4_encode_spl(buf + RK_SPL_HDR_START,
++                              rkcommon_rc4_encode_spl(buf + header_size,
+                                                       spl_params.init_size,
+                                                       spl_params.boot_size);
+               }
+@@ -624,7 +646,7 @@ int rkcommon_vrec_header(struct image_to
+        * 4 bytes of these images can safely be overwritten using the
+        * boot magic.
+        */
+-      tparams->header_size = RK_SPL_HDR_START;
++      tparams->header_size = rkcommon_get_header_size(params);
+       /* Allocate, clear and install the header */
+       tparams->hdr = malloc(tparams->header_size);
+@@ -642,7 +664,8 @@ int rkcommon_vrec_header(struct image_to
+       params->orig_file_size = tparams->header_size +
+               spl_params.init_size + spl_params.boot_size;
+-      params->file_size = ROUND(params->orig_file_size, RK_SIZE_ALIGN);
++      params->file_size = rkcommon_get_aligned_size(params,
++                                                    params->orig_file_size);
+       /* Ignoring pad len, since we are using our own copy_image() */
+       return 0;
+--- a/tools/rkcommon.h
++++ b/tools/rkcommon.h
+@@ -10,9 +10,7 @@
+ enum {
+       RK_BLK_SIZE             = 512,
+       RK_SIZE_ALIGN           = 2048,
+-      RK_INIT_OFFSET          = 4,
+       RK_MAX_BOOT_SIZE        = 512 << 10,
+-      RK_SPL_HDR_START        = RK_INIT_OFFSET * RK_BLK_SIZE,
+       RK_SPL_HDR_SIZE         = 4,
+ };
diff --git a/package/boot/uboot-rockchip/patches/108-05-rockchip-mkimage-Add-support-for-up-to-4-input-files.patch b/package/boot/uboot-rockchip/patches/108-05-rockchip-mkimage-Add-support-for-up-to-4-input-files.patch
new file mode 100644 (file)
index 0000000..8f4fab3
--- /dev/null
@@ -0,0 +1,200 @@
+From 31255e35146c279696c51cde45facd1ea10eed28 Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Wed, 29 Jan 2025 22:36:31 +0000
+Subject: [PATCH 5/7] rockchip: mkimage: Add support for up to 4 input files
+
+The v2 image format can support up to 4 embedded images that can be
+loaded by the BootROM using the back-to-bootrom method.
+
+Currently two input files can be passed in using the datafile parameter,
+separated by a colon (":").
+
+Extend the datafile parameter parsing to support up to 4 input files
+separated by a colon (":") for use with the v2 image format.
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -166,17 +166,15 @@ static struct spl_info spl_infos[] = {
+ /**
+  * struct spl_params - spl params parsed in check_params()
+  *
+- * @init_file:                Init data file path
+- * @init_size:                Aligned size of init data in bytes
+- * @boot_file:                Boot data file path
+- * @boot_size:                Aligned size of boot data in bytes
++ * @file:     image file path
++ * @size:     aligned size of image in bytes
+  */
+ struct spl_params {
+-      char *init_file;
+-      uint32_t init_size;
+-      char *boot_file;
+-      uint32_t boot_size;
++      struct {
++              char *file;
++              uint32_t size;
++      } images[4];
+ };
+ static struct spl_params spl_params = { 0 };
+@@ -256,31 +254,32 @@ int rkcommon_check_params(struct image_t
+       if (!rkcommon_get_spl_info(params->imagename))
+               goto err_spl_info;
+-      spl_params.init_file = params->datafile;
++      spl_params.images[0].file = params->datafile;
++      for (i = 1; i < ARRAY_SIZE(spl_params.images); i++) {
++              spl_params.images[i].file =
++                              strchr(spl_params.images[i - 1].file, ':');
++              if (!spl_params.images[i].file)
++                      break;
+-      spl_params.boot_file = strchr(spl_params.init_file, ':');
+-      if (spl_params.boot_file) {
+-              *spl_params.boot_file = '\0';
+-              spl_params.boot_file += 1;
++              *spl_params.images[i].file = '\0';
++              spl_params.images[i].file += 1;
+       }
+-      size = rkcommon_get_aligned_filesize(params, spl_params.init_file);
+-      if (size < 0)
+-              return EXIT_FAILURE;
+-      spl_params.init_size = size;
++      for (i = 0; i < ARRAY_SIZE(spl_params.images); i++) {
++              if (!spl_params.images[i].file)
++                      break;
+-      /* Boot file is optional, and only for back-to-bootrom functionality. */
+-      if (spl_params.boot_file) {
+-              size = rkcommon_get_aligned_filesize(params, spl_params.boot_file);
++              size = rkcommon_get_aligned_filesize(params,
++                                                   spl_params.images[i].file);
+               if (size < 0)
+                       return EXIT_FAILURE;
+-              spl_params.boot_size = size;
++              spl_params.images[i].size = size;
+       }
+-      if (spl_params.init_size > rkcommon_get_spl_size(params)) {
++      if (spl_params.images[0].size > rkcommon_get_spl_size(params)) {
+               fprintf(stderr,
+                       "Error: SPL image is too large (size %#x than %#x)\n",
+-                      spl_params.init_size, rkcommon_get_spl_size(params));
++                      spl_params.images[0].size, rkcommon_get_spl_size(params));
+               return EXIT_FAILURE;
+       }
+@@ -347,7 +346,7 @@ static void rkcommon_set_header0(void *b
+       hdr->magic = cpu_to_le32(RK_MAGIC);
+       hdr->disable_rc4 = cpu_to_le32(!rkcommon_need_rc4_spl(params));
+       hdr->init_offset = cpu_to_le16(init_offset);
+-      hdr->init_size   = cpu_to_le16(spl_params.init_size / RK_BLK_SIZE);
++      hdr->init_size = cpu_to_le16(spl_params.images[0].size / RK_BLK_SIZE);
+       /*
+        * init_boot_size needs to be set, as it is read by the BootROM
+@@ -357,10 +356,11 @@ static void rkcommon_set_header0(void *b
+        * see https://lists.denx.de/pipermail/u-boot/2017-May/293267.html
+        * for a more detailed explanation by Andy Yan
+        */
+-      if (spl_params.boot_file)
+-              init_boot_size = spl_params.init_size + spl_params.boot_size;
++      if (spl_params.images[1].file)
++              init_boot_size = spl_params.images[0].size +
++                               spl_params.images[1].size;
+       else
+-              init_boot_size = spl_params.init_size + RK_MAX_BOOT_SIZE;
++              init_boot_size = spl_params.images[0].size + RK_MAX_BOOT_SIZE;
+       hdr->init_boot_size = cpu_to_le16(init_boot_size / RK_BLK_SIZE);
+       rc4_encode(buf, RK_BLK_SIZE, rc4_key);
+@@ -370,7 +370,6 @@ static void rkcommon_set_header0_v2(void
+ {
+       struct header0_info_v2 *hdr = buf;
+       uint32_t sector_offset, image_sector_count;
+-      uint32_t image_size_array[2];
+       uint8_t *image_ptr = NULL;
+       int i;
+@@ -378,19 +377,17 @@ static void rkcommon_set_header0_v2(void
+       memset(buf, '\0', sector_offset * RK_BLK_SIZE);
+       hdr->magic = cpu_to_le32(RK_MAGIC_V2);
+       hdr->boot_flag = cpu_to_le32(HASH_SHA256);
+-      image_size_array[0] = spl_params.init_size;
+-      image_size_array[1] = spl_params.boot_size;
+-      for (i = 0; i < 2; i++) {
+-              if (!image_size_array[i])
++      for (i = 0; i < ARRAY_SIZE(spl_params.images); i++) {
++              if (!spl_params.images[i].size)
+                       break;
+-              image_sector_count = image_size_array[i] / RK_BLK_SIZE;
++              image_sector_count = spl_params.images[i].size / RK_BLK_SIZE;
+               hdr->images[i].offset = cpu_to_le16(sector_offset);
+               hdr->images[i].size = cpu_to_le16(image_sector_count);
+               hdr->images[i].address = 0xFFFFFFFF;
+               hdr->images[i].counter = cpu_to_le32(i + 1);
+               image_ptr = buf + sector_offset * RK_BLK_SIZE;
+-              do_sha256_hash(image_ptr, image_size_array[i],
++              do_sha256_hash(image_ptr, spl_params.images[i].size,
+                              hdr->images[i].hash);
+               sector_offset = sector_offset + image_sector_count;
+       }
+@@ -417,13 +414,13 @@ void rkcommon_set_header(void *buf,  str
+               if (rkcommon_need_rc4_spl(params))
+                       rkcommon_rc4_encode_spl(buf, header_size,
+-                                              spl_params.init_size);
++                                              spl_params.images[0].size);
+-              if (spl_params.boot_file) {
++              if (spl_params.images[1].file) {
+                       if (rkcommon_need_rc4_spl(params))
+                               rkcommon_rc4_encode_spl(buf + header_size,
+-                                                      spl_params.init_size,
+-                                                      spl_params.boot_size);
++                                                      spl_params.images[0].size,
++                                                      spl_params.images[1].size);
+               }
+       }
+ }
+@@ -661,8 +658,9 @@ int rkcommon_vrec_header(struct image_to
+        * We need to store the original file-size (i.e. before padding), as
+        * imagetool does not set this during its adjustment of file_size.
+        */
+-      params->orig_file_size = tparams->header_size +
+-              spl_params.init_size + spl_params.boot_size;
++      params->orig_file_size = tparams->header_size;
++      for (int i = 0; i < ARRAY_SIZE(spl_params.images); i++)
++              params->orig_file_size += spl_params.images[i].size;
+       params->file_size = rkcommon_get_aligned_size(params,
+                                                     params->orig_file_size);
+@@ -749,16 +747,13 @@ err_close:
+ int rockchip_copy_image(int ifd, struct image_tool_params *params)
+ {
+-      int ret;
+-
+-      ret = copy_file(params, ifd, spl_params.init_file,
+-                      spl_params.init_size);
+-      if (ret)
+-              return ret;
++      int i, ret;
+-      if (spl_params.boot_file) {
+-              ret = copy_file(params, ifd, spl_params.boot_file,
+-                              spl_params.boot_size);
++      for (i = 0; i < ARRAY_SIZE(spl_params.images); i++) {
++              if (!spl_params.images[i].size)
++                      break;
++              ret = copy_file(params, ifd, spl_params.images[i].file,
++                              spl_params.images[i].size);
+               if (ret)
+                       return ret;
+       }
diff --git a/package/boot/uboot-rockchip/patches/108-06-rockchip-mkimage-Add-option-for-image-load-address-a.patch b/package/boot/uboot-rockchip/patches/108-06-rockchip-mkimage-Add-option-for-image-load-address-a.patch
new file mode 100644 (file)
index 0000000..7bd8b53
--- /dev/null
@@ -0,0 +1,47 @@
+From 3e252cae2b5b95c483104318120338d5a51a6b4d Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Wed, 29 Jan 2025 22:36:32 +0000
+Subject: [PATCH 6/7] rockchip: mkimage: Add option for image load address and
+ flag
+
+The v2 image format supports defining a load address and flag for each
+embedded image.
+
+Add initial support for writing the image load address and flag to the
+v2 image format header.
+
+This may later be used for RK3576 to embed a minimal initial image that
+if required to fix booting from SD-card due to a BootROM issue.
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -168,12 +168,16 @@ static struct spl_info spl_infos[] = {
+  *
+  * @file:     image file path
+  * @size:     aligned size of image in bytes
++ * @address:  image load address
++ * @flag:     no use
+  */
+ struct spl_params {
+       struct {
+               char *file;
+               uint32_t size;
++              uint32_t address;
++              uint32_t flag;
+       } images[4];
+ };
+@@ -384,7 +388,8 @@ static void rkcommon_set_header0_v2(void
+               image_sector_count = spl_params.images[i].size / RK_BLK_SIZE;
+               hdr->images[i].offset = cpu_to_le16(sector_offset);
+               hdr->images[i].size = cpu_to_le16(image_sector_count);
+-              hdr->images[i].address = 0xFFFFFFFF;
++              hdr->images[i].address = spl_params.images[i].address ?: 0xFFFFFFFF;
++              hdr->images[i].flag = spl_params.images[i].flag;
+               hdr->images[i].counter = cpu_to_le32(i + 1);
+               image_ptr = buf + sector_offset * RK_BLK_SIZE;
+               do_sha256_hash(image_ptr, spl_params.images[i].size,
diff --git a/package/boot/uboot-rockchip/patches/108-07-WIP-rockchip-mkimage-Add-rk3576-align-and-sd-card-wo.patch b/package/boot/uboot-rockchip/patches/108-07-WIP-rockchip-mkimage-Add-rk3576-align-and-sd-card-wo.patch
new file mode 100644 (file)
index 0000000..b1dfe1b
--- /dev/null
@@ -0,0 +1,106 @@
+From f6f1066339a58444d515f1ed72a172610995d090 Mon Sep 17 00:00:00 2001
+From: Jonas Karlman <jonas@kwiboo.se>
+Date: Tue, 28 Jan 2025 01:30:12 +0000
+Subject: [PATCH 7/7] WIP: rockchip: mkimage: Add rk3576 align and sd-card
+ workaround
+
+The BootROM on RK3576 has an issue loading boot images from an SD-card.
+This issue can be worked around by injecting an initial boot image
+before TPL that:
+
+  writel(0x3ffff800, 0x3ff803b0)
+
+Prepend an image containing binary code that does this and return to
+BootROM to load next image, TPL.
+
+TODO: embed the binary code into rkcommon.c
+
+Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
+---
+
+--- /dev/null
++++ b/rk3576-boost.c
+@@ -0,0 +1,49 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++// Copyright Contributors to the U-Boot project.
++
++/*
++ * Generate assembly code for the c code in this file:
++ *  aarch64-linux-gnu-gcc -nostdlib -ffreestanding -Os -S -o rk3576-boost.S rk3576-boost.c
++ *
++ * Compile assembly code and extract the AArch64 binary code:
++ *  aarch64-linux-gnu-as -o rk3576-boost.o rk3576-boost.S
++ *  aarch64-linux-gnu-objcopy -O binary -j .text rk3576-boost.o rk3576-boost.bin
++ */
++
++#include <stdint.h>
++
++#define SYS_SRAM_BASE 0x3ff80000
++#define OFFSET                0x03b0
++
++int _start(void)
++{
++      uint32_t *sram = (void*)(SYS_SRAM_BASE + OFFSET);
++
++      /* set unknown value in sram to fix boot from sdmmc */
++      *(sram) = 0x3ffff800;
++
++      return 0;
++}
++
++/*
++      .arch armv8-a
++      .file   "rk3576-boost.c"
++      .text
++      .align  2
++      .global _start
++      .type   _start, %function
++_start:
++.LFB0:
++      .cfi_startproc
++      mov     x0, 944
++      mov     w1, 1073739776
++      movk    x0, 0x3ff8, lsl 16
++      str     w1, [x0]
++      mov     w0, 0
++      ret
++      .cfi_endproc
++.LFE0:
++      .size   _start, .-_start
++      .ident  "GCC: (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0"
++      .section        .note.GNU-stack,"",@progbits
++*/
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -159,7 +159,7 @@ static struct spl_info spl_infos[] = {
+       { "rv1126", "110B", 0x10000 - 0x1000, false, RK_HEADER_V1 },
+       { "rk3528", "RK35", 0x10000 - 0x1000, false, RK_HEADER_V2 },
+       { "rk3568", "RK35", 0x10000 - 0x1000, false, RK_HEADER_V2 },
+-      { "rk3576", "RK35", 0x80000 - 0x1000, false, RK_HEADER_V2 },
++      { "rk3576", "RK35", 0x80000 - 0x1000, false, RK_HEADER_V2, 8 },
+       { "rk3588", "RK35", 0x100000 - 0x1000, false, RK_HEADER_V2 },
+ };
+@@ -287,6 +287,22 @@ int rkcommon_check_params(struct image_t
+               return EXIT_FAILURE;
+       }
++      if (!strcmp(params->imagename, "rk3576")) {
++              size = rkcommon_get_aligned_filesize(params, "rk3576-boost.bin");
++              if (size < 0)
++                      return EXIT_SUCCESS;
++
++              for (i = ARRAY_SIZE(spl_params.images) - 1; i > 0; i--) {
++                      spl_params.images[i] = spl_params.images[i - 1];
++              }
++
++              spl_params.images[0].file = "rk3576-boost.bin";
++              spl_params.images[0].size = size;
++
++              spl_params.images[0].address = 0x3ffc0000;
++              spl_params.images[1].address = 0x3ff81000;
++      }
++
+       return EXIT_SUCCESS;
+ err_spl_info: