Skip to contentSkip to conversation

ARM: S5PV210: CPUFREQ Initial Support

PATCH Superseded MyungJoo Ham 6 participants 15 messages Jul 16, 2010 – Jul 19, 2010

Subsystems (3)

v2 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v2 cover ARM: S5PV210: CPUFREQ Initial Support

S5PV210 CPUFREQ Initial Support.

This is a series of patches to enable CPUFREQ for S5PV210.

Although this works without PMIC's DVS support, it is not as effective without DVS support as supposed. AVS is not supported in this version.

MyungJoo Ham (5):
ARM: Samsung SoC: added hclk/pclk info to s3c_freq for s5pv210
cpu-freq
ARM: S5P: Added default pll values for APLL 800/1000MHz
ARM: S5PV210: macros for clock registers at regs-clock.h
ARM: S5PV210: add DMCx access virtual address
ARM: S5PV210: Initial CPUFREQ Support

 arch/arm/Kconfig                                |    1 +
 arch/arm/mach-s5pv210/Makefile                  |    3 +
 arch/arm/mach-s5pv210/cpu.c                     |   12 +-
 arch/arm/mach-s5pv210/cpufreq-s5pv210.c         |  776 +++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h   |   50 ++
 arch/arm/mach-s5pv210/include/mach/map.h        |    8 +
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   45 ++-
 arch/arm/plat-s5p/include/plat/pll.h            |    8 +
 arch/arm/plat-samsung/include/plat/cpu-freq.h   |    6 +
 9 files changed, 905 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq-s5pv210.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h
#1 lore raw

PATCH v2 1/5 ARM: Samsung SoC: added hclk/pclk info to s3c_freq for s5pv210 cpu-freq

S5PV210 requires msys/dsys info as well; thus, we've included those at struct s3c_freq, which is used by CPUFREQ of S5PV210.

---
 arch/arm/plat-samsung/include/plat/cpu-freq.h |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
arch/arm/plat-samsung/include/plat/cpu-freq.h +6 -0
index 80c4a80..9e97df7 100644
@@ -38,6 +38,12 @@ struct s3c_freq {
 	unsigned long	hclk_tns;	/* in 10ths of ns */
 	unsigned long	hclk;
 	unsigned long	pclk;
+#ifdef CONFIG_ARCH_S5PV210
+	unsigned long	hclk_msys;
+	unsigned long	pclk_msys;
+	unsigned long	hclk_dsys;
+	unsigned long	pclk_dsys;
+#endif
 };
 
 /**
Signature · 1 line
1.6.3.3
#2 lore raw

PATCH v2 2/5 ARM: S5P: Added default pll values for APLL 800/1000MHz

CPUFREQ of S5PV210 uses different APLL settings and we provide such values for CPUFREQ at pll.h. We have been using differently between EVT0 and EVT1 machines. Although this version of kernel assumes that the CPU is EVT1, users may use code for EVT0 later.

Note that at 1GHz of ARMCLK, APLL should be 1GHz and for other lower ARMCLK, APLL should be 800MHz.

---
 arch/arm/plat-s5p/include/plat/pll.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
arch/arm/plat-s5p/include/plat/pll.h +8 -0
index 7db3227..3112aba 100644
@@ -21,6 +21,14 @@
 
 #include <asm/div64.h>
 
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+#define PLL45XX_APLL_VAL_1000	(1 << 31) | (0xfa<<16) | (0x6<<8) | (0x1)
+#define PLL45XX_APLL_VAL_800	(1 << 31) | (0xc8<<16) | (0x6<<8) | (0x1)
+#else
+#define PLL45XX_APLL_VAL_1000	(1 << 31) | (125<<16) | (3<<8) | (1)
+#define PLL45XX_APLL_VAL_800	(1 << 31) | (100<<16) | (3<<8) | (1)
+#endif
+
 enum pll45xx_type_t {
 	pll_4500,
 	pll_4502,
Signature · 1 line
1.6.3.3
#3 lore raw

PATCH v2 3/5 ARM: S5PV210: macros for clock registers at regs-clock.h

Previously, most of CLK_DIV/SRC register accessing mask and shift values were used at arch/arm/mach-s5pv210/clock.c only; thus we had not been using macros for these. However, as CPUFREQ uses those shift and mask values as well, we'd better define them at a single location, whose proper location would be regs-clock.h.

Note that only the information about registers used by CPUFREQ are defined. However, we may need to define other registers later if we add other parts.

---
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   45 +++++++++++++++++++++--
 1 files changed, 42 insertions(+), 3 deletions(-)
arch/arm/mach-s5pv210/include/mach/regs-clock.h +42 -3
index 2a25ab4..a117ecc 100644
@@ -66,11 +66,30 @@
 #define S5P_CLKGATE_BUS0	S5P_CLKREG(0x484)
 #define S5P_CLKGATE_BUS1	S5P_CLKREG(0x488)
 #define S5P_CLK_OUT		S5P_CLKREG(0x500)
+#define S5P_CLK_DIV_STAT0   S5P_CLKREG(0x1000)
+#define S5P_CLK_DIV_STAT1   S5P_CLKREG(0x1004)
+#define S5P_CLK_MUX_STAT0   S5P_CLKREG(0x1100)
+#define S5P_CLK_MUX_STAT1   S5P_CLKREG(0x1104)
+
+#define S5P_ARM_MCS_CON		S5P_CLKREG(0x6100)
 
 /* CLKSRC0 */
-#define S5P_CLKSRC0_MUX200_MASK		(0x1<<16)
-#define S5P_CLKSRC0_MUX166_MASK		(0x1<<20)
-#define S5P_CLKSRC0_MUX133_MASK		(0x1<<24)
+#define S5P_CLKSRC0_APLL_MASK		(0x1 << 0)
+#define S5P_CLKSRC0_APLL_SHIFT		(0)
+#define S5P_CLKSRC0_MPLL_MASK		(0x1 << 4)
+#define S5P_CLKSRC0_MPLL_SHIFT		(4)
+#define S5P_CLKSRC0_EPLL_MASK		(0x1 << 8)
+#define S5P_CLKSRC0_EPLL_SHIFT		(8)
+#define S5P_CLKSRC0_VPLL_MASK		(0x1 << 12)
+#define S5P_CLKSRC0_VPLL_SHIFT		(12)
+#define S5P_CLKSRC0_MUX200_MASK		(0x1 << 16)
+#define S5P_CLKSRC0_MUX200_SHIFT	(16)
+#define S5P_CLKSRC0_MUX166_MASK		(0x1 << 20)
+#define S5P_CLKSRC0_MUX166_SHIFT	(20)
+#define S5P_CLKSRC0_MUX133_MASK		(0x1 << 24)
+#define S5P_CLKSRC0_MUX133_SHIFT	(24)
+#define S5P_CLKSRC0_ONENAND_MASK	(0x1 << 28)
+#define S5P_CLKSRC0_ONENAND_SHIFT	(28)
 
 /* CLKDIV0 */
 #define S5P_CLKDIV0_APLL_SHIFT		(0)
@@ -90,6 +109,26 @@
 #define S5P_CLKDIV0_PCLK66_SHIFT	(28)
 #define S5P_CLKDIV0_PCLK66_MASK		(0x7 << S5P_CLKDIV0_PCLK66_SHIFT)
 
+/* CLKSRC2 */
+#define S5P_CLKSRC2_G3D_MASK		(0x3 << 0)
+#define S5P_CLKSRC2_G3D_SHIFT		(0)
+#define S5P_CLKSRC2_MFC_MASK		(0x3 << 4)
+#define S5P_CLKSRC2_MFC_SHIFT		(4)
+#define S5P_CLKSRC2_G2D_MASK		(0x3 << 8)
+#define S5P_CLKSRC2_G2D_SHIFT		(8)
+
+/* CLKDIV2 */
+#define S5P_CLKDIV2_G3D_MASK		(0xF << 0)
+#define S5P_CLKDIV2_G3D_SHIFT		(0)
+#define S5P_CLKDIV2_MFC_MASK		(0xF << 4)
+#define S5P_CLKDIV2_MFC_SHIFT		(4)
+#define S5P_CLKDIV2_G2D_MASK		(0xF << 8)
+#define S5P_CLKDIV2_G2D_SHIFT		(8)
+
+/* CLKDIV6 */
+#define S5P_CLKDIV6_ONEDRAM_MASK	(0xf<<28)
+#define S5P_CLKDIV6_ONEDRAM_SHIFT	(28)
+
 /* Registers related to power management */
 #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
 #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
Signature · 1 line
1.6.3.3
#4 lore raw

PATCH v2 4/5 ARM: S5PV210: add DMCx access virtual address

This patch prepares CPUFREQ support for S5PV210 by adding definitions for S5P_VA_DMCx accessed by CPUFREQ, which were not defined previously.

---
 arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
 arch/arm/mach-s5pv210/include/mach/map.h |    8 ++++++++
 2 files changed, 19 insertions(+), 1 deletions(-)
arch/arm/mach-s5pv210/cpu.c +11 -1
index 94c632b..84a6708 100644
@@ -59,7 +59,17 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
 		.pfn		= __phys_to_pfn(S5PV210_PA_SROMC),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
-	}
+	}, {
+		.virtual    = (unsigned long)S5P_VA_DMC0,
+		.pfn        = __phys_to_pfn(S5P_PA_DMC0),
+		.length     = SZ_4K,
+		.type       = MT_DEVICE,
+	}, {
+		.virtual    = (unsigned long)S5P_VA_DMC1,
+		.pfn        = __phys_to_pfn(S5P_PA_DMC1),
+		.length     = SZ_4K,
+		.type       = MT_DEVICE,
+	},
 };
 
 static void s5pv210_idle(void)
arch/arm/mach-s5pv210/include/mach/map.h +8 -0
index 17687f0..4945674 100644
@@ -108,4 +108,12 @@
 #define SAMSUNG_PA_ADC		S5PV210_PA_ADC
 #define SAMSUNG_PA_KEYPAD	S5PV210_PA_KEYPAD
 
+/* DMC */
+#define S5P_PA_DMC0     (0xF0000000)
+#define S5P_VA_DMC0     S3C_ADDR(0x00a00000)
+
+#define S5P_PA_DMC1     (0xF1400000)
+#define S5P_VA_DMC1     S3C_ADDR(0x00b00000)
+
+
 #endif /* __ASM_ARCH_MAP_H */
Signature · 1 line
1.6.3.3
#5 lore raw

PATCH v2 5/5 ARM: S5PV210: Initial CPUFREQ Support

S5PV210 CPUFREQ Support.

This CPUFREQ may work without PMIC's DVS support. However, it is not as effective without DVS support as supposed. AVS is not supported in this version.

Note that CLK_SRC of some clocks including ARMCLK, G3D, G2D, MFC, and ONEDRAM are modified directly without updating clksrc_src representations of the clocks. Because CPUFREQ reverts the CLK_SRC to the supposed values, this does not affect the consistency as long as there are no other modules that modifies clock sources of ARMCLK, G3D, G2D, MFC, and ONEDRAM (and only CPUFREQ should have the control). As soon as clock framework is settled, we may update source clocks (.parent field) of those clocks accordingly later.

--
v2:
- Ramp-up delay is removed. (let regulator framework do the job)
- Provide proper max values for regulator_set_voltage
- Removed unneccesary #ifdef's.
- Removed unnecessary initialiser for CLK_OUT

---
 arch/arm/Kconfig                              |    1 +
 arch/arm/mach-s5pv210/Makefile                |    3 +
 arch/arm/mach-s5pv210/cpufreq-s5pv210.c       |  776 +++++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h |   50 ++
 4 files changed, 830 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq-s5pv210.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h
arch/arm/Kconfig +1 -0
index 98922f7..d5a5916 100644
@@ -701,6 +701,7 @@ config ARCH_S5PV210
 	select HAVE_CLK
 	select ARM_L1_CACHE_SHIFT_6
 	select ARCH_USES_GETTIMEOFFSET
+	select ARCH_HAS_CPUFREQ
 	help
 	  Samsung S5PV210/S5PC110 series based systems
 
arch/arm/mach-s5pv210/Makefile +3 -0
index aae592a..293dbac 100644
@@ -34,3 +34,6 @@ obj-$(CONFIG_S5PV210_SETUP_I2C2) 	+= setup-i2c2.o
 obj-$(CONFIG_S5PV210_SETUP_KEYPAD)	+= setup-keypad.o
 obj-$(CONFIG_S5PV210_SETUP_SDHCI)       += setup-sdhci.o
 obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o
