Message ID | 1354046672-7392-7-git-send-email-mark.langsdorf@calxeda.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
On Tue, Nov 27, 2012 at 02:04:32PM -0600, Mark Langsdorf wrote: > Highbank processors depend on the external ECME to perform voltage > management based on a requested frequency. Communication between the > A9 cores and the ECME happens over the pl320 IPC channel. ... > +static int hb_voltage_change(unsigned int freq) > +{ > + int i; > + u32 msg[7]; > + > + msg[0] = HB_CPUFREQ_CHANGE_NOTE; > + msg[1] = freq / 1000; > + for (i = 2; i < 7; i++) > + msg[i] = 0; > + > + return pl320_ipc_transmit(msg); Is it possible to have this handled inside clk_set_rate() call of cpu clock? Shawn > +} -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/27/2012 08:32 PM, Shawn Guo wrote: > On Tue, Nov 27, 2012 at 02:04:32PM -0600, Mark Langsdorf wrote: >> Highbank processors depend on the external ECME to perform voltage >> management based on a requested frequency. Communication between the >> A9 cores and the ECME happens over the pl320 IPC channel. > > ... > >> +static int hb_voltage_change(unsigned int freq) >> +{ >> + int i; >> + u32 msg[7]; >> + >> + msg[0] = HB_CPUFREQ_CHANGE_NOTE; >> + msg[1] = freq / 1000; >> + for (i = 2; i < 7; i++) >> + msg[i] = 0; >> + >> + return pl320_ipc_transmit(msg); > > Is it possible to have this handled inside clk_set_rate() call of cpu > clock? Standard practice is to have cpufreq_set_target() handle voltage transitions and leave clk_set_rate() handle the frequency changes. I'd have to move most of the logic of hb_set_target() into clk_highbank.c:clk_pll_set_rate() and then add extra logic for when cpufreq is not enabled/loaded. I don't think the clk maintainers would take that patch, either. So no. --Mark Langsdorf Calxeda, Inc. -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: > Standard practice is to have cpufreq_set_target() handle voltage > transitions and leave clk_set_rate() handle the frequency changes. The standard practice is to have cpufreq_set_target() handle both voltage and frequency transitions, while voltage is handled by regulator and frequency by clk API. > I'd > have to move most of the logic of hb_set_target() into > clk_highbank.c:clk_pll_set_rate() and then add extra logic for when > cpufreq is not enabled/loaded. You only need to move hb_voltage_change() into cpu clock's .set_rate() hook with no need of checking if cpufreq is enabled or not. > I don't think the clk maintainers would > take that patch, either. This is all handled platform clock specific .set_rate() hook. I doubt it will concern clk maintainers at all, especially when doing so we will avoid another cpufreq driver by just using cpufreq-cpu0 driver. Shawn -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/28/2012 09:17 AM, Shawn Guo wrote: > On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote: >> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: >>> I'd >>> have to move most of the logic of hb_set_target() into >>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when >>> cpufreq is not enabled/loaded. >> >> You only need to move hb_voltage_change() into cpu clock's .set_rate() >> hook with no need of checking if cpufreq is enabled or not. >> > Need to also check whether frequency or voltage should be changed first > in .set_rate() though. Yes, that's entirely what I meant when I said that I would need to move most of the hb_set_target() logic into .set_rate(). I would also need to account for retries if the voltage set operation fails, which it sometimes does. The ECME handles changing the voltage but doesn't look like a voltage regulator. Amongst other things, by design it doesn't export meaningful voltage information to Linux. I tried to get cpufreq-clk0 to work with the Highbank design and it ended up being much easier and more sane to create a separate driver. --Mark Langsdorf Calxeda, Inc. -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote: > On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: > > I'd > > have to move most of the logic of hb_set_target() into > > clk_highbank.c:clk_pll_set_rate() and then add extra logic for when > > cpufreq is not enabled/loaded. > > You only need to move hb_voltage_change() into cpu clock's .set_rate() > hook with no need of checking if cpufreq is enabled or not. > Need to also check whether frequency or voltage should be changed first in .set_rate() though. Shawn -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Shawn Guo (2012-11-28 07:17:44) > On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote: > > On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: > > > I'd > > > have to move most of the logic of hb_set_target() into > > > clk_highbank.c:clk_pll_set_rate() and then add extra logic for when > > > cpufreq is not enabled/loaded. > > > > You only need to move hb_voltage_change() into cpu clock's .set_rate() > > hook with no need of checking if cpufreq is enabled or not. > > > Need to also check whether frequency or voltage should be changed first > in .set_rate() though. > > Shawn > The notifiers in the clk framework might be a better place for this than just simply hacking the logic into the .set_rate callback. I haven't looked at the definition of hb_voltage_change but does the call graph make any clk api calls? Are you talking over i2c to a regulator? If so then you'll probably hit the same reentrancy problem I hit when trying to make a general solution. Regards, Mike > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/28/2012 10:01 AM, Mike Turquette wrote: > Quoting Shawn Guo (2012-11-28 07:17:44) >> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote: >>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: >>>> I'd >>>> have to move most of the logic of hb_set_target() into >>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when >>>> cpufreq is not enabled/loaded. >>> >>> You only need to move hb_voltage_change() into cpu clock's .set_rate() >>> hook with no need of checking if cpufreq is enabled or not. >>> >> Need to also check whether frequency or voltage should be changed first >> in .set_rate() though. >> >> Shawn >> > > The notifiers in the clk framework might be a better place for this than > just simply hacking the logic into the .set_rate callback. Unless the clk notifiers are different than the cpufreq notifiers, they don't handle returning error conditions very well. And given that the voltage change operation can fail (though it almost always succeeds on a retry) I need to be able to handle and detect that error condition. > I haven't looked at the definition of hb_voltage_change but does the > call graph make any clk api calls? Are you talking over i2c to a > regulator? If so then you'll probably hit the same reentrancy problem I > hit when trying to make a general solution. I'm talking over a pl320 Interprocessor Communication Mailbox to a separate core running it's own RTOS. The RTOS might speak i2c to a regulator but it's a black box to me. hb_voltage_change() doesn't make any clk api calls. It changes the voltages, and then hb_set_target() makes clk api calls to change the frequency. --Mark Langsdorf Calxeda, Inc. -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Mark Langsdorf (2012-11-28 08:18:35) > On 11/28/2012 10:01 AM, Mike Turquette wrote: > > Quoting Shawn Guo (2012-11-28 07:17:44) > >> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote: > >>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: > >>>> I'd > >>>> have to move most of the logic of hb_set_target() into > >>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when > >>>> cpufreq is not enabled/loaded. > >>> > >>> You only need to move hb_voltage_change() into cpu clock's .set_rate() > >>> hook with no need of checking if cpufreq is enabled or not. > >>> > >> Need to also check whether frequency or voltage should be changed first > >> in .set_rate() though. > >> > >> Shawn > >> > > > > The notifiers in the clk framework might be a better place for this than > > just simply hacking the logic into the .set_rate callback. > > Unless the clk notifiers are different than the cpufreq notifiers, they > don't handle returning error conditions very well. And given that the > voltage change operation can fail (though it almost always succeeds on a > retry) I need to be able to handle and detect that error condition. > The notifier handler can handle the case where the transition fails (and needs to be retried). Also you should check out the clk notifiers. I think they handle failure decently. If a notifer returns an error code then everything unrolls and the clk_set_rate operation aborts. Regards, Mike > > I haven't looked at the definition of hb_voltage_change but does the > > call graph make any clk api calls? Are you talking over i2c to a > > regulator? If so then you'll probably hit the same reentrancy problem I > > hit when trying to make a general solution. > > I'm talking over a pl320 Interprocessor Communication Mailbox to a > separate core running it's own RTOS. The RTOS might speak i2c to a > regulator but it's a black box to me. > > hb_voltage_change() doesn't make any clk api calls. It changes the > voltages, and then hb_set_target() makes clk api calls to change the > frequency. > > --Mark Langsdorf > Calxeda, Inc. -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 11/28/2012 03:05 PM, Mike Turquette wrote: > Quoting Mark Langsdorf (2012-11-28 08:18:35) >> On 11/28/2012 10:01 AM, Mike Turquette wrote: >>> Quoting Shawn Guo (2012-11-28 07:17:44) >>>> On Wed, Nov 28, 2012 at 10:58:02PM +0800, Shawn Guo wrote: >>>>> On Wed, Nov 28, 2012 at 07:16:12AM -0600, Mark Langsdorf wrote: >>>>>> I'd >>>>>> have to move most of the logic of hb_set_target() into >>>>>> clk_highbank.c:clk_pll_set_rate() and then add extra logic for when >>>>>> cpufreq is not enabled/loaded. >>>>> >>>>> You only need to move hb_voltage_change() into cpu clock's .set_rate() >>>>> hook with no need of checking if cpufreq is enabled or not. >>>>> >>>> Need to also check whether frequency or voltage should be changed first >>>> in .set_rate() though. >>>> >>>> Shawn >>>> >>> >>> The notifiers in the clk framework might be a better place for this than >>> just simply hacking the logic into the .set_rate callback. >> >> Unless the clk notifiers are different than the cpufreq notifiers, they >> don't handle returning error conditions very well. And given that the >> voltage change operation can fail (though it almost always succeeds on a >> retry) I need to be able to handle and detect that error condition. > > The notifier handler can handle the case where the transition fails (and > needs to be retried). > > Also you should check out the clk notifiers. I think they handle > failure decently. If a notifer returns an error code then everything > unrolls and the clk_set_rate operation aborts. Thanks for the pointer. The clk notifier calls seem to be working with cpufreq-cpu0. I did enough surgery on the code that I want to run a lot of stress tests before I resubmit. I'll try to have something for Tuesday. --Mark Langsdorf Calxeda, Inc. -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> The notifiers in the clk framework might be a better place for this than > just simply hacking the logic into the .set_rate callback. Ah, right. How did I forget about that nice piece? > I haven't looked at the definition of hb_voltage_change but does the > call graph make any clk api calls? Are you talking over i2c to a > regulator? If so then you'll probably hit the same reentrancy problem I > hit when trying to make a general solution. So, how is your "reentrancy in the common clk framework" series[1] going on? Haven't seen any update since August. Shawn [1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/182198 -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Shawn Guo (2012-11-28 17:51:36) > > The notifiers in the clk framework might be a better place for this than > > just simply hacking the logic into the .set_rate callback. > > Ah, right. How did I forget about that nice piece? > > > I haven't looked at the definition of hb_voltage_change but does the > > call graph make any clk api calls? Are you talking over i2c to a > > regulator? If so then you'll probably hit the same reentrancy problem I > > hit when trying to make a general solution. > > So, how is your "reentrancy in the common clk framework" series[1] > going on? Haven't seen any update since August. > I've begun to look at a dvfs api that builds on top of the clock framework, as opposed to using clk_set_rate as the dvfs api itself. This eliminates the need for reentrancy, at least for the dvfs case. I'll post more when I have it. Honestly the reentrancy stuff was just too ugly. I might try again some day but for now I'm thinking a less radical approach deserves consideration. Thanks, Mike > Shawn > > [1] http://thread.gmane.org/gmane.linux.ports.arm.kernel/182198 -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt new file mode 100644 index 0000000..1d5a836 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt @@ -0,0 +1,53 @@ +Highbank cpufreq driver + +This is cpufreq driver for Calxeda ECX-1000 (highbank) processor. It is based +on the generic cpu0 driver and uses a similar format for bindings. Since +the EnergyCore Management Engine maintains the voltage based on the +frequency, the voltage component of the operating points can be set to any +arbitrary values. + +Both required properties listed below must be defined under node /cpus/cpu@0. + +Required properties: +- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt + for details +- transition-latency: Specify the possible maximum transition latency for clock, + in unit of nanoseconds. + +Examples: + +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz ignored */ + 790000 1000000 + 396000 1000000 + 198000 1000000 + >; + transition-latency = <200000>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + reg = <2>; + next-level-cache = <&L2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + reg = <3>; + next-level-cache = <&L2>; + }; +}; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 0c6fc34..8624c94 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -36,6 +36,16 @@ next-level-cache = <&L2>; clocks = <&a9pll>; clock-names = "cpu"; + operating-points = < + /* kHz ignored */ + 1300000 1000000 + 1200000 1000000 + 1100000 1000000 + 800000 1000000 + 400000 1000000 + 200000 1000000 + >; + transition-latency = <100000>; }; cpu@1 { diff --git a/arch/arm/mach-highbank/Kconfig b/arch/arm/mach-highbank/Kconfig index 2896881..b7862da 100644 --- a/arch/arm/mach-highbank/Kconfig +++ b/arch/arm/mach-highbank/Kconfig @@ -1,5 +1,7 @@ config ARCH_HIGHBANK bool "Calxeda ECX-1000 (Highbank)" if ARCH_MULTI_V7 + select ARCH_HAS_CPUFREQ + select ARCH_HAS_OPP select ARCH_WANT_OPTIONAL_GPIOLIB select ARM_AMBA select ARM_GIC diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 5961e64..7a8bcdc 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -76,3 +76,16 @@ config ARM_EXYNOS5250_CPUFREQ help This adds the CPUFreq driver for Samsung EXYNOS5250 SoC. + +config ARM_HIGHBANK_CPUFREQ + tristate "Calxeda Highbank-based" + depends on ARCH_HIGHBANK + select CPU_FREQ_TABLE + select PM_OPP + default m + help + This adds the CPUFreq driver for Calxeda Highbank SoC + based boards. + + If in doubt, say N. + diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 1bc90e1..9e8f12a 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o +obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o ################################################################################## # PowerPC platform drivers diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c new file mode 100644 index 0000000..878d3ff --- /dev/null +++ b/drivers/cpufreq/highbank-cpufreq.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2012 Calxeda, Inc. + * + * derived from cpufreq-cpu0 by Freescale Semiconductor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/clk.h> +#include <linux/cpu.h> +#include <linux/cpufreq.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/opp.h> +#include <linux/slab.h> +#include <linux/mailbox.h> + +#define HB_CPUFREQ_CHANGE_NOTE 0x80000001 + +static unsigned int transition_latency; + +static struct device *cpu_dev; +static struct clk *cpu_clk; +static struct cpufreq_frequency_table *freq_table; + +static int hb_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static unsigned int hb_get_speed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +static int hb_voltage_change(unsigned int freq) +{ + int i; + u32 msg[7]; + + msg[0] = HB_CPUFREQ_CHANGE_NOTE; + msg[1] = freq / 1000; + for (i = 2; i < 7; i++) + msg[i] = 0; + + return pl320_ipc_transmit(msg); +} + +static int hb_set_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long freq_Hz; + unsigned int index, cpu; + int ret; + + ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, + relation, &index); + if (ret) { + pr_err("failed to match target freqency %d: %d\n", + target_freq, ret); + return ret; + } + + freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); + if (freq_Hz < 0) + freq_Hz = freq_table[index].frequency * 1000; + freqs.new = freq_Hz / 1000; + freqs.old = clk_get_rate(cpu_clk) / 1000; + + if (freqs.old == freqs.new) + return 0; + + for_each_online_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + pr_debug("%u MHz --> %u MHz\n", freqs.old / 1000, freqs.new / 1000); + + /* scaling up? scale voltage before frequency */ + if (freqs.new > freqs.old) { + ret = hb_voltage_change(freqs.new); + if (ret) { + freqs.new = freqs.old; + return -EAGAIN; + } + } + + ret = clk_set_rate(cpu_clk, freqs.new * 1000); + if (ret) { + pr_err("failed to set clock rate: %d\n", ret); + hb_voltage_change(freqs.old); + return ret; + } + + /* scaling down? scale voltage after frequency */ + if (freqs.new < freqs.old) { + ret = hb_voltage_change(freqs.new); + if (ret) { + if (clk_set_rate(cpu_clk, freqs.old * 1000)) + pr_err("also failed to reset freq\n"); + freqs.new = freqs.old; + return -EAGAIN; + } + } + + for_each_online_cpu(cpu) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + return 0; +} + +static int hb_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + + if (policy->cpu != 0) + return -EINVAL; + + ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (ret) { + pr_err("invalid frequency table: %d\n", ret); + return ret; + } + + policy->cpuinfo.transition_latency = transition_latency; + policy->cur = clk_get_rate(cpu_clk) / 1000; + + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_setall(policy->cpus); + + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + + return 0; +} + +static int hb_cpufreq_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + + return 0; +} + +static struct freq_attr *hb_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver hb_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .verify = hb_verify_speed, + .target = hb_set_target, + .get = hb_get_speed, + .init = hb_cpufreq_init, + .exit = hb_cpufreq_exit, + .name = "highbank-cpufreq", + .attr = hb_cpufreq_attr, +}; + +static int __devinit hb_cpufreq_driver_init(void) +{ + struct device_node *np; + int ret; + + np = of_find_node_by_path("/cpus/cpu@0"); + if (!np) { + pr_err("failed to find highbank cpufreq node\n"); + return -ENOENT; + } + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) { + pr_err("failed to get highbank cpufreq device\n"); + ret = -ENODEV; + goto out_put_node; + } + + cpu_dev->of_node = np; + + cpu_clk = clk_get(cpu_dev, NULL); + if (IS_ERR(cpu_clk)) { + ret = PTR_ERR(cpu_clk); + pr_err("failed to get cpu0 clock: %d\n", ret); + goto out_put_node; + } + + ret = of_init_opp_table(cpu_dev); + if (ret) { + pr_err("failed to init OPP table: %d\n", ret); + goto out_put_node; + } + + ret = opp_init_cpufreq_table(cpu_dev, &freq_table); + if (ret) { + pr_err("failed to init cpufreq table: %d\n", ret); + goto out_put_node; + } + + if (of_property_read_u32(np, "transition-latency", &transition_latency)) + transition_latency = CPUFREQ_ETERNAL; + + ret = cpufreq_register_driver(&hb_cpufreq_driver); + if (ret) { + pr_err("failed register driver: %d\n", ret); + goto out_free_table; + } + + of_node_put(np); + return 0; + +out_free_table: + opp_free_cpufreq_table(cpu_dev, &freq_table); +out_put_node: + of_node_put(np); + return ret; +} +late_initcall(hb_cpufreq_driver_init); + +MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>"); +MODULE_DESCRIPTION("Calxeda Highbank cpufreq driver"); +MODULE_LICENSE("GPL");
Highbank processors depend on the external ECME to perform voltage management based on a requested frequency. Communication between the A9 cores and the ECME happens over the pl320 IPC channel. Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com> Cc: devicetree-discuss@lists.ozlabs.org --- Changes from v5 Changed ipc_transmit() to pl320_ipc_transmit(). Changes from v4 Removed erroneous changes to arch/arm/Kconfig. Removed unnecessary changes to drivers/cpufreq/Kconfig.arm Alphabetized additions to arch/arm/mach-highbank/Kconfig Changed ipc call and header to match new ipc location in drivers/mailbox. Changes from v3 None. Changes from v2 Changed transition latency binding in code to match documentation. Changes from v1 Added highbank specific Kconfig changes. .../bindings/cpufreq/highbank-cpufreq.txt | 53 +++++ arch/arm/boot/dts/highbank.dts | 10 + arch/arm/mach-highbank/Kconfig | 2 + drivers/cpufreq/Kconfig.arm | 13 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/highbank-cpufreq.c | 229 +++++++++++++++++++++ 6 files changed, 308 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/highbank-cpufreq.txt create mode 100644 drivers/cpufreq/highbank-cpufreq.c