Re: [PATCH 2/5] clk: notifier handler for dynamic voltage scaling
On Fri, Mar 01, 2013 at 06:55:54PM -0800, Bill Huang wrote: On Sat, 2013-03-02 at 04:48 +0800, Mike Turquette wrote: Quoting Mike Turquette (2013-03-01 10:22:34) Quoting Bill Huang (2013-03-01 01:41:31) On Thu, 2013-02-28 at 12:49 +0800, Mike Turquette wrote: Dynamic voltage and frequency scaling (dvfs) is a common power saving technique in many of today's modern processors. This patch introduces a common clk rate-change notifier handler which scales voltage appropriately whenever clk_set_rate is called on an affected clock. I really think clk_enable and clk_disable should also be triggering notifier call and DVFS should act accordingly since there are cases drivers won't set clock rate but instead disable its clock directly, do you agree? Hi Bill, I'll think about this. Perhaps a better solution would be to adapt these drivers to runtime PM. Then a call to runtime_pm_put() would result in a call to clk_disable(...) and regulator_set_voltage(...). There is no performance-based equivalent to runtime PM, which is one reason why clk_set_rate is a likely entry point into dvfs. But for operations that have nice api's like runtime PM it would be better to use those interfaces and not overload the clk.h api unnecessarily. Bill, I wasn't thinking at all when I wrote this. Trying to rush to the airport I guess... clk_enable() and clk_disable() must not sleep and all operations are done under a spinlock. So this rules out most use of notifiers. It is expected for some drivers to very aggressively enable/disable clocks in interrupt handlers so scaling voltage as a function of clk_{en|dis}able calls is also likely out of the question. Yeah for those existing drivers to call enable/disable clocks in interrupt have ruled out this, I didn't think through when I was asking. Some platforms have chosen to implement voltage scaling in their .prepare callbacks. I personally do not like this and still prefer drivers be adapted to runtime pm and let those callbacks handle voltage scaling along with clock handling. Voltage scaling in clock notifiers seems similar. Clock and regulater embedded code into each other will cause things complicated. I think different SoC have different mechanisms or constraints on doing their DVFS, such as Tegra VDD_CORE rail, it supplies power to many devices and as a consequence each device do not have their own power rail to control, instead a central driver to handle/control this power rail is needed (to set voltage at the maximum of the requested voltage from all its sub-devices), so I'm wondering even if every drivers are doing DVFS through runtime pm, we're still having hole on knowing whether or not clocks of the interested devices are enabled/disabled at runtime, I'm not familiar with runtime pm and hence do not know if there is a mechanism to handle this, I'll study a bit. Thanks. Regards, Mike There are three prerequisites to using this feature: 1) the affected clocks must be using the common clk framework 2) voltage must be scaled using the regulator framework 3) clock frequency and regulator voltage values must be paired via the OPP library Just a note, Tegra Core won't meet prerequisite #3 since each regulator voltage values is associated with clocks driving those many sub-HW blocks in it. This patch isn't the one and only way to perform dvfs. It is just a helper function for registering notifier handlers for systems that meet the above three requirements. Even if you do not use the OPP library there is no reason why you could not register your own rate-change notifier handler to implement dvfs using whatever lookup-table you use today. And patches are welcome to extend the usefulness of this helper. I'd like as many people to benefit from this mechanism as possible. The extension is not so easy for us though since OPP library is assuming each device has a 1-1 mapping on its operating frequency and voltage. Is there someone working on OPP clock/regulator sets support? Thanks Richard At some point we should think hard about DT bindings for these operating points... Regards, Mike ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v7 3/3] clk: basic clock hardware types
[...] +static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + + if (!rate) + rate = 1; + + maxdiv = (1 divider-width); + + if (divider-flags CLK_DIVIDER_ONE_BASED) + maxdiv--; + + if (!best_parent_rate) { + parent_rate = __clk_get_rate(__clk_get_parent(hw-clk)); + bestdiv = DIV_ROUND_UP(parent_rate, rate); + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv maxdiv ? maxdiv : bestdiv; + return bestdiv; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i = maxdiv; i++) { + parent_rate = __clk_round_rate(__clk_get_parent(hw-clk), + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; + if (now = rate now best) { + bestdiv = i; + best = now; + *best_parent_rate = parent_rate; Better add if (now == rate) break; There may be more than one hit for (now == rate). We'd better select smallest div, thus smallest parent_rate. It's the same comment for v6, but not show stopper. Thanks Richard + } + } + + if (!bestdiv) { + bestdiv = (1 divider-width); + if (divider-flags CLK_DIVIDER_ONE_BASED) + bestdiv--; + *best_parent_rate = __clk_round_rate(__clk_get_parent(hw-clk), 1); + } + + return bestdiv; +} ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v6 3/3] clk: basic clock hardware types
Hi Mike, +static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; + + maxdiv = (1 divider-width); + + if (divider-flags CLK_DIVIDER_ONE_BASED) + maxdiv--; + + if (!(__clk_get_flags(hw-clk) CLK_SET_RATE_PARENT)) { + parent_rate = __clk_get_rate(__clk_get_parent(hw-clk)); + bestdiv = parent_rate / rate; + bestdiv = bestdiv == 0 ? 1 : bestdiv; + bestdiv = bestdiv maxdiv ? maxdiv : bestdiv; + goto out; + } + + /* + * The maximum divider we can use without overflowing + * unsigned long in rate * i below + */ + maxdiv = min(ULONG_MAX / rate, maxdiv); + + for (i = 1; i = maxdiv; i++) { + int div; + parent_rate = __clk_round_rate(__clk_get_parent(hw-clk), + rate * i); + div = parent_rate / rate; + div = div maxdiv ? maxdiv : div; + div = div 1 ? 1 : div; + now = parent_rate / div; + + if (now = rate now = best) { + bestdiv = div; + best = now; + *best_parent_rate = parent_rate; if (now == rate) break; we don't need it to loop to end, and smaller parent_rate is better. + } + } + + if (!bestdiv) { + bestdiv = (1 divider-width); + parent_rate = __clk_round_rate(__clk_get_parent(hw-clk), 1); + } else { + parent_rate = best * bestdiv; + } + +out: + if (best_parent_rate) + *best_parent_rate = parent_rate; + + return bestdiv; +} ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v6 2/3] clk: introduce the common clock framework
Looks like you didn't take my comments for v5. http://www.spinics.net/lists/arm-kernel/msg162903.html Regards Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v5 0/4] common clk framework
Hello Mike, The main interface for clk implementer is to register clocks dynamically. I think it highly depends on clk DT bindings. From the patch Grant sent out, it looks like he doesn't like one node per clk. So how do we register clocks dynamically? You have any sample code? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v5 3/4] clk: introduce the common clock framework
Hi Mike, On Sat, Mar 03, 2012 at 12:29:00AM -0800, Mike Turquette wrote: [snip] +static void __clk_disable(struct clk *clk) +{ + if (!clk) + return; + + if (WARN_ON(clk-enable_count == 0)) + return; + + if (--clk-enable_count 0) + return; + + if (clk-ops-disable) + clk-ops-disable(clk-hw); + + if (clk-parent) + __clk_disable(clk-parent); if __clk_xxx handle NULL clk, we might not need to check parent here? There're also many places that checks parent below. +} + +/** + * clk_disable - gate a clock + * @clk: the clk being gated + * + * clk_disable must not sleep, which differentiates it from clk_unprepare. In + * a simple case, clk_disable can be used instead of clk_unprepare to gate a + * clk if the operation is fast and will never sleep. One example is a + * SoC-internal clk which is controlled via simple register writes. In the + * complex case a clk gate operation may require a fast and a slow part. It is + * this reason that clk_unprepare and clk_disable are not mutually exclusive. + * In fact clk_disable must be called before clk_unprepare. + */ +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(enable_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(enable_lock, flags); +} +EXPORT_SYMBOL_GPL(clk_disable); + +static int __clk_enable(struct clk *clk) +{ + int ret = 0; + + if (!clk) + return 0; + + if (WARN_ON(clk-prepare_count == 0)) + return -ESHUTDOWN; + + if (clk-enable_count == 0) { + if (clk-parent) + ret = __clk_enable(clk-parent); ditto + + if (ret) + return ret; + + if (clk-ops-enable) { + ret = clk-ops-enable(clk-hw); + if (ret) { + __clk_disable(clk-parent); it's good case that don't check parent is NULL. + return ret; + } + } + } + + clk-enable_count++; + return 0; +} + +/** + * clk_enable - ungate a clock + * @clk: the clk being ungated + * + * clk_enable must not sleep, which differentiates it from clk_prepare. In a + * simple case, clk_enable can be used instead of clk_prepare to ungate a clk + * if the operation will never sleep. One example is a SoC-internal clk which + * is controlled via simple register writes. In the complex case a clk ungate + * operation may require a fast and a slow part. It is this reason that + * clk_enable and clk_prepare are not mutually exclusive. In fact clk_prepare + * must be called before clk_enable. Returns 0 on success, -EERROR + * otherwise. + */ +int clk_enable(struct clk *clk) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(enable_lock, flags); + ret = __clk_enable(clk); + spin_unlock_irqrestore(enable_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_enable); + +/** + * clk_get_rate - return the rate of clk + * @clk: the clk whose rate is being returned + * + * Simply returns the cached rate of the clk. Does not query the hardware. If + * clk is NULL then returns -EINVAL. + */ +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + mutex_lock(prepare_lock); + rate = __clk_get_rate(clk); + mutex_unlock(prepare_lock); + + return rate; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + +/** + * __clk_round_rate - round the given rate for a clk + * @clk: round the rate of this clock + * + * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate + */ +unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (!clk !clk-ops-round_rate) be || ? + return -EINVAL; + + return clk-ops-round_rate(clk-hw, rate, NULL); +} + +/** + * clk_round_rate - round the given rate for a clk + * @clk: the clk for which we are rounding a rate + * @rate: the rate which is to be rounded + * + * Takes in a rate as input and rounds it to a rate that the clk can actually + * use which is then returned. If clk doesn't support round_rate operation + * then the rate passed in is returned. + */ +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long ret = rate; + + mutex_lock(prepare_lock); + if (clk clk-ops-round_rate) + ret = __clk_round_rate(clk, rate); + mutex_unlock(prepare_lock); + + return ret; If clk is NULL, clk_round_rate and __clk_round_rate return different values. Do you mean it? +} +EXPORT_SYMBOL_GPL(clk_round_rate); + +/** + * __clk_notify - call clk notifier chain + * @clk: struct clk * that is changing rate + * @msg: clk notifier type (see include/linux/clk.h) + * @old_rate: old clk rate + * @new_rate: new clk
Re: [PATCH v5 2/4] clk: Kconfig: add entry for HAVE_CLK_PREPARE
On Sat, Mar 03, 2012 at 12:28:59AM -0800, Mike Turquette wrote: The common clk framework provides clk_prepare and clk_unprepare implementations. Create an entry for HAVE_CLK_PREPARE so that COMMON_CLK can select it. Signed-off-by: Mike Turquette mturque...@linaro.org Signed-off-by: Mike Turquette mturque...@ti.com Acked-by: Shawn Guo shawn@linaro.org Cc: Jeremy Kerr jeremy.k...@canonical.com Cc: Thomas Gleixner t...@linutronix.de Cc: Arnd Bergman arnd.bergm...@linaro.org Cc: Paul Walmsley p...@pwsan.com Cc: Richard Zhao richard.z...@linaro.org Cc: Saravana Kannan skan...@codeaurora.org Cc: Magnus Damm magnus.d...@gmail.com Cc: Rob Herring rob.herr...@calxeda.com Cc: Mark Brown broo...@opensource.wolfsonmicro.com Cc: Linus Walleij linus.wall...@stericsson.com Cc: Stephen Boyd sb...@codeaurora.org Cc: Amit Kucheria amit.kuche...@linaro.org Cc: Deepak Saxena dsax...@linaro.org Cc: Grant Likely grant.lik...@secretlab.ca Cc: Andrew Lunn and...@lunn.ch --- drivers/clk/Kconfig |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 9b3cd08..3912576 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -8,3 +8,6 @@ config HAVE_CLK_PREPARE config HAVE_MACH_CLKDEV bool + +config HAVE_CLK_PREPARE + bool We've already had it. redundant? Thanks Richard -- 1.7.5.4 ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH 2/2] cpufreq: OMAP: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/omap-cpufreq.c | 36 1 files changed, 0 insertions(+), 36 deletions(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5d04c57..17da4c4 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -37,16 +37,6 @@ #include mach/hardware.h -#ifdef CONFIG_SMP -struct lpj_info { - unsigned long ref; - unsigned intfreq; -}; - -static DEFINE_PER_CPU(struct lpj_info, lpj_ref); -static struct lpj_info global_lpj_ref; -#endif - static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); static struct clk *mpu_clk; @@ -118,32 +108,6 @@ static int omap_target(struct cpufreq_policy *policy, ret = clk_set_rate(mpu_clk, freqs.new * 1000); freqs.new = omap_getspeed(policy-cpu); -#ifdef CONFIG_SMP - /* -* Note that loops_per_jiffy is not updated on SMP systems in -* cpufreq driver. So, update the per-CPU loops_per_jiffy value -* on frequency transition. We need to update all dependent CPUs. -*/ - for_each_cpu(i, policy-cpus) { - struct lpj_info *lpj = per_cpu(lpj_ref, i); - if (!lpj-freq) { - lpj-ref = per_cpu(cpu_data, i).loops_per_jiffy; - lpj-freq = freqs.old; - } - - per_cpu(cpu_data, i).loops_per_jiffy = - cpufreq_scale(lpj-ref, lpj-freq, freqs.new); - } - - /* And don't forget to adjust the global one */ - if (!global_lpj_ref.freq) { - global_lpj_ref.ref = loops_per_jiffy; - global_lpj_ref.freq = freqs.old; - } - loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, - freqs.new); -#endif - /* notifiers */ for_each_cpu(i, policy-cpus) { freqs.cpu = i; -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH 0/2] change lpj in arm smp common code
The two patches were originally in [PATCH V6 0/7] add a generic cpufreq driver. I seperated them and hope they can go to upstream earlier. Richard Zhao (2): ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp cpufreq: OMAP: remove loops_per_jiffy recalculate for smp arch/arm/kernel/smp.c | 54 drivers/cpufreq/omap-cpufreq.c | 36 -- 2 files changed, 54 insertions(+), 36 deletions(-) -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH 1/2] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp
If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different arch has different per-cpu loops_per_jiffy definition. Signed-off-by: Richard Zhao richard.z...@linaro.org Acked-by: Russell King rmk+ker...@arm.linux.org.uk --- arch/arm/kernel/smp.c | 54 + 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index cdeb727..4381bef 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -25,6 +25,7 @@ #include linux/percpu.h #include linux/clockchips.h #include linux/completion.h +#include linux/cpufreq.h #include linux/atomic.h #include asm/cacheflush.h @@ -599,3 +600,56 @@ int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; } + +#ifdef CONFIG_CPU_FREQ + +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq); +static unsigned long global_l_p_j_ref; +static unsigned long global_l_p_j_ref_freq; + +static int cpufreq_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + int cpu = freq-cpu; + + if (freq-flags CPUFREQ_CONST_LOOPS) + return NOTIFY_OK; + + if (!per_cpu(l_p_j_ref, cpu)) { + per_cpu(l_p_j_ref, cpu) = + per_cpu(cpu_data, cpu).loops_per_jiffy; + per_cpu(l_p_j_ref_freq, cpu) = freq-old; + if (!global_l_p_j_ref) { + global_l_p_j_ref = loops_per_jiffy; + global_l_p_j_ref_freq = freq-old; + } + } + + if ((val == CPUFREQ_PRECHANGE freq-old freq-new) || + (val == CPUFREQ_POSTCHANGE freq-old freq-new) || + (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { + loops_per_jiffy = cpufreq_scale(global_l_p_j_ref, + global_l_p_j_ref_freq, + freq-new); + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(l_p_j_ref, cpu), + per_cpu(l_p_j_ref_freq, cpu), + freq-new); + } + return NOTIFY_OK; +} + +static struct notifier_block cpufreq_notifier = { + .notifier_call = cpufreq_callback, +}; + +static int __init register_cpufreq_notifier(void) +{ + return cpufreq_register_notifier(cpufreq_notifier, + CPUFREQ_TRANSITION_NOTIFIER); +} +core_initcall(register_cpufreq_notifier); + +#endif -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V6 4/7] cpufreq: add clk-reg cpufreq driver
On Wed, Jan 11, 2012 at 03:22:34PM -0800, Kevin Hilman wrote: Richard Zhao richard.z...@linaro.org writes: The driver get cpu operation point table from device tree cpu0 node, Since we already have an existing OPP infrastructure in the kernel, seems like this driver should get OPPs by asking the OPP layer. When I created the patch, there's only omap cpufreq driver using OPP. If it depends on OPP, it might prevent users who have not adopted OPP from using the driver. This approach assumes the OPP layer is static at boot time and not changing, however that's not the case in practice. The OPP layer could be extended to read boot-time OPPs from DT if desired, but since the OPPs are also populated/enabled/disabled dynamicaly on some platforms (e.g. OMAP), I think the any generic CPUfreq driver should use the OPP interface and not DT directly. and adjusts operating points using clk and regulator APIs. For a generic driver, the regulator used should also be configurable. For example, this driver currently assumes a regulator named cpu for all instances. If you had separate clusters with independent voltage control, you'd likely have a separate regulator for each cluster. The driver, for now, assumes all cpu cores uses the same clk and voltage. It's correct for most arm multi-core SoC. Do you have real case to need different voltage/clk? And the regulator will be specified in dts after cpu convert from sys device to normal device. Thanks Richard Kevin ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V6 0/7] add a generic cpufreq driver
On Fri, Jan 06, 2012 at 08:53:37AM +0800, Richard Zhao wrote: On Thu, Jan 05, 2012 at 06:16:54AM +0800, Richard Zhao wrote: hi Russell, May I have your ACK, you merge it? Russell, ping would you have time to look at this patch series? Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V6 0/7] add a generic cpufreq driver
On Thu, Jan 05, 2012 at 06:16:54AM +0800, Richard Zhao wrote: hi Russell, May I have your ACK, you merge it? Russell, ping Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V6 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate for smp
Hi Sascha Shawn, Could you look and ack the patch? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V6 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for smp
Hi Kevin, Could you please look at and ack the patch if possible? Sorry, I didn't cc you. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V6 0/7] add a generic cpufreq driver
hi Russell, May I have your ACK, you merge it? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 3/6] clk: introduce the common clock framework
On Wed, Jan 04, 2012 at 05:01:43PM -0800, Turquette, Mike wrote: On Wed, Jan 4, 2012 at 6:32 AM, Rob Herring robherri...@gmail.com wrote: On 01/03/2012 08:15 PM, Richard Zhao wrote: On Fri, Dec 16, 2011 at 04:45:48PM -0800, Turquette, Mike wrote: On Wed, Dec 14, 2011 at 5:18 AM, Thomas Gleixner t...@linutronix.de wrote: On Tue, 13 Dec 2011, Mike Turquette wrote: snip +/** + * clk_init - initialize the data structures in a struct clk + * @dev: device initializing this clk, placeholder for now + * @clk: clk being initialized + * + * Initializes the lists in struct clk, queries the hardware for the + * parent and rate and sets them both. Adds the clk to the sysfs tree + * topology. + * + * Caller must populate clk-name and clk-flags before calling I'm not too happy about this construct. That leaves struct clk and its members exposed to the world instead of making it a real opaque cookie. I know from my own painful experience, that this will lead to random fiddling in that data structure in drivers and arch code just because the core code has a shortcoming. Why can't we make struct clk a real cookie and confine the data structure to the core code ? That would change the init call to something like: struct clk *clk_init(struct device *dev, const struct clk_hw *hw, struct clk *parent) And have: struct clk_hw { struct clk_hw_ops *ops; const char *name; unsigned long flags; }; Implementers can do: struct my_clk_hw { struct clk_hw hw; mydata; }; And then change the clk ops callbacks to take struct clk_hw * as an argument. We have to define static clocks before we adopt DT binding. If clk is opaque and allocate memory in clk core, it'll make hard to define static clocks. And register/init will pass a long parameter list. DT is not a prerequisite for having dynamically created clocks. You can make clock init dynamic without DT. I can not find clock info at runtime without DT. If I use static info, I find it was hard/strange to define and register it, using Mike's early patches. Agreed. What data goes in struct clk vs. struct clk_hw could change over time. So perhaps we can start with some data in clk_hw and plan to move it to struct clk later. Even if almost everything ends up in clk_hw initially, at least the structure is in place to have common, core-only data separate from platform data. What is the point of this? The original clk_hw was defined simply as: struct clk_hw { struct clk *clk; }; It's only purpose in life was as a handle for navigation between the opaque struct clk and the hardware-specific struct my_clk_hw. struct clk_hw is defined in clk.h and everyone can see it. If we're suddenly OK putting clk data in this structure then why bother with an opaque struct clk at all? I think Rob meant one time a step to make it opaque. But it'll make clk core always changing, easier mess, and let clk driver confused. What is the actual data you need to be static and accessible to the platform code? A ptr to parent clk is the main thing I've seen for static initialization. So make the parent ptr be struct clk_hw* and allow the platforms to access. To answer your question on what data we're trying to expose: platform code commonly needs the parent pointer and the clk rate (and by extension, the rate of the parent). For debug/error prints it is also nice to have the clk name. Generic clk flags are also conceivably something that platform code might want. I'd like to spin the question around: if we're OK exposing some stuff (in your example above, the parent pointer), then what clk data are you trying to hide? Regards, Mike Rob ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver
Hi Russel, On 3 January 2012 17:06, Russell King - ARM Linux li...@arm.linux.org.uk wrote: On Mon, Dec 26, 2011 at 09:44:52PM +0800, Richard Zhao wrote: On Mon, Dec 26, 2011 at 11:10:30AM +, Mark Brown wrote: The *call* is there in the regulator subsystem, it's just that none of the drivers back it up with an actual implementation yet. Which turns out to be a good thing as cpufreq can't currently understand variable latencies and the governors don't deal well with non-trivial latencies anyway. but clk API don't have such calls. and many SoCs only adjust clk frequencies, using one single voltage. That's because it's often not known - especially in the case of PLLs, data sheets don't tend to specify how long it takes for the PLL to relock after a requested change. If it's important that the PLL be locked, there will be a bit to poll (or they'll cause the CPU itself to stall while the PLL is not locked.) So, for these kinds of situations, how do you suggest that the clk API provides this information? In latest v6 version, I get clk transition latency from dt property, and get regulator transition latency from regulator API. Could you please help review other arm common changes in v6 version? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver
On 3 January 2012 21:47, Russell King - ARM Linux li...@arm.linux.org.uk wrote: On Tue, Jan 03, 2012 at 09:25:30PM +0800, Richard Zhao wrote: Hi Russel, On 3 January 2012 17:06, Russell King - ARM Linux li...@arm.linux.org.uk wrote: On Mon, Dec 26, 2011 at 09:44:52PM +0800, Richard Zhao wrote: On Mon, Dec 26, 2011 at 11:10:30AM +, Mark Brown wrote: The *call* is there in the regulator subsystem, it's just that none of the drivers back it up with an actual implementation yet. Which turns out to be a good thing as cpufreq can't currently understand variable latencies and the governors don't deal well with non-trivial latencies anyway. but clk API don't have such calls. and many SoCs only adjust clk frequencies, using one single voltage. That's because it's often not known - especially in the case of PLLs, data sheets don't tend to specify how long it takes for the PLL to relock after a requested change. If it's important that the PLL be locked, there will be a bit to poll (or they'll cause the CPU itself to stall while the PLL is not locked.) So, for these kinds of situations, how do you suggest that the clk API provides this information? In latest v6 version, I get clk transition latency from dt property, and get regulator transition latency from regulator API. Could you please help review other arm common changes in v6 version? You didn't get my point: how do you specify a clock transition latency for a clock with a PLL when the data sheets don't tell you what that is, and they instead give you a bit to poll? clk-trans-latency is not a MUST property. If the datasheet don't provide it or you don't want to measure, you may not specify the property. In such case cpufreq governor ondemand and conservative will not work, because they can not determine the sample rate without the latency value. Do you: (a) make up some number and hope that it's representative No, I always get it from dt. (b) not specify any transition latency It's allowed. (c) think about the problem _now_ and define what it means for a clock without a transition latency. It's ondemand/conservative governors that strongly need the latency value. If user don't want to use it, it's fine. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 3/6] clk: introduce the common clock framework
On Fri, Dec 16, 2011 at 04:45:48PM -0800, Turquette, Mike wrote: On Wed, Dec 14, 2011 at 5:18 AM, Thomas Gleixner t...@linutronix.de wrote: On Tue, 13 Dec 2011, Mike Turquette wrote: +void __clk_unprepare(struct clk *clk) +{ + if (!clk) + return; + + if (WARN_ON(clk-prepare_count == 0)) + return; + + if (--clk-prepare_count 0) + return; + + WARN_ON(clk-enable_count 0); So this leaves the clock enable count set. I'm a bit wary about that. Shouldn't it either return (including bumping the prepare_count again) or call clk_disable() ? I've hit this in my port of OMAP. It comes from this simple situation: driver 1 (adapted for clk_prepare/clk_unprepare): clk_prepare(clk); clk_enable(clk); ... driver2 (not adapted for clk_prepare/clk_unprepare): clk_enable(clk); ... driver1: clk_disable(clk); clk_unprepare(clk); In such a case we don't want to bump the prepare_count, since the offending driver2 won't decrement that count. Also we don't want to shut down that clk since driver2 is using it. Returning after the WARN is maybe OK, but the point of this check is really to find code which hasn't yet been made prepare-aware, and the current implementation is noisy enough about it. +/** + * clk_get_parent - return the parent of a clk + * @clk: the clk whose parent gets returned + * + * Simply returns clk-parent. It is up to the caller to hold the + * prepare_lock, if desired. Returns NULL if clk is NULL. Holding the prepare lock in the caller will deadlock. So it's not a real good idea to document it as an option :) Oops. That comment is left over from before clk_get_parent held the lock. Will remove. + */ +struct clk *clk_get_parent(struct clk *clk) +{ + struct clk *parent; + + if (!clk) + return NULL; + + mutex_lock(prepare_lock); +/** + * clk_init - initialize the data structures in a struct clk + * @dev: device initializing this clk, placeholder for now + * @clk: clk being initialized + * + * Initializes the lists in struct clk, queries the hardware for the + * parent and rate and sets them both. Adds the clk to the sysfs tree + * topology. + * + * Caller must populate clk-name and clk-flags before calling I'm not too happy about this construct. That leaves struct clk and its members exposed to the world instead of making it a real opaque cookie. I know from my own painful experience, that this will lead to random fiddling in that data structure in drivers and arch code just because the core code has a shortcoming. Why can't we make struct clk a real cookie and confine the data structure to the core code ? That would change the init call to something like: struct clk *clk_init(struct device *dev, const struct clk_hw *hw, struct clk *parent) And have: struct clk_hw { struct clk_hw_ops *ops; const char *name; unsigned long flags; }; Implementers can do: struct my_clk_hw { struct clk_hw hw; mydata; }; And then change the clk ops callbacks to take struct clk_hw * as an argument. We have to define static clocks before we adopt DT binding. If clk is opaque and allocate memory in clk core, it'll make hard to define static clocks. And register/init will pass a long parameter list. So the core code can allocate the clk data structure and you return a real opaque cookie. You do the same thing for the basic gated clock in one of the next patches, so doing it for struct clk itself is just consequent. The opaque cookie would work if platform code never needs any information outside of the data a single clk_hw_whatever provides. Unfortunately hardware doesn't make things that easy on us and the operations we do for a single clk are affected by the state of other clks. Here is an example I've been using a lot lately: on OMAP we have two clock inputs to our PLLs: a bypass clk and reference clk (actually we can have more than this). When changing the PLL rate both clks must be enabled, regardless of which clk ends up driving the PLL. To illustrate, the PLL may be driven by clk_ref at 400MHz, and then we call clk_set_rate(pll_clk, 19600); which will also leave it clocked by clk_ref but at 196MHz. For this to happen however, the clk_bypass had to be enabled during the rate change operation. Here is the relevant .set_rate implementation: http://git.linaro.org/gitweb?p=people/mturquette/linux.git;a=blob;f=arch/arm/mach-omap2/dpll3xxx.c;h=b2412574b63829944593c1a7a6eda5fa4350686f;hb=738bde65918ae1ac743b1498801da0b860e2ee32#l461 In order for the OMAP platform code to do this, we have to have two things: firstly we need the struct clk so that we can call clk_enable/disable and __clk_prepare/unprepare on the ref and bypass clks from within .set_rate. The
[PATCH V6 5/7] dts/imx6q: add cpufreq property
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |7 +++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..d89b42d 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,13 @@ compatible = arm,cortex-a9; reg = 0; next-level-cache = L2; + cpu-freqs = 99600 79200 39600 19800; + cpu-volts =/* min max */ + 1225000 145 /* 996M */ + 110 145 /* 792M */ + 95 145 /* 396M */ + 85 145; /* 198M */ + clk-trans-latency = 61036; /* two CLK32 periods */ }; cpu@1 { -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V6 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa97..39cf00a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -595,6 +595,7 @@ comment i.MX6 family: config SOC_IMX6Q bool i.MX6 Quad support + select ARCH_HAS_CPUFREQ select ARM_GIC select CACHE_L2X0 select CPU_V7 -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V6 0/7] add a generic cpufreq driver
The driver is based on clock and regulator APIs and support single core and multi core ARM SoCs. For multi core, it assume all cores share the same clock and voltage. Thanks Arnd, Mark, Jamie, Shawn, Rob, for your review. Changes in V6: - add scaling_available_freqs Changes in V5: - add more comments - rename trans-latency to clk-trans-latency, and it only describe clk latency. Regulator latency is got from regulator_set_voltage_time. Changes in v4: - add depends on HAVE_CLK OF REGULATOR - add set_cpu_freq fail check - regulator_put wehn module exit - add pr_fmt and convert all printk to pr_xxx - use voltage range - comment and doc fix - add cpu_volts value pre-check in module init - add helpfull module parameter max_freq - remove compatible string check on Arnd's comment. - remove generic-cpufreq to clk-reg-cpufreq Changes in v3: - move adjusting smp loops_per_jiffy to arm common code, and also adjust global loops_per_jiffy. - remove adjusting loops_per_jiffy in imx and omap cpufreq drivers. - check compatible generic-cpufreq when module_init - change printk to pr_xxx - add generic-cpufreq DT binding doc Changes in v2: - add volatage change support - change '_' in property name to '-' - use initial value to calculate loops_per_jiffy - fix reading cpu_volts property bug - let cpufreq_frequency_table_cpuinfo routines handle cpu_freq_khz_max/min - don't change freq in arm_cpufreq_exit, because every core share the same freq. - use unsigned long describe frequency as much as possible. Because clk use unsigned long, but cpufreq use unsigned int. [PATCH V6 1/7] ARM: add cpufreq transiton notifier to adjust [PATCH V6 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate [PATCH V6 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for [PATCH V6 4/7] cpufreq: add clk-reg cpufreq driver [PATCH V6 5/7] dts/imx6q: add cpufreq property [PATCH V6 6/7] arm/imx6q: register arm_clk as cpu to clkdev [PATCH V6 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V6 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/omap-cpufreq.c | 36 1 files changed, 0 insertions(+), 36 deletions(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5d04c57..17da4c4 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -37,16 +37,6 @@ #include mach/hardware.h -#ifdef CONFIG_SMP -struct lpj_info { - unsigned long ref; - unsigned intfreq; -}; - -static DEFINE_PER_CPU(struct lpj_info, lpj_ref); -static struct lpj_info global_lpj_ref; -#endif - static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); static struct clk *mpu_clk; @@ -118,32 +108,6 @@ static int omap_target(struct cpufreq_policy *policy, ret = clk_set_rate(mpu_clk, freqs.new * 1000); freqs.new = omap_getspeed(policy-cpu); -#ifdef CONFIG_SMP - /* -* Note that loops_per_jiffy is not updated on SMP systems in -* cpufreq driver. So, update the per-CPU loops_per_jiffy value -* on frequency transition. We need to update all dependent CPUs. -*/ - for_each_cpu(i, policy-cpus) { - struct lpj_info *lpj = per_cpu(lpj_ref, i); - if (!lpj-freq) { - lpj-ref = per_cpu(cpu_data, i).loops_per_jiffy; - lpj-freq = freqs.old; - } - - per_cpu(cpu_data, i).loops_per_jiffy = - cpufreq_scale(lpj-ref, lpj-freq, freqs.new); - } - - /* And don't forget to adjust the global one */ - if (!global_lpj_ref.freq) { - global_lpj_ref.ref = loops_per_jiffy; - global_lpj_ref.freq = freqs.old; - } - loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, - freqs.new); -#endif - /* notifiers */ for_each_cpu(i, policy-cpus) { freqs.cpu = i; -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V6 4/7] cpufreq: add clk-reg cpufreq driver
The driver get cpu operation point table from device tree cpu0 node, and adjusts operating points using clk and regulator APIs. It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org Reviewed-by: Jamie Iles ja...@jamieiles.com Reviewed-by: Mark Brown broo...@opensource.wolfsonmicro.com Acked-by: Shawn Guo shawn@linaro.org --- .../devicetree/bindings/cpufreq/clk-reg-cpufreq| 21 ++ drivers/cpufreq/Kconfig| 10 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/clk-reg-cpufreq.c | 308 4 files changed, 341 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq create mode 100644 drivers/cpufreq/clk-reg-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq b/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq new file mode 100644 index 000..e8dc763 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq @@ -0,0 +1,21 @@ +Generic cpufreq driver based on clk and regulator APIs + +Required properties in /cpus/cpu@0: +- cpu-freqs : cpu frequency points it supports, in unit of Hz. + Each point takes on cell. +- cpu-volts : cpu voltage ranges required by the frequency points + at the same index, in unit of uV. + Each range takes two cells, one for min, the other for max. +- clk-trans-latency : cpu clk transition latency, in unit of ns. + It takes one cell. + +An example: +cpu@0 { + cpu-freqs = 99600 79200 39600 19800; + cpu-volts =/* min max */ + 1225000 145 /* 996M */ + 110 145 /* 792M */ + 95 145 /* 396M */ + 85 145; /* 198M */ + clk-trans-latency = 61036; /* two CLK32 periods */ +}; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..95470f1 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,16 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config CLK_REG_CPUFREQ_DRIVER + tristate Generic cpufreq driver using clk and regulator APIs + depends on HAVE_CLK OF REGULATOR + select CPU_FREQ_TABLE + help + This adds generic CPUFreq driver based on clk and regulator APIs. + It assumes all cores of the CPU share the same clock and voltage. + + If in doubt, say N. + menu x86 CPU frequency scaling drivers depends on X86 source drivers/cpufreq/Kconfig.x86 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..2c4eb33 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_CLK_REG_CPUFREQ_DRIVER) += clk-reg-cpufreq.o + ## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early diff --git a/drivers/cpufreq/clk-reg-cpufreq.c b/drivers/cpufreq/clk-reg-cpufreq.c new file mode 100644 index 000..77c4408 --- /dev/null +++ b/drivers/cpufreq/clk-reg-cpufreq.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#define pr_fmt(fmt)KBUILD_MODNAME : fmt + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h + +static u32 *cpu_freqs; /* Hz */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; +static unsigned int cur_index; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) { + ret = regulator_set_voltage(cpu_reg, + cpu_volts[index * 2], cpu_volts[index * 2 + 1]); + if (ret) { + pr_err(set cpu voltage failed!\n); + return ret; + } + } + + ret = clk_set_rate
Re: [PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver
On Wed, Dec 28, 2011 at 11:42:37AM +, Mark Brown wrote: On Wed, Dec 28, 2011 at 11:31:29AM +0800, Richard Zhao wrote: On Wed, Dec 28, 2011 at 11:14:10AM +0800, Richard Zhao wrote: + if (cpu_reg) { + ret = regulator_is_supported_voltage(cpu_reg, + cpu_volts[i * 2], cpu_volts[i * 2 + 1]); Is there any reason you didn't export symbol regulator_is_supported_voltage? and also it don't have !REGULATOR dummy implementation. regulator_set_voltage_time and some other functions don't have dummy one either. You can't usefully work with voltages without knowing what the actual voltages are - the only sensible stubs we could provide would return errors but then any driver using the stubs would probably fail to do whatever it was doing. With enable and disable we can sensibly stub things out with an always on regulator. Sorry, I can not get your point here. Let me describe the problem I met: - regulator_is_supported_voltage is not exported. when I build clk-reg-cpufreq as kernel module, there's a link error. - I saw linux/regulator/consumer.h has some dummy functions if !REGULATOR. I tried to make clk-reg-cpufreq driver work even !REGULATOR. I think that's why the dummy functions are there. If regulator_get return NULL, it'll avoid calling other regulator functions. But regulator_is_supported_voltage and regulator_set_voltage_time don't have such dummy ones. Undefined functions. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver
There's still a bug that, after rmmod module, cpu0 still has cpufreq sysfs entry. cpufreq_unregister_driver can not clean up everything. unfortunately, I don't have much time to debug cpufreq core. Log: root@ubuntu:~# insmod /clk-reg-cpufreq.ko clk_reg_cpufreq: regulator cpu get failed. trying to register driver clk-reg adding CPU 0 CPU 1 already managed, adding link CPU 2 already managed, adding link CPU 3 already managed, adding link setting new policy for CPU 0: 198000 - 996000 kHz new min and max freqs are 198000 - 996000 kHz governor switch __cpufreq_governor for CPU 0, event 1 governor: change or update limits __cpufreq_governor for CPU 0, event 3 target for CPU 0: 792000 kHz, relation 0 initialization complete adding CPU 1 adding CPU 2 adding CPU 3 driver clk-reg up and running root@ubuntu:~# root@ubuntu:~# root@ubuntu:~# root@ubuntu:~# rmmod clk-reg-cpufreq unregistering driver clk-reg unregistering CPU 0 removing link for cpu 1 removing link for cpu 2 removing link for cpu 3 __cpufreq_governor for CPU 0, event 2 last reference is dropped waiting for dropping of refcount wait complete adding CPU 1 Restoring governor userspace for cpu 1 CPU 0 already managed, adding link CPU 2 already managed, adding link CPU 3 already managed, adding link setting new policy for CPU 1: 198000 - 996000 kHz new min and max freqs are 198000 - 996000 kHz governor switch __cpufreq_governor for CPU 1, event 1 governor: change or update limits __cpufreq_governor for CPU 1, event 3 target for CPU 1: 792000 kHz, relation 0 initialization complete unregistering CPU 0 removing link unregistering CPU 1 removing link for cpu 2 removing link for cpu 3 __cpufreq_governor for CPU 1, event 2 last reference is dropped waiting for dropping of refcount wait complete adding CPU 2 Restoring governor userspace for cpu 2 CPU 0 already managed, adding link CPU 1 already managed, adding link CPU 3 already managed, adding link setting new policy for CPU 2: 198000 - 996000 kHz new min and max freqs are 198000 - 996000 kHz governor switch __cpufreq_governor for CPU 2, event 1 governor: change or update limits __cpufreq_governor for CPU 2, event 3 target for CPU 2: 792000 kHz, relation 0 initialization complete unregistering CPU 1 removing link unregistering CPU 2 removing link for cpu 0 removing link for cpu 3 __cpufreq_governor for CPU 2, event 2 last reference is dropped waiting for dropping of refcount wait complete adding CPU 0 Restoring governor userspace for cpu 0 CPU 1 already managed, adding link CPU 2 already managed, adding link CPU 3 already managed, adding link setting new policy for CPU 0: 198000 - 996000 kHz new min and max freqs are 198000 - 996000 kHz governor switch __cpufreq_governor for CPU 0, event 1 governor: change or update limits __cpufreq_governor for CPU 0, event 3 target for CPU 0: 792000 kHz, relation 0 initialization complete unregistering CPU 2 removing link unregistering CPU 3 removing link Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/omap-cpufreq.c | 36 1 files changed, 0 insertions(+), 36 deletions(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5d04c57..17da4c4 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -37,16 +37,6 @@ #include mach/hardware.h -#ifdef CONFIG_SMP -struct lpj_info { - unsigned long ref; - unsigned intfreq; -}; - -static DEFINE_PER_CPU(struct lpj_info, lpj_ref); -static struct lpj_info global_lpj_ref; -#endif - static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); static struct clk *mpu_clk; @@ -118,32 +108,6 @@ static int omap_target(struct cpufreq_policy *policy, ret = clk_set_rate(mpu_clk, freqs.new * 1000); freqs.new = omap_getspeed(policy-cpu); -#ifdef CONFIG_SMP - /* -* Note that loops_per_jiffy is not updated on SMP systems in -* cpufreq driver. So, update the per-CPU loops_per_jiffy value -* on frequency transition. We need to update all dependent CPUs. -*/ - for_each_cpu(i, policy-cpus) { - struct lpj_info *lpj = per_cpu(lpj_ref, i); - if (!lpj-freq) { - lpj-ref = per_cpu(cpu_data, i).loops_per_jiffy; - lpj-freq = freqs.old; - } - - per_cpu(cpu_data, i).loops_per_jiffy = - cpufreq_scale(lpj-ref, lpj-freq, freqs.new); - } - - /* And don't forget to adjust the global one */ - if (!global_lpj_ref.freq) { - global_lpj_ref.ref = loops_per_jiffy; - global_lpj_ref.freq = freqs.old; - } - loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, - freqs.new); -#endif - /* notifiers */ for_each_cpu(i, policy-cpus) { freqs.cpu = i; -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 0/7] add a generic cpufreq driver
The driver is based on clock and regulator APIs and support single core and multi core ARM SoCs. For multi core, it assume all cores share the same clock and voltage. Thanks Arnd, Mark, Jamie, Rob, for your review. Changes in V5: - add more comments - rename trans-latency to clk-trans-latency, and it only describe clk latency. Regulator latency is got from regulator_set_voltage_time. Changes in v4: - add depends on HAVE_CLK OF REGULATOR - add set_cpu_freq fail check - regulator_put wehn module exit - add pr_fmt and convert all printk to pr_xxx - use voltage range - comment and doc fix - add cpu_volts value pre-check in module init - add helpfull module parameter max_freq - remove compatible string check on Arnd's comment. - remove generic-cpufreq to clk-reg-cpufreq Changes in v3: - move adjusting smp loops_per_jiffy to arm common code, and also adjust global loops_per_jiffy. - remove adjusting loops_per_jiffy in imx and omap cpufreq drivers. - check compatible generic-cpufreq when module_init - change printk to pr_xxx - add generic-cpufreq DT binding doc Changes in v2: - add volatage change support - change '_' in property name to '-' - use initial value to calculate loops_per_jiffy - fix reading cpu_volts property bug - let cpufreq_frequency_table_cpuinfo routines handle cpu_freq_khz_max/min - don't change freq in arm_cpufreq_exit, because every core share the same freq. - use unsigned long describe frequency as much as possible. Because clk use unsigned long, but cpufreq use unsigned int. [PATCH V5 1/7] ARM: add cpufreq transiton notifier to adjust [PATCH V5 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate [PATCH V5 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for [PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver [PATCH V5 5/7] dts/imx6q: add cpufreq property [PATCH V5 6/7] arm/imx6q: register arm_clk as cpu to clkdev [PATCH V5 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver
The driver get cpu operation point table from device tree cpu0 node, and adjusts operating points using clk and regulator APIs. It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org Reviewed-by: Jamie Iles ja...@jamieiles.com Reviewed-by: Mark Brown broo...@opensource.wolfsonmicro.com --- .../devicetree/bindings/cpufreq/clk-reg-cpufreq| 21 ++ drivers/cpufreq/Kconfig| 10 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/clk-reg-cpufreq.c | 302 4 files changed, 335 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq create mode 100644 drivers/cpufreq/clk-reg-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq b/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq new file mode 100644 index 000..e8dc763 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq @@ -0,0 +1,21 @@ +Generic cpufreq driver based on clk and regulator APIs + +Required properties in /cpus/cpu@0: +- cpu-freqs : cpu frequency points it supports, in unit of Hz. + Each point takes on cell. +- cpu-volts : cpu voltage ranges required by the frequency points + at the same index, in unit of uV. + Each range takes two cells, one for min, the other for max. +- clk-trans-latency : cpu clk transition latency, in unit of ns. + It takes one cell. + +An example: +cpu@0 { + cpu-freqs = 99600 79200 39600 19800; + cpu-volts =/* min max */ + 1225000 145 /* 996M */ + 110 145 /* 792M */ + 95 145 /* 396M */ + 85 145; /* 198M */ + clk-trans-latency = 61036; /* two CLK32 periods */ +}; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..95470f1 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,16 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config CLK_REG_CPUFREQ_DRIVER + tristate Generic cpufreq driver using clk and regulator APIs + depends on HAVE_CLK OF REGULATOR + select CPU_FREQ_TABLE + help + This adds generic CPUFreq driver based on clk and regulator APIs. + It assumes all cores of the CPU share the same clock and voltage. + + If in doubt, say N. + menu x86 CPU frequency scaling drivers depends on X86 source drivers/cpufreq/Kconfig.x86 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..2c4eb33 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_CLK_REG_CPUFREQ_DRIVER) += clk-reg-cpufreq.o + ## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early diff --git a/drivers/cpufreq/clk-reg-cpufreq.c b/drivers/cpufreq/clk-reg-cpufreq.c new file mode 100644 index 000..4b28fdd --- /dev/null +++ b/drivers/cpufreq/clk-reg-cpufreq.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#define pr_fmt(fmt)KBUILD_MODNAME : fmt + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h + +static u32 *cpu_freqs; /* Hz */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; +static unsigned int cur_index; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) { + ret = regulator_set_voltage(cpu_reg, + cpu_volts[index * 2], cpu_volts[index * 2 + 1]); + if (ret) { + pr_err(set cpu voltage failed!\n); + return ret; + } + } + + ret = clk_set_rate(cpu_clk, freq); + if (ret
[PATCH V5 1/7] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp
If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different arch has different per-cpu loops_per_jiffy definition. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/kernel/smp.c | 54 + 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index ef5640b..ac9cadc 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -25,6 +25,7 @@ #include linux/percpu.h #include linux/clockchips.h #include linux/completion.h +#include linux/cpufreq.h #include linux/atomic.h #include asm/cacheflush.h @@ -631,3 +632,56 @@ int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; } + +#ifdef CONFIG_CPU_FREQ + +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq); +static unsigned long global_l_p_j_ref; +static unsigned long global_l_p_j_ref_freq; + +static int cpufreq_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + int cpu = freq-cpu; + + if (freq-flags CPUFREQ_CONST_LOOPS) + return NOTIFY_OK; + + if (!per_cpu(l_p_j_ref, cpu)) { + per_cpu(l_p_j_ref, cpu) = + per_cpu(cpu_data, cpu).loops_per_jiffy; + per_cpu(l_p_j_ref_freq, cpu) = freq-old; + if (!global_l_p_j_ref) { + global_l_p_j_ref = loops_per_jiffy; + global_l_p_j_ref_freq = freq-old; + } + } + + if ((val == CPUFREQ_PRECHANGE freq-old freq-new) || + (val == CPUFREQ_POSTCHANGE freq-old freq-new) || + (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { + loops_per_jiffy = cpufreq_scale(global_l_p_j_ref, + global_l_p_j_ref_freq, + freq-new); + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(l_p_j_ref, cpu), + per_cpu(l_p_j_ref_freq, cpu), + freq-new); + } + return NOTIFY_OK; +} + +static struct notifier_block cpufreq_notifier = { + .notifier_call = cpufreq_callback, +}; + +static int __init register_cpufreq_notifier(void) +{ + return cpufreq_register_notifier(cpufreq_notifier, + CPUFREQ_TRANSITION_NOTIFIER); +} +core_initcall(register_cpufreq_notifier); + +#endif -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 6/7] arm/imx6q: register arm_clk as cpu to clkdev
cpufreq needs cpu clock to change frequency. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/clock-imx6q.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index 039a7ab..72acbc2 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -1911,6 +1911,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, gpmi_io_clk, gpmi_io_clk), _REGISTER_CLOCK(NULL, usboh3_clk, usboh3_clk), _REGISTER_CLOCK(NULL, sata_clk, sata_clk), + _REGISTER_CLOCK(NULL, cpu, arm_clk), }; int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 5/7] dts/imx6q: add cpufreq property
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |7 +++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..d89b42d 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,13 @@ compatible = arm,cortex-a9; reg = 0; next-level-cache = L2; + cpu-freqs = 99600 79200 39600 19800; + cpu-volts =/* min max */ + 1225000 145 /* 996M */ + 110 145 /* 792M */ + 95 145 /* 396M */ + 85 145; /* 198M */ + clk-trans-latency = 61036; /* two CLK32 periods */ }; cpu@1 { -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/plat-mxc/cpufreq.c | 10 -- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c index c937e75..364793a 100644 --- a/arch/arm/plat-mxc/cpufreq.c +++ b/arch/arm/plat-mxc/cpufreq.c @@ -99,16 +99,6 @@ static int mxc_set_target(struct cpufreq_policy *policy, ret = set_cpu_freq(freq_Hz); -#ifdef CONFIG_SMP - /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. -* So update it for all CPUs. -*/ - for_each_possible_cpu(cpu) - per_cpu(cpu_data, cpu).loops_per_jiffy = - cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, - freqs.old, freqs.new); -#endif - for_each_possible_cpu(cpu) { freqs.cpu = cpu; cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V5 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa97..39cf00a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -595,6 +595,7 @@ comment i.MX6 family: config SOC_IMX6Q bool i.MX6 Quad support + select ARCH_HAS_CPUFREQ select ARM_GIC select CACHE_L2X0 select CPU_V7 -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver
On Tue, Dec 27, 2011 at 11:05:41PM +0800, Shawn Guo wrote: Hi Richard, On Tue, Dec 27, 2011 at 04:24:19PM +0800, Richard Zhao wrote: The driver get cpu operation point table from device tree cpu0 node, and adjusts operating points using clk and regulator APIs. It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org Reviewed-by: Jamie Iles ja...@jamieiles.com Reviewed-by: Mark Brown broo...@opensource.wolfsonmicro.com --- .../devicetree/bindings/cpufreq/clk-reg-cpufreq| 21 ++ drivers/cpufreq/Kconfig| 10 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/clk-reg-cpufreq.c | 302 4 files changed, 335 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq create mode 100644 drivers/cpufreq/clk-reg-cpufreq.c [...] +static struct cpufreq_driver clk_reg_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = clk_reg_verify_speed, + .target = clk_reg_set_target, + .get = clk_reg_get_speed, + .init = clk_reg_cpufreq_init, + .exit = clk_reg_cpufreq_exit, + .name = clk-reg, +}; + +static u32 max_freq = UINT_MAX / 1000; /* kHz */ +module_param(max_freq, uint, 0); +MODULE_PARM_DESC(max_freq, max cpu frequency in unit of kHz); + Have you tried to pass this param from kernel cmdline? What's the syntax if we want to pass a 800 MHz max_freq? clk-reg-cpufreq.max_freq=80 And I played this driver on imx6q with pm-qa [1] cpufreq test suit from Linaro PMWG. ### cpufreq_01: ### test the cpufreq framework is available for frequency ### https://wiki.linaro.org/WorkingGroups/PowerManagement/Doc/QA/Scripts#cpufreq_01 ### cpufreq_01.0/cpu0: checking 'scaling_available_frequencies' exists... fail cpufreq_01.0/cpu1: checking 'scaling_available_frequencies' exists... fail cpufreq_01.0/cpu2: checking 'scaling_available_frequencies' exists... fail cpufreq_01.0/cpu3: checking 'scaling_available_frequencies' exists... fail hmm, scaling_available_frequencies is nice-to-have feature. I'm glad to add it. ### cpufreq_05: ### test 'ondemand' and 'conservative' trigger correctly the configuration directory ### https://wiki.linaro.org/WorkingGroups/PowerManagement/Doc/QA/Scripts#cpufreq_05 ### cpufreq_05.0: checking 'ondemand' directory exists... pass cpufreq_05.1: checking 'conservative' directory exists... pass cpufreq_05.2: checking 'ondemand' directory is not there... pass cpufreq_05.3: checking 'conservative' directory is not there... pass cpufreq_05.4: checking 'ondemand' directory exists... fail cpufreq_05.5: checking 'conservative' directory exists... pass I past fail part script here: switch_ondemand cpu0 switch_conservative cpu1 check 'ondemand' directory exists test -d $CPU_PATH/cpufreq/ondemand check 'conservative' directory exists test -d $CPU_PATH/cpufreq/conservative This driver assume all cpu cores to share the same freq and voltage. The affected cpu is all other cpus. They also share one single governor. The test case does not suit this driver and not for most arm multi-core cpus I guess. The cpufreq_01 can be easily fixed with the following change. 8- @@ -146,6 +150,11 @@ static int clk_reg_cpufreq_exit(struct cpufreq_policy *policy) return 0; } +static struct freq_attr *clk_reg_cpufreq_attr[] = { + cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + static struct cpufreq_driver clk_reg_cpufreq_driver = { .flags = CPUFREQ_STICKY, .verify = clk_reg_verify_speed, @@ -153,10 +162,15 @@ static struct cpufreq_driver clk_reg_cpufreq_driver = { .get = clk_reg_get_speed, .init = clk_reg_cpufreq_init, .exit = clk_reg_cpufreq_exit, + .attr = clk_reg_cpufreq_attr, .name = clk-reg, }; -8 quite right. Thanks Richard And I have not looked into the second one deeply, but maybe you want to :) -- Regards, Shawn [1] git://git.linaro.org/people/dlezcano/pm-qa.git ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver
Hi Mark, [...] + if (cpu_reg) { + ret = regulator_is_supported_voltage(cpu_reg, + cpu_volts[i * 2], cpu_volts[i * 2 + 1]); Is there any reason you didn't export symbol regulator_is_supported_voltage? and also it don't have !REGULATOR dummy implementation. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V5 4/7] cpufreq: add clk-reg cpufreq driver
On Wed, Dec 28, 2011 at 11:14:10AM +0800, Richard Zhao wrote: Hi Mark, [...] + if (cpu_reg) { + ret = regulator_is_supported_voltage(cpu_reg, + cpu_volts[i * 2], cpu_volts[i * 2 + 1]); Is there any reason you didn't export symbol regulator_is_supported_voltage? and also it don't have !REGULATOR dummy implementation. regulator_set_voltage_time and some other functions don't have dummy one either. Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver
On Mon, Dec 26, 2011 at 11:10:30AM +, Mark Brown wrote: On Sat, Dec 24, 2011 at 11:52:29PM +0800, Richard Zhao wrote: On Sat, Dec 24, 2011 at 01:42:29PM +, Mark Brown wrote: On Sat, Dec 24, 2011 at 09:28:33PM +0800, Richard Zhao wrote: If you think regulator thansition latency is board specific, then the board dts can overrite it. We should just query this information from the regulator subsystem (there's hooks but currently nothing implements them). The regulators can define their own bindings if they need to read it from device tree, most of them should be able to do this as a function of knowing about the device. None of this is specific to cpufreq so cpufreq shouldn't have to define its own support for this. I'd like to query the latency by call clk and regulator APIs. but as you said both of them have not implemented it yet. I think, for now, we can use the The *call* is there in the regulator subsystem, it's just that none of the drivers back it up with an actual implementation yet. Which turns out to be a good thing as cpufreq can't currently understand variable latencies and the governors don't deal well with non-trivial latencies anyway. but clk API don't have such calls. and many SoCs only adjust clk frequencies, using one single voltage. property to get the total latency. Once I can get it at runtime, I'll remove it. So the definition of trans-latency is just the same as cpufreq transition_latency, people get less confused. What do you think? The problem with device tree is that once you've defined a binding you're stuck with it, it's very hard to change - witness all the magic number based stuff with the interrupt bindings for example So what's your suggestion? We can not set transition_latency to set random number. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver
On Fri, Dec 23, 2011 at 01:18:51PM +, Mark Brown wrote: On Thu, Dec 22, 2011 at 03:09:10PM +0800, Richard Zhao wrote: The driver get cpu operation point table from device tree cpu0 node, and adjusts operating points using clk and regulator APIs. Reviewed-by: Mark Brown broo...@opensource.wolfsonmicro.com Thanks. but one nit: +Required properties in /cpus/cpu@0: +- cpu-freqs : cpu frequency points it support, in unit of Hz. +- cpu-volts : cpu voltages required by the frequency point at the same index, + in unit of uV. +- trans-latency : transition_latency, in unit of ns. trans-latency should really say what latency is being measured (the CPU core only or the whole operation). dts only descibe hw info. so the transition latency is for hw. - trans-latency : transition latency of HW, in unit of ns. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver
On Sat, Dec 24, 2011 at 01:42:29PM +, Mark Brown wrote: On Sat, Dec 24, 2011 at 09:28:33PM +0800, Richard Zhao wrote: On Sat, Dec 24, 2011 at 12:24:11PM +, Mark Brown wrote: - trans-latency : transition latency of cpu freq and related regulator, in unit of ns. Does it look better? I think it shouldn't include the regulator part of things. If you think regulator thansition latency is board specific, then the board dts can overrite it. We should just query this information from the regulator subsystem (there's hooks but currently nothing implements them). The regulators can define their own bindings if they need to read it from device tree, most of them should be able to do this as a function of knowing about the device. None of this is specific to cpufreq so cpufreq shouldn't have to define its own support for this. I'd like to query the latency by call clk and regulator APIs. but as you said both of them have not implemented it yet. I think, for now, we can use the property to get the total latency. Once I can get it at runtime, I'll remove it. So the definition of trans-latency is just the same as cpufreq transition_latency, people get less confused. What do you think? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Wed, Dec 21, 2011 at 09:20:46AM +0800, Richard Zhao wrote: Hi Mark, On Tue, Dec 20, 2011 at 11:48:45PM +, Mark Brown wrote: On Wed, Dec 21, 2011 at 07:27:03AM +0800, Richard Zhao wrote: On Tue, Dec 20, 2011 at 02:59:04PM +, Mark Brown wrote: My comments on the previous version of the patch still apply: - The voltage ranges being set need to be specified as ranges. cpu normally need strict voltages. and only proved operating opints are allowed to set in dts. If the voltage changes slightly especially for high frequency, it's easy to cause unstable. Clearly there will be limits which get more and more restrictive as the frequencies get higher but there will always be at least some play in the numbers as one must at a minimum specify tolerance ranges, and at lower frequencies the ranges specified will typically get compartively large. hmm, reasonable. I'll add it in dts. Thanks. Note also that not all hardware specifies things in terms of a fixed set of operating points, sometimes only the minimum voltage specification is varied with frequency or sometimes you see maximum and minimum stepping independently. cpus that don't use freq table is out of scope of this driver. Further note that if all hardware really does have as tight a set of requirements as you suggest then the regulator support in the driver needs to be non-optional otherwise a board without software regulator control might drop the frequency without also dropping the voltage. It's ok to only adjuct freq without changes voltage. You can find many arm soc cpufreq drivers don't change voltage. If dts specify voltage but don't have such regulator. I'll assume it always runs on the initial volatage (highest for most cases). - Frequencies that can't be supported due to limitations of the available supplies shouldn't be exposed to users. As I said, only proved operation points are allowed. This statement appears to be unrelated to the comment you're replying to. I meant the exact voltage can always successfull set. Anyway, I'll add regulator_set_voltage return value checking. You also need to define how the core supplies get looked up. It's pure software. platform uses this driver have to define cpu consumer. You still need to define this in the binding. You mean regulator DT binding? already in ? I'll check it. Mark, cpu node is not a struct device, sys_device instead. I can not find regulator via device/dt node. Can I still use the string to get regulator after converting to DT? And regulator binding is not on cpufreq git tree. Thanks Richard + pr_info(Generic CPU frequency driver\n); This seems noisy... Why? Do you think only errors and warnings can print out? Yes. Maybe I can remove it. But I'd probably add freq table dump. It's more important. Agree? I checked pr_fmt. Thanks very much. I'll use below and remove __func_. #define pr_fmt(fmt) KBUILD_MODNAME : fmt Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Wed, Dec 21, 2011 at 01:49:07PM +0100, Kay Sievers wrote: On Wed, Dec 21, 2011 at 13:12, Mark Brown broo...@opensource.wolfsonmicro.com wrote: On Wed, Dec 21, 2011 at 12:44:57PM +0100, Kay Sievers wrote: We will convert all classes to buses over time time, and have a single type of device and a single type of subsystem. Are there any conversions that have been done already that I can look at for reference? The first step is the conversion from 'sys_device' to 'device', which is here: http://git.kernel.org/?p=linux/kernel/git/kay/patches.git;a=tree That should hit the tree soon, if all works according to plan. All sys_devices and sysdev classes will be gone for forever. Even cpu node is device, I still need to find a way to get it. I think it's better have another patch to fix the regulator dt binding in cpu node. I'll not include it in this patch series. Richard The 'class' to 'bus' work is simpler, because the logic in both of them is very similar and both use the same 'struct device' already. We'll need to add some convenience APIs to bus, and add code to make sure the converted stuff has compat symlinks in /sys/class when needed. Then we can convert-over one 'struct class' to 'struct bus_type' after the other until 'struct class' can be deleted. This work has not yet started, because we are busy with the sys_device stuff at the moment. No new stuff should use 'struct class' or 'struct sys_device', they should all start right away with 'struct bus_type'. Kay ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 1/7] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp
Hi Russel, Are the patch #1 #2 #3 ok for you? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH v4 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa97..39cf00a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -595,6 +595,7 @@ comment i.MX6 family: config SOC_IMX6Q bool i.MX6 Quad support + select ARCH_HAS_CPUFREQ select ARM_GIC select CACHE_L2X0 select CPU_V7 -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH v4 5/7] dts/imx6q: add cpufreq property
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |7 +++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..2087db7 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,13 @@ compatible = arm,cortex-a9; reg = 0; next-level-cache = L2; + cpu-freqs = 99600 79200 39600 19800; + cpu-volts =/* min max */ + 1225000 145 /* 996M */ + 110 145 /* 792M */ + 95 145 /* 396M */ + 85 145; /* 198M */ + trans-latency = 61036; /* two CLK32 periods */ }; cpu@1 { -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH v4 0/7] add a generic cpufreq driver
Thanks Arnd, Mark, Jamie, Rob, for your review. Changes in v4: - add depends on HAVE_CLK OF REGULATOR - add set_cpu_freq fail check - regulator_put wehn module exit - add pr_fmt and convert all printk to pr_xxx - use voltage range - comment and doc fix - add cpu_volts value pre-check in module init - add helpfull module parameter max_freq - remove compatible string check on Arnd's comment. - remove generic-cpufreq to clk-reg-cpufreq Changes in v3: - move adjusting smp loops_per_jiffy to arm common code, and also adjust global loops_per_jiffy. - remove adjusting loops_per_jiffy in imx and omap cpufreq drivers. - check compatible generic-cpufreq when module_init - change printk to pr_xxx - add generic-cpufreq DT binding doc Changes in v2: - add volatage change support - change '_' in property name to '-' - use initial value to calculate loops_per_jiffy - fix reading cpu_volts property bug - let cpufreq_frequency_table_cpuinfo routines handle cpu_freq_khz_max/min - don't change freq in arm_cpufreq_exit, because every core share the same freq. - use unsigned long describe frequency as much as possible. Because clk use unsigned long, but cpufreq use unsigned int. [PATCH v4 1/7] ARM: add cpufreq transiton notifier to adjust [PATCH v4 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate [PATCH v4 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for [PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver [PATCH v4 5/7] dts/imx6q: add cpufreq property [PATCH v4 6/7] arm/imx6q: register arm_clk as cpu to clkdev [PATCH v4 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH v4 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/omap-cpufreq.c | 36 1 files changed, 0 insertions(+), 36 deletions(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5d04c57..17da4c4 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -37,16 +37,6 @@ #include mach/hardware.h -#ifdef CONFIG_SMP -struct lpj_info { - unsigned long ref; - unsigned intfreq; -}; - -static DEFINE_PER_CPU(struct lpj_info, lpj_ref); -static struct lpj_info global_lpj_ref; -#endif - static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); static struct clk *mpu_clk; @@ -118,32 +108,6 @@ static int omap_target(struct cpufreq_policy *policy, ret = clk_set_rate(mpu_clk, freqs.new * 1000); freqs.new = omap_getspeed(policy-cpu); -#ifdef CONFIG_SMP - /* -* Note that loops_per_jiffy is not updated on SMP systems in -* cpufreq driver. So, update the per-CPU loops_per_jiffy value -* on frequency transition. We need to update all dependent CPUs. -*/ - for_each_cpu(i, policy-cpus) { - struct lpj_info *lpj = per_cpu(lpj_ref, i); - if (!lpj-freq) { - lpj-ref = per_cpu(cpu_data, i).loops_per_jiffy; - lpj-freq = freqs.old; - } - - per_cpu(cpu_data, i).loops_per_jiffy = - cpufreq_scale(lpj-ref, lpj-freq, freqs.new); - } - - /* And don't forget to adjust the global one */ - if (!global_lpj_ref.freq) { - global_lpj_ref.ref = loops_per_jiffy; - global_lpj_ref.freq = freqs.old; - } - loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, - freqs.new); -#endif - /* notifiers */ for_each_cpu(i, policy-cpus) { freqs.cpu = i; -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH v4 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/plat-mxc/cpufreq.c | 10 -- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c index c937e75..364793a 100644 --- a/arch/arm/plat-mxc/cpufreq.c +++ b/arch/arm/plat-mxc/cpufreq.c @@ -99,16 +99,6 @@ static int mxc_set_target(struct cpufreq_policy *policy, ret = set_cpu_freq(freq_Hz); -#ifdef CONFIG_SMP - /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. -* So update it for all CPUs. -*/ - for_each_possible_cpu(cpu) - per_cpu(cpu_data, cpu).loops_per_jiffy = - cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, - freqs.old, freqs.new); -#endif - for_each_possible_cpu(cpu) { freqs.cpu = cpu; cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH v4 4/7] cpufreq: add clk-reg cpufreq driver
The driver get cpu operation point table from device tree cpu0 node, and adjusts operating points using clk and regulator APIs. It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- .../devicetree/bindings/cpufreq/clk-reg-cpufreq|7 + drivers/cpufreq/Kconfig| 10 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/clk-reg-cpufreq.c | 289 4 files changed, 308 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq create mode 100644 drivers/cpufreq/clk-reg-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq b/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq new file mode 100644 index 000..bf07c1b --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/clk-reg-cpufreq @@ -0,0 +1,7 @@ +Generic cpufreq driver based on clk and regulator APIs + +Required properties in /cpus/cpu@0: +- cpu-freqs : cpu frequency points it support, in unit of Hz. +- cpu-volts : cpu voltages required by the frequency point at the same index, + in unit of uV. +- trans-latency : transition_latency, in unit of ns. diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..95470f1 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,16 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config CLK_REG_CPUFREQ_DRIVER + tristate Generic cpufreq driver using clk and regulator APIs + depends on HAVE_CLK OF REGULATOR + select CPU_FREQ_TABLE + help + This adds generic CPUFreq driver based on clk and regulator APIs. + It assumes all cores of the CPU share the same clock and voltage. + + If in doubt, say N. + menu x86 CPU frequency scaling drivers depends on X86 source drivers/cpufreq/Kconfig.x86 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..2c4eb33 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_CLK_REG_CPUFREQ_DRIVER) += clk-reg-cpufreq.o + ## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early diff --git a/drivers/cpufreq/clk-reg-cpufreq.c b/drivers/cpufreq/clk-reg-cpufreq.c new file mode 100644 index 000..c30d2c5 --- /dev/null +++ b/drivers/cpufreq/clk-reg-cpufreq.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#define pr_fmt(fmt)KBUILD_MODNAME : fmt + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h + +static u32 *cpu_freqs; /* Hz */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; +static unsigned int cur_index; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) { + ret = regulator_set_voltage(cpu_reg, + cpu_volts[index * 2], cpu_volts[index * 2 + 1]); + if (ret) { + pr_err(set cpu voltage failed!\n); + return ret; + } + } + + ret = clk_set_rate(cpu_clk, freq); + if (ret) { + if (cpu_reg) + regulator_set_voltage(cpu_reg, cpu_volts[cur_index * 2], + cpu_volts[cur_index * 2 + 1]); + pr_err(cannot set CPU clock rate\n); + return ret; + } + + if (!higher cpu_reg) { + ret = regulator_set_voltage(cpu_reg, + cpu_volts[index * 2], cpu_volts[index * 2 + 1]); + if (ret) + pr_warn(set cpu voltage failed, might run on +higher voltage!\n); + ret = 0; + } + + return ret; +} + +static int clk_reg_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static unsigned int
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
在 2011-12-20 下午11:22,Arnd Bergmann a...@arndb.de写道: On Tuesday 20 December 2011, Richard Zhao wrote: +Generic cpufreq driver + +Required properties in /cpus/cpu@0: +- compatible : generic-cpufreq I'm not convinced this is the best way to do this. By requiring a generic-cpufreq compatible string we're encoding Linux driver information into the hardware description. The only way I can see to avoid this is to provide a generic_clk_cpufreq_init() function that platforms can call in their machine init code to use the driver. Agreed on the compatible string. Assume you reject to use compatible string. It's putting Linux specifics into DT. You could flip this around and have the module make a call into the kernel to determine whether to initialize or not. Then platforms could set a flag to indicate this. Could you make it more clear? kernel global variable, macro, or function? - Following your idea, I think, we can add in driver/cpufreq/cpufreq.c: int (*clk_reg_cpufreq_get_op_table) (struct op_table *tbl, int *size); SoC code set the callback. If it's NULL, driver will exit. We can get rid of DT. It'll make cpufreq core dirty, but it's the only file built-in. - Drop module support. SoC call generic_clk_cpufreq_init as Jamie said. I think you don't actually need a compatible property here, as long as we ensure that the cpu-freqs, cpu-volts and trans-latency properties are present in the cpu node if and only if the machine works with this driver (why else would you put them there?). It is more easy for me. Rob, agree? Richard CPUs are special in the device trees in a number of ways, so I think we can treat this as a logical extension. This way, you can still make the generic cpufreq driver a loadable module. You don't get module autoloading with this structure, but that is already the case because the cpu nodes in the device tree are not translated into linux devices. Arnd ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
在 2011-12-20 下午11:13,Rob Herring robherri...@gmail.com写道: On 12/19/2011 07:59 PM, Richard Zhao wrote: On Mon, Dec 19, 2011 at 09:00:44AM -0600, Rob Herring wrote: On 12/19/2011 08:39 AM, Jamie Iles wrote: On Mon, Dec 19, 2011 at 10:19:29PM +0800, Richard Zhao wrote: On Mon, Dec 19, 2011 at 10:05:12AM +, Jamie Iles wrote: Hi Richard, On Mon, Dec 19, 2011 at 11:21:40AM +0800, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- .../devicetree/bindings/cpufreq/generic-cpufreq|7 + drivers/cpufreq/Kconfig|8 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/generic-cpufreq.c | 251 4 files changed, 268 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/generic-cpufreq create mode 100644 drivers/cpufreq/generic-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/generic-cpufreq b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq new file mode 100644 index 000..15dd780 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq @@ -0,0 +1,7 @@ +Generic cpufreq driver + +Required properties in /cpus/cpu@0: +- compatible : generic-cpufreq I'm not convinced this is the best way to do this. By requiring a generic-cpufreq compatible string we're encoding Linux driver information into the hardware description. The only way I can see to avoid this is to provide a generic_clk_cpufreq_init() function that platforms can call in their machine init code to use the driver. Agreed on the compatible string. Assume you reject to use compatible string. It's putting Linux specifics into DT. You could flip this around and have the module make a call into the kernel to determine whether to initialize or not. Then platforms could set a flag to indicate this. Could you make it more clear? kernel global variable, macro, or function? Any of those. Of course, direct access to variables across modules is discouraged, so it would probably be a function that checks a variable. why not use function pointer? arch that don't use this driver do not have to set it. if use function, everyone should define it. - Following your idea, I think, we can add in driver/cpufreq/cpufreq.c: int (*clk_reg_cpufreq_get_op_table) (struct op_table *tbl, int *size); SoC code set the callback. If it's NULL, driver will exit. We can get rid of DT. It'll make cpufreq core dirty, but it's the only file built-in. But aren't you getting the operating points from the DT? Then you don't want to put this code into each platform. the variable is mainly used to check whether some platform want to use this driver. getting ride of dt is side affect. - Drop module support. SoC call generic_clk_cpufreq_init as Jamie said. It'll prevent the driver from being a kernel module. Hmm, that's not very nice either! I guess you _could_ add an of_machine_is_compatible() check against a list of compatible machines in the driver but that feels a little gross. Hopefully Rob or Grant have a good alternative! What does cpufreq core do if multiple drivers are registered? current cpufreq core only support one cpufreq_driver. Others will fail except the first time. Then whoever gets there first wins. Make your driver register late and if someone doesn't want to use it they can register a custom driver earlier. this driver did Rob Perhaps a ranking is needed and this would only get enabled if there are no other drivers and other conditions like having the clock cpu present are met. We'd better keep cpufreq core simple. For this driver, register cpufreq_driver is the last thing after checking all conditions. Rob Hi Grant Rob, Could you comment? +- cpu-freqs : cpu frequency points it support +- cpu-volts : cpu voltages required by the frequency point at the same index +- trans-latency : transition_latency diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..216eecd 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,14 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config GENERIC_CPUFREQ_DRIVER +bool Generic cpufreq driver using clock/regulator/devicetree +help + This adds generic CPUFreq driver. It assumes all + cores of the CPU share the same clock and voltage. + + If in doubt, say N. I think this needs dependencies on HAVE_CLK, OF and REGULATOR. right, Thanks. I can not check clk before generic clock framework come in. Added: depends on OF REGULATOR select CPU_FREQ_TABLE You can still use HAVE_CLK
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Tue, Dec 20, 2011 at 02:59:04PM +, Mark Brown wrote: On Mon, Dec 19, 2011 at 11:21:40AM +0800, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. My comments on the previous version of the patch still apply: - The voltage ranges being set need to be specified as ranges. cpu normally need strict voltages. and only proved operating opints are allowed to set in dts. If the voltage changes slightly especially for high frequency, it's easy to cause unstable. - Frequencies that can't be supported due to limitations of the available supplies shouldn't be exposed to users. As I said, only proved operation points are allowed. - The driver needs to handle errors. Yes. +Required properties in /cpus/cpu@0: +- compatible : generic-cpufreq +- cpu-freqs : cpu frequency points it support +- cpu-volts : cpu voltages required by the frequency point at the same index +- trans-latency : transition_latency You need to define units for all of these, and for the transition latency you need to be clear about what's being measured (it looks like the CPU time only, not any voltage ramping). right. You also need to define how the core supplies get looked up. It's pure software. platform uses this driver have to define cpu consumer. + /* Manual states, that PLL stabilizes in two CLK32 periods */ + policy-cpuinfo.transition_latency = trans_latency; I guess this comment is a cut'n'paste error. right, thanks. + + ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); + + if (ret 0) { + pr_err(%s: invalid frequency table for cpu %d\n, + __func__, policy-cpu); You should define pr_fmt to always include __func__ in the messages rather than open coding - ensures consistency and is less noisy in the code. I'll check it. + pr_info(Generic CPU frequency driver\n); This seems noisy... Why? Do you think only errors and warnings can print out? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
Hi Mark, On Tue, Dec 20, 2011 at 11:48:45PM +, Mark Brown wrote: On Wed, Dec 21, 2011 at 07:27:03AM +0800, Richard Zhao wrote: On Tue, Dec 20, 2011 at 02:59:04PM +, Mark Brown wrote: My comments on the previous version of the patch still apply: - The voltage ranges being set need to be specified as ranges. cpu normally need strict voltages. and only proved operating opints are allowed to set in dts. If the voltage changes slightly especially for high frequency, it's easy to cause unstable. Clearly there will be limits which get more and more restrictive as the frequencies get higher but there will always be at least some play in the numbers as one must at a minimum specify tolerance ranges, and at lower frequencies the ranges specified will typically get compartively large. hmm, reasonable. I'll add it in dts. Thanks. Note also that not all hardware specifies things in terms of a fixed set of operating points, sometimes only the minimum voltage specification is varied with frequency or sometimes you see maximum and minimum stepping independently. cpus that don't use freq table is out of scope of this driver. Further note that if all hardware really does have as tight a set of requirements as you suggest then the regulator support in the driver needs to be non-optional otherwise a board without software regulator control might drop the frequency without also dropping the voltage. It's ok to only adjuct freq without changes voltage. You can find many arm soc cpufreq drivers don't change voltage. If dts specify voltage but don't have such regulator. I'll assume it always runs on the initial volatage (highest for most cases). - Frequencies that can't be supported due to limitations of the available supplies shouldn't be exposed to users. As I said, only proved operation points are allowed. This statement appears to be unrelated to the comment you're replying to. I meant the exact voltage can always successfull set. Anyway, I'll add regulator_set_voltage return value checking. You also need to define how the core supplies get looked up. It's pure software. platform uses this driver have to define cpu consumer. You still need to define this in the binding. You mean regulator DT binding? already in ? I'll check it. + pr_info(Generic CPU frequency driver\n); This seems noisy... Why? Do you think only errors and warnings can print out? Yes. Maybe I can remove it. But I'd probably add freq table dump. It's more important. Agree? I checked pr_fmt. Thanks very much. I'll use below and remove __func_. #define pr_fmt(fmt) KBUILD_MODNAME : fmt Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Wed, Dec 21, 2011 at 01:32:21AM +, Mark Brown wrote: On Wed, Dec 21, 2011 at 09:20:46AM +0800, Richard Zhao wrote: On Tue, Dec 20, 2011 at 11:48:45PM +, Mark Brown wrote: Note also that not all hardware specifies things in terms of a fixed set of operating points, sometimes only the minimum voltage specification is varied with frequency or sometimes you see maximum and minimum stepping independently. cpus that don't use freq table is out of scope of this driver. That's not the point - the point is that you may do something like specify a defined set of frequencies and just drop the minimum supported voltage without altering the maximum supported voltage as the frequency gets lower. What do you mean by drop? cpu-volts = /* min max */ 110 120 /* 1G HZ */ 100 120 /* 800M HZ */ 90 120 /* 600M HZ */ ; The above sample dts could meet your point? Further note that if all hardware really does have as tight a set of requirements as you suggest then the regulator support in the driver needs to be non-optional otherwise a board without software regulator control might drop the frequency without also dropping the voltage. It's ok to only adjuct freq without changes voltage. You can find many arm soc cpufreq drivers don't change voltage. If dts specify voltage but don't have such regulator. I'll assume it always runs on the initial volatage (highest for most cases). My point exactly; such devices are examples of the policy outlined above where only the minimum voltage changes with frequency and the maximum voltage is constant. The cpufreq driver would lower the supported voltage when possible but wouldn't actually care if the voltage changes. accepted seting voltage range. I guess the above sample dts code meet your point. - Frequencies that can't be supported due to limitations of the available supplies shouldn't be exposed to users. As I said, only proved operation points are allowed. This statement appears to be unrelated to the comment you're replying to. I meant the exact voltage can always successfull set. Anyway, I'll add This is just not the case. Regulators don't offer a continuous range of voltages, they offer steps of varying sizes which may miss setting some voltages, and board designers may choose not to support some of the voltage range. regulator_set_voltage return value checking. While this is important the driver should also be enumerating the supported voltages at probe time and eliminating unsupportable settings so that governors aren't constantly trying to set things that can never be supported. The s3c64xx cpufreq driver provides an implementation of this. I'll use regulator_is_supported_voltage pre-check the cpu-volts. For clock, conditions ((clk_round_rate(cpu-freq)/1000) * 1000 == cpu-freq) seems too strict. Because cpu clock is SoC dependent, I'll not add the check. Maybe I can remove it. But I'd probably add freq table dump. It's more important. Agree? That seems like something the core should be doing if hmm, cpu table dumps it with pr_debug. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Wed, Dec 21, 2011 at 02:33:36AM +, Mark Brown wrote: On Wed, Dec 21, 2011 at 10:24:53AM +0800, Richard Zhao wrote: On Wed, Dec 21, 2011 at 01:32:21AM +, Mark Brown wrote: That's not the point - the point is that you may do something like specify a defined set of frequencies and just drop the minimum supported voltage without altering the maximum supported voltage as the frequency gets lower. What do you mean by drop? Drop is a synonym for lower in this context. cpu-volts = /* min max */ 110 120 /* 1G HZ */ 100 120 /* 800M HZ */ 90 120 /* 600M HZ */ ; The above sample dts could meet your point? Yes. While this is important the driver should also be enumerating the supported voltages at probe time and eliminating unsupportable settings so that governors aren't constantly trying to set things that can never be supported. The s3c64xx cpufreq driver provides an implementation of this. I'll use regulator_is_supported_voltage pre-check the cpu-volts. For clock, conditions ((clk_round_rate(cpu-freq)/1000) * 1000 == cpu-freq) seems too strict. Because cpu clock is SoC dependent, I'll not add the check. The issue that was there for is that there are multiple runtime detectable variant clocking configurations which couldn't be switched between so the driver needs to select only the rates that can be reached from the current configuration. I'd imagine that might be an issue elsewhere. one case is that, cpu freq is 800M, clock may only reach 799M. I'd rather let clock code to decide how to handle 800M request. That's why I said the condition check is too strict. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Mon, Dec 19, 2011 at 10:05:12AM +, Jamie Iles wrote: Hi Richard, On Mon, Dec 19, 2011 at 11:21:40AM +0800, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- .../devicetree/bindings/cpufreq/generic-cpufreq|7 + drivers/cpufreq/Kconfig|8 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/generic-cpufreq.c | 251 4 files changed, 268 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/generic-cpufreq create mode 100644 drivers/cpufreq/generic-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/generic-cpufreq b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq new file mode 100644 index 000..15dd780 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq @@ -0,0 +1,7 @@ +Generic cpufreq driver + +Required properties in /cpus/cpu@0: +- compatible : generic-cpufreq I'm not convinced this is the best way to do this. By requiring a generic-cpufreq compatible string we're encoding Linux driver information into the hardware description. The only way I can see to avoid this is to provide a generic_clk_cpufreq_init() function that platforms can call in their machine init code to use the driver. It'll prevent the driver from being a kernel module. Hi Grant Rob, Could you comment? +- cpu-freqs : cpu frequency points it support +- cpu-volts : cpu voltages required by the frequency point at the same index +- trans-latency : transition_latency diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..216eecd 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,14 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config GENERIC_CPUFREQ_DRIVER + bool Generic cpufreq driver using clock/regulator/devicetree + help + This adds generic CPUFreq driver. It assumes all + cores of the CPU share the same clock and voltage. + + If in doubt, say N. I think this needs dependencies on HAVE_CLK, OF and REGULATOR. right, Thanks. I can not check clk before generic clock framework come in. Added: depends on OF REGULATOR select CPU_FREQ_TABLE + menu x86 CPU frequency scaling drivers depends on X86 source drivers/cpufreq/Kconfig.x86 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..2dbdab1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_GENERIC_CPUFREQ_DRIVER) += generic-cpufreq.o + ## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early diff --git a/drivers/cpufreq/generic-cpufreq.c b/drivers/cpufreq/generic-cpufreq.c new file mode 100644 index 000..781bb9b --- /dev/null +++ b/drivers/cpufreq/generic-cpufreq.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h + +static u32 *cpu_freqs; /* HZ */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + pr_err(generic-cpufreq: cannot set CPU clock rate\n); + return ret; + } + + if (!higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + return ret; +} + +static int generic_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify
Re: [PATCH V3 4/7] cpufreq: add generic cpufreq driver
On Mon, Dec 19, 2011 at 09:00:44AM -0600, Rob Herring wrote: On 12/19/2011 08:39 AM, Jamie Iles wrote: On Mon, Dec 19, 2011 at 10:19:29PM +0800, Richard Zhao wrote: On Mon, Dec 19, 2011 at 10:05:12AM +, Jamie Iles wrote: Hi Richard, On Mon, Dec 19, 2011 at 11:21:40AM +0800, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- .../devicetree/bindings/cpufreq/generic-cpufreq|7 + drivers/cpufreq/Kconfig|8 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/generic-cpufreq.c | 251 4 files changed, 268 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/generic-cpufreq create mode 100644 drivers/cpufreq/generic-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/generic-cpufreq b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq new file mode 100644 index 000..15dd780 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq @@ -0,0 +1,7 @@ +Generic cpufreq driver + +Required properties in /cpus/cpu@0: +- compatible : generic-cpufreq I'm not convinced this is the best way to do this. By requiring a generic-cpufreq compatible string we're encoding Linux driver information into the hardware description. The only way I can see to avoid this is to provide a generic_clk_cpufreq_init() function that platforms can call in their machine init code to use the driver. Agreed on the compatible string. Assume you reject to use compatible string. It's putting Linux specifics into DT. You could flip this around and have the module make a call into the kernel to determine whether to initialize or not. Then platforms could set a flag to indicate this. Could you make it more clear? kernel global variable, macro, or function? - Following your idea, I think, we can add in driver/cpufreq/cpufreq.c: int (*clk_reg_cpufreq_get_op_table) (struct op_table *tbl, int *size); SoC code set the callback. If it's NULL, driver will exit. We can get rid of DT. It'll make cpufreq core dirty, but it's the only file built-in. - Drop module support. SoC call generic_clk_cpufreq_init as Jamie said. It'll prevent the driver from being a kernel module. Hmm, that's not very nice either! I guess you _could_ add an of_machine_is_compatible() check against a list of compatible machines in the driver but that feels a little gross. Hopefully Rob or Grant have a good alternative! What does cpufreq core do if multiple drivers are registered? current cpufreq core only support one cpufreq_driver. Others will fail except the first time. Perhaps a ranking is needed and this would only get enabled if there are no other drivers and other conditions like having the clock cpu present are met. We'd better keep cpufreq core simple. For this driver, register cpufreq_driver is the last thing after checking all conditions. Rob Hi Grant Rob, Could you comment? +- cpu-freqs : cpu frequency points it support +- cpu-volts : cpu voltages required by the frequency point at the same index +- trans-latency : transition_latency diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..216eecd 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,14 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config GENERIC_CPUFREQ_DRIVER +bool Generic cpufreq driver using clock/regulator/devicetree +help + This adds generic CPUFreq driver. It assumes all + cores of the CPU share the same clock and voltage. + + If in doubt, say N. I think this needs dependencies on HAVE_CLK, OF and REGULATOR. right, Thanks. I can not check clk before generic clock framework come in. Added: depends on OF REGULATOR select CPU_FREQ_TABLE You can still use HAVE_CLK. That symbol has been around for ages and any platform implementing the clk API should select it so it's fine to depend on it even before there is a generic struct clk. You are right. Thanks. Richard Jamie ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
On Sat, Dec 17, 2011 at 10:29:29AM +0100, Arnd Bergmann wrote: On Saturday 17 December 2011 16:00:03 Richard Zhao wrote: On Fri, Dec 16, 2011 at 08:32:35AM -0600, Rob Herring wrote: On 12/16/2011 04:30 AM, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/Kconfig.arm |8 ++ drivers/cpufreq/Makefile |1 + drivers/cpufreq/arm-cpufreq.c | 269 + 3 files changed, 278 insertions(+), 0 deletions(-) create mode 100644 drivers/cpufreq/arm-cpufreq.c What makes this specific to ARM and not a generic DT + clk api + regulator api driver? smp loops_per_jiffy update needs arm header asm/cpu.h. I would suggest to instead change the definition of adjust_jiffies in the core so it can be overridden by the architecture, like this diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 987a165..174584d 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -189,6 +189,7 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put); * systems as each CPU might be scaled differently. So, use the arch * per-CPU loops_per_jiffy value wherever possible. */ +#ifndef adjust_jiffies #ifndef CONFIG_SMP static unsigned long l_p_j_ref; static unsigned int l_p_j_ref_freq; @@ -218,7 +219,8 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; } -#endif +#endif /* CONFIG_SMP */ +#endif /* adjust_jiffies */ /** Then ARM (and any others that want the driver) can provide their own implementation and set #define adjust_jiffies(val, ci) adjust_jiffies((val), (ci)) to let the core use that instead of the generic UP version. While we're there, we should probably try to fix drivers that use loops_per_jiffy, because that is not what they think it is on SMP. Or let different arch register its different CPUFREQ_TRANSITION_NOTIFIER ? Thanks Richard Arnd ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
Hi Bryan, On Fri, Dec 16, 2011 at 11:59:02AM -0800, Bryan Huntsman wrote: On 12/16/2011 02:52 AM, Jamie Iles wrote: +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static unsigned long l_p_j_ref_freq; + +static struct clk *cpu_clk; This assumes that all CPU's share the same clk and run at the same rate. Is that a fair/safe assumption? I honestly don't know the answer to this so it's just a question!!! On MSM, cpus independently scale both frequency and voltage. Our clock driver isn't upstream yet. David Brown has a preliminary version here: https://www.codeaurora.org/gitweb/quic/kernel/?p=davidb/linux-msm.git;a=shortlog;h=refs/heads/msm-clock-rfc Once we get our driver upstream, MSM will be an exception and not select ARM_GENERIC_CPUFREQ. We'll probably have a separate msm-cpufreq.c driver under drivers/cpufreq/. Do you have to patch to implement per-cpu udelay? In current code, udelay uses global loops_per_jiffy. Thanks Richard - Bryan -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa97..39cf00a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -595,6 +595,7 @@ comment i.MX6 family: config SOC_IMX6Q bool i.MX6 Quad support + select ARCH_HAS_CPUFREQ select ARM_GIC select CACHE_L2X0 select CPU_V7 -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/omap-cpufreq.c | 36 1 files changed, 0 insertions(+), 36 deletions(-) diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 5d04c57..17da4c4 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -37,16 +37,6 @@ #include mach/hardware.h -#ifdef CONFIG_SMP -struct lpj_info { - unsigned long ref; - unsigned intfreq; -}; - -static DEFINE_PER_CPU(struct lpj_info, lpj_ref); -static struct lpj_info global_lpj_ref; -#endif - static struct cpufreq_frequency_table *freq_table; static atomic_t freq_table_users = ATOMIC_INIT(0); static struct clk *mpu_clk; @@ -118,32 +108,6 @@ static int omap_target(struct cpufreq_policy *policy, ret = clk_set_rate(mpu_clk, freqs.new * 1000); freqs.new = omap_getspeed(policy-cpu); -#ifdef CONFIG_SMP - /* -* Note that loops_per_jiffy is not updated on SMP systems in -* cpufreq driver. So, update the per-CPU loops_per_jiffy value -* on frequency transition. We need to update all dependent CPUs. -*/ - for_each_cpu(i, policy-cpus) { - struct lpj_info *lpj = per_cpu(lpj_ref, i); - if (!lpj-freq) { - lpj-ref = per_cpu(cpu_data, i).loops_per_jiffy; - lpj-freq = freqs.old; - } - - per_cpu(cpu_data, i).loops_per_jiffy = - cpufreq_scale(lpj-ref, lpj-freq, freqs.new); - } - - /* And don't forget to adjust the global one */ - if (!global_lpj_ref.freq) { - global_lpj_ref.ref = loops_per_jiffy; - global_lpj_ref.freq = freqs.old; - } - loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, - freqs.new); -#endif - /* notifiers */ for_each_cpu(i, policy-cpus) { freqs.cpu = i; -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 5/7] dts/imx6q: add cpufreq property
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |5 - 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..80e47b5 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -26,9 +26,12 @@ #size-cells = 0; cpu@0 { - compatible = arm,cortex-a9; + compatible = arm,cortex-a9, generic-cpufreq; reg = 0; next-level-cache = L2; + cpu-freqs = 99600 79200 39600 19800; + cpu-volts = 1225000 110 95 85; + trans-latency = 61036; /* two CLK32 periods */ }; cpu@1 { -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate for smp
arm registered cpufreq transition notifier to recalculate it. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/plat-mxc/cpufreq.c | 10 -- 1 files changed, 0 insertions(+), 10 deletions(-) diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c index c937e75..364793a 100644 --- a/arch/arm/plat-mxc/cpufreq.c +++ b/arch/arm/plat-mxc/cpufreq.c @@ -99,16 +99,6 @@ static int mxc_set_target(struct cpufreq_policy *policy, ret = set_cpu_freq(freq_Hz); -#ifdef CONFIG_SMP - /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. -* So update it for all CPUs. -*/ - for_each_possible_cpu(cpu) - per_cpu(cpu_data, cpu).loops_per_jiffy = - cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, - freqs.old, freqs.new); -#endif - for_each_possible_cpu(cpu) { freqs.cpu = cpu; cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 0/7] add a generic cpufreq driver
The driver support single core and multi core ARM SoCs. For multi core, it assume all cores share the same clock and voltage. TODO: - Add each core seperate freq/volt support (MSM). Changes in v3: - move adjusting smp loops_per_jiffy to arm common code, and also adjust global loops_per_jiffy. - remove adjusting loops_per_jiffy in imx and omap cpufreq drivers. - check compatible generic-cpufreq when module_init - change printk to pr_xxx - add generic-cpufreq DT binding doc Changes in v2: - add volatage change support - change '_' in property name to '-' - use initial value to calculate loops_per_jiffy - fix reading cpu_volts property bug - let cpufreq_frequency_table_cpuinfo routines handle cpu_freq_khz_max/min - don't change freq in arm_cpufreq_exit, because every core share the same freq. - use unsigned long describe frequency as much as possible. Because clk use unsigned long, but cpufreq use unsigned int. [PATCH V3 1/7] ARM: add cpufreq transiton notifier to adjust [PATCH V3 2/7] arm/imx: cpufreq: remove loops_per_jiffy recalculate [PATCH V3 3/7] cpufreq: OMAP: remove loops_per_jiffy recalculate for [PATCH V3 4/7] cpufreq: add generic cpufreq driver [PATCH V3 5/7] dts/imx6q: add cpufreq property [PATCH V3 6/7] arm/imx6q: register arm_clk as cpu to clkdev [PATCH V3 7/7] arm/imx6q: select ARCH_HAS_CPUFREQ ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 1/7] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp
If CONFIG_SMP, cpufreq skips loops_per_jiffy update, because different arch has different per-cpu loops_per_jiffy definition. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/kernel/smp.c | 54 + 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index ef5640b..ac9cadc 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -25,6 +25,7 @@ #include linux/percpu.h #include linux/clockchips.h #include linux/completion.h +#include linux/cpufreq.h #include linux/atomic.h #include asm/cacheflush.h @@ -631,3 +632,56 @@ int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; } + +#ifdef CONFIG_CPU_FREQ + +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq); +static unsigned long global_l_p_j_ref; +static unsigned long global_l_p_j_ref_freq; + +static int cpufreq_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct cpufreq_freqs *freq = data; + int cpu = freq-cpu; + + if (freq-flags CPUFREQ_CONST_LOOPS) + return NOTIFY_OK; + + if (!per_cpu(l_p_j_ref, cpu)) { + per_cpu(l_p_j_ref, cpu) = + per_cpu(cpu_data, cpu).loops_per_jiffy; + per_cpu(l_p_j_ref_freq, cpu) = freq-old; + if (!global_l_p_j_ref) { + global_l_p_j_ref = loops_per_jiffy; + global_l_p_j_ref_freq = freq-old; + } + } + + if ((val == CPUFREQ_PRECHANGE freq-old freq-new) || + (val == CPUFREQ_POSTCHANGE freq-old freq-new) || + (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) { + loops_per_jiffy = cpufreq_scale(global_l_p_j_ref, + global_l_p_j_ref_freq, + freq-new); + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(l_p_j_ref, cpu), + per_cpu(l_p_j_ref_freq, cpu), + freq-new); + } + return NOTIFY_OK; +} + +static struct notifier_block cpufreq_notifier = { + .notifier_call = cpufreq_callback, +}; + +static int __init register_cpufreq_notifier(void) +{ + return cpufreq_register_notifier(cpufreq_notifier, + CPUFREQ_TRANSITION_NOTIFIER); +} +core_initcall(register_cpufreq_notifier); + +#endif -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V3 4/7] cpufreq: add generic cpufreq driver
It support single core and multi-core ARM SoCs. But currently it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- .../devicetree/bindings/cpufreq/generic-cpufreq|7 + drivers/cpufreq/Kconfig|8 + drivers/cpufreq/Makefile |2 + drivers/cpufreq/generic-cpufreq.c | 251 4 files changed, 268 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/generic-cpufreq create mode 100644 drivers/cpufreq/generic-cpufreq.c diff --git a/Documentation/devicetree/bindings/cpufreq/generic-cpufreq b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq new file mode 100644 index 000..15dd780 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/generic-cpufreq @@ -0,0 +1,7 @@ +Generic cpufreq driver + +Required properties in /cpus/cpu@0: +- compatible : generic-cpufreq +- cpu-freqs : cpu frequency points it support +- cpu-volts : cpu voltages required by the frequency point at the same index +- trans-latency : transition_latency diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index e24a2a1..216eecd 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -179,6 +179,14 @@ config CPU_FREQ_GOV_CONSERVATIVE If in doubt, say N. +config GENERIC_CPUFREQ_DRIVER + bool Generic cpufreq driver using clock/regulator/devicetree + help + This adds generic CPUFreq driver. It assumes all + cores of the CPU share the same clock and voltage. + + If in doubt, say N. + menu x86 CPU frequency scaling drivers depends on X86 source drivers/cpufreq/Kconfig.x86 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..2dbdab1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_GENERIC_CPUFREQ_DRIVER) += generic-cpufreq.o + ## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early diff --git a/drivers/cpufreq/generic-cpufreq.c b/drivers/cpufreq/generic-cpufreq.c new file mode 100644 index 000..781bb9b --- /dev/null +++ b/drivers/cpufreq/generic-cpufreq.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h + +static u32 *cpu_freqs; /* HZ */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + pr_err(generic-cpufreq: cannot set CPU clock rate\n); + return ret; + } + + if (!higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + return ret; +} + +static int generic_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static unsigned int generic_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int generic_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long freq_Hz; + int cpu; + int ret = 0; + unsigned int index; + + cpufreq_frequency_table_target(policy, freq_table, + target_freq, relation, index); + freq_Hz = clk_round_rate(cpu_clk, cpu_freqs[index]); + freq_Hz = freq_Hz ? freq_Hz : cpu_freqs[index]; + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = freq_Hz / 1000; + freqs.flags = 0; + + if (freqs.old == freqs.new) + return 0; + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_PRECHANGE
[PATCH V3 6/7] arm/imx6q: register arm_clk as cpu to clkdev
cpufreq needs cpu clock to change frequency. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/clock-imx6q.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index 039a7ab..72acbc2 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -1911,6 +1911,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, gpmi_io_clk, gpmi_io_clk), _REGISTER_CLOCK(NULL, usboh3_clk, usboh3_clk), _REGISTER_CLOCK(NULL, sata_clk, sata_clk), + _REGISTER_CLOCK(NULL, cpu, arm_clk), }; int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
On Fri, Dec 16, 2011 at 12:26:03PM +0100, Heiko Stübner wrote: Am Freitag, 16. Dezember 2011, 11:30:59 schrieb Richard Zhao: It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/Kconfig.arm |8 ++ drivers/cpufreq/Makefile |1 + drivers/cpufreq/arm-cpufreq.c | 269 + 3 files changed, 278 insertions(+), 0 deletions(-) create mode 100644 drivers/cpufreq/arm-cpufreq.c looks quite cool, but should also provide a description of the devicetree bindings (i.e. like the rest in Documentation/devicetree/bindings/...) for future reference. Yes, Thanks for your remind. Heiko ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
On Fri, Dec 16, 2011 at 08:32:35AM -0600, Rob Herring wrote: On 12/16/2011 04:30 AM, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/Kconfig.arm |8 ++ drivers/cpufreq/Makefile |1 + drivers/cpufreq/arm-cpufreq.c | 269 + 3 files changed, 278 insertions(+), 0 deletions(-) create mode 100644 drivers/cpufreq/arm-cpufreq.c What makes this specific to ARM and not a generic DT + clk api + regulator api driver? smp loops_per_jiffy update needs arm header asm/cpu.h. Also, you need documentation of the DT bindings. Yes, Thanks. Richard Rob diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 72a0044..a0f7d35 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -2,6 +2,14 @@ # ARM CPU Frequency scaling drivers # +config ARM_GENERIC_CPUFREQ + bool ARM generic + help + This adds ARM generic CPUFreq driver. It assumes all + cores of the SoC share the same clock and voltage. + + If in doubt, say N. + config ARM_S3C64XX_CPUFREQ bool Samsung S3C64XX depends on CPU_S3C6410 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..6ccf02d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o ## # ARM SoC drivers +obj-$(CONFIG_ARM_GENERIC_CPUFREQ) += arm-cpufreq.o obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o diff --git a/drivers/cpufreq/arm-cpufreq.c b/drivers/cpufreq/arm-cpufreq.c new file mode 100644 index 000..e4d20da --- /dev/null +++ b/drivers/cpufreq/arm-cpufreq.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h +#include asm/cpu.h + +static u32 *cpu_freqs; /* HZ */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; + +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static unsigned long l_p_j_ref_freq; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *arm_freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + printk(KERN_DEBUG cannot set CPU clock rate\n); + return ret; + } + + if (!higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + return ret; +} + +static int arm_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, arm_freq_table); +} + +static unsigned int arm_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int arm_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long freq_Hz; + int cpu; + int ret = 0; + unsigned int index; + + cpufreq_frequency_table_target(policy, arm_freq_table, + target_freq, relation, index); + freq_Hz = clk_round_rate(cpu_clk, cpu_freqs[index]); + freq_Hz = freq_Hz ? freq_Hz : cpu_freqs[index]; + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = clk_round_rate(cpu_clk, cpu_freqs[index]); + freqs.new = freq_Hz / 1000; + freqs.flags = 0; + + if (freqs.old == freqs.new) + return 0; + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_PRECHANGE); + } + + ret = set_cpu_freq(freq_Hz, index, (freqs.new freqs.old)); + +#ifdef CONFIG_SMP + /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. +* So update
Re: [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
On Fri, Dec 16, 2011 at 10:52:29AM +, Jamie Iles wrote: Hi Richard, A couple of questions inline, but otherwise looks nice! Thanks for your review. Jamie On Fri, Dec 16, 2011 at 06:30:59PM +0800, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- [...] diff --git a/drivers/cpufreq/arm-cpufreq.c b/drivers/cpufreq/arm-cpufreq.c new file mode 100644 index 000..e4d20da --- /dev/null +++ b/drivers/cpufreq/arm-cpufreq.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h +#include asm/cpu.h + +static u32 *cpu_freqs; /* HZ */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; + +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static unsigned long l_p_j_ref_freq; + +static struct clk *cpu_clk; This assumes that all CPU's share the same clk and run at the same rate. Is that a fair/safe assumption? I honestly don't know the answer to this so it's just a question!!! As I know, most share the same clk/volt. From the code: IMX6: yes Tegra: Yes, but strange it sets CPUFREQ_SHARED_TYPE_ALL. MSM is an exception. I can support the case, but I have to make sure it's handy to use. +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *arm_freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + printk(KERN_DEBUG cannot set CPU clock rate\n); Perhaps use pr_debug() and friends throughout this driver? ok. Thanks. + return ret; + } + + if (!higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + return ret; +} + +static int arm_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, arm_freq_table); +} + +static unsigned int arm_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int arm_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long freq_Hz; + int cpu; + int ret = 0; + unsigned int index; + + cpufreq_frequency_table_target(policy, arm_freq_table, + target_freq, relation, index); + freq_Hz = clk_round_rate(cpu_clk, cpu_freqs[index]); + freq_Hz = freq_Hz ? freq_Hz : cpu_freqs[index]; + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = clk_round_rate(cpu_clk, cpu_freqs[index]); I forgot to delete this line. + freqs.new = freq_Hz / 1000; Why round the rate then overwrite it? Should this be freqs.new /= 1000? + freqs.flags = 0; + + if (freqs.old == freqs.new) + return 0; + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_PRECHANGE); + } + + ret = set_cpu_freq(freq_Hz, index, (freqs.new freqs.old)); + +#ifdef CONFIG_SMP + /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. +* So update it for all CPUs. +*/ + for_each_possible_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(l_p_j_ref, cpu), l_p_j_ref_freq, + freqs.new); +#endif + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); + } + + return ret; +} + +static int arm_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + + if (policy-cpu = num_possible_cpus()) + return -EINVAL; + + policy-cur = clk_get_rate(cpu_clk) / 1000; + policy-shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_setall(policy-cpus); + /* Manual states, that PLL stabilizes in two CLK32 periods */ + policy-cpuinfo.transition_latency = trans_latency; + + ret = cpufreq_frequency_table_cpuinfo(policy, arm_freq_table
Re: [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
On Fri, Dec 16, 2011 at 11:59:02AM -0800, Bryan Huntsman wrote: On 12/16/2011 02:52 AM, Jamie Iles wrote: +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static unsigned long l_p_j_ref_freq; + +static struct clk *cpu_clk; This assumes that all CPU's share the same clk and run at the same rate. Is that a fair/safe assumption? I honestly don't know the answer to this so it's just a question!!! On MSM, cpus independently scale both frequency and voltage. Our clock driver isn't upstream yet. David Brown has a preliminary version here: If - cpu_clk are per_cpu, and get from cpu0 clk, cpu1 clk, etc. The same to regulators. - set CPUFREQ_SHARED_TYPE_NONE - don't set affect cpus. Does that help you? Thanks Richard https://www.codeaurora.org/gitweb/quic/kernel/?p=davidb/linux-msm.git;a=shortlog;h=refs/heads/msm-clock-rfc Once we get our driver upstream, MSM will be an exception and not select ARM_GENERIC_CPUFREQ. We'll probably have a separate msm-cpufreq.c driver under drivers/cpufreq/. - Bryan -- Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [RFC V1 1/4] cpufreq: add arm soc generic cpufreq driver
On Fri, Dec 16, 2011 at 08:24:23AM +, Russell King - ARM Linux wrote: On Thu, Dec 15, 2011 at 12:50:07PM -0600, Mark Langsdorf wrote: I'd prefer to see clk_get90 replaced with of_clk_get() and get_this_cpu_node() from the clk-cpufreq driver by Jamie Iles that I resubmitted yesterday. Why isn't of_clk_get() hidden inside clk_get() ? Good point. ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V2 0/4] add arm soc generic cpufreq driver
The driver support single core and multi core ARM SoCs. For multi core, it assume all cores share the same clock and voltage. Changes in v2: - add volatage change support - change '_' in property name to '-' - use initial value to calculate loops_per_jiffy - fix reading cpu_volts property bug - let cpufreq_frequency_table_cpuinfo routines handle cpu_freq_khz_max/min - don't change freq in arm_cpufreq_exit, because every core share the same freq. - use unsigned long describe frequency as much as possible. Because clk use unsigned long, but cpufreq use unsigned int. [PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver [PATCH V2 2/4] dts/imx6q: add cpufreq property [PATCH V2 3/4] arm/imx6q: register arm_clk as cpu to clkdev [PATCH V2 4/4] arm/imx6q: select ARCH_HAS_CPUFREQ Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V2 4/4] arm/imx6q: select ARCH_HAS_CPUFREQ
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa97..39cf00a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -595,6 +595,7 @@ comment i.MX6 family: config SOC_IMX6Q bool i.MX6 Quad support + select ARCH_HAS_CPUFREQ select ARM_GIC select CACHE_L2X0 select CPU_V7 -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V2 3/4] arm/imx6q: register arm_clk as cpu to clkdev
cpufreq needs cpu clock to change frequency. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/clock-imx6q.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index 039a7ab..72acbc2 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -1911,6 +1911,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, gpmi_io_clk, gpmi_io_clk), _REGISTER_CLOCK(NULL, usboh3_clk, usboh3_clk), _REGISTER_CLOCK(NULL, sata_clk, sata_clk), + _REGISTER_CLOCK(NULL, cpu, arm_clk), }; int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[PATCH V2 1/4] cpufreq: add arm soc generic cpufreq driver
It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/Kconfig.arm |8 ++ drivers/cpufreq/Makefile |1 + drivers/cpufreq/arm-cpufreq.c | 269 + 3 files changed, 278 insertions(+), 0 deletions(-) create mode 100644 drivers/cpufreq/arm-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 72a0044..a0f7d35 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -2,6 +2,14 @@ # ARM CPU Frequency scaling drivers # +config ARM_GENERIC_CPUFREQ + bool ARM generic + help + This adds ARM generic CPUFreq driver. It assumes all + cores of the SoC share the same clock and voltage. + + If in doubt, say N. + config ARM_S3C64XX_CPUFREQ bool Samsung S3C64XX depends on CPU_S3C6410 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..6ccf02d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o ## # ARM SoC drivers +obj-$(CONFIG_ARM_GENERIC_CPUFREQ) += arm-cpufreq.o obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o diff --git a/drivers/cpufreq/arm-cpufreq.c b/drivers/cpufreq/arm-cpufreq.c new file mode 100644 index 000..e4d20da --- /dev/null +++ b/drivers/cpufreq/arm-cpufreq.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/regulator/consumer.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h +#include asm/cpu.h + +static u32 *cpu_freqs; /* HZ */ +static u32 *cpu_volts; /* uV */ +static u32 trans_latency; /* ns */ +static int cpu_op_nr; + +static DEFINE_PER_CPU(unsigned long, l_p_j_ref); +static unsigned long l_p_j_ref_freq; + +static struct clk *cpu_clk; +static struct regulator *cpu_reg; +static struct cpufreq_frequency_table *arm_freq_table; + +static int set_cpu_freq(unsigned long freq, int index, int higher) +{ + int ret = 0; + + if (higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + printk(KERN_DEBUG cannot set CPU clock rate\n); + return ret; + } + + if (!higher cpu_reg) + regulator_set_voltage(cpu_reg, + cpu_volts[index], cpu_volts[index]); + + return ret; +} + +static int arm_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, arm_freq_table); +} + +static unsigned int arm_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int arm_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long freq_Hz; + int cpu; + int ret = 0; + unsigned int index; + + cpufreq_frequency_table_target(policy, arm_freq_table, + target_freq, relation, index); + freq_Hz = clk_round_rate(cpu_clk, cpu_freqs[index]); + freq_Hz = freq_Hz ? freq_Hz : cpu_freqs[index]; + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = clk_round_rate(cpu_clk, cpu_freqs[index]); + freqs.new = freq_Hz / 1000; + freqs.flags = 0; + + if (freqs.old == freqs.new) + return 0; + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_PRECHANGE); + } + + ret = set_cpu_freq(freq_Hz, index, (freqs.new freqs.old)); + +#ifdef CONFIG_SMP + /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. +* So update it for all CPUs. +*/ + for_each_possible_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(l_p_j_ref, cpu), l_p_j_ref_freq, + freqs.new); +#endif + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); + } + + return ret
[PATCH V2 2/4] dts/imx6q: add cpufreq property
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..f2e3eaf 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,9 @@ compatible = arm,cortex-a9; reg = 0; next-level-cache = L2; + cpu-freqs = 99600 79200 39600 19800; + cpu-volts = 1225000 110 95 85; + trans-latency = 61036; /* two CLK32 periods */ }; cpu@1 { -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH V2 3/4] arm/imx6q: register arm_clk as cpu to clkdev
On Fri, Dec 16, 2011 at 11:35:39AM -0500, Mark Langsdorf wrote: Is there a portable/generic approach for other drivers that may want to use arm-cpufreq.c? arm_clk is not normally defined for my SoC and I don't see an easy way to pull it in. Could you tell me the details? Is your board arch/arm/mach-highbank/ Rob maintained? clk API is the most generic way for arm as far as I find out. Thanks Richard --Mark Langsdorf Calxeda, Inc. From: Richard Zhao [richard.z...@linaro.org] Sent: Friday, December 16, 2011 4:31 AM To: linux-arm-ker...@lists.infradead.org; cpuf...@vger.kernel.org; devicetree-disc...@lists.ozlabs.org Cc: li...@arm.linux.org.uk; da...@redhat.com; ker...@pengutronix.de; shawn@linaro.org; eric.m...@linaro.org; Mark Langsdorf; linaro-dev@lists.linaro.org; patc...@linaro.org; Richard Zhao Subject: [PATCH V2 3/4] arm/imx6q: register arm_clk as cpu to clkdev cpufreq needs cpu clock to change frequency. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/clock-imx6q.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index 039a7ab..72acbc2 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -1911,6 +1911,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, gpmi_io_clk, gpmi_io_clk), _REGISTER_CLOCK(NULL, usboh3_clk, usboh3_clk), _REGISTER_CLOCK(NULL, sata_clk, sata_clk), + _REGISTER_CLOCK(NULL, cpu, arm_clk), }; int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[RFC V1 4/4] arm/imx6q: select ARCH_HAS_CPUFREQ
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/Kconfig |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index c44aa97..39cf00a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -595,6 +595,7 @@ comment i.MX6 family: config SOC_IMX6Q bool i.MX6 Quad support + select ARCH_HAS_CPUFREQ select ARM_GIC select CACHE_L2X0 select CPU_V7 -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[RFC V1 1/4] cpufreq: add arm soc generic cpufreq driver
It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhao richard.z...@linaro.org --- drivers/cpufreq/Kconfig.arm |8 ++ drivers/cpufreq/Makefile |1 + drivers/cpufreq/arm-cpufreq.c | 260 + 3 files changed, 269 insertions(+), 0 deletions(-) create mode 100644 drivers/cpufreq/arm-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 72a0044..a0f7d35 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -2,6 +2,14 @@ # ARM CPU Frequency scaling drivers # +config ARM_GENERIC_CPUFREQ + bool ARM generic + help + This adds ARM generic CPUFreq driver. It assumes all + cores of the SoC share the same clock and voltage. + + If in doubt, say N. + config ARM_S3C64XX_CPUFREQ bool Samsung S3C64XX depends on CPU_S3C6410 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ce75fcb..6ccf02d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o ## # ARM SoC drivers +obj-$(CONFIG_ARM_GENERIC_CPUFREQ) += arm-cpufreq.o obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o diff --git a/drivers/cpufreq/arm-cpufreq.c b/drivers/cpufreq/arm-cpufreq.c new file mode 100644 index 000..fd9759f --- /dev/null +++ b/drivers/cpufreq/arm-cpufreq.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include linux/module.h +#include linux/cpufreq.h +#include linux/clk.h +#include linux/err.h +#include linux/slab.h +#include linux/of.h +#include asm/cpu.h +#include mach/hardware.h +#include mach/clock.h + +static u32 *cpu_freqs; +static u32 *cpu_volts; +static u32 trans_latency; +static int cpu_op_nr; + +static int cpu_freq_khz_min; +static int cpu_freq_khz_max; + +static struct clk *cpu_clk; +static struct cpufreq_frequency_table *arm_freq_table; + +static int set_cpu_freq(int freq) +{ + int ret = 0; + int org_cpu_rate; + + org_cpu_rate = clk_get_rate(cpu_clk); + if (org_cpu_rate == freq) + return ret; + + ret = clk_set_rate(cpu_clk, freq); + if (ret != 0) { + printk(KERN_DEBUG cannot set CPU clock rate\n); + return ret; + } + + return ret; +} + +static int arm_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, arm_freq_table); +} + +static unsigned int arm_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int arm_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + int freq_Hz, cpu; + int ret = 0; + unsigned int index; + + cpufreq_frequency_table_target(policy, arm_freq_table, + target_freq, relation, index); + freq_Hz = arm_freq_table[index].frequency * 1000; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = clk_round_rate(cpu_clk, freq_Hz); + freqs.new = (freqs.new ? freqs.new : freq_Hz) / 1000; + freqs.flags = 0; + + if (freqs.old == freqs.new) + return 0; + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_PRECHANGE); + } + + ret = set_cpu_freq(freq_Hz); + +#ifdef CONFIG_SMP + /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. +* So update it for all CPUs. +*/ + for_each_possible_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, + freqs.old, freqs.new); +#endif + + for_each_possible_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); + } + + return ret; +} + +static int arm_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + + printk(KERN_INFO ARM CPU frequency driver\n); + + if (policy-cpu = num_possible_cpus()) + return -EINVAL; + + policy-cur = clk_get_rate(cpu_clk) / 1000; + policy-min = policy-cpuinfo.min_freq = cpu_freq_khz_min
[RFC V1 3/4] arm/imx6q: register arm_clk as cpu to clkdev
cpufreq needs cpu clock to change frequency. Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/mach-imx/clock-imx6q.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index 039a7ab..72acbc2 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -1911,6 +1911,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, gpmi_io_clk, gpmi_io_clk), _REGISTER_CLOCK(NULL, usboh3_clk, usboh3_clk), _REGISTER_CLOCK(NULL, sata_clk, sata_clk), + _REGISTER_CLOCK(NULL, cpu, arm_clk), }; int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
[RFC V1 2/4] dts/imx6q: add cpufreq property
Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..9e9943b 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,8 @@ compatible = arm,cortex-a9; reg = 0; next-level-cache = L2; + cpu_freqs = 99600 79200 39600 19800; + cpu_volts = 1225000 110 95 85; }; cpu@1 { -- 1.7.5.4 ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [RFC V1 1/4] cpufreq: add arm soc generic cpufreq driver
TODO: - add voltage change. Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [RFC V1 2/4] dts/imx6q: add cpufreq property
On Thu, Dec 15, 2011 at 07:58:54PM +0800, Shawn Guo wrote: Hi Richard, Whenever we invent some new device tree binding support, we need to Cc devicetree-disc...@lists.ozlabs.org (Cc-ed). Thanks for your reminder. On Thu, Dec 15, 2011 at 07:16:36PM +0800, Richard Zhao wrote: Signed-off-by: Richard Zhao richard.z...@linaro.org --- arch/arm/boot/dts/imx6q.dtsi |2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3..9e9943b 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -29,6 +29,8 @@ compatible = arm,cortex-a9; reg = 0; next-level-cache = L2; + cpu_freqs = 99600 79200 39600 19800; + cpu_volts = 1225000 110 95 85; For dt property name, we use '-' rather than '_'. ok. And I'm not sure this is correct, since these data obviously does not belong to arm,cortex-a9. That's why RFC. Thanks Richard Regards, Shawn }; cpu@1 { -- 1.7.5.4 ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [RFC V1 1/4] cpufreq: add arm soc generic cpufreq driver
On Thu, Dec 15, 2011 at 12:50:07PM -0600, Mark Langsdorf wrote: Comments below. I tested this on the Calxeda Highbank SoC using QEMU. I found one definite error and a few things I would change. Thanks for your test. On 12/15/2011 05:16 AM, Richard Zhao wrote: It support single core and multi-core ARM SoCs. But it assume all cores share the same frequency and voltage. Signed-off-by: Richard Zhaorichard.z...@linaro.org --- diff --git a/drivers/cpufreq/arm-cpufreq.c b/drivers/cpufreq/arm-cpufreq.c new file mode 100644 index 000..fd9759f --- /dev/null +++ b/drivers/cpufreq/arm-cpufreq.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#includelinux/module.h +#includelinux/cpufreq.h +#includelinux/clk.h +#includelinux/err.h +#includelinux/slab.h +#includelinux/of.h +#includeasm/cpu.h +#includemach/hardware.h +#includemach/clock.h These should probably be replaced by linux/of_clk.h. See below for details. I'll remove mach/*. But are you sure clk DT binding has went to -next or -rc? If yes, I'm glad to use it. If no, I don't want to pend on it. + +static u32 *cpu_freqs; +static u32 *cpu_volts; +static u32 trans_latency; +static int cpu_op_nr; + +static int cpu_freq_khz_min; +static int cpu_freq_khz_max; + +static struct clk *cpu_clk; +static struct cpufreq_frequency_table *arm_freq_table; + +static int set_cpu_freq(int freq) +{ +int ret = 0; +int org_cpu_rate; + +org_cpu_rate = clk_get_rate(cpu_clk); +if (org_cpu_rate == freq) +return ret; + +ret = clk_set_rate(cpu_clk, freq); +if (ret != 0) { +printk(KERN_DEBUG cannot set CPU clock rate\n); +return ret; +} + +return ret; +} + +static int arm_verify_speed(struct cpufreq_policy *policy) +{ +return cpufreq_frequency_table_verify(policy, arm_freq_table); +} + +static unsigned int arm_get_speed(unsigned int cpu) +{ +return clk_get_rate(cpu_clk) / 1000; +} + +static int arm_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ +struct cpufreq_freqs freqs; +int freq_Hz, cpu; +int ret = 0; +unsigned int index; + +cpufreq_frequency_table_target(policy, arm_freq_table, +target_freq, relation,index); +freq_Hz = arm_freq_table[index].frequency * 1000; + +freqs.old = clk_get_rate(cpu_clk) / 1000; +freqs.new = clk_round_rate(cpu_clk, freq_Hz); +freqs.new = (freqs.new ? freqs.new : freq_Hz) / 1000; +freqs.flags = 0; + +if (freqs.old == freqs.new) +return 0; + +for_each_possible_cpu(cpu) { +freqs.cpu = cpu; +cpufreq_notify_transition(freqs, CPUFREQ_PRECHANGE); +} + +ret = set_cpu_freq(freq_Hz); + +#ifdef CONFIG_SMP +/* loops_per_jiffy is not updated by the cpufreq core for SMP systems. + * So update it for all CPUs. + */ +for_each_possible_cpu(cpu) +per_cpu(cpu_data, cpu).loops_per_jiffy = +cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, +freqs.old, freqs.new); +#endif + +for_each_possible_cpu(cpu) { +freqs.cpu = cpu; +cpufreq_notify_transition(freqs, CPUFREQ_POSTCHANGE); +} + +return ret; +} + +static int arm_cpufreq_init(struct cpufreq_policy *policy) +{ +int ret; + +printk(KERN_INFO ARM CPU frequency driver\n); + +if (policy-cpu= num_possible_cpus()) +return -EINVAL; + +policy-cur = clk_get_rate(cpu_clk) / 1000; +policy-min = policy-cpuinfo.min_freq = cpu_freq_khz_min; +policy-max = policy-cpuinfo.max_freq = cpu_freq_khz_max; +policy-shared_type = CPUFREQ_SHARED_TYPE_ANY; +cpumask_setall(policy-cpus); +/* Manual states, that PLL stabilizes in two CLK32 periods */ +policy-cpuinfo.transition_latency = trans_latency; + +ret = cpufreq_frequency_table_cpuinfo(policy, arm_freq_table); + +if (ret 0) { +printk(KERN_ERR %s: failed to register i.MXC CPUfreq with error code %d\n, + __func__, ret); +return ret; +} + +cpufreq_frequency_table_get_attr(arm_freq_table, policy-cpu); +return 0; +} + +static int arm_cpufreq_exit(struct cpufreq_policy *policy) +{ +cpufreq_frequency_table_put_attr(policy-cpu); + +set_cpu_freq(cpu_freq_khz_max * 1000); +return 0; +} + +static struct cpufreq_driver arm_cpufreq_driver = { +.flags = CPUFREQ_STICKY, +.verify = arm_verify_speed
Re: [RFC V1 1/4] cpufreq: add arm soc generic cpufreq driver
On Thu, Dec 15, 2011 at 08:29:11PM +, Russell King - ARM Linux wrote: On Thu, Dec 15, 2011 at 07:16:35PM +0800, Richard Zhao wrote: +#ifdef CONFIG_SMP + /* loops_per_jiffy is not updated by the cpufreq core for SMP systems. +* So update it for all CPUs. +*/ + for_each_possible_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + cpufreq_scale(per_cpu(cpu_data, cpu).loops_per_jiffy, + freqs.old, freqs.new); NAK. If you think this is a good solution, you're very wrong. If this is what's in the core cpufreq code, then it too is very broken. I've seen this exact method result in the loops_per_jiffy being totally buggered over time by the constant scaling up and down. The only way to do this _sensibly_ is to record the _initial_ loops_per_jiffy and _inital_ frequency, and scale from that. That way you get consistent results irrespective of the scalings you do over time, rather than something which continually deteriorates with every frequency change. Thanks for your comments. I'll recalculate loops_per_jiffy always based on boot up values. Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [Activity] Power Management WG Weekly Status report for week ending 2011-12-09
Hi Amit, On 12 December 2011 15:21, Amit Kucheria amit.kuche...@linaro.org wrote: On Sat, Dec 10, 2011 at 6:59 AM, Richard Zhao richard.z...@linaro.org wrote: I saw a topic 'Multi-core decision co-ordination' at https://wiki.linaro.org/WorkingGroups/PowerManagement/Doc/CPUFreq . Is it still going on? Richard, This was related to teaching cpufreq to synchronise the scaling of frequency on both cores in case of a hardware constraint. But that is already taken care of by the cpufreq core (affected_cpus, related_cpus) policy-shared_type = CPUFREQ_SHARED_TYPE_ANY; cpumask_setall(policy-cpus); Do you mean add above to cpufreq_driver.init ? When suspend/resume, cpufreq_driver.init/exit also be called multi times, though finally only cpu0 inited. Thanks Richard Regards, Amit ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v4 3/6] clk: introduce the common clock framework
Hi Mike, + * + * @recalc_rate Recalculate the rate of this clock, by quering hardware + * and/or the clock's parent. It is up to the caller to insure + * that the prepare_mutex is held across this call. Returns the + * calculated rate. Optional, but recommended - if this op is not + * set then clock rate will be initialized to 0. I'm still concerned, if it's NULL, why don't just retrun parent's rate if it has? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [Activity] Power Management WG Weekly Status report for week ending 2011-12-09
I saw a topic 'Multi-core decision co-ordination' at https://wiki.linaro.org/WorkingGroups/PowerManagement/Doc/CPUFreq . Is it still going on? Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: Bus framework
On 26 October 2011 14:39, Amit Kucheria amit.kuche...@linaro.org wrote: On 11 Oct 26, Richard Zhao wrote: Hi Amit, Is there anyone working on a SoC bus framework? The bus framework can manage the bus fabric, ddr, OCRAM clocks. When a device driver become working, it tells bus framework, cpu may access me (ip bus and related bus fabric on), I'm also a bus master, may access ddr (ddr dma access +1 ). For bus framework, if ddr dma access request is zero, ddr clk can be disabled in WFI/wait mode. The bus framework manage the SoC bus topology. If a bus switch use count is zero, it can be disabled. It may even adjust the bus freq dynamically according to bus request. Why can't this be handled in the PM runtime framework? Bus runtime drivers retain the logic for enabling/disabling the clocks and regulators required for the bus. Yes, I think it could be part of PM runtime framework. I just need the function described above. Can we do that now? Regards Richard /Amit ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
On Thu, Sep 22, 2011 at 03:26:56PM -0700, Mike Turquette wrote: +/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported + * through other headers; we don't want them used anywhere but here. */ +#ifdef CONFIG_USE_COMMON_STRUCT_CLK change to CONFIG_GENERIC_CLK? +extern int __clk_get(struct clk *clk); +extern void __clk_put(struct clk *clk); clk.c does not define it. +#endif Thanks Richard ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 4/7] clk: Add simple gated clock
On Sun, Oct 16, 2011 at 08:26:49PM +0200, Sascha Hauer wrote: On Wed, Oct 12, 2011 at 07:59:19AM -0700, Turquette, Mike wrote: On Tue, Oct 11, 2011 at 11:46 PM, Richard Zhao richard.z...@freescale.com wrote: On Thu, Sep 22, 2011 at 03:26:59PM -0700, Mike Turquette wrote: From: Jeremy Kerr jeremy.k...@canonical.com Signed-off-by: Jeremy Kerr jeremy.k...@canonical.com Signed-off-by: Mark Brown broo...@opensource.wolfsonmicro.com Signed-off-by: Jamie Iles ja...@jamieiles.com Signed-off-by: Mike Turquette mturque...@ti.com --- Changes since v1: Add copyright header Fold in Jamie's patch for set-to-disable clks Use BIT macro instead of shift drivers/clk/Kconfig | 4 ++ drivers/clk/Makefile | 1 + drivers/clk/clk-gate.c | 78 include/linux/clk.h | 13 4 files changed, 96 insertions(+), 0 deletions(-) create mode 100644 drivers/clk/clk-gate.c I feel hard to tell the tree the clk parent, at register/init time. For the simple gate clk, the only way is to set .get_parent. But normally, for clk without any divider we set .get_parent to NULL. Maybe we can put .parent to struct clk_hw? For non-mux clocks, whose parent is *always* going to be the same, you should create a duplicate .parent in the clk_hw_* structure and then have .get_parent return clk_hw_*-parent. Maybe I do not understand what you mean here, but I think there is something missing in the gate. yes, clk_gate can not set fixed parent in v2 patch. Mike means add .parent int clk_gate and set .get_parent in the ops. This is analogous to the way clk_hw_fixed returns clk_hw_fixed-rate when .recalc is called on it. + +static unsigned long clk_gate_get_rate(struct clk_hw *clk) +{ + return clk_get_rate(clk_get_parent(clk-clk)); +} clk_get_parent goes down to clk_gate_set_enable_ops.get_parent below... + + +struct clk_hw_ops clk_gate_set_enable_ops = { + .recalc_rate = clk_gate_get_rate, + .enable = clk_gate_enable_set, + .disable = clk_gate_disable_clear, +}; ...but this does not have a get_parent pointer, so clk_get_parent() for a gate always returns NULL which means that a gate never has a valid rate. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0| Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917- | ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
On Sun, Oct 16, 2011 at 07:55:21PM +0200, Sascha Hauer wrote: On Fri, Oct 14, 2011 at 06:32:33PM +0800, Richard Zhao wrote: On Fri, Oct 14, 2011 at 11:05:04AM +0100, Mark Brown wrote: On Fri, Oct 14, 2011 at 04:10:26PM +0800, Richard Zhao wrote: On Thu, Sep 22, 2011 at 03:26:56PM -0700, Mike Turquette wrote: snip essentially Mike's entire mail - *please* delete irrelevant quotes from your replies, it makes it very much easier to find the new text in your mail and is much more friendly to people reading mail on mobile devices. I snip not enough? sorry for that. I'll be carefull. +static int __clk_enable(struct clk *clk) +{ Could you expose __clk_enable/__clk_disable? I find it hard to implement clk group. clk group means, when a major clk enable/disable, it want a set of other clks enable/disable accordingly. Shouldn't this be something the core is implementing? I'd strongly expect that the clock drivers are relatively dumb and delegate all the decision making to the core API. Otherwise it's going to be hard for the core to implement any logic that involves working with more than one clock like rate change notification, or guarantee that driver requests made through the API are satisfied, as the state of the clocks will be changing underneath it. From my point of view, the first step of generic clk can be, easy to adopt features of clocks in current mainline git. Back to the clk group, I have a patch based on Sascha's work. http://git.linaro.org/gitweb?p=people/riczhao/linux-2.6.git;a=shortlog;h=refs/heads/imx-clk I thought further about this and a clock group is not something we want to have at all. Clocks are supposed to be arranged in a tree and grouping clocks together violates this which leads to problems. This grouping should be done at driver level, so when a driver needs more than one clock it should request them all, maybe with a clk_get_all helper function. clock group is not limited to help driver get clock. It refects clock dependency. For example, devices that possible access to on-chip RAM, depend on OCRAM clock. On imx53, VPU depends on OCRAM clock, even when VPU does not use OCRAM. Thanks Richard Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0| Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917- | ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
On Mon, Oct 17, 2011 at 10:20:28AM +0100, Mark Brown wrote: On Mon, Oct 17, 2011 at 04:48:52PM +0800, Richard Zhao wrote: For example, devices that possible access to on-chip RAM, depend on OCRAM clock. On imx53, VPU depends on OCRAM clock, even when VPU does not use OCRAM. So if the VPU depends on OCRAM the VPU should be enabling the OCRAM clock. The function of a given clock isn't terribly relevant, and certainly grouping clocks together doesn't seem to be the obvious solution from what you've said VPU don't know OCRAM clk, it's SoC specific. I know it's clock function replationship. But it's the only better place to refect the dependency in clock tree. Another dependency example, from SoC bus topology, some bus clk always depends on bus switch/hub. - if the driver doesn't know about the clock it seems like the core ought to be enabling it transparently rather than gluing it together with some other random clock. If you mean clk core here, then we need things like below: struct clk_hw { struct clk *clk; struct dependency { struct clk_hw *clks; int count; }; }; Though Mike does not like to add things in clk_hw, but it's the only place to put common things of clk drivers. Thanks Richard Either way the point here is that individual drivers shouldn't be hand coding this stuff, it should be being handled by core code. ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
On Sun, Oct 16, 2011 at 02:17:29PM -0700, Turquette, Mike wrote: On Fri, Oct 14, 2011 at 7:24 PM, Richard Zhao richard.z...@linaro.org wrote: On Fri, Oct 14, 2011 at 11:14:19AM -0700, Turquette, Mike wrote: On Thu, Sep 22, 2011 at 3:26 PM, Mike Turquette mturque...@ti.com wrote: unsigned long omap_recalc_rate(struct clk_hw *hw) { struct clk *parent; struct clk_hw_omap *oclk; parent = hw-clk-parent; clk drivers can not see struct clk details. I use clk_get_parent. clk_get_parent should query the hardware to see what the parent is. This can have undesireable overhead. It is quite acceptable to reference a clock's parent through clk-parent, just as it is acceptable to get a clock rate through clk-rate. IMHO, we only need to get parent from hw at register/init time. clk_get_parent can get it from cache, like current code. An analogous situation is a clk_get_rate call which uses a clk's .recalc. There is undesirable overhead involved in .recalc for clocks whose rates won't change behind our backs, so best to just treat the data in struct clk as cache and reference it directly. oclk = to_clk_omap(hw); ... } ... unsigned long omap_recalc_rate(struct clk *clk) { struct clk *parent; struct clk_hw_omap *oclk; parent = clk-parent; oclk = to_clk_omap(clk-hw); ... } In my understanding, struct clk stores things specific to clk core, struct clk_hw stores common things needed by clk drivers. For static clk driver there' some problems: - For clocks without mux, I need duplicate a .parent and set .get_parent. Even when we adopt DT and dynamicly create clk, it's still a problem. Moving .parent to clk_hw can fix it. For clocks with a fixed parent we should just pass it in at register-time. We should definitely not move .parent out of struct clk, since struct clk should be the platform agnostic bit that lets us do tree walks, build topology, etc etc. If you really want a .parent outside of struct clk then duplicate it in your struct clk_hw_imx I don't have clk_hw_imx. I just use generic clks like clk_hw_gate, clk_hw_divider, clk_hw_mux, and some specific clks. and teach your .ops about it (analogous to struct clk_hw_fixed-rate). I have to define things like below: stuct pair { struct clk_hw *clk = clk_hw_gate.hw; struct clk_hw_ops *ops; }; and use for (.. ) to register the clk array. - When I define a clk array, I don't need to find another place to store .ops. It's not problem for dynamic creating clock. Something like the following? static struct clk aess_fclk; static const clk_hw_ops aess_fclk_ops = { .recalc = omap2_clksel_recalc, .round_rate = omap2_clksel_round_rate, .set_rate = omap2_clksel_set_rate, }; static struct clk_hw_omap aess_fclk_hw = { .hw = { .clk = aess_fclk, }, .clksel = aess_fclk_div, .clksel_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_AESS_FCLK_MASK, }; static struct clk aess_fclk = { .name = aess_fclk, .ops = aess_fclk_ops, .hw = aess_fclk_hw.hw, .parent = abe_clk, }; If we don't protect struct clk members, how about the below: struct clk_hw_omap aess_fclk = { .clk = { .name = aess_fclk, .ops = aess_fclk_ops, .parent = abe_clk, }; .clksel = aess_fclk_div, .clksel_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL, .clksel_mask = OMAP4430_CLKSEL_AESS_FCLK_MASK, }; - As I mentioned in another mail, clk group need no lock version prepare/unprepare and enable/disable functions Clock groups are out of scope for this first series. We should discuss more what the needs are for your clock groups. If it boils down to just enabling all of the clocks for a given device then you might want to abstract that away with pm_runtime_* calls, and maybe a supplementary layer like OMAP's hwmod. But I might be way off base, I really don't understand your use case for clock groups. clk group is clk function dependency. I talked about it in another email in this thread. That's ok to leave it to other framework. Another way is, add a {struct clk_hw *clks; int count} in clk_hw, let clk core handle it. I prefer the second way, but I'm not sure whether it's common enough. It's still a problem for dynamic creating clock. struct clk_hw is just a pointer for navigating from struct clk - struct your_custom_clk and vice versa. Again can you elaborate on your needs for managing multiple clocks with a single struct clk_hw? Thanks, Mike Thanks Richard It is a small nitpick, but it affects the API for everybody so best to get it right now before folks start migrating over to it. Thanks, Mike int
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
Hi Mike, On Thu, Sep 22, 2011 at 03:26:56PM -0700, Mike Turquette wrote: From: Jeremy Kerr jeremy.k...@canonical.com We currently have ~21 definitions of struct clk in the ARM architecture, each defined on a per-platform basis. This makes it difficult to define platform- (or architecture-) independent clock sources without making assumptions about struct clk, and impossible to compile two platforms with different struct clks into a single image. This change is an effort to unify struct clk where possible, by defining a common struct clk, and a set of clock operations. Different clock implementations can set their own operations, and have a standard interface for generic code. The callback interface is exposed to the kernel proper, while the clock implementations only need to be seen by the platform internals. The interface is split into two halves: * struct clk, which is the generic-device-driver interface. This provides a set of functions which drivers may use to request enable/disable, query or manipulate in a hardware-independent manner. * struct clk_hw and struct clk_hw_ops, which is the hardware-specific interface. Clock drivers implement the ops, which allow the core clock code to implement the generic 'struct clk' API. This allows us to share clock code among platforms, and makes it possible to dynamically create clock devices in platform-independent code. Platforms can enable the generic struct clock through CONFIG_GENERIC_CLK. In this case, the clock infrastructure consists of a common, opaque struct clk, and a set of clock operations (defined per type of clock): struct clk_hw_ops { int (*prepare)(struct clk_hw *); void(*unprepare)(struct clk_hw *); int (*enable)(struct clk_hw *); void(*disable)(struct clk_hw *); unsigned long (*recalc_rate)(struct clk_hw *); int (*set_rate)(struct clk_hw *, unsigned long, unsigned long *); long(*round_rate)(struct clk_hw *, unsigned long); int (*set_parent)(struct clk_hw *, struct clk *); struct clk *(*get_parent)(struct clk_hw *); }; Platform clock code can register a clock through clk_register, passing a set of operations, and a pointer to hardware-specific data: struct clk_hw_foo { struct clk_hw clk; void __iomem *enable_reg; }; #define to_clk_foo(c) offsetof(c, clk_hw_foo, clk) static int clk_foo_enable(struct clk_hw *clk) { struct clk_foo *foo = to_clk_foo(clk); raw_writeb(foo-enable_reg, 1); return 0; } struct clk_hw_ops clk_foo_ops = { .enable = clk_foo_enable, }; And in the platform initialisation code: struct clk_foo my_clk_foo; void init_clocks(void) { my_clk_foo.enable_reg = ioremap(...); clk_register(clk_foo_ops, my_clk_foo, NULL); } Changes from Thomas Gleixner t...@linutronix.de. The common clock definitions are based on a development patch from Ben Herrenschmidt b...@kernel.crashing.org. TODO: * We don't keep any internal reference to the clock topology at present. Signed-off-by: Jeremy Kerr jeremy.k...@canonical.com Signed-off-by: Thomas Gleixner t...@linutronix.de Signed-off-by: Mark Brown broo...@opensource.wolfsonmicro.com Signed-off-by: Mike Turquette mturque...@ti.com --- Changes since v1: Create a dummy clk_unregister and prototype/document it and clk_register Constify struct clk_hw_ops Remove spinlock.h header, include kernel.h Use EOPNOTSUPP instead of ENOTSUPP Add might_sleep to clk_prepare/clk_unprepare stubs Properly init children hlist and child_node Whitespace and typo fixes drivers/clk/Kconfig |3 + drivers/clk/Makefile |1 + drivers/clk/clk.c| 232 ++ drivers/clk/clkdev.c |7 ++ include/linux/clk.h | 140 +++--- 5 files changed, 371 insertions(+), 12 deletions(-) create mode 100644 drivers/clk/clk.c [...] +static void __clk_disable(struct clk *clk) +{ + if (!clk) + return; + + if (WARN_ON(clk-enable_count == 0)) + return; + + if (--clk-enable_count 0) + return; + + if (clk-ops-disable) + clk-ops-disable(clk-hw); + __clk_disable(clk-parent); +} + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(enable_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(enable_lock, flags); +} +EXPORT_SYMBOL_GPL(clk_disable); + +static int __clk_enable(struct clk *clk) +{ + int ret; + + if (!clk) + return 0; + + if (WARN_ON(clk-prepare_count == 0)) + return -ESHUTDOWN; + + + if (clk-enable_count == 0) { + ret = __clk_enable(clk-parent); +
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
On Fri, Oct 14, 2011 at 11:05:04AM +0100, Mark Brown wrote: On Fri, Oct 14, 2011 at 04:10:26PM +0800, Richard Zhao wrote: On Thu, Sep 22, 2011 at 03:26:56PM -0700, Mike Turquette wrote: snip essentially Mike's entire mail - *please* delete irrelevant quotes from your replies, it makes it very much easier to find the new text in your mail and is much more friendly to people reading mail on mobile devices. I snip not enough? sorry for that. I'll be carefull. +static int __clk_enable(struct clk *clk) +{ Could you expose __clk_enable/__clk_disable? I find it hard to implement clk group. clk group means, when a major clk enable/disable, it want a set of other clks enable/disable accordingly. Shouldn't this be something the core is implementing? I'd strongly expect that the clock drivers are relatively dumb and delegate all the decision making to the core API. Otherwise it's going to be hard for the core to implement any logic that involves working with more than one clock like rate change notification, or guarantee that driver requests made through the API are satisfied, as the state of the clocks will be changing underneath it. From my point of view, the first step of generic clk can be, easy to adopt features of clocks in current mainline git. Back to the clk group, I have a patch based on Sascha's work. http://git.linaro.org/gitweb?p=people/riczhao/linux-2.6.git;a=shortlog;h=refs/heads/imx-clk Thanks Richard ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
On Fri, Oct 14, 2011 at 11:14:19AM -0700, Turquette, Mike wrote: On Thu, Sep 22, 2011 at 3:26 PM, Mike Turquette mturque...@ti.com wrote: From: Jeremy Kerr jeremy.k...@canonical.com struct clk_hw_ops { int (*prepare)(struct clk_hw *); void (*unprepare)(struct clk_hw *); int (*enable)(struct clk_hw *); void (*disable)(struct clk_hw *); unsigned long (*recalc_rate)(struct clk_hw *); In implementing recalc for divider clocks, I started to wonder, why not just pass struct clk *clk into the clk_hw_ops func ptrs?. recalc is an obvious example whereby we need access to parent-rate. The code usually ends up looking something like: unsigned long omap_recalc_rate(struct clk_hw *hw) { struct clk *parent; struct clk_hw_omap *oclk; parent = hw-clk-parent; clk drivers can not see struct clk details. I use clk_get_parent. oclk = to_clk_omap(hw); ... } That's a bit of a song and dance to have to do in almost every op, and often these ops will need access to stuff like clk-rate also. Is there any opposition to just passing in struct clk? e.g: unsigned long omap_recalc_rate(struct clk *clk) { struct clk *parent; struct clk_hw_omap *oclk; parent = clk-parent; oclk = to_clk_omap(clk-hw); ... } In my understanding, struct clk stores things specific to clk core, struct clk_hw stores common things needed by clk drivers. For static clk driver there' some problems: - For clocks without mux, I need duplicate a .parent and set .get_parent. Even when we adopt DT and dynamicly create clk, it's still a problem. Moving .parent to clk_hw can fix it. - When I define a clk array, I don't need to find another place to store .ops. It's not problem for dynamic creating clock. - As I mentioned in another mail, clk group need no lock version prepare/unprepare and enable/disable functions Another way is, add a {struct clk_hw *clks; int count} in clk_hw, let clk core handle it. I prefer the second way, but I'm not sure whether it's common enough. It's still a problem for dynamic creating clock. Thanks Richard It is a small nitpick, but it affects the API for everybody so best to get it right now before folks start migrating over to it. Thanks, Mike int (*set_rate)(struct clk_hw *, unsigned long, unsigned long *); long (*round_rate)(struct clk_hw *, unsigned long); int (*set_parent)(struct clk_hw *, struct clk *); struct clk * (*get_parent)(struct clk_hw *); }; ___ linux-arm-kernel mailing list linux-arm-ker...@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Re: [PATCH v2 1/7] clk: Add a generic clock infrastructure
- When I define a clk array, I don't need to find another place to store .ops. ^ remove don't. sorry for that. ___ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev