[1/3] clk: add flag for clocks that need to be enabled on rate changes
diff mbox

Message ID 1929669.AsgMSusdJb@phil
State New
Headers show

Commit Message

Heiko Stuebner Aug. 21, 2015, 5:46 p.m. UTC
Some clocks need to be enabled to accept rate changes. This patch adds a
new flag CLK_SET_RATE_UNGATE that lets clk_change_rate enable the clock
before trying to change the rate and disable it again afterwards.
This of course doesn't effect clocks that are already running at that
point, as their refcount will only temporarily increase.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/clk/clk.c            | 18 ++++++++++++++++++
 include/linux/clk-provider.h |  1 +
 2 files changed, 19 insertions(+)

Comments

Heiko Stuebner Oct. 2, 2015, 2:12 p.m. UTC | #1
Hi,

any comment on these 3 patches?

Thanks
Heiko

Am Freitag, 21. August 2015, 19:46:31 schrieb Heiko Stuebner:
> Some clocks need to be enabled to accept rate changes. This patch adds a
> new flag CLK_SET_RATE_UNGATE that lets clk_change_rate enable the clock
> before trying to change the rate and disable it again afterwards.
> This of course doesn't effect clocks that are already running at that
> point, as their refcount will only temporarily increase.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> ---
>  drivers/clk/clk.c            | 18 ++++++++++++++++++
>  include/linux/clk-provider.h |  1 +
>  2 files changed, 19 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 28cd923..564f11e 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -1438,6 +1438,15 @@ static void clk_change_rate(struct clk_core *core)
>  	else if (core->parent)
>  		best_parent_rate = core->parent->rate;
> 
> +	if (core->flags & CLK_SET_RATE_UNGATE) {
> +		unsigned long flags;
> +
> +		clk_core_prepare(core);
> +		flags = clk_enable_lock();
> +		clk_core_enable(core);
> +		clk_enable_unlock(flags);
> +	}
> +
>  	if (core->new_parent && core->new_parent != core->parent) {
>  		old_parent = __clk_set_parent_before(core, core->new_parent);
>  		trace_clk_set_parent(core, core->new_parent);
> @@ -1464,6 +1473,15 @@ static void clk_change_rate(struct clk_core *core)
> 
>  	core->rate = clk_recalc(core, best_parent_rate);
> 
> +	if (core->flags & CLK_SET_RATE_UNGATE) {
> +		unsigned long flags;
> +
> +		flags = clk_enable_lock();
> +		clk_core_disable(core);
> +		clk_enable_unlock(flags);
> +		clk_core_unprepare(core);
> +	}
> +
>  	if (core->notifier_count && old_rate != core->rate)
>  		__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
> 
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 3ecc07d..21e0025 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -31,6 +31,7 @@
>  #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change
> */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk
> accuracy */ #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after
> notifications */ +#define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run
> to set rate */
> 
>  struct clk;
>  struct clk_hw;
Sjoerd Simons Oct. 5, 2015, 7:09 p.m. UTC | #2
On Fri, 2015-08-21 at 19:46 +0200, Heiko Stuebner wrote:
> Some clocks need to be enabled to accept rate changes. This patch
> adds a
> new flag CLK_SET_RATE_UNGATE that lets clk_change_rate enable the
> clock
> before trying to change the rate and disable it again afterwards.
> This of course doesn't effect clocks that are already running at that
> point, as their refcount will only temporarily increase.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>

Tested-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>
Reviewed-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk>

> ---
>  drivers/clk/clk.c            | 18 ++++++++++++++++++
>  include/linux/clk-provider.h |  1 +
>  2 files changed, 19 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 28cd923..564f11e 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -1438,6 +1438,15 @@ static void clk_change_rate(struct clk_core
> *core)
>  	else if (core->parent)
>  		best_parent_rate = core->parent->rate;
>  
> +	if (core->flags & CLK_SET_RATE_UNGATE) {
> +		unsigned long flags;
> +
> +		clk_core_prepare(core);
> +		flags = clk_enable_lock();
> +		clk_core_enable(core);
> +		clk_enable_unlock(flags);
> +	}
> +
>  	if (core->new_parent && core->new_parent != core->parent) {
>  		old_parent = __clk_set_parent_before(core, core
> ->new_parent);
>  		trace_clk_set_parent(core, core->new_parent);
> @@ -1464,6 +1473,15 @@ static void clk_change_rate(struct clk_core
> *core)
>  
>  	core->rate = clk_recalc(core, best_parent_rate);
>  
> +	if (core->flags & CLK_SET_RATE_UNGATE) {
> +		unsigned long flags;
> +
> +		flags = clk_enable_lock();
> +		clk_core_disable(core);
> +		clk_enable_unlock(flags);
> +		clk_core_unprepare(core);
> +	}
> +
>  	if (core->notifier_count && old_rate != core->rate)
>  		__clk_notify(core, POST_RATE_CHANGE, old_rate, core
> ->rate);
>  
> diff --git a/include/linux/clk-provider.h b/include/linux/clk
> -provider.h
> index 3ecc07d..21e0025 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -31,6 +31,7 @@
>  #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate
> change */
>  #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk
> accuracy */
>  #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after
> notifications */
> +#define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to
> set rate */
>  
>  struct clk;
>  struct clk_hw;
Stephen Boyd Oct. 8, 2015, 9:58 p.m. UTC | #3
On 10/02, Heiko Stübner wrote:
> Hi,
> 
> any comment on these 3 patches?
> 

Dong has a similar problem, but those patches conflate this with
enabling parent clocks during clk_disable_unused() which makes no
sense to me. So I'm ok with the requirement that we turn clocks
on to change rates, but I wonder if in this case we need to turn
on the clock that's changing rates itself, or if we just need to
turn on the parent and/or future parent of the clock during the
rate switch. Care to elaborate on that?
Heiko Stuebner Oct. 11, 2015, 10:41 a.m. UTC | #4
Hi Stephen,

Am Donnerstag, 8. Oktober 2015, 14:58:40 schrieb Stephen Boyd:
> On 10/02, Heiko Stübner wrote:
> > Hi,
> > 
> > any comment on these 3 patches?
> 
> Dong has a similar problem, but those patches conflate this with
> enabling parent clocks during clk_disable_unused() which makes no
> sense to me. So I'm ok with the requirement that we turn clocks
> on to change rates, but I wonder if in this case we need to turn
> on the clock that's changing rates itself, or if we just need to
> turn on the parent and/or future parent of the clock during the
> rate switch. Care to elaborate on that?

As you can see in the follow-up patches, the fractional dividers on Rockchip 
SoCs are quite strange in that they even need to have their _downstream_ mux 
point to them to actually accept rate changes.

The register value always reflects the value set by the system, but hardware 
really only accepts it if the clock is enabled and even the downstream mux 
selects the fractional divider as parent (they call it a auto-gating feature).

So in the worst (and current) case, you end up with the register showing the 
right value, but the hardware can use completely different dividers from the 
previous setting.

That strange behaviour got quite deeply investigated between Rockchip and 
Google engineers who stumbled upon this in the first place, so I'm reasonably 
sure this is the right solution for that clock type :-) .


Heiko
Heiko Stuebner Oct. 12, 2015, 4:03 p.m. UTC | #5
Am Sonntag, 11. Oktober 2015, 12:41:09 schrieb Heiko Stübner:
> Hi Stephen,
> 
> Am Donnerstag, 8. Oktober 2015, 14:58:40 schrieb Stephen Boyd:
> > On 10/02, Heiko Stübner wrote:
> > > Hi,
> > > 
> > > any comment on these 3 patches?
> > 
> > Dong has a similar problem, but those patches conflate this with
> > enabling parent clocks during clk_disable_unused() which makes no
> > sense to me. So I'm ok with the requirement that we turn clocks
> > on to change rates, but I wonder if in this case we need to turn
> > on the clock that's changing rates itself, or if we just need to
> > turn on the parent and/or future parent of the clock during the
> > rate switch. Care to elaborate on that?
> 
> As you can see in the follow-up patches, the fractional dividers on Rockchip
> SoCs are quite strange in that they even need to have their _downstream_
> mux point to them to actually accept rate changes.
> 
> The register value always reflects the value set by the system, but hardware
> really only accepts it if the clock is enabled and even the downstream mux
> selects the fractional divider as parent (they call it a auto-gating
> feature).
> 
> So in the worst (and current) case, you end up with the register showing the
> right value, but the hardware can use completely different dividers from
> the previous setting.
> 
> That strange behaviour got quite deeply investigated between Rockchip and
> Google engineers who stumbled upon this in the first place, so I'm
> reasonably sure this is the right solution for that clock type :-) .

