diff options
author | Philipp Tomsich <philipp.tomsich@theobroma-systems.com> | 2018-11-27 23:00:18 +0100 |
---|---|---|
committer | Philipp Tomsich <philipp.tomsich@theobroma-systems.com> | 2018-12-10 10:04:44 +0100 |
commit | ebb73de1687cfd6449f492b54cc2f32b4b0ce9c5 (patch) | |
tree | 944b0df2343457620b370027c174a7541578351c /drivers/bootcount | |
parent | f338cca1d2bce906b049722d2fdbf527a4963b61 (diff) | |
download | u-boot-ebb73de1687cfd6449f492b54cc2f32b4b0ce9c5.tar.gz |
bootcount: add uclass for bootcount
The original bootcount methods do not provide an interface to DM and
rely on a static configuration for I2C devices (e.g. bus, chip-addr,
etc. are configured through defines statically). On a modern system
that exposes multiple devices in a DTS-configurable way, this is less
than optimal and a interface to DM-based devices will be desirable.
This adds a simple driver that is DM-aware and configurable via DTS.
If ambiguous (i.e. multiple bootcount-devices are present) the
/chosen/u-boot,bootcount-device property can be used to select one
bootcount device.
Initially, this provides support for the following DM devices:
* RTC devices
Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Tested-by: Klaus Goger <klaus.goger@theobroma-systems.com>
Diffstat (limited to 'drivers/bootcount')
-rw-r--r-- | drivers/bootcount/Kconfig | 8 | ||||
-rw-r--r-- | drivers/bootcount/Makefile | 2 | ||||
-rw-r--r-- | drivers/bootcount/bootcount-uclass.c | 93 |
3 files changed, 103 insertions, 0 deletions
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 67033637c0..46571eb322 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -70,6 +70,14 @@ 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 config BOOTCOUNT_BOOTLIMIT diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index 68bc006b75..81980b3cad 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -7,3 +7,5 @@ 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 diff --git a/drivers/bootcount/bootcount-uclass.c b/drivers/bootcount/bootcount-uclass.c new file mode 100644 index 0000000000..0689db7a5b --- /dev/null +++ b/drivers/bootcount/bootcount-uclass.c @@ -0,0 +1,93 @@ +// 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> + +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, +}; |