diff options
Diffstat (limited to 'roms/u-boot/drivers/bootcount')
-rw-r--r-- | roms/u-boot/drivers/bootcount/Kconfig | 193 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/Makefile | 15 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount-uclass.c | 94 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount.c | 144 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount_at91.c | 30 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount_davinci.c | 41 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount_env.c | 29 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount_ext.c | 83 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount_i2c.c | 43 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/bootcount_ram.c | 66 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/i2c-eeprom.c | 96 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/rtc.c | 90 | ||||
-rw-r--r-- | roms/u-boot/drivers/bootcount/spi-flash.c | 125 |
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, ®->kick0r); + writel(RTC_KICK1R_WE, ®->kick1r); + raw_bootcount_store(®->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(®->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, +}; |