[PATCH v2 1/7] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions

Lukasz Majewski l.majewski at samsung.com
Tue Jan 28 03:17:21 EST 2014


Hi Thomas, Mike

> Hi Mike,
> 
> On Tue, Jan 28, 2014 at 1:55 AM, Mike Turquette
> <mturquette at linaro.org> wrote:
> > Quoting Thomas Abraham (2014-01-18 04:10:51)
> >> From: Thomas Abraham <thomas.ab at samsung.com>
> >>
> >> On some platforms such as the Samsung Exynos, changing the
> >> frequency of the CPU clock requires changing the frequency of the
> >> PLL that is supplying the CPU clock. To change the frequency of
> >> the PLL, the CPU clock is temporarily reparented to another parent
> >> clock.
> >>
> >> The clock frequency of this temporary parent clock could be much
> >> higher than the clock frequency of the PLL at the time of
> >> reparenting. Due to the temporary increase in the CPU clock speed,
> >> the CPU (and any other components in the CPU clock domain such as
> >> dividers, mux, etc.) have to to be operated at a higher voltage
> >> level, called the safe voltage level. This patch adds optional
> >> support to temporarily switch to a safe voltage level during CPU
> >> frequency transitions.
> >>
> >> Cc: Shawn Guo <shawn.guo at linaro.org>
> >> Signed-off-by: Thomas Abraham <thomas.ab at samsung.com>
> >
> > I'm not a fan of this change. This corner case should be abstracted
> > away somehow. I had talked to Chander Kayshap previously about
> > handling voltage changes in clock notifier callbacks, which then
> > renders any voltage change as a trivial part of the clock rate
> > transition. That means that this "safe voltage" thing could be
> > handled automagically without any additional code in the CPUfreq
> > driver.
> >
> > There are two nice ways to do this with the clock framework. First
> > is explicit re-parenting with voltage scaling done in the clock
> > rate-change notifiers:
> >
> > clk_set_parent(cpu_clk, temp_parent);
> > /* implicit voltage scaling to "safe voltage" happens above */
> > clk_set_rate(pll, some_rate);
> > clk_set_parent(cpu_clk, pll);
> > /* implicit voltage scaling to nominal OPP voltage happens above */
> >

I must agree with Mike here. In my opinion the above approach is more
compliant with CCF (as I've pointed it out in my other comment - the
cpu_clk has more than one parent and we could switch between them when
needed). 

> > The above sequence would require a separate exnyos CPUfreq driver,
> > due to the added clk_set_parent logic.
> >
> > The second way to do this is to abstract the clk re-muxing logic out
> > into the clk driver, which would allow cpufreq-cpu0 to be used for
> > the exynos chips.
> 
> This is the approach this patch series takes (patch 2/7). The clock
> re-muxing logic is handled by a clock driver code. The difference from
> what you suggested is that the safe voltage (that may be optionally)
> required before doing the re-muxing is handled here in cpufreq-cpu0
> driver.
> 
> The safe voltage setup can be done in the notifier as you suggested.

If the clk_set_parent() approach is not suitable, then cannot we
consider using the one from highbank-cpufreq.c?

Here we have cpufreq-cpu0.c which sets voltage of the cpu_clk. 
In the highbank-cpufreq.c there are clock notifiers to change the
voltage.

Cannot Exynos reuse such approach? Why shall we pollute cpufreq-cpu0.c
with another solution?

> But, doing that in cpufreq-cpu0 driver will help other platforms reuse
> this feature if required. Also, if done here, the regulator handling
> is localized in this driver which otherwise would need to be handled
> in two places, cpufreq-cpu0 driver and the clock notifier.

I think that there is a logical distinction between setting voltage for
cpufreq-cpu0 related clock and increasing voltage of reparented clock.

The former fits naturally to cpufreq-cpu0, when the latter seems like
some corner case (as Mike pointed out) for Exynos. 

> 
> So I tend to prefer the approach in this patch but I am willing to
> consider any suggestions. 

Thomas, what do you think about highbank-cpufreq.c approach (with
using clock notifiers)? 

Do you think, that it is feasible to reuse it with Exynos?

