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:
Pavel Kubelun 2017-12-09 20:15:05 +03:00 committed by Felix Fietkau
parent 83499bef73
commit 7903a9219c
16 changed files with 388 additions and 814 deletions

View file

@ -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> 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 Krait CPUs have a handful of L2 cache controller registers that
live behind a cp15 based indirection register. First you program live behind a cp15 based indirection register. First you program

View file

@ -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> 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 We want to reuse the logic in clk-mux.c for other clock drivers
that don't use readl as register accessors. Fortunately, there 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. drivers can use the same logic.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
--- ---
drivers/clk/clk-mux.c | 76 ++++++++++++++++++++++++++++---------------- drivers/clk/clk-mux.c | 75 +++++++++++++++++++++++++++-----------------
include/linux/clk-provider.h | 11 +++++-- include/linux/clk-provider.h | 9 ++++--
2 files changed, 57 insertions(+), 30 deletions(-) 2 files changed, 54 insertions(+), 30 deletions(-)
--- a/drivers/clk/clk-mux.c --- a/drivers/clk/clk-mux.c
+++ b/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 * parent - parent is adjustable through clk_set_parent
*/ */
-static u8 clk_mux_get_parent(struct clk_hw *hw) -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 clk_mux_get_parent(struct clk_hw *hw, unsigned int val,
+ unsigned int *table, unsigned long flags) + 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); int num_parents = clk_hw_get_num_parents(hw);
- u32 val; - u32 val;
-
- /* - /*
- * FIXME need a mux-specific flag to determine if val is bitwise or numeric - * 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 - * 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 = clk_readl(mux->reg) >> mux->shift;
- val &= mux->mask; - val &= mux->mask;
-
- if (mux->table) { - if (mux->table) {
+ if (table) { + if (table) {
int i; int i;
@ -64,7 +73,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
val--; val--;
if (val >= num_parents) 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; return val;
} }
@ -80,9 +89,9 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
- if (mux->table) { - if (mux->table) {
- index = mux->table[index]; - index = mux->table[index];
+ /* + /*
+ * FIXME need a mux-specific flag to determine if val is bitwise or numeric + * FIXME need a mux-specific flag to determine if val is bitwise or
+ * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 + * numeric e.g. sys_clkin_ck's clksel field is 3 bits wide,
+ * to 0x7 (index starts at one) + * but ranges from 0x1 to 0x7 (index starts at one)
+ * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * 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" + * 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) if (mux->lock)
spin_lock_irqsave(mux->lock, flags); spin_lock_irqsave(mux->lock, flags);
else 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 = { 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); 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, const char * const *parent_names, u8 num_parents,
unsigned long flags, unsigned long flags,
void __iomem *reg, u8 shift, u32 mask, 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, struct clk *clk_register_mux(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, const char * const *parent_names, u8 num_parents,
unsigned long flags, unsigned long flags,
@@ -499,12 +504,12 @@ struct clk *clk_register_mux_table(struc @@ -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,
- 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,
const char * const *parent_names, u8 num_parents, const char * const *parent_names, u8 num_parents,
unsigned long flags, unsigned long flags,
void __iomem *reg, u8 shift, u32 mask, void __iomem *reg, u8 shift, u32 mask,

View file

@ -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;

View file

@ -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,

View file

@ -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> 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 HFPLLs are the main frequency source for Krait CPU clocks. Add
support for changing the rate of these PLLs. 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 + * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe. + * de-asserting the reset. Delay 10us just to be safe.
+ */ + */
+ udelay(10); + usleep_range(10, 100);
+ +
+ /* De-assert active-low PLL reset. */ + /* De-assert active-low PLL reset. */
+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N); + 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); + regmap_read(regmap, hd->status_reg, &val);
+ } while (!(val & BIT(hd->lock_bit))); + } while (!(val & BIT(hd->lock_bit)));
+ } else { + } else {
+ udelay(60); + usleep_range(60, 100);
+ } + }
+ +
+ /* Enable PLL output. */ + /* Enable PLL output. */
@ -151,7 +163,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ * and assert the reset. + * and assert the reset.
+ */ + */
+ regmap_update_bits(regmap, hd->mode_reg, + regmap_update_bits(regmap, hd->mode_reg,
+ PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0); + PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
+} +}
+ +
+static void clk_hfpll_disable(struct clk_hw *hw) +static void clk_hfpll_disable(struct clk_hw *hw)
@ -252,7 +264,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ regmap_read(regmap, hd->status_reg, &status); + regmap_read(regmap, hd->status_reg, &status);
+ if (!(status & BIT(hd->lock_bit))) { + if (!(status & BIT(hd->lock_bit))) {
+ WARN(1, "HFPLL %s is ON, but not locked!\n", + WARN(1, "HFPLL %s is ON, but not locked!\n",
+ __clk_get_name(hw->clk)); + __clk_get_name(hw->clk));
+ clk_hfpll_disable(hw); + clk_hfpll_disable(hw);
+ __clk_hfpll_init_once(hw); + __clk_hfpll_init_once(hw);
+ } + }

