diff options
-rw-r--r-- | drivers/bootcount/Kconfig | 10 | ||||
-rw-r--r-- | drivers/bootcount/Makefile | 1 | ||||
-rw-r--r-- | drivers/bootcount/i2c-eeprom.c | 95 |
3 files changed, 106 insertions, 0 deletions
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index b7c29f2fd3..0e506c9ea2 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -96,6 +96,16 @@ config DM_BOOTCOUNT_RTC 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. + endmenu endif diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index f9841d8615..73ccfb5a08 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -10,3 +10,4 @@ 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 diff --git a/drivers/bootcount/i2c-eeprom.c b/drivers/bootcount/i2c-eeprom.c new file mode 100644 index 0000000000..ee760a2742 --- /dev/null +++ b/drivers/bootcount/i2c-eeprom.c @@ -0,0 +1,95 @@ +// 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> + +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_alloc_size = sizeof(struct bootcount_i2c_eeprom_priv), + .probe = bootcount_i2c_eeprom_probe, + .of_match = bootcount_i2c_eeprom_ids, + .ops = &bootcount_i2c_eeprom_ops, +}; |