> Shawn, it would be helpful if you could let
> us know your thoughts on this. I am almost done with testing the v3 of
> this series and want to post it so if there are any objections to the
> changes in this patch, please let me know.
> 
> Thanks,
> Thomas.
> 
> >
> > I'm more a fan of explicitly listing the Exact Steps for the cpu opp
> > transition in a separate exynos-specific CPUfreq driver, but that's
> > probably an unpopular view.
> >
> > Regards,
> > Mike
> >
> >> ---
> >>  .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt   |    7 ++++
> >>  drivers/cpufreq/cpufreq-cpu0.c                     |   37
> >> +++++++++++++++++-- 2 files changed, 40 insertions(+), 4
> >> deletions(-)
> >>
> >> diff --git
> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index
> >> f055515..37453ab 100644 ---
> >> a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++
> >> b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@
> >> -19,6 +19,12 @@ Optional properties:
> >>  - cooling-min-level:
> >>  - cooling-max-level:
> >>       Please refer to
> >> Documentation/devicetree/bindings/thermal/thermal.txt. +-
> >> safe-opp: Certain platforms require that during a opp transition,
> >> +  a system should not go below a particular opp level. For such
> >> systems,
> >> +  this property specifies the minimum opp to be maintained during
> >> the
> >> +  opp transitions. The safe-opp value is a tuple with first
> >> element
> >> +  representing the safe frequency and the second element
> >> representing the
> >> +  safe voltage.
> >>
> >>  Examples:
> >>
> >> @@ -36,6 +42,7 @@ cpus {
> >>                         396000  950000
> >>                         198000  850000
> >>                 >;
> >> +               safe-opp = <396000 950000>
> >>                 clock-latency = <61036>; /* two CLK32 periods */
> >>                 #cooling-cells = <2>;
> >>                 cooling-min-level = <0>;
> >> diff --git a/drivers/cpufreq/cpufreq-cpu0.c
> >> b/drivers/cpufreq/cpufreq-cpu0.c index 0c12ffc..075d3d1 100644
> >> --- a/drivers/cpufreq/cpufreq-cpu0.c
> >> +++ b/drivers/cpufreq/cpufreq-cpu0.c
> >> @@ -27,6 +27,8 @@
> >>
> >>  static unsigned int transition_latency;
> >>  static unsigned int voltage_tolerance; /* in percentage */
> >> +static unsigned long safe_frequency;
> >> +static unsigned long safe_voltage;
> >>
> >>  static struct device *cpu_dev;
> >>  static struct clk *cpu_clk;
> >> @@ -64,17 +66,30 @@ static int cpu0_set_target(struct
> >> cpufreq_policy *policy, unsigned int index) volt_old =
> >> regulator_get_voltage(cpu_reg); }
> >>
> >> -       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >> +       pr_debug("\n\n%u MHz, %ld mV --> %u MHz, %ld mV\n",
> >>                  old_freq / 1000, volt_old ? volt_old / 1000 : -1,
> >>                  new_freq / 1000, volt ? volt / 1000 : -1);
> >>
> >>         /* scaling up?  scale voltage before frequency */
> >> -       if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
> >> +       if (!IS_ERR(cpu_reg) && new_freq > old_freq &&
> >> +                               new_freq >= safe_frequency) {
> >>                 ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> tol); if (ret) {
> >>                         pr_err("failed to scale voltage up: %d\n",
> >> ret); return ret;
> >>                 }
> >> +       } else if (!IS_ERR(cpu_reg) && old_freq < safe_frequency) {
> >> +               /*
> >> +                * the scaled up voltage level for the new_freq is
> >> lower
> >> +                * than the safe voltage level. so set safe_voltage
> >> +                * as the intermediate voltage level and revert it
> >> +                * back after the frequency has been changed.
> >> +                */
> >> +               ret = regulator_set_voltage_tol(cpu_reg,
> >> safe_voltage, tol);
> >> +               if (ret) {
> >> +                       pr_err("failed to set safe voltage: %d\n",
> >> ret);
> >> +                       return ret;
> >> +               }
> >>         }
> >>
> >>         ret = clk_set_rate(cpu_clk, freq_exact);
> >> @@ -86,7 +101,8 @@ static int cpu0_set_target(struct
> >> cpufreq_policy *policy, unsigned int index) }
> >>
> >>         /* scaling down?  scale voltage after frequency */
> >> -       if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
> >> +       if (!IS_ERR(cpu_reg) &&
> >> +                       (new_freq < old_freq || new_freq <
> >> safe_frequency)) { ret = regulator_set_voltage_tol(cpu_reg, volt,
> >> tol); if (ret) {
> >>                         pr_err("failed to scale voltage down:
> >> %d\n", ret); @@ -116,6 +132,8 @@ static struct cpufreq_driver
> >> cpu0_cpufreq_driver = {
> >>
> >>  static int cpu0_cpufreq_probe(struct platform_device *pdev)
> >>  {
> >> +       const struct property *prop;
> >> +       struct dev_pm_opp *opp;
> >>         struct device_node *np;
> >>         int ret;
> >>
> >> @@ -165,13 +183,24 @@ static int cpu0_cpufreq_probe(struct
> >> platform_device *pdev) goto out_put_node;
> >>         }
> >>
> >> +       prop = of_find_property(np, "safe-opp", NULL);
> >> +       if (prop) {
> >> +               if (prop->value && (prop->length / sizeof(u32)) ==
> >> 2) {
> >> +                       const __be32 *val;
> >> +                       val = prop->value;
> >> +                       safe_frequency = be32_to_cpup(val++);
> >> +                       safe_voltage = be32_to_cpup(val);
> >> +               } else {
> >> +                       pr_err("invalid safe-opp level
> >> specified\n");
> >> +               }
> >> +       }
> >> +
> >>         of_property_read_u32(np, "voltage-tolerance",
> >> &voltage_tolerance);
> >>
> >>         if (of_property_read_u32(np, "clock-latency",
> >> &transition_latency)) transition_latency = CPUFREQ_ETERNAL;
> >>
> >>         if (!IS_ERR(cpu_reg)) {
> >> -               struct dev_pm_opp *opp;
> >>                 unsigned long min_uV, max_uV;
> >>                 int i;
> >>
> >> --
> >> 1.6.6.rc2
> >>



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group



More information about the linux-arm-kernel mailing list