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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxx>
---
 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





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux