You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.6 KiB
161 lines
4.6 KiB
![]()
6 years ago
|
From patchwork Fri Dec 8 09:42:28 2017
|
||
|
Content-Type: text/plain; charset="utf-8"
|
||
|
MIME-Version: 1.0
|
||
|
Content-Transfer-Encoding: 7bit
|
||
|
Subject: [v4,10/12] clk: qcom: Add safe switch hook for krait mux clocks
|
||
|
From: Sricharan R <sricharan@codeaurora.org>
|
||
|
X-Patchwork-Id: 10102057
|
||
|
Message-Id: <1512726150-7204-11-git-send-email-sricharan@codeaurora.org>
|
||
|
To: mturquette@baylibre.com, sboyd@codeaurora.org,
|
||
|
devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
|
||
|
linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
|
||
|
viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
|
||
|
Cc: sricharan@codeaurora.org
|
||
|
Date: Fri, 8 Dec 2017 15:12:28 +0530
|
||
|
|
||
|
When the Hfplls are reprogrammed during the rate change,
|
||
|
the primary muxes which are sourced from the same hfpll
|
||
|
for higher frequencies, needs to be switched to the 'safe
|
||
|
secondary mux' as the parent for that small window. This
|
||
|
is done by registering a clk notifier for the muxes and
|
||
|
switching to the safe parent in the PRE_RATE_CHANGE notifier
|
||
|
and back to the original parent in the POST_RATE_CHANGE notifier.
|
||
|
|
||
|
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
|
||
|
---
|
||
|
drivers/clk/qcom/clk-krait.c | 2 ++
|
||
|
drivers/clk/qcom/clk-krait.h | 3 +++
|
||
|
drivers/clk/qcom/krait-cc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++
|
||
|
3 files changed, 61 insertions(+)
|
||
|
|
||
|
--- a/drivers/clk/qcom/clk-krait.c
|
||
|
+++ b/drivers/clk/qcom/clk-krait.c
|
||
|
@@ -60,6 +60,8 @@ static int krait_mux_set_parent(struct c
|
||
|
if (__clk_is_enabled(hw->clk))
|
||
|
__krait_mux_set_sel(mux, sel);
|
||
|
|
||
|
+ mux->reparent = true;
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
--- a/drivers/clk/qcom/clk-krait.h
|
||
|
+++ b/drivers/clk/qcom/clk-krait.h
|
||
|
@@ -23,6 +23,9 @@ struct krait_mux_clk {
|
||
|
u32 shift;
|
||
|
u32 en_mask;
|
||
|
bool lpl;
|
||
|
+ u8 safe_sel;
|
||
|
+ u8 old_index;
|
||
|
+ bool reparent;
|
||
|
|
||
|
struct clk_hw hw;
|
||
|
struct notifier_block clk_nb;
|
||
|
--- a/drivers/clk/qcom/krait-cc.c
|
||
|
+++ b/drivers/clk/qcom/krait-cc.c
|
||
|
@@ -35,6 +35,49 @@ static unsigned int pri_mux_map[] = {
|
||
|
0,
|
||
|
};
|
||
|
|
||
|
+/*
|
||
|
+ * Notifier function for switching the muxes to safe parent
|
||
|
+ * while the hfpll is getting reprogrammed.
|
||
|
+ */
|
||
|
+static int krait_notifier_cb(struct notifier_block *nb,
|
||
|
+ unsigned long event,
|
||
|
+ void *data)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+ struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
|
||
|
+ clk_nb);
|
||
|
+ /* Switch to safe parent */
|
||
|
+ if (event == PRE_RATE_CHANGE) {
|
||
|
+ mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
|
||
|
+ ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
|
||
|
+ mux->reparent = false;
|
||
|
+ /*
|
||
|
+ * By the time POST_RATE_CHANGE notifier is called,
|
||
|
+ * clk framework itself would have changed the parent for the new rate.
|
||
|
+ * Only otherwise, put back to the old parent.
|
||
|
+ */
|
||
|
+ } else if (event == POST_RATE_CHANGE) {
|
||
|
+ if (!mux->reparent)
|
||
|
+ ret = krait_mux_clk_ops.set_parent(&mux->hw,
|
||
|
+ mux->old_index);
|
||
|
+ }
|
||
|
+
|
||
|
+ return notifier_from_errno(ret);
|
||
|
+}
|
||
|
+
|
||
|
+static int krait_notifier_register(struct device *dev, struct clk *clk,
|
||
|
+ struct krait_mux_clk *mux)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ mux->clk_nb.notifier_call = krait_notifier_cb;
|
||
|
+ ret = clk_notifier_register(clk, &mux->clk_nb);
|
||
|
+ if (ret)
|
||
|
+ dev_err(dev, "failed to register clock notifier: %d\n", ret);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
|
||
|
{
|
||
|
@@ -79,6 +122,7 @@ static int
|
||
|
krait_add_sec_mux(struct device *dev, int id, const char *s,
|
||
|
unsigned int offset, bool unique_aux)
|
||
|
{
|
||
|
+ int ret;
|
||
|
struct krait_mux_clk *mux;
|
||
|
static const char *sec_mux_list[] = {
|
||
|
"acpu_aux",
|
||
|
@@ -102,6 +146,7 @@ krait_add_sec_mux(struct device *dev, in
|
||
|
mux->shift = 2;
|
||
|
mux->parent_map = sec_mux_map;
|
||
|
mux->hw.init = &init;
|
||
|
+ mux->safe_sel = 0;
|
||
|
|
||
|
init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
|
||
|
if (!init.name)
|
||
|
@@ -117,6 +162,11 @@ krait_add_sec_mux(struct device *dev, in
|
||
|
|
||
|
clk = devm_clk_register(dev, &mux->hw);
|
||
|
|
||
|
+ ret = krait_notifier_register(dev, clk, mux);
|
||
|
+ if (ret)
|
||
|
+ goto unique_aux;
|
||
|
+
|
||
|
+unique_aux:
|
||
|
if (unique_aux)
|
||
|
kfree(sec_mux_list[0]);
|
||
|
err_aux:
|
||
|
@@ -128,6 +178,7 @@ static struct clk *
|
||
|
krait_add_pri_mux(struct device *dev, int id, const char *s,
|
||
|
unsigned int offset)
|
||
|
{
|
||
|
+ int ret;
|
||
|
struct krait_mux_clk *mux;
|
||
|
const char *p_names[3];
|
||
|
struct clk_init_data init = {
|
||
|
@@ -148,6 +199,7 @@ krait_add_pri_mux(struct device *dev, in
|
||
|
mux->lpl = id >= 0;
|
||
|
mux->parent_map = pri_mux_map;
|
||
|
mux->hw.init = &init;
|
||
|
+ mux->safe_sel = 2;
|
||
|
|
||
|
init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
|
||
|
if (!init.name)
|
||
|
@@ -173,6 +225,10 @@ krait_add_pri_mux(struct device *dev, in
|
||
|
|
||
|
clk = devm_clk_register(dev, &mux->hw);
|
||
|
|
||
|
+ ret = krait_notifier_register(dev, clk, mux);
|
||
|
+ if (ret)
|
||
|
+ goto err_p3;
|
||
|
+err_p3:
|
||
|
kfree(p_names[2]);
|
||
|
err_p2:
|
||
|
kfree(p_names[1]);
|