diff options
author | Rajan Vaja <rajan.vaja@xilinx.com> | 2020-04-24 13:58:04 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-04-28 15:46:54 +0200 |
commit | ae5c961da6483b413dcb36d8bf6a881ffd2fb33f (patch) | |
tree | 395146d6efb94eb9420663ced6772f10d8ca195a /drivers/firmware/xilinx | |
parent | 4f680b72ea07a3e161ce1167a97ee09b1369f7de (diff) |
firmware: xilinx: Add sysfs interface
Add firmware-ggs sysfs interface which provides read/write
interface to global storage registers.
Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Tejas Patel <tejas.patel@xilinx.com>
Signed-off-by: Jolly Shah <jolly.shah@xilinx.com>
Link: https://lore.kernel.org/r/1587761887-4279-23-git-send-email-jolly.shah@xilinx.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/firmware/xilinx')
-rw-r--r-- | drivers/firmware/xilinx/zynqmp.c | 167 |
1 files changed, 166 insertions, 1 deletions
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 3518456bf73d..2fe4f57c005a 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -2,7 +2,7 @@ /* * Xilinx Zynq MPSoC Firmware layer * - * Copyright (C) 2014-2018 Xilinx, Inc. + * Copyright (C) 2014-2020 Xilinx, Inc. * * Michal Simek <michal.simek@xilinx.com> * Davorin Mista <davorin.mista@aggios.com> @@ -875,6 +875,170 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out) } EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine); +static ssize_t ggs_show(struct device *device, + struct device_attribute *attr, + char *buf, + u32 reg) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + ret = zynqmp_pm_read_ggs(reg, ret_payload); + if (ret) + return ret; + + return sprintf(buf, "0x%x\n", ret_payload[1]); +} + +static ssize_t ggs_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count, + u32 reg) +{ + long value; + int ret; + + if (reg >= GSS_NUM_REGS) + return -EINVAL; + + ret = kstrtol(buf, 16, &value); + if (ret) { + count = -EFAULT; + goto err; + } + + ret = zynqmp_pm_write_ggs(reg, value); + if (ret) + count = -EFAULT; + +err: + return count; +} + +/* GGS register show functions */ +#define GGS0_SHOW(N) \ + ssize_t ggs##N##_show(struct device *device, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return ggs_show(device, attr, buf, N); \ + } + +static GGS0_SHOW(0); +static GGS0_SHOW(1); +static GGS0_SHOW(2); +static GGS0_SHOW(3); + +/* GGS register store function */ +#define GGS0_STORE(N) \ + ssize_t ggs##N##_store(struct device *device, \ + struct device_attribute *attr, \ + const char *buf, \ + size_t count) \ + { \ + return ggs_store(device, attr, buf, count, N); \ + } + +static GGS0_STORE(0); +static GGS0_STORE(1); +static GGS0_STORE(2); +static GGS0_STORE(3); + +static ssize_t pggs_show(struct device *device, + struct device_attribute *attr, + char *buf, + u32 reg) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + ret = zynqmp_pm_read_pggs(reg, ret_payload); + if (ret) + return ret; + + return sprintf(buf, "0x%x\n", ret_payload[1]); +} + +static ssize_t pggs_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count, + u32 reg) +{ + long value; + int ret; + + if (reg >= GSS_NUM_REGS) + return -EINVAL; + + ret = kstrtol(buf, 16, &value); + if (ret) { + count = -EFAULT; + goto err; + } + + ret = zynqmp_pm_write_pggs(reg, value); + if (ret) + count = -EFAULT; + +err: + return count; +} + +#define PGGS0_SHOW(N) \ + ssize_t pggs##N##_show(struct device *device, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return pggs_show(device, attr, buf, N); \ + } + +#define PGGS0_STORE(N) \ + ssize_t pggs##N##_store(struct device *device, \ + struct device_attribute *attr, \ + const char *buf, \ + size_t count) \ + { \ + return pggs_store(device, attr, buf, count, N); \ + } + +/* PGGS register show functions */ +static PGGS0_SHOW(0); +static PGGS0_SHOW(1); +static PGGS0_SHOW(2); +static PGGS0_SHOW(3); + +/* PGGS register store functions */ +static PGGS0_STORE(0); +static PGGS0_STORE(1); +static PGGS0_STORE(2); +static PGGS0_STORE(3); + +/* GGS register attributes */ +static DEVICE_ATTR_RW(ggs0); +static DEVICE_ATTR_RW(ggs1); +static DEVICE_ATTR_RW(ggs2); +static DEVICE_ATTR_RW(ggs3); + +/* PGGS register attributes */ +static DEVICE_ATTR_RW(pggs0); +static DEVICE_ATTR_RW(pggs1); +static DEVICE_ATTR_RW(pggs2); +static DEVICE_ATTR_RW(pggs3); + +static struct attribute *zynqmp_firmware_attrs[] = { + &dev_attr_ggs0.attr, + &dev_attr_ggs1.attr, + &dev_attr_ggs2.attr, + &dev_attr_ggs3.attr, + &dev_attr_pggs0.attr, + &dev_attr_pggs1.attr, + &dev_attr_pggs2.attr, + &dev_attr_pggs3.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(zynqmp_firmware); + static int zynqmp_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -952,6 +1116,7 @@ static struct platform_driver zynqmp_firmware_driver = { .driver = { .name = "zynqmp_firmware", .of_match_table = zynqmp_firmware_of_match, + .dev_groups = zynqmp_firmware_groups, }, .probe = zynqmp_firmware_probe, .remove = zynqmp_firmware_remove, |