+
+# CPUFREQ (DVFS)
+obj-$(CONFIG_CPU_FREQ)		+= cpufreq-s5pv210.o
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +776 -0

776 lines not on this page · raw message

arch/arm/mach-s5pv210/include/mach/cpu-freq.h new file +50 -0

50 lines not on this page · raw message

Signature · 1 line
1.6.3.3
#6 lore raw

PATCH v2 5/5 ARM: S5PV210: Initial CPUFREQ Support

Quoted 5 lines · MyungJoo Ham

S5PV210 CPUFREQ Support.

This CPUFREQ may work without PMIC's DVS support. However, it is not as effective without DVS support as supposed. AVS is not supported in this version.

Especially in terms of the regulator API usage:

#7 lore raw

PATCH v2 5/5 ARM: S5PV210: Initial CPUFREQ Support

In reply to MyungJoo Ham

Op 16-07-10 10:01, MyungJoo Ham schreef:

Quoted 115 lines

S5PV210 CPUFREQ Support.

This CPUFREQ may work without PMIC's DVS support. However, it is not as effective without DVS support as supposed. AVS is not supported in this version.

Note that CLK_SRC of some clocks including ARMCLK, G3D, G2D, MFC, and ONEDRAM are modified directly without updating clksrc_src representations of the clocks. Because CPUFREQ reverts the CLK_SRC to the supposed values, this does not affect the consistency as long as there are no other modules that modifies clock sources of ARMCLK, G3D, G2D, MFC, and ONEDRAM (and only CPUFREQ should have the control). As soon as clock framework is settled, we may update source clocks (.parent field) of those clocks accordingly later.

--
v2:
- Ramp-up delay is removed. (let regulator framework do the job)
- Provide proper max values for regulator_set_voltage
- Removed unneccesary #ifdef's.
- Removed unnecessary initialiser for CLK_OUT

---
 arch/arm/Kconfig                              |    1 +
 arch/arm/mach-s5pv210/Makefile                |    3 +
 arch/arm/mach-s5pv210/cpufreq-s5pv210.c       |  776 +++++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h |   50 ++
 4 files changed, 830 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq-s5pv210.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h
arch/arm/Kconfig +1 -0
index 98922f7..d5a5916 100644
@@ -701,6 +701,7 @@ config ARCH_S5PV210
 	select HAVE_CLK
 	select ARM_L1_CACHE_SHIFT_6
 	select ARCH_USES_GETTIMEOFFSET
+	select ARCH_HAS_CPUFREQ
 	help
 	  Samsung S5PV210/S5PC110 series based systems
 
arch/arm/mach-s5pv210/Makefile +3 -0
index aae592a..293dbac 100644
@@ -34,3 +34,6 @@ obj-$(CONFIG_S5PV210_SETUP_I2C2) 	+= setup-i2c2.o
 obj-$(CONFIG_S5PV210_SETUP_KEYPAD)	+= setup-keypad.o
 obj-$(CONFIG_S5PV210_SETUP_SDHCI)       += setup-sdhci.o
 obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o
