diff options
author | Wu Hao <hao.wu@intel.com> | 2019-08-12 10:49:59 +0800 |
---|---|---|
committer | Moritz Fischer <mdf@kernel.org> | 2019-09-03 19:35:41 -0700 |
commit | f09991adfb3454530598586424ece3082e95fb0b (patch) | |
tree | 98e9f076a9500aba434187ea513a6949baab2831 /drivers/fpga/dfl-afu-main.c | |
parent | a80a4b82e7d8cf71bf495bda92072d1397b790a1 (diff) | |
download | lwn-f09991adfb3454530598586424ece3082e95fb0b.tar.gz lwn-f09991adfb3454530598586424ece3082e95fb0b.zip |
fpga: dfl: afu: add userclock sysfs interfaces.
This patch introduces userclock sysfs interfaces for AFU, user
could use these interfaces for clock setting to AFU.
Please note that, this is only working for port header feature
with revision 0, for later revisions, userclock setting is moved
to a separated private feature, so one revision sysfs interface
is exposed to userspace application for this purpose too.
Signed-off-by: Ananda Ravuri <ananda.ravuri@intel.com>
Signed-off-by: Russ Weight <russell.h.weight@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@intel.com>
Signed-off-by: Wu Hao <hao.wu@intel.com>
Acked-by: Alan Tull <atull@kernel.org>
Signed-off-by: Moritz Fischer <mdf@kernel.org>
Diffstat (limited to 'drivers/fpga/dfl-afu-main.c')
-rw-r--r-- | drivers/fpga/dfl-afu-main.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index e955149722bd..f0b45f2d9750 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -274,17 +274,126 @@ power_state_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(power_state); +static ssize_t +userclk_freqcmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freq_cmd; + void __iomem *base; + + if (kstrtou64(buf, 0, &userclk_freq_cmd)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + writeq(userclk_freq_cmd, base + PORT_HDR_USRCLK_CMD0); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_WO(userclk_freqcmd); + +static ssize_t +userclk_freqcntrcmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freqcntr_cmd; + void __iomem *base; + + if (kstrtou64(buf, 0, &userclk_freqcntr_cmd)) + return -EINVAL; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + writeq(userclk_freqcntr_cmd, base + PORT_HDR_USRCLK_CMD1); + mutex_unlock(&pdata->lock); + + return count; +} +static DEVICE_ATTR_WO(userclk_freqcntrcmd); + +static ssize_t +userclk_freqsts_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freqsts; + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + userclk_freqsts = readq(base + PORT_HDR_USRCLK_STS0); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", (unsigned long long)userclk_freqsts); +} +static DEVICE_ATTR_RO(userclk_freqsts); + +static ssize_t +userclk_freqcntrsts_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dfl_feature_platform_data *pdata = dev_get_platdata(dev); + u64 userclk_freqcntrsts; + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + mutex_lock(&pdata->lock); + userclk_freqcntrsts = readq(base + PORT_HDR_USRCLK_STS1); + mutex_unlock(&pdata->lock); + + return sprintf(buf, "0x%llx\n", + (unsigned long long)userclk_freqcntrsts); +} +static DEVICE_ATTR_RO(userclk_freqcntrsts); + static struct attribute *port_hdr_attrs[] = { &dev_attr_id.attr, &dev_attr_ltr.attr, &dev_attr_ap1_event.attr, &dev_attr_ap2_event.attr, &dev_attr_power_state.attr, + &dev_attr_userclk_freqcmd.attr, + &dev_attr_userclk_freqcntrcmd.attr, + &dev_attr_userclk_freqsts.attr, + &dev_attr_userclk_freqcntrsts.attr, NULL, }; +static umode_t port_hdr_attrs_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + umode_t mode = attr->mode; + void __iomem *base; + + base = dfl_get_feature_ioaddr_by_id(dev, PORT_FEATURE_ID_HEADER); + + if (dfl_feature_revision(base) > 0) { + /* + * userclk sysfs interfaces are only visible in case port + * revision is 0, as hardware with revision >0 doesn't + * support this. + */ + if (attr == &dev_attr_userclk_freqcmd.attr || + attr == &dev_attr_userclk_freqcntrcmd.attr || + attr == &dev_attr_userclk_freqsts.attr || + attr == &dev_attr_userclk_freqcntrsts.attr) + mode = 0; + } + + return mode; +} + static const struct attribute_group port_hdr_group = { - .attrs = port_hdr_attrs, + .attrs = port_hdr_attrs, + .is_visible = port_hdr_attrs_visible, }; static int port_hdr_init(struct platform_device *pdev, |