From 82dd9cc400864655c733ee33999a8c24a5fa4423 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 13 May 2010 09:01:08 +0000 Subject: [PATCH] add cpufreq support --- .config | 16 +++++ arch/arm/Kconfig | 1 + arch/arm/mach-rk2818/clock.c | 9 +++ arch/arm/mach-rk2818/cpufreq.c | 107 +++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100755 arch/arm/mach-rk2818/cpufreq.c diff --git a/.config b/.config index 4410605dce39..22afaf7228e7 100644 --- a/.config +++ b/.config @@ -17,6 +17,7 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_HARDIRQS_SW_RESEND=y CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y @@ -277,6 +278,21 @@ CONFIG_CMDLINE="mem=128M console=ttyS1,115200n8" # # CPU Power Management # +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_STAT_DETAILS=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set # CONFIG_CPU_IDLE is not set # diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 270b2c28b2c7..69c7e1becf06 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -708,6 +708,7 @@ config ARCH_RK2818 select HAVE_TCM select HAVE_CLK select COMMON_CLKDEV + select ARCH_HAS_CPUFREQ select GENERIC_TIME select GENERIC_CLOCKEVENTS select ARCH_REQUIRE_GPIOLIB diff --git a/arch/arm/mach-rk2818/clock.c b/arch/arm/mach-rk2818/clock.c index 7435aa9512a7..4fa5b845a153 100644 --- a/arch/arm/mach-rk2818/clock.c +++ b/arch/arm/mach-rk2818/clock.c @@ -1249,6 +1249,15 @@ static void clk_enable_init_clocks(void) } } +#ifdef CONFIG_CPU_FREQ +#include + +void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) +{ +} +EXPORT_SYMBOL(clk_init_cpufreq_table); +#endif /* CONFIG_CPU_FREQ */ + static unsigned int __initdata armclk; /* diff --git a/arch/arm/mach-rk2818/cpufreq.c b/arch/arm/mach-rk2818/cpufreq.c new file mode 100755 index 000000000000..36b85fa26951 --- /dev/null +++ b/arch/arm/mach-rk2818/cpufreq.c @@ -0,0 +1,107 @@ +/* arch/arm/mach-rk2818/cpufreq.c + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +static struct cpufreq_frequency_table *freq_table; +static struct clk *arm_clk; + +static int rk2818_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, freq_table); +} + +static int rk2818_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) +{ + int index; + struct cpufreq_freqs freqs; + + if (policy->cpu != 0) + return -EINVAL; + if (cpufreq_frequency_table_target(policy, freq_table, target_freq, relation, &index)) { + pr_err("cpufreq: invalid target_freq: %d\n", target_freq); + return -EINVAL; + } + + if (policy->cur == freq_table[index].frequency) + return 0; + +#ifdef CONFIG_CPU_FREQ_DEBUG + printk("%s %d r %d (%d-%d) selected %d\n", __func__, target_freq, relation, policy->min, policy->max, freq_table[index].frequency); +#endif + freqs.old = policy->cur; + freqs.new = freq_table[index].frequency; + freqs.cpu = 0; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + clk_set_rate(arm_clk, freqs.new * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); + +static int __init rk2818_cpufreq_init(struct cpufreq_policy *policy) +{ + arm_clk = clk_get(NULL, "arm"); + if (IS_ERR(arm_clk)) + return PTR_ERR(arm_clk); + + if (policy->cpu != 0) + return -EINVAL; + + clk_init_cpufreq_table(&freq_table); + if (!freq_table) + return -EINVAL; + + BUG_ON(cpufreq_frequency_table_cpuinfo(policy, freq_table)); + cpufreq_frequency_table_get_attr(freq_table, policy->cpu); + policy->cur = clk_get_rate(arm_clk) / 1000; + policy->cpuinfo.transition_latency = 300 * NSEC_PER_USEC; // FIXME: 0.3ms? + + return 0; +} + +static int rk2818_cpufreq_exit(struct cpufreq_policy *policy) +{ + clk_put(arm_clk); + return 0; +} + +static struct freq_attr *rk2818_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver rk2818_cpufreq_driver = { + .flags = CPUFREQ_STICKY, + .init = rk2818_cpufreq_init, + .exit = rk2818_cpufreq_exit, + .verify = rk2818_cpufreq_verify, + .target = rk2818_cpufreq_target, + .name = "rk2818", + .attr = rk2818_cpufreq_attr, +}; + +static int __init rk2818_cpufreq_register(void) +{ + return cpufreq_register_driver(&rk2818_cpufreq_driver); +} + +late_initcall(rk2818_cpufreq_register); + -- 2.34.1