View file

@ -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> 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 On some devices (MSM8974 for example), the HFPLLs are
instantiated within the Krait processor subsystem as separate 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> Cc: <devicetree@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.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 ++++++++ .../devicetree/bindings/clock/qcom,hfpll.txt | 40 ++++++++
drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Kconfig | 8 ++
@ -171,7 +182,7 @@ Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+ return PTR_ERR(regmap); + return PTR_ERR(regmap);
+ +
+ if (of_property_read_string_index(dev->of_node, "clock-output-names", + if (of_property_read_string_index(dev->of_node, "clock-output-names",
+ 0, &init.name)) + 0, &init.name))
+ return -ENODEV; + return -ENODEV;
+ +
+ h->d = &hdata; + h->d = &hdata;

View file

@ -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> 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. Describe the HFPLLs present on IPQ806X devices.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
--- ---
drivers/clk/qcom/gcc-ipq806x.c | 83 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/gcc-ipq806x.c | 82 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+) 1 file changed, 82 insertions(+)
--- a/drivers/clk/qcom/gcc-ipq806x.c --- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/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" #include "reset.h"
static struct clk_pll pll0 = { 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), + .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
+}; +};
+
+ +
static struct clk_pll pll14 = { static struct clk_pll pll14 = {
.l_reg = 0x31c4, .l_reg = 0x31c4,
.m_reg = 0x31c8, .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, [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr, [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
[NSSTCM_CLK] = &nss_tcm_clk.clkr, [NSSTCM_CLK] = &nss_tcm_clk.clkr,

View file

@ -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> 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 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 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/Kconfig | 4 ++
drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/clk-krait.c | 167 +++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-krait.c | 134 +++++++++++++++++++++++++++++++++++++++++++
drivers/clk/qcom/clk-krait.h | 49 +++++++++++++ drivers/clk/qcom/clk-krait.h | 48 ++++++++++++++++
4 files changed, 221 insertions(+) 4 files changed, 187 insertions(+)
create mode 100644 drivers/clk/qcom/clk-krait.c create mode 100644 drivers/clk/qcom/clk-krait.c
create mode 100644 drivers/clk/qcom/clk-krait.h 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 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
--- /dev/null --- /dev/null
+++ b/drivers/clk/qcom/clk-krait.c +++ 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. + * 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 */ + /* Don't touch mux if CPU is off as it won't work */
+ if (__clk_is_enabled(hw->clk)) + if (__clk_is_enabled(hw->clk))
+ __krait_mux_set_sel(mux, sel); + __krait_mux_set_sel(mux, sel);
+
+ return 0; + 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); + 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 = { +const struct clk_ops krait_mux_clk_ops = {
+ .enable = krait_mux_enable,
+ .disable = krait_mux_disable,
+ .set_parent = krait_mux_set_parent, + .set_parent = krait_mux_set_parent,
+ .get_parent = krait_mux_get_parent, + .get_parent = krait_mux_get_parent,
+ .determine_rate = __clk_mux_determine_rate_closest, + .determine_rate = __clk_mux_determine_rate_closest,
+ .get_safe_parent = krait_mux_get_safe_parent,
+}; +};
+EXPORT_SYMBOL_GPL(krait_mux_clk_ops); +EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
+ +
@ -169,7 +148,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+} +}
+ +
+static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, +static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate) + unsigned long parent_rate)
+{ +{
+ struct krait_div2_clk *d = to_krait_div2_clk(hw); + struct krait_div2_clk *d = to_krait_div2_clk(hw);
+ unsigned long flags; + unsigned long flags;
@ -211,7 +190,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+EXPORT_SYMBOL_GPL(krait_div2_clk_ops); +EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
--- /dev/null --- /dev/null
+++ b/drivers/clk/qcom/clk-krait.h +++ b/drivers/clk/qcom/clk-krait.h
@@ -0,0 +1,49 @@ @@ -0,0 +1,48 @@
+/* +/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * 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 { +struct krait_mux_clk {
+ unsigned int *parent_map; + unsigned int *parent_map;
+ bool has_safe_parent;
+ u8 safe_sel;
+ u32 offset; + u32 offset;
+ u32 mask; + u32 mask;
+ u32 shift; + u32 shift;
@ -241,6 +218,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ bool lpl; + bool lpl;
+ +
+ struct clk_hw hw; + struct clk_hw hw;
+ struct notifier_block clk_nb;
+}; +};
+ +
+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw) +#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)

View file

@ -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> 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 The ACC and GCC regions present in KPSSv1 contain registers to
control clocks and power to each Krait CPU and L2. For CPUfreq 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 +++++++ .../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 28 +++++++
drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Kconfig | 8 ++
drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/kpss-xcc.c | 95 ++++++++++++++++++++++ drivers/clk/qcom/kpss-xcc.c | 96 ++++++++++++++++++++++
5 files changed, 139 insertions(+) 5 files changed, 140 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
create mode 100644 drivers/clk/qcom/kpss-xcc.c 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 obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
--- /dev/null --- /dev/null
+++ b/drivers/clk/qcom/kpss-xcc.c +++ 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. +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * + *
+ * This program is free software; you can redistribute it and/or modify + * 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 (id->data) {
+ if (of_property_read_string_index(pdev->dev.of_node, + if (of_property_read_string_index(pdev->dev.of_node,
+ "clock-output-names", 0, &name)) + "clock-output-names",
+ 0, &name))
+ return -ENODEV; + return -ENODEV;
+ base += 0x14; + base += 0x14;
+ } else { + } else {

View file

@ -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> 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 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 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 ++ .../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++
drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Kconfig | 8 +
drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++ drivers/clk/qcom/krait-cc.c | 350 +++++++++++++++++++++
4 files changed, 383 insertions(+) 4 files changed, 381 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
create mode 100644 drivers/clk/qcom/krait-cc.c 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 +obj-$(CONFIG_KRAITCC) += krait-cc.o
--- /dev/null --- /dev/null
+++ b/drivers/clk/qcom/krait-cc.c +++ 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. +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * + *
+ * This program is free software; you can redistribute it and/or modify + * 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 +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 krait_div2_clk *div;
+ struct clk_init_data init = { + struct clk_init_data init = {
@ -150,8 +162,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+} +}
+ +
+static int +static int
+krait_add_sec_mux(struct device *dev, int id, const char *s, unsigned offset, +krait_add_sec_mux(struct device *dev, int id, const char *s,
+ bool unique_aux) + unsigned int offset, bool unique_aux)
+{ +{
+ struct krait_mux_clk *mux; + struct krait_mux_clk *mux;
+ static const char *sec_mux_list[] = { + static const char *sec_mux_list[] = {
@ -172,8 +184,6 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ +
+ mux->offset = offset; + mux->offset = offset;
+ mux->lpl = id >= 0; + mux->lpl = id >= 0;
+ mux->has_safe_parent = true;
+ mux->safe_sel = 2;
+ mux->mask = 0x3; + mux->mask = 0x3;
+ mux->shift = 2; + mux->shift = 2;
+ mux->parent_map = sec_mux_map; + mux->parent_map = sec_mux_map;
@ -201,7 +211,8 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+} +}
+ +
+static struct clk * +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; + struct krait_mux_clk *mux;
+ const char *p_names[3]; + const char *p_names[3];
@ -217,8 +228,6 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ if (!mux) + if (!mux)
+ return ERR_PTR(-ENOMEM); + return ERR_PTR(-ENOMEM);
+ +
+ mux->has_safe_parent = true;
+ mux->safe_sel = 0;
+ mux->mask = 0x3; + mux->mask = 0x3;
+ mux->shift = 0; + mux->shift = 0;
+ mux->offset = offset; + 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) +static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
+{ +{
+ int ret; + int ret;
+ unsigned offset; + unsigned int offset;
+ void *p = NULL; + void *p = NULL;
+ const char *s; + const char *s;
+ struct clk *clk; + struct clk *clk;
@ -332,7 +341,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ return -ENODEV; + return -ENODEV;
+ +
+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */ + /* 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)) + if (IS_ERR(clk))
+ return PTR_ERR(clk); + return PTR_ERR(clk);
+ +
@ -370,7 +379,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ for_each_online_cpu(cpu) { + for_each_online_cpu(cpu) {
+ clk_prepare_enable(l2_pri_mux_clk); + clk_prepare_enable(l2_pri_mux_clk);
+ WARN(clk_prepare_enable(clks[cpu]), + WARN(clk_prepare_enable(clks[cpu]),
+ "Unable to turn on CPU%d clock", cpu); + "Unable to turn on CPU%d clock", cpu);
+ } + }
+ +
+ /* + /*
@ -401,6 +410,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu); + pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
+ cur_rate = aux_rate; + cur_rate = aux_rate;
+ } + }
+
+ clk_set_rate(clk, aux_rate); + clk_set_rate(clk, aux_rate);
+ clk_set_rate(clk, 2); + clk_set_rate(clk, 2);
+ clk_set_rate(clk, cur_rate); + clk_set_rate(clk, cur_rate);

View file

@ -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]);

View file

@ -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);

View file

@ -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> 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 Register a cpufreq-generic device whenever we detect that a
"qcom,krait" compatible CPU is present in DT. "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/platform_device.h>
+#include <linux/pm_opp.h> +#include <linux/pm_opp.h>
+#include <linux/slab.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) +static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver)
+{ +{
@ -227,7 +239,7 @@ Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+ } + }
+ +
+ snprintf(table_name, sizeof(table_name), + snprintf(table_name, sizeof(table_name),
+ "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver); + "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver);
+ +
+ if (!of_find_property(np, table_name, &len)) + if (!of_find_property(np, table_name, &len))
+ return -EINVAL; + return -EINVAL;

View file

@ -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 The Platform data was removed earlier by,
removed between kernel 4.4 and 4.9 by upstream commits 'commit eb96924acddc ("cpufreq: dt: Kill platform-data")'
eb96924acddc709db58221c210ca05cd9effb1df and since there were no users at that time.
e86eee6bc2aaa6b3637f6497b26beee09a91bde9 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 Signed-off-by: Sricharan R <sricharan@codeaurora.org>
* use new cpufreq-dt.h in qcom-cpufreq.c ---
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 --- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c
@@ -221,7 +221,10 @@ static int cpufreq_init(struct cpufreq_p @@ -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) if (data && data->have_governor_per_policy)
dt_cpufreq_driver.flags |= CPUFREQ_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); ret = cpufreq_register_driver(&dt_cpufreq_driver);
if (ret) if (ret)
dev_err(&pdev->dev, "failed register driver: %d\n", ret); dev_err(&pdev->dev, "failed register driver: %d\n", ret);
--- a/drivers/cpufreq/qcom-cpufreq.c --- a/drivers/cpufreq/cpufreq-dt.h
+++ b/drivers/cpufreq/qcom-cpufreq.c +++ b/drivers/cpufreq/cpufreq-dt.h
@@ -20,7 +20,7 @@ @@ -13,6 +13,12 @@
#include <linux/platform_device.h> #include <linux/types.h>
#include <linux/pm_opp.h>
#include <linux/slab.h> struct cpufreq_dt_platform_data {
-#include <linux/cpufreq-dt.h> + /*
+#include "cpufreq-dt.h" + * 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)
{

View file

@ -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

View file

@ -14,7 +14,7 @@ Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
--- a/drivers/clk/qcom/gcc-ipq806x.c --- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/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, .parent_map = gcc_pxo_pll8_map,
}, },
.clkr = { .clkr = {