From: Souradeep Chowdhury <schowdhu@codeaurora.org>
To: Andy Gross <agross@kernel.org>,
Bjorn Andersson <bjorn.andersson@linaro.org>,
Rob Herring <robh+dt@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
devicetree@vger.kernel.org,
Rajendra Nayak <rnayak@codeaurora.org>,
Sibi Sankar <sibis@codeaurora.org>,
Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>,
Souradeep Chowdhury <schowdhu@codeaurora.org>
Subject: [PATCH V0 4/6] soc: qcom: dcc:Add the sysfs variables to the Data Capture and Compare driver(DCC)
Date: Wed, 17 Feb 2021 12:18:25 +0530 [thread overview]
Message-ID: <0b478cfd38cc01e43f4af3445b070327fa907db5.1613541226.git.schowdhu@codeaurora.org> (raw)
In-Reply-To: <cover.1613541226.git.schowdhu@codeaurora.org>
In-Reply-To: <cover.1613541226.git.schowdhu@codeaurora.org>
Added the sysfs variables to expose the user space functionalities
like DCC enable,disable,configure addresses and software triggers.
Also added the necessary methods along with the same.
Signed-off-by: Souradeep Chowdhury <schowdhu@codeaurora.org>
---
drivers/soc/qcom/dcc.c | 519 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 519 insertions(+)
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index d67452b..02eee96 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -185,6 +185,82 @@ static int dcc_sram_writel(struct dcc_drvdata *drvdata,
return 0;
}
+static bool dcc_ready(struct dcc_drvdata *drvdata)
+{
+ u32 val;
+
+ /* poll until DCC ready */
+ if (!readl_poll_timeout((drvdata->base + DCC_STATUS), val,
+ (BMVAL(val, 0, 1) == 0), 1, TIMEOUT_US))
+ return true;
+
+ return false;
+}
+
+static int dcc_read_status(struct dcc_drvdata *drvdata)
+{
+ int curr_list;
+ u32 bus_status;
+ u32 ll_cfg = 0;
+ u32 tmp_ll_cfg = 0;
+
+ for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
+ if (!drvdata->enable[curr_list])
+ continue;
+
+ bus_status = dcc_readl(drvdata, DCC_LL_BUS_ACCESS_STATUS(curr_list));
+
+ if (bus_status) {
+ dev_err(drvdata->dev,
+ "Read access error for list %d err: 0x%x.\n",
+ curr_list, bus_status);
+
+ ll_cfg = dcc_readl(drvdata, DCC_LL_CFG(curr_list));
+ tmp_ll_cfg = ll_cfg & ~BIT(9);
+ dcc_writel(drvdata, tmp_ll_cfg, DCC_LL_CFG(curr_list));
+ dcc_writel(drvdata, 0x3,
+ DCC_LL_BUS_ACCESS_STATUS(curr_list));
+ dcc_writel(drvdata, ll_cfg, DCC_LL_CFG(curr_list));
+ return -ENODATA;
+ }
+ }
+
+ return 0;
+}
+
+static int dcc_sw_trigger(struct dcc_drvdata *drvdata)
+{
+ int ret = 0;
+ int curr_list;
+ u32 ll_cfg = 0;
+ u32 tmp_ll_cfg = 0;
+
+ mutex_lock(&drvdata->mutex);
+
+ for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
+ if (!drvdata->enable[curr_list])
+ continue;
+ ll_cfg = dcc_readl(drvdata, DCC_LL_CFG(curr_list));
+ tmp_ll_cfg = ll_cfg & ~BIT(9);
+ dcc_writel(drvdata, tmp_ll_cfg, DCC_LL_CFG(curr_list));
+ dcc_writel(drvdata, 1, DCC_LL_SW_TRIGGER(curr_list));
+ dcc_writel(drvdata, ll_cfg, DCC_LL_CFG(curr_list));
+ }
+
+ if (!dcc_ready(drvdata)) {
+ dev_err(drvdata->dev,
+ "DCC is busy after receiving sw tigger.\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ ret = dcc_read_status(drvdata);
+
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
static int _dcc_ll_cfg_read_write(struct dcc_drvdata *drvdata,
struct dcc_config_entry *entry, struct dcc_cfg_attr *cfg)
{
@@ -628,6 +704,211 @@ static int dcc_enable(struct dcc_drvdata *drvdata)
return ret;
}
+static void dcc_disable(struct dcc_drvdata *drvdata)
+{
+ int curr_list;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (!dcc_ready(drvdata))
+ dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n");
+
+ for (curr_list = 0; curr_list < drvdata->nr_link_list; curr_list++) {
+ if (!drvdata->enable[curr_list])
+ continue;
+ dcc_writel(drvdata, 0, DCC_LL_CFG(curr_list));
+ dcc_writel(drvdata, 0, DCC_LL_BASE(curr_list));
+ dcc_writel(drvdata, 0, DCC_FD_BASE(curr_list));
+ dcc_writel(drvdata, 0, DCC_LL_LOCK(curr_list));
+ drvdata->enable[curr_list] = false;
+ }
+ memset_io(drvdata->ram_base, 0, drvdata->ram_size);
+ drvdata->ram_cfg = 0;
+ drvdata->ram_start = 0;
+ mutex_unlock(&drvdata->mutex);
+}
+
+static ssize_t curr_list_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ mutex_lock(&drvdata->mutex);
+ if (drvdata->curr_list == DCC_INVALID_LINK_LIST) {
+ dev_err(dev, "curr_list is not set.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = scnprintf(buf, PAGE_SIZE, "%d\n", drvdata->curr_list);
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static ssize_t curr_list_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+ unsigned long val;
+ u32 lock_reg;
+ bool dcc_enable = false;
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ if (val >= drvdata->nr_link_list)
+ return -EINVAL;
+
+ mutex_lock(&drvdata->mutex);
+
+ dcc_enable = is_dcc_enabled(drvdata);
+ if (drvdata->curr_list != DCC_INVALID_LINK_LIST && dcc_enable) {
+ dev_err(drvdata->dev, "DCC is enabled, please disable it first.\n");
+ mutex_unlock(&drvdata->mutex);
+ return -EINVAL;
+ }
+
+ lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val));
+ if (lock_reg & 0x1) {
+ dev_err(drvdata->dev, "DCC linked list is already configured\n");
+ mutex_unlock(&drvdata->mutex);
+ return -EINVAL;
+ }
+ drvdata->curr_list = val;
+ mutex_unlock(&drvdata->mutex);
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(curr_list);
+
+
+static ssize_t trigger_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = 0;
+ unsigned long val;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+ if (val != 1)
+ return -EINVAL;
+
+ ret = dcc_sw_trigger(drvdata);
+ if (!ret)
+ ret = size;
+
+ return ret;
+}
+static DEVICE_ATTR_WO(trigger);
+
+static ssize_t enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ bool dcc_enable = false;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ mutex_lock(&drvdata->mutex);
+ if (drvdata->curr_list >= drvdata->nr_link_list) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dcc_enable = is_dcc_enabled(drvdata);
+
+ ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+ (unsigned int)dcc_enable);
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static ssize_t enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = 0;
+ unsigned long val;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ if (val)
+ ret = dcc_enable(drvdata);
+ else
+ dcc_disable(drvdata);
+
+ if (!ret)
+ ret = size;
+
+ return ret;
+
+}
+
+static DEVICE_ATTR_RW(enable);
+
+static ssize_t config_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+ struct dcc_config_entry *entry;
+ char local_buf[64];
+ int len = 0, count = 0;
+
+ buf[0] = '\0';
+
+ mutex_lock(&drvdata->mutex);
+ if (drvdata->curr_list >= drvdata->nr_link_list) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ count = -EINVAL;
+ goto err;
+ }
+
+ list_for_each_entry(entry,
+ &drvdata->cfg_head[drvdata->curr_list], list) {
+ switch (entry->desc_type) {
+ case DCC_READ_WRITE_TYPE:
+ len = snprintf(local_buf, 64, "Index: 0x%x, mask: 0x%x, val: 0x%x\n",
+ entry->index, entry->mask, entry->write_val);
+ break;
+ case DCC_LOOP_TYPE:
+ len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n",
+ entry->index, entry->loop_cnt);
+ break;
+ case DCC_WRITE_TYPE:
+ len = snprintf(local_buf, 64,
+ "Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+ entry->index, entry->base, entry->offset, entry->len,
+ entry->apb_bus);
+ break;
+ default:
+ len = snprintf(local_buf, 64,
+ "Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+ entry->index, entry->base, entry->offset,
+ entry->len, entry->apb_bus);
+ }
+
+ if ((count + len) > PAGE_SIZE) {
+ dev_err(dev, "DCC: Couldn't write complete config\n");
+ break;
+ }
+ strlcat(buf, local_buf, PAGE_SIZE);
+ count += len;
+ }
+
+err:
+ mutex_unlock(&drvdata->mutex);
+ return count;
+}
+
static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
unsigned int len, int apb_bus)
{
@@ -709,6 +990,38 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
return ret;
}
+static ssize_t config_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret, len, apb_bus;
+ unsigned int base;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+ int nval;
+
+ nval = sscanf(buf, "%x %i %d", &base, &len, &apb_bus);
+ if (nval <= 0 || nval > 3)
+ return -EINVAL;
+
+ if (nval == 1) {
+ len = 1;
+ apb_bus = 0;
+ } else if (nval == 2) {
+ apb_bus = 0;
+ } else {
+ apb_bus = 1;
+ }
+
+ ret = dcc_config_add(drvdata, base, len, apb_bus);
+ if (ret)
+ return ret;
+
+ return size;
+
+}
+
+static DEVICE_ATTR_RW(config);
+
static void dcc_config_reset(struct dcc_drvdata *drvdata)
{
struct dcc_config_entry *entry, *temp;
@@ -730,6 +1043,80 @@ static void dcc_config_reset(struct dcc_drvdata *drvdata)
mutex_unlock(&drvdata->mutex);
}
+static ssize_t config_reset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long val;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ if (val)
+ dcc_config_reset(drvdata);
+
+ return size;
+}
+
+static DEVICE_ATTR_WO(config_reset);
+
+static ssize_t ready_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ mutex_lock(&drvdata->mutex);
+
+ if (drvdata->curr_list >= drvdata->nr_link_list) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!drvdata->enable[drvdata->curr_list]) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = scnprintf(buf, PAGE_SIZE, "%u\n",
+ (unsigned int)BVAL(dcc_readl(drvdata, DCC_STATUS), 1));
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR_RO(ready);
+
+static ssize_t interrupt_disable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ (unsigned int)drvdata->interrupt_disable);
+}
+
+static ssize_t interrupt_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long val;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ if (kstrtoul(buf, 16, &val))
+ return -EINVAL;
+
+ mutex_lock(&drvdata->mutex);
+ drvdata->interrupt_disable = (val ? 1:0);
+ mutex_unlock(&drvdata->mutex);
+ return size;
+}
+
+static DEVICE_ATTR_RW(interrupt_disable);
+
static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt)
{
struct dcc_config_entry *entry;
@@ -747,6 +1134,40 @@ static int dcc_add_loop(struct dcc_drvdata *drvdata, unsigned long loop_cnt)
return 0;
}
+static ssize_t loop_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ unsigned long loop_cnt;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ mutex_lock(&drvdata->mutex);
+
+ if (kstrtoul(buf, 16, &loop_cnt)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (drvdata->curr_list >= drvdata->nr_link_list) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = dcc_add_loop(drvdata, loop_cnt);
+ if (ret)
+ goto err;
+
+ mutex_unlock(&drvdata->mutex);
+ return size;
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR_WO(loop);
+
static int dcc_rd_mod_wr_add(struct dcc_drvdata *drvdata, unsigned int mask,
unsigned int val)
{
@@ -784,6 +1205,30 @@ static int dcc_rd_mod_wr_add(struct dcc_drvdata *drvdata, unsigned int mask,
return ret;
}
+static ssize_t rd_mod_wr_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ int nval;
+ unsigned int mask, val;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ nval = sscanf(buf, "%x %x", &mask, &val);
+
+ if (nval <= 1 || nval > 2)
+ return -EINVAL;
+
+ ret = dcc_rd_mod_wr_add(drvdata, mask, val);
+ if (ret)
+ return ret;
+
+ return size;
+
+}
+
+static DEVICE_ATTR_WO(rd_mod_wr);
+
static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr,
unsigned int write_val, int apb_bus)
{
@@ -806,6 +1251,77 @@ static int dcc_add_write(struct dcc_drvdata *drvdata, unsigned int addr,
return 0;
}
+static ssize_t config_write_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret;
+ int nval;
+ unsigned int addr, write_val;
+ int apb_bus = 0;
+ struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+
+ mutex_lock(&drvdata->mutex);
+
+ nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
+
+ if (nval <= 1 || nval > 3) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (drvdata->curr_list >= drvdata->nr_link_list) {
+ dev_err(dev, "Select link list to program using curr_list\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (nval == 3 && apb_bus != 0)
+ apb_bus = 1;
+
+ ret = dcc_add_write(drvdata, addr, write_val, apb_bus);
+ if (ret)
+ goto err;
+
+ mutex_unlock(&drvdata->mutex);
+ return size;
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR_WO(config_write);
+
+static const struct device_attribute *dcc_attrs[] = {
+ &dev_attr_trigger,
+ &dev_attr_enable,
+ &dev_attr_config,
+ &dev_attr_config_reset,
+ &dev_attr_ready,
+ &dev_attr_interrupt_disable,
+ &dev_attr_loop,
+ &dev_attr_rd_mod_wr,
+ &dev_attr_curr_list,
+ &dev_attr_config_write,
+ NULL,
+};
+
+static int dcc_create_files(struct device *dev,
+ const struct device_attribute **attrs)
+{
+ int ret = 0, i;
+
+ for (i = 0; attrs[i] != NULL; i++) {
+ ret = device_create_file(dev, attrs[i]);
+ if (ret) {
+ dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n",
+ attrs[i]->attr.name);
+ break;
+ }
+ }
+ return ret;
+}
+
static int dcc_sram_open(struct inode *inode, struct file *file)
{
struct dcc_drvdata *drvdata = container_of(inode->i_cdev,
@@ -1018,6 +1534,9 @@ static int dcc_probe(struct platform_device *pdev)
ret = dcc_sram_dev_init(drvdata);
if (ret)
goto err;
+ ret = dcc_create_files(dev, dcc_attrs);
+ if (ret)
+ goto err;
return ret;
err:
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
next prev parent reply other threads:[~2021-02-17 6:50 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-17 6:48 [PATCH V0 0/6] Add driver support for Data Capture and Compare Engine(DCC) for SM8150 Souradeep Chowdhury
2021-02-17 6:48 ` [PATCH V0 1/6] dt-bindings: Added the yaml bindings for DCC Souradeep Chowdhury
2021-02-17 11:02 ` Vinod Koul
2021-02-17 13:20 ` schowdhu
2021-02-17 20:24 ` Rob Herring
2021-02-17 6:48 ` [PATCH V0 2/6] arm64: dts: qcom: sm8150: Add Data Capture and Compare(DCC) support node Souradeep Chowdhury
2021-02-17 11:03 ` Vinod Koul
2021-02-17 13:10 ` schowdhu
2021-02-17 6:48 ` [PATCH V0 3/6] soc: qcom: dcc:Add driver support for Data Capture and Compare unit(DCC) Souradeep Chowdhury
2021-02-17 8:08 ` kernel test robot
2021-02-18 6:59 ` Vinod Koul
2021-02-18 11:51 ` schowdhu
2021-02-17 6:48 ` Souradeep Chowdhury [this message]
2021-02-17 6:48 ` [PATCH V0 5/6] DCC:Added the sysfs entries for DCC(Data Capture and Compare) driver Souradeep Chowdhury
2021-02-17 6:48 ` [PATCH V0 6/6] MAINTAINERS:Added the entry for DCC(Data Capture and Compare) driver support Souradeep Chowdhury
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0b478cfd38cc01e43f4af3445b070327fa907db5.1613541226.git.schowdhu@codeaurora.org \
--to=schowdhu@codeaurora.org \
--cc=agross@kernel.org \
--cc=bjorn.andersson@linaro.org \
--cc=devicetree@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rnayak@codeaurora.org \
--cc=robh+dt@kernel.org \
--cc=saiprakash.ranjan@codeaurora.org \
--cc=sibis@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox