From: Anson Huang <b20788@freescale.com>
To: Shawn Guo <shawn.guo@linaro.org>
Cc: cpufreq@vger.kernel.org, linux-pm@vger.kernel.org,
"Rafael J. Wysocki" <rjw@sisk.pl>,
linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v5] cpufreq: add imx6q-cpufreq driver
Date: Mon, 4 Feb 2013 13:40:18 -0500 [thread overview]
Message-ID: <20130204184018.GA12696@ubuntu> (raw)
In-Reply-To: <20130204050909.GD26233@S2101-09.ap.freescale.net>
On Mon, Feb 04, 2013 at 01:09:11PM +0800, Shawn Guo wrote:
> On Mon, Feb 04, 2013 at 11:06:22AM -0500, Anson Huang wrote:
> > > + /*
> > > + * The setpoints are selected per PLL/PDF frequencies, so we need to
> > > + * reprogram PLL for frequency scaling. The procedure of reprogramming
> > > + * PLL1 is as below.
> > > + *
> > > + * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
> > > + * - Disable pll1_sys_clk and reprogram it
> > > + * - Enable pll1_sys_clk and reparent pll1_sw_clk back to it
> > > + * - Disable pll2_pfd2_396m_clk
> > > + */
> > > + clk_prepare_enable(pll2_pfd2_396m_clk);
> > > + clk_set_parent(step_clk, pll2_pfd2_396m_clk);
> > > + clk_set_parent(pll1_sw_clk, step_clk);
> > > + clk_prepare_enable(pll1_sys_clk);
> > > + if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
> > > + clk_disable_unprepare(pll1_sys_clk);
> > > + clk_set_rate(pll1_sys_clk, freqs.new * 1000);
> > > + clk_prepare_enable(pll1_sys_clk);
> > > + clk_set_parent(pll1_sw_clk, pll1_sys_clk);
> > > + clk_disable_unprepare(pll2_pfd2_396m_clk);
> > > + } else {
> > > + /*
> > > + * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
> > > + * to provide the frequency.
> > > + */
> > > + clk_disable_unprepare(pll1_sys_clk);
> > > + }
> > Seems like we will get pll2_pfd2_396m_clk's use count mismatch? As every time cpu freq is changed, pll2_pfd2_396m_clk will be added at the beginning of this code piece, but only decreased when cpu freq > 396M, so everytime cpu freq changed to 396M, this pll2_pfd2_396m_clk will in increased?
>
> Ah, good catch. And pll1_sys_clk has the same problem. Since it's
> been verified by FSL kernel that we do not necessarily need to disable
> pll1_sys_clk before reprogramming it, I would choose to rewrite the
> code as below to make it cleaner and correct on clock usage.
>
> /*
> * The setpoints are selected per PLL/PDF frequencies, so we need to
> * reprogram PLL for frequency scaling. The procedure of reprogramming
> * PLL1 is as below.
> *
> * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
> * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
> * - Disable pll2_pfd2_396m_clk
> */
> clk_prepare_enable(pll2_pfd2_396m_clk);
> clk_set_parent(step_clk, pll2_pfd2_396m_clk);
> clk_set_parent(pll1_sw_clk, step_clk);
> if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
> clk_set_rate(pll1_sys_clk, freqs.new * 1000);
> /*
> * If we are leaving 396 MHz set-point, we need to enable
> * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
> * their use count correct.
> */
> if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
> clk_prepare_enable(pll1_sys_clk);
> clk_disable_unprepare(pll2_pfd2_396m_clk);
> }
> clk_set_parent(pll1_sw_clk, pll1_sys_clk);
> clk_disable_unprepare(pll2_pfd2_396m_clk);
> } else {
> /*
> * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
> * to provide the frequency.
> */
> clk_disable_unprepare(pll1_sys_clk);
> }
>
Looks good:)
> > > +
> > > + /* Ensure the arm clock divider is what we expect */
> > > + ret = clk_set_rate(arm_clk, freqs.new * 1000);
> > > + if (ret) {
> > > + dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
> > > + regulator_set_voltage_tol(arm_reg, volt_old, 0);
> > > + return ret;
> > > + }
> > > +
> > > + /* scaling down? scale voltage after frequency */
> > > + if (freqs.new < freqs.old) {
> > > + ret = regulator_set_voltage_tol(arm_reg, volt, 0);
> > > + if (ret)
> > > + dev_warn(cpu_dev,
> > > + "failed to scale vddarm down: %d\n", ret);
> > > +
> > > + if (freqs.old == FREQ_1P2_GHZ / 1000) {
> > > + regulator_set_voltage_tol(pu_reg,
> > > + PU_SOC_VOLTAGE_NORMAL, 0);
> > > + regulator_set_voltage_tol(soc_reg,
> > > + PU_SOC_VOLTAGE_NORMAL, 0);
> > > + }
> > > + }
> > > +
> > > + for_each_online_cpu(cpu) {
> > > + freqs.cpu = cpu;
> > > + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> > > + }
> > > +
> > Should we need to update the percpu loops_per_jiffy variable and global loops_per_jiffy? As the udelay and mdelay will rely on this global loops_per_jiffy? Or the latest kernel has handle it in other place such as cpufreq common driver? I remembered that common cpufreq driver only handle the noSMP case.
>
> No, it's not needed since commit ec971ea (ARM: add cpufreq transiton
> notifier to adjust loops_per_jiffy for smp) is in place.
>
> Shawn
I see, just check the latest kernel's implementation about global loops_per_jiffy, it is OK.
WARNING: multiple messages have this Message-ID (diff)
From: b20788@freescale.com (Anson Huang)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v5] cpufreq: add imx6q-cpufreq driver
Date: Mon, 4 Feb 2013 13:40:18 -0500 [thread overview]
Message-ID: <20130204184018.GA12696@ubuntu> (raw)
In-Reply-To: <20130204050909.GD26233@S2101-09.ap.freescale.net>
On Mon, Feb 04, 2013 at 01:09:11PM +0800, Shawn Guo wrote:
> On Mon, Feb 04, 2013 at 11:06:22AM -0500, Anson Huang wrote:
> > > + /*
> > > + * The setpoints are selected per PLL/PDF frequencies, so we need to
> > > + * reprogram PLL for frequency scaling. The procedure of reprogramming
> > > + * PLL1 is as below.
> > > + *
> > > + * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
> > > + * - Disable pll1_sys_clk and reprogram it
> > > + * - Enable pll1_sys_clk and reparent pll1_sw_clk back to it
> > > + * - Disable pll2_pfd2_396m_clk
> > > + */
> > > + clk_prepare_enable(pll2_pfd2_396m_clk);
> > > + clk_set_parent(step_clk, pll2_pfd2_396m_clk);
> > > + clk_set_parent(pll1_sw_clk, step_clk);
> > > + clk_prepare_enable(pll1_sys_clk);
> > > + if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
> > > + clk_disable_unprepare(pll1_sys_clk);
> > > + clk_set_rate(pll1_sys_clk, freqs.new * 1000);
> > > + clk_prepare_enable(pll1_sys_clk);
> > > + clk_set_parent(pll1_sw_clk, pll1_sys_clk);
> > > + clk_disable_unprepare(pll2_pfd2_396m_clk);
> > > + } else {
> > > + /*
> > > + * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
> > > + * to provide the frequency.
> > > + */
> > > + clk_disable_unprepare(pll1_sys_clk);
> > > + }
> > Seems like we will get pll2_pfd2_396m_clk's use count mismatch? As every time cpu freq is changed, pll2_pfd2_396m_clk will be added at the beginning of this code piece, but only decreased when cpu freq > 396M, so everytime cpu freq changed to 396M, this pll2_pfd2_396m_clk will in increased?
>
> Ah, good catch. And pll1_sys_clk has the same problem. Since it's
> been verified by FSL kernel that we do not necessarily need to disable
> pll1_sys_clk before reprogramming it, I would choose to rewrite the
> code as below to make it cleaner and correct on clock usage.
>
> /*
> * The setpoints are selected per PLL/PDF frequencies, so we need to
> * reprogram PLL for frequency scaling. The procedure of reprogramming
> * PLL1 is as below.
> *
> * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
> * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
> * - Disable pll2_pfd2_396m_clk
> */
> clk_prepare_enable(pll2_pfd2_396m_clk);
> clk_set_parent(step_clk, pll2_pfd2_396m_clk);
> clk_set_parent(pll1_sw_clk, step_clk);
> if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
> clk_set_rate(pll1_sys_clk, freqs.new * 1000);
> /*
> * If we are leaving 396 MHz set-point, we need to enable
> * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
> * their use count correct.
> */
> if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
> clk_prepare_enable(pll1_sys_clk);
> clk_disable_unprepare(pll2_pfd2_396m_clk);
> }
> clk_set_parent(pll1_sw_clk, pll1_sys_clk);
> clk_disable_unprepare(pll2_pfd2_396m_clk);
> } else {
> /*
> * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
> * to provide the frequency.
> */
> clk_disable_unprepare(pll1_sys_clk);
> }
>
Looks good:)
> > > +
> > > + /* Ensure the arm clock divider is what we expect */
> > > + ret = clk_set_rate(arm_clk, freqs.new * 1000);
> > > + if (ret) {
> > > + dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
> > > + regulator_set_voltage_tol(arm_reg, volt_old, 0);
> > > + return ret;
> > > + }
> > > +
> > > + /* scaling down? scale voltage after frequency */
> > > + if (freqs.new < freqs.old) {
> > > + ret = regulator_set_voltage_tol(arm_reg, volt, 0);
> > > + if (ret)
> > > + dev_warn(cpu_dev,
> > > + "failed to scale vddarm down: %d\n", ret);
> > > +
> > > + if (freqs.old == FREQ_1P2_GHZ / 1000) {
> > > + regulator_set_voltage_tol(pu_reg,
> > > + PU_SOC_VOLTAGE_NORMAL, 0);
> > > + regulator_set_voltage_tol(soc_reg,
> > > + PU_SOC_VOLTAGE_NORMAL, 0);
> > > + }
> > > + }
> > > +
> > > + for_each_online_cpu(cpu) {
> > > + freqs.cpu = cpu;
> > > + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> > > + }
> > > +
> > Should we need to update the percpu loops_per_jiffy variable and global loops_per_jiffy? As the udelay and mdelay will rely on this global loops_per_jiffy? Or the latest kernel has handle it in other place such as cpufreq common driver? I remembered that common cpufreq driver only handle the noSMP case.
>
> No, it's not needed since commit ec971ea (ARM: add cpufreq transiton
> notifier to adjust loops_per_jiffy for smp) is in place.
>
> Shawn
I see, just check the latest kernel's implementation about global loops_per_jiffy, it is OK.
next prev parent reply other threads:[~2013-02-04 18:40 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-04 2:51 [PATCH v5] cpufreq: add imx6q-cpufreq driver Shawn Guo
2013-02-04 2:51 ` Shawn Guo
2013-02-04 16:06 ` Anson Huang
2013-02-04 16:06 ` Anson Huang
2013-02-04 5:09 ` Shawn Guo
2013-02-04 5:09 ` Shawn Guo
2013-02-04 18:40 ` Anson Huang [this message]
2013-02-04 18:40 ` Anson Huang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130204184018.GA12696@ubuntu \
--to=b20788@freescale.com \
--cc=cpufreq@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-pm@vger.kernel.org \
--cc=rjw@sisk.pl \
--cc=shawn.guo@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.