uboot-rockchip: fix boot from SD card for rk3576

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>
This commit is contained in:
Ryan Leung
2026-05-14 17:52:56 +02:00
committed by Hauke Mehrtens
parent e13cbab684
commit 54e47e56c2
8 changed files with 861 additions and 0 deletions
+10
View 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
@@ -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,
@@ -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)
@@ -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),
@@ -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,
};
@@ -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;
}
@@ -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,
@@ -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: