|
@@ -8,6 +8,7 @@
|
|
|
#include <cpu_func.h>
|
|
|
#include <linux/compiler.h>
|
|
|
|
|
|
+#if !defined(CONFIG_DM_BOOTCOUNT)
|
|
|
/* Now implement the generic default functions */
|
|
|
__weak void bootcount_store(ulong a)
|
|
|
{
|
|
@@ -49,3 +50,94 @@ __weak ulong bootcount_load(void)
|
|
|
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_alloc_size = sizeof(struct bootcount_mem_priv),
|
|
|
+ .probe = bootcount_mem_probe,
|
|
|
+ .of_match = bootcount_mem_ids,
|
|
|
+ .ops = &bootcount_mem_ops,
|
|
|
+};
|
|
|
+#endif
|