+
+# CPUFREQ (DVFS)
+obj-$(CONFIG_CPU_FREQ)		+= cpufreq-s5pv210.o
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +53 -0
new file mode 100644
index 0000000..82ec31b
@@ -0,0 +1,776 @@
+/*  linux/arch/arm/plat-s5pc11x/s5pc11x-cpufreq.c
+ *
+ *  Copyright (C) 2010 Samsung Electronics Co., Ltd.
+ *
+ *  CPU frequency scaling for S5PC110
+ *  Based on cpu-sa1110.c
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <asm/system.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+#include <mach/cpu-freq.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/pll.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <plat/regs-fb.h>
+#ifdef CONFIG_PM
+#include <plat/pm.h>
+#endif
+
+static struct clk *mpu_clk;
+static struct regulator *arm_regulator;
+static struct regulator *internal_regulator;
+
+struct s3c_cpufreq_freqs s3c_freqs;
+
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+#define	CPUFREQ_DISABLE_1GHZ
+#endif
+/* #define	CPUFREQ_DISABLE_100MHZ */
+
+static unsigned long previous_arm_volt;
+
+/* frequency */
+static struct cpufreq_frequency_table s5pv210_freq_table[] = {

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 63

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+	{L0, 1000*1000},
+	{L1, 800*1000},
+	{L2, 400*1000},
+	{L3, 200*1000},
+	{L4, 100*1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+struct s5pc11x_dvs_conf {
+	const unsigned long lvl;        /* DVFS level : L0,L1,L2,L3... */

Why add this when you don't use it? You could use the level as the lookup key instead.

Quoted 356 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +356 -0
+	unsigned long       arm_volt;   /* uV */
+	unsigned long       int_volt;   /* uV */
+};
+
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+const unsigned long arm_volt_max = 1350000;
+const unsigned long int_volt_max = 1250000;
+#else
+const unsigned long arm_volt_max = 1300000;
+const unsigned long int_volt_max = 1200000;
+#endif
+
+static struct s5pc11x_dvs_conf s5pv210_dvs_conf[] = {
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+	{
+		.lvl        = L0,
+		.arm_volt   = 1300000,
+		.int_volt   = 1200000,
+	}, {
+		.lvl        = L1,
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+
+	}, {
+		.lvl        = L2,
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+
+	}, {
+		.lvl        = L3,
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+	}, {
+		.lvl        = L4,
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+	},
+#else
+	{
+		.lvl        = L0,
+		.arm_volt   = 1250000,
+		.int_volt   = 1100000,
+	}, {
+		.lvl        = L1,
+		.arm_volt   = 1200000,
+		.int_volt   = 1100000,
+
+	}, {
+		.lvl        = L2,
+		.arm_volt   = 1050000,
+		.int_volt   = 1100000,
+
+	}, {
+		.lvl        = L3,
+		.arm_volt   = 950000,
+		.int_volt   = 1100000,
+	}, {
+		.lvl        = L4,
+		.arm_volt   = 950000,
+		.int_volt   = 1000000,
+	},
+#endif
+};
+
+static u32 clkdiv_val[5][11] = {
+	/*{ APLL, A2M, HCLK_MSYS, PCLK_MSYS,
+	 * HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS, ONEDRAM,
+	 * MFC, G3D }
+	 */
+	/* L0 : [1000/200/200/100][166/83][133/66][200/200] */
+	{0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
+	/* L1 : [800/200/200/100][166/83][133/66][200/200] */
+	{0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
+	/* L2 : [400/200/200/100][166/83][133/66][200/200] */
+	{1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
+	/* L3 : [200/200/200/100][166/83][133/66][200/200] */
+	{3, 3, 0, 1, 3, 1, 4, 1, 3, 0, 0},
+	/* L4 : [100/100/100/100][83/83][66/66][100/100] */
+	{7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
+};
+
+static struct s3c_freq s5pv210_clk_info[] = {
+	[L0] = {	/* L0: 1GHz */
+		.fclk       = 1000000,
+		.armclk     = 1000000,
+		.hclk_tns   = 0,
+		.hclk       = 133000,
+		.pclk       = 66000,
+		.hclk_msys  = 200000,
+		.pclk_msys  = 100000,
+		.hclk_dsys  = 166750,
+		.pclk_dsys  = 83375,
+	},
+	[L1] = {	/* L1: 800MHz */
+		.fclk       = 800000,
+		.armclk     = 800000,
+		.hclk_tns   = 0,
+		.hclk       = 133000,
+		.pclk       = 66000,
+		.hclk_msys  = 200000,
+		.pclk_msys  = 100000,
+		.hclk_dsys  = 166750,
+		.pclk_dsys  = 83375,
+	},
+	[L2] = {	/* L2: 400MHz */
+		.fclk       = 800000,
+		.armclk     = 400000,
+		.hclk_tns   = 0,
+		.hclk       = 133000,
+		.pclk       = 66000,
+		.hclk_msys  = 200000,
+		.pclk_msys  = 100000,
+		.hclk_dsys  = 166750,
+		.pclk_dsys  = 83375,
+	},
+	[L3] = {	/* L3: 200MHz */
+		.fclk       = 800000,
+		.armclk     = 200000,
+		.hclk_tns   = 0,
+		.hclk       = 133000,
+		.pclk       = 66000,
+		.hclk_msys  = 200000,
+		.pclk_msys  = 100000,
+		.hclk_dsys  = 166750,
+		.pclk_dsys  = 83375,
+	},
+	[L4] = {	/* L4: 100MHz */
+		.fclk       = 800000,
+		.armclk     = 100000,
+		.hclk_tns   = 0,
+		.hclk       = 66000,
+		.pclk       = 66000,
+		.hclk_msys  = 100000,
+		.pclk_msys  = 100000,
+		.hclk_dsys  = 83375,
+		.pclk_dsys  = 83375,
+	},
+};
+
+int s5pv210_verify_speed(struct cpufreq_policy *policy)
+{
+
+	if (policy->cpu)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, s5pv210_freq_table);
+}
+
+unsigned int s5pv210_getspeed(unsigned int cpu)
+{
+	unsigned long rate;
+
+	if (cpu)
+		return 0;
+
+	rate = clk_get_rate(mpu_clk) / KHZ_T;
+
+	return rate;
+}
+
+static void s5pv210_target_APLL2MPLL(unsigned int index,
+		unsigned int bus_speed_changing)
+{
+	unsigned int reg;
+
+	/* 1. Temporarily change divider for MFC and G3D
+	 * SCLKA2M(200/1=200)->(200/4=50)MHz
+	 **/
+	reg = __raw_readl(S5P_CLK_DIV2);
+	reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
+	reg |= (0x3 << S5P_CLKDIV2_G3D_SHIFT) |
+		(0x3 << S5P_CLKDIV2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+	reg &= ~S5P_CLKDIV2_G2D_MASK;
+	reg |= (0x2 << S5P_CLKDIV2_G2D_SHIFT);
+#endif
+	__raw_writel(reg, S5P_CLK_DIV2);
+
+	/* For MFC, G3D dividing */
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & ((1 << 16) | (1 << 17)));
+
+	/* 2. Change SCLKA2M(200MHz) to SCLKMPLL in MFC_MUX, G3D MUX
+	 * (100/4=50)->(667/4=166)MHz
+	 **/
+	reg = __raw_readl(S5P_CLK_SRC2);
+	reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+	reg |= (0x1 << S5P_CLKSRC2_G3D_SHIFT) |
+		(0x1 << S5P_CLKSRC2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+	reg &= ~S5P_CLKSRC2_G2D_MASK;
+	reg |= (0x1 << S5P_CLKSRC2_G2D_SHIFT);
+#endif
+	__raw_writel(reg, S5P_CLK_SRC2);
+
+	do {
+		reg = __raw_readl(S5P_CLK_MUX_STAT1);
+	} while (reg & ((1 << 7) | (1 << 3)));
+
+	/* 3. DMC1 refresh count for 133MHz if (index == L4) is true
+	 * refresh counter is already programmed in the outer/upper
+	 * code. 0x287 at 83MHz
+	 **/
+	if (!bus_speed_changing)
+		__raw_writel(0x40d, S5P_VA_DMC1 + 0x30);
+
+	/* 4. SCLKAPLL -> SCLKMPLL */
+	reg = __raw_readl(S5P_CLK_SRC0);
+	reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+	reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
+	__raw_writel(reg, S5P_CLK_SRC0);
+
+	do {
+		reg = __raw_readl(S5P_CLK_MUX_STAT0);
+	} while (reg & (0x1 << 18));
+
+#if defined(CONFIG_S5PC110_H_TYPE)
+	/* DMC0 source clock: SCLKA2M -> SCLKMPLL */
+	__raw_writel(0x50e, S5P_VA_DMC0 + 0x30);
+
+	reg = __raw_readl(S5P_CLK_DIV6);
+	reg &= ~(S5P_CLKDIV6_ONEDRAM_MASK);
+	reg |= (0x3 << S5P_CLKDIV6_ONEDRAM_SHIFT);
+	__raw_writel(reg, S5P_CLK_DIV6);
+
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT1);
+	} while (reg & (1 << 15));
+
+	reg = __raw_readl(S5P_CLK_SRC6);
+	reg &= ~(S5P_CLKSRC6_ONEDRAM_MASK);
+	reg |= (0x1 << S5P_CLKSRC6_ONEDRAM_SHIFT);
+	__raw_writel(reg, S5P_CLK_SRC6);
+
+	do {
+		reg = __raw_readl(S5P_CLK_MUX_STAT1);
+	} while (reg & (1 << 11));
+#endif
+}
+
+static void s5pv210_target_MPLL2APLL(unsigned int index,
+		unsigned int bus_speed_changing)
+{
+	unsigned int reg;
+
+	/* 7. Set Lock time = 30us*24MHz = 02cf (EVT1) */
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+	/* Lock time = 300us*24Mhz = 7200(0x1c20)*/
+	__raw_writel(0x1c20, S5P_APLL_LOCK);
+#else
+	/* Lock time = 30us*24Mhz = 0x2cf*/
+	__raw_writel(0x2cf, S5P_APLL_LOCK);
+#endif
+
+	/* 8. Turn on APLL
+	 * 8-1. Set PMS values
+	 * 8-3. Wait until the PLL is locked
+	 **/
+	if (index == L0)
+		/* APLL FOUT becomes 1000 Mhz */
+		__raw_writel(PLL45XX_APLL_VAL_1000, S5P_APLL_CON);
+	else
+		/* APLL FOUT becomes 800 Mhz */
+		__raw_writel(PLL45XX_APLL_VAL_800, S5P_APLL_CON);
+
+	do {
+		reg = __raw_readl(S5P_APLL_CON);
+	} while (!(reg & (0x1 << 29)));
+
+	/* 9. Change source clock from SCLKMPLL(667MHz)
+	 * to SCLKA2M(200MHz) in MFC_MUX and G3D_MUX
+	 * (667/4=166)->(200/4=50)MHz
+	 **/
+	reg = __raw_readl(S5P_CLK_SRC2);
+	reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+	reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) | (0 << S5P_CLKSRC2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+	reg &= ~S5P_CLKSRC2_G2D_MASK;
+	reg |= 0x1 << S5P_CLKSRC2_G2D_SHIFT;
+#endif
+	__raw_writel(reg, S5P_CLK_SRC2);
+
+	do {
+		reg = __raw_readl(S5P_CLK_MUX_STAT1);
+	} while (reg & ((1 << 7) | (1 << 3)));
+
+	/* 10. Change divider for MFC and G3D
+	 * (200/4=50)->(200/1=200)MHz
+	 **/
+	reg = __raw_readl(S5P_CLK_DIV2);
+	reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
+	reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
+		(clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+	reg &= ~S5P_CLKDIV2_G2D_MASK;
+	reg |= 0x2 << S5P_CLKDIV2_G2D_SHIFT;
+#endif
+	__raw_writel(reg, S5P_CLK_DIV2);
+
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & ((1 << 16) | (1 << 17)));
+
+	/* 11. Change MPLL to APLL in MSYS_MUX */
+	reg = __raw_readl(S5P_CLK_SRC0);
+	reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+	reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT); /* SCLKMPLL -> SCLKAPLL   */
+	__raw_writel(reg, S5P_CLK_SRC0);
+
+	do {
+		reg = __raw_readl(S5P_CLK_MUX_STAT0);
+	} while (reg & (0x1 << 18));
+
+	/* 12. DMC1 refresh counter
+	 * L4: DMC1 = 100MHz 7.8us/(1/100) = 0x30c
+	 * Others: DMC1 = 200MHz 7.8us/(1/200) = 0x618
+	 **/
+	if (!bus_speed_changing)
+		__raw_writel(0x618, S5P_VA_DMC1 + 0x30);
+
+#if defined(CONFIG_S5PC110_H_TYPE)
+	/* DMC0 source clock: SCLKMPLL -> SCLKA2M */
+	reg = __raw_readl(S5P_CLK_SRC6);
+	reg &= ~(S5P_CLKSRC6_ONEDRAM_MASK);
+	reg |= (0x0 << S5P_CLKSRC6_ONEDRAM_SHIFT);
+	__raw_writel(reg, S5P_CLK_SRC6);
+
+	do {
+		reg = __raw_readl(S5P_CLK_MUX_STAT1);
+	} while (reg & (1 << 11));
+
+	reg = __raw_readl(S5P_CLK_DIC6);
+	reg &= ~(S5P_CLKDIV6_ONEDRAM_MASK);
+	reg |= (0x0 << S5P_CLKDIV6_ONEDRAM_SHIFT);
+	__raw_writel(reg, S5P_CLK_DIV6);
+
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT1);
+	} while (reg & (1 << 15));
+	__raw_writel(0x618, S5P_VA_DMC0 + 0x30);
+#endif
+}
+
+#ifdef CONFIG_PM
+static int no_cpufreq_access;
+/* s5pv210_target: relation has an additional symantics other than
+ * the standard
+ * [0x30]:
+ *	1: disable further access to target until being re-enabled.
+ *	2: re-enable access to target */
+#endif
+static int s5pv210_target(struct cpufreq_policy *policy,
+		unsigned int target_freq,
+		unsigned int relation)
+{

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 429

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+	static int initialized;
+	int ret = 0;
+	unsigned long arm_clk;
+	unsigned int index, reg, arm_volt, int_volt;
+	unsigned int pll_changing = 0;
+	unsigned int bus_speed_changing = 0;
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+	printk(KERN_INFO "cpufreq: Entering for %dkHz\n", target_freq);
+#endif

cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, <prefix>, ...)

Quoted 6 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +6 -0
+#ifdef CONFIG_PM
+	if ((relation & ENABLE_FURTHER_CPUFREQ) &&
+			(relation & DISABLE_FURTHER_CPUFREQ)) {
+		/* Invalidate both if both marked */
+		relation &= ~ENABLE_FURTHER_CPUFREQ;
+		relation &= ~DISABLE_FURTHER_CPUFREQ;

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 445

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+		printk(KERN_ERR "%s:%d denied marking \"FURTHER_CPUFREQ\""
+				" as both marked.\n",
+				__FILE__, __LINE__);
+	}
+	if (relation & ENABLE_FURTHER_CPUFREQ)
+		no_cpufreq_access = 0;
+	if (no_cpufreq_access == 1) {
+#ifdef CONFIG_PM_VERBOSE
+		printk(KERN_ERR "%s:%d denied access to %s as it is disabled"
+			       " temporarily\n", __FILE__, __LINE__, __func__);

Use pr_err(...)

Quoted 164 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +164 -0
+#endif
+		ret = -EINVAL;
+		goto out;
+	}
+	if (relation & DISABLE_FURTHER_CPUFREQ)
+		no_cpufreq_access = 1;
+	relation &= ~MASK_FURTHER_CPUFREQ;
+#endif
+
+	s3c_freqs.freqs.old = s5pv210_getspeed(0);
+
+	if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
+				target_freq, relation, &index)) {
+		ret = -EINVAL;
+		goto out;
+	}
+#ifdef CPUFREQ_DISABLE_100MHZ
+	if (index == L4)
+		index = L3;
+#endif
+#ifdef CPUFREQ_DISABLE_1GHZ
+	if (index == L0)
+		index = L1;
+#endif
+
+	arm_clk = s5pv210_freq_table[index].frequency;
+
+	s3c_freqs.freqs.new = arm_clk;
+	s3c_freqs.freqs.cpu = 0;
+
+	if (s3c_freqs.freqs.new == s3c_freqs.freqs.old &&
+			initialized >= 2)
+		return 0;
+	else if (initialized < 2)
+		initialized++;
+
+	arm_volt = s5pv210_dvs_conf[index].arm_volt;
+	int_volt = s5pv210_dvs_conf[index].int_volt;
+
+	/* iNew clock information update */
+	memcpy(&s3c_freqs.new, &s5pv210_clk_info[index],
+			sizeof(struct s3c_freq));
+
+	if (s3c_freqs.freqs.new >= s3c_freqs.freqs.old) {
+		/* Voltage up code: increase ARM first */
+		if (!IS_ERR_OR_NULL(arm_regulator) &&
+				!IS_ERR_OR_NULL(internal_regulator)) {
+			regulator_set_voltage(arm_regulator,
+					arm_volt, arm_volt_max);
+			regulator_set_voltage(internal_regulator,
+					int_volt, int_volt_max);
+		}
+	}
+	cpufreq_notify_transition(&s3c_freqs.freqs, CPUFREQ_PRECHANGE);
+
+	if (s3c_freqs.new.fclk != s3c_freqs.old.fclk || initialized < 2)
+		pll_changing = 1;
+
+	if (s3c_freqs.new.hclk_msys != s3c_freqs.old.hclk_msys ||
+			initialized < 2)
+		bus_speed_changing = 1;
+
+	if (bus_speed_changing) {
+		/* Reconfigure DRAM refresh counter value for minimum
+		 * temporary clock while changing divider.
+		 * expected clock is 83MHz: 7.8usec/(1/83MHz) = 0x287
+		 **/
+		if (pll_changing)
+			__raw_writel(0x287, S5P_VA_DMC1 + 0x30);
+		else
+			__raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
+
+		__raw_writel(0x287, S5P_VA_DMC0 + 0x30);
+	}
+
+	/* APLL should be changed in this level
+	 * APLL -> MPLL(for stable transition) -> APLL
+	 * Some clock source's clock API  are not prepared. Do not use clock API
+	 * in below code.
+	 */
+	if (pll_changing)
+		s5pv210_target_APLL2MPLL(index, bus_speed_changing);
+
+	/* ARM MCS value changed */
+	if (index != L4) {
+		reg = __raw_readl(S5P_ARM_MCS_CON);
+		reg &= ~0x3;
+		reg |= 0x1;
+		__raw_writel(reg, S5P_ARM_MCS_CON);
+	}
+
+	reg = __raw_readl(S5P_CLK_DIV0);
+
+	reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK
+			| S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK
+			| S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK
+			| S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK);
+
+	reg |= ((clkdiv_val[index][0]<<S5P_CLKDIV0_APLL_SHIFT)
+			| (clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT)
+			| (clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT)
+			| (clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT)
+			| (clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT)
+			| (clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT)
+			| (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT)
+			| (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
+
+	__raw_writel(reg, S5P_CLK_DIV0);
+
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & 0xff);
+
+	/* ARM MCS value changed */
+	if (index == L4) {
+		reg = __raw_readl(S5P_ARM_MCS_CON);
+		reg &= ~0x3;
+		reg |= 0x3;
+		__raw_writel(reg, S5P_ARM_MCS_CON);
+	}
+
+	if (pll_changing)
+		s5pv210_target_MPLL2APLL(index, bus_speed_changing);
+
+	/* L4 level need to change memory bus speed,
+	 * hence onedram clock divier and
+	 * memory refresh parameter should be changed
+	 */
+	if (bus_speed_changing) {
+		reg = __raw_readl(S5P_CLK_DIV6);
+		reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
+		reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
+		/* ONEDRAM Clock Divider Ratio: 7 for L4, 3 for Others */
+		__raw_writel(reg, S5P_CLK_DIV6);
+
+		do {
+			reg = __raw_readl(S5P_CLK_DIV_STAT1);
+		} while (reg & (1 << 15));
+
+		/* Reconfigure DRAM refresh counter value */
+		if (index != L4) {
+			/* DMC0: 166MHz
+			 * DMC1: 200MHz
+			 **/
+			__raw_writel(0x618, S5P_VA_DMC1 + 0x30);
+#if !defined(CONFIG_S5PC110_H_TYPE)
+			__raw_writel(0x50e, S5P_VA_DMC0 + 0x30);
+#else
+			__raw_writel(0x618, S5P_VA_DMC0 + 0x30);
+#endif
+		} else {
+			/* DMC0: 83MHz
+			 * DMC1: 100MHz
+			 **/
+			__raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
+			__raw_writel(0x287, S5P_VA_DMC0 + 0x30);
+		}
+	}
+
+	if (s3c_freqs.freqs.new < s3c_freqs.freqs.old) {
+		/* Voltage down: decrease INT first.*/
+		if (!IS_ERR_OR_NULL(arm_regulator) &&
+				!IS_ERR_OR_NULL(internal_regulator)) {
+			regulator_set_voltage(internal_regulator,

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 619

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+					int_volt, int_volt_max);
+			regulator_set_voltage(arm_regulator,
+					arm_volt, arm_volt_max);
+		}
+	}
+	cpufreq_notify_transition(&s3c_freqs.freqs, CPUFREQ_POSTCHANGE);
+
+	memcpy(&s3c_freqs.old, &s3c_freqs.new, sizeof(struct s3c_freq));
+#ifdef CONFIG_CPU_FREQ_DEBUG
+	printk(KERN_INFO "cpufreq: Performance changed[L%d]\n", index);

pr_info

Quoted 5 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +5 -0
+#endif
+	previous_arm_volt = s5pv210_dvs_conf[index].arm_volt;
+out:
+	return ret;
+}

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 634

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+
+
+#ifdef CONFIG_PM
+static int previous_frequency;
+
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
+		pm_message_t pmsg)
+{
+	int ret = 0;
+	printk(KERN_INFO "cpufreq: Entering suspend.\n");

pr_info

Quoted 5 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +5 -0
+
+	previous_frequency = cpufreq_get(0);
+	ret = __cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+			DISABLE_FURTHER_CPUFREQ);
+	return ret;

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 649

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+}
+
+static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
+{
+	int ret = 0;
+	u32 rate;
+	int level = CPUFREQ_TABLE_END;
+	int i;
+
+	printk(KERN_INFO "cpufreq: Waking up from a suspend.\n");

pr_info

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+
+	__cpufreq_driver_target(cpufreq_cpu_get(0), previous_frequency,
+			ENABLE_FURTHER_CPUFREQ);
+
+	/* Clock information update with wakeup value */
+	rate = clk_get_rate(mpu_clk);
+
+	i = 0;
+	while (s5pv210_freq_table[i].frequency != CPUFREQ_TABLE_END) {
+		if (s5pv210_freq_table[i].frequency * 1000 == rate) {

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 669

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+			level = s5pv210_freq_table[i].index;
+			break;
+		}
+		i++;
+	}
+
+	if (level == CPUFREQ_TABLE_END) { /* Not found */
+		printk(KERN_ERR "[%s:%d] clock speed does not match: "
+				"%d. Using L1 of 800MHz.\n",
+				__FILE__, __LINE__, rate);

pr_err

Quoted 7 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +7 -0
+		level = L1;
+	}
+
+	memcpy(&s3c_freqs.old, &s5pv210_clk_info[level],
+			sizeof(struct s3c_freq));
+	previous_arm_volt = s5pv210_dvs_conf[level].arm_volt;
+	return ret;

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 686

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+}
+#endif
+
+
+static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
+{
+	u32 rate ;
+	int i, level = CPUFREQ_TABLE_END;
+
+	printk(KERN_INFO "S5PV210 CPUFREQ %s:%d\n", __FILE__, __LINE__);

pr_info

Quoted 4 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +4 -0
+#ifdef CONFIG_PM
+	no_cpufreq_access = 0;
+#endif
+#ifdef CLK_OUT_PROBING

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 700

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+	reg = __raw_readl(S5P_CLK_OUT);
+	reg &= ~(0x1f << 12 | 0xf << 20); /* CLKSEL and DIVVAL*/
+	reg |= (0xf << 12 | 0x1 << 20); /* CLKSEL = ARMCLK/4, DIVVAL = 1 */
+	/* Result = ARMCLK / 4 / ( 1 + 1 ) */
+	__raw_writel(reg, S5P_CLK_OUT);
+#endif
+	mpu_clk = clk_get(NULL, MPU_CLK);
+	if (IS_ERR(mpu_clk)) {
+		printk(KERN_ERR "S5PV210 CPUFREQ cannot get MPU_CLK(%s)\n",
+				MPU_CLK);

pr_err

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 706

Quoted 6 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +6 -0
+		return PTR_ERR(mpu_clk);
+	}
+
+	if (policy->cpu != 0) {
+		printk(KERN_ERR "S5PV210 CPUFREQ cannot get proper cpu(%d)\n",
+				policy->cpu);

pr_err

Quoted 17 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +17 -0
+		return -EINVAL;
+	}
+	policy->cur = policy->min = policy->max = s5pv210_getspeed(0);
+
+	cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu);
+
+	policy->cpuinfo.transition_latency = 40000;	/*1us*/
+
+	rate = clk_get_rate(mpu_clk);
+	i = 0;
+
+	while (s5pv210_freq_table[i].frequency != CPUFREQ_TABLE_END) {
+		if (s5pv210_freq_table[i].frequency * 1000 == rate) {
+			level = s5pv210_freq_table[i].index;
+			break;
+		}
+		i++;

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 733

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+	}
+
+	if (level == CPUFREQ_TABLE_END) { /* Not found */
+		printk(KERN_ERR "[%s:%d] clock speed does not match: "
+				"%d. Using L1 of 800MHz.\n",
+				__FILE__, __LINE__, rate);
+		level = L1;
+	}
+
+	printk(KERN_INFO "S5PV210 CPUFREQ Initialized.\n");

