From 92e03c41a415e8e9e8009a1f5bbb9036f3bfb2f4 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 13 Jul 2011 17:58:32 -0400 Subject: [PATCH 01/17] [CPUFREQ] Handle CPUs with different capabilities in acpi-cpufreq acpi-cpufreq checks each CPU for aperf/mperf support, but only sets a global flag. This will cause errors if some CPUs in the system don't support the feature. Check boot_cpu_has() instead in order to make sure that all CPUs support it. Signed-off-by: Matthew Garrett Signed-off-by: Dave Jones --- drivers/cpufreq/acpi-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 596d5dd32f415..56c6c6b4eb4d6 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -655,7 +655,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) acpi_processor_notify_smm(THIS_MODULE); /* Check for APERF/MPERF support in hardware */ - if (cpu_has(c, X86_FEATURE_APERFMPERF)) + if (boot_cpu_has(X86_FEATURE_APERFMPERF)) acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf; pr_debug("CPU%u - ACPI performance management activated.\n", cpu); From be2de99beaca6506a1f97a636750c108a41b5c00 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 10 May 2011 15:42:08 +0200 Subject: [PATCH 02/17] [CPUFREQ/S3C64xx] Move S3C64xx CPUfreq driver into drivers/cpufreq This is a straight code motion patch, there are no changes to the driver itself. The Kconfig is left untouched as the ARM CPUfreq Kconfig is all in one big block in arm/Kconfig and should be moved en masse rather than being done piecemeal. Signed-off-by: Mark Brown Signed-off-by: Dave Jones --- arch/arm/mach-s3c64xx/Makefile | 4 ---- drivers/cpufreq/Makefile | 1 + arch/arm/mach-s3c64xx/cpufreq.c => drivers/cpufreq/s3c64xx.c | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) rename arch/arm/mach-s3c64xx/cpufreq.c => drivers/cpufreq/s3c64xx.c (99%) diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile index 4657363f0674a..f5a7144a052fa 100644 --- a/arch/arm/mach-s3c64xx/Makefile +++ b/arch/arm/mach-s3c64xx/Makefile @@ -23,10 +23,6 @@ obj-$(CONFIG_CPU_S3C6410) += s3c6410.o obj-y += irq.o obj-y += irq-eint.o -# CPU frequency scaling - -obj-$(CONFIG_CPU_FREQ_S3C64XX) += cpufreq.o - # DMA support obj-$(CONFIG_S3C64XX_DMA) += dma.o diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index e2fc2d21fa616..0fd8cae1c8285 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o # ARM SoC drivers obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o +obj-$(CONFIG_CPU_FREQ_S3C64XX) += s3c64xx.o diff --git a/arch/arm/mach-s3c64xx/cpufreq.c b/drivers/cpufreq/s3c64xx.c similarity index 99% rename from arch/arm/mach-s3c64xx/cpufreq.c rename to drivers/cpufreq/s3c64xx.c index 4375b97588b81..fc3f18078e5d7 100644 --- a/arch/arm/mach-s3c64xx/cpufreq.c +++ b/drivers/cpufreq/s3c64xx.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s3c64xx/cpufreq.c - * +/* * Copyright 2009 Wolfson Microelectronics plc * * S3C64xx CPUfreq Support From f7d770790f29781116d0de1339214934b8020c1e Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 1 Jun 2011 14:18:22 -0700 Subject: [PATCH 03/17] [CPUFREQ] Move ARM Samsung cpufreq drivers to drivers/cpufreq/ According to discussion of the ARM arch subsystem migration, ARM cpufreq drivers move to drivers/cpufreq. So this patch adds Kconfig.arm for ARM like x86 and adds Samsung S5PV210 and EXYNOS4210 cpufreq driver compile in there. As a note, otherw will be moved. Cc: Dave Jones Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- arch/arm/mach-exynos4/Makefile | 1 - arch/arm/mach-s5pv210/Makefile | 1 - drivers/cpufreq/Kconfig | 5 ++++ drivers/cpufreq/Kconfig.arm | 23 +++++++++++++++++++ drivers/cpufreq/Makefile | 2 ++ .../cpufreq/exynos4210-cpufreq.c | 3 +-- .../cpufreq/s5pv210-cpufreq.c | 3 +-- 7 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 drivers/cpufreq/Kconfig.arm rename arch/arm/mach-exynos4/cpufreq.c => drivers/cpufreq/exynos4210-cpufreq.c (99%) rename arch/arm/mach-s5pv210/cpufreq.c => drivers/cpufreq/s5pv210-cpufreq.c (99%) diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile index 60fe5ecf35996..1366995d8c2ce 100644 --- a/arch/arm/mach-exynos4/Makefile +++ b/arch/arm/mach-exynos4/Makefile @@ -15,7 +15,6 @@ obj- := obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o obj-$(CONFIG_PM) += pm.o sleep.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile index 50907aca006c4..599a3c0e8f6cd 100644 --- a/arch/arm/mach-s5pv210/Makefile +++ b/arch/arm/mach-s5pv210/Makefile @@ -15,7 +15,6 @@ obj- := obj-$(CONFIG_CPU_S5PV210) += cpu.o init.o clock.o dma.o obj-$(CONFIG_CPU_S5PV210) += setup-i2c0.o obj-$(CONFIG_S5PV210_PM) += pm.o sleep.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o # machine support diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 9fb84853d8e30..e898215b88af9 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -184,5 +184,10 @@ depends on X86 source "drivers/cpufreq/Kconfig.x86" endmenu +menu "ARM CPU frequency scaling drivers" +depends on ARM +source "drivers/cpufreq/Kconfig.arm" +endmenu + endif endmenu diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm new file mode 100644 index 0000000000000..e5c56c7b3389b --- /dev/null +++ b/drivers/cpufreq/Kconfig.arm @@ -0,0 +1,23 @@ +# +# ARM CPU Frequency scaling drivers +# + +config ARM_S5PV210_CPUFREQ + bool "Samsung S5PV210 and S5PC110" + depends on CPU_S5PV210 + default y + help + This adds the CPUFreq driver for Samsung S5PV210 and + S5PC110 SoCs. + + If in doubt, say N. + +config ARM_EXYNOS4210_CPUFREQ + bool "Samsung EXYNOS4210" + depends on CPU_EXYNOS4210 + default y + help + This adds the CPUFreq driver for Samsung EXYNOS4210 + SoC (S5PV310 or S5PC210). + + If in doubt, say N. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 0fd8cae1c8285..9922294cc775d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -42,3 +42,5 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o # ARM SoC drivers obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o obj-$(CONFIG_CPU_FREQ_S3C64XX) += s3c64xx.o +obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o +obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o diff --git a/arch/arm/mach-exynos4/cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c similarity index 99% rename from arch/arm/mach-exynos4/cpufreq.c rename to drivers/cpufreq/exynos4210-cpufreq.c index a1bd258f0c4d5..54025fc4b52b7 100644 --- a/arch/arm/mach-exynos4/cpufreq.c +++ b/drivers/cpufreq/exynos4210-cpufreq.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/mach-exynos4/cpufreq.c - * +/* * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c similarity index 99% rename from arch/arm/mach-s5pv210/cpufreq.c rename to drivers/cpufreq/s5pv210-cpufreq.c index 153af8b359ec0..ea35d3f74e3d3 100644 --- a/arch/arm/mach-s5pv210/cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/mach-s5pv210/cpufreq.c - * +/* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * From 069283c3ec87e0abaa14f6bef96342b609f0fb92 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 6 Jun 2011 21:10:04 -0400 Subject: [PATCH 04/17] [CPUFREQ] Remove some vi noise that escaped into the Makefile. --- drivers/cpufreq/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 9922294cc775d..54194788b47fc 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o -##################################################################################d +################################################################################## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early # K8 systems. ACPI is preferred to all other hardware-specific drivers. @@ -37,8 +37,7 @@ obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o -##################################################################################d - +################################################################################## # ARM SoC drivers obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o obj-$(CONFIG_CPU_FREQ_S3C64XX) += s3c64xx.o From 15964d388528c1dbb672027c8003fe7e81630a35 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Mon, 6 Jun 2011 18:43:01 -0700 Subject: [PATCH 05/17] [CPUFREQ] Move compile for S3C64XX cpufreq to /drivers/cpufreq Cc: Mark Brown Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- arch/arm/Kconfig | 4 ---- drivers/cpufreq/Kconfig.arm | 9 +++++++++ drivers/cpufreq/Makefile | 2 +- drivers/cpufreq/{s3c64xx.c => s3c64xx-cpufreq.c} | 0 4 files changed, 10 insertions(+), 5 deletions(-) rename drivers/cpufreq/{s3c64xx.c => s3c64xx-cpufreq.c} (100%) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278a22abb..31c2899131022 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1875,10 +1875,6 @@ config CPU_FREQ_PXA default y select CPU_FREQ_DEFAULT_GOV_USERSPACE -config CPU_FREQ_S3C64XX - bool "CPUfreq support for Samsung S3C64XX CPUs" - depends on CPU_FREQ && CPU_S3C6410 - config CPU_FREQ_S3C bool help diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index e5c56c7b3389b..72a0044c1baa8 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -2,6 +2,15 @@ # ARM CPU Frequency scaling drivers # +config ARM_S3C64XX_CPUFREQ + bool "Samsung S3C64XX" + depends on CPU_S3C6410 + default y + help + This adds the CPUFreq driver for Samsung S3C6410 SoC. + + If in doubt, say N. + config ARM_S5PV210_CPUFREQ bool "Samsung S5PV210 and S5PC110" depends on CPU_S5PV210 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 54194788b47fc..ab75e573c69f4 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -40,6 +40,6 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o ################################################################################## # ARM SoC drivers obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o -obj-$(CONFIG_CPU_FREQ_S3C64XX) += s3c64xx.o +obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o diff --git a/drivers/cpufreq/s3c64xx.c b/drivers/cpufreq/s3c64xx-cpufreq.c similarity index 100% rename from drivers/cpufreq/s3c64xx.c rename to drivers/cpufreq/s3c64xx-cpufreq.c From 4911ca1031c2ade225fdf22cc872bc121c2c2ec5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 6 Jun 2011 18:59:02 -0700 Subject: [PATCH 06/17] [CPUFREQ] s5pv210-cpufreq.c: Add missing clk_put The successive calls to clk_get each call clk_put in the case of failure, but this is not done for subsequent error handling code. The calls to clk_get are moved to the end of the function, and appropriate gotos are added. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ expression e1,e2; statement S; @@ e1 = clk_get@p1(...); ... when != e1 = e2 when != clk_put(e1) when any if (...) { ... when != clk_put(e1) when != if (...) { ... clk_put(e1) ... } * return@p3 ...; } else S // Signed-off-by: Julia Lawall Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index ea35d3f74e3d3..a7cb3385bf5ed 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -415,6 +415,7 @@ static int check_mem_type(void __iomem *dmc_reg) static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) { unsigned long mem_type; + int ret; cpu_clk = clk_get(NULL, "armclk"); if (IS_ERR(cpu_clk)) @@ -422,19 +423,20 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) dmc0_clk = clk_get(NULL, "sclk_dmc0"); if (IS_ERR(dmc0_clk)) { - clk_put(cpu_clk); - return PTR_ERR(dmc0_clk); + ret = PTR_ERR(dmc0_clk); + goto out_dmc0; } dmc1_clk = clk_get(NULL, "hclk_msys"); if (IS_ERR(dmc1_clk)) { - clk_put(dmc0_clk); - clk_put(cpu_clk); - return PTR_ERR(dmc1_clk); + ret = PTR_ERR(dmc1_clk); + goto out_dmc1; } - if (policy->cpu != 0) - return -EINVAL; + if (policy->cpu != 0) { + ret = -EINVAL; + goto out_dmc1; + } /* * check_mem_type : This driver only support LPDDR & LPDDR2. @@ -444,7 +446,8 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) if ((mem_type != LPDDR) && (mem_type != LPDDR2)) { printk(KERN_ERR "CPUFreq doesn't support this memory type\n"); - return -EINVAL; + ret = -EINVAL; + goto out_dmc1; } /* Find current refresh counter and frequency each DMC */ @@ -461,6 +464,12 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 40000; return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); + +out_dmc1: + clk_put(dmc0_clk); +out_dmc0: + clk_put(cpu_clk); + return ret; } static struct cpufreq_driver s5pv210_driver = { From c6e2d68558b612fdfdb0d7ddcb51ad4578b81eba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Jun 2011 14:49:15 +0100 Subject: [PATCH 07/17] [CPUFREQ] S3C6410: Support 800MHz operation in cpufreq At least some newer S3C6410 silicon supports operation up to 800MHz rather than just 667MHz. Unfortunately I don't have access to any of documentation of this other than some running systems, add a new cpufreq table entry for this based on the behaviour of those systems. Signed-off-by: Mark Brown Acked-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s3c64xx-cpufreq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index fc3f18078e5d7..fc69178798e6e 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -31,6 +31,7 @@ static struct s3c64xx_dvfs s3c64xx_dvfs_table[] = { [1] = { 1050000, 1150000 }, [2] = { 1100000, 1150000 }, [3] = { 1200000, 1350000 }, + [4] = { 1300000, 1350000 }, }; static struct cpufreq_frequency_table s3c64xx_freq_table[] = { @@ -43,6 +44,7 @@ static struct cpufreq_frequency_table s3c64xx_freq_table[] = { { 2, 532000 }, { 2, 533000 }, { 3, 667000 }, + { 4, 800000 }, { 0, CPUFREQ_TABLE_END }, }; #endif From fb3b1fefaaccdbdc716db0963ba41fb6b4221e60 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 22 Jun 2011 15:08:56 +0100 Subject: [PATCH 08/17] [CPUFREQ] S3C64xx: Notify transition complete as soon as frequency changed The CPUFREQ_POSTCHANGE notification is used to update things that depend on the system clock rates. Since this may include the interfaces used to talk to the regulators do the notification before we try to update regulators to reflect lowered system clock rate. The voltage scaling is just a power optimisation and may not happen at all so there's no concern about it not having completed. Signed-off-by: Mark Brown Acked-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s3c64xx-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index fc69178798e6e..e818248ab2b1f 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -112,6 +112,8 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, goto err; } + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + #ifdef CONFIG_REGULATOR if (vddarm && freqs.new < freqs.old) { ret = regulator_set_voltage(vddarm, @@ -125,8 +127,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, } #endif - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - pr_debug("cpufreq: Set actual frequency %lukHz\n", clk_get_rate(armclk) / 1000); From 90d5d0a119bcf189e8b33f776b4f8371b789b311 Mon Sep 17 00:00:00 2001 From: Huisung Kang Date: Fri, 24 Jun 2011 16:04:13 +0900 Subject: [PATCH 09/17] [CPUFREQ] S5PV210: Add additional symantics for "relation" in cpufreq with pm Relation has an additional symantics other than standard. s5pv310_target funtion have below additional relation. - DISABLE_FURTHER_CPUFREQ : disable further access to target - ENABLE_FURTHER_CPUFRER : enable access to target Signed-off-by: Huisung Kang Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index a7cb3385bf5ed..48a4a9058864e 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -29,6 +29,18 @@ static struct cpufreq_freqs freqs; #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) +/* + * relation has an additional symantics other than the standard of cpufreq + * DISALBE_FURTHER_CPUFREQ: disable further access to target + * ENABLE_FURTUER_CPUFREQ: enable access to target + */ +enum cpufreq_access { + DISABLE_FURTHER_CPUFREQ = 0x10, + ENABLE_FURTHER_CPUFREQ = 0x20, +}; + +static bool no_cpufreq_access; + /* * DRAM configurations to calculate refresh counter for changing * frequency of memory. @@ -146,6 +158,22 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int pll_changing = 0; unsigned int bus_speed_changing = 0; + if (relation & ENABLE_FURTHER_CPUFREQ) + no_cpufreq_access = false; + + if (no_cpufreq_access) { +#ifdef CONFIG_PM_VERBOSE + pr_err("%s:%d denied access to %s as it is disabled" + "temporarily\n", __FILE__, __LINE__, __func__); +#endif + return -EINVAL; + } + + if (relation & DISABLE_FURTHER_CPUFREQ) + no_cpufreq_access = true; + + relation &= ~(ENABLE_FURTHER_CPUFREQ | DISABLE_FURTHER_CPUFREQ); + freqs.old = s5pv210_getspeed(0); if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, From e8b4c1986efbb5b1e1bab9f359c340816e4d9869 Mon Sep 17 00:00:00 2001 From: Jonghwan Choi Date: Fri, 24 Jun 2011 16:04:14 +0900 Subject: [PATCH 10/17] [CPUFREQ] S5PV210: Add arm/int voltage control support Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 71 +++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 48a4a9058864e..9a5b28474342f 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,40 @@ static struct cpufreq_frequency_table s5pv210_freq_table[] = { {0, CPUFREQ_TABLE_END}, }; +static struct regulator *arm_regulator; +static struct regulator *int_regulator; + +struct s5pv210_dvs_conf { + int arm_volt; /* uV */ + int int_volt; /* uV */ +}; + +static const int arm_volt_max = 1350000; +static const int int_volt_max = 1250000; + +static struct s5pv210_dvs_conf dvs_conf[] = { + [L0] = { + .arm_volt = 1250000, + .int_volt = 1100000, + }, + [L1] = { + .arm_volt = 1200000, + .int_volt = 1100000, + }, + [L2] = { + .arm_volt = 1050000, + .int_volt = 1100000, + }, + [L3] = { + .arm_volt = 950000, + .int_volt = 1100000, + }, + [L4] = { + .arm_volt = 950000, + .int_volt = 1000000, + }, +}; + static u32 clkdiv_val[5][11] = { /* * Clock divider value for following @@ -157,6 +192,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index, priv_index; unsigned int pll_changing = 0; unsigned int bus_speed_changing = 0; + int arm_volt, int_volt; + int ret = 0; if (relation & ENABLE_FURTHER_CPUFREQ) no_cpufreq_access = false; @@ -191,12 +228,23 @@ static int s5pv210_target(struct cpufreq_policy *policy, freqs.old, relation, &priv_index)) return -EINVAL; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + arm_volt = dvs_conf[index].arm_volt; + int_volt = dvs_conf[index].int_volt; if (freqs.new > freqs.old) { - /* Voltage up: will be implemented */ + ret = regulator_set_voltage(arm_regulator, + arm_volt, arm_volt_max); + if (ret) + return ret; + + ret = regulator_set_voltage(int_regulator, + int_volt, int_volt_max); + if (ret) + return ret; } + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + /* Check if there need to change PLL */ if ((index == L0) || (priv_index == L0)) pll_changing = 1; @@ -408,7 +456,11 @@ static int s5pv210_target(struct cpufreq_policy *policy, } if (freqs.new < freqs.old) { - /* Voltage down: will be implemented */ + regulator_set_voltage(int_regulator, + int_volt, int_volt_max); + + regulator_set_voltage(arm_regulator, + arm_volt, arm_volt_max); } cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); @@ -515,6 +567,19 @@ static struct cpufreq_driver s5pv210_driver = { static int __init s5pv210_cpufreq_init(void) { + arm_regulator = regulator_get(NULL, "vddarm"); + if (IS_ERR(arm_regulator)) { + pr_err("failed to get regulator vddarm"); + return PTR_ERR(arm_regulator); + } + + int_regulator = regulator_get(NULL, "vddint"); + if (IS_ERR(int_regulator)) { + pr_err("failed to get regulator vddint"); + regulator_put(arm_regulator); + return PTR_ERR(int_regulator); + } + return cpufreq_register_driver(&s5pv210_driver); } From 405e6d6df739a27a267b381213aa9e86c4929543 Mon Sep 17 00:00:00 2001 From: Huisung Kang Date: Fri, 24 Jun 2011 16:04:15 +0900 Subject: [PATCH 11/17] [CPUFREQ] S5PV210: Add pm_notifier to prevent system unstable Minimum 800MHz is needed to enter/exit suspend mode due to voltage mismatch. Signed-off-by: Huisung Kang Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 9a5b28474342f..79b1b4ec8e3c6 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,9 @@ static struct cpufreq_freqs freqs; #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) +/* Use 800MHz when entering sleep mode */ +#define SLEEP_FREQ (800 * 1000) + /* * relation has an additional symantics other than the standard of cpufreq * DISALBE_FURTHER_CPUFREQ: disable further access to target @@ -552,6 +556,30 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) return ret; } +static int s5pv210_cpufreq_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + int ret; + + switch (event) { + case PM_SUSPEND_PREPARE: + ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, + DISABLE_FURTHER_CPUFREQ); + if (ret < 0) + return NOTIFY_BAD; + + return NOTIFY_OK; + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, + ENABLE_FURTHER_CPUFREQ); + + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + static struct cpufreq_driver s5pv210_driver = { .flags = CPUFREQ_STICKY, .verify = s5pv210_verify_speed, @@ -565,6 +593,10 @@ static struct cpufreq_driver s5pv210_driver = { #endif }; +static struct notifier_block s5pv210_cpufreq_notifier = { + .notifier_call = s5pv210_cpufreq_notifier_event, +}; + static int __init s5pv210_cpufreq_init(void) { arm_regulator = regulator_get(NULL, "vddarm"); @@ -580,6 +612,8 @@ static int __init s5pv210_cpufreq_init(void) return PTR_ERR(int_regulator); } + register_pm_notifier(&s5pv210_cpufreq_notifier); + return cpufreq_register_driver(&s5pv210_driver); } From 5b02b7794b555e299c5e9298c6b223b538888ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 24 Jun 2011 16:04:16 +0900 Subject: [PATCH 12/17] [CPUFREQ] S5PV210: Lock a mutex while changing the cpu frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this lock the call to change the frequency for suspend could switch to a new frequency while another thread was still changing the cpu voltage. Signed-off-by: Arve Hjønnevåg Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 79b1b4ec8e3c6..7fba356d27297 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -26,6 +26,7 @@ static struct clk *cpu_clk; static struct clk *dmc0_clk; static struct clk *dmc1_clk; static struct cpufreq_freqs freqs; +static DEFINE_MUTEX(set_freq_lock); /* APLL M,P,S values for 1G/800Mhz */ #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) @@ -199,6 +200,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, int arm_volt, int_volt; int ret = 0; + mutex_lock(&set_freq_lock); + if (relation & ENABLE_FURTHER_CPUFREQ) no_cpufreq_access = false; @@ -207,7 +210,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, pr_err("%s:%d denied access to %s as it is disabled" "temporarily\n", __FILE__, __LINE__, __func__); #endif - return -EINVAL; + ret = -EINVAL; + goto exit; } if (relation & DISABLE_FURTHER_CPUFREQ) @@ -218,19 +222,23 @@ static int s5pv210_target(struct cpufreq_policy *policy, freqs.old = s5pv210_getspeed(0); if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, - target_freq, relation, &index)) - return -EINVAL; + target_freq, relation, &index)) { + ret = -EINVAL; + goto exit; + } freqs.new = s5pv210_freq_table[index].frequency; freqs.cpu = 0; if (freqs.new == freqs.old) - return 0; + goto exit; /* Finding current running level index */ if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, - freqs.old, relation, &priv_index)) - return -EINVAL; + freqs.old, relation, &priv_index)) { + ret = -EINVAL; + goto exit; + } arm_volt = dvs_conf[index].arm_volt; int_volt = dvs_conf[index].int_volt; @@ -239,12 +247,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt_max); if (ret) - return ret; + goto exit; ret = regulator_set_voltage(int_regulator, int_volt, int_volt_max); if (ret) - return ret; + goto exit; } cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); @@ -471,7 +479,9 @@ static int s5pv210_target(struct cpufreq_policy *policy, printk(KERN_DEBUG "Perf changed[L%d]\n", index); - return 0; +exit: + mutex_unlock(&set_freq_lock); + return ret; } #ifdef CONFIG_PM From 74df8e69e901e624fe0b439f914aa7be66201154 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Fri, 24 Jun 2011 16:04:17 +0900 Subject: [PATCH 13/17] [CPUFREQ] S5PV210: Adjust udelay prior to voltage scaling down Voltage scaling accesses the MAX8998 regulators over bit-banged I2C with lots of udelays. In the case of decreasing CPU speed, the number of loops per us for udelay needs to be adjusted prior to decreasing voltage to avoid delaying for up to 10X too long. Signed-off-by: Todd Poynor Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 7fba356d27297..155242cfc7143 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -467,6 +467,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, } } + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + if (freqs.new < freqs.old) { regulator_set_voltage(int_regulator, int_volt, int_volt_max); @@ -475,8 +477,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, arm_volt, arm_volt_max); } - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - printk(KERN_DEBUG "Perf changed[L%d]\n", index); exit: From fe7f1bcbff917f22e121d4b2c045fb1de80cc450 Mon Sep 17 00:00:00 2001 From: Huisung Kang Date: Fri, 24 Jun 2011 16:04:18 +0900 Subject: [PATCH 14/17] [CPUFREQ] S5PV210: Add reboot notifier to prevent system hang When system reboot, the CPUFREQ level should be 800MHz to prevent system lockup. Signed-off-by: Huisung Kang Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 155242cfc7143..7c4bb070b904b 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -590,6 +591,19 @@ static int s5pv210_cpufreq_notifier_event(struct notifier_block *this, return NOTIFY_DONE; } +static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + int ret; + + ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, + DISABLE_FURTHER_CPUFREQ); + if (ret < 0) + return NOTIFY_BAD; + + return NOTIFY_DONE; +} + static struct cpufreq_driver s5pv210_driver = { .flags = CPUFREQ_STICKY, .verify = s5pv210_verify_speed, @@ -607,6 +621,10 @@ static struct notifier_block s5pv210_cpufreq_notifier = { .notifier_call = s5pv210_cpufreq_notifier_event, }; +static struct notifier_block s5pv210_cpufreq_reboot_notifier = { + .notifier_call = s5pv210_cpufreq_reboot_notifier_event, +}; + static int __init s5pv210_cpufreq_init(void) { arm_regulator = regulator_get(NULL, "vddarm"); @@ -623,6 +641,7 @@ static int __init s5pv210_cpufreq_init(void) } register_pm_notifier(&s5pv210_cpufreq_notifier); + register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier); return cpufreq_register_driver(&s5pv210_driver); } From ef993ef8dcd4f3e4d058400c5bd2f7c547344e74 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Jun 2011 20:26:49 -0700 Subject: [PATCH 15/17] [CPUFREQ] S3C6410: Add some lower frequencies for 800MHz base clock operation By extension from the 667MHz based clocks currently supported add 100MHz and 200MHz operating points. Due to a lack of documentation these have not been confirmed as supported but by extension from the existing frequencies they should be OK, and I've given them quite a bit of runtime testing. The major risk is synchronization with the non-ARM clocks but as we can't currently scale the ARM PLL the risk should be relatively low. Signed-off-by: Mark Brown Acked-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s3c64xx-cpufreq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index e818248ab2b1f..b8d1d205e1eff 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -36,7 +36,9 @@ static struct s3c64xx_dvfs s3c64xx_dvfs_table[] = { static struct cpufreq_frequency_table s3c64xx_freq_table[] = { { 0, 66000 }, + { 0, 100000 }, { 0, 133000 }, + { 1, 200000 }, { 1, 222000 }, { 1, 266000 }, { 2, 333000 }, From 2f0d6f20ec4cc157ba092e008ed20a99590142c4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 8 Jul 2011 14:20:44 +0800 Subject: [PATCH 16/17] [CPUFREQ] exynos4210: make needlessly global symbols static The following symbols are needlessly defined global: exynos4_verify_speed exynos4_getspeed exynos4_set_clkdiv Make them static. Signed-off-by: Axel Lin Acked-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/exynos4210-cpufreq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c index 54025fc4b52b7..b7c3a84c4cfa8 100644 --- a/drivers/cpufreq/exynos4210-cpufreq.c +++ b/drivers/cpufreq/exynos4210-cpufreq.c @@ -191,17 +191,17 @@ static unsigned int exynos4_apll_pms_table[CPUFREQ_LEVEL_END] = { ((200 << 16) | (6 << 8) | 4), }; -int exynos4_verify_speed(struct cpufreq_policy *policy) +static int exynos4_verify_speed(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, exynos4_freq_table); } -unsigned int exynos4_getspeed(unsigned int cpu) +static unsigned int exynos4_getspeed(unsigned int cpu) { return clk_get_rate(cpu_clk) / 1000; } -void exynos4_set_clkdiv(unsigned int div_index) +static void exynos4_set_clkdiv(unsigned int div_index) { unsigned int tmp; From 133de1211982bd2ba9ab401f7a73d25d052ccd61 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 8 Jul 2011 14:24:36 +0800 Subject: [PATCH 17/17] [CPUFREQ] s5pv210: make needlessly global symbols static The following symbols are needlessly defined global: s5pv210_verify_speed s5pv210_getspeed Make them static. Signed-off-by: Axel Lin Acked-by: Kukjin Kim Signed-off-by: Dave Jones --- drivers/cpufreq/s5pv210-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 7c4bb070b904b..a484aaea98091 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c @@ -174,7 +174,7 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq) __raw_writel(tmp1, reg); } -int s5pv210_verify_speed(struct cpufreq_policy *policy) +static int s5pv210_verify_speed(struct cpufreq_policy *policy) { if (policy->cpu) return -EINVAL; @@ -182,7 +182,7 @@ int s5pv210_verify_speed(struct cpufreq_policy *policy) return cpufreq_frequency_table_verify(policy, s5pv210_freq_table); } -unsigned int s5pv210_getspeed(unsigned int cpu) +static unsigned int s5pv210_getspeed(unsigned int cpu) { if (cpu) return 0;