All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sagar Dharia <sdharia@codeaurora.org>
To: gregkh@linuxfoundation.org, bp@suse.de, poeschel@lemonage.de,
	sdharia@codeaurora.org, treding@nvidia.com, broonie@kernel.org,
	gong.chen@linux.intel.com, andreas.noever@gmail.com,
	alan@linux.intel.com, mathieu.poirier@linaro.org,
	daniel@ffwll.ch, oded.gabbay@amd.com, jkosina@suse.cz,
	sharon.dvir1@mail.huji.ac.il, joe@perches.com,
	davem@davemloft.net, james.hogan@imgtec.com,
	michael.opdenacker@free-electrons.com,
	daniel.thompson@linaro.org, linux-kernel@vger.kernel.org
Cc: nkaje@codeaurora.org, kheitke@audience.com,
	mlocke@codeaurora.org, agross@codeaurora.org,
	linux-arm-msm@vger.kernel.org
Subject: [PATCH V2 6/6] slim: qcom: Add runtime-pm support using clock-pause feature
Date: Tue, 16 Jun 2015 19:46:04 -0600	[thread overview]
Message-ID: <1434505564-14333-7-git-send-email-sdharia@codeaurora.org> (raw)
In-Reply-To: <1434505564-14333-1-git-send-email-sdharia@codeaurora.org>

Slimbus HW mandates that clock-pause sequence has to be executed
before disabling relevant interface and core clocks.
Runtime-PM's autosuspend feature is used here to enter/exit low
power mode for Qualcomm's Slimbus controller. Autosuspend feature
enables driver to avoid changing power-modes too frequently since
entering clock-pause is an expensive sequence

Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
---
 drivers/slimbus/slim-qcom-ctrl.c | 133 ++++++++++++++++++++++++++++++++++++++-
 drivers/slimbus/slim-qcom.h      |   1 +
 2 files changed, 132 insertions(+), 2 deletions(-)

diff --git a/drivers/slimbus/slim-qcom-ctrl.c b/drivers/slimbus/slim-qcom-ctrl.c
index feae9d1..ec8687d 100644
--- a/drivers/slimbus/slim-qcom-ctrl.c
+++ b/drivers/slimbus/slim-qcom-ctrl.c
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #include <linux/of.h>
 #include <linux/slimbus.h>
+#include <linux/pm_runtime.h>
 #include "slim-qcom.h"
 
 #define MSM_SLIM_NAME	"msm_slim_ctrl"
@@ -193,6 +194,7 @@ rx_ret_irq:
 		if (notify_rx)
 			complete(&dev->rx_msgq_notify);
 	}
+	pm_runtime_mark_last_busy(dev->dev);
 	return IRQ_HANDLED;
 }
 
@@ -211,6 +213,28 @@ static void msm_slim_wait_retry(struct msm_slim_ctrl *dev)
 	msleep(msec_per_frm);
 }
 
+static int msm_clk_pause_wakeup(struct slim_controller *ctrl)
+{
+	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
+
+	clk_prepare_enable(dev->hclk);
+	clk_prepare_enable(dev->rclk);
+	writel_relaxed(1, dev->base + FRM_WAKEUP);
+	/* Make sure framer wakeup write goes through before ISR fires */
+	mb();
+	/**
+	 * HW Workaround: Currently, slave is reporting lost-sync messages
+	 * after slimbus comes out of clock pause.
+	 * Transaction with slave fail before slave reports that message
+	 * Give some time for that report to come
+	 * Slimbus wakes up in clock gear 10 at 24.576MHz. With each superframe
+	 * being 250 usecs, we wait for 5-10 superframes here to ensure
+	 * we get the message
+	 */
+	usleep_range(1250, 2500);
+	return 0;
+}
+
 static void msm_slim_cb(void *ctx, int err)
 {
 	if (err)
@@ -225,14 +249,29 @@ static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
 	struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
 	u32 *pbuf;
 	u8 *puc;
-	int timeout;
+	int ret, timeout;
 	u8 la = txn->la;
+	enum slim_clk_state cur_clk_state = ctrl->sched.clk_state;
 	struct msm_wr_cb wr_cb = {msm_slim_cb, (void *)&done};
 
 	/* No support to send this dest-type of message */
 	if (txn->dt == SLIM_MSG_DEST_ENUMADDR)
 		return -EPROTONOSUPPORT;
 
+	if (cur_clk_state == SLIM_CLK_ENTERING_PAUSE) {
+		if (txn->mc != SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+		    txn->mc != SLIM_MSG_MC_RECONFIGURE_NOW &&
+		    txn->mc != SLIM_MSG_MC_NEXT_PAUSE_CLOCK)
+			return -EBUSY;
+	} else {
+		ret = pm_runtime_get_sync(dev->dev);
+		if (ret < 0) {
+			pm_runtime_set_suspended(dev->dev);
+			dev_err(dev->dev, "runtime-pm vote failed:%d\n", ret);
+			return ret;
+		}
+	}
+
 	/* HW expects length field to be excluded */
 	txn->rl--;
 
@@ -276,6 +315,8 @@ static int msm_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
 			txn->mt);
 
 	mutex_unlock(&dev->txn_lock);
