* [PATCH 1/3] driver: add support for device aliases
2023-09-13 13:24 [PATCH 0/3] firmware-zynqmp: add accessors for ggs/pggs Ahmad Fatoum
@ 2023-09-13 13:24 ` Ahmad Fatoum
2023-09-13 13:24 ` [PATCH 2/3] firmware-zynqmp: export functions for setting GGS/PGGS Ahmad Fatoum
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2023-09-13 13:24 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Device names can get quite long, which makes them cumbersome to use
on the shell, e.g. firmware:zynqmp-firmware:clock-controller.of.
In addition, the names are prone to change when the device tree nodes
are renamed.
One way we work around this is using aliases, but that is partially at
odds with upstream binding. This commit adds an alternative way of
allowing drivers and board code to set an alias that affects only
device_param_complete.
This provides an easy way of defining device names that should be stable
for use in shell scripts.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/complete.c | 14 ++++++-------
drivers/base/driver.c | 46 +++++++++++++++++++++++++++++++++++++++++++
include/driver.h | 7 +++++++
3 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/common/complete.c b/common/complete.c
index e9f3f8ee033f..4137bb3084fc 100644
--- a/common/complete.c
+++ b/common/complete.c
@@ -154,8 +154,8 @@ int device_complete(struct string_list *sl, char *instr)
}
EXPORT_SYMBOL(device_complete);
-static int device_param_complete(struct device *dev, struct string_list *sl,
- char *instr, int eval)
+static int device_param_complete(struct device *dev, const char *devname,
+ struct string_list *sl, char *instr, int eval)
{
struct param_d *param;
int len;
@@ -167,7 +167,7 @@ static int device_param_complete(struct device *dev, struct string_list *sl,
continue;
string_list_add_asprintf(sl, "%s%s.%s%c",
- eval ? "$" : "", dev_name(dev), param->name,
+ eval ? "$" : "", devname, param->name,
eval ? ' ' : '=');
}
@@ -308,14 +308,12 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
char *devname;
devname = xstrndup(instr, dot - instr);
-
-
dev = get_device_by_name(devname);
- free(devname);
if (dev)
- device_param_complete(dev, sl, dot + 1, eval);
+ device_param_complete(dev, devname, sl, dot + 1, eval);
+ free(devname);
pos = dot + 1;
}
@@ -323,7 +321,7 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
for_each_device(dev) {
if (!strncmp(instr, dev_name(dev), len))
- device_param_complete(dev, sl, "", eval);
+ device_param_complete(dev, dev_name(dev), sl, "", eval);
}
return 0;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 10d765e1a213..5811c7a11b75 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -24,6 +24,7 @@
#include <fs.h>
#include <of.h>
#include <linux/list.h>
+#include <linux/overflow.h>
#include <linux/err.h>
#include <complete.h>
#include <pinctrl.h>
@@ -46,6 +47,8 @@ LIST_HEAD(active_device_list);
EXPORT_SYMBOL(active_device_list);
static LIST_HEAD(deferred);
+static LIST_HEAD(device_alias_list);
+
struct device *find_device(const char *str)
{
struct device *dev;
@@ -65,12 +68,18 @@ struct device *find_device(const char *str)
struct device *get_device_by_name(const char *name)
{
struct device *dev;
+ struct device_alias *alias;
for_each_device(dev) {
if(!strcmp(dev_name(dev), name))
return dev;
}
+ list_for_each_entry(alias, &device_alias_list, list) {
+ if(!strcmp(alias->name, name))
+ return alias->dev;
+ }
+
return NULL;
}
@@ -261,6 +270,7 @@ EXPORT_SYMBOL(register_device);
int unregister_device(struct device *old_dev)
{
+ struct device_alias *alias, *at;
struct cdev *cdev, *ct;
struct device *child, *dt;
@@ -271,6 +281,11 @@ int unregister_device(struct device *old_dev)
if (old_dev->driver)
old_dev->bus->remove(old_dev);
+ list_for_each_entry_safe(alias, at, &device_alias_list, list) {
+ if(alias->dev == old_dev)
+ list_del(&alias->list);
+ }
+
list_for_each_entry_safe(child, dt, &old_dev->children, sibling) {
dev_dbg(old_dev, "unregister child %s\n", dev_name(child));
unregister_device(child);
@@ -592,6 +607,37 @@ int dev_set_name(struct device *dev, const char *fmt, ...)
}
EXPORT_SYMBOL_GPL(dev_set_name);
+/**
+ * dev_add_alias - add alias for device
+ * @dev: device
+ * @fmt: format string for the device's alias
+ */
+int dev_add_alias(struct device *dev, const char *fmt, ...)
+{
+ va_list va, va_copy;
+ unsigned int len;
+ struct device_alias *alias;
+
+ va_start(va, fmt);
+ va_copy(va_copy, va);
+ len = vsnprintf(NULL, 0, fmt, va_copy);
+ va_end(va_copy);
+
+ alias = malloc(struct_size(alias, name, len + 1));
+ if (!alias)
+ return -ENOMEM;
+
+ vsnprintf(alias->name, len + 1, fmt, va);
+
+ va_end(va);
+
+ alias->dev = dev;
+ list_add_tail(&alias->list, &device_alias_list);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dev_set_alias);
+
static void devices_shutdown(void)
{
struct device *dev;
diff --git a/include/driver.h b/include/driver.h
index 2651cddecc21..a0234fb6c31b 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -101,6 +101,12 @@ struct device {
char *deferred_probe_reason;
};
+struct device_alias {
+ struct device *dev;
+ struct list_head list;
+ char name[];
+};
+
/** @brief Describes a driver present in the system */
struct driver {
/*! The name of this driver. Used to match to
@@ -216,6 +222,7 @@ static inline const char *dev_name(const struct device *dev)
}
int dev_set_name(struct device *dev, const char *fmt, ...);
+int dev_add_alias(struct device *dev, const char *fmt, ...);
/*
* get resource 'num' for a device
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/3] firmware-zynqmp: export functions for setting GGS/PGGS
2023-09-13 13:24 [PATCH 0/3] firmware-zynqmp: add accessors for ggs/pggs Ahmad Fatoum
2023-09-13 13:24 ` [PATCH 1/3] driver: add support for device aliases Ahmad Fatoum
@ 2023-09-13 13:24 ` Ahmad Fatoum
2023-09-13 13:24 ` [PATCH 3/3] firmware-zynqmp: add device parameters for ggs/pggs Ahmad Fatoum
2023-09-14 7:59 ` [PATCH 0/3] firmware-zynqmp: add accessors " Sascha Hauer
3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2023-09-13 13:24 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
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.
Import the Linux API used to read and write these registers.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/mach-zynqmp/firmware-zynqmp.c | 66 ++++++++++++++++++++++++++
include/mach/zynqmp/firmware-zynqmp.h | 33 +++++++++++--
2 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
index 128f042ddc4c..8d06c65b0ee0 100644
--- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
+++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
@@ -503,6 +503,72 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
arg1, arg2, out);
}
+/*
+ * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs)
+ * @index: GGS register index
+ * @value: Register value to be written
+ *
+ * This function writes value to GGS register.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_write_ggs(u32 index, u32 value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS,
+ index, value, NULL);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
+
+/**
+ * zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs)
+ * @index: GGS register index
+ * @value: Register value to be written
+ *
+ * This function returns GGS register value.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_read_ggs(u32 index, u32 *value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS,
+ index, 0, value);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
+
+/**
+ * zynqmp_pm_write_pggs() - PM API for writing persistent global general
+ * storage (pggs)
+ * @index: PGGS register index
+ * @value: Register value to be written
+ *
+ * This function writes value to PGGS register.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_write_pggs(u32 index, u32 value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value,
+ NULL);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
+
+/**
+ * zynqmp_pm_read_pggs() - PM API for reading persistent global general
+ * storage (pggs)
+ * @index: PGGS register index
+ * @value: Register value to be written
+ *
+ * This function returns PGGS register value.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_read_pggs(u32 index, u32 *value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0,
+ value);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
+
/**
* zynqmp_pm_fpga_load - Perform the fpga load
* @address: Address to write to
diff --git a/include/mach/zynqmp/firmware-zynqmp.h b/include/mach/zynqmp/firmware-zynqmp.h
index ddccfe3d6f9a..482a7ebf994f 100644
--- a/include/mach/zynqmp/firmware-zynqmp.h
+++ b/include/mach/zynqmp/firmware-zynqmp.h
@@ -74,10 +74,32 @@ struct fpgamgr {
};
enum pm_ioctl_id {
+ IOCTL_GET_RPU_OPER_MODE = 0,
+ IOCTL_SET_RPU_OPER_MODE = 1,
+ IOCTL_RPU_BOOT_ADDR_CONFIG = 2,
+ IOCTL_TCM_COMB_CONFIG = 3,
+ IOCTL_SET_TAPDELAY_BYPASS = 4,
+ IOCTL_SD_DLL_RESET = 6,
+ IOCTL_SET_SD_TAPDELAY = 7,
IOCTL_SET_PLL_FRAC_MODE = 8,
- IOCTL_GET_PLL_FRAC_MODE,
- IOCTL_SET_PLL_FRAC_DATA,
- IOCTL_GET_PLL_FRAC_DATA,
+ IOCTL_GET_PLL_FRAC_MODE = 9,
+ IOCTL_SET_PLL_FRAC_DATA = 10,
+ IOCTL_GET_PLL_FRAC_DATA = 11,
+ IOCTL_WRITE_GGS = 12,
+ IOCTL_READ_GGS = 13,
+ IOCTL_WRITE_PGGS = 14,
+ IOCTL_READ_PGGS = 15,
+ /* Set healthy bit value */
+ IOCTL_SET_BOOT_HEALTH_STATUS = 17,
+ IOCTL_OSPI_MUX_SELECT = 21,
+ /* Register SGI to ATF */
+ IOCTL_REGISTER_SGI = 25,
+ /* Runtime feature configuration */
+ IOCTL_SET_FEATURE_CONFIG = 26,
+ IOCTL_GET_FEATURE_CONFIG = 27,
+ /* Dynamic SD/GEM configuration */
+ IOCTL_SET_SD_CONFIG = 30,
+ IOCTL_SET_GEM_CONFIG = 31,
};
enum pm_query_id {
@@ -123,4 +145,9 @@ struct zynqmp_eemi_ops {
const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
+int zynqmp_pm_write_ggs(u32 index, u32 value);
+int zynqmp_pm_read_ggs(u32 index, u32 *value);
+int zynqmp_pm_write_pggs(u32 index, u32 value);
+int zynqmp_pm_read_pggs(u32 index, u32 *value);
+
#endif /* FIRMWARE_ZYNQMP_H_ */
--
2.39.2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/3] firmware-zynqmp: add device parameters for ggs/pggs
2023-09-13 13:24 [PATCH 0/3] firmware-zynqmp: add accessors for ggs/pggs Ahmad Fatoum
2023-09-13 13:24 ` [PATCH 1/3] driver: add support for device aliases Ahmad Fatoum
2023-09-13 13:24 ` [PATCH 2/3] firmware-zynqmp: export functions for setting GGS/PGGS Ahmad Fatoum
@ 2023-09-13 13:24 ` Ahmad Fatoum
2023-09-14 7:59 ` [PATCH 0/3] firmware-zynqmp: add accessors " Sascha Hauer
3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2023-09-13 13:24 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
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@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
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] firmware-zynqmp: add accessors for ggs/pggs
2023-09-13 13:24 [PATCH 0/3] firmware-zynqmp: add accessors for ggs/pggs Ahmad Fatoum
` (2 preceding siblings ...)
2023-09-13 13:24 ` [PATCH 3/3] firmware-zynqmp: add device parameters for ggs/pggs Ahmad Fatoum
@ 2023-09-14 7:59 ` Sascha Hauer
3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2023-09-14 7:59 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Wed, Sep 13, 2023 at 03:24:53PM +0200, Ahmad Fatoum wrote:
> 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 board code
> via exported functions and 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 device alias support added
> in this series to make the variables more compact:
>
> echo ${zynqmp_fw.ggs0}
> zynqmp_fw.pggs0=4
>
> Ahmad Fatoum (3):
> driver: add support for device aliases
> firmware-zynqmp: export functions for setting GGS/PGGS
> firmware-zynqmp: add device parameters for ggs/pggs
Applied, thanks
Sascha
>
> arch/arm/mach-zynqmp/firmware-zynqmp.c | 133 +++++++++++++++++++++++++
> common/complete.c | 14 ++-
> drivers/base/driver.c | 46 +++++++++
> include/driver.h | 7 ++
> include/mach/zynqmp/firmware-zynqmp.h | 33 +++++-
> 5 files changed, 222 insertions(+), 11 deletions(-)
>
> --
> 2.39.2
>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 5+ messages in thread