summaryrefslogtreecommitdiff
path: root/board/keymile
diff options
context:
space:
mode:
authorAleksandar Gerasimovski <aleksandar.gerasimovski@hitachienergy.com>2021-12-10 13:07:53 +0300
committerPriyanka Jain <priyanka.jain@nxp.com>2022-02-01 12:38:07 +0300
commitefe19295a59dae28c1af813486fe88f34378a980 (patch)
treee750362b8dc09b974e1f97f7e432bb66e52326cc /board/keymile
parentde144d5ffe0c15c56e3bbd64832bc4b265bd663f (diff)
downloadu-boot-efe19295a59dae28c1af813486fe88f34378a980.tar.xz
km: common: implement field fail-safe u-boot update
This patch provides possibility for field fail-safe u-boot updates. The implementation can be used on all pg-wcom boards that are booting from parallel NOR flash. When used in a board design, provided check_for_uboot_update function will start new u-boot at defined location if updateduboot envvar is set to yes. With this implementation it is expected that factory programmed u-boot will always stay as it is, and optionally new u-boot can be safely programmed by embedded software when the unit is rolled out on the field. It is expected check_for_uboot_update to be called early in execution before relocation (*_f) once SoC is basically initialized and environment can be read, with this possibilities to not be able to fix a u-boot bug by a u-boot update are reduced to minimum. Signed-off-by: Aleksandar Gerasimovski <aleksandar.gerasimovski@hitachienergy.com> Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
Diffstat (limited to 'board/keymile')
-rw-r--r--board/keymile/Kconfig32
-rw-r--r--board/keymile/README18
-rw-r--r--board/keymile/common/common.c53
-rw-r--r--board/keymile/common/common.h1
4 files changed, 104 insertions, 0 deletions
diff --git a/board/keymile/Kconfig b/board/keymile/Kconfig
index 7dd8213ab5..863c07db47 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 0000000000..4e5cfb142a
--- /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 ff07260194..3999f48719 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 fc14728f9b..d16c82487b 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))