pr_info

Quoted 14 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +14 -0
+
+	memcpy(&s3c_freqs.old, &s5pv210_clk_info[level],
+			sizeof(struct s3c_freq));
+	previous_arm_volt = s5pv210_dvs_conf[level].arm_volt;
+
+	return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table);
+}
+
+static struct cpufreq_driver s5pv210_driver = {
+	.flags		= CPUFREQ_STICKY,
+	.verify		= s5pv210_verify_speed,
+	.target		= s5pv210_target,
+	.get		= s5pv210_getspeed,
+	.init		= s5pv210_cpu_init,

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 757

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+	.name		= "s5pv210",
+#ifdef CONFIG_PM
+	.suspend	= s5pv210_cpufreq_suspend,
+	.resume		= s5pv210_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv210_cpufreq_init(void)
+{
+	printk(KERN_INFO "S5PV210 CPUFREQ Init.\n");

pr_info
Also, I guess one banner is enough?

Quoted 4 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +4 -0
+	arm_regulator = regulator_get_exclusive(NULL, "vddarm");
+	if (IS_ERR(arm_regulator)) {
+		printk(KERN_ERR "failed to get regulater resource vddarm\n");
+		goto error;

arch/arm/mach-s5pv210/cpufreq-s5pv210.c line 771

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+	}
+	internal_regulator = regulator_get_exclusive(NULL, "vddint");
+	if (IS_ERR(internal_regulator)) {
+		printk(KERN_ERR "failed to get regulater resource vddint\n");
+		goto error;
+	}
+	goto finish;
+error:
+	printk(KERN_WARNING "Cannot get vddarm or vddint. CPUFREQ Will not"
+		       " change the voltage.\n");

pr_warn

Quoted 61 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +5 -0
+finish:
+	return cpufreq_register_driver(&s5pv210_driver);
+}
+
+late_initcall(s5pv210_cpufreq_init);
arch/arm/mach-s5pv210/include/mach/cpu-freq.h new file +50 -0
new file mode 100644
index 0000000..d3c31b2
@@ -0,0 +1,50 @@
+/* arch/arm/mach-s5pv210/include/mach/cpu-freq.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * 	MyungJoo Ham <[email protected]>
+ *
+ * S5PV210/S5PC110 CPU frequency scaling support
+ *
+ * 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.
+*/
+
+#ifndef _ARCH_ARM_MACH_S5PV210_INCLUDE_MACH_CPU_FREQ_H_
+#define _ARCH_ARM_MACH_S5PV210_INCLUDE_MACH_CPU_FREQ_H_
+
+#include <linux/cpufreq.h>
+
+#ifdef CONFIG_CPU_S5PV210
+
+#define USE_FREQ_TABLE
+
+#define KHZ_T           1000
+
+#define MPU_CLK         "armclk"
+
+enum perf_level {
+	L0 = 0,
+	L1,
+	L2,
+	L3,
+	L4,
+};
+
+#define CLK_DIV0_MASK   ((0x7<<0)|(0x7<<8)|(0x7<<12))   /* APLL,HCLK_MSYS,PCLK_MSYS mask value  */
+
+#ifdef CONFIG_PM
+#define SLEEP_FREQ      (800 * 1000) /* Use 800MHz when entering sleep */
+
+/* additional symantics for "relation" in cpufreq with pm */
+#define DISABLE_FURTHER_CPUFREQ         0x10
+#define ENABLE_FURTHER_CPUFREQ          0x20
+#define MASK_FURTHER_CPUFREQ            0x30
+/* With 0x00(NOCHANGE), it depends on the previous "further" status */
+
+#endif
+
+
+#endif /* CONFIG_CPU_S5PV210 */
+#endif /* _ARCH_ARM_MACH_S5PV210_INCLUDE_MACH_CPU_FREQ_H_ */
Signature · 1 line
Maurus Cuelenaere
#8 lore raw

PATCH v2 5/5 ARM: S5PV210: Initial CPUFREQ Support

Quoted 34 lines · Maurus Cuelenaere

?Op 16-07-10 10:01, MyungJoo Ham schreef:

Quoted 33 lines

S5PV210 CPUFREQ Support.

This CPUFREQ may work without PMIC's DVS support. However, it is not as effective without DVS support as supposed. AVS is not supported in this version.

Note that CLK_SRC of some clocks including ARMCLK, G3D, G2D, MFC, and ONEDRAM are modified directly without updating clksrc_src representations of the clocks. ?Because CPUFREQ reverts the CLK_SRC to the supposed values, this does not affect the consistency as long as there are no other modules that modifies clock sources of ARMCLK, G3D, G2D, MFC, and ONEDRAM (and only CPUFREQ should have the control). As soon as clock framework is settled, we may update source clocks (.parent field) of those clocks accordingly later.

--
v2:
? ? ? - Ramp-up delay is removed. (let regulator framework do the job) ? ? ? - Provide proper max values for regulator_set_voltage ? ? ? - Removed unneccesary #ifdef's.
? ? ? - Removed unnecessary initialiser for CLK_OUT

---

?arch/arm/Kconfig ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ?1 +
?arch/arm/mach-s5pv210/Makefile ? ? ? ? ? ? ? ?| ? ?3 +
?arch/arm/mach-s5pv210/cpufreq-s5pv210.c ? ? ? | ?776 +++++++++++++++++++++++++
?arch/arm/mach-s5pv210/include/mach/cpu-freq.h | ? 50 ++

?4 files changed, 830 insertions(+), 0 deletions(-) ?create mode 100644 arch/arm/mach-s5pv210/cpufreq-s5pv210.c ?create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h

(snip)

Quoted 6 lines

arch/arm/mach-s5pv210/cpufreq-s5pv210.c

Quoted 3 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +3 -0
+
+struct s5pc11x_dvs_conf {
+ ? ? const unsigned long lvl; ? ? ? ?/* DVFS level : L0,L1,L2,L3... */

Why add this when you don't use it? You could use the level as the lookup key instead.

Thank you for pointing out. I'll correct them (including pr_* and duplicated info messages) in the next version of patches.

Quoted 811 lines
Quoted 356 lines

+ ? ? unsigned long ? ? ? arm_volt; ? /* uV */
+ ? ? unsigned long ? ? ? int_volt; ? /* uV */

(quoted diff) +354 -0
+};
+
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+const unsigned long arm_volt_max = 1350000;
+const unsigned long int_volt_max = 1250000;
+#else
+const unsigned long arm_volt_max = 1300000;
+const unsigned long int_volt_max = 1200000;
+#endif
+
+static struct s5pc11x_dvs_conf s5pv210_dvs_conf[] = {
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+ ? ? {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L0,
+ ? ? ? ? ? ? .arm_volt ? = 1300000,
+ ? ? ? ? ? ? .int_volt ? = 1200000,
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L1,
+ ? ? ? ? ? ? .arm_volt ? = 1250000,
+ ? ? ? ? ? ? .int_volt ? = 1200000,
+
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L2,
+ ? ? ? ? ? ? .arm_volt ? = 1250000,
+ ? ? ? ? ? ? .int_volt ? = 1200000,
+
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L3,
+ ? ? ? ? ? ? .arm_volt ? = 1250000,
+ ? ? ? ? ? ? .int_volt ? = 1200000,
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L4,
+ ? ? ? ? ? ? .arm_volt ? = 1250000,
+ ? ? ? ? ? ? .int_volt ? = 1200000,
+ ? ? },
+#else
+ ? ? {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L0,
+ ? ? ? ? ? ? .arm_volt ? = 1250000,
+ ? ? ? ? ? ? .int_volt ? = 1100000,
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L1,
+ ? ? ? ? ? ? .arm_volt ? = 1200000,
+ ? ? ? ? ? ? .int_volt ? = 1100000,
+
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L2,
+ ? ? ? ? ? ? .arm_volt ? = 1050000,
+ ? ? ? ? ? ? .int_volt ? = 1100000,
+
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L3,
+ ? ? ? ? ? ? .arm_volt ? = 950000,
+ ? ? ? ? ? ? .int_volt ? = 1100000,
+ ? ? }, {
+ ? ? ? ? ? ? .lvl ? ? ? ?= L4,
+ ? ? ? ? ? ? .arm_volt ? = 950000,
+ ? ? ? ? ? ? .int_volt ? = 1000000,
+ ? ? },
+#endif
+};
+
+static u32 clkdiv_val[5][11] = {
+ ? ? /*{ APLL, A2M, HCLK_MSYS, PCLK_MSYS,
+ ? ? ?* HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS, ONEDRAM,
+ ? ? ?* MFC, G3D }
+ ? ? ?*/
+ ? ? /* L0 : [1000/200/200/100][166/83][133/66][200/200] */
+ ? ? {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
+ ? ? /* L1 : [800/200/200/100][166/83][133/66][200/200] */
+ ? ? {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
+ ? ? /* L2 : [400/200/200/100][166/83][133/66][200/200] */
+ ? ? {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
+ ? ? /* L3 : [200/200/200/100][166/83][133/66][200/200] */
+ ? ? {3, 3, 0, 1, 3, 1, 4, 1, 3, 0, 0},
+ ? ? /* L4 : [100/100/100/100][83/83][66/66][100/100] */
+ ? ? {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
+};
+
+static struct s3c_freq s5pv210_clk_info[] = {
+ ? ? [L0] = { ? ? ? ?/* L0: 1GHz */
+ ? ? ? ? ? ? .fclk ? ? ? = 1000000,
+ ? ? ? ? ? ? .armclk ? ? = 1000000,
+ ? ? ? ? ? ? .hclk_tns ? = 0,
+ ? ? ? ? ? ? .hclk ? ? ? = 133000,
+ ? ? ? ? ? ? .pclk ? ? ? = 66000,
+ ? ? ? ? ? ? .hclk_msys ?= 200000,
+ ? ? ? ? ? ? .pclk_msys ?= 100000,
+ ? ? ? ? ? ? .hclk_dsys ?= 166750,
+ ? ? ? ? ? ? .pclk_dsys ?= 83375,
+ ? ? },
+ ? ? [L1] = { ? ? ? ?/* L1: 800MHz */
+ ? ? ? ? ? ? .fclk ? ? ? = 800000,
+ ? ? ? ? ? ? .armclk ? ? = 800000,
+ ? ? ? ? ? ? .hclk_tns ? = 0,
+ ? ? ? ? ? ? .hclk ? ? ? = 133000,
+ ? ? ? ? ? ? .pclk ? ? ? = 66000,
+ ? ? ? ? ? ? .hclk_msys ?= 200000,
+ ? ? ? ? ? ? .pclk_msys ?= 100000,
+ ? ? ? ? ? ? .hclk_dsys ?= 166750,
+ ? ? ? ? ? ? .pclk_dsys ?= 83375,
+ ? ? },
+ ? ? [L2] = { ? ? ? ?/* L2: 400MHz */
+ ? ? ? ? ? ? .fclk ? ? ? = 800000,
+ ? ? ? ? ? ? .armclk ? ? = 400000,
+ ? ? ? ? ? ? .hclk_tns ? = 0,
+ ? ? ? ? ? ? .hclk ? ? ? = 133000,
+ ? ? ? ? ? ? .pclk ? ? ? = 66000,
+ ? ? ? ? ? ? .hclk_msys ?= 200000,
+ ? ? ? ? ? ? .pclk_msys ?= 100000,
+ ? ? ? ? ? ? .hclk_dsys ?= 166750,
+ ? ? ? ? ? ? .pclk_dsys ?= 83375,
+ ? ? },
+ ? ? [L3] = { ? ? ? ?/* L3: 200MHz */
+ ? ? ? ? ? ? .fclk ? ? ? = 800000,
+ ? ? ? ? ? ? .armclk ? ? = 200000,
+ ? ? ? ? ? ? .hclk_tns ? = 0,
+ ? ? ? ? ? ? .hclk ? ? ? = 133000,
+ ? ? ? ? ? ? .pclk ? ? ? = 66000,
+ ? ? ? ? ? ? .hclk_msys ?= 200000,
+ ? ? ? ? ? ? .pclk_msys ?= 100000,
+ ? ? ? ? ? ? .hclk_dsys ?= 166750,
+ ? ? ? ? ? ? .pclk_dsys ?= 83375,
+ ? ? },
+ ? ? [L4] = { ? ? ? ?/* L4: 100MHz */
+ ? ? ? ? ? ? .fclk ? ? ? = 800000,
+ ? ? ? ? ? ? .armclk ? ? = 100000,
+ ? ? ? ? ? ? .hclk_tns ? = 0,
+ ? ? ? ? ? ? .hclk ? ? ? = 66000,
+ ? ? ? ? ? ? .pclk ? ? ? = 66000,
+ ? ? ? ? ? ? .hclk_msys ?= 100000,
+ ? ? ? ? ? ? .pclk_msys ?= 100000,
+ ? ? ? ? ? ? .hclk_dsys ?= 83375,
+ ? ? ? ? ? ? .pclk_dsys ?= 83375,
+ ? ? },
+};
+
+int s5pv210_verify_speed(struct cpufreq_policy *policy)
+{
+
+ ? ? if (policy->cpu)
+ ? ? ? ? ? ? return -EINVAL;
+
+ ? ? return cpufreq_frequency_table_verify(policy, s5pv210_freq_table);
+}
+
+unsigned int s5pv210_getspeed(unsigned int cpu)
+{
+ ? ? unsigned long rate;
+
+ ? ? if (cpu)
+ ? ? ? ? ? ? return 0;
+
+ ? ? rate = clk_get_rate(mpu_clk) / KHZ_T;
+
+ ? ? return rate;
+}
+
+static void s5pv210_target_APLL2MPLL(unsigned int index,
+ ? ? ? ? ? ? unsigned int bus_speed_changing)
+{
+ ? ? unsigned int reg;
+
+ ? ? /* 1. Temporarily change divider for MFC and G3D
+ ? ? ?* SCLKA2M(200/1=200)->(200/4=50)MHz
+ ? ? ?**/
+ ? ? reg = __raw_readl(S5P_CLK_DIV2);
+ ? ? reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
+ ? ? reg |= (0x3 << S5P_CLKDIV2_G3D_SHIFT) |
+ ? ? ? ? ? ? (0x3 << S5P_CLKDIV2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+ ? ? reg &= ~S5P_CLKDIV2_G2D_MASK;
+ ? ? reg |= (0x2 << S5P_CLKDIV2_G2D_SHIFT);
+#endif
+ ? ? __raw_writel(reg, S5P_CLK_DIV2);
+
+ ? ? /* For MFC, G3D dividing */
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV_STAT0);
+ ? ? } while (reg & ((1 << 16) | (1 << 17)));
+
+ ? ? /* 2. Change SCLKA2M(200MHz) to SCLKMPLL in MFC_MUX, G3D MUX
+ ? ? ?* (100/4=50)->(667/4=166)MHz
+ ? ? ?**/
+ ? ? reg = __raw_readl(S5P_CLK_SRC2);
+ ? ? reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+ ? ? reg |= (0x1 << S5P_CLKSRC2_G3D_SHIFT) |
+ ? ? ? ? ? ? (0x1 << S5P_CLKSRC2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+ ? ? reg &= ~S5P_CLKSRC2_G2D_MASK;
+ ? ? reg |= (0x1 << S5P_CLKSRC2_G2D_SHIFT);
+#endif
+ ? ? __raw_writel(reg, S5P_CLK_SRC2);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_MUX_STAT1);
+ ? ? } while (reg & ((1 << 7) | (1 << 3)));
+
+ ? ? /* 3. DMC1 refresh count for 133MHz if (index == L4) is true
+ ? ? ?* refresh counter is already programmed in the outer/upper
+ ? ? ?* code. 0x287 at 83MHz
+ ? ? ?**/
+ ? ? if (!bus_speed_changing)
+ ? ? ? ? ? ? __raw_writel(0x40d, S5P_VA_DMC1 + 0x30);
+
+ ? ? /* 4. SCLKAPLL -> SCLKMPLL */
+ ? ? reg = __raw_readl(S5P_CLK_SRC0);
+ ? ? reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+ ? ? reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
+ ? ? __raw_writel(reg, S5P_CLK_SRC0);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_MUX_STAT0);
+ ? ? } while (reg & (0x1 << 18));
+
+#if defined(CONFIG_S5PC110_H_TYPE)
+ ? ? /* DMC0 source clock: SCLKA2M -> SCLKMPLL */
+ ? ? __raw_writel(0x50e, S5P_VA_DMC0 + 0x30);
+
+ ? ? reg = __raw_readl(S5P_CLK_DIV6);
+ ? ? reg &= ~(S5P_CLKDIV6_ONEDRAM_MASK);
+ ? ? reg |= (0x3 << S5P_CLKDIV6_ONEDRAM_SHIFT);
+ ? ? __raw_writel(reg, S5P_CLK_DIV6);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV_STAT1);
+ ? ? } while (reg & (1 << 15));
+
+ ? ? reg = __raw_readl(S5P_CLK_SRC6);
+ ? ? reg &= ~(S5P_CLKSRC6_ONEDRAM_MASK);
+ ? ? reg |= (0x1 << S5P_CLKSRC6_ONEDRAM_SHIFT);
+ ? ? __raw_writel(reg, S5P_CLK_SRC6);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_MUX_STAT1);
+ ? ? } while (reg & (1 << 11));
+#endif
+}
+
+static void s5pv210_target_MPLL2APLL(unsigned int index,
+ ? ? ? ? ? ? unsigned int bus_speed_changing)
+{
+ ? ? unsigned int reg;
+
+ ? ? /* 7. Set Lock time = 30us*24MHz = 02cf (EVT1) */
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+ ? ? /* Lock time = 300us*24Mhz = 7200(0x1c20)*/
+ ? ? __raw_writel(0x1c20, S5P_APLL_LOCK);
+#else
+ ? ? /* Lock time = 30us*24Mhz = 0x2cf*/
+ ? ? __raw_writel(0x2cf, S5P_APLL_LOCK);
+#endif
+
+ ? ? /* 8. Turn on APLL
+ ? ? ?* 8-1. Set PMS values
+ ? ? ?* 8-3. Wait until the PLL is locked
+ ? ? ?**/
+ ? ? if (index == L0)
+ ? ? ? ? ? ? /* APLL FOUT becomes 1000 Mhz */
+ ? ? ? ? ? ? __raw_writel(PLL45XX_APLL_VAL_1000, S5P_APLL_CON);
+ ? ? else
+ ? ? ? ? ? ? /* APLL FOUT becomes 800 Mhz */
+ ? ? ? ? ? ? __raw_writel(PLL45XX_APLL_VAL_800, S5P_APLL_CON);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_APLL_CON);
+ ? ? } while (!(reg & (0x1 << 29)));
+
+ ? ? /* 9. Change source clock from SCLKMPLL(667MHz)
+ ? ? ?* to SCLKA2M(200MHz) in MFC_MUX and G3D_MUX
+ ? ? ?* (667/4=166)->(200/4=50)MHz
+ ? ? ?**/
+ ? ? reg = __raw_readl(S5P_CLK_SRC2);
+ ? ? reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+ ? ? reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) | (0 << S5P_CLKSRC2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+ ? ? reg &= ~S5P_CLKSRC2_G2D_MASK;
+ ? ? reg |= 0x1 << S5P_CLKSRC2_G2D_SHIFT;
+#endif
+ ? ? __raw_writel(reg, S5P_CLK_SRC2);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_MUX_STAT1);
+ ? ? } while (reg & ((1 << 7) | (1 << 3)));
+
+ ? ? /* 10. Change divider for MFC and G3D
+ ? ? ?* (200/4=50)->(200/1=200)MHz
+ ? ? ?**/
+ ? ? reg = __raw_readl(S5P_CLK_DIV2);
+ ? ? reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
+ ? ? reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
+ ? ? ? ? ? ? (clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
+#ifndef CONFIG_CPU_S5PC110_EVT0_ERRATA
+ ? ? reg &= ~S5P_CLKDIV2_G2D_MASK;
+ ? ? reg |= 0x2 << S5P_CLKDIV2_G2D_SHIFT;
+#endif
+ ? ? __raw_writel(reg, S5P_CLK_DIV2);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV_STAT0);
+ ? ? } while (reg & ((1 << 16) | (1 << 17)));
+
+ ? ? /* 11. Change MPLL to APLL in MSYS_MUX */
+ ? ? reg = __raw_readl(S5P_CLK_SRC0);
+ ? ? reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+ ? ? reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT); /* SCLKMPLL -> SCLKAPLL ? */
+ ? ? __raw_writel(reg, S5P_CLK_SRC0);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_MUX_STAT0);
+ ? ? } while (reg & (0x1 << 18));
+
+ ? ? /* 12. DMC1 refresh counter
+ ? ? ?* L4: DMC1 = 100MHz 7.8us/(1/100) = 0x30c
+ ? ? ?* Others: DMC1 = 200MHz 7.8us/(1/200) = 0x618
+ ? ? ?**/
+ ? ? if (!bus_speed_changing)
+ ? ? ? ? ? ? __raw_writel(0x618, S5P_VA_DMC1 + 0x30);
+
+#if defined(CONFIG_S5PC110_H_TYPE)
+ ? ? /* DMC0 source clock: SCLKMPLL -> SCLKA2M */
+ ? ? reg = __raw_readl(S5P_CLK_SRC6);
+ ? ? reg &= ~(S5P_CLKSRC6_ONEDRAM_MASK);
+ ? ? reg |= (0x0 << S5P_CLKSRC6_ONEDRAM_SHIFT);
+ ? ? __raw_writel(reg, S5P_CLK_SRC6);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_MUX_STAT1);
+ ? ? } while (reg & (1 << 11));
+
+ ? ? reg = __raw_readl(S5P_CLK_DIC6);
+ ? ? reg &= ~(S5P_CLKDIV6_ONEDRAM_MASK);
+ ? ? reg |= (0x0 << S5P_CLKDIV6_ONEDRAM_SHIFT);
+ ? ? __raw_writel(reg, S5P_CLK_DIV6);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV_STAT1);
+ ? ? } while (reg & (1 << 15));
+ ? ? __raw_writel(0x618, S5P_VA_DMC0 + 0x30);
+#endif
+}
+
+#ifdef CONFIG_PM
+static int no_cpufreq_access;
+/* s5pv210_target: relation has an additional symantics other than
+ * the standard
+ * [0x30]:
+ * ? 1: disable further access to target until being re-enabled.
+ * ? 2: re-enable access to target */
+#endif
+static int s5pv210_target(struct cpufreq_policy *policy,
+ ? ? ? ? ? ? unsigned int target_freq,
+ ? ? ? ? ? ? unsigned int relation)
+{

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? static int initialized;
+ ? ? int ret = 0;
+ ? ? unsigned long arm_clk;
+ ? ? unsigned int index, reg, arm_volt, int_volt;
+ ? ? unsigned int pll_changing = 0;
+ ? ? unsigned int bus_speed_changing = 0;
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ ? ? printk(KERN_INFO "cpufreq: Entering for %dkHz\n", target_freq);
+#endif

cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, <prefix>, ...)

