aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/bootcount
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/bootcount')
-rw-r--r--roms/u-boot/drivers/bootcount/Kconfig193
-rw-r--r--roms/u-boot/drivers/bootcount/Makefile15
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount-uclass.c94
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount.c144
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount_at91.c30
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount_davinci.c41
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount_env.c29
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount_ext.c83
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount_i2c.c43
-rw-r--r--roms/u-boot/drivers/bootcount/bootcount_ram.c66
-rw-r--r--roms/u-boot/drivers/bootcount/i2c-eeprom.c96
-rw-r--r--roms/u-boot/drivers/bootcount/rtc.c90
-rw-r--r--roms/u-boot/drivers/bootcount/spi-flash.c125
13 files changed, 1049 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/bootcount/Kconfig b/roms/u-boot/drivers/bootcount/Kconfig
new file mode 100644
index 000000000..b5ccea0d9
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/Kconfig
@@ -0,0 +1,193 @@
+#
+# Boot count configuration
+#
+
+menuconfig BOOTCOUNT_LIMIT
+ bool "Enable support for checking boot count limit"
+ help
+ Enable checking for exceeding the boot count limit.
+ More information: http://www.denx.de/wiki/DULG/UBootBootCountLimit
+
+if BOOTCOUNT_LIMIT
+
+choice
+ prompt "Boot count device"
+ default BOOTCOUNT_AM33XX if AM33XX || SOC_DA8XX
+ default BOOTCOUNT_AT91 if AT91SAM9XE
+ default BOOTCOUNT_GENERIC
+
+config BOOTCOUNT_GENERIC
+ bool "Generic default boot counter"
+ help
+ Generic bootcount stored at SYS_BOOTCOUNT_ADDR.
+
+ SYS_BOOTCOUNT_ADDR:
+ Set to the address where the bootcount and bootcount magic
+ will be stored.
+
+config BOOTCOUNT_EXT
+ bool "Boot counter on EXT filesystem"
+ depends on FS_EXT4
+ select EXT4_WRITE
+ help
+ Add support for maintaining boot count in a file on an EXT
+ filesystem.
+
+config BOOTCOUNT_AM33XX
+ bool "Boot counter in AM33XX RTC IP block"
+ depends on AM33XX || SOC_DA8XX
+ select SPL_AM33XX_ENABLE_RTC32K_OSC if AM33XX
+ help
+ A bootcount driver for the RTC IP block found on many TI platforms.
+ This requires the RTC clocks, etc, to be enabled prior to use and
+ not all boards with this IP block on it will have the RTC in use.
+
+config BOOTCOUNT_ENV
+ bool "Boot counter in environment"
+ help
+ If no softreset save registers are found on the hardware
+ "bootcount" is stored in the environment. To prevent a
+ saveenv on all reboots, the environment variable
+ "upgrade_available" is used. If "upgrade_available" is
+ 0, "bootcount" is always 0, if "upgrade_available" is
+ 1 "bootcount" is incremented in the environment.
+ So the Userspace Application must set the "upgrade_available"
+ and "bootcount" variable to 0, if a boot was successfully.
+
+config BOOTCOUNT_RAM
+ bool "Boot counter in RAM"
+ help
+ Store the bootcount in DRAM protected against against bit errors
+ due to short power loss or holding a system in RESET.
+
+config BOOTCOUNT_I2C
+ bool "Boot counter on I2C device"
+ help
+ Enable support for the bootcounter on an i2c (like RTC) device.
+ CONFIG_SYS_I2C_RTC_ADDR = i2c chip address
+ CONFIG_SYS_BOOTCOUNT_ADDR = i2c addr which is used for
+ the bootcounter.
+
+config BOOTCOUNT_AT91
+ bool "Boot counter for Atmel AT91SAM9XE"
+ depends on AT91SAM9XE
+
+config DM_BOOTCOUNT
+ bool "Boot counter in a device-model device"
+ help
+ Enables reading/writing the bootcount in a device-model based
+ backing store. If an entry in /chosen/u-boot,bootcount-device
+ exists, this will be the preferred bootcount device; otherwise
+ the first available bootcount device will be used.
+
+endchoice
+
+if DM_BOOTCOUNT
+
+menu "Backing stores for device-model backed bootcount"
+config DM_BOOTCOUNT_RTC
+ bool "Support RTC devices as a backing store for bootcount"
+ depends on DM_RTC
+ help
+ Enabled reading/writing the bootcount in a DM RTC device.
+ The wrapper device is to be specified with the compatible string
+ 'u-boot,bootcount-rtc' and the 'rtc'-property (a phandle pointing
+ to the underlying RTC device) and an optional 'offset' property
+ are supported.
+
+ Accesses to the backing store are performed using the write16
+ and read16 ops of DM RTC devices.
+
+config DM_BOOTCOUNT_I2C_EEPROM
+ bool "Support i2c eeprom devices as a backing store for bootcount"
+ depends on I2C_EEPROM
+ help
+ Enabled reading/writing the bootcount in a DM i2c eeprom device.
+ The wrapper device is to be specified with the compatible string
+ 'u-boot,bootcount-i2c-eeprom' and the 'i2c-eeprom'-property (a phandle
+ pointing to the underlying i2c eeprom device) and an optional 'offset'
+ property are supported.
+
+config DM_BOOTCOUNT_SPI_FLASH
+ bool "Support SPI flash devices as a backing store for bootcount"
+ depends on DM_SPI_FLASH
+ help
+ Enabled reading/writing the bootcount in a DM SPI flash device.
+ The wrapper device is to be specified with the compatible string
+ 'u-boot,bootcount-spi-flash' and the 'spi-flash'-property (a phandle
+ pointing to the underlying SPI flash device) and an optional 'offset'
+ property are supported.
+
+config BOOTCOUNT_MEM
+ bool "Support memory based bootcounter"
+ help
+ Enabling Memory based bootcount, typically in a SoC register which
+ is not cleared on softreset.
+ compatible = "u-boot,bootcount";
+
+endmenu
+
+endif
+
+config BOOTCOUNT_BOOTLIMIT
+ int "Maximum number of reboot cycles allowed"
+ default 0
+ help
+ Set the Maximum number of reboot cycles allowed without the boot
+ counter being cleared.
+ If set to 0 do not set a boot limit in the environment.
+
+config BOOTCOUNT_ALEN
+ int "I2C address length"
+ default 1
+ depends on BOOTCOUNT_I2C
+ help
+ Length of the the I2C address at SYS_BOOTCOUNT_ADDR for storing
+ the boot counter.
+
+config SYS_BOOTCOUNT_SINGLEWORD
+ bool "Use single word to pack boot count and magic value"
+ depends on BOOTCOUNT_GENERIC
+ help
+ This option enables packing boot count magic value and boot count
+ into single word (32 bits).
+
+config SYS_BOOTCOUNT_EXT_INTERFACE
+ string "Interface on which to find boot counter EXT filesystem"
+ default "mmc"
+ depends on BOOTCOUNT_EXT
+ help
+ Set the interface to use when locating the filesystem to use for the
+ boot counter.
+
+config SYS_BOOTCOUNT_EXT_DEVPART
+ string "Partition of the boot counter EXT filesystem"
+ default "0:1"
+ depends on BOOTCOUNT_EXT
+ help
+ Set the partition to use when locating the filesystem to use for the
+ boot counter.
+
+config SYS_BOOTCOUNT_EXT_NAME
+ string "Path and filename of the EXT filesystem based boot counter"
+ default "/boot/failures"
+ depends on BOOTCOUNT_EXT
+ help
+ Set the filename and path of the file used to store the boot counter.
+
+config SYS_BOOTCOUNT_ADDR
+ hex "RAM address used for reading and writing the boot counter"
+ default 0x44E3E000 if BOOTCOUNT_AM33XX
+ default 0xE0115FF8 if ARCH_LS1043A || ARCH_LS1021A
+ depends on BOOTCOUNT_AM33XX || BOOTCOUNT_GENERIC || BOOTCOUNT_EXT || \
+ BOOTCOUNT_I2C
+ help
+ Set the address used for reading and writing the boot counter.
+
+config SYS_BOOTCOUNT_MAGIC
+ hex "Magic value for the boot counter"
+ default 0xB001C041
+ help
+ Set the magic value used for the boot counter.
+
+endif
diff --git a/roms/u-boot/drivers/bootcount/Makefile b/roms/u-boot/drivers/bootcount/Makefile
new file mode 100644
index 000000000..51d860b00
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_BOOTCOUNT_GENERIC) += bootcount.o
+obj-$(CONFIG_BOOTCOUNT_MEM) += bootcount.o
+obj-$(CONFIG_BOOTCOUNT_AT91) += bootcount_at91.o
+obj-$(CONFIG_BOOTCOUNT_AM33XX) += bootcount_davinci.o
+obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o
+obj-$(CONFIG_BOOTCOUNT_ENV) += bootcount_env.o
+obj-$(CONFIG_BOOTCOUNT_I2C) += bootcount_i2c.o
+obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o
+
+obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o
+obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o
+obj-$(CONFIG_DM_BOOTCOUNT_I2C_EEPROM) += i2c-eeprom.o
+obj-$(CONFIG_DM_BOOTCOUNT_SPI_FLASH) += spi-flash.o
diff --git a/roms/u-boot/drivers/bootcount/bootcount-uclass.c b/roms/u-boot/drivers/bootcount/bootcount-uclass.c
new file mode 100644
index 000000000..34ac08d59
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount-uclass.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <bootcount.h>
+#include <log.h>
+
+int dm_bootcount_get(struct udevice *dev, u32 *bootcount)
+{
+ struct bootcount_ops *ops = bootcount_get_ops(dev);
+
+ assert(ops);
+ if (!ops->get)
+ return -ENOSYS;
+ return ops->get(dev, bootcount);
+}
+
+int dm_bootcount_set(struct udevice *dev, const u32 bootcount)
+{
+ struct bootcount_ops *ops = bootcount_get_ops(dev);
+
+ assert(ops);
+ if (!ops->set)
+ return -ENOSYS;
+ return ops->set(dev, bootcount);
+}
+
+/* Now implement the generic default functions */
+void bootcount_store(ulong val)
+{
+ struct udevice *dev = NULL;
+ ofnode node;
+ const char *propname = "u-boot,bootcount-device";
+ int ret = -ENODEV;
+
+ /*
+ * If there's a preferred bootcount device selected by the user (by
+ * setting '/chosen/u-boot,bootcount-device' in the DTS), try to use
+ * it if available.
+ */
+ node = ofnode_get_chosen_node(propname);
+ if (ofnode_valid(node))
+ ret = uclass_get_device_by_ofnode(UCLASS_BOOTCOUNT, node, &dev);
+
+ /* If there was no user-selected device, use the first available one */
+ if (ret)
+ ret = uclass_get_device(UCLASS_BOOTCOUNT, 0, &dev);
+
+ if (dev)
+ ret = dm_bootcount_set(dev, val);
+
+ if (ret)
+ pr_debug("%s: failed to store 0x%lx\n", __func__, val);
+}
+
+ulong bootcount_load(void)
+{
+ struct udevice *dev = NULL;
+ ofnode node;
+ const char *propname = "u-boot,bootcount-device";
+ int ret = -ENODEV;
+ u32 val;
+
+ /*
+ * If there's a preferred bootcount device selected by the user (by
+ * setting '/chosen/u-boot,bootcount-device' in the DTS), try to use
+ * it if available.
+ */
+ node = ofnode_get_chosen_node(propname);
+ if (ofnode_valid(node))
+ ret = uclass_get_device_by_ofnode(UCLASS_BOOTCOUNT, node, &dev);
+
+ /* If there was no user-selected device, use the first available one */
+ if (ret)
+ ret = uclass_get_device(UCLASS_BOOTCOUNT, 0, &dev);
+
+ if (dev)
+ ret = dm_bootcount_get(dev, &val);
+
+ if (ret)
+ pr_debug("%s: failed to load bootcount\n", __func__);
+
+ /* Return the 0, if the call to dm_bootcount_get failed */
+ return ret ? 0 : val;
+}
+
+UCLASS_DRIVER(bootcount) = {
+ .name = "bootcount",
+ .id = UCLASS_BOOTCOUNT,
+};
diff --git a/roms/u-boot/drivers/bootcount/bootcount.c b/roms/u-boot/drivers/bootcount/bootcount.c
new file mode 100644
index 000000000..343b8a344
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010-2012
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ */
+
+#include <bootcount.h>
+#include <cpu_func.h>
+#include <asm/cache.h>
+#include <linux/compiler.h>
+
+#if !defined(CONFIG_DM_BOOTCOUNT)
+/* Now implement the generic default functions */
+__weak void bootcount_store(ulong a)
+{
+ void *reg = (void *)CONFIG_SYS_BOOTCOUNT_ADDR;
+ uintptr_t flush_start = rounddown(CONFIG_SYS_BOOTCOUNT_ADDR,
+ CONFIG_SYS_CACHELINE_SIZE);
+ uintptr_t flush_end;
+
+#if defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD)
+ raw_bootcount_store(reg, (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000) | a);
+
+ flush_end = roundup(CONFIG_SYS_BOOTCOUNT_ADDR + 4,
+ CONFIG_SYS_CACHELINE_SIZE);
+#else
+ raw_bootcount_store(reg, a);
+ raw_bootcount_store(reg + 4, CONFIG_SYS_BOOTCOUNT_MAGIC);
+
+ flush_end = roundup(CONFIG_SYS_BOOTCOUNT_ADDR + 8,
+ CONFIG_SYS_CACHELINE_SIZE);
+#endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD */
+ flush_dcache_range(flush_start, flush_end);
+}
+
+__weak ulong bootcount_load(void)
+{
+ void *reg = (void *)CONFIG_SYS_BOOTCOUNT_ADDR;
+
+#if defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD)
+ u32 tmp = raw_bootcount_load(reg);
+
+ if ((tmp & 0xffff0000) != (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000))
+ return 0;
+ else
+ return (tmp & 0x0000ffff);
+#else
+ if (raw_bootcount_load(reg + 4) != CONFIG_SYS_BOOTCOUNT_MAGIC)
+ return 0;
+ else
+ return raw_bootcount_load(reg);
+#endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) */
+}
+#else
+#include <dm.h>
+
+/*
+ * struct bootcount_mem_priv - private bootcount mem driver data
+ *
+ * @base: base address used for bootcounter
+ * @singleword: if true use only one 32 bit word for bootcounter
+ */
+struct bootcount_mem_priv {
+ phys_addr_t base;
+ bool singleword;
+};
+
+static int bootcount_mem_get(struct udevice *dev, u32 *a)
+{
+ struct bootcount_mem_priv *priv = dev_get_priv(dev);
+ void *reg = (void *)priv->base;
+ u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
+
+ if (priv->singleword) {
+ u32 tmp = raw_bootcount_load(reg);
+
+ if ((tmp & 0xffff0000) != (magic & 0xffff0000))
+ return -ENODEV;
+
+ *a = (tmp & 0x0000ffff);
+ } else {
+ if (raw_bootcount_load(reg + 4) != magic)
+ return -ENODEV;
+
+ *a = raw_bootcount_load(reg);
+ }
+
+ return 0;
+};
+
+static int bootcount_mem_set(struct udevice *dev, const u32 a)
+{
+ struct bootcount_mem_priv *priv = dev_get_priv(dev);
+ void *reg = (void *)priv->base;
+ u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
+ uintptr_t flush_start = rounddown(priv->base,
+ CONFIG_SYS_CACHELINE_SIZE);
+ uintptr_t flush_end;
+
+ if (priv->singleword) {
+ raw_bootcount_store(reg, (magic & 0xffff0000) | a);
+ flush_end = roundup(priv->base + 4,
+ CONFIG_SYS_CACHELINE_SIZE);
+ } else {
+ raw_bootcount_store(reg, a);
+ raw_bootcount_store(reg + 4, magic);
+ flush_end = roundup(priv->base + 8,
+ CONFIG_SYS_CACHELINE_SIZE);
+ }
+ flush_dcache_range(flush_start, flush_end);
+
+ return 0;
+};
+
+static const struct bootcount_ops bootcount_mem_ops = {
+ .get = bootcount_mem_get,
+ .set = bootcount_mem_set,
+};
+
+static int bootcount_mem_probe(struct udevice *dev)
+{
+ struct bootcount_mem_priv *priv = dev_get_priv(dev);
+
+ priv->base = (phys_addr_t)dev_read_addr(dev);
+ if (dev_read_bool(dev, "single-word"))
+ priv->singleword = true;
+
+ return 0;
+}
+
+static const struct udevice_id bootcount_mem_ids[] = {
+ { .compatible = "u-boot,bootcount" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_mem) = {
+ .name = "bootcount-mem",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_mem_priv),
+ .probe = bootcount_mem_probe,
+ .of_match = bootcount_mem_ids,
+ .ops = &bootcount_mem_ops,
+};
+#endif
diff --git a/roms/u-boot/drivers/bootcount/bootcount_at91.c b/roms/u-boot/drivers/bootcount/bootcount_at91.c
new file mode 100644
index 000000000..c4ab5ceaf
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount_at91.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_gpbr.h>
+
+/*
+ * We combine the CONFIG_SYS_BOOTCOUNT_MAGIC and bootcount in one 32-bit
+ * register. This is done so we need to use only one of the four GPBR
+ * registers.
+ */
+void bootcount_store(ulong a)
+{
+ at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
+
+ writel((CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000) | (a & 0x0000ffff),
+ &gpbr->reg[AT91_GPBR_INDEX_BOOTCOUNT]);
+}
+
+ulong bootcount_load(void)
+{
+ at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
+
+ ulong val = readl(&gpbr->reg[AT91_GPBR_INDEX_BOOTCOUNT]);
+ if ((val & 0xffff0000) != (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000))
+ return 0;
+ else
+ return val & 0x0000ffff;
+}
diff --git a/roms/u-boot/drivers/bootcount/bootcount_davinci.c b/roms/u-boot/drivers/bootcount/bootcount_davinci.c
new file mode 100644
index 000000000..6326957d7
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount_davinci.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * A bootcount driver for the RTC IP block found on many TI platforms.
+ * This requires the RTC clocks, etc, to be enabled prior to use and
+ * not all boards with this IP block on it will have the RTC in use.
+ */
+
+#include <bootcount.h>
+#include <asm/davinci_rtc.h>
+
+void bootcount_store(ulong a)
+{
+ struct davinci_rtc *reg =
+ (struct davinci_rtc *)CONFIG_SYS_BOOTCOUNT_ADDR;
+
+ /*
+ * write RTC kick registers to enable write
+ * for RTC Scratch registers. Scratch register 2 is
+ * used for bootcount value.
+ */
+ writel(RTC_KICK0R_WE, &reg->kick0r);
+ writel(RTC_KICK1R_WE, &reg->kick1r);
+ raw_bootcount_store(&reg->scratch2,
+ (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000) | (a & 0x0000ffff));
+}
+
+ulong bootcount_load(void)
+{
+ unsigned long val;
+ struct davinci_rtc *reg =
+ (struct davinci_rtc *)CONFIG_SYS_BOOTCOUNT_ADDR;
+
+ val = raw_bootcount_load(&reg->scratch2);
+ if ((val & 0xffff0000) != (CONFIG_SYS_BOOTCOUNT_MAGIC & 0xffff0000))
+ return 0;
+ else
+ return val & 0x0000ffff;
+}
diff --git a/roms/u-boot/drivers/bootcount/bootcount_env.c b/roms/u-boot/drivers/bootcount/bootcount_env.c
new file mode 100644
index 000000000..b75c9002b
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount_env.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2013
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ */
+
+#include <common.h>
+#include <env.h>
+
+void bootcount_store(ulong a)
+{
+ int upgrade_available = env_get_ulong("upgrade_available", 10, 0);
+
+ if (upgrade_available) {
+ env_set_ulong("bootcount", a);
+ env_save();
+ }
+}
+
+ulong bootcount_load(void)
+{
+ int upgrade_available = env_get_ulong("upgrade_available", 10, 0);
+ ulong val = 0;
+
+ if (upgrade_available)
+ val = env_get_ulong("bootcount", 10, 0);
+
+ return val;
+}
diff --git a/roms/u-boot/drivers/bootcount/bootcount_ext.c b/roms/u-boot/drivers/bootcount/bootcount_ext.c
new file mode 100644
index 000000000..9639e638e
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount_ext.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 General Electric Company. All rights reserved.
+ */
+
+#include <bootcount.h>
+#include <fs.h>
+#include <mapmem.h>
+
+#define BC_MAGIC 0xbd
+#define BC_VERSION 1
+
+typedef struct {
+ u8 magic;
+ u8 version;
+ u8 bootcount;
+ u8 upgrade_available;
+} bootcount_ext_t;
+
+static u8 upgrade_available = 1;
+
+void bootcount_store(ulong a)
+{
+ bootcount_ext_t *buf;
+ loff_t len;
+ int ret;
+
+ if (fs_set_blk_dev(CONFIG_SYS_BOOTCOUNT_EXT_INTERFACE,
+ CONFIG_SYS_BOOTCOUNT_EXT_DEVPART, FS_TYPE_EXT)) {
+ puts("Error selecting device\n");
+ return;
+ }
+
+ /* Only update bootcount during upgrade process */
+ if (!upgrade_available)
+ return;
+
+ buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, sizeof(bootcount_ext_t));
+ buf->magic = BC_MAGIC;
+ buf->version = BC_VERSION;
+ buf->bootcount = (a & 0xff);
+ buf->upgrade_available = upgrade_available;
+ unmap_sysmem(buf);
+
+ ret = fs_write(CONFIG_SYS_BOOTCOUNT_EXT_NAME,
+ CONFIG_SYS_BOOTCOUNT_ADDR, 0, sizeof(bootcount_ext_t),
+ &len);
+ if (ret != 0)
+ puts("Error storing bootcount\n");
+}
+
+ulong bootcount_load(void)
+{
+ bootcount_ext_t *buf;
+ loff_t len_read;
+ int ret;
+
+ if (fs_set_blk_dev(CONFIG_SYS_BOOTCOUNT_EXT_INTERFACE,
+ CONFIG_SYS_BOOTCOUNT_EXT_DEVPART, FS_TYPE_EXT)) {
+ puts("Error selecting device\n");
+ return 0;
+ }
+
+ ret = fs_read(CONFIG_SYS_BOOTCOUNT_EXT_NAME, CONFIG_SYS_BOOTCOUNT_ADDR,
+ 0, sizeof(bootcount_ext_t), &len_read);
+ if (ret != 0 || len_read != sizeof(bootcount_ext_t)) {
+ puts("Error loading bootcount\n");
+ return 0;
+ }
+
+ buf = map_sysmem(CONFIG_SYS_BOOTCOUNT_ADDR, sizeof(bootcount_ext_t));
+ if (buf->magic == BC_MAGIC && buf->version == BC_VERSION) {
+ upgrade_available = buf->upgrade_available;
+ if (upgrade_available)
+ ret = buf->bootcount;
+ } else {
+ puts("Incorrect bootcount file\n");
+ }
+
+ unmap_sysmem(buf);
+
+ return ret;
+}
diff --git a/roms/u-boot/drivers/bootcount/bootcount_i2c.c b/roms/u-boot/drivers/bootcount/bootcount_i2c.c
new file mode 100644
index 000000000..496741d63
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount_i2c.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2013
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ */
+
+#include <bootcount.h>
+#include <linux/compiler.h>
+#include <i2c.h>
+
+#define BC_MAGIC 0xbc
+
+void bootcount_store(ulong a)
+{
+ unsigned char buf[3];
+ int ret;
+
+ buf[0] = BC_MAGIC;
+ buf[1] = (a & 0xff);
+ ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR,
+ CONFIG_BOOTCOUNT_ALEN, buf, 2);
+ if (ret != 0)
+ puts("Error writing bootcount\n");
+}
+
+ulong bootcount_load(void)
+{
+ unsigned char buf[3];
+ int ret;
+
+ ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, CONFIG_SYS_BOOTCOUNT_ADDR,
+ CONFIG_BOOTCOUNT_ALEN, buf, 2);
+ if (ret != 0) {
+ puts("Error loading bootcount\n");
+ return 0;
+ }
+ if (buf[0] == BC_MAGIC)
+ return buf[1];
+
+ bootcount_store(0);
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/bootcount/bootcount_ram.c b/roms/u-boot/drivers/bootcount/bootcount_ram.c
new file mode 100644
index 000000000..8cc30cf40
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/bootcount_ram.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2010
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ */
+
+#include <common.h>
+#include <cpu_func.h>
+#include <asm/cache.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+const ulong patterns[] = { 0x00000000,
+ 0xFFFFFFFF,
+ 0xFF00FF00,
+ 0x0F0F0F0F,
+ 0xF0F0F0F0};
+const ulong NBR_OF_PATTERNS = sizeof(patterns) / sizeof(*patterns);
+const ulong OFFS_PATTERN = 3;
+const ulong REPEAT_PATTERN = 1000;
+
+void bootcount_store(ulong a)
+{
+ ulong *save_addr;
+ ulong size = 0;
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
+ size += gd->bd->bi_dram[i].size;
+ save_addr = (ulong *)(size - BOOTCOUNT_ADDR);
+ writel(a, save_addr);
+ writel(CONFIG_SYS_BOOTCOUNT_MAGIC, &save_addr[1]);
+
+ for (i = 0; i < REPEAT_PATTERN; i++)
+ writel(patterns[i % NBR_OF_PATTERNS],
+ &save_addr[i + OFFS_PATTERN]);
+
+ /* Make sure the data is written to RAM */
+ flush_dcache_range((ulong)&save_addr[0],
+ (((ulong)&save_addr[REPEAT_PATTERN + OFFS_PATTERN] &
+ ~(ARCH_DMA_MINALIGN - 1)) + ARCH_DMA_MINALIGN));
+}
+
+ulong bootcount_load(void)
+{
+ ulong *save_addr;
+ ulong size = 0;
+ ulong counter = 0;
+ int i, tmp;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
+ size += gd->bd->bi_dram[i].size;
+ save_addr = (ulong *)(size - BOOTCOUNT_ADDR);
+
+ counter = readl(&save_addr[0]);
+
+ /* Is the counter reliable, check in the big pattern for bit errors */
+ for (i = 0; (i < REPEAT_PATTERN) && (counter != 0); i++) {
+ tmp = readl(&save_addr[i + OFFS_PATTERN]);
+ if (tmp != patterns[i % NBR_OF_PATTERNS])
+ counter = 0;
+ }
+ return counter;
+}
diff --git a/roms/u-boot/drivers/bootcount/i2c-eeprom.c b/roms/u-boot/drivers/bootcount/i2c-eeprom.c
new file mode 100644
index 000000000..709be094b
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/i2c-eeprom.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Collabora
+ * (C) Copyright 2019 GE
+ */
+
+#include <common.h>
+#include <bootcount.h>
+#include <dm.h>
+#include <i2c_eeprom.h>
+#include <log.h>
+
+static const u8 bootcount_magic = 0xbc;
+
+struct bootcount_i2c_eeprom_priv {
+ struct udevice *i2c_eeprom;
+ u32 offset;
+};
+
+static int bootcount_i2c_eeprom_set(struct udevice *dev, const u32 a)
+{
+ struct bootcount_i2c_eeprom_priv *priv = dev_get_priv(dev);
+ const u16 val = bootcount_magic << 8 | (a & 0xff);
+
+ if (i2c_eeprom_write(priv->i2c_eeprom, priv->offset,
+ (uint8_t *)&val, 2) < 0) {
+ debug("%s: write failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int bootcount_i2c_eeprom_get(struct udevice *dev, u32 *a)
+{
+ struct bootcount_i2c_eeprom_priv *priv = dev_get_priv(dev);
+ u16 val;
+
+ if (i2c_eeprom_read(priv->i2c_eeprom, priv->offset,
+ (uint8_t *)&val, 2) < 0) {
+ debug("%s: read failed\n", __func__);
+ return -EIO;
+ }
+
+ if (val >> 8 == bootcount_magic) {
+ *a = val & 0xff;
+ return 0;
+ }
+
+ debug("%s: bootcount magic does not match on %04x\n", __func__, val);
+ return -EIO;
+}
+
+static int bootcount_i2c_eeprom_probe(struct udevice *dev)
+{
+ struct ofnode_phandle_args phandle_args;
+ struct bootcount_i2c_eeprom_priv *priv = dev_get_priv(dev);
+ struct udevice *i2c_eeprom;
+
+ if (dev_read_phandle_with_args(dev, "i2c-eeprom", NULL, 0, 0,
+ &phandle_args)) {
+ debug("%s: i2c-eeprom backing device not specified\n",
+ dev->name);
+ return -ENOENT;
+ }
+
+ if (uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, phandle_args.node,
+ &i2c_eeprom)) {
+ debug("%s: could not get backing device\n", dev->name);
+ return -ENODEV;
+ }
+
+ priv->i2c_eeprom = i2c_eeprom;
+ priv->offset = dev_read_u32_default(dev, "offset", 0);
+
+ return 0;
+}
+
+static const struct bootcount_ops bootcount_i2c_eeprom_ops = {
+ .get = bootcount_i2c_eeprom_get,
+ .set = bootcount_i2c_eeprom_set,
+};
+
+static const struct udevice_id bootcount_i2c_eeprom_ids[] = {
+ { .compatible = "u-boot,bootcount-i2c-eeprom" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_spi_flash) = {
+ .name = "bootcount-i2c-eeprom",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_i2c_eeprom_priv),
+ .probe = bootcount_i2c_eeprom_probe,
+ .of_match = bootcount_i2c_eeprom_ids,
+ .ops = &bootcount_i2c_eeprom_ops,
+};
diff --git a/roms/u-boot/drivers/bootcount/rtc.c b/roms/u-boot/drivers/bootcount/rtc.c
new file mode 100644
index 000000000..483caaa80
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/rtc.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <bootcount.h>
+#include <dm.h>
+#include <log.h>
+#include <rtc.h>
+
+static const u8 bootcount_magic = 0xbc;
+
+struct bootcount_rtc_priv {
+ struct udevice *rtc;
+ u32 offset;
+};
+
+static int bootcount_rtc_set(struct udevice *dev, const u32 a)
+{
+ struct bootcount_rtc_priv *priv = dev_get_priv(dev);
+ const u16 val = bootcount_magic << 8 | (a & 0xff);
+
+ if (rtc_write16(priv->rtc, priv->offset, val) < 0) {
+ debug("%s: rtc_write16 failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int bootcount_rtc_get(struct udevice *dev, u32 *a)
+{
+ struct bootcount_rtc_priv *priv = dev_get_priv(dev);
+ u16 val;
+
+ if (rtc_read16(priv->rtc, priv->offset, &val) < 0) {
+ debug("%s: rtc_write16 failed\n", __func__);
+ return -EIO;
+ }
+
+ if (val >> 8 == bootcount_magic) {
+ *a = val & 0xff;
+ return 0;
+ }
+
+ debug("%s: bootcount magic does not match on %04x\n", __func__, val);
+ return -EIO;
+}
+
+static int bootcount_rtc_probe(struct udevice *dev)
+{
+ struct ofnode_phandle_args phandle_args;
+ struct bootcount_rtc_priv *priv = dev_get_priv(dev);
+ struct udevice *rtc;
+
+ if (dev_read_phandle_with_args(dev, "rtc", NULL, 0, 0, &phandle_args)) {
+ debug("%s: rtc backing device not specified\n", dev->name);
+ return -ENOENT;
+ }
+
+ if (uclass_get_device_by_ofnode(UCLASS_RTC, phandle_args.node, &rtc)) {
+ debug("%s: could not get backing device\n", dev->name);
+ return -ENODEV;
+ }
+
+ priv->rtc = rtc;
+ priv->offset = dev_read_u32_default(dev, "offset", 0);
+
+ return 0;
+}
+
+static const struct bootcount_ops bootcount_rtc_ops = {
+ .get = bootcount_rtc_get,
+ .set = bootcount_rtc_set,
+};
+
+static const struct udevice_id bootcount_rtc_ids[] = {
+ { .compatible = "u-boot,bootcount-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_rtc) = {
+ .name = "bootcount-rtc",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_rtc_priv),
+ .probe = bootcount_rtc_probe,
+ .of_match = bootcount_rtc_ids,
+ .ops = &bootcount_rtc_ops,
+};
diff --git a/roms/u-boot/drivers/bootcount/spi-flash.c b/roms/u-boot/drivers/bootcount/spi-flash.c
new file mode 100644
index 000000000..03050e666
--- /dev/null
+++ b/roms/u-boot/drivers/bootcount/spi-flash.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019 Collabora
+ * (C) Copyright 2019 GE
+ */
+
+#include <common.h>
+#include <bootcount.h>
+#include <dm.h>
+#include <spi_flash.h>
+
+static const u8 bootcount_magic = 0xbc;
+
+struct bootcount_spi_flash_priv {
+ struct udevice *spi_flash;
+ u32 offset;
+};
+
+static int bootcount_spi_flash_update(struct udevice *dev, u32 offset, u32 len, const void *buf)
+{
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
+ u32 sector_size = flash->sector_size;
+ u32 sector_offset = offset % sector_size;
+ u32 sector = offset - sector_offset;
+ int err = 0;
+
+ /* code only supports updating a single sector */
+ if (sector_offset + len > sector_size)
+ return -ENOSYS;
+
+ u8 *buffer = malloc(sector_size);
+ if (!buffer)
+ return -ENOMEM;
+
+ err = spi_flash_read_dm(dev, sector, sector_size, buffer);
+ if (err < 0)
+ goto out;
+
+ memcpy(buffer + sector_offset, buf, len);
+
+ err = spi_flash_erase_dm(dev, sector, sector_size);
+ if (err < 0)
+ goto out;
+
+ err = spi_flash_write_dm(dev, sector, sector_size, buffer);
+ if (err < 0)
+ goto out;
+
+out:
+ free(buffer);
+ return err;
+}
+
+static int bootcount_spi_flash_set(struct udevice *dev, const u32 a)
+{
+ struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
+ const u16 val = bootcount_magic << 8 | (a & 0xff);
+
+ if (bootcount_spi_flash_update(priv->spi_flash, priv->offset, 2, &val) < 0) {
+ debug("%s: write failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int bootcount_spi_flash_get(struct udevice *dev, u32 *a)
+{
+ struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
+ u16 val;
+
+ if (spi_flash_read_dm(priv->spi_flash, priv->offset, 2, &val) < 0) {
+ debug("%s: read failed\n", __func__);
+ return -EIO;
+ }
+
+ if (val >> 8 == bootcount_magic) {
+ *a = val & 0xff;
+ return 0;
+ }
+
+ debug("%s: bootcount magic does not match on %04x\n", __func__, val);
+ return -EIO;
+}
+
+static int bootcount_spi_flash_probe(struct udevice *dev)
+{
+ struct ofnode_phandle_args phandle_args;
+ struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
+ struct udevice *spi_flash;
+
+ if (dev_read_phandle_with_args(dev, "spi-flash", NULL, 0, 0, &phandle_args)) {
+ debug("%s: spi-flash backing device not specified\n", dev->name);
+ return -ENOENT;
+ }
+
+ if (uclass_get_device_by_ofnode(UCLASS_SPI_FLASH, phandle_args.node, &spi_flash)) {
+ debug("%s: could not get backing device\n", dev->name);
+ return -ENODEV;
+ }
+
+ priv->spi_flash = spi_flash;
+ priv->offset = dev_read_u32_default(dev, "offset", 0);
+
+ return 0;
+}
+
+static const struct bootcount_ops bootcount_spi_flash_ops = {
+ .get = bootcount_spi_flash_get,
+ .set = bootcount_spi_flash_set,
+};
+
+static const struct udevice_id bootcount_spi_flash_ids[] = {
+ { .compatible = "u-boot,bootcount-spi-flash" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_spi_flash) = {
+ .name = "bootcount-spi-flash",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto = sizeof(struct bootcount_spi_flash_priv),
+ .probe = bootcount_spi_flash_probe,
+ .of_match = bootcount_spi_flash_ids,
+ .ops = &bootcount_spi_flash_ops,
+};