ipq806x: update clk and cpufreq drivers
A newer clk and cpufreq drivers for ipq806x platform had been sent upstream. A change that i have noticed is that now it's possible to set min, cur and max frequencies from sysfs (previously it was bugged and caused nothing). Following patches are removed: - 0036-clk-Avoid-sending-high-rates-to-downstream-clocks-du.patch - seems it was dropped from the patchset by current committer. - 0044-clk-qcom-krait-Remove-CLK_IS_ROOT.patch - already applied to the driver itself in the corresponding patch. - 0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch - seem to be irrelevant to ipq806x. Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
This commit is contained in:
parent
83499bef73
commit
7903a9219c
16 changed files with 388 additions and 814 deletions
|
@ -1,7 +1,21 @@
|
|||
From 1d6b12f73c98ecf252743936a53242356cc50a34 Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:19 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,01/12] ARM: Add Krait L2 register accessor functions
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102101
|
||||
Message-Id: <1512726150-7204-2-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, Mark Rutland <mark.rutland@arm.com>,
|
||||
Russell King <linux@arm.linux.org.uk>,
|
||||
Courtney Cavin <courtney.cavin@sonymobile.com>
|
||||
Date: Fri, 8 Dec 2017 15:12:19 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:20 -0700
|
||||
Subject: [PATCH 34/69] ARM: Add Krait L2 register accessor functions
|
||||
|
||||
Krait CPUs have a handful of L2 cache controller registers that
|
||||
live behind a cp15 based indirection register. First you program
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
From 9d381d65eae163d8f50d97a3ad9033bba176f62b Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:20 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,02/12] clk: mux: Split out register accessors for reuse
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102103
|
||||
Message-Id: <1512726150-7204-3-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:20 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:21 -0700
|
||||
Subject: [PATCH 35/69] clk: mux: Split out register accessors for reuse
|
||||
|
||||
We want to reuse the logic in clk-mux.c for other clock drivers
|
||||
that don't use readl as register accessors. Fortunately, there
|
||||
|
@ -12,28 +24,25 @@ that operate on an optional table and some flags so that other
|
|||
drivers can use the same logic.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
---
|
||||
drivers/clk/clk-mux.c | 76 ++++++++++++++++++++++++++++----------------
|
||||
include/linux/clk-provider.h | 11 +++++--
|
||||
2 files changed, 57 insertions(+), 30 deletions(-)
|
||||
drivers/clk/clk-mux.c | 75 +++++++++++++++++++++++++++-----------------
|
||||
include/linux/clk-provider.h | 9 ++++--
|
||||
2 files changed, 54 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/drivers/clk/clk-mux.c
|
||||
+++ b/drivers/clk/clk-mux.c
|
||||
@@ -26,35 +26,27 @@
|
||||
@@ -26,35 +26,24 @@
|
||||
* parent - parent is adjustable through clk_set_parent
|
||||
*/
|
||||
|
||||
-static u8 clk_mux_get_parent(struct clk_hw *hw)
|
||||
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
|
||||
+
|
||||
+unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val,
|
||||
+ unsigned int *table, unsigned long flags)
|
||||
{
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
- struct clk_mux *mux = to_clk_mux(hw);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
- u32 val;
|
||||
|
||||
-
|
||||
- /*
|
||||
- * FIXME need a mux-specific flag to determine if val is bitwise or numeric
|
||||
- * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
|
||||
|
@ -43,7 +52,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
|||
- */
|
||||
- val = clk_readl(mux->reg) >> mux->shift;
|
||||
- val &= mux->mask;
|
||||
-
|
||||
|
||||
- if (mux->table) {
|
||||
+ if (table) {
|
||||
int i;
|
||||
|
@ -64,7 +73,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
|||
val--;
|
||||
|
||||
if (val >= num_parents)
|
||||
@@ -62,23 +54,53 @@ static u8 clk_mux_get_parent(struct clk_
|
||||
@@ -62,23 +51,53 @@ static u8 clk_mux_get_parent(struct clk_
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -80,9 +89,9 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
|||
- if (mux->table) {
|
||||
- index = mux->table[index];
|
||||
+ /*
|
||||
+ * FIXME need a mux-specific flag to determine if val is bitwise or numeric
|
||||
+ * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
|
||||
+ * to 0x7 (index starts at one)
|
||||
+ * FIXME need a mux-specific flag to determine if val is bitwise or
|
||||
+ * numeric e.g. sys_clkin_ck's clksel field is 3 bits wide,
|
||||
+ * but ranges from 0x1 to 0x7 (index starts at one)
|
||||
+ * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
|
||||
+ * val = 0x4 really means "bit 2, index starts at bit 0"
|
||||
+ */
|
||||
|
@ -126,7 +135,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
|||
if (mux->lock)
|
||||
spin_lock_irqsave(mux->lock, flags);
|
||||
else
|
||||
@@ -102,14 +124,14 @@ static int clk_mux_set_parent(struct clk
|
||||
@@ -102,14 +121,14 @@ static int clk_mux_set_parent(struct clk
|
||||
}
|
||||
|
||||
const struct clk_ops clk_mux_ops = {
|
||||
|
@ -143,7 +152,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
|
||||
|
||||
@@ -117,7 +139,7 @@ struct clk_hw *clk_hw_register_mux_table
|
||||
@@ -117,7 +136,7 @@ struct clk_hw *clk_hw_register_mux_table
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u32 mask,
|
||||
|
@ -175,13 +184,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
|||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags,
|
||||
@@ -499,12 +504,12 @@ struct clk *clk_register_mux_table(struc
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u32 mask,
|
||||
- u8 clk_mux_flags, u32 *table, spinlock_t *lock);
|
||||
+ u8 clk_mux_flags, unsigned int *table, spinlock_t *lock);
|
||||
struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
|
||||
@@ -504,7 +509,7 @@ struct clk_hw *clk_hw_register_mux_table
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u32 mask,
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
From 88e1d6d9c113fe50810d1b03eb1fdbf015e5d1bd Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:22 -0700
|
||||
Subject: [PATCH 36/69] clk: Avoid sending high rates to downstream clocks
|
||||
during set_rate
|
||||
|
||||
If a clock is on and we call clk_set_rate() on it we may get into
|
||||
a situation where the clock temporarily increases in rate
|
||||
dramatically while we walk the tree and call .set_rate() ops. For
|
||||
example, consider a case where a PLL feeds into a divider.
|
||||
Initially the divider is set to divide by 1 and the PLL is
|
||||
running fairly slow (100MHz). The downstream consumer of the
|
||||
divider output can only handle rates =< 400 MHz, but the divider
|
||||
can only choose between divisors of 1 and 4.
|
||||
|
||||
+-----+ +----------------+
|
||||
| PLL |-->| div 1 or div 4 |---> consumer device
|
||||
+-----+ +----------------+
|
||||
|
||||
To achieve a rate of 400MHz on the output of the divider, we
|
||||
would have to set the rate of the PLL to 1.6 GHz and then divide
|
||||
it by 4. The current code would set the PLL to 1.6GHz first while
|
||||
the divider is still set to 1, thus causing the downstream
|
||||
consumer of the clock to receive a few clock cycles of 1.6GHz
|
||||
clock (far beyond it's maximum acceptable rate). We should be
|
||||
changing the divider first before increasing the PLL rate to
|
||||
avoid this problem.
|
||||
|
||||
Therefore, set the rate of any child clocks that are increasing
|
||||
in rate from their current rate so that they can increase their
|
||||
dividers if necessary. We assume that there isn't such a thing as
|
||||
minimum rate requirements.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
|
||||
Conflicts:
|
||||
drivers/clk/clk.c
|
||||
---
|
||||
drivers/clk/clk.c | 22 +++++++++++++++-------
|
||||
1 file changed, 15 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -1466,12 +1466,12 @@ static struct clk_core *clk_propagate_ra
|
||||
* walk down a subtree and set the new rates notifying the rate
|
||||
* change on the way
|
||||
*/
|
||||
-static void clk_change_rate(struct clk_core *core)
|
||||
+static void
|
||||
+clk_change_rate(struct clk_core *core, unsigned long best_parent_rate)
|
||||
{
|
||||
struct clk_core *child;
|
||||
struct hlist_node *tmp;
|
||||
unsigned long old_rate;
|
||||
- unsigned long best_parent_rate = 0;
|
||||
bool skip_set_rate = false;
|
||||
struct clk_core *old_parent;
|
||||
struct clk_core *parent = NULL;
|
||||
@@ -1523,6 +1523,7 @@ static void clk_change_rate(struct clk_c
|
||||
trace_clk_set_rate_complete(core, core->new_rate);
|
||||
|
||||
core->rate = clk_recalc(core, best_parent_rate);
|
||||
+ core->rate = core->new_rate;
|
||||
|
||||
if (core->flags & CLK_SET_RATE_UNGATE) {
|
||||
unsigned long flags;
|
||||
@@ -1550,12 +1551,13 @@ static void clk_change_rate(struct clk_c
|
||||
/* Skip children who will be reparented to another clock */
|
||||
if (child->new_parent && child->new_parent != core)
|
||||
continue;
|
||||
- clk_change_rate(child);
|
||||
+ if (child->new_rate != child->rate)
|
||||
+ clk_change_rate(child, core->new_rate);
|
||||
}
|
||||
|
||||
- /* handle the new child who might not be in core->children yet */
|
||||
- if (core->new_child)
|
||||
- clk_change_rate(core->new_child);
|
||||
+ /* handle the new child who might not be in clk->children yet */
|
||||
+ if (core->new_child && core->new_child->new_rate != core->new_child->rate)
|
||||
+ clk_change_rate(core->new_child, core->new_rate);
|
||||
}
|
||||
|
||||
static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
@@ -1563,6 +1565,7 @@ static int clk_core_set_rate_nolock(stru
|
||||
{
|
||||
struct clk_core *top, *fail_clk;
|
||||
unsigned long rate = req_rate;
|
||||
+ unsigned long parent_rate;
|
||||
|
||||
if (!core)
|
||||
return 0;
|
||||
@@ -1588,8 +1591,13 @@ static int clk_core_set_rate_nolock(stru
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
+ if (top->parent)
|
||||
+ parent_rate = top->parent->rate;
|
||||
+ else
|
||||
+ parent_rate = 0;
|
||||
+
|
||||
/* change the rates */
|
||||
- clk_change_rate(top);
|
||||
+ clk_change_rate(top, parent_rate);
|
||||
|
||||
core->req_rate = req_rate;
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
From a1adfb782789ae9b25c928dfe3d639288563a86c Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:23 -0700
|
||||
Subject: [PATCH 37/69] clk: Add safe switch hook
|
||||
|
||||
Sometimes clocks can't accept their parent source turning off
|
||||
while the source is reprogrammed to a different rate. Most
|
||||
notably CPU clocks require a way to switch away from the current
|
||||
PLL they're running on, reprogram that PLL to a new rate, and
|
||||
then switch back to the PLL with the new rate once they're done.
|
||||
Add a hook that drivers can implement allowing them to return a
|
||||
'safe parent' and 'safe frequency' that they can switch their
|
||||
parent to while the upstream source is reprogrammed to support
|
||||
this.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
---
|
||||
drivers/clk/clk.c | 73 +++++++++++++++++++++++++++++++++++++++++---
|
||||
include/linux/clk-provider.h | 2 ++
|
||||
2 files changed, 70 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -51,9 +51,13 @@ struct clk_core {
|
||||
struct clk_core **parents;
|
||||
u8 num_parents;
|
||||
u8 new_parent_index;
|
||||
+ u8 safe_parent_index;
|
||||
unsigned long rate;
|
||||
unsigned long req_rate;
|
||||
+ unsigned long old_rate;
|
||||
unsigned long new_rate;
|
||||
+ unsigned long safe_freq;
|
||||
+ struct clk_core *safe_parent;
|
||||
struct clk_core *new_parent;
|
||||
struct clk_core *new_child;
|
||||
unsigned long flags;
|
||||
@@ -1310,7 +1314,9 @@ out:
|
||||
static void clk_calc_subtree(struct clk_core *core, unsigned long new_rate,
|
||||
struct clk_core *new_parent, u8 p_index)
|
||||
{
|
||||
- struct clk_core *child;
|
||||
+ struct clk_core *child, *parent;
|
||||
+ struct clk_hw *parent_hw;
|
||||
+ unsigned long safe_freq = 0;
|
||||
|
||||
core->new_rate = new_rate;
|
||||
core->new_parent = new_parent;
|
||||
@@ -1320,6 +1326,23 @@ static void clk_calc_subtree(struct clk_
|
||||
if (new_parent && new_parent != core->parent)
|
||||
new_parent->new_child = core;
|
||||
|
||||
+ if (core->ops->get_safe_parent) {
|
||||
+ parent_hw = core->ops->get_safe_parent(core->hw, &safe_freq);
|
||||
+ if (parent_hw) {
|
||||
+ parent = parent_hw->core;
|
||||
+ p_index = clk_fetch_parent_index(core, parent);
|
||||
+ core->safe_parent_index = p_index;
|
||||
+ core->safe_parent = parent;
|
||||
+ if (safe_freq)
|
||||
+ core->safe_freq = safe_freq;
|
||||
+ else
|
||||
+ core->safe_freq = 0;
|
||||
+ }
|
||||
+ } else {
|
||||
+ core->safe_parent = NULL;
|
||||
+ core->safe_freq = 0;
|
||||
+ }
|
||||
+
|
||||
hlist_for_each_entry(child, &core->children, child_node) {
|
||||
child->new_rate = clk_recalc(child, new_rate);
|
||||
clk_calc_subtree(child, child->new_rate, NULL, 0);
|
||||
@@ -1432,14 +1455,51 @@ static struct clk_core *clk_propagate_ra
|
||||
unsigned long event)
|
||||
{
|
||||
struct clk_core *child, *tmp_clk, *fail_clk = NULL;
|
||||
+ struct clk_core *old_parent;
|
||||
int ret = NOTIFY_DONE;
|
||||
|
||||
- if (core->rate == core->new_rate)
|
||||
+ if (core->rate == core->new_rate && event != POST_RATE_CHANGE)
|
||||
return NULL;
|
||||
|
||||
+ switch (event) {
|
||||
+ case PRE_RATE_CHANGE:
|
||||
+ if (core->safe_parent) {
|
||||
+ if (core->safe_freq)
|
||||
+ core->ops->set_rate_and_parent(core->hw,
|
||||
+ core->safe_freq,
|
||||
+ core->safe_parent->rate,
|
||||
+ core->safe_parent_index);
|
||||
+ else
|
||||
+ core->ops->set_parent(core->hw,
|
||||
+ core->safe_parent_index);
|
||||
+ }
|
||||
+ core->old_rate = core->rate;
|
||||
+ break;
|
||||
+ case POST_RATE_CHANGE:
|
||||
+ if (core->safe_parent) {
|
||||
+ old_parent = __clk_set_parent_before(core,
|
||||
+ core->new_parent);
|
||||
+ if (core->ops->set_rate_and_parent) {
|
||||
+ core->ops->set_rate_and_parent(core->hw,
|
||||
+ core->new_rate,
|
||||
+ core->new_parent ?
|
||||
+ core->new_parent->rate : 0,
|
||||
+ core->new_parent_index);
|
||||
+ } else if (core->ops->set_parent) {
|
||||
+ core->ops->set_parent(core->hw,
|
||||
+ core->new_parent_index);
|
||||
+ }
|
||||
+ __clk_set_parent_after(core, core->new_parent,
|
||||
+ old_parent);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
if (core->notifier_count) {
|
||||
- ret = __clk_notify(core, event, core->rate, core->new_rate);
|
||||
- if (ret & NOTIFY_STOP_MASK)
|
||||
+ if (event != POST_RATE_CHANGE || core->old_rate != core->rate)
|
||||
+ ret = __clk_notify(core, event, core->old_rate,
|
||||
+ core->new_rate);
|
||||
+ if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
|
||||
fail_clk = core;
|
||||
}
|
||||
|
||||
@@ -1495,7 +1555,8 @@ clk_change_rate(struct clk_core *core, u
|
||||
clk_enable_unlock(flags);
|
||||
}
|
||||
|
||||
- if (core->new_parent && core->new_parent != core->parent) {
|
||||
+ if (core->new_parent && core->new_parent != core->parent &&
|
||||
+ !core->safe_parent) {
|
||||
old_parent = __clk_set_parent_before(core, core->new_parent);
|
||||
trace_clk_set_parent(core, core->new_parent);
|
||||
|
||||
@@ -1601,6 +1662,8 @@ static int clk_core_set_rate_nolock(stru
|
||||
|
||||
core->req_rate = req_rate;
|
||||
|
||||
+ clk_propagate_rate_change(top, POST_RATE_CHANGE);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -206,6 +206,8 @@ struct clk_ops {
|
||||
struct clk_rate_request *req);
|
||||
int (*set_parent)(struct clk_hw *hw, u8 index);
|
||||
u8 (*get_parent)(struct clk_hw *hw);
|
||||
+ struct clk_hw *(*get_safe_parent)(struct clk_hw *hw,
|
||||
+ unsigned long *safe_freq);
|
||||
int (*set_rate)(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate);
|
||||
int (*set_rate_and_parent)(struct clk_hw *hw,
|
|
@ -1,7 +1,19 @@
|
|||
From f044ffe2d612dcaa2de36c918aaab79c8db1482e Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:21 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,03/12] clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102083
|
||||
Message-Id: <1512726150-7204-4-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:21 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:24 -0700
|
||||
Subject: [PATCH 38/69] clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
|
||||
|
||||
HFPLLs are the main frequency source for Krait CPU clocks. Add
|
||||
support for changing the rate of these PLLs.
|
||||
|
@ -105,7 +117,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ * H/W requires a 5us delay between disabling the bypass and
|
||||
+ * de-asserting the reset. Delay 10us just to be safe.
|
||||
+ */
|
||||
+ udelay(10);
|
||||
+ usleep_range(10, 100);
|
||||
+
|
||||
+ /* De-assert active-low PLL reset. */
|
||||
+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
|
||||
|
@ -116,7 +128,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ regmap_read(regmap, hd->status_reg, &val);
|
||||
+ } while (!(val & BIT(hd->lock_bit)));
|
||||
+ } else {
|
||||
+ udelay(60);
|
||||
+ usleep_range(60, 100);
|
||||
+ }
|
||||
+
|
||||
+ /* Enable PLL output. */
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
From 23f680d03e5894f494572a5162d21328bd86890c Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:22 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,04/12] clk: qcom: Add HFPLL driver
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102079
|
||||
Message-Id: <1512726150-7204-5-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:22 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:25 -0700
|
||||
Subject: [PATCH 39/69] clk: qcom: Add HFPLL driver
|
||||
|
||||
On some devices (MSM8974 for example), the HFPLLs are
|
||||
instantiated within the Krait processor subsystem as separate
|
||||
|
@ -10,7 +22,6 @@ provide HFPLL clocks for use by the system.
|
|||
|
||||
Cc: <devicetree@vger.kernel.org>
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
---
|
||||
.../devicetree/bindings/clock/qcom,hfpll.txt | 40 ++++++++
|
||||
drivers/clk/qcom/Kconfig | 8 ++
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
From 0dfdf84ee3982e88a62123b3de1c094d2c0829af Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:24 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,06/12] clk: qcom: Add IPQ806X's HFPLLs
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102047
|
||||
Message-Id: <1512726150-7204-7-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:24 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:27 -0700
|
||||
Subject: [PATCH 40/69] clk: qcom: Add IPQ806X's HFPLLs
|
||||
|
||||
Describe the HFPLLs present on IPQ806X devices.
|
||||
|
||||
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq806x.c | 83 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 83 insertions(+)
|
||||
drivers/clk/qcom/gcc-ipq806x.c | 82 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 82 insertions(+)
|
||||
|
||||
--- a/drivers/clk/qcom/gcc-ipq806x.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq806x.c
|
||||
|
@ -20,7 +32,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
#include "reset.h"
|
||||
|
||||
static struct clk_pll pll0 = {
|
||||
@@ -113,6 +114,85 @@ static struct clk_regmap pll8_vote = {
|
||||
@@ -113,6 +114,84 @@ static struct clk_regmap pll8_vote = {
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -101,12 +113,11 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ },
|
||||
+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
|
||||
+};
|
||||
+
|
||||
+
|
||||
static struct clk_pll pll14 = {
|
||||
.l_reg = 0x31c4,
|
||||
.m_reg = 0x31c8,
|
||||
@@ -2801,6 +2881,9 @@ static struct clk_regmap *gcc_ipq806x_cl
|
||||
@@ -2801,6 +2880,9 @@ static struct clk_regmap *gcc_ipq806x_cl
|
||||
[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
|
||||
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
|
||||
[NSSTCM_CLK] = &nss_tcm_clk.clkr,
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
From b9747125a8e7633ed2701a70e32dbb0442193774 Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:25 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,07/12] clk: qcom: Add support for Krait clocks
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102051
|
||||
Message-Id: <1512726150-7204-8-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:25 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:28 -0700
|
||||
Subject: [PATCH 41/69] clk: qcom: Add support for Krait clocks
|
||||
|
||||
The Krait clocks are made up of a series of muxes and a divider
|
||||
that choose between a fixed rate clock and dedicated HFPLLs for
|
||||
|
@ -13,9 +25,9 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
---
|
||||
drivers/clk/qcom/Kconfig | 4 ++
|
||||
drivers/clk/qcom/Makefile | 1 +
|
||||
drivers/clk/qcom/clk-krait.c | 167 +++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/clk/qcom/clk-krait.h | 49 +++++++++++++
|
||||
4 files changed, 221 insertions(+)
|
||||
drivers/clk/qcom/clk-krait.c | 134 +++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/clk/qcom/clk-krait.h | 48 ++++++++++++++++
|
||||
4 files changed, 187 insertions(+)
|
||||
create mode 100644 drivers/clk/qcom/clk-krait.c
|
||||
create mode 100644 drivers/clk/qcom/clk-krait.h
|
||||
|
||||
|
@ -41,7 +53,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/qcom/clk-krait.c
|
||||
@@ -0,0 +1,167 @@
|
||||
@@ -0,0 +1,134 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
|
@ -103,6 +115,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ /* Don't touch mux if CPU is off as it won't work */
|
||||
+ if (__clk_is_enabled(hw->clk))
|
||||
+ __krait_mux_set_sel(mux, sel);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
|
@ -119,44 +132,10 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
|
||||
+}
|
||||
+
|
||||
+static struct clk_hw *krait_mux_get_safe_parent(struct clk_hw *hw,
|
||||
+ unsigned long *safe_freq)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
|
||||
+ int num_parents = clk_hw_get_num_parents(hw);
|
||||
+
|
||||
+ i = mux->safe_sel;
|
||||
+ for (i = 0; i < num_parents; i++)
|
||||
+ if (mux->safe_sel == mux->parent_map[i])
|
||||
+ break;
|
||||
+
|
||||
+ return clk_hw_get_parent_by_index(hw, i);
|
||||
+}
|
||||
+
|
||||
+static int krait_mux_enable(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
|
||||
+
|
||||
+ __krait_mux_set_sel(mux, mux->en_mask);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void krait_mux_disable(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
|
||||
+
|
||||
+ __krait_mux_set_sel(mux, mux->safe_sel);
|
||||
+}
|
||||
+
|
||||
+const struct clk_ops krait_mux_clk_ops = {
|
||||
+ .enable = krait_mux_enable,
|
||||
+ .disable = krait_mux_disable,
|
||||
+ .set_parent = krait_mux_set_parent,
|
||||
+ .get_parent = krait_mux_get_parent,
|
||||
+ .determine_rate = __clk_mux_determine_rate_closest,
|
||||
+ .get_safe_parent = krait_mux_get_safe_parent,
|
||||
+};
|
||||
+EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
|
||||
+
|
||||
|
@ -211,7 +190,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/qcom/clk-krait.h
|
||||
@@ -0,0 +1,49 @@
|
||||
@@ -0,0 +1,48 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
|
@ -232,8 +211,6 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+
|
||||
+struct krait_mux_clk {
|
||||
+ unsigned int *parent_map;
|
||||
+ bool has_safe_parent;
|
||||
+ u8 safe_sel;
|
||||
+ u32 offset;
|
||||
+ u32 mask;
|
||||
+ u32 shift;
|
||||
|
@ -241,6 +218,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ bool lpl;
|
||||
+
|
||||
+ struct clk_hw hw;
|
||||
+ struct notifier_block clk_nb;
|
||||
+};
|
||||
+
|
||||
+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
From 6039eb63fabdd6871fc70940aa98102665c78eed Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:26 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,08/12] clk: qcom: Add KPSS ACC/GCC driver
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102023
|
||||
Message-Id: <1512726150-7204-9-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:26 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:29 -0700
|
||||
Subject: [PATCH 42/69] clk: qcom: Add KPSS ACC/GCC driver
|
||||
|
||||
The ACC and GCC regions present in KPSSv1 contain registers to
|
||||
control clocks and power to each Krait CPU and L2. For CPUfreq
|
||||
|
@ -15,8 +27,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
.../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 28 +++++++
|
||||
drivers/clk/qcom/Kconfig | 8 ++
|
||||
drivers/clk/qcom/Makefile | 1 +
|
||||
drivers/clk/qcom/kpss-xcc.c | 95 ++++++++++++++++++++++
|
||||
5 files changed, 139 insertions(+)
|
||||
drivers/clk/qcom/kpss-xcc.c | 96 ++++++++++++++++++++++
|
||||
5 files changed, 140 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
|
||||
create mode 100644 drivers/clk/qcom/kpss-xcc.c
|
||||
|
||||
|
@ -98,7 +110,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/qcom/kpss-xcc.c
|
||||
@@ -0,0 +1,95 @@
|
||||
@@ -0,0 +1,96 @@
|
||||
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
|
@ -158,7 +170,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+
|
||||
+ if (id->data) {
|
||||
+ if (of_property_read_string_index(pdev->dev.of_node,
|
||||
+ "clock-output-names", 0, &name))
|
||||
+ "clock-output-names",
|
||||
+ 0, &name))
|
||||
+ return -ENODEV;
|
||||
+ base += 0x14;
|
||||
+ } else {
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
From 7fb5976eb0231a06f484a6bde5e5fbfee7ee4f4a Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:27 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,09/12] clk: qcom: Add Krait clock controller driver
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102061
|
||||
Message-Id: <1512726150-7204-10-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:27 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:30 -0700
|
||||
Subject: [PATCH 43/69] clk: qcom: Add Krait clock controller driver
|
||||
|
||||
The Krait CPU clocks are made up of a primary mux and secondary
|
||||
mux for each CPU and the L2, controlled via cp15 accessors. For
|
||||
|
@ -15,8 +27,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
.../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++
|
||||
drivers/clk/qcom/Kconfig | 8 +
|
||||
drivers/clk/qcom/Makefile | 1 +
|
||||
drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++
|
||||
4 files changed, 383 insertions(+)
|
||||
drivers/clk/qcom/krait-cc.c | 350 +++++++++++++++++++++
|
||||
4 files changed, 381 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
|
||||
create mode 100644 drivers/clk/qcom/krait-cc.c
|
||||
|
||||
|
@ -71,7 +83,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+obj-$(CONFIG_KRAITCC) += krait-cc.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/qcom/krait-cc.c
|
||||
@@ -0,0 +1,352 @@
|
||||
@@ -0,0 +1,350 @@
|
||||
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
|
@ -110,7 +122,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+};
|
||||
+
|
||||
+static int
|
||||
+krait_add_div(struct device *dev, int id, const char *s, unsigned offset)
|
||||
+krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
|
||||
+{
|
||||
+ struct krait_div2_clk *div;
|
||||
+ struct clk_init_data init = {
|
||||
|
@ -150,8 +162,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+}
|
||||
+
|
||||
+static int
|
||||
+krait_add_sec_mux(struct device *dev, int id, const char *s, unsigned offset,
|
||||
+ bool unique_aux)
|
||||
+krait_add_sec_mux(struct device *dev, int id, const char *s,
|
||||
+ unsigned int offset, bool unique_aux)
|
||||
+{
|
||||
+ struct krait_mux_clk *mux;
|
||||
+ static const char *sec_mux_list[] = {
|
||||
|
@ -172,8 +184,6 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+
|
||||
+ mux->offset = offset;
|
||||
+ mux->lpl = id >= 0;
|
||||
+ mux->has_safe_parent = true;
|
||||
+ mux->safe_sel = 2;
|
||||
+ mux->mask = 0x3;
|
||||
+ mux->shift = 2;
|
||||
+ mux->parent_map = sec_mux_map;
|
||||
|
@ -201,7 +211,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+}
|
||||
+
|
||||
+static struct clk *
|
||||
+krait_add_pri_mux(struct device *dev, int id, const char *s, unsigned offset)
|
||||
+krait_add_pri_mux(struct device *dev, int id, const char *s,
|
||||
+ unsigned int offset)
|
||||
+{
|
||||
+ struct krait_mux_clk *mux;
|
||||
+ const char *p_names[3];
|
||||
|
@ -217,8 +228,6 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ if (!mux)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ mux->has_safe_parent = true;
|
||||
+ mux->safe_sel = 0;
|
||||
+ mux->mask = 0x3;
|
||||
+ mux->shift = 0;
|
||||
+ mux->offset = offset;
|
||||
|
@ -264,7 +273,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
|
||||
+{
|
||||
+ int ret;
|
||||
+ unsigned offset;
|
||||
+ unsigned int offset;
|
||||
+ void *p = NULL;
|
||||
+ const char *s;
|
||||
+ struct clk *clk;
|
||||
|
@ -332,7 +341,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ return -ENODEV;
|
||||
+
|
||||
+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
|
||||
+ clk = clk_register_fixed_rate(dev, "qsb", NULL, CLK_IS_ROOT, 1);
|
||||
+ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
|
||||
+ if (IS_ERR(clk))
|
||||
+ return PTR_ERR(clk);
|
||||
+
|
||||
|
@ -401,6 +410,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
|
||||
+ cur_rate = aux_rate;
|
||||
+ }
|
||||
+
|
||||
+ clk_set_rate(clk, aux_rate);
|
||||
+ clk_set_rate(clk, 2);
|
||||
+ clk_set_rate(clk, cur_rate);
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
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]);
|
|
@ -1,23 +0,0 @@
|
|||
From 58f8215f1d9397f9130657cc2c15a956bd99210e Mon Sep 17 00:00:00 2001
|
||||
From: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
Date: Wed, 13 Jul 2016 15:22:25 +0300
|
||||
Subject: [PATCH 44/69] clk: qcom: krait: Remove CLK_IS_ROOT
|
||||
|
||||
The flag CLK_IS_ROOT is no-op now. Remove it.
|
||||
|
||||
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
---
|
||||
drivers/clk/qcom/krait-cc.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/clk/qcom/krait-cc.c
|
||||
+++ b/drivers/clk/qcom/krait-cc.c
|
||||
@@ -258,7 +258,7 @@ static int krait_cc_probe(struct platfor
|
||||
return -ENODEV;
|
||||
|
||||
/* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
|
||||
- clk = clk_register_fixed_rate(dev, "qsb", NULL, CLK_IS_ROOT, 1);
|
||||
+ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
|
@ -1,7 +1,19 @@
|
|||
From 42eea6bc2858ab9649cf6931455e391e48939685 Mon Sep 17 00:00:00 2001
|
||||
From patchwork Fri Dec 8 09:42:29 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,11/12] cpufreq: Add module to register cpufreq on Krait CPUs
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102075
|
||||
Message-Id: <1512726150-7204-12-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:29 +0530
|
||||
|
||||
From: Stephen Boyd <sboyd@codeaurora.org>
|
||||
Date: Fri, 20 Mar 2015 23:45:31 -0700
|
||||
Subject: [PATCH 45/69] cpufreq: Add module to register cpufreq on Krait CPUs
|
||||
|
||||
Register a cpufreq-generic device whenever we detect that a
|
||||
"qcom,krait" compatible CPU is present in DT.
|
||||
|
@ -111,7 +123,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
|
|||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pm_opp.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/cpufreq-dt.h>
|
||||
+#include "cpufreq-dt.h"
|
||||
+
|
||||
+static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver)
|
||||
+{
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
ipq806x: support independent core clocks with kernel 4.9+
|
||||
From patchwork Fri Dec 8 09:42:30 2017
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Subject: [v4,12/12] cpufreq: dt: Reintroduce independent_clocks platform data
|
||||
From: Sricharan R <sricharan@codeaurora.org>
|
||||
X-Patchwork-Id: 10102073
|
||||
Message-Id: <1512726150-7204-13-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:30 +0530
|
||||
|
||||
Add back support for the independent_clocks definition that has been
|
||||
removed between kernel 4.4 and 4.9 by upstream commits
|
||||
eb96924acddc709db58221c210ca05cd9effb1df and
|
||||
e86eee6bc2aaa6b3637f6497b26beee09a91bde9
|
||||
The Platform data was removed earlier by,
|
||||
'commit eb96924acddc ("cpufreq: dt: Kill platform-data")'
|
||||
since there were no users at that time.
|
||||
Now this is required when the each of the cpu clocks
|
||||
can be scaled independently, which is the case
|
||||
for krait cores. So reintroduce it.
|
||||
|
||||
* extend the new cpufreq_dt_platform_data definition in cpufreq-dt.h
|
||||
* use new cpufreq-dt.h in qcom-cpufreq.c
|
||||
Signed-off-by: Sricharan R <sricharan@codeaurora.org>
|
||||
---
|
||||
drivers/cpufreq/cpufreq-dt.c | 7 ++++++-
|
||||
drivers/cpufreq/cpufreq-dt.h | 6 ++++++
|
||||
2 files changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
Signed-off-by: Hannu Nyman <hannu.nyman@iki.fi>
|
||||
|
||||
--- a/drivers/cpufreq/cpufreq-dt.h
|
||||
+++ b/drivers/cpufreq/cpufreq-dt.h
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
struct cpufreq_dt_platform_data {
|
||||
bool have_governor_per_policy;
|
||||
+ bool independent_clocks;
|
||||
};
|
||||
|
||||
#endif /* __CPUFREQ_DT_H__ */
|
||||
--- a/drivers/cpufreq/cpufreq-dt.c
|
||||
+++ b/drivers/cpufreq/cpufreq-dt.c
|
||||
@@ -221,7 +221,10 @@ static int cpufreq_init(struct cpufreq_p
|
||||
|
@ -38,19 +44,23 @@ Signed-off-by: Hannu Nyman <hannu.nyman@iki.fi>
|
|||
if (data && data->have_governor_per_policy)
|
||||
dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY;
|
||||
|
||||
+ dt_cpufreq_driver.driver_data = dev_get_platdata(&pdev->dev);
|
||||
+ dt_cpufreq_driver.driver_data = data;
|
||||
+
|
||||
ret = cpufreq_register_driver(&dt_cpufreq_driver);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed register driver: %d\n", ret);
|
||||
--- a/drivers/cpufreq/qcom-cpufreq.c
|
||||
+++ b/drivers/cpufreq/qcom-cpufreq.c
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/slab.h>
|
||||
-#include <linux/cpufreq-dt.h>
|
||||
+#include "cpufreq-dt.h"
|
||||
--- a/drivers/cpufreq/cpufreq-dt.h
|
||||
+++ b/drivers/cpufreq/cpufreq-dt.h
|
||||
@@ -13,6 +13,12 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
struct cpufreq_dt_platform_data {
|
||||
+ /*
|
||||
+ * True when each CPU has its own clock to control its
|
||||
+ * frequency, false when all CPUs are controlled by a single
|
||||
+ * clock.
|
||||
+ */
|
||||
+ bool independent_clocks;
|
||||
bool have_governor_per_policy;
|
||||
};
|
||||
|
||||
static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver)
|
||||
{
|
||||
|
|
|
@ -1,372 +0,0 @@
|
|||
From f72c5aa18281c44945fea6181d0d816a7605505c Mon Sep 17 00:00:00 2001
|
||||
From: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
Date: Wed, 18 Mar 2015 17:23:29 +0200
|
||||
Subject: [PATCH 57/69] clk: qcom: Add regmap mux-div clocks support
|
||||
|
||||
Add support for hardware that can switch both parent clocks and divider
|
||||
at the same time. This avoids generating intermediate frequencies from
|
||||
either the old parent clock and new divider or new parent clock and
|
||||
old divider combinations.
|
||||
|
||||
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
|
||||
---
|
||||
drivers/clk/qcom/Makefile | 1 +
|
||||
drivers/clk/qcom/clk-regmap-mux-div.c | 272 ++++++++++++++++++++++++++++++++++
|
||||
drivers/clk/qcom/clk-regmap-mux-div.h | 65 ++++++++
|
||||
3 files changed, 338 insertions(+)
|
||||
create mode 100644 drivers/clk/qcom/clk-regmap-mux-div.c
|
||||
create mode 100644 drivers/clk/qcom/clk-regmap-mux-div.h
|
||||
|
||||
--- a/drivers/clk/qcom/Makefile
|
||||
+++ b/drivers/clk/qcom/Makefile
|
||||
@@ -9,6 +9,7 @@ clk-qcom-y += clk-rcg2.o
|
||||
clk-qcom-y += clk-branch.o
|
||||
clk-qcom-y += clk-regmap-divider.o
|
||||
clk-qcom-y += clk-regmap-mux.o
|
||||
+clk-qcom-y += clk-regmap-mux-div.o
|
||||
clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
|
||||
clk-qcom-y += clk-hfpll.o
|
||||
clk-qcom-y += reset.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/qcom/clk-regmap-mux-div.c
|
||||
@@ -0,0 +1,272 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2015, Linaro Limited
|
||||
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This software is licensed under the terms of the GNU General Public
|
||||
+ * License version 2, as published by the Free Software Foundation, and
|
||||
+ * may be copied, distributed, and modified under those terms.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/bitops.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include "clk-regmap-mux-div.h"
|
||||
+
|
||||
+#define CMD_RCGR 0x0
|
||||
+#define CMD_RCGR_UPDATE BIT(0)
|
||||
+#define CMD_RCGR_DIRTY_CFG BIT(4)
|
||||
+#define CMD_RCGR_ROOT_OFF BIT(31)
|
||||
+#define CFG_RCGR 0x4
|
||||
+
|
||||
+#define to_clk_regmap_mux_div(_hw) \
|
||||
+ container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr)
|
||||
+
|
||||
+int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div)
|
||||
+{
|
||||
+ int ret, count;
|
||||
+ u32 val, mask;
|
||||
+ const char *name = clk_hw_get_name(&md->clkr.hw);
|
||||
+
|
||||
+ val = (div << md->hid_shift) | (src << md->src_shift);
|
||||
+ mask = ((BIT(md->hid_width) - 1) << md->hid_shift) |
|
||||
+ ((BIT(md->src_width) - 1) << md->src_shift);
|
||||
+
|
||||
+ ret = regmap_update_bits(md->clkr.regmap, CFG_RCGR + md->reg_offset,
|
||||
+ mask, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_update_bits(md->clkr.regmap, CMD_RCGR + md->reg_offset,
|
||||
+ CMD_RCGR_UPDATE, CMD_RCGR_UPDATE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Wait for update to take effect */
|
||||
+ for (count = 500; count > 0; count--) {
|
||||
+ ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset,
|
||||
+ &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ if (!(val & CMD_RCGR_UPDATE))
|
||||
+ return 0;
|
||||
+ udelay(1);
|
||||
+ }
|
||||
+
|
||||
+ pr_err("%s: RCG did not update its configuration", name);
|
||||
+ return -EBUSY;
|
||||
+}
|
||||
+
|
||||
+static void __mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src,
|
||||
+ u32 *div)
|
||||
+{
|
||||
+ u32 val, __div, __src;
|
||||
+ const char *name = clk_hw_get_name(&md->clkr.hw);
|
||||
+
|
||||
+ regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, &val);
|
||||
+
|
||||
+ if (val & CMD_RCGR_DIRTY_CFG) {
|
||||
+ pr_err("%s: RCG configuration is pending\n", name);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ regmap_read(md->clkr.regmap, CFG_RCGR + md->reg_offset, &val);
|
||||
+ __src = (val >> md->src_shift);
|
||||
+ __src &= BIT(md->src_width) - 1;
|
||||
+ *src = __src;
|
||||
+
|
||||
+ __div = (val >> md->hid_shift);
|
||||
+ __div &= BIT(md->hid_width) - 1;
|
||||
+ *div = __div;
|
||||
+}
|
||||
+
|
||||
+static int mux_div_enable(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+
|
||||
+ return __mux_div_set_src_div(md, md->src, md->div);
|
||||
+}
|
||||
+
|
||||
+static inline bool is_better_rate(unsigned long req, unsigned long best,
|
||||
+ unsigned long new)
|
||||
+{
|
||||
+ return (req <= new && new < best) || (best < req && best < new);
|
||||
+}
|
||||
+
|
||||
+static int mux_div_determine_rate(struct clk_hw *hw,
|
||||
+ struct clk_rate_request *req)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+ unsigned int i, div, max_div;
|
||||
+ unsigned long actual_rate, best_rate = 0;
|
||||
+ unsigned long req_rate = req->rate;
|
||||
+
|
||||
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
|
||||
+ unsigned long parent_rate = clk_hw_get_rate(parent);
|
||||
+
|
||||
+ max_div = BIT(md->hid_width) - 1;
|
||||
+ for (div = 1; div < max_div; div++) {
|
||||
+ parent_rate = mult_frac(req_rate, div, 2);
|
||||
+ parent_rate = clk_hw_round_rate(parent, parent_rate);
|
||||
+ actual_rate = mult_frac(parent_rate, 2, div);
|
||||
+
|
||||
+ if (is_better_rate(req_rate, best_rate, actual_rate)) {
|
||||
+ best_rate = actual_rate;
|
||||
+ req->rate = best_rate;
|
||||
+ req->best_parent_rate = parent_rate;
|
||||
+ req->best_parent_hw = parent;
|
||||
+ }
|
||||
+
|
||||
+ if (actual_rate < req_rate || best_rate <= req_rate)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!best_rate)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
|
||||
+ unsigned long prate, u32 src)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+ int ret;
|
||||
+ u32 div, max_div, best_src = 0, best_div = 0;
|
||||
+ unsigned int i;
|
||||
+ unsigned long actual_rate, best_rate = 0;
|
||||
+
|
||||
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
|
||||
+ unsigned long parent_rate = clk_hw_get_rate(parent);
|
||||
+
|
||||
+ max_div = BIT(md->hid_width) - 1;
|
||||
+ for (div = 1; div < max_div; div++) {
|
||||
+ parent_rate = mult_frac(rate, div, 2);
|
||||
+ parent_rate = clk_hw_round_rate(parent, parent_rate);
|
||||
+ actual_rate = mult_frac(parent_rate, 2, div);
|
||||
+
|
||||
+ if (is_better_rate(rate, best_rate, actual_rate)) {
|
||||
+ best_rate = actual_rate;
|
||||
+ best_src = md->parent_map[i].cfg;
|
||||
+ best_div = div - 1;
|
||||
+ }
|
||||
+
|
||||
+ if (actual_rate < rate || best_rate <= rate)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ret = __mux_div_set_src_div(md, best_src, best_div);
|
||||
+ if (!ret) {
|
||||
+ md->div = best_div;
|
||||
+ md->src = best_src;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static u8 mux_div_get_parent(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+ const char *name = clk_hw_get_name(hw);
|
||||
+ u32 i, div, src = 0;
|
||||
+
|
||||
+ __mux_div_get_src_div(md, &src, &div);
|
||||
+
|
||||
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++)
|
||||
+ if (src == md->parent_map[i].cfg)
|
||||
+ return i;
|
||||
+
|
||||
+ pr_err("%s: Can't find parent with src %d\n", name, src);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mux_div_set_parent(struct clk_hw *hw, u8 index)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+
|
||||
+ return __mux_div_set_src_div(md, md->parent_map[index].cfg, md->div);
|
||||
+}
|
||||
+
|
||||
+static int mux_div_set_rate(struct clk_hw *hw,
|
||||
+ unsigned long rate, unsigned long prate)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+
|
||||
+ return __mux_div_set_rate_and_parent(hw, rate, prate, md->src);
|
||||
+}
|
||||
+
|
||||
+static int mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
|
||||
+ unsigned long prate, u8 index)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+
|
||||
+ return __mux_div_set_rate_and_parent(hw, rate, prate,
|
||||
+ md->parent_map[index].cfg);
|
||||
+}
|
||||
+
|
||||
+static unsigned long mux_div_recalc_rate(struct clk_hw *hw, unsigned long prate)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+ u32 div, src;
|
||||
+ int i, num_parents = clk_hw_get_num_parents(hw);
|
||||
+ const char *name = clk_hw_get_name(hw);
|
||||
+
|
||||
+ __mux_div_get_src_div(md, &src, &div);
|
||||
+ for (i = 0; i < num_parents; i++)
|
||||
+ if (src == md->parent_map[i].cfg) {
|
||||
+ struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
|
||||
+ unsigned long parent_rate = clk_hw_get_rate(p);
|
||||
+
|
||||
+ return mult_frac(parent_rate, 2, div + 1);
|
||||
+ }
|
||||
+
|
||||
+ pr_err("%s: Can't find parent %d\n", name, src);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct clk_hw *mux_div_get_safe_parent(struct clk_hw *hw,
|
||||
+ unsigned long *safe_freq)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+
|
||||
+ if (md->safe_freq)
|
||||
+ *safe_freq = md->safe_freq;
|
||||
+
|
||||
+ for (i = 0; i < clk_hw_get_num_parents(hw); i++)
|
||||
+ if (md->safe_src == md->parent_map[i].cfg)
|
||||
+ break;
|
||||
+
|
||||
+ return clk_hw_get_parent_by_index(hw, i);
|
||||
+}
|
||||
+
|
||||
+static void mux_div_disable(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
|
||||
+
|
||||
+ __mux_div_set_src_div(md, md->safe_src, md->safe_div);
|
||||
+}
|
||||
+
|
||||
+const struct clk_ops clk_regmap_mux_div_ops = {
|
||||
+ .enable = mux_div_enable,
|
||||
+ .disable = mux_div_disable,
|
||||
+ .get_parent = mux_div_get_parent,
|
||||
+ .set_parent = mux_div_set_parent,
|
||||
+ .set_rate = mux_div_set_rate,
|
||||
+ .set_rate_and_parent = mux_div_set_rate_and_parent,
|
||||
+ .determine_rate = mux_div_determine_rate,
|
||||
+ .recalc_rate = mux_div_recalc_rate,
|
||||
+ .get_safe_parent = mux_div_get_safe_parent,
|
||||
+};
|
||||
+EXPORT_SYMBOL_GPL(clk_regmap_mux_div_ops);
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/qcom/clk-regmap-mux-div.h
|
||||
@@ -0,0 +1,65 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2015, Linaro Limited
|
||||
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * This software is licensed under the terms of the GNU General Public
|
||||
+ * License version 2, as published by the Free Software Foundation, and
|
||||
+ * may be copied, distributed, and modified under those terms.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __QCOM_CLK_REGMAP_MUX_DIV_H__
|
||||
+#define __QCOM_CLK_REGMAP_MUX_DIV_H__
|
||||
+
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include "clk-rcg.h"
|
||||
+#include "clk-regmap.h"
|
||||
+
|
||||
+/**
|
||||
+ * struct mux_div_clk - combined mux/divider clock
|
||||
+ * @reg_offset: offset of the mux/divider register
|
||||
+ * @hid_width: number of bits in half integer divider
|
||||
+ * @hid_shift: lowest bit of hid value field
|
||||
+ * @src_width: number of bits in source select
|
||||
+ * @src_shift: lowest bit of source select field
|
||||
+ * @div: the divider raw configuration value
|
||||
+ * @src: the mux index which will be used if the clock is enabled
|
||||
+ * @safe_src: the safe source mux value we switch to, while the main PLL is
|
||||
+ * reconfigured
|
||||
+ * @safe_div: the safe divider value that we set, while the main PLL is
|
||||
+ * reconfigured
|
||||
+ * @safe_freq: When switching rates from A to B, the mux div clock will
|
||||
+ * instead switch from A -> safe_freq -> B. This allows the
|
||||
+ * mux_div clock to change rates while enabled, even if this
|
||||
+ * behavior is not supported by the parent clocks.
|
||||
+ * If changing the rate of parent A also causes the rate of
|
||||
+ * parent B to change, then safe_freq must be defined.
|
||||
+ * safe_freq is expected to have a source clock which is always
|
||||
+ * on and runs at only one rate.
|
||||
+ * @parent_map: pointer to parent_map struct
|
||||
+ * @clkr: handle between common and hardware-specific interfaces
|
||||
+ */
|
||||
+
|
||||
+struct clk_regmap_mux_div {
|
||||
+ u32 reg_offset;
|
||||
+ u32 hid_width;
|
||||
+ u32 hid_shift;
|
||||
+ u32 src_width;
|
||||
+ u32 src_shift;
|
||||
+ u32 div;
|
||||
+ u32 src;
|
||||
+ u32 safe_src;
|
||||
+ u32 safe_div;
|
||||
+ unsigned long safe_freq;
|
||||
+ const struct parent_map *parent_map;
|
||||
+ struct clk_regmap clkr;
|
||||
+};
|
||||
+
|
||||
+extern const struct clk_ops clk_regmap_mux_div_ops;
|
||||
+int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div);
|
||||
+
|
||||
+#endif
|
|
@ -14,7 +14,7 @@ Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
|
|||
|
||||
--- a/drivers/clk/qcom/gcc-ipq806x.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq806x.c
|
||||
@@ -1234,6 +1234,8 @@ static struct clk_rcg prng_src = {
|
||||
@@ -1233,6 +1233,8 @@ static struct clk_rcg prng_src = {
|
||||
.parent_map = gcc_pxo_pll8_map,
|
||||
},
|
||||
.clkr = {
|
||||
|
|
Loading…
Reference in a new issue