diff options
Diffstat (limited to 'board/keymile/common')
| -rw-r--r-- | board/keymile/common/common.c | 53 | ||||
| -rw-r--r-- | board/keymile/common/common.h | 4 | ||||
| -rw-r--r-- | board/keymile/common/qrio.c | 64 | ||||
| -rw-r--r-- | board/keymile/common/qrio.h | 2 |
4 files changed, 123 insertions, 0 deletions
diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c index ff07260194c..3999f487192 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 15a3c3797d1..d16c82487b8 100644 --- a/board/keymile/common/common.h +++ b/board/keymile/common/common.h @@ -133,6 +133,10 @@ int get_testpin(void); 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)) diff --git a/board/keymile/common/qrio.c b/board/keymile/common/qrio.c index da516918af1..5401bddf06a 100644 --- a/board/keymile/common/qrio.c +++ b/board/keymile/common/qrio.c @@ -27,6 +27,32 @@ void show_qrio(void) (id_rev >> 8) & 0xff, id_rev & 0xff); } +#define SLFTEST_OFF 0x06 + +bool qrio_get_selftest_pin(void) +{ + u8 slftest; + + void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE; + + slftest = in_8(qrio_base + SLFTEST_OFF); + + return (slftest & 1) > 0; +} + +#define BPRTH_OFF 0x04 + +bool qrio_get_pgy_pres_pin(void) +{ + u8 pgy_pres; + + void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE; + + pgy_pres = in_8(qrio_base + BPRTH_OFF); + + return (pgy_pres & 0x80) > 0; +} + int qrio_get_gpio(u8 port_off, u8 gpio_nr) { u32 gprt; @@ -244,6 +270,44 @@ void qrio_uprstreq(u8 mode) out_8(qrio_base + RSTCFG_OFF, rstcfg); } +/* Early bootcount memory area is avilable starting from QRIO3 Rev.2 */ +#define QRIO3_ID 0x71 +#define QRIO3_REV 0x02 +#define EBOOTCNT_OFF 0x28 + +ulong early_bootcount_load(void) +{ + void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE; + u16 id_rev = in_be16(qrio_base + ID_REV_OFF); + u8 id = (id_rev >> 8) & 0xff; + u8 rev = id_rev & 0xff; + u32 ebootcount = 0; + + if (id == QRIO3_ID && rev >= QRIO3_REV) { + ebootcount = in_be32(qrio_base + EBOOTCNT_OFF); + } else { + printf("QRIO: warning: early bootcount not supported, "); + printf("id = %u, rev = %u\n", id, rev); + } + + return ebootcount; +} + +void early_bootcount_store(ulong ebootcount) +{ + void __iomem *qrio_base = (void *)CONFIG_SYS_QRIO_BASE; + u16 id_rev = in_be16(qrio_base + ID_REV_OFF); + u8 id = (id_rev >> 8) & 0xff; + u8 rev = id_rev & 0xff; + + if (id == QRIO3_ID && rev >= QRIO3_REV) { + out_be32(qrio_base + EBOOTCNT_OFF, ebootcount); + } else { + printf("QRIO: warning: early bootcount not supported, "); + printf("id = %u, rev = %u\n", id, rev); + } +} + /* I2C deblocking uses the algorithm defined in board/keymile/common/common.c * 2 dedicated QRIO GPIOs externally pull the SCL and SDA lines * For I2C only the low state is activly driven and high state is pulled-up diff --git a/board/keymile/common/qrio.h b/board/keymile/common/qrio.h index 757bcbf2f3d..2b997d90590 100644 --- a/board/keymile/common/qrio.h +++ b/board/keymile/common/qrio.h @@ -12,6 +12,8 @@ #define QRIO_GPIO_B 0x60 void show_qrio(void); +bool qrio_get_selftest_pin(void); +bool qrio_get_pgy_pres_pin(void); int qrio_get_gpio(u8 port_off, u8 gpio_nr); void qrio_set_opendrain_gpio(u8 port_off, u8 gpio_nr, u8 val); void qrio_set_gpio(u8 port_off, u8 gpio_nr, bool value); |
