diff options
-rw-r--r-- | drivers/bootcount/Kconfig | 20 | ||||
-rw-r--r-- | drivers/bootcount/Makefile | 1 | ||||
-rw-r--r-- | drivers/bootcount/rtc.c | 89 |
3 files changed, 110 insertions, 0 deletions
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 46571eb322..b7c29f2fd3 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -80,6 +80,26 @@ config DM_BOOTCOUNT 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. + +endmenu + +endif + config BOOTCOUNT_BOOTLIMIT int "Maximum number of reboot cycles allowed" default 0 diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index 81980b3cad..f9841d8615 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -9,3 +9,4 @@ 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 diff --git a/drivers/bootcount/rtc.c b/drivers/bootcount/rtc.c new file mode 100644 index 0000000000..db89fa3a35 --- /dev/null +++ b/drivers/bootcount/rtc.c @@ -0,0 +1,89 @@ +// 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 <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_alloc_size = sizeof(struct bootcount_rtc_priv), + .probe = bootcount_rtc_probe, + .of_match = bootcount_rtc_ids, + .ops = &bootcount_rtc_ops, +}; |