Quoted 6 lines
(quoted diff) +6 -0
+#ifdef CONFIG_PM
+ ? ? if ((relation & ENABLE_FURTHER_CPUFREQ) &&
+ ? ? ? ? ? ? ? ? ? ? (relation & DISABLE_FURTHER_CPUFREQ)) {
+ ? ? ? ? ? ? /* Invalidate both if both marked */
+ ? ? ? ? ? ? relation &= ~ENABLE_FURTHER_CPUFREQ;
+ ? ? ? ? ? ? relation &= ~DISABLE_FURTHER_CPUFREQ;

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? ? ? ? ? printk(KERN_ERR "%s:%d denied marking \"FURTHER_CPUFREQ\""
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? " as both marked.\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? __FILE__, __LINE__);
+ ? ? }
+ ? ? if (relation & ENABLE_FURTHER_CPUFREQ)
+ ? ? ? ? ? ? no_cpufreq_access = 0;
+ ? ? if (no_cpufreq_access == 1) {
+#ifdef CONFIG_PM_VERBOSE
+ ? ? ? ? ? ? printk(KERN_ERR "%s:%d denied access to %s as it is disabled"
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ?" temporarily\n", __FILE__, __LINE__, __func__);

Use pr_err(...)

Quoted 164 lines
(quoted diff) +164 -0
+#endif
+ ? ? ? ? ? ? ret = -EINVAL;
+ ? ? ? ? ? ? goto out;
+ ? ? }
+ ? ? if (relation & DISABLE_FURTHER_CPUFREQ)
+ ? ? ? ? ? ? no_cpufreq_access = 1;
+ ? ? relation &= ~MASK_FURTHER_CPUFREQ;
+#endif
+
+ ? ? s3c_freqs.freqs.old = s5pv210_getspeed(0);
+
+ ? ? if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? target_freq, relation, &index)) {
+ ? ? ? ? ? ? ret = -EINVAL;
+ ? ? ? ? ? ? goto out;
+ ? ? }
+#ifdef CPUFREQ_DISABLE_100MHZ
+ ? ? if (index == L4)
+ ? ? ? ? ? ? index = L3;
+#endif
+#ifdef CPUFREQ_DISABLE_1GHZ
+ ? ? if (index == L0)
+ ? ? ? ? ? ? index = L1;
+#endif
+
+ ? ? arm_clk = s5pv210_freq_table[index].frequency;
+
+ ? ? s3c_freqs.freqs.new = arm_clk;
+ ? ? s3c_freqs.freqs.cpu = 0;
+
+ ? ? if (s3c_freqs.freqs.new == s3c_freqs.freqs.old &&
+ ? ? ? ? ? ? ? ? ? ? initialized >= 2)
+ ? ? ? ? ? ? return 0;
+ ? ? else if (initialized < 2)
+ ? ? ? ? ? ? initialized++;
+
+ ? ? arm_volt = s5pv210_dvs_conf[index].arm_volt;
+ ? ? int_volt = s5pv210_dvs_conf[index].int_volt;
+
+ ? ? /* iNew clock information update */
+ ? ? memcpy(&s3c_freqs.new, &s5pv210_clk_info[index],
+ ? ? ? ? ? ? ? ? ? ? sizeof(struct s3c_freq));
+
+ ? ? if (s3c_freqs.freqs.new >= s3c_freqs.freqs.old) {
+ ? ? ? ? ? ? /* Voltage up code: increase ARM first */
+ ? ? ? ? ? ? if (!IS_ERR_OR_NULL(arm_regulator) &&
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? !IS_ERR_OR_NULL(internal_regulator)) {
+ ? ? ? ? ? ? ? ? ? ? regulator_set_voltage(arm_regulator,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? arm_volt, arm_volt_max);
+ ? ? ? ? ? ? ? ? ? ? regulator_set_voltage(internal_regulator,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int_volt, int_volt_max);
+ ? ? ? ? ? ? }
+ ? ? }
+ ? ? cpufreq_notify_transition(&s3c_freqs.freqs, CPUFREQ_PRECHANGE);
+
+ ? ? if (s3c_freqs.new.fclk != s3c_freqs.old.fclk || initialized < 2)
+ ? ? ? ? ? ? pll_changing = 1;
+
+ ? ? if (s3c_freqs.new.hclk_msys != s3c_freqs.old.hclk_msys ||
+ ? ? ? ? ? ? ? ? ? ? initialized < 2)
+ ? ? ? ? ? ? bus_speed_changing = 1;
+
+ ? ? if (bus_speed_changing) {
+ ? ? ? ? ? ? /* Reconfigure DRAM refresh counter value for minimum
+ ? ? ? ? ? ? ?* temporary clock while changing divider.
+ ? ? ? ? ? ? ?* expected clock is 83MHz: 7.8usec/(1/83MHz) = 0x287
+ ? ? ? ? ? ? ?**/
+ ? ? ? ? ? ? if (pll_changing)
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x287, S5P_VA_DMC1 + 0x30);
+ ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
+
+ ? ? ? ? ? ? __raw_writel(0x287, S5P_VA_DMC0 + 0x30);
+ ? ? }
+
+ ? ? /* APLL should be changed in this level
+ ? ? ?* APLL -> MPLL(for stable transition) -> APLL
+ ? ? ?* Some clock source's clock API ?are not prepared. Do not use clock API
+ ? ? ?* in below code.
+ ? ? ?*/
+ ? ? if (pll_changing)
+ ? ? ? ? ? ? s5pv210_target_APLL2MPLL(index, bus_speed_changing);
+
+ ? ? /* ARM MCS value changed */
+ ? ? if (index != L4) {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_ARM_MCS_CON);
+ ? ? ? ? ? ? reg &= ~0x3;
+ ? ? ? ? ? ? reg |= 0x1;
+ ? ? ? ? ? ? __raw_writel(reg, S5P_ARM_MCS_CON);
+ ? ? }
+
+ ? ? reg = __raw_readl(S5P_CLK_DIV0);
+
+ ? ? reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK
+ ? ? ? ? ? ? ? ? ? ? | S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK
+ ? ? ? ? ? ? ? ? ? ? | S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK
+ ? ? ? ? ? ? ? ? ? ? | S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK);
+
+ ? ? reg |= ((clkdiv_val[index][0]<<S5P_CLKDIV0_APLL_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT)
+ ? ? ? ? ? ? ? ? ? ? | (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
+
+ ? ? __raw_writel(reg, S5P_CLK_DIV0);
+
+ ? ? do {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV_STAT0);
+ ? ? } while (reg & 0xff);
+
+ ? ? /* ARM MCS value changed */
+ ? ? if (index == L4) {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_ARM_MCS_CON);
+ ? ? ? ? ? ? reg &= ~0x3;
+ ? ? ? ? ? ? reg |= 0x3;
+ ? ? ? ? ? ? __raw_writel(reg, S5P_ARM_MCS_CON);
+ ? ? }
+
+ ? ? if (pll_changing)
+ ? ? ? ? ? ? s5pv210_target_MPLL2APLL(index, bus_speed_changing);
+
+ ? ? /* L4 level need to change memory bus speed,
+ ? ? ?* hence onedram clock divier and
+ ? ? ?* memory refresh parameter should be changed
+ ? ? ?*/
+ ? ? if (bus_speed_changing) {
+ ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV6);
+ ? ? ? ? ? ? reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
+ ? ? ? ? ? ? reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
+ ? ? ? ? ? ? /* ONEDRAM Clock Divider Ratio: 7 for L4, 3 for Others */
+ ? ? ? ? ? ? __raw_writel(reg, S5P_CLK_DIV6);
+
+ ? ? ? ? ? ? do {
+ ? ? ? ? ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV_STAT1);
+ ? ? ? ? ? ? } while (reg & (1 << 15));
+
+ ? ? ? ? ? ? /* Reconfigure DRAM refresh counter value */
+ ? ? ? ? ? ? if (index != L4) {
+ ? ? ? ? ? ? ? ? ? ? /* DMC0: 166MHz
+ ? ? ? ? ? ? ? ? ? ? ?* DMC1: 200MHz
+ ? ? ? ? ? ? ? ? ? ? ?**/
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x618, S5P_VA_DMC1 + 0x30);
+#if !defined(CONFIG_S5PC110_H_TYPE)
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x50e, S5P_VA_DMC0 + 0x30);
+#else
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x618, S5P_VA_DMC0 + 0x30);
+#endif
+ ? ? ? ? ? ? } else {
+ ? ? ? ? ? ? ? ? ? ? /* DMC0: 83MHz
+ ? ? ? ? ? ? ? ? ? ? ?* DMC1: 100MHz
+ ? ? ? ? ? ? ? ? ? ? ?**/
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
+ ? ? ? ? ? ? ? ? ? ? __raw_writel(0x287, S5P_VA_DMC0 + 0x30);
+ ? ? ? ? ? ? }
+ ? ? }
+
+ ? ? if (s3c_freqs.freqs.new < s3c_freqs.freqs.old) {
+ ? ? ? ? ? ? /* Voltage down: decrease INT first.*/
+ ? ? ? ? ? ? if (!IS_ERR_OR_NULL(arm_regulator) &&
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? !IS_ERR_OR_NULL(internal_regulator)) {
+ ? ? ? ? ? ? ? ? ? ? regulator_set_voltage(internal_regulator,

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int_volt, int_volt_max);
+ ? ? ? ? ? ? ? ? ? ? regulator_set_voltage(arm_regulator,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? arm_volt, arm_volt_max);
+ ? ? ? ? ? ? }
+ ? ? }
+ ? ? cpufreq_notify_transition(&s3c_freqs.freqs, CPUFREQ_POSTCHANGE);
+
+ ? ? memcpy(&s3c_freqs.old, &s3c_freqs.new, sizeof(struct s3c_freq));
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ ? ? printk(KERN_INFO "cpufreq: Performance changed[L%d]\n", index);

