diff --git a/common/Kconfig b/common/Kconfig index b679e3a132b9..d5b0eaa49b01 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1069,5 +1069,6 @@ config OPENIPC_NOR_SPLIT kernel is told nothing about it: the fixed-slot mtdparts and root= of a saved environment are dropped, and bootm checks the uImage CRC. Only for boards whose kernel knows the layout (gk7205v200 family, - hi3516cv6xx, hi3519dv500, hi3516cv300/hi3516ev100). + hi3516cv6xx, hi3519dv500, hi3516cv300/hi3516ev100, the hi3516ev200 + family). diff --git a/common/openipc.c b/common/openipc.c index c2e4fa7fafb4..d59f5b692753 100644 --- a/common/openipc.c +++ b/common/openipc.c @@ -777,8 +777,18 @@ int firmware_scan(void) { env_set("fwsize", str); /* RAM only, like the rest of the scan: a saved environment keeps an * older fwwrite that erased only the file's length */ - env_set("fwwrite", "sf probe 0; sf erase ${kernaddr} ${fwsize}; " - "sf write ${baseaddr} ${kernaddr} ${filesize}"); + env_set("fwwrite", OPENIPC_FWWRITE_SPLIT_CMD); + } + /* A saved fwupd from before the split layout fetches only the pair; + * exactly that one takes the firmware file first. An edited one is + * left alone. */ + { + const char *fu = env_get("fwupd"); + + if (fu && !strcmp(fu, OPENIPC_FWUPD_LEGACY_CMD)) + env_set("fwupd", OPENIPC_FWUPD_SPLIT_CMD); + if (!env_get("fwfile")) + env_set("fwfile", OPENIPC_FW_FILE); } } #endif @@ -898,6 +908,25 @@ int firmware_scan(void) { env_set("mtds", mtds); sprintf(mtdparts, "%s:%s", mtdids ? mtdids : "", mtds); env_set("mtdparts", mtdparts); +#ifdef CONFIG_OPENIPC_NOR_SPLIT + /* + * Fixed slots need root= and mtdparts= on the command line. A build of + * this bootloader that saved its environment after the scan could + * have stored a split boot's bootargs without them; put them back, in + * RAM, when both are missing. A command line that names either is the + * owner's and is left alone. + */ + { + const char *ba = env_get("bootargs"); + char buf[1024]; + + if (ba && !strstr(ba, "root=") && !strstr(ba, "mtdparts=") && + strlen(ba) + 64 < sizeof(buf)) { + snprintf(buf, sizeof(buf), "%s root=/dev/mtdblock3 mtdparts=${mtdparts}", ba); + env_set("bootargs", buf); + } + } +#endif } if (kernel_off && rootfs_off) { @@ -994,14 +1023,18 @@ int openipc_helper(void) { sprintf(msize, "%ldM", gd->ram_size / 1024 / 1024); env_set("totalmem", msize); firmware_recovery(); - firmware_scan(); altbootcmd_migrate(); /* Persist the default environment on first start (or after a bad env); * only if the device env area is still blank so we never overwrite - * foreign data (e.g. a RAM-booted U-Boot on another device). */ + * foreign data (e.g. a RAM-booted U-Boot on another device). Both saves + * come before the scan: what it sets (the layout's addresses and + * mtdparts, a split boot's bootargs without root= and mtdparts=) is for + * this boot only, and a later fixed-slot image needs the defaults. */ if ((gd->flags & GD_FLG_ENV_DEFAULT) && env_crc_is_blank()) env_save(); + firmware_scan(); + return 0; } diff --git a/include/configs/openipc-common.h b/include/configs/openipc-common.h index 1efdc7b88aeb..aba8df827fdd 100644 --- a/include/configs/openipc-common.h +++ b/include/configs/openipc-common.h @@ -202,12 +202,26 @@ void hi_gpio_status(void); * size selects the NOR schema. */ #ifdef CONFIG_OPENIPC_NOR_SPLIT +/* the firmware file when the server has one, else the fixed-slot pair */ +#define OPENIPC_FWUPD_SPLIT_CMD \ + "if ${source} ${baseaddr} ${fwfile}; then run fwwrite; else run ur; run uk; fi" +/* fwupd as a saved environment from before the split layout spells it */ +#define OPENIPC_FWUPD_LEGACY_CMD "run ur; run uk" +/* + * The whole firmware area (the scan sets fwsize to the end of the chip), and + * only for a file that fits it: an oversized download must not erase the + * firmware it cannot replace. + */ +#define OPENIPC_FWWRITE_SPLIT_CMD \ + "sf probe 0; if itest ${filesize} -gt 0; then if itest ${filesize} -le ${fwsize}; then " \ + "sf erase ${kernaddr} ${fwsize}; sf write ${baseaddr} ${kernaddr} ${filesize}; " \ + "else echo fwwrite: ${filesize} bytes do not fit ${fwsize} from ${kernaddr}, nothing written; fi; " \ + "else echo fwwrite: empty file, nothing written; fi" #define OPENIPC_FWUPD \ "fwfile=" OPENIPC_FW_FILE "\0" \ - "fwupd=if ${source} ${baseaddr} ${fwfile}; then run fwwrite; else run ur; run uk; fi\0" -/* the whole firmware area: the scan sets fwsize to the end of the chip */ + "fwupd=" OPENIPC_FWUPD_SPLIT_CMD "\0" #define OPENIPC_FWWRITE \ - "fwwrite=sf probe 0; sf erase ${kernaddr} ${fwsize}; sf write ${baseaddr} ${kernaddr} ${filesize}\0" + "fwwrite=" OPENIPC_FWWRITE_SPLIT_CMD "\0" #else #define OPENIPC_FWUPD "fwupd=run ur; run uk\0" #define OPENIPC_FWWRITE \ diff --git a/openipc/hi3516dv200_config b/openipc/hi3516dv200_config index 4b639510d489..33bea8fd3854 100644 --- a/openipc/hi3516dv200_config +++ b/openipc/hi3516dv200_config @@ -8,3 +8,7 @@ CONFIG_SYS_LOAD_ADDR=0x42000000 CONFIG_MMC=y CONFIG_CMD_MMC=y CONFIG_MMC_SDHCI=y + +# The split NOR layout: the kernel (OpenIPC/linux hisilicon-hi3516ev200) +# divides one firmware partition from its own device tree. +CONFIG_OPENIPC_NOR_SPLIT=y diff --git a/openipc/hi3516ev200_config b/openipc/hi3516ev200_config index df6e82cad012..b679c1e90f5d 100644 --- a/openipc/hi3516ev200_config +++ b/openipc/hi3516ev200_config @@ -3,3 +3,7 @@ CONFIG_SYS_LOAD_ADDR=0x42000000 CONFIG_MMC=y CONFIG_CMD_MMC=y CONFIG_MMC_SDHCI=y + +# The split NOR layout: the kernel (OpenIPC/linux hisilicon-hi3516ev200) +# divides one firmware partition from its own device tree. +CONFIG_OPENIPC_NOR_SPLIT=y diff --git a/openipc/hi3516ev300_config b/openipc/hi3516ev300_config index 2b6778487743..4852f7406314 100644 --- a/openipc/hi3516ev300_config +++ b/openipc/hi3516ev300_config @@ -8,3 +8,7 @@ CONFIG_SYS_LOAD_ADDR=0x42000000 CONFIG_MMC=y CONFIG_CMD_MMC=y CONFIG_MMC_SDHCI=y + +# The split NOR layout: the kernel (OpenIPC/linux hisilicon-hi3516ev200) +# divides one firmware partition from its own device tree. +CONFIG_OPENIPC_NOR_SPLIT=y diff --git a/openipc/hi3518ev300_config b/openipc/hi3518ev300_config index 95f81d45574a..5586243f3ae0 100644 --- a/openipc/hi3518ev300_config +++ b/openipc/hi3518ev300_config @@ -8,3 +8,7 @@ CONFIG_SYS_LOAD_ADDR=0x42000000 CONFIG_MMC=y CONFIG_CMD_MMC=y CONFIG_MMC_SDHCI=y + +# The split NOR layout: the kernel (OpenIPC/linux hisilicon-hi3516ev200) +# divides one firmware partition from its own device tree. +CONFIG_OPENIPC_NOR_SPLIT=y