[PATCH] bootcount: zynqmp: Extend ZynqMP specific bootcount support
Marek Vasut
marex at denx.de
Thu Jan 30 02:37:19 CET 2025
The PGGS area contains four registers, each of which can hold up to
32bit of data. Extend the boot counter to support storing boot count
in either of the four registers with arbitrary mask to avoid limiting
the boot counter only to the PGGS register 2 LSByte.
Drop U_BOOT_DRVINFO() as that would instantiate the boot counter even
if there is no DT node associated with it, that is undesired behavior.
The boot counter configuration is implemented using three new DT properties:
reg - PGGS register address, fallback to PGGS 2 at 0xffd80058
u-boot,bootcount-reg-mask - Register mask, applied on PGGS register
u-boot,bootcount-mask - Boot counter mask, applied on boot counter
u-boot,bootcount-magic - Boot counter magic, applied on boot counter
Example configuration of 16bit boot counter with 0xb0010000 magic in PGGS0:
&amba {
bootcount at 0xffd80050 {
compatible = "u-boot,bootcount-zynqmp";
reg = <0 0xffd80050 0 0x4>;
u-boot,bootcount-magic = <0xb0010000>;
u-boot,bootcount-mask = <0xffff>;
u-boot,bootcount-reg-mask = <0xffffffff>;
};
};
Signed-off-by: Marek Vasut <marex at denx.de>
---
Cc: Heiko Schocher <hs at denx.de>
Cc: Michal Simek <michal.simek at amd.com>
Cc: Tom Rini <trini at konsulko.com>
Cc: Vasileios Amoiridis <vasileios.amoiridis at cern.ch>
Cc: u-boot at lists.denx.de
---
drivers/bootcount/bootcount_zynqmp.c | 79 +++++++++++++++++++++++++---
1 file changed, 71 insertions(+), 8 deletions(-)
diff --git a/drivers/bootcount/bootcount_zynqmp.c b/drivers/bootcount/bootcount_zynqmp.c
index bc0984e2d26..6613b80caec 100644
--- a/drivers/bootcount/bootcount_zynqmp.c
+++ b/drivers/bootcount/bootcount_zynqmp.c
@@ -3,16 +3,32 @@
#include <bootcount.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <stdio.h>
#include <zynqmp_firmware.h>
#include <asm/arch/hardware.h>
#include <dm/platdata.h>
+struct bootcount_zynqmp_priv {
+ void __iomem *reg; /* PGGS register to use for boot counter */
+ u32 regmask; /* Mask over the valid register bits */
+ u32 mask; /* Mask over the valid boot counter bits */
+ u32 magic; /* Magic to place in the rest of the register */
+};
+
static int bootcount_zynqmp_set(struct udevice *dev, const u32 val)
{
+ struct bootcount_zynqmp_priv *priv = dev_get_priv(dev);
+ u32 rwval = val;
int ret;
- ret = zynqmp_mmio_write((ulong)&pmu_base->pers_gen_storage2, 0xFF, val);
+ /* Apply magic to detect whether the boot counter is valid. */
+ rwval &= priv->mask; /* Clear all non-bootcounter bits */
+ rwval |= priv->magic; /* Apply magic value */
+
+ rwval &= priv->regmask; /* Apply register mask */
+
+ ret = zynqmp_mmio_write((ulong)priv->reg, priv->regmask, rwval);
if (ret)
pr_info("%s write fail\n", __func__);
@@ -21,27 +37,74 @@ static int bootcount_zynqmp_set(struct udevice *dev, const u32 val)
static int bootcount_zynqmp_get(struct udevice *dev, u32 *val)
{
+ struct bootcount_zynqmp_priv *priv = dev_get_priv(dev);
int ret;
*val = 0;
- ret = zynqmp_mmio_read((ulong)&pmu_base->pers_gen_storage2, val);
- if (ret)
+ ret = zynqmp_mmio_read((ulong)priv->reg, val);
+ if (ret) {
pr_info("%s read fail\n", __func__);
+ return ret;
+ }
- return ret;
-}
+ /* Clear out unrelated register content. */
+ *val &= priv->regmask;
-U_BOOT_DRVINFO(bootcount_zynqmp) = {
- .name = "bootcount_zynqmp",
-};
+ /* Check whether magic is valid, if not, boot counter value is 0. */
+ if ((*val & ~priv->mask) != priv->magic)
+ *val = 0;
+
+ /* Remove magic from boot counter value. */
+ *val &= priv->mask;
+
+ return 0;
+}
static const struct bootcount_ops bootcount_zynqmp_ops = {
.get = bootcount_zynqmp_get,
.set = bootcount_zynqmp_set,
};
+static int bootcount_zynqmp_probe(struct udevice *dev)
+{
+ struct bootcount_zynqmp_priv *priv = dev_get_priv(dev);
+
+ /*
+ * ZynqMP PGGS register to use for boot counter,
+ * default to PGGS2 to maintain backward compatibility.
+ */
+ priv->reg = dev_read_addr_ptr(dev);
+ if (!priv->reg)
+ priv->reg = &pmu_base->pers_gen_storage2;
+
+ /*
+ * Boot counter mask and register mask, default to 0x000000ff
+ * to maintain backward compatibility.
+ */
+ priv->mask = dev_read_u32_default(dev, "u-boot,bootcount-mask", 0xff);
+ priv->regmask = dev_read_u32_default(dev, "u-boot,bootcount-reg-mask",
+ priv->mask);
+
+ /*
+ * Boot counter magic, default to 0x00000000
+ * to maintain backward compatibility.
+ */
+ priv->magic = dev_read_u32_default(dev, "u-boot,bootcount-magic", 0);
+ priv->magic &= ~priv->mask;
+
+ return 0;
+}
+
+static const struct udevice_id bootcount_zynqmp_ids[] = {
+ { .compatible = "u-boot,bootcount-zynqmp" },
+ { }
+};
+
U_BOOT_DRIVER(bootcount_zynqmp) = {
.name = "bootcount_zynqmp",
.id = UCLASS_BOOTCOUNT,
.ops = &bootcount_zynqmp_ops,
+ .probe = bootcount_zynqmp_probe,
+ .of_match = bootcount_zynqmp_ids,
+ .priv_auto = sizeof(struct bootcount_zynqmp_priv),
};
--
2.45.2
More information about the U-Boot
mailing list