pr_info

Quoted 5 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +5 -0
+#endif
+ ? ? previous_arm_volt = s5pv210_dvs_conf[index].arm_volt;
+out:
+ ? ? return ret;
+}

arch/arm/mach-s5pv210/cpufreq-s5pv210.c

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+
+
+#ifdef CONFIG_PM
+static int previous_frequency;
+
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
+ ? ? ? ? ? ? pm_message_t pmsg)
+{
+ ? ? int ret = 0;
+ ? ? printk(KERN_INFO "cpufreq: Entering suspend.\n");

pr_info

Quoted 5 lines
(quoted diff) +5 -0
+
+ ? ? previous_frequency = cpufreq_get(0);
+ ? ? ret = __cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+ ? ? ? ? ? ? ? ? ? ? DISABLE_FURTHER_CPUFREQ);
+ ? ? return ret;

Review

Quoted 10 lines
(quoted diff) +10 -0
+}
+
+static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
+{
+ ? ? int ret = 0;
+ ? ? u32 rate;
+ ? ? int level = CPUFREQ_TABLE_END;
+ ? ? int i;
+
+ ? ? printk(KERN_INFO "cpufreq: Waking up from a suspend.\n");

pr_info

Quoted 10 lines
(quoted diff) +10 -0
+
+ ? ? __cpufreq_driver_target(cpufreq_cpu_get(0), previous_frequency,
+ ? ? ? ? ? ? ? ? ? ? ENABLE_FURTHER_CPUFREQ);
+
+ ? ? /* Clock information update with wakeup value */
+ ? ? rate = clk_get_rate(mpu_clk);
+
+ ? ? i = 0;
+ ? ? while (s5pv210_freq_table[i].frequency != CPUFREQ_TABLE_END) {
+ ? ? ? ? ? ? if (s5pv210_freq_table[i].frequency * 1000 == rate) {

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? ? ? ? ? ? ? ? ? level = s5pv210_freq_table[i].index;
+ ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? }
+ ? ? ? ? ? ? i++;
+ ? ? }
+
+ ? ? if (level == CPUFREQ_TABLE_END) { /* Not found */
+ ? ? ? ? ? ? printk(KERN_ERR "[%s:%d] clock speed does not match: "
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? "%d. Using L1 of 800MHz.\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? __FILE__, __LINE__, rate);

pr_err

Quoted 7 lines

+ ? ? ? ? ? ? level = L1;
+ ? ? }

arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +5 -0
+
+ ? ? memcpy(&s3c_freqs.old, &s5pv210_clk_info[level],
+ ? ? ? ? ? ? ? ? ? ? sizeof(struct s3c_freq));
+ ? ? previous_arm_volt = s5pv210_dvs_conf[level].arm_volt;
+ ? ? return ret;

arch/arm/mach-s5pv210/cpufreq-s5pv210.c

Quoted 10 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +10 -0
+}
+#endif
+
+
+static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
+{
+ ? ? u32 rate ;
+ ? ? int i, level = CPUFREQ_TABLE_END;
+
+ ? ? printk(KERN_INFO "S5PV210 CPUFREQ %s:%d\n", __FILE__, __LINE__);

pr_info

Quoted 4 lines
(quoted diff) +4 -0
+#ifdef CONFIG_PM
+ ? ? no_cpufreq_access = 0;
+#endif
+#ifdef CLK_OUT_PROBING

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? reg = __raw_readl(S5P_CLK_OUT);
+ ? ? reg &= ~(0x1f << 12 | 0xf << 20); /* CLKSEL and DIVVAL*/
+ ? ? reg |= (0xf << 12 | 0x1 << 20); /* CLKSEL = ARMCLK/4, DIVVAL = 1 */
+ ? ? /* Result = ARMCLK / 4 / ( 1 + 1 ) */
+ ? ? __raw_writel(reg, S5P_CLK_OUT);
+#endif
+ ? ? mpu_clk = clk_get(NULL, MPU_CLK);
+ ? ? if (IS_ERR(mpu_clk)) {
+ ? ? ? ? ? ? printk(KERN_ERR "S5PV210 CPUFREQ cannot get MPU_CLK(%s)\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? MPU_CLK);

pr_err

Quoted 6 lines

+ ? ? ? ? ? ? return PTR_ERR(mpu_clk);
+ ? ? }
+
+ ? ? if (policy->cpu != 0) {
+ ? ? ? ? ? ? printk(KERN_ERR "S5PV210 CPUFREQ cannot get proper cpu(%d)\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? policy->cpu);

pr_err

Quoted 17 lines

+ ? ? ? ? ? ? return -EINVAL;
+ ? ? }
+ ? ? policy->cur = policy->min = policy->max = s5pv210_getspeed(0);

(quoted diff) +14 -0
+
+ ? ? cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu);
+
+ ? ? policy->cpuinfo.transition_latency = 40000; ? ? /*1us*/
+
+ ? ? rate = clk_get_rate(mpu_clk);
+ ? ? i = 0;
+
+ ? ? while (s5pv210_freq_table[i].frequency != CPUFREQ_TABLE_END) {
+ ? ? ? ? ? ? if (s5pv210_freq_table[i].frequency * 1000 == rate) {
+ ? ? ? ? ? ? ? ? ? ? level = s5pv210_freq_table[i].index;
+ ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? }
+ ? ? ? ? ? ? i++;

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? }
+
+ ? ? if (level == CPUFREQ_TABLE_END) { /* Not found */
+ ? ? ? ? ? ? printk(KERN_ERR "[%s:%d] clock speed does not match: "
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? "%d. Using L1 of 800MHz.\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? __FILE__, __LINE__, rate);
+ ? ? ? ? ? ? level = L1;
+ ? ? }
+
+ ? ? printk(KERN_INFO "S5PV210 CPUFREQ Initialized.\n");

pr_info

Quoted 14 lines
(quoted diff) +14 -0
+
+ ? ? memcpy(&s3c_freqs.old, &s5pv210_clk_info[level],
+ ? ? ? ? ? ? ? ? ? ? sizeof(struct s3c_freq));
+ ? ? previous_arm_volt = s5pv210_dvs_conf[level].arm_volt;
+
+ ? ? return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table);
+}
+
+static struct cpufreq_driver s5pv210_driver = {
+ ? ? .flags ? ? ? ? ?= CPUFREQ_STICKY,
+ ? ? .verify ? ? ? ? = s5pv210_verify_speed,
+ ? ? .target ? ? ? ? = s5pv210_target,
+ ? ? .get ? ? ? ? ? ?= s5pv210_getspeed,
+ ? ? .init ? ? ? ? ? = s5pv210_cpu_init,

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? .name ? ? ? ? ? = "s5pv210",
+#ifdef CONFIG_PM
+ ? ? .suspend ? ? ? ?= s5pv210_cpufreq_suspend,
+ ? ? .resume ? ? ? ? = s5pv210_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv210_cpufreq_init(void)
+{
+ ? ? printk(KERN_INFO "S5PV210 CPUFREQ Init.\n");

pr_info
Also, I guess one banner is enough?

Quoted 6 lines

+ ? ? arm_regulator = regulator_get_exclusive(NULL, "vddarm");
+ ? ? if (IS_ERR(arm_regulator)) {
+ ? ? ? ? ? ? printk(KERN_ERR "failed to get regulater resource vddarm\n");
+ ? ? ? ? ? ? goto error;
+ ? ? }
+ ? ? internal_regulator = regulator_get_exclusive(NULL, "vddint");

Quoted 8 lines

+ ? ? if (IS_ERR(internal_regulator)) {
+ ? ? ? ? ? ? printk(KERN_ERR "failed to get regulater resource vddint\n");
+ ? ? ? ? ? ? goto error;
+ ? ? }
+ ? ? goto finish;
+error:
+ ? ? printk(KERN_WARNING "Cannot get vddarm or vddint. CPUFREQ Will not"
+ ? ? ? ? ? ? ? ? ? ?" change the voltage.\n");

pr_warn

Quoted 51 lines
arch/arm/mach-s5pv210/cpufreq-s5pv210.c new file +5 -0
+finish:
+ ? ? return cpufreq_register_driver(&s5pv210_driver);
+}
+
+late_initcall(s5pv210_cpufreq_init);
arch/arm/mach-s5pv210/include/mach/cpu-freq.h new file +40 -0
new file mode 100644
index 0000000..d3c31b2
@@ -0,0 +1,50 @@
+/* arch/arm/mach-s5pv210/include/mach/cpu-freq.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * ? MyungJoo Ham <[email protected]>
+ *
+ * S5PV210/S5PC110 CPU frequency scaling support
+ *
+ * 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.
+*/
+
+#ifndef _ARCH_ARM_MACH_S5PV210_INCLUDE_MACH_CPU_FREQ_H_
+#define _ARCH_ARM_MACH_S5PV210_INCLUDE_MACH_CPU_FREQ_H_
+
+#include <linux/cpufreq.h>
+
+#ifdef CONFIG_CPU_S5PV210
+
+#define USE_FREQ_TABLE
+
+#define KHZ_T ? ? ? ? ? 1000
+
+#define MPU_CLK ? ? ? ? "armclk"
+
+enum perf_level {
+ ? ? L0 = 0,
+ ? ? L1,
+ ? ? L2,
+ ? ? L3,
+ ? ? L4,
+};
+
+#define CLK_DIV0_MASK ? ((0x7<<0)|(0x7<<8)|(0x7<<12)) ? /* APLL,HCLK_MSYS,PCLK_MSYS mask value ?*/
+
+#ifdef CONFIG_PM
+#define SLEEP_FREQ ? ? ?(800 * 1000) /* Use 800MHz when entering sleep */
+
+/* additional symantics for "relation" in cpufreq with pm */

arch/arm/mach-s5pv210/include/mach/cpu-freq.h line 50

Quoted 10 lines
arch/arm/mach-s5pv210/include/mach/cpu-freq.h new file +10 -0
+#define DISABLE_FURTHER_CPUFREQ ? ? ? ? 0x10
+#define ENABLE_FURTHER_CPUFREQ ? ? ? ? ?0x20
+#define MASK_FURTHER_CPUFREQ ? ? ? ? ? ?0x30
+/* With 0x00(NOCHANGE), it depends on the previous "further" status */
+
+#endif
+
+
+#endif /* CONFIG_CPU_S5PV210 */
+#endif /* _ARCH_ARM_MACH_S5PV210_INCLUDE_MACH_CPU_FREQ_H_ */

--
Maurus Cuelenaere

Signature · 5 lines
MyungJoo Ham (???), Ph.D.
Mobile Software Platform Lab,
Digital Media and Communications (DMC) Business
Samsung Electronics
cell: 82-10-6714-2858
#9 lore raw

PATCH v2 4/5 ARM: S5PV210: add DMCx access virtual address

In reply to MyungJoo Ham
Quoted 40 lines · MyungJoo Ham

This patch prepares CPUFREQ support for S5PV210 by adding definitions for S5P_VA_DMCx accessed by CPUFREQ, which were not defined previously.

---
 arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
 arch/arm/mach-s5pv210/include/mach/map.h |    8 ++++++++
 2 files changed, 19 insertions(+), 1 deletions(-)
arch/arm/mach-s5pv210/cpu.c +11 -1
index 94c632b..84a6708 100644
@@ -59,7 +59,17 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
 		.pfn		= __phys_to_pfn(S5PV210_PA_SROMC),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
-	}
+	}, {
+		.virtual    = (unsigned long)S5P_VA_DMC0,
+		.pfn        = __phys_to_pfn(S5P_PA_DMC0),
+		.length     = SZ_4K,
+		.type       = MT_DEVICE,
+	}, {
+		.virtual    = (unsigned long)S5P_VA_DMC1,
+		.pfn        = __phys_to_pfn(S5P_PA_DMC1),
+		.length     = SZ_4K,
+		.type       = MT_DEVICE,
+	},
 };
 
 static void s5pv210_idle(void)