+	if (cur_clk_state != SLIM_CLK_ENTERING_PAUSE)
+		pm_runtime_put(dev->dev);
 	return timeout ? 0 : -ETIMEDOUT;
 }
 
@@ -295,6 +336,13 @@ static int msm_set_laddr(struct slim_controller *ctrl,
 	ea[2] = (u8) (ead->prod_code & 0xFF);
 	ea[1] = ead->dev_index;
 	ea[0] = ead->instance;
+
+	ret = pm_runtime_get_sync(dev->dev);
+	if (ret < 0) {
+		pm_runtime_set_suspended(dev->dev);
+		dev_err(dev->dev, "runtime-pm vote failed:%d\n", ret);
+		return ret;
+	}
 	mutex_lock(&dev->txn_lock);
 	/**
 	 * Retries are needed since bus may lose sync when multiple devices
@@ -305,6 +353,7 @@ retry_laddr:
 	buf = (u32 *)msm_slim_get_tx(dev, &wr_cb);
 	if (buf == NULL) {
 		mutex_unlock(&dev->txn_lock);
+		pm_runtime_put(dev->dev);
 		return -ENOMEM;
 	}
 
@@ -332,6 +381,7 @@ retry_laddr:
 		}
 	}
 	mutex_unlock(&dev->txn_lock);
+	pm_runtime_put(dev->dev);
 	return ret;
 }
 
@@ -512,6 +562,7 @@ static int msm_slim_probe(struct platform_device *pdev)
 	}
 	dev->ctrl.set_laddr = msm_set_laddr;
 	dev->ctrl.xfer_msg = msm_xfer_msg;
+	dev->ctrl.wakeup =  msm_clk_pause_wakeup;
 
 	mutex_init(&dev->txn_lock);
 	init_completion(&dev->rx_msgq_notify);
@@ -615,6 +666,12 @@ static int msm_slim_probe(struct platform_device *pdev)
 	/* Add devices registered with board-info now that controller is up */
 	slim_ctrl_add_boarddevs(&dev->ctrl);
 
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	dev_dbg(dev->dev, "MSM SB controller is up:ver:0x%x!\n", dev->ver);
 	return 0;
 
@@ -651,6 +708,7 @@ static int msm_slim_remove(struct platform_device *pdev)
 	struct resource *slim_mem;
 	struct resource *slew_mem = dev->slew_mem;
 
+	pm_runtime_disable(&pdev->dev);
 	free_irq(dev->irq, dev);
 	slim_del_controller(&dev->ctrl);
 	clk_put(dev->rclk);
@@ -671,20 +729,91 @@ static int msm_slim_remove(struct platform_device *pdev)
 	return 0;
 }
 
