summaryrefslogtreecommitdiff
path: root/drivers/firmware/xilinx/zynqmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/xilinx/zynqmp.c')
-rw-r--r--drivers/firmware/xilinx/zynqmp.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index 0fa6cae4969d..7d8cb2ec6f8e 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -42,6 +42,16 @@ static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
static struct platform_device *em_dev;
/**
+ * struct zynqmp_devinfo - Structure for Zynqmp device instance
+ * @dev: Device Pointer
+ * @feature_conf_id: Feature conf id
+ */
+struct zynqmp_devinfo {
+ struct device *dev;
+ u32 feature_conf_id;
+};
+
+/**
* struct pm_api_feature_data - PM API Feature data
* @pm_api_id: PM API Id, used as key to index into hashmap
* @feature_status: status of PM API feature: valid, invalid
@@ -1451,6 +1461,78 @@ static DEVICE_ATTR_RW(pggs1);
static DEVICE_ATTR_RW(pggs2);
static DEVICE_ATTR_RW(pggs3);
+static ssize_t feature_config_id_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+ return sysfs_emit(buf, "%d\n", devinfo->feature_conf_id);
+}
+
+static ssize_t feature_config_id_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 config_id;
+ int ret;
+ struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+ if (!buf)
+ return -EINVAL;
+
+ ret = kstrtou32(buf, 10, &config_id);
+ if (ret)
+ return ret;
+
+ devinfo->feature_conf_id = config_id;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(feature_config_id);
+
+static ssize_t feature_config_value_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+ ret = zynqmp_pm_get_feature_config(devinfo->feature_conf_id,
+ ret_payload);
+ if (ret)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", ret_payload[1]);
+}
+
+static ssize_t feature_config_value_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 value;
+ int ret;
+ struct zynqmp_devinfo *devinfo = dev_get_drvdata(device);
+
+ if (!buf)
+ return -EINVAL;
+
+ ret = kstrtou32(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ ret = zynqmp_pm_set_feature_config(devinfo->feature_conf_id,
+ value);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(feature_config_value);
+
static struct attribute *zynqmp_firmware_attrs[] = {
&dev_attr_ggs0.attr,
&dev_attr_ggs1.attr,
@@ -1462,6 +1544,8 @@ static struct attribute *zynqmp_firmware_attrs[] = {
&dev_attr_pggs3.attr,
&dev_attr_shutdown_scope.attr,
&dev_attr_health_status.attr,
+ &dev_attr_feature_config_id.attr,
+ &dev_attr_feature_config_value.attr,
NULL,
};
@@ -1471,6 +1555,7 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np;
+ struct zynqmp_devinfo *devinfo;
int ret;
np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
@@ -1487,6 +1572,14 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
if (ret)
return ret;
+ devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL);
+ if (!devinfo)
+ return -ENOMEM;
+
+ devinfo->dev = dev;
+
+ platform_set_drvdata(pdev, devinfo);
+
/* Check PM API version number */
ret = zynqmp_pm_get_api_version(&pm_api_version);
if (ret)