Xing Zheng now also independently stumbled upon this issue with his rk3036 
work. And came to the same conclusion that the gate must be enabled as well as 
the downstream mux be set to the fractional divider for it to actually accept 
a new setting.
zhengxing Oct. 13, 2015, 3:34 a.m. UTC | #6
Hi,

On 2015?10?13? 00:03, Heiko Stübner wrote:
> Am Sonntag, 11. Oktober 2015, 12:41:09 schrieb Heiko Stübner:
>> Hi Stephen,
>>
>> Am Donnerstag, 8. Oktober 2015, 14:58:40 schrieb Stephen Boyd:
>>> On 10/02, Heiko Stübner wrote:
>>>> Hi,
>>>>
>>>> any comment on these 3 patches?
>>> Dong has a similar problem, but those patches conflate this with
>>> enabling parent clocks during clk_disable_unused() which makes no
>>> sense to me. So I'm ok with the requirement that we turn clocks
>>> on to change rates, but I wonder if in this case we need to turn
>>> on the clock that's changing rates itself, or if we just need to
>>> turn on the parent and/or future parent of the clock during the
>>> rate switch. Care to elaborate on that?
>> As you can see in the follow-up patches, the fractional dividers on Rockchip
>> SoCs are quite strange in that they even need to have their _downstream_
>> mux point to them to actually accept rate changes.
>>
>> The register value always reflects the value set by the system, but hardware
>> really only accepts it if the clock is enabled and even the downstream mux
>> selects the fractional divider as parent (they call it a auto-gating
>> feature).
>>
>> So in the worst (and current) case, you end up with the register showing the
>> right value, but the hardware can use completely different dividers from
>> the previous setting.
>>
>> That strange behaviour got quite deeply investigated between Rockchip and
>> Google engineers who stumbled upon this in the first place, so I'm
>> reasonably sure this is the right solution for that clock type :-) .
> Xing Zheng now also independently stumbled upon this issue with his rk3036
> work. And came to the same conclusion that the gate must be enabled as well as
> the downstream mux be set to the fractional divider for it to actually accept
> a new setting.
Yes, I discussed such problems with Heiko about the question:
The RK3036 i2s frac(CRU_SEL7_CON) set value is invalid when I playback a 
48KHz music:
/ # io -4 0x20000060
20000060: 01003057
read register is 0x01003057, but the result of frac divider on the basis 
of default 0x0bb8ea60(numerator=3000, denominator=60000, ratio=20), so 
the out of mclk remains 594/20=29.7MHz

