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>
This commit is contained in:
Aleksandar Gerasimovski 2021-12-10 11:07:53 +01:00 committed by Priyanka Jain
parent de144d5ffe
commit efe19295a5
4 changed files with 104 additions and 0 deletions

View file

@ -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"

18
board/keymile/README Normal file
View file

@ -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.

View file

@ -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)
{

View file

@ -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))