summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/qcom/dcc.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index b4a3536361a3..42307b8fdda1 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -22,6 +22,10 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <soc/qcom/memory_dump.h>
+#include <soc/qcom/rpm-smd.h>
+
+#define RPM_MISC_REQ_TYPE 0x6373696d
+#define RPM_MISC_DDR_DCC_ENABLE 0x32726464
#define TIMEOUT_US (100)
@@ -77,6 +81,11 @@ static const char * const str_dcc_data_sink[] = {
[DCC_DATA_SINK_SRAM] = "sram",
};
+struct rpm_trig_req {
+ uint32_t enable;
+ uint32_t reserved;
+};
+
struct dcc_config_entry {
uint32_t base;
uint32_t offset;
@@ -108,6 +117,8 @@ struct dcc_drvdata {
bool save_reg;
void *sram_buf;
struct msm_dump_data sram_data;
+ struct rpm_trig_req rpm_trig_req;
+ struct msm_rpm_kvp rpm_kvp;
};
static bool dcc_ready(struct dcc_drvdata *drvdata)
@@ -364,6 +375,38 @@ err:
return ret;
}
+static int __dcc_rpm_sw_trigger(struct dcc_drvdata *drvdata, bool enable)
+{
+ int ret = 0;
+ struct msm_rpm_kvp *rpm_kvp = &drvdata->rpm_kvp;
+
+ if (enable == drvdata->rpm_trig_req.enable)
+ return 0;
+
+ if (enable && (!drvdata->enable || drvdata->func_type !=
+ DCC_FUNC_TYPE_CRC)) {
+ dev_err(drvdata->dev,
+ "DCC: invalid state! Can't send sw trigger req to rpm\n");
+ return -EINVAL;
+ }
+
+ drvdata->rpm_trig_req.enable = enable;
+ rpm_kvp->key = RPM_MISC_DDR_DCC_ENABLE;
+ rpm_kvp->length = sizeof(struct rpm_trig_req);
+ rpm_kvp->data = (void *)(&drvdata->rpm_trig_req);
+
+ ret = msm_rpm_send_message(MSM_RPM_CTX_ACTIVE_SET,
+ RPM_MISC_REQ_TYPE, 0, rpm_kvp, 1);
+ if (ret) {
+ dev_err(drvdata->dev,
+ "DCC: SW trigger %s req to rpm failed %d\n",
+ (enable ? "enable" : "disable"), ret);
+ drvdata->rpm_trig_req.enable = !enable;
+ }
+
+ return ret;
+}
+
static void dcc_disable(struct dcc_drvdata *drvdata)
{
mutex_lock(&drvdata->mutex);
@@ -372,6 +415,12 @@ static void dcc_disable(struct dcc_drvdata *drvdata)
return;
}
+ /* Send request to RPM to disable DCC SW trigger */
+
+ if (__dcc_rpm_sw_trigger(drvdata, 0))
+ dev_err(drvdata->dev,
+ "DCC: Request to RPM to disable SW trigger failed.\n");
+
if (!dcc_ready(drvdata))
dev_err(drvdata->dev, "DCC is not ready! Disabling DCC...\n");
@@ -727,6 +776,34 @@ static ssize_t dcc_store_interrupt_disable(struct device *dev,
static DEVICE_ATTR(interrupt_disable, S_IRUGO | S_IWUSR,
dcc_show_interrupt_disable, dcc_store_interrupt_disable);
+static ssize_t dcc_show_rpm_sw_trigger_on(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)drvdata->rpm_trig_req.enable);
+}
+
+static ssize_t dcc_store_rpm_sw_trigger_on(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);
+ __dcc_rpm_sw_trigger(drvdata, !!val);
+ mutex_unlock(&drvdata->mutex);
+ return size;
+}
+static DEVICE_ATTR(rpm_sw_trigger_on, S_IRUGO | S_IWUSR,
+ dcc_show_rpm_sw_trigger_on, dcc_store_rpm_sw_trigger_on);
+
static const struct device_attribute *dcc_attrs[] = {
&dev_attr_func_type,
&dev_attr_data_sink,
@@ -737,6 +814,7 @@ static const struct device_attribute *dcc_attrs[] = {
&dev_attr_ready,
&dev_attr_crc_error,
&dev_attr_interrupt_disable,
+ &dev_attr_rpm_sw_trigger_on,
NULL,
};