I tracked the logs:
[ 49.770322] clk_fd_set_rate: 91, name: i2s_frac, rate = 12288000, 
parent_rate = 594000000
[ 49.778524] clk_fd_set_rate: 107, name: i2s_frac, val = 0x01003057
[ 49.784714] clk_fd_recalc_rate: 29, name: i2s_frac, parent_rate = 594000000
[ 49.791707] clk_fd_recalc_rate: 47, name: i2s_frac, val = 0x01003057, m 
= 256, n = 12375
[ 49.799836] clk_mux_set_parent: 81, name: i2s_pre
It seem like set i2s_frac_div then set mux is i2s_pre. I think we should 
select the correct mux and open clock gate, then set the i2s_frac_div, 
and I tried to do it, setting i2s_frac_div is vaild and mclk is 
12.288MHz. Therefore, I think that select parent mux and enable gate 
should before child node set value.

Thanks. :)

Patch
diff mbox

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 28cd923..564f11e 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1438,6 +1438,15 @@  static void clk_change_rate(struct clk_core *core)
 	else if (core->parent)
 		best_parent_rate = core->parent->rate;
 
+	if (core->flags & CLK_SET_RATE_UNGATE) {
+		unsigned long flags;
+
+		clk_core_prepare(core);
+		flags = clk_enable_lock();
+		clk_core_enable(core);
+		clk_enable_unlock(flags);
+	}
+
 	if (core->new_parent && core->new_parent != core->parent) {
 		old_parent = __clk_set_parent_before(core, core->new_parent);
 		trace_clk_set_parent(core, core->new_parent);
@@ -1464,6 +1473,15 @@  static void clk_change_rate(struct clk_core *core)
 
 	core->rate = clk_recalc(core, best_parent_rate);
 
+	if (core->flags & CLK_SET_RATE_UNGATE) {
+		unsigned long flags;
+
+		flags = clk_enable_lock();
+		clk_core_disable(core);
+		clk_enable_unlock(flags);
+		clk_core_unprepare(core);
+	}
+
 	if (core->notifier_count && old_rate != core->rate)
 		__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 3ecc07d..21e0025 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -31,6 +31,7 @@ 
 #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
 #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
 #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
+#define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to set rate */
 
 struct clk;
 struct clk_hw;