From 2972d94a8e8c0e4ed229728977d827c7a218c0cf Mon Sep 17 00:00:00 2001 From: Shashank Mittal Date: Thu, 14 May 2015 20:03:07 -0700 Subject: soc: qcom: dcc: add support to send SW trigger on/off req to RPM Add support to request RPM to turn on/off DCC SW trigger. This request can be used to enable/disable DDR training data verification before DDR frequency switch. After receiving enable request RPM assumes that DCC is configured in CRC mode to verify DDR training data. Hence it starts to send SW trigger to DCC to run CRC on configured data before DDR frequency switch. Change-Id: I491bc3e41e11a5366162c65907f41f7cbcdd7809 Signed-off-by: Shashank Mittal --- drivers/soc/qcom/dcc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'drivers/soc/qcom/dcc.c') 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 #include #include +#include + +#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, }; -- cgit v1.2.3