[PATCH v3] tools: sunxi-spl-image-builder: support H6/H616 NAND boot
    Richard Genoud 
    richard.genoud at bootlin.com
       
    Tue Oct 28 09:37:33 CET 2025
    
    
  
The H6/H616 boot ROM doesn't expect a SPL scrambled the same way as
older SoCs.
It doesn't use a specific seeds table, it expects a maximized ECC
(BCH-80), a specific BBM (FF000301) and doesn't work if empty pages are
skipped (it needs its specific BBM, even in the padding).
So, add a --soc=h6 option to support H6/616 with:
- more ECC strengths
- specific BBM
- default_scrambler_seeds[] with all values
- no empty pages skip
In Kconfig, select BCH-80 by default for SUNXI_SPL_ECC_STRENGTH to make
BROM happy.
And in scripts/Makefile.xpl, use --soc=h6 option when building for a
SUN50I_GEN_H6 SoC.
Tested on Whatsminer H616 board, booting from NAND.
Co-developed-by: James Hilliard <james.hilliard1 at gmail.com>
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
Signed-off-by: Richard Genoud <richard.genoud at bootlin.com>
---
 drivers/mtd/nand/raw/Kconfig    |  1 +
 scripts/Makefile.xpl            |  1 +
 tools/sunxi-spl-image-builder.c | 92 ++++++++++++++++++++++++++-------
 3 files changed, 75 insertions(+), 19 deletions(-)
Changes from v2:
- add a --soc=h6 option as suggested by Michael
Changes from v1:
- move up "default 80 if SUN50I_GEN_H6" (sorry for the noise)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 9c8a32bb0a89..b5fc4f5f8c34 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -475,6 +475,7 @@ if NAND_SUNXI
 
 config NAND_SUNXI_SPL_ECC_STRENGTH
 	int "Allwinner NAND SPL ECC Strength"
+	default 80 if SUN50I_GEN_H6
 	default 64
 
 config NAND_SUNXI_SPL_ECC_SIZE
diff --git a/scripts/Makefile.xpl b/scripts/Makefile.xpl
index 3e940bf562d5..98d139724c54 100644
--- a/scripts/Makefile.xpl
+++ b/scripts/Makefile.xpl
@@ -454,6 +454,7 @@ $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
 
 quiet_cmd_sunxi_spl_image_builder = SUNXI_SPL_IMAGE_BUILDER $@
 cmd_sunxi_spl_image_builder = $(objtree)/tools/sunxi-spl-image-builder \
+				$(if $(CONFIG_SUN50I_GEN_H6),--soc=h6) \
 				-c $(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH)/$(CONFIG_NAND_SUNXI_SPL_ECC_SIZE) \
 				-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
 				-o $(CONFIG_SYS_NAND_OOBSIZE) \
diff --git a/tools/sunxi-spl-image-builder.c b/tools/sunxi-spl-image-builder.c
index a367f1177403..8a8ab124a7e4 100644
--- a/tools/sunxi-spl-image-builder.c
+++ b/tools/sunxi-spl-image-builder.c
@@ -11,6 +11,7 @@
 #include <linux/bch.h>
 
 #include <getopt.h>
+#include <string.h>
 #include <version.h>
 
 #define BCH_PRIMITIVE_POLY	0x5803
