diff options
-rw-r--r-- | board/keymile/Kconfig | 32 | ||||
-rw-r--r-- | board/keymile/README | 18 | ||||
-rw-r--r-- | board/keymile/common/common.c | 53 | ||||
-rw-r--r-- | board/keymile/common/common.h | 1 |
4 files changed, 104 insertions, 0 deletions
diff --git a/board/keymile/Kconfig b/board/keymile/Kconfig index 7dd8213..863c07d 100644 --- a/board/keymile/Kconfig +++ b/board/keymile/Kconfig @@ -130,6 +130,38 @@ config SYS_IVM_EEPROM_PAGE_LEN help Page size of inventory in EEPROM. +config PG_WCOM_UBOOT_UPDATE_SUPPORTED + bool "Enable U-boot Field Fail-Safe Update Functionality" + default n + help + Indicates that field fail-safe u-boot update is supported. + This functionality works only for designs that are booting + from parallel NOR flash. + +config PG_WCOM_UBOOT_BOOTPACKAGE + bool "U-boot Is Part Of Factory Boot-Package Image" + default n + help + Indicates that u-boot will be a part of the factory programmed + boot-package image. + Has to be set for original u-boot programmed at factory. + +config PG_WCOM_UBOOT_UPDATE_TEXT_BASE + hex "Text Base For U-boot Programmed Outside Factory" + default 0xFFFFFFFF + help + Text base of an updated u-boot that is not factory programmed but + later when the unit is rolled out on the field. + Has to be set for original u-boot programmed at factory. + +config PG_WCOM_UBOOT_UPDATE + bool "U-boot Is Part Of Factory Boot-Package Image" + default n + help + Indicates that u-boot will be a part of the embedded software and + programmed at field. + Has to be set for updated u-boot version programmed at field. + source "board/keymile/km83xx/Kconfig" source "board/keymile/kmcent2/Kconfig" source "board/keymile/km_arm/Kconfig" diff --git a/board/keymile/README b/board/keymile/README new file mode 100644 index 0000000..4e5cfb1 --- /dev/null +++ b/board/keymile/README @@ -0,0 +1,18 @@ +Field Fail-Save U-boot Update +----------------------------- +Field Fail-Save u-boot update is a feature that allows save u-boot update +of FOX and XMC products that are rolled out in the field. + +The feature is initially implemented for designs based on LS102x SoC, but in +theory can be used on all designs that are booting from parallel NOR flash. + +The implementation expects redundant (secondary) u-boot image on a predefined +location in the NOR flash, u-boot execution will be transferred to the redundant +(secondary) u-boot and redundant u-boot will be started if 'updateduboot' envvar +is set to 'yes'. +Update logic check_for_uboot_update() has to be invoked from the design early +before relocation just after SoC initialization, e.g from board_early_init_f or +misc_init_f functions. +By design it is expected that primary u-boot image is burned in the factory and +never updated, and in case u-boot update is required it can flashed and started +from secondary u-boot location. diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c index ff07260..3999f48 100644 --- a/board/keymile/common/common.c +++ b/board/keymile/common/common.c @@ -19,6 +19,8 @@ #include <asm/io.h> #include <linux/ctype.h> #include <linux/delay.h> +#include <linux/bug.h> +#include <bootcount.h> #if defined(CONFIG_POST) #include "post.h" @@ -76,6 +78,57 @@ int set_km_env(void) return 0; } +#if CONFIG_IS_ENABLED(PG_WCOM_UBOOT_UPDATE_SUPPORTED) +#if ((!CONFIG_IS_ENABLED(PG_WCOM_UBOOT_BOOTPACKAGE) && \ + !CONFIG_IS_ENABLED(PG_WCOM_UBOOT_UPDATE)) || \ + (CONFIG_IS_ENABLED(PG_WCOM_UBOOT_BOOTPACKAGE) && \ + CONFIG_IS_ENABLED(PG_WCOM_UBOOT_UPDATE))) +#error "It has to be either bootpackage or update u-boot image!" +#endif +void check_for_uboot_update(void) +{ + void (*uboot_update_entry)(void) = + (void (*)(void)) CONFIG_PG_WCOM_UBOOT_UPDATE_TEXT_BASE; + char *isupdated = env_get("updateduboot"); + ulong bootcount = bootcount_load(); + ulong ebootcount = 0; + + if (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_BOOTPACKAGE)) { + /* + * When running in factory burned u-boot move to the updated + * u-boot version only if updateduboot envvar is set to 'yes' + * and bootcount limit is not exceeded. + * Board must be able to start in factory bootloader mode! + */ + if (isupdated && !strncmp(isupdated, "yes", 3) && + bootcount <= CONFIG_BOOTCOUNT_BOOTLIMIT) { + printf("Check update: update detected, "); + printf("starting new image @%08x ...\n", + CONFIG_PG_WCOM_UBOOT_UPDATE_TEXT_BASE); + ebootcount = early_bootcount_load(); + if (ebootcount <= CONFIG_BOOTCOUNT_BOOTLIMIT) { + early_bootcount_store(++ebootcount); + uboot_update_entry(); + } else { + printf("Check update: warning: "); + printf("early bootcount exceeded (%lu)\n", + ebootcount); + } + } + printf("Check update: starting factory image @%08x ...\n", + CONFIG_SYS_TEXT_BASE); + } else if (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_UPDATE)) { + /* + * When running in field updated u-boot, make sure that + * bootcount limit is never exceeded. Must never happen! + */ + WARN_ON(bootcount > CONFIG_BOOTCOUNT_BOOTLIMIT); + printf("Check update: updated u-boot starting @%08x ...\n", + CONFIG_SYS_TEXT_BASE); + } +} +#endif + #if defined(CONFIG_SYS_I2C_INIT_BOARD) static void i2c_write_start_seq(void) { diff --git a/board/keymile/common/common.h b/board/keymile/common/common.h index fc14728..d16c824 100644 --- a/board/keymile/common/common.h +++ b/board/keymile/common/common.h @@ -135,6 +135,7 @@ int set_km_env(void); ulong early_bootcount_load(void); void early_bootcount_store(ulong ebootcount); +void check_for_uboot_update(void); #define DELAY_ABORT_SEQ 62 /* @200kHz 9 clocks = 44us, 62us is ok */ #define DELAY_HALF_PERIOD (500 / (CONFIG_SYS_I2C_SPEED / 1000)) |