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 -h6 parameter 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 --h6 parameter when building for a
SUN50I_GEN_H6 SoC.

Tested on Whatsminer H616 board, booting from NAND.

Co-developed-by: James Hilliard <[email protected]>
Signed-off-by: James Hilliard <[email protected]>
Signed-off-by: Richard Genoud <[email protected]>
---
 drivers/mtd/nand/raw/Kconfig    |  1 +
 scripts/Makefile.xpl            |  1 +
 tools/sunxi-spl-image-builder.c | 89 ++++++++++++++++++++++++++-------
 3 files changed, 72 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 754b99bf3eb6..5977de76429c 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -484,6 +484,7 @@ if NAND_SUNXI
 config NAND_SUNXI_SPL_ECC_STRENGTH
        int "Allwinner NAND SPL ECC Strength"
        default 64
+       default 80 if SUN50I_GEN_H6
 
 config NAND_SUNXI_SPL_ECC_SIZE
        int "Allwinner NAND SPL ECC Step Size"
diff --git a/scripts/Makefile.xpl b/scripts/Makefile.xpl
index 52f014ad3324..aa4ee5cc1ce7 100644
--- a/scripts/Makefile.xpl
+++ b/scripts/Makefile.xpl
@@ -455,6 +455,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),--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..f9ba1c474be9 100644
--- a/tools/sunxi-spl-image-builder.c
+++ b/tools/sunxi-spl-image-builder.c
@@ -27,6 +27,7 @@ struct image_info {
        int eraseblock_size;
        int scramble;
        int boot0;
+       int h6;
        off_t offset;
        const char *source;
        const char *dest;
@@ -84,18 +85,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 +149,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 +229,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 +328,7 @@ 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"
+               "-6               --h6                 Build an image 
compatible with H6/H616 SoC\n"
                "-a <offset>      --address=<offset>   Where the image will be 
programmed.\n"
                "\n"
                "Notes:\n"
@@ -313,6 +339,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 +371,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 +401,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 +463,11 @@ int main(int argc, char **argv)
                        {"boot0", no_argument, 0, 'b'},
                        {"scramble", no_argument, 0, 's'},
                        {"address", required_argument, 0, 'a'},
+                       {"h6", no_argument, 0, '6'},
                        {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:sh6",
                                long_options, &option_index);
                if (c == EOF)
                        break;
@@ -454,6 +502,9 @@ int main(int argc, char **argv)
                case 'a':
                        info.offset = strtoull(optarg, NULL, 0);
                        break;
+               case '6':
+                       info.h6 = 1;
+                       break;
                case '?':
                        display_help(-1);
                        break;

base-commit: 2ba64e303b2706e5c42a6bf982326d632342ca66
-- 
2.47.3

Reply via email to