summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/dcc.c
diff options
context:
space:
mode:
authorShashank Mittal <mittals@codeaurora.org>2015-05-13 17:01:45 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-05-16 20:10:38 -0700
commit65d782b85e613df69e17161024517af636c706d4 (patch)
tree5da119b71999294badd378943d9b784850d4f769 /drivers/soc/qcom/dcc.c
parent2972d94a8e8c0e4ed229728977d827c7a218c0cf (diff)
soc: qcom: dcc: change configuration programming interface
Currently user needs to provide base, offset, and length to program a configuration in DCC. To simplify user input, this change requires user to provide just start address and length. Driver is going to calculate most optimized base, offset and length to configure user request in SRAM. Change-Id: Ic1b7b2d4d4ed4baa9e8d33a2b60c10d2e799b211 Signed-off-by: Shashank Mittal <mittals@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom/dcc.c')
-rw-r--r--drivers/soc/qcom/dcc.c104
1 files changed, 77 insertions, 27 deletions
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index 42307b8fdda1..c1161b675018 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -61,6 +61,9 @@
#define DCC_REG_DUMP_MAGIC_V2 (0x42445953)
#define DCC_REG_DUMP_VER (1)
+#define MAX_DCC_OFFSET (0xFF * 4)
+#define MAX_DCC_LEN 0x7F
+
enum dcc_func_type {
DCC_FUNC_TYPE_CAPTURE,
DCC_FUNC_TYPE_CRC,
@@ -611,42 +614,84 @@ static ssize_t dcc_show_config(struct device *dev,
return count;
}
-static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned base,
- unsigned offset, unsigned len)
+static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned addr,
+ unsigned len)
{
int ret;
- struct dcc_config_entry *entry;
+ struct dcc_config_entry *entry, *pentry;
+ unsigned base, offset;
mutex_lock(&drvdata->mutex);
- /* Validate data */
- if (!len || len > BM(0, 6)) {
- dev_err(drvdata->dev,
- "DCC: Invalid length! Expected range [1, %u] in words.\n",
- (unsigned int)BM(0, 6));
+ if (!len) {
+ dev_err(drvdata->dev, "DCC: Invalid length!\n");
ret = -EINVAL;
goto err;
}
- if (base & BM(0, 3)) {
- dev_err(drvdata->dev,
- "DCC: Invalid base! Expected [31:4] bits of actual address.\n");
- ret = -EINVAL;
- goto err;
- }
+ base = addr & BM(4, 31);
- entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
- if (!entry) {
- ret = -ENOMEM;
- goto err;
+ if (!list_empty(&drvdata->config_head)) {
+ pentry = list_last_entry(&drvdata->config_head,
+ struct dcc_config_entry, list);
+
+ if (addr >= (pentry->base + pentry->offset) &&
+ addr <= (pentry->base + pentry->offset + MAX_DCC_OFFSET)) {
+
+ /* Re-use base address from last entry */
+ base = pentry->base;
+
+ /*
+ * Check if new address is contiguous to last entry's
+ * addresses. If yes then we can re-use last entry and
+ * just need to update its length.
+ */
+ if ((pentry->len * 4 + pentry->base + pentry->offset)
+ == addr) {
+ len += pentry->len;
+
+ /*
+ * Check if last entry can hold additional new
+ * length. If yes then we don't need to create
+ * a new entry else we need to add a new entry
+ * with same base but updated offset.
+ */
+ if (len > MAX_DCC_LEN)
+ pentry->len = MAX_DCC_LEN;
+ else
+ pentry->len = len;
+
+ /*
+ * Update start addr and len for remaining
+ * addresses, which will be part of new
+ * entry.
+ */
+ addr = pentry->base + pentry->offset +
+ pentry->len * 4;
+ len -= pentry->len;
+ }
+ }
}
- entry->base = base;
- entry->offset = offset;
- entry->len = len;
- entry->index = drvdata->nr_config++;
- INIT_LIST_HEAD(&entry->list);
- list_add_tail(&entry->list, &drvdata->config_head);
+ offset = addr - base;
+
+ while (len) {
+ entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ entry->base = base;
+ entry->offset = offset;
+ entry->len = min_t(uint32_t, len, MAX_DCC_LEN);
+ entry->index = drvdata->nr_config++;
+ INIT_LIST_HEAD(&entry->list);
+ list_add_tail(&entry->list, &drvdata->config_head);
+
+ len -= entry->len;
+ offset += MAX_DCC_LEN * 4;
+ }
mutex_unlock(&drvdata->mutex);
return 0;
@@ -660,13 +705,18 @@ static ssize_t dcc_store_config(struct device *dev,
const char *buf, size_t size)
{
int ret;
- unsigned base, offset, len;
+ unsigned base, len;
struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+ int nval;
- if (sscanf(buf, "%x %x %u", &base, &offset, &len) != 3)
+ nval = sscanf(buf, "%x %i", &base, &len);
+ if (nval <= 0 || nval > 2)
return -EINVAL;
- ret = dcc_config_add(drvdata, base, offset, len);
+ if (nval == 1)
+ len = 1;
+
+ ret = dcc_config_add(drvdata, base, len);
if (ret)
return ret;