+/**
+ * If PM_RUNTIME is not defined, these 2 functions become helper
+ * functions to be called from system suspend/resume.
+ */
+#ifdef CONFIG_PM
+static int msm_slim_runtime_suspend(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	int ret;
+
+	dev_dbg(device, "pm_runtime: suspending...\n");
+	ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
+	if (ret)
+		dev_err(device, "clk pause not entered:%d", ret);
+	else {
+		clk_disable_unprepare(dev->hclk);
+		clk_disable_unprepare(dev->rclk);
+	}
+	return ret;
+}
+
+static int msm_slim_runtime_resume(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	dev_dbg(device, "pm_runtime: resuming...\n");
+	ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
+	if (ret)
+		dev_err(device, "clk pause not exited:%d", ret);
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 static int msm_slim_suspend(struct device *dev)
 {
-	return 0;
+	int ret = 0;
+
+	if (!pm_runtime_enabled(dev) ||
+		(!pm_runtime_suspended(dev))) {
+		dev_dbg(dev, "system suspend");
+		ret = msm_slim_runtime_suspend(dev);
+	}
+	if (ret == -EISCONN) {
+		/**
+		* If the clock pause failed due to active channels, there is
+		* a possibility that some audio stream is active during suspend
+		* We dont want to return suspend failure in that case so that
+		* display and relevant components can still go to suspend.
+		* If there is some other error, then it should prevent
+		* system level suspend
+		*/
+		ret = 0;
+	}
+	return ret;
 }
 
 static int msm_slim_resume(struct device *dev)
 {
+	if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+		int ret;
+
+		dev_dbg(dev, "system resume");
+		ret = msm_slim_runtime_resume(dev);
+		if (!ret) {
+			pm_runtime_mark_last_busy(dev);
+			pm_request_autosuspend(dev);
+		}
+		return ret;
+
+	}
 	return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops msm_slim_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(msm_slim_suspend, msm_slim_resume)
+	SET_RUNTIME_PM_OPS(
+			   msm_slim_runtime_suspend,
+			   msm_slim_runtime_resume,
+			   NULL
+	)
 };
 
 static const struct of_device_id msm_slim_dt_match[] = {
diff --git a/drivers/slimbus/slim-qcom.h b/drivers/slimbus/slim-qcom.h
index 32073fc..f37a10a 100644
--- a/drivers/slimbus/slim-qcom.h
+++ b/drivers/slimbus/slim-qcom.h
@@ -25,6 +25,7 @@
 #define SLIM_ROOT_FREQ 24576000
 #define INIT_MX_RETRIES 10
 #define DEF_RETRY_MS	10
+#define MSM_SLIM_AUTOSUSPEND 1000
 
 /* MAX message size over control channel */
 #define SLIM_MSGQ_BUF_LEN	40
-- 
1.8.2.1

      parent reply	other threads:[~2015-06-17  1:46 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-17  1:45 [PATCH V2 0/6] Introduce framework for SLIMbus device drivers Sagar Dharia
2015-06-17  1:45 ` [PATCH V2 1/6] SLIMbus: Device management on SLIMbus Sagar Dharia
2015-06-17  3:38   ` Joe Perches
2015-06-17 13:16   ` Mark Brown
2015-06-17 17:36     ` Sagar Dharia
2015-06-18 21:39   ` Srinivas Kandagatla
2015-06-19  8:22   ` Daniel Thompson
2015-06-17  1:46 ` [PATCH V2 2/6] of/slimbus: OF helper for SLIMbus Sagar Dharia
2015-06-17 13:09   ` Mark Brown
2015-06-17 17:01     ` Sagar Dharia
2015-06-17  1:46 ` [PATCH V2 3/6] slimbus: Add messaging APIs to slimbus framework Sagar Dharia
2015-06-17  1:46 ` [PATCH V2 4/6] slim: qcom: Add Qualcomm Slimbus controller driver Sagar Dharia
2015-06-17 13:53   ` Mark Brown
2015-06-28 19:13     ` Sagar Dharia
2015-06-17  1:46 ` [PATCH V2 5/6] slimbus: Add support for 'clock-pause' feature Sagar Dharia
2015-06-17  1:46 ` Sagar Dharia [this message]

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=1434505564-14333-7-git-send-email-sdharia@codeaurora.org \
    --to=sdharia@codeaurora.org \
    --cc=agross@codeaurora.org \
    --cc=alan@linux.intel.com \
    --cc=andreas.noever@gmail.com \
    --cc=bp@suse.de \
    --cc=broonie@kernel.org \
    --cc=daniel.thompson@linaro.org \
    --cc=daniel@ffwll.ch \
    --cc=davem@davemloft.net \
    --cc=gong.chen@linux.intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=james.hogan@imgtec.com \
    --cc=jkosina@suse.cz \
    --cc=joe@perches.com \
    --cc=kheitke@audience.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.poirier@linaro.org \
    --cc=michael.opdenacker@free-electrons.com \
    --cc=mlocke@codeaurora.org \
    --cc=nkaje@codeaurora.org \
    --cc=oded.gabbay@amd.com \
    --cc=poeschel@lemonage.de \
    --cc=sharon.dvir1@mail.huji.ac.il \
    --cc=treding@nvidia.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.