[PATCH 3/3] firmware-zynqmp: add device parameters for ggs/pggs

Ahmad Fatoum a.fatoum at pengutronix.de
Wed Sep 13 06:24:56 PDT 2023


The ZynqMP features eight 32-bit global storage registers that are
available for general use. Four of them have their values preserved
after software reboots and four are cleared on software reboots.

In Linux they are accessed as:

  /sys/firmware/zynqmp/ggs[0-4]
  /sys/firmware/zynqmp/pggs[0-4]

Allow reading and writing these parameters from barebox shell as well
via device parameters:

  echo ${firmware:zynqmp-firmware.of.ggs0}
  firmware:zynqmp-firmware.of.pggs0=4

Because the name is a bit unwieldy, use the recently added device alias
support to make the variables more compact:

  echo ${zynqmp_fw.ggs0}
  zynqmp_fw.pggs0=4

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/mach-zynqmp/firmware-zynqmp.c | 67 ++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
index 8d06c65b0ee0..a2b61efff413 100644
--- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
+++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
@@ -14,10 +14,18 @@
 
 #include <common.h>
 #include <init.h>
+#include <driver.h>
+#include <param.h>
 #include <linux/arm-smccc.h>
 
 #include <mach/zynqmp/firmware-zynqmp.h>
 
+struct zynqmp_fw {
+	struct device *dev;
+	u32 ggs[4];
+	u32 pggs[4];
+};
+
 #define ZYNQMP_TZ_VERSION(MAJOR, MINOR)	((MAJOR << 16) | MINOR)
 
 #define ZYNQMP_PM_VERSION_MAJOR		1
@@ -642,11 +650,58 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
 
+static bool parse_reg(const char *reg, unsigned *idx)
+{
+	bool pggs = reg[0] == 'p';
+	kstrtouint(reg + pggs + sizeof("ggs") - 1, 10, idx);
+	return pggs;
+}
+
+static int ggs_set(struct param_d *p, void *_val)
+{
+	u32 *val = _val;
+	unsigned idx;
+
+	if (parse_reg(p->name, &idx))
+		return zynqmp_pm_write_pggs(idx, *val);
+	else
+		return zynqmp_pm_write_ggs(idx, *val);
+}
+static int ggs_get(struct param_d *p, void *_val)
+{
+	u32 ret_payload[PAYLOAD_ARG_CNT];
+	u32 *val = _val;
+	unsigned idx;
+	int ret;
+
+	if (parse_reg(p->name, &idx))
+		ret = zynqmp_pm_read_pggs(idx, ret_payload);
+	else
+		ret = zynqmp_pm_read_ggs(idx, ret_payload);
+
+	if (ret)
+		return ret;
+
+	*val = ret_payload[1];
+
+	return 0;
+}
+
+static inline void dev_add_param_ggs(struct zynqmp_fw *fw, const char *str, u32 *value)
+{
+	dev_add_param_uint32(fw->dev, str, ggs_set, ggs_get, value, "0x%x", value);
+}
 
 static int zynqmp_firmware_probe(struct device *dev)
 {
+
+	struct zynqmp_fw *fw;
 	int ret;
 
+	fw = xzalloc(sizeof(*fw));
+
+	dev_add_alias(dev, "zynqmp_fw");
+
 	ret = get_set_conduit_method(dev->of_node);
 	if (ret)
 		goto out;
@@ -686,6 +741,18 @@ static int zynqmp_firmware_probe(struct device *dev)
 			pm_tz_version >> 16, pm_tz_version & 0xFFFF);
 
 	of_platform_populate(dev->of_node, NULL, dev);
+
+	fw->dev = dev;
+
+	dev_add_param_ggs(fw, "ggs0", &fw->ggs[0]);
+	dev_add_param_ggs(fw, "ggs1", &fw->ggs[1]);
+	dev_add_param_ggs(fw, "ggs2", &fw->ggs[2]);
+	dev_add_param_ggs(fw, "ggs3", &fw->ggs[3]);
+
+	dev_add_param_ggs(fw, "pggs0", &fw->pggs[0]);
+	dev_add_param_ggs(fw, "pggs1", &fw->pggs[1]);
+	dev_add_param_ggs(fw, "pggs2", &fw->pggs[2]);
+	dev_add_param_ggs(fw, "pggs3", &fw->pggs[3]);
 out:
 	if (ret)
 		do_fw_call = do_fw_call_fail;
-- 
2.39.2




More information about the barebox mailing list