arch/arm/mach- renamed from arch/arm/mach-s5pv210/include/mach/map.h +0 -0

s5pv210/include/mach/map.h
index 17687f0..4945674 100644

arch/arm/mach-s5pv210/include/mach/map.h line 112

Quoted 5 lines
arch/arm/mach-s5pv210/include/mach/map.h +2 -0
@@ -108,4 +108,12 @@
 #define SAMSUNG_PA_ADC		S5PV210_PA_ADC
 #define SAMSUNG_PA_KEYPAD	S5PV210_PA_KEYPAD
 
+/* DMC */
+#define S5P_PA_DMC0     (0xF0000000)

Should be S5PV210_PA_DMC0..
If you need to define S5P_PA_xxx, you can re-define like others in here. But right now no need S5P_PA_xxx because used in cpu.c of mach directory not plat-s5p.

arch/arm/mach-s5pv210/include/mach/map.h line 113

Quoted 1 line
arch/arm/mach-s5pv210/include/mach/map.h +1 -0
+#define S5P_VA_DMC0     S3C_ADDR(0x00a00000)

If you need to add VA_xxx, should be in plat-s5p/include/plat/map-s5p.h

arch/arm/mach-s5pv210/include/mach/map.h line 116

Quoted 3 lines
arch/arm/mach-s5pv210/include/mach/map.h +3 -0
+
+#define S5P_PA_DMC1     (0xF1400000)
+#define S5P_VA_DMC1     S3C_ADDR(0x00b00000)

