Blob Blame History Raw
From dad4e7fda4bdc1a6357db500a7bab8843c08e521 Mon Sep 17 00:00:00 2001
From: Mike Tipton <mdtipton@codeaurora.org>
Date: Fri, 14 Feb 2020 18:12:32 -0800
Subject: [PATCH] clk: qcom: clk-rpmh: Wait for completion when enabling clocks
Git-commit: dad4e7fda4bdc1a6357db500a7bab8843c08e521
Patch-mainline: v5.7-rc1
References: git-fixes

The current implementation always uses rpmh_write_async, which doesn't
wait for completion. That's fine for disable requests since there's no
immediate need for the clocks and they can be disabled in the
background. However, for enable requests we need to ensure the clocks
are actually enabled before returning to the client. Otherwise, clients
can end up accessing their HW before the necessary clocks are enabled,
which can lead to bus errors.

Use the synchronous version of this API (rpmh_write) for enable requests
in the active set to ensure completion.

Completion isn't required for sleep/wake sets, since they don't take
effect until after we enter sleep. All rpmh requests are automatically
flushed prior to entering sleep.

Fixes: 9c7e47025a6b ("clk: qcom: clk-rpmh: Add QCOM RPMh clock driver")
Signed-off-by: Mike Tipton <mdtipton@codeaurora.org>
Link: https://lkml.kernel.org/r/20200215021232.1149-1-mdtipton@codeaurora.org
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
[sboyd@kernel.org: Reorg code a bit for readability, rename to 'wait' to
make local variable not conflict with completion.h mechanism]

Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/clk/qcom/clk-rpmh.c |   15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -147,12 +147,22 @@ static inline bool has_state_changed(str
 		!= (c->aggr_state & BIT(state));
 }
 
+static int clk_rpmh_send(struct clk_rpmh *c, enum rpmh_state state,
+			 struct tcs_cmd *cmd, bool wait)
+{
+	if (wait)
+		return rpmh_write(c->dev, state, cmd, 1);
+
+	return rpmh_write_async(c->dev, state, cmd, 1);
+}
+
 static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c)
 {
 	struct tcs_cmd cmd = { 0 };
 	u32 cmd_state, on_val;
 	enum rpmh_state state = RPMH_SLEEP_STATE;
 	int ret;
+	bool wait;
 
 	cmd.addr = c->res_addr;
 	cmd_state = c->aggr_state;
@@ -163,7 +173,8 @@ static int clk_rpmh_send_aggregate_comma
 			if (cmd_state & BIT(state))
 				cmd.data = on_val;
 
-			ret = rpmh_write_async(c->dev, state, &cmd, 1);
+			wait = cmd_state && state == RPMH_ACTIVE_ONLY_STATE;
+			ret = clk_rpmh_send(c, state, &cmd, wait);
 			if (ret) {
 				dev_err(c->dev, "set %s state of %s failed: (%d)\n",
 					!state ? "sleep" :
@@ -271,7 +282,7 @@ static int clk_rpmh_bcm_send_cmd(struct
 	cmd.addr = c->res_addr;
 	cmd.data = BCM_TCS_CMD(enable, cmd_state);
 
-	ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1);
+	ret = clk_rpmh_send(c, RPMH_ACTIVE_ONLY_STATE, &cmd, enable);
 	if (ret) {
 		dev_err(c->dev, "set active state of %s failed: (%d)\n",
 			c->res_name, ret);