summaryrefslogtreecommitdiff
path: root/board/keymile/common
diff options
context:
space:
mode:
Diffstat (limited to 'board/keymile/common')
-rw-r--r--board/keymile/common/common.c53
-rw-r--r--board/keymile/common/common.h4
-rw-r--r--board/keymile/common/qrio.c64
-rw-r--r--board/keymile/common/qrio.h2
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);