Same...

arch/arm/mach-s5pv210/include/mach/map.h line 118

Quoted 2 lines
arch/arm/mach-s5pv210/include/mach/map.h +2 -0
+
+

No need 2 empty lines...1 empty line is enough.

arch/arm/mach-s5pv210/include/mach/map.h

Quoted 2 lines
arch/arm/mach-s5pv210/include/mach/map.h +0 -1
 #endif /* __ASM_ARCH_MAP_H */
--

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#10 lore raw

PATCH v2 2/5 ARM: S5P: Added default pll values for APLL 800/1000MHz

In reply to MyungJoo Ham
Quoted 9 lines · MyungJoo Ham

CPUFREQ of S5PV210 uses different APLL settings and we provide such values for CPUFREQ at pll.h. We have been using differently between EVT0 and EVT1 machines. Although this version of kernel assumes that the CPU is EVT1, users may use code for EVT0 later.

Note that at 1GHz of ARMCLK, APLL should be 1GHz and for other lower ARMCLK, APLL should be 800MHz.

Review

Quoted 7 lines
---
 arch/arm/plat-s5p/include/plat/pll.h |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
(quoted diff) +0 -0

b/arch/arm/plat-s5p/include/plat/pll.h

arch/arm/plat-s5p/include/plat/pll.h line 24

Quoted 8 lines

index 7db3227..3112aba 100644

arch/arm/plat-s5p/include/plat/pll.h +1 -0
@@ -21,6 +21,14 @@
 
 #include <asm/div64.h>
 
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA

Actually, EVT0 is not real chip and not for mass production. So don't use in here.

arch/arm/plat-s5p/include/plat/pll.h line 25

Quoted 1 line
arch/arm/plat-s5p/include/plat/pll.h +1 -0
+#define PLL45XX_APLL_VAL_1000	(1 << 31) | (0xfa<<16) | (0x6<<8) |

(0x1)

arch/arm/plat-s5p/include/plat/pll.h

Quoted 10 lines
arch/arm/plat-s5p/include/plat/pll.h +6 -1
+#define PLL45XX_APLL_VAL_800	(1 << 31) | (0xc8<<16) | (0x6<<8) | (0x1)
+#else
+#define PLL45XX_APLL_VAL_1000	(1 << 31) | (125<<16) | (3<<8) | (1)
+#define PLL45XX_APLL_VAL_800	(1 << 31) | (100<<16) | (3<<8) | (1)
+#endif
+
 enum pll45xx_type_t {
 	pll_4500,
 	pll_4502,
--

And...I got the below result from scripts/checkpatch.pl.

--

ERROR: Macros with complex values should be enclosed in parenthesis #27: FILE: arch/arm/plat-s5p/include/plat/pll.h:25:
+#define PLL45XX_APLL_VAL_1000 (1 << 31) | (0xfa<<16) | (0x6<<8) | (0x1)

ERROR: Macros with complex values should be enclosed in parenthesis #28: FILE: arch/arm/plat-s5p/include/plat/pll.h:26:
+#define PLL45XX_APLL_VAL_800 (1 << 31) | (0xc8<<16) | (0x6<<8) | (0x1)

ERROR: Macros with complex values should be enclosed in parenthesis #30: FILE: arch/arm/plat-s5p/include/plat/pll.h:28:
+#define PLL45XX_APLL_VAL_1000 (1 << 31) | (125<<16) | (3<<8) | (1)

ERROR: Macros with complex values should be enclosed in parenthesis #31: FILE: arch/arm/plat-s5p/include/plat/pll.h:29:
+#define PLL45XX_APLL_VAL_800 (1 << 31) | (100<<16) | (3<<8) | (1)

total: 4 errors, 0 warnings, 14 lines checked

--

I already said to you about that :-(
See the Documentation/SubmittingPatches...

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#11 lore raw

PATCH v2 2/5 ARM: S5P: Added default pll values for APLL 800/1000MHz

Quoted 23 lines · Kukjin Kim
Quoted 9 lines · MyungJoo Ham

CPUFREQ of S5PV210 uses different APLL settings and we provide such values for CPUFREQ at pll.h. We have been using differently between EVT0 and EVT1 machines. Although this version of kernel assumes that the CPU is EVT1, users may use code for EVT0 later.

Note that at 1GHz of ARMCLK, APLL should be 1GHz and for other lower ARMCLK, APLL should be 800MHz.

Review

Quoted 7 lines

---
?arch/arm/plat-s5p/include/plat/pll.h | ? ?8 ++++++++ ?1 files changed, 8 insertions(+), 0 deletions(-)

(quoted diff) +0 -0

b/arch/arm/plat-s5p/include/plat/pll.h

Quoted 5 lines

index 7db3227..3112aba 100644

arch/arm/plat-s5p/include/plat/pll.h +0 -0
@@ -21,6 +21,14 @@
 
Quoted 6 lines
Quoted 3 lines

?#include <asm/div64.h>

+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA

Actually, EVT0 is not real chip and not for mass production. So don't use in here.

But we got too many board and want to use it. ARM core is also has some workaround to fix internal bug. so you can regard it.

config S5PC110_WORKAROUND
help
Early s5pc110 has some errata blah blah ... To fix it you can enable it.

Thank you,
Kyungmin Park

Quoted 54 lines
Quoted 2 lines

+#define PLL45XX_APLL_VAL_1000 ? ? ? ?(1 << 31) | (0xfa<<16) | (0x6<<8) |

(0x1)

Quoted 10 lines
arch/arm/plat-s5p/include/plat/pll.h +6 -0
+#define PLL45XX_APLL_VAL_800 (1 << 31) | (0xc8<<16) | (0x6<<8) | (0x1)
+#else
+#define PLL45XX_APLL_VAL_1000 ? ? ? ?(1 << 31) | (125<<16) | (3<<8) | (1)
+#define PLL45XX_APLL_VAL_800 (1 << 31) | (100<<16) | (3<<8) | (1)
+#endif
+

?enum pll45xx_type_t {
? ? ? pll_4500,
? ? ? pll_4502,
--

And...I got the below result from scripts/checkpatch.pl.

--

ERROR: Macros with complex values should be enclosed in parenthesis #27: FILE: arch/arm/plat-s5p/include/plat/pll.h:25:
+#define PLL45XX_APLL_VAL_1000 ?(1 << 31) | (0xfa<<16) | (0x6<<8) | (0x1)

ERROR: Macros with complex values should be enclosed in parenthesis #28: FILE: arch/arm/plat-s5p/include/plat/pll.h:26:
+#define PLL45XX_APLL_VAL_800 ? (1 << 31) | (0xc8<<16) | (0x6<<8) | (0x1)

ERROR: Macros with complex values should be enclosed in parenthesis #30: FILE: arch/arm/plat-s5p/include/plat/pll.h:28:
+#define PLL45XX_APLL_VAL_1000 ?(1 << 31) | (125<<16) | (3<<8) | (1)

ERROR: Macros with complex values should be enclosed in parenthesis #31: FILE: arch/arm/plat-s5p/include/plat/pll.h:29:
+#define PLL45XX_APLL_VAL_800 ? (1 << 31) | (100<<16) | (3<<8) | (1)

total: 4 errors, 0 warnings, 14 lines checked

--

I already said to you about that :-(
See the Documentation/SubmittingPatches...

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html

#12 lore raw

PATCH v2 2/5 ARM: S5P: Added default pll values for APLL 800/1000MHz

In reply to Kukjin Kim
Quoted 23 lines · Kukjin Kim
Quoted 9 lines · MyungJoo Ham

CPUFREQ of S5PV210 uses different APLL settings and we provide such values for CPUFREQ at pll.h. We have been using differently between EVT0 and EVT1 machines. Although this version of kernel assumes that the CPU is EVT1, users may use code for EVT0 later.

Note that at 1GHz of ARMCLK, APLL should be 1GHz and for other lower ARMCLK, APLL should be 800MHz.

Review

Quoted 7 lines

---
?arch/arm/plat-s5p/include/plat/pll.h | ? ?8 ++++++++ ?1 files changed, 8 insertions(+), 0 deletions(-)

(quoted diff) +0 -0

b/arch/arm/plat-s5p/include/plat/pll.h

Quoted 5 lines

index 7db3227..3112aba 100644

arch/arm/plat-s5p/include/plat/pll.h +0 -0
@@ -21,6 +21,14 @@
 
Quoted 6 lines
Quoted 3 lines

?#include <asm/div64.h>

+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA

Actually, EVT0 is not real chip and not for mass production. So don't use in here.

That was my point in a thread few days ago when I suggested we be careful while pushing code upstream.
Rather than flood mainline Samsung support with any hardware we can get our hands on, we need to strategically select SoCs (& their versions) and machines so that we have maximum overlap of features and, equally important, _users_ of that code. That will help us concentrate our efforts on support needed by most of the users and devices.

#13 lore raw

PATCH v2 2/5 ARM: S5P: Added default pll values for APLL 800/1000MHz

Quoted 31 lines · Jassi Brar
Quoted 23 lines · Kukjin Kim
Quoted 9 lines · MyungJoo Ham

CPUFREQ of S5PV210 uses different APLL settings and we provide such values for CPUFREQ at pll.h. We have been using differently between EVT0 and EVT1 machines. Although this version of kernel assumes that the CPU is EVT1, users may use code for EVT0 later.

Note that at 1GHz of ARMCLK, APLL should be 1GHz and for other lower ARMCLK, APLL should be 800MHz.

Review

Quoted 7 lines

---
?arch/arm/plat-s5p/include/plat/pll.h | ? ?8 ++++++++ ?1 files changed, 8 insertions(+), 0 deletions(-)

(quoted diff) +0 -0

b/arch/arm/plat-s5p/include/plat/pll.h

Quoted 5 lines

index 7db3227..3112aba 100644

arch/arm/plat-s5p/include/plat/pll.h +0 -0
@@ -21,6 +21,14 @@
 
Quoted 6 lines
Quoted 3 lines

?#include <asm/div64.h>

+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA

Actually, EVT0 is not real chip and not for mass production. So don't use in here.

Quoted 8 lines

That was my point in a thread few days ago when I suggested we be careful while pushing code upstream.
Rather than flood mainline Samsung support with any hardware we can get our hands on, we need to strategically select SoCs (& their versions) and machines so that we have maximum overlap of features and, equally important, _users_ of that code. That will help us concentrate our efforts on support needed by most of the users and devices.

That's point of view from chip vendor. but in my side we made a product using all chips from evt0, evt1, and fused evt1. Some product used the evt0 chip already.

I don't say LSI need to support early chip. you focus on the your selected SoC. The remaining will be done by us.

Thank you,
Kyungmin Park

Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html

#14 lore raw

PATCH v2 2/5 ARM: S5P: Added default pll values for APLL 800/1000MHz

Quoted 2 lines · Kyungmin Park

I don't say LSI need to support early chip. you focus on the your selected SoC. The remaining will be done by us.

Of course, you can do whatever you want.
I only worry that this mindless rush to push support for such obscure and rare machines will create maintenance issues in future when we have some serious updates to make in the core but don't have these rare machines to test. There are already such antiquated boards supported but at least they were popular
when the support was added and helped many users. These new additions don't seem to serve any purpose other than shifting maintenance overhead from the submitter
to mainline developers.

Just my personal opinion, I don't speak for my team.