@@ -27,6 +28,7 @@ struct image_info {
 	int eraseblock_size;
 	int scramble;
 	int boot0;
+	int h6;
 	off_t offset;
 	const char *source;
 	const char *dest;
@@ -84,18 +86,29 @@ static void scramble(const struct image_info *info,
 	uint16_t state;
 	int i;
 
-	/* Boot0 is always scrambled no matter the command line option. */
-	if (info->boot0) {
+	/*
+	 * Bail out earlier if the user didn't ask for scrambling.
+	 * But Boot0 is always scrambled no matter the command line option.
+	 */
+	if (!info->boot0 && !info->scramble)
+		return;
+
+	/*
+	 * On H6, the BROM scrambler seed is no different than the default one
+	 */
+	if (info->boot0 && !info->h6) {
 		state = brom_scrambler_seeds[0];
 	} else {
-		unsigned seedmod = info->eraseblock_size / info->page_size;
+		unsigned int seedmod;
 
-		/* Bail out earlier if the user didn't ask for scrambling. */
-		if (!info->scramble)
-			return;
-
-		if (seedmod > ARRAY_SIZE(default_scrambler_seeds))
+		if (info->h6) {
+			/* H6 boot0 uses all 128 seeds */
 			seedmod = ARRAY_SIZE(default_scrambler_seeds);
+		} else {
+			seedmod = info->eraseblock_size / info->page_size;
+			if (seedmod > ARRAY_SIZE(default_scrambler_seeds))
+				seedmod = ARRAY_SIZE(default_scrambler_seeds);
+		}
 
 		state = default_scrambler_seeds[page % seedmod];
 	}
@@ -137,14 +150,19 @@ static int write_page(const struct image_info *info, uint8_t *buffer,
 
 	fwrite(buffer, info->page_size + info->oob_size, 1, dst);
 
-	for (i = 0; i < info->usable_page_size; i++) {
-		if (buffer[i] !=  0xff)
-			break;
-	}
+	/*
+	 * H6 BROM doesn't support empty pages
+	 */
+	if (!info->h6) {
+		for (i = 0; i < info->usable_page_size; i++) {
+			if (buffer[i] !=  0xff)
+				break;
+		}
 
-	/* We leave empty pages at 0xff. */
-	if (i == info->usable_page_size)
-		return 0;
+		/* We leave empty pages at 0xff. */
+		if (i == info->usable_page_size)
+			return 0;
+	}
 
 	/* Restore the source pointer to read it again. */
 	fseek(src, -cnt, SEEK_CUR);
@@ -212,6 +230,14 @@ static int write_page(const struct image_info *info, uint8_t *buffer,
 		}
 
 		memset(ecc, 0, eccbytes);
+
+		if (info->h6) {
+			/* BBM taken from vendor code: FF 00 03 01 */
+			buffer[info->ecc_step_size + 1] = 0;
+			buffer[info->ecc_step_size + 2] = 3; // NAND_VERSION_0
+			buffer[info->ecc_step_size + 3] = 1; // NAND_VERSION_1
+		}
+
 		swap_bits(buffer, info->ecc_step_size + 4);
 		encode_bch(bch, buffer, info->ecc_step_size + 4, ecc);
 		swap_bits(buffer, info->ecc_step_size + 4);
@@ -303,6 +329,8 @@ static void display_help(int status)
 		"-e <size>        --eraseblock=<size>  Erase block size\n"
 		"-b               --boot0              Build a boot0 image.\n"
 		"-s               --scramble           Scramble data\n"
+		"-t               --soc=<soc>          Build an image compatible with SoC type <soc>\n"
+		"                                      (possible values: a10, h6. Default: a10)\n"
 		"-a <offset>      --address=<offset>   Where the image will be programmed.\n"
 		"\n"
 		"Notes:\n"
@@ -313,6 +341,9 @@ static void display_help(int status)
 		"  Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64\n"
 		"  Valid ECC step size: 512 and 1024\n"
 		"\n"
+		"On H6/H616, the only ECC step size supported is 1024, but more ECC\n"
+		"strengths are supported: 44, 52, 68, 72, 76, 80\n"
+		"\n"
 		"If you are building a boot0 image, you'll have specify extra options.\n"
 		"These options should be chosen based on the layouts described here:\n"
 		"  http://linux-sunxi.org/NAND#More_information_on_BROM_NAND\n"
@@ -342,7 +373,12 @@ static void display_help(int status)
 
 static int check_image_info(struct image_info *info)
 {
-	static int valid_ecc_strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
+	static int ecc_strengths_a10[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
+	static int ecc_strengths_h6[] = {
+		16, 24, 28, 32, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80
+	};
+	int *valid_ecc_strengths;
+	size_t nstrengths;
 	int eccbytes, eccsteps;
 	unsigned i;
 
@@ -367,12 +403,25 @@ static int check_image_info(struct image_info *info)
 		return -EINVAL;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(valid_ecc_strengths); i++) {
+	if (info->h6) {
+		if (info->ecc_step_size != 1024) {
+			fprintf(stderr,
+				"H6 SoCs supports only 1024 bytes ECC step\n");
+			return -EINVAL;
+		}
+		valid_ecc_strengths = ecc_strengths_h6;
+		nstrengths = ARRAY_SIZE(ecc_strengths_h6);
+	} else {
+		valid_ecc_strengths = ecc_strengths_a10;
+		nstrengths = ARRAY_SIZE(ecc_strengths_a10);
+	}
+
+	for (i = 0; i < nstrengths; i++) {
 		if (valid_ecc_strengths[i] == info->ecc_strength)
 			break;
 	}
 
-	if (i == ARRAY_SIZE(valid_ecc_strengths)) {
+	if (i == nstrengths) {
 		fprintf(stderr, "Invalid ECC strength argument: %d\n",
 			info->ecc_strength);
 		return -EINVAL;
@@ -416,10 +465,11 @@ int main(int argc, char **argv)
 			{"boot0", no_argument, 0, 'b'},
 			{"scramble", no_argument, 0, 's'},
 			{"address", required_argument, 0, 'a'},
+			{"soc", required_argument, 0, 't'},
 			{0, 0, 0, 0},
 		};
 
-		int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sh",
+		int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sht:",
 				long_options, &option_index);
 		if (c == EOF)
 			break;
@@ -454,6 +504,10 @@ int main(int argc, char **argv)
 		case 'a':
 			info.offset = strtoull(optarg, NULL, 0);
 			break;
+		case 't':
+			if (strcmp("h6", optarg) == 0)
+				info.h6 = 1;
+			break;
 		case '?':
 			display_help(-1);
 			break;
base-commit: e50b1e8715011def8aff1588081a2649a2c6cd47
-- 
2.47.3
    
    
More information about the U-Boot
mailing list