All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/7] ARM: S5PV210: CPUFREQ Initial Support
@ 2010-08-03 10:04 ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

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.

At the patch revision v6, the following patches are updated from v5.
- 1/7: ARM: S5PV210: Allow to probe EVT revision number
	* Removed EVT1-Fused and related functions
	* Renamed evt related functions.
- 3/7: ARM: S5P: Added default pll values for APLL 800/100MHz
	* Corrected style.
- 7/7: ARM: S5PV210: Initial CPUFREQ Support
	* Following the renamed evt-related functions at 1/7 patch.

At the patch revision v5, the following patches are updated from v4.
- 1/7: ARM: S5PV210: Allow to probe EVT revision number
	* Renamed revision check function
	* Revise revision check function so that it does not access
	board-specific information
	* Chip-ID is used to identify some of EVT revisions.
	* Added "s5pv210_revision_or_later()" function
- 6/7: ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
	* Added entry infromation for G3D/G2D/MFC of the register
	S5P_CLK_[DIV|MUX]_STAT[0|1]. These entries are accessed
	multiple times at /arch/arm/mach-s5pv210/cpufreq.c.
- 7/7: ARM: S5PV210: Initial CPUFREQ Support
	* Remove unnecessary USE_FREQ_TABLE
	* Renamed functions in cpufreq.c
	* Initialization of s5pv210_cpufreq_target (previously,
	s5pv210_target) is revised (initilization --> first_run)
	* "workaround" --> "revision"
	* CLK_*_STATx register entries use macros: they are used
	multiple times.

MyungJoo Ham (7):
  ARM: S5PV210: Allow to probe EVT revision number.
  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: S5P: Virtual Addresses for DMCx registers.
  ARM: S5PV210: Access for DMCx registers
  ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
  ARM: S5PV210: Initial CPUFREQ Support

 arch/arm/Kconfig                                |    1 +
 arch/arm/mach-s5pv210/Kconfig                   |    5 +
 arch/arm/mach-s5pv210/Makefile                  |    2 +
 arch/arm/mach-s5pv210/cpu.c                     |   25 +-
 arch/arm/mach-s5pv210/cpufreq.c                 |  802 +++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h   |   38 ++
 arch/arm/mach-s5pv210/include/mach/hardware.h   |   12 +-
 arch/arm/mach-s5pv210/include/mach/map.h        |    4 +
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   60 ++-
 arch/arm/mach-s5pv210/mach-aquila.c             |    9 +
 arch/arm/mach-s5pv210/mach-goni.c               |    3 +
 arch/arm/plat-s5p/include/plat/map-s5p.h        |    3 +
 arch/arm/plat-s5p/include/plat/pll.h            |    3 +
 arch/arm/plat-samsung/include/plat/cpu-freq.h   |    6 +
 14 files changed, 968 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 0/7] ARM: S5PV210: CPUFREQ Initial Support
@ 2010-08-03 10:04 ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

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.

At the patch revision v6, the following patches are updated from v5.
- 1/7: ARM: S5PV210: Allow to probe EVT revision number
	* Removed EVT1-Fused and related functions
	* Renamed evt related functions.
- 3/7: ARM: S5P: Added default pll values for APLL 800/100MHz
	* Corrected style.
- 7/7: ARM: S5PV210: Initial CPUFREQ Support
	* Following the renamed evt-related functions at 1/7 patch.

At the patch revision v5, the following patches are updated from v4.
- 1/7: ARM: S5PV210: Allow to probe EVT revision number
	* Renamed revision check function
	* Revise revision check function so that it does not access
	board-specific information
	* Chip-ID is used to identify some of EVT revisions.
	* Added "s5pv210_revision_or_later()" function
- 6/7: ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
	* Added entry infromation for G3D/G2D/MFC of the register
	S5P_CLK_[DIV|MUX]_STAT[0|1]. These entries are accessed
	multiple times at /arch/arm/mach-s5pv210/cpufreq.c.
- 7/7: ARM: S5PV210: Initial CPUFREQ Support
	* Remove unnecessary USE_FREQ_TABLE
	* Renamed functions in cpufreq.c
	* Initialization of s5pv210_cpufreq_target (previously,
	s5pv210_target) is revised (initilization --> first_run)
	* "workaround" --> "revision"
	* CLK_*_STATx register entries use macros: they are used
	multiple times.

MyungJoo Ham (7):
  ARM: S5PV210: Allow to probe EVT revision number.
  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: S5P: Virtual Addresses for DMCx registers.
  ARM: S5PV210: Access for DMCx registers
  ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
  ARM: S5PV210: Initial CPUFREQ Support

 arch/arm/Kconfig                                |    1 +
 arch/arm/mach-s5pv210/Kconfig                   |    5 +
 arch/arm/mach-s5pv210/Makefile                  |    2 +
 arch/arm/mach-s5pv210/cpu.c                     |   25 +-
 arch/arm/mach-s5pv210/cpufreq.c                 |  802 +++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h   |   38 ++
 arch/arm/mach-s5pv210/include/mach/hardware.h   |   12 +-
 arch/arm/mach-s5pv210/include/mach/map.h        |    4 +
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   60 ++-
 arch/arm/mach-s5pv210/mach-aquila.c             |    9 +
 arch/arm/mach-s5pv210/mach-goni.c               |    3 +
 arch/arm/plat-s5p/include/plat/map-s5p.h        |    3 +
 arch/arm/plat-s5p/include/plat/pll.h            |    3 +
 arch/arm/plat-samsung/include/plat/cpu-freq.h   |    6 +
 14 files changed, 968 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 1/7] ARM: S5PV210: Allow to probe EVT revision number.
  2010-08-03 10:04 ` MyungJoo Ham
@ 2010-08-03 10:04   ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

Early products of S5PV210, EVT0, had several errata that require
kernel to avoid using some parts/instructions of the CPU or to
add protection instructions. There are products with such early
production CPUs; thus, we want to distinguish them in kernel.
This patch is to distinguish such products.

Include <mach/hardware.h> and call s5pv210_revision().

For example,

	if (s5pv210_revision(EVT0)) {
		... execute code targeted only to EVT0 ...
	} else {
		... execute normal code ...
	}

Call set_s5pv210_revision(EVTx) when the EVT revision number can be
identified. We have EVT0, EVT1, and EVT1-Fused avaialble right now and
only EVT1-Fused has the unique revision number at chipid (PRO_ID
register). A function, get_s5pv210_revision_chipid(), returns EVT
revision number if the revision is identified by the chipid; otherwise,
the function returns EVT_UNKNOWN. When EVT cannot be identified with
chipid, it can be identified at board support file
(arch/arm/mach-s5pv210/mach-*.c), not at the cpu file
(arch/arm/mach-s5pv210/cpu.c).

For Aquila machine. (mach-aquila.c)

Part of Aquila machines have the early production CPUs that require
to address errata issues. Note that we don't do this for GONI machines
because they have never used early production CPUs with errata. Besides,
please note that there are other boards that use such early produces
other than Aquila. However, those boards/machines are not registered at
the /linux/arch/arm/tools/mach-types, yet; thus, we have omitted them
in this patch.

For Goni machine. (mach-goni.c)

It's either EVT1 or EVT1-Fused; thus, it can be identified by
get_s5pv210_revision_chipid() function.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
--
v5 updates:
	- rename revision check function.
	- revise revision check functions so that it does not access
	  board-related information.
	- chipid is used to identify EVT revision.
	- added "s5pv210_revision_or_later()" function
v6 updates:
	- removed consideration for EVT1-FUSED

---
 arch/arm/mach-s5pv210/cpu.c                   |   13 +++++++++++++
 arch/arm/mach-s5pv210/include/mach/hardware.h |   12 +++++++++++-
 arch/arm/mach-s5pv210/mach-aquila.c           |    9 +++++++++
 arch/arm/mach-s5pv210/mach-goni.c             |    3 +++
 4 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index 94c632b..74d4c08 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -27,6 +27,7 @@
 #include <asm/proc-fns.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
+#include <mach/hardware.h>
 
 #include <plat/cpu.h>
 #include <plat/devs.h>
@@ -128,6 +129,18 @@ static struct sys_device s5pv210_sysdev = {
 	.cls	= &s5pv210_sysclass,
 };
 
+static bool s5pv210_evt0;
+
+bool s5pv210_revision_evt0(void)
+{
+	return s5pv210_evt0 == true;
+}
+
+void set_s5pv210_revision_evt0(bool evt0)
+{
+	s5pv210_evt0 = evt0;
+}
+
 static int __init s5pv210_core_init(void)
 {
 	return sysdev_class_register(&s5pv210_sysclass);
diff --git a/arch/arm/mach-s5pv210/include/mach/hardware.h b/arch/arm/mach-s5pv210/include/mach/hardware.h
index fada7a3..fa50868 100644
--- a/arch/arm/mach-s5pv210/include/mach/hardware.h
+++ b/arch/arm/mach-s5pv210/include/mach/hardware.h
@@ -13,6 +13,16 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H __FILE__
 
-/* currently nothing here, placeholder */
+extern bool s5pv210_revision_evt0(void);
+extern void set_s5pv210_revision_evt0(bool);
+
+/*
+ * get_s5pv210_revision_chipid returns s5pv210_revision if the
+ * EVT revision can be determined by the chipid(PRO_ID) register.
+ * However, note that only EVT1-FUSED can be identified from it and
+ * it cannot distinguish between EVT0 and EVT1. In such case, it
+ * returns EVT_UNKNOWN. In such case use set_s5pv210_revision() to
+ * set the revision number manually.
+ */
 
 #endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index 46d5c7e..6a8deaa 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -30,6 +30,7 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-fb.h>
 #include <mach/gpio.h>
+#include <mach/hardware.h>
 
 #include <plat/gpio-cfg.h>
 #include <plat/regs-serial.h>
@@ -536,6 +537,14 @@ static void __init aquila_map_io(void)
 
 static void __init aquila_machine_init(void)
 {
+	/* CPU Revision (EVTx) */
+	set_s5pv210_revision_evt0(false);
+	if (system_rev & 0x0800) {
+		if ((system_rev & 0xF) < 8)
+			set_s5pv210_revision_evt0(true);
+	} else if (system_rev & 0x2000)
+		set_s5pv210_revision_evt0(true);
+
 	/* PMIC */
 	aquila_pmic_init();
 	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs,
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 380d2ae..08ee3f6 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -32,6 +32,7 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-fb.h>
 #include <mach/gpio.h>
+#include <mach/hardware.h>
 
 #include <plat/gpio-cfg.h>
 #include <plat/regs-serial.h>
@@ -520,6 +521,8 @@ static void __init goni_map_io(void)
 
 static void __init goni_machine_init(void)
 {
+	set_s5pv210_revision_evt0(false);
+
 	/* PMIC */
 	goni_pmic_init();
 	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs,
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 1/7] ARM: S5PV210: Allow to probe EVT revision number.
@ 2010-08-03 10:04   ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

Early products of S5PV210, EVT0, had several errata that require
kernel to avoid using some parts/instructions of the CPU or to
add protection instructions. There are products with such early
production CPUs; thus, we want to distinguish them in kernel.
This patch is to distinguish such products.

Include <mach/hardware.h> and call s5pv210_revision().

For example,

	if (s5pv210_revision(EVT0)) {
		... execute code targeted only to EVT0 ...
	} else {
		... execute normal code ...
	}

Call set_s5pv210_revision(EVTx) when the EVT revision number can be
identified. We have EVT0, EVT1, and EVT1-Fused avaialble right now and
only EVT1-Fused has the unique revision number at chipid (PRO_ID
register). A function, get_s5pv210_revision_chipid(), returns EVT
revision number if the revision is identified by the chipid; otherwise,
the function returns EVT_UNKNOWN. When EVT cannot be identified with
chipid, it can be identified at board support file
(arch/arm/mach-s5pv210/mach-*.c), not at the cpu file
(arch/arm/mach-s5pv210/cpu.c).

For Aquila machine. (mach-aquila.c)

Part of Aquila machines have the early production CPUs that require
to address errata issues. Note that we don't do this for GONI machines
because they have never used early production CPUs with errata. Besides,
please note that there are other boards that use such early produces
other than Aquila. However, those boards/machines are not registered at
the /linux/arch/arm/tools/mach-types, yet; thus, we have omitted them
in this patch.

For Goni machine. (mach-goni.c)

It's either EVT1 or EVT1-Fused; thus, it can be identified by
get_s5pv210_revision_chipid() function.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
--
v5 updates:
	- rename revision check function.
	- revise revision check functions so that it does not access
	  board-related information.
	- chipid is used to identify EVT revision.
	- added "s5pv210_revision_or_later()" function
v6 updates:
	- removed consideration for EVT1-FUSED

---
 arch/arm/mach-s5pv210/cpu.c                   |   13 +++++++++++++
 arch/arm/mach-s5pv210/include/mach/hardware.h |   12 +++++++++++-
 arch/arm/mach-s5pv210/mach-aquila.c           |    9 +++++++++
 arch/arm/mach-s5pv210/mach-goni.c             |    3 +++
 4 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index 94c632b..74d4c08 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -27,6 +27,7 @@
 #include <asm/proc-fns.h>
 #include <mach/map.h>
 #include <mach/regs-clock.h>
+#include <mach/hardware.h>
 
 #include <plat/cpu.h>
 #include <plat/devs.h>
@@ -128,6 +129,18 @@ static struct sys_device s5pv210_sysdev = {
 	.cls	= &s5pv210_sysclass,
 };
 
+static bool s5pv210_evt0;
+
+bool s5pv210_revision_evt0(void)
+{
+	return s5pv210_evt0 == true;
+}
+
+void set_s5pv210_revision_evt0(bool evt0)
+{
+	s5pv210_evt0 = evt0;
+}
+
 static int __init s5pv210_core_init(void)
 {
 	return sysdev_class_register(&s5pv210_sysclass);
diff --git a/arch/arm/mach-s5pv210/include/mach/hardware.h b/arch/arm/mach-s5pv210/include/mach/hardware.h
index fada7a3..fa50868 100644
--- a/arch/arm/mach-s5pv210/include/mach/hardware.h
+++ b/arch/arm/mach-s5pv210/include/mach/hardware.h
@@ -13,6 +13,16 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H __FILE__
 
-/* currently nothing here, placeholder */
+extern bool s5pv210_revision_evt0(void);
+extern void set_s5pv210_revision_evt0(bool);
+
+/*
+ * get_s5pv210_revision_chipid returns s5pv210_revision if the
+ * EVT revision can be determined by the chipid(PRO_ID) register.
+ * However, note that only EVT1-FUSED can be identified from it and
+ * it cannot distinguish between EVT0 and EVT1. In such case, it
+ * returns EVT_UNKNOWN. In such case use set_s5pv210_revision() to
+ * set the revision number manually.
+ */
 
 #endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index 46d5c7e..6a8deaa 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -30,6 +30,7 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-fb.h>
 #include <mach/gpio.h>
+#include <mach/hardware.h>
 
 #include <plat/gpio-cfg.h>
 #include <plat/regs-serial.h>
@@ -536,6 +537,14 @@ static void __init aquila_map_io(void)
 
 static void __init aquila_machine_init(void)
 {
+	/* CPU Revision (EVTx) */
+	set_s5pv210_revision_evt0(false);
+	if (system_rev & 0x0800) {
+		if ((system_rev & 0xF) < 8)
+			set_s5pv210_revision_evt0(true);
+	} else if (system_rev & 0x2000)
+		set_s5pv210_revision_evt0(true);
+
 	/* PMIC */
 	aquila_pmic_init();
 	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs,
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 380d2ae..08ee3f6 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -32,6 +32,7 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-fb.h>
 #include <mach/gpio.h>
+#include <mach/hardware.h>
 
 #include <plat/gpio-cfg.h>
 #include <plat/regs-serial.h>
@@ -520,6 +521,8 @@ static void __init goni_map_io(void)
 
 static void __init goni_machine_init(void)
 {
+	set_s5pv210_revision_evt0(false);
+
 	/* PMIC */
 	goni_pmic_init();
 	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs,
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 2/7] ARM: Samsung SoC: added hclk/pclk info to s3c_freq for s5pv210 cpu-freq
  2010-08-03 10:04   ` MyungJoo Ham
@ 2010-08-03 10:04     ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

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

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/include/plat/cpu-freq.h |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq.h b/arch/arm/plat-samsung/include/plat/cpu-freq.h
index 80c4a80..9e97df7 100644
--- a/arch/arm/plat-samsung/include/plat/cpu-freq.h
+++ b/arch/arm/plat-samsung/include/plat/cpu-freq.h
@@ -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
 };
 
 /**
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 2/7] ARM: Samsung SoC: added hclk/pclk info to s3c_freq for s5pv210 cpu-freq
@ 2010-08-03 10:04     ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-samsung/include/plat/cpu-freq.h |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq.h b/arch/arm/plat-samsung/include/plat/cpu-freq.h
index 80c4a80..9e97df7 100644
--- a/arch/arm/plat-samsung/include/plat/cpu-freq.h
+++ b/arch/arm/plat-samsung/include/plat/cpu-freq.h
@@ -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
 };
 
 /**
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 3/7] ARM: S5P: Added default pll values for APLL 800/1000MHz
  2010-08-03 10:04     ` MyungJoo Ham
@ 2010-08-03 10:04       ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

CPUFREQ of S5PV210 uses different APLL settings according to
different CPU frequencies. We provide such settings values for
CPUFREQ at pll.h.

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

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
--
v6
	- Style correction

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

diff --git a/arch/arm/plat-s5p/include/plat/pll.h b/arch/arm/plat-s5p/include/plat/pll.h
index 7db3227..d5ee48c 100644
--- a/arch/arm/plat-s5p/include/plat/pll.h
+++ b/arch/arm/plat-s5p/include/plat/pll.h
@@ -21,6 +21,9 @@
 
 #include <asm/div64.h>
 
+#define PLL45XX_APLL_VAL_1000	((1 << 31) | (125 << 16) | (3 << 8) | (1))
+#define PLL45XX_APLL_VAL_800	((1 << 31) | (100 << 16) | (3 << 8) | (1))
+
 enum pll45xx_type_t {
 	pll_4500,
 	pll_4502,
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 3/7] ARM: S5P: Added default pll values for APLL 800/1000MHz
@ 2010-08-03 10:04       ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

CPUFREQ of S5PV210 uses different APLL settings according to
different CPU frequencies. We provide such settings values for
CPUFREQ at pll.h.

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

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
--
v6
	- Style correction

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

diff --git a/arch/arm/plat-s5p/include/plat/pll.h b/arch/arm/plat-s5p/include/plat/pll.h
index 7db3227..d5ee48c 100644
--- a/arch/arm/plat-s5p/include/plat/pll.h
+++ b/arch/arm/plat-s5p/include/plat/pll.h
@@ -21,6 +21,9 @@
 
 #include <asm/div64.h>
 
+#define PLL45XX_APLL_VAL_1000	((1 << 31) | (125 << 16) | (3 << 8) | (1))
+#define PLL45XX_APLL_VAL_800	((1 << 31) | (100 << 16) | (3 << 8) | (1))
+
 enum pll45xx_type_t {
 	pll_4500,
 	pll_4502,
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 4/7] ARM: S5P: Virtual Addresses for DMCx registers.
  2010-08-03 10:04       ` MyungJoo Ham
@ 2010-08-03 10:04         ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

	The CPUFREQ driver requires an access to DMCx registers. We
define virtual addresses of DMCx registers.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-s5p/include/plat/map-s5p.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h
index 1482852..bd803f1 100644
--- a/arch/arm/plat-s5p/include/plat/map-s5p.h
+++ b/arch/arm/plat-s5p/include/plat/map-s5p.h
@@ -31,4 +31,7 @@
 #define VA_VIC2			VA_VIC(2)
 #define VA_VIC3			VA_VIC(3)
 
+#define S5P_VA_DMC0		S3C_ADDR(0x00a00000)
+#define S5P_VA_DMC1		S3C_ADDR(0x00b00000)
+
 #endif /* __ASM_PLAT_MAP_S5P_H */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 4/7] ARM: S5P: Virtual Addresses for DMCx registers.
@ 2010-08-03 10:04         ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

	The CPUFREQ driver requires an access to DMCx registers. We
define virtual addresses of DMCx registers.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-s5p/include/plat/map-s5p.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h
index 1482852..bd803f1 100644
--- a/arch/arm/plat-s5p/include/plat/map-s5p.h
+++ b/arch/arm/plat-s5p/include/plat/map-s5p.h
@@ -31,4 +31,7 @@
 #define VA_VIC2			VA_VIC(2)
 #define VA_VIC3			VA_VIC(3)
 
+#define S5P_VA_DMC0		S3C_ADDR(0x00a00000)
+#define S5P_VA_DMC1		S3C_ADDR(0x00b00000)
+
 #endif /* __ASM_PLAT_MAP_S5P_H */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
  2010-08-03 10:04         ` MyungJoo Ham
@ 2010-08-03 10:04           ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

	The CPUFREQ driver requires an access to DMCx registers. We
define physical addresses and mapping between physical and virtual
addresses of DMCx registers.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
 arch/arm/mach-s5pv210/include/mach/map.h |    4 ++++
 2 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index 74d4c08..2066695 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -60,7 +60,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(S5PV210_PA_DMC0),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_DMC1,
+		.pfn		= __phys_to_pfn(S5PV210_PA_DMC1),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
 };
 
 static void s5pv210_idle(void)
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index 17687f0..daf6456 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -108,4 +108,8 @@
 #define SAMSUNG_PA_ADC		S5PV210_PA_ADC
 #define SAMSUNG_PA_KEYPAD	S5PV210_PA_KEYPAD
 
+/* DMC */
+#define S5PV210_PA_DMC0		(0xF0000000)
+#define S5PV210_PA_DMC1		(0xF1400000)
+
 #endif /* __ASM_ARCH_MAP_H */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
@ 2010-08-03 10:04           ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

	The CPUFREQ driver requires an access to DMCx registers. We
define physical addresses and mapping between physical and virtual
addresses of DMCx registers.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
 arch/arm/mach-s5pv210/include/mach/map.h |    4 ++++
 2 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index 74d4c08..2066695 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -60,7 +60,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(S5PV210_PA_DMC0),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_DMC1,
+		.pfn		= __phys_to_pfn(S5PV210_PA_DMC1),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
 };
 
 static void s5pv210_idle(void)
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index 17687f0..daf6456 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -108,4 +108,8 @@
 #define SAMSUNG_PA_ADC		S5PV210_PA_ADC
 #define SAMSUNG_PA_KEYPAD	S5PV210_PA_KEYPAD
 
+/* DMC */
+#define S5PV210_PA_DMC0		(0xF0000000)
+#define S5PV210_PA_DMC1		(0xF1400000)
+
 #endif /* __ASM_ARCH_MAP_H */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 6/7] ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
  2010-08-03 10:04           ` MyungJoo Ham
@ 2010-08-03 10:04             ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

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. Besides, later, we will probably need to use these macros
at arch/arm/mach-s5pv210/clock.c as well especially for entries that are
used out of clock.c as well.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   60 +++++++++++++++++++++-
 1 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
index 2a25ab4..f370ae8 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
@@ -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,41 @@
 #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)
+
+/* CLK_DIV_STAT0 */
+#define S5P_CLKDIV_STAT0_G3D		(1 << 16)
+#define S5P_CLKDIV_STAT0_MFC		(1 << 17)
+
+/* CLK_DIV_STAT1 */
+#define S5P_CLKDIV_STAT1_G2D		(1 << 20)
+
+/* CLK_MUX_STAT0 */
+#define S5P_CLKMUX_STAT0_MUX200		(1 << 18)
+
+/* CLK_MUX_STAT1 */
+#define S5P_CLKMUX_STAT1_G3D		(1 << 3)
+#define S5P_CLKMUX_STAT1_MFC		(1 << 7)
+#define S5P_CLKMUX_STAT1_G2D		(1 << 27)
+
 /* Registers related to power management */
 #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
 #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 6/7] ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
@ 2010-08-03 10:04             ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

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. Besides, later, we will probably need to use these macros
at arch/arm/mach-s5pv210/clock.c as well especially for entries that are
used out of clock.c as well.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   60 +++++++++++++++++++++-
 1 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
index 2a25ab4..f370ae8 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
@@ -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,41 @@
 #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)
+
+/* CLK_DIV_STAT0 */
+#define S5P_CLKDIV_STAT0_G3D		(1 << 16)
+#define S5P_CLKDIV_STAT0_MFC		(1 << 17)
+
+/* CLK_DIV_STAT1 */
+#define S5P_CLKDIV_STAT1_G2D		(1 << 20)
+
+/* CLK_MUX_STAT0 */
+#define S5P_CLKMUX_STAT0_MUX200		(1 << 18)
+
+/* CLK_MUX_STAT1 */
+#define S5P_CLKMUX_STAT1_G3D		(1 << 3)
+#define S5P_CLKMUX_STAT1_MFC		(1 << 7)
+#define S5P_CLKMUX_STAT1_G2D		(1 << 27)
+
 /* Registers related to power management */
 #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
 #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 7/7] ARM: S5PV210: Initial CPUFREQ Support
  2010-08-03 10:04             ` MyungJoo Ham
@ 2010-08-03 10:04               ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-samsung-soc, kyungmin.park, kgene.kim, myungjoo.ham, ben-linux

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.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
--
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
v3:
	- Style corrections (pr_info/pr_err, ...)
	- Revised dvs_conf struct
v4:
	- Renamed cpufreq-s5pv210.c -> cpufreq.c
	- Style corrections (less #ifdef's, comments)
	- Removed unncessary codes
	- Remove #ifdef for WORKAROUND, use s5pv210_workaround()
	- Renamed some static variables (get rid of s5pv210 prefix)
	- Added machine dependency to Kconfig/Makefile
	- DMC0, DMC1 refresh counter is not updated by a hardcoded value, but
	with the value given as the default and relative clock speeds. Besides,
	the algorithm to update DMC0/1 refresh counter is reformed.
v5:
	- Remove unnecessary USE_FREQ_TABLE
	- Renamed functions
	- s5pv210_cpufreq_target's initialization revised. (first_run)
	- "workaround" --> "revision"
	- CLK_*_STAT register entries use macros: they are used mutiple
	  times.
v6:
	- Restyled evt0-related codes.

---
 arch/arm/Kconfig                              |    1 +
 arch/arm/mach-s5pv210/Kconfig                 |    5 +
 arch/arm/mach-s5pv210/Makefile                |    2 +
 arch/arm/mach-s5pv210/cpufreq.c               |  802 +++++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h |   38 ++
 5 files changed, 848 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 98922f7..d5a5916 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
 
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 631019a..1c6d3bc 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -14,6 +14,7 @@ config CPU_S5PV210
 	select PLAT_S5P
 	select S3C_PL330_DMA
 	select S5P_EXT_INT
+	select S5PV210_CPU_FREQ if CPU_FREQ
 	help
 	  Enable S5PV210 CPU support
 
@@ -101,4 +102,8 @@ config MACH_SMDKC110
 	  Machine support for Samsung SMDKC110
 	  S5PC110(MCP) is one of package option of S5PV210
 
+config S5PV210_CPU_FREQ
+	bool "S5PV210 CPU-FREQ Support"
+	depends on CPU_S5PV210 && CPU_FREQ
+
 endif
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index aae592a..72ca5ec 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -34,3 +34,5 @@ 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
+
+obj-$(CONFIG_S5PV210_CPU_FREQ)		+= cpufreq.o
diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c
new file mode 100644
index 0000000..f394007
--- /dev/null
+++ b/arch/arm/mach-s5pv210/cpufreq.c
@@ -0,0 +1,802 @@
+/*  linux/arch/arm/mach-s5pv210/cpufreq.c
+ *
+ *  Copyright (C) 2010 Samsung Electronics Co., Ltd.
+ *
+ *  CPU frequency scaling for S5PV210/S5PC110
+ *  Based on cpu-sa1110.c and s5pc11x-cpufreq.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;
+
+static unsigned long previous_arm_volt;
+
+static unsigned int backup_dmc0_reg;
+static unsigned int backup_dmc1_reg;
+static unsigned int backup_freq_level;
+static unsigned int mpll_freq; /* in MHz */
+static unsigned int apll_freq_max; /* in MHz */
+
+/* frequency */
+static struct cpufreq_frequency_table freq_table[] = {
+	{L0, 1000*1000},
+	{L1, 800*1000},
+	{L2, 400*1000},
+	{L3, 200*1000},
+	{L4, 100*1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+struct s5pv210_dvs_conf {
+	unsigned long       arm_volt;   /* uV */
+	unsigned long       int_volt;   /* uV */
+};
+
+const unsigned long arm_volt_max = 1350000;
+const unsigned long int_volt_max = 1250000;
+
+static struct s5pv210_dvs_conf dvs_conf_evt0[] = {
+	[L0] = {
+		.arm_volt   = 1300000,
+		.int_volt   = 1200000,
+	},
+	[L1] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+
+	},
+	[L2] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+
+	},
+	[L3] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+	},
+	[L4] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+	},
+};
+static struct s5pv210_dvs_conf dvs_conf_default[] = {
+	[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 struct s5pv210_dvs_conf *dvs_conf = dvs_conf_default;
+
+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 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,
+	},
+};
+
+static int s5pv210_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int s5pv210_cpufreq_getspeed(unsigned int cpu)
+{
+	unsigned long rate;
+
+	if (cpu)
+		return 0;
+
+	rate = clk_get_rate(mpu_clk) / 1000;
+
+	return rate;
+}
+
+static void s5pv210_cpufreq_clksrcs_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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKDIV2_G2D_MASK;
+		reg |= (0x2 << S5P_CLKDIV2_G2D_SHIFT);
+	}
+
+	__raw_writel(reg, S5P_CLK_DIV2);
+
+	/* Wait for MFC, G3D div changing */
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
+	/* Wait for G2D div changing */
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		do {
+			reg = __raw_readl(S5P_CLK_DIV_STAT1);
+		} while  (reg & (S5P_CLKDIV_STAT1_G2D));
+	}
+
+	/*
+	 * 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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKSRC2_G2D_MASK;
+		reg |= (0x1 << S5P_CLKSRC2_G2D_SHIFT);
+	}
+	__raw_writel(reg, S5P_CLK_SRC2);
+
+	if (s5pv210_revision_evt0()) {
+		/* Wait for MFC, G3D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC));
+	} else {
+		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC
+					| S5P_CLKMUX_STAT1_G2D));
+	}
+
+	/* 3. msys: 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 & S5P_CLKMUX_STAT0_MUX200);
+}
+
+static void s5pv210_cpufreq_clksrcs_MPLL2APLL(unsigned int index,
+		unsigned int bus_speed_changing)
+{
+	unsigned int reg;
+
+	/*
+	 * 1. Set Lock time = 30us*24MHz = 02cf (EVT1)
+	 * EVT0			: Lock time = 300us*24Mhz = 7200(0x1c20)
+	 * EVT1 and later	: Lock time = 30us*24Mhz = 0x2cf
+	 */
+	if (s5pv210_revision_evt0())
+		__raw_writel(0x1c20, S5P_APLL_LOCK);
+	else
+		__raw_writel(0x2cf, S5P_APLL_LOCK);
+
+	/*
+	 * 2. Turn on APLL
+	 * 2-1. Set PMS values
+	 */
+	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);
+	/* 2-2. Wait until the PLL is locked */
+	do {
+		reg = __raw_readl(S5P_APLL_CON);
+	} while (!(reg & (0x1 << 29)));
+
+	/*
+	 * 3. 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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKSRC2_G2D_MASK;
+		reg |= 0x1 << S5P_CLKSRC2_G2D_SHIFT;
+	}
+	__raw_writel(reg, S5P_CLK_SRC2);
+
+	if (s5pv210_revision_evt0()) {
+		/* Wait for MFC, G3D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC));
+	} else {
+		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC
+					| S5P_CLKMUX_STAT1_G2D));
+	}
+
+	/*
+	 * 4. 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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKDIV2_G2D_MASK;
+		reg |= 0x2 << S5P_CLKDIV2_G2D_SHIFT;
+	}
+	__raw_writel(reg, S5P_CLK_DIV2);
+
+	/* Wait for MFC, G3D div changing */
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
+	/* Wait for G2D div changing */
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		do {
+			reg = __raw_readl(S5P_CLK_DIV_STAT1);
+		} while  (reg & (S5P_CLKDIV_STAT1_G2D));
+	}
+
+	/* 5. 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 & S5P_CLKMUX_STAT0_MUX200);
+}
+
+#ifdef CONFIG_PM
+static int no_cpufreq_access;
+/*
+ * s5pv210_cpufreq_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_cpufreq_target(struct cpufreq_policy *policy,
+		unsigned int target_freq,
+		unsigned int relation)
+{
+	static bool first_run = true;
+	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;
+
+	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
+			"cpufreq: Entering for %dkHz\n", target_freq);
+#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;
+		pr_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
+		pr_err("%s:%d denied access to %s as it is disabled"
+			       " temporarily\n", __FILE__, __LINE__, __func__);
+#endif
+		ret = -EINVAL;
+		goto out;
+	}
+	if (relation & DISABLE_FURTHER_CPUFREQ)
+		no_cpufreq_access = 1;
+	relation &= ~MASK_FURTHER_CPUFREQ;
+#endif
+
+	s3c_freqs.freqs.old = s5pv210_cpufreq_getspeed(0);
+
+	if (cpufreq_frequency_table_target(policy, freq_table,
+				target_freq, relation, &index)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	arm_clk = freq_table[index].frequency;
+
+	s3c_freqs.freqs.new = arm_clk;
+	s3c_freqs.freqs.cpu = 0;
+
+	/*
+	 * Run this function unconditionally until s3c_freqs.freqs.new
+	 * and s3c_freqs.freqs.old are both set by this function.
+	 */
+	if (s3c_freqs.freqs.new == s3c_freqs.freqs.old && !first_run)
+		return 0;
+
+	arm_volt = dvs_conf[index].arm_volt;
+	int_volt = dvs_conf[index].int_volt;
+
+	/* New clock information update */
+	memcpy(&s3c_freqs.new, &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 || first_run)
+		pll_changing = 1;
+
+	if (s3c_freqs.new.hclk_msys != s3c_freqs.old.hclk_msys || first_run)
+		bus_speed_changing = 1;
+
+	/*
+	 * If ONEDRAM(DMC0)'s clock is getting slower, DMC0's
+	 * refresh counter should decrease before slowing down
+	 * DMC0 clock. We assume that DMC0's source clock never
+	 * changes. This is a temporary setting for the transition.
+	 * Stable setting is done at the end of this function.
+	 */
+	reg = (__raw_readl(S5P_CLK_DIV6) & S5P_CLKDIV6_ONEDRAM_MASK)
+		>> S5P_CLKDIV6_ONEDRAM_SHIFT;
+	if (clkdiv_val[index][8] > reg) {
+		reg = backup_dmc0_reg * (reg + 1) / (clkdiv_val[index][8] + 1);
+		WARN_ON(reg > 0xFFFF);
+		reg &= 0xFFFF;
+		__raw_writel(reg, S5P_VA_DMC0 + 0x30);
+	}
+
+	/*
+	 * If hclk_msys (for DMC1) is getting slower, DMC1's
+	 * refresh counter should decrease before slowing down
+	 * hclk_msys in order to get rid of glitches in the
+	 * transition. This is temporary setting for the transition.
+	 * Stable setting is done at the end of this function.
+	 *
+	 * Besides, we need to consider the case when PLL speed changes,
+	 * where the DMC1's source clock hclk_msys is changed from ARMCLK
+	 * to MPLL temporarily. DMC1 needs to be ready for this
+	 * transition as well.
+	 */
+	if (s3c_freqs.new.hclk_msys < s3c_freqs.old.hclk_msys || first_run) {
+		/*
+		 * hclk_msys is up to 12bit. (200000)
+		 * reg is 16bit. so no overflow, yet.
+		 *
+		 * May need to use div64.h later with larger hclk_msys or
+		 * DMCx refresh counter. But, we have bugs in do_div and
+		 * that should be fixed before.
+		 */
+		reg = backup_dmc1_reg * s3c_freqs.new.hclk_msys;
+		reg /= clk_info[backup_freq_level].hclk_msys;
+
+		/*
+		 * When ARM_CLK is absed on APLL->MPLL,
+		 * hclk_msys becomes hclk_msys *= MPLL/APLL;
+		 *
+		 * Based on the worst case scenario, we use MPLL/APLL_MAX
+		 * assuming that MPLL clock speed does not change.
+		 *
+		 * Multiplied first in order to reduce rounding error.
+		 * because reg has 15b length, using 64b should be enough to
+		 * prevent overflow.
+		 */
+		if (pll_changing) {
+			reg *= mpll_freq;
+			reg /= apll_freq_max;
+		}
+		WARN_ON(reg > 0xFFFF);
+		__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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_cpufreq_clksrcs_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_cpufreq_clksrcs_MPLL2APLL(index, bus_speed_changing);
+
+	/*
+	 * Adjust DMC0 refresh ratio according to the rate of DMC0
+	 * The DIV value of DMC0 clock changes and SRC value is not controlled.
+	 * We assume that no one changes SRC value of DMC0 clock, either.
+	 */
+	reg = __raw_readl(S5P_CLK_DIV6);
+	reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
+	reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
+	/* ONEDRAM(DMC0) Clock Divider Ratio: 7+1 for L4, 3+1 for Others */
+	__raw_writel(reg, S5P_CLK_DIV6);
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT1);
+	} while (reg & (1 << 15));
+
+	/*
+	 * If DMC0 clock gets slower (by orginal clock speed / n),
+	 * then, the refresh rate should decrease
+	 * (by original refresh count / n) (n: divider)
+	 */
+	reg = backup_dmc0_reg * (clkdiv_val[backup_freq_level][8] + 1)
+		/ (clkdiv_val[index][8] + 1);
+	__raw_writel(reg & 0xFFFF, S5P_VA_DMC0 + 0x30);
+
+	/*
+	 * Adjust DMC1 refresh ratio according to the rate of hclk_msys
+	 * (L0~L3: 200 <-> L4: 100)
+	 * If DMC1 clock gets slower (by original clock speed * n),
+	 * then, the refresh rate should decrease
+	 * (by original refresh count * n) (n : clock rate)
+	 */
+	reg = backup_dmc1_reg * clk_info[index].hclk_msys;
+	reg /= clk_info[backup_freq_level].hclk_msys;
+	__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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,
+					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));
+	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
+			"cpufreq: Performance changed[L%d]\n", index);
+	previous_arm_volt = dvs_conf[index].arm_volt;
+
+	if (first_run)
+		first_run = false;
+out:
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int previous_frequency;
+
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
+		pm_message_t pmsg)
+{
+	int ret = 0;
+	pr_info("cpufreq: Entering suspend.\n");
+
+	previous_frequency = cpufreq_get(0);
+	ret = __cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+			DISABLE_FURTHER_CPUFREQ);
+	return ret;
+}
+
+static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
+{
+	int ret = 0;
+	u32 rate;
+	int level = CPUFREQ_TABLE_END;
+	int i = 0;
+
+	pr_info("cpufreq: Waking up from a suspend.\n");
+
+	__cpufreq_driver_target(cpufreq_cpu_get(0), previous_frequency,
+			ENABLE_FURTHER_CPUFREQ);
+
+	/* Clock information update with wakeup value */
+	rate = clk_get_rate(mpu_clk);
+
+	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
+		if (freq_table[i].frequency * 1000 == rate) {
+			level = freq_table[i].index;
+			break;
+		}
+		i++;
+	}
+
+	if (level == CPUFREQ_TABLE_END) { /* Not found */
+		pr_err("[%s:%d] clock speed does not match: "
+				"%d. Using L1 of 800MHz.\n",
+				__FILE__, __LINE__, rate);
+		level = L1;
+	}
+
+	memcpy(&s3c_freqs.old, &clk_info[level],
+			sizeof(struct s3c_freq));
+	previous_arm_volt = dvs_conf[level].arm_volt;
+	return ret;
+}
+#endif
+
+static int __init s5pv210_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+	u32 rate ;
+	int i, level = CPUFREQ_TABLE_END;
+	struct clk *mpll_clk;
+
+	pr_info("S5PV210 CPUFREQ Initialising...\n");
+#ifdef CONFIG_PM
+	no_cpufreq_access = 0;
+#endif
+	mpu_clk = clk_get(NULL, "armclk");
+	if (IS_ERR(mpu_clk)) {
+		pr_err("S5PV210 CPUFREQ cannot get armclk\n");
+		return PTR_ERR(mpu_clk);
+	}
+
+	if (policy->cpu != 0) {
+		pr_err("S5PV210 CPUFREQ cannot get proper cpu(%d)\n",
+				policy->cpu);
+		return -EINVAL;
+	}
+	policy->cur = policy->min = policy->max = s5pv210_cpufreq_getspeed(0);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	policy->cpuinfo.transition_latency = 40000;	/* 1us */
+
+	rate = clk_get_rate(mpu_clk);
+	i = 0;
+
+	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
+		if (freq_table[i].frequency * 1000 == rate) {
+			level = freq_table[i].index;
+			break;
+		}
+		i++;
+	}
+
+	if (level == CPUFREQ_TABLE_END) { /* Not found */
+		pr_err("[%s:%d] clock speed does not match: "
+				"%d. Using L1 of 800MHz.\n",
+				__FILE__, __LINE__, rate);
+		level = L1;
+	}
+
+	backup_dmc0_reg = __raw_readl(S5P_VA_DMC0 + 0x30) & 0xFFFF;
+	backup_dmc1_reg = __raw_readl(S5P_VA_DMC1 + 0x30) & 0xFFFF;
+	backup_freq_level = level;
+	mpll_clk = clk_get(NULL, "mout_mpll");
+	mpll_freq = clk_get_rate(mpll_clk) / 1000 / 1000; /* in MHz */
+	clk_put(mpll_clk);
+	i = 0;
+	do {
+		int index = freq_table[i].index;
+		if (apll_freq_max < clk_info[index].fclk)
+			apll_freq_max = clk_info[index].fclk;
+		i++;
+	} while (freq_table[i].frequency != CPUFREQ_TABLE_END);
+	apll_freq_max /= 1000; /* in MHz */
+
+	memcpy(&s3c_freqs.old, &clk_info[level],
+			sizeof(struct s3c_freq));
+	previous_arm_volt = dvs_conf[level].arm_volt;
+
+	return cpufreq_frequency_table_cpuinfo(policy, freq_table);
+}
+
+static struct cpufreq_driver s5pv210_cpufreq_driver = {
+	.flags		= CPUFREQ_STICKY,
+	.verify		= s5pv210_cpufreq_verify_speed,
+	.target		= s5pv210_cpufreq_target,
+	.get		= s5pv210_cpufreq_getspeed,
+	.init		= s5pv210_cpufreq_driver_init,
+	.name		= "s5pv210",
+#ifdef CONFIG_PM
+	.suspend	= s5pv210_cpufreq_suspend,
+	.resume		= s5pv210_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv210_cpufreq_init(void)
+{
+	if (s5pv210_revision_evt0())
+		dvs_conf = dvs_conf_evt0;
+
+	arm_regulator = regulator_get_exclusive(NULL, "vddarm");
+	if (IS_ERR(arm_regulator)) {
+		pr_err("failed to get regulater resource vddarm\n");
+		goto error;
+	}
+	internal_regulator = regulator_get_exclusive(NULL, "vddint");
+	if (IS_ERR(internal_regulator)) {
+		pr_err("failed to get regulater resource vddint\n");
+		goto error;
+	}
+	goto finish;
+error:
+	pr_warn("Cannot get vddarm or vddint. CPUFREQ Will not"
+		       " change the voltage.\n");
+finish:
+	return cpufreq_register_driver(&s5pv210_cpufreq_driver);
+}
+
+late_initcall(s5pv210_cpufreq_init);
diff --git a/arch/arm/mach-s5pv210/include/mach/cpu-freq.h b/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
new file mode 100644
index 0000000..76806ab
--- /dev/null
+++ b/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
@@ -0,0 +1,38 @@
+/* arch/arm/mach-s5pv210/include/mach/cpu-freq.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ *       MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * 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 __ASM_ARCH_CPU_FREQ_H
+#define __ASM_ARCH_CPU_FREQ_H
+
+#include <linux/cpufreq.h>
+
+enum perf_level {
+	L0 = 0,
+	L1,
+	L2,
+	L3,
+	L4,
+};
+
+#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 /* CONFIG_PM */
+
+#endif /* __ASM_ARCH_CPU_FREQ_H */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v6 7/7] ARM: S5PV210: Initial CPUFREQ Support
@ 2010-08-03 10:04               ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-03 10:04 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
--
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
v3:
	- Style corrections (pr_info/pr_err, ...)
	- Revised dvs_conf struct
v4:
	- Renamed cpufreq-s5pv210.c -> cpufreq.c
	- Style corrections (less #ifdef's, comments)
	- Removed unncessary codes
	- Remove #ifdef for WORKAROUND, use s5pv210_workaround()
	- Renamed some static variables (get rid of s5pv210 prefix)
	- Added machine dependency to Kconfig/Makefile
	- DMC0, DMC1 refresh counter is not updated by a hardcoded value, but
	with the value given as the default and relative clock speeds. Besides,
	the algorithm to update DMC0/1 refresh counter is reformed.
v5:
	- Remove unnecessary USE_FREQ_TABLE
	- Renamed functions
	- s5pv210_cpufreq_target's initialization revised. (first_run)
	- "workaround" --> "revision"
	- CLK_*_STAT register entries use macros: they are used mutiple
	  times.
v6:
	- Restyled evt0-related codes.

---
 arch/arm/Kconfig                              |    1 +
 arch/arm/mach-s5pv210/Kconfig                 |    5 +
 arch/arm/mach-s5pv210/Makefile                |    2 +
 arch/arm/mach-s5pv210/cpufreq.c               |  802 +++++++++++++++++++++++++
 arch/arm/mach-s5pv210/include/mach/cpu-freq.h |   38 ++
 5 files changed, 848 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
 create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 98922f7..d5a5916 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -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
 
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 631019a..1c6d3bc 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -14,6 +14,7 @@ config CPU_S5PV210
 	select PLAT_S5P
 	select S3C_PL330_DMA
 	select S5P_EXT_INT
+	select S5PV210_CPU_FREQ if CPU_FREQ
 	help
 	  Enable S5PV210 CPU support
 
@@ -101,4 +102,8 @@ config MACH_SMDKC110
 	  Machine support for Samsung SMDKC110
 	  S5PC110(MCP) is one of package option of S5PV210
 
+config S5PV210_CPU_FREQ
+	bool "S5PV210 CPU-FREQ Support"
+	depends on CPU_S5PV210 && CPU_FREQ
+
 endif
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index aae592a..72ca5ec 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -34,3 +34,5 @@ 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
+
+obj-$(CONFIG_S5PV210_CPU_FREQ)		+= cpufreq.o
diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c
new file mode 100644
index 0000000..f394007
--- /dev/null
+++ b/arch/arm/mach-s5pv210/cpufreq.c
@@ -0,0 +1,802 @@
+/*  linux/arch/arm/mach-s5pv210/cpufreq.c
+ *
+ *  Copyright (C) 2010 Samsung Electronics Co., Ltd.
+ *
+ *  CPU frequency scaling for S5PV210/S5PC110
+ *  Based on cpu-sa1110.c and s5pc11x-cpufreq.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;
+
+static unsigned long previous_arm_volt;
+
+static unsigned int backup_dmc0_reg;
+static unsigned int backup_dmc1_reg;
+static unsigned int backup_freq_level;
+static unsigned int mpll_freq; /* in MHz */
+static unsigned int apll_freq_max; /* in MHz */
+
+/* frequency */
+static struct cpufreq_frequency_table freq_table[] = {
+	{L0, 1000*1000},
+	{L1, 800*1000},
+	{L2, 400*1000},
+	{L3, 200*1000},
+	{L4, 100*1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+struct s5pv210_dvs_conf {
+	unsigned long       arm_volt;   /* uV */
+	unsigned long       int_volt;   /* uV */
+};
+
+const unsigned long arm_volt_max = 1350000;
+const unsigned long int_volt_max = 1250000;
+
+static struct s5pv210_dvs_conf dvs_conf_evt0[] = {
+	[L0] = {
+		.arm_volt   = 1300000,
+		.int_volt   = 1200000,
+	},
+	[L1] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+
+	},
+	[L2] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+
+	},
+	[L3] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+	},
+	[L4] = {
+		.arm_volt   = 1250000,
+		.int_volt   = 1200000,
+	},
+};
+static struct s5pv210_dvs_conf dvs_conf_default[] = {
+	[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 struct s5pv210_dvs_conf *dvs_conf = dvs_conf_default;
+
+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 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,
+	},
+};
+
+static int s5pv210_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int s5pv210_cpufreq_getspeed(unsigned int cpu)
+{
+	unsigned long rate;
+
+	if (cpu)
+		return 0;
+
+	rate = clk_get_rate(mpu_clk) / 1000;
+
+	return rate;
+}
+
+static void s5pv210_cpufreq_clksrcs_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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKDIV2_G2D_MASK;
+		reg |= (0x2 << S5P_CLKDIV2_G2D_SHIFT);
+	}
+
+	__raw_writel(reg, S5P_CLK_DIV2);
+
+	/* Wait for MFC, G3D div changing */
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
+	/* Wait for G2D div changing */
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		do {
+			reg = __raw_readl(S5P_CLK_DIV_STAT1);
+		} while  (reg & (S5P_CLKDIV_STAT1_G2D));
+	}
+
+	/*
+	 * 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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKSRC2_G2D_MASK;
+		reg |= (0x1 << S5P_CLKSRC2_G2D_SHIFT);
+	}
+	__raw_writel(reg, S5P_CLK_SRC2);
+
+	if (s5pv210_revision_evt0()) {
+		/* Wait for MFC, G3D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC));
+	} else {
+		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC
+					| S5P_CLKMUX_STAT1_G2D));
+	}
+
+	/* 3. msys: 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 & S5P_CLKMUX_STAT0_MUX200);
+}
+
+static void s5pv210_cpufreq_clksrcs_MPLL2APLL(unsigned int index,
+		unsigned int bus_speed_changing)
+{
+	unsigned int reg;
+
+	/*
+	 * 1. Set Lock time = 30us*24MHz = 02cf (EVT1)
+	 * EVT0			: Lock time = 300us*24Mhz = 7200(0x1c20)
+	 * EVT1 and later	: Lock time = 30us*24Mhz = 0x2cf
+	 */
+	if (s5pv210_revision_evt0())
+		__raw_writel(0x1c20, S5P_APLL_LOCK);
+	else
+		__raw_writel(0x2cf, S5P_APLL_LOCK);
+
+	/*
+	 * 2. Turn on APLL
+	 * 2-1. Set PMS values
+	 */
+	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);
+	/* 2-2. Wait until the PLL is locked */
+	do {
+		reg = __raw_readl(S5P_APLL_CON);
+	} while (!(reg & (0x1 << 29)));
+
+	/*
+	 * 3. 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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKSRC2_G2D_MASK;
+		reg |= 0x1 << S5P_CLKSRC2_G2D_SHIFT;
+	}
+	__raw_writel(reg, S5P_CLK_SRC2);
+
+	if (s5pv210_revision_evt0()) {
+		/* Wait for MFC, G3D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC));
+	} else {
+		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
+		do {
+			reg = __raw_readl(S5P_CLK_MUX_STAT1);
+		} while (reg & (S5P_CLKMUX_STAT1_G3D | S5P_CLKMUX_STAT1_MFC
+					| S5P_CLKMUX_STAT1_G2D));
+	}
+
+	/*
+	 * 4. 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);
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		reg &= ~S5P_CLKDIV2_G2D_MASK;
+		reg |= 0x2 << S5P_CLKDIV2_G2D_SHIFT;
+	}
+	__raw_writel(reg, S5P_CLK_DIV2);
+
+	/* Wait for MFC, G3D div changing */
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT0);
+	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
+	/* Wait for G2D div changing */
+	if (s5pv210_revision_evt0()) {
+		/* Nothing to do for EVT0 */
+	} else {
+		do {
+			reg = __raw_readl(S5P_CLK_DIV_STAT1);
+		} while  (reg & (S5P_CLKDIV_STAT1_G2D));
+	}
+
+	/* 5. 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 & S5P_CLKMUX_STAT0_MUX200);
+}
+
+#ifdef CONFIG_PM
+static int no_cpufreq_access;
+/*
+ * s5pv210_cpufreq_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_cpufreq_target(struct cpufreq_policy *policy,
+		unsigned int target_freq,
+		unsigned int relation)
+{
+	static bool first_run = true;
+	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;
+
+	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
+			"cpufreq: Entering for %dkHz\n", target_freq);
+#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;
+		pr_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
+		pr_err("%s:%d denied access to %s as it is disabled"
+			       " temporarily\n", __FILE__, __LINE__, __func__);
+#endif
+		ret = -EINVAL;
+		goto out;
+	}
+	if (relation & DISABLE_FURTHER_CPUFREQ)
+		no_cpufreq_access = 1;
+	relation &= ~MASK_FURTHER_CPUFREQ;
+#endif
+
+	s3c_freqs.freqs.old = s5pv210_cpufreq_getspeed(0);
+
+	if (cpufreq_frequency_table_target(policy, freq_table,
+				target_freq, relation, &index)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	arm_clk = freq_table[index].frequency;
+
+	s3c_freqs.freqs.new = arm_clk;
+	s3c_freqs.freqs.cpu = 0;
+
+	/*
+	 * Run this function unconditionally until s3c_freqs.freqs.new
+	 * and s3c_freqs.freqs.old are both set by this function.
+	 */
+	if (s3c_freqs.freqs.new == s3c_freqs.freqs.old && !first_run)
+		return 0;
+
+	arm_volt = dvs_conf[index].arm_volt;
+	int_volt = dvs_conf[index].int_volt;
+
+	/* New clock information update */
+	memcpy(&s3c_freqs.new, &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 || first_run)
+		pll_changing = 1;
+
+	if (s3c_freqs.new.hclk_msys != s3c_freqs.old.hclk_msys || first_run)
+		bus_speed_changing = 1;
+
+	/*
+	 * If ONEDRAM(DMC0)'s clock is getting slower, DMC0's
+	 * refresh counter should decrease before slowing down
+	 * DMC0 clock. We assume that DMC0's source clock never
+	 * changes. This is a temporary setting for the transition.
+	 * Stable setting is done at the end of this function.
+	 */
+	reg = (__raw_readl(S5P_CLK_DIV6) & S5P_CLKDIV6_ONEDRAM_MASK)
+		>> S5P_CLKDIV6_ONEDRAM_SHIFT;
+	if (clkdiv_val[index][8] > reg) {
+		reg = backup_dmc0_reg * (reg + 1) / (clkdiv_val[index][8] + 1);
+		WARN_ON(reg > 0xFFFF);
+		reg &= 0xFFFF;
+		__raw_writel(reg, S5P_VA_DMC0 + 0x30);
+	}
+
+	/*
+	 * If hclk_msys (for DMC1) is getting slower, DMC1's
+	 * refresh counter should decrease before slowing down
+	 * hclk_msys in order to get rid of glitches in the
+	 * transition. This is temporary setting for the transition.
+	 * Stable setting is done at the end of this function.
+	 *
+	 * Besides, we need to consider the case when PLL speed changes,
+	 * where the DMC1's source clock hclk_msys is changed from ARMCLK
+	 * to MPLL temporarily. DMC1 needs to be ready for this
+	 * transition as well.
+	 */
+	if (s3c_freqs.new.hclk_msys < s3c_freqs.old.hclk_msys || first_run) {
+		/*
+		 * hclk_msys is up to 12bit. (200000)
+		 * reg is 16bit. so no overflow, yet.
+		 *
+		 * May need to use div64.h later with larger hclk_msys or
+		 * DMCx refresh counter. But, we have bugs in do_div and
+		 * that should be fixed before.
+		 */
+		reg = backup_dmc1_reg * s3c_freqs.new.hclk_msys;
+		reg /= clk_info[backup_freq_level].hclk_msys;
+
+		/*
+		 * When ARM_CLK is absed on APLL->MPLL,
+		 * hclk_msys becomes hclk_msys *= MPLL/APLL;
+		 *
+		 * Based on the worst case scenario, we use MPLL/APLL_MAX
+		 * assuming that MPLL clock speed does not change.
+		 *
+		 * Multiplied first in order to reduce rounding error.
+		 * because reg has 15b length, using 64b should be enough to
+		 * prevent overflow.
+		 */
+		if (pll_changing) {
+			reg *= mpll_freq;
+			reg /= apll_freq_max;
+		}
+		WARN_ON(reg > 0xFFFF);
+		__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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_cpufreq_clksrcs_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_cpufreq_clksrcs_MPLL2APLL(index, bus_speed_changing);
+
+	/*
+	 * Adjust DMC0 refresh ratio according to the rate of DMC0
+	 * The DIV value of DMC0 clock changes and SRC value is not controlled.
+	 * We assume that no one changes SRC value of DMC0 clock, either.
+	 */
+	reg = __raw_readl(S5P_CLK_DIV6);
+	reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
+	reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
+	/* ONEDRAM(DMC0) Clock Divider Ratio: 7+1 for L4, 3+1 for Others */
+	__raw_writel(reg, S5P_CLK_DIV6);
+	do {
+		reg = __raw_readl(S5P_CLK_DIV_STAT1);
+	} while (reg & (1 << 15));
+
+	/*
+	 * If DMC0 clock gets slower (by orginal clock speed / n),
+	 * then, the refresh rate should decrease
+	 * (by original refresh count / n) (n: divider)
+	 */
+	reg = backup_dmc0_reg * (clkdiv_val[backup_freq_level][8] + 1)
+		/ (clkdiv_val[index][8] + 1);
+	__raw_writel(reg & 0xFFFF, S5P_VA_DMC0 + 0x30);
+
+	/*
+	 * Adjust DMC1 refresh ratio according to the rate of hclk_msys
+	 * (L0~L3: 200 <-> L4: 100)
+	 * If DMC1 clock gets slower (by original clock speed * n),
+	 * then, the refresh rate should decrease
+	 * (by original refresh count * n) (n : clock rate)
+	 */
+	reg = backup_dmc1_reg * clk_info[index].hclk_msys;
+	reg /= clk_info[backup_freq_level].hclk_msys;
+	__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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,
+					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));
+	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
+			"cpufreq: Performance changed[L%d]\n", index);
+	previous_arm_volt = dvs_conf[index].arm_volt;
+
+	if (first_run)
+		first_run = false;
+out:
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int previous_frequency;
+
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
+		pm_message_t pmsg)
+{
+	int ret = 0;
+	pr_info("cpufreq: Entering suspend.\n");
+
+	previous_frequency = cpufreq_get(0);
+	ret = __cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
+			DISABLE_FURTHER_CPUFREQ);
+	return ret;
+}
+
+static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
+{
+	int ret = 0;
+	u32 rate;
+	int level = CPUFREQ_TABLE_END;
+	int i = 0;
+
+	pr_info("cpufreq: Waking up from a suspend.\n");
+
+	__cpufreq_driver_target(cpufreq_cpu_get(0), previous_frequency,
+			ENABLE_FURTHER_CPUFREQ);
+
+	/* Clock information update with wakeup value */
+	rate = clk_get_rate(mpu_clk);
+
+	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
+		if (freq_table[i].frequency * 1000 == rate) {
+			level = freq_table[i].index;
+			break;
+		}
+		i++;
+	}
+
+	if (level == CPUFREQ_TABLE_END) { /* Not found */
+		pr_err("[%s:%d] clock speed does not match: "
+				"%d. Using L1 of 800MHz.\n",
+				__FILE__, __LINE__, rate);
+		level = L1;
+	}
+
+	memcpy(&s3c_freqs.old, &clk_info[level],
+			sizeof(struct s3c_freq));
+	previous_arm_volt = dvs_conf[level].arm_volt;
+	return ret;
+}
+#endif
+
+static int __init s5pv210_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+	u32 rate ;
+	int i, level = CPUFREQ_TABLE_END;
+	struct clk *mpll_clk;
+
+	pr_info("S5PV210 CPUFREQ Initialising...\n");
+#ifdef CONFIG_PM
+	no_cpufreq_access = 0;
+#endif
+	mpu_clk = clk_get(NULL, "armclk");
+	if (IS_ERR(mpu_clk)) {
+		pr_err("S5PV210 CPUFREQ cannot get armclk\n");
+		return PTR_ERR(mpu_clk);
+	}
+
+	if (policy->cpu != 0) {
+		pr_err("S5PV210 CPUFREQ cannot get proper cpu(%d)\n",
+				policy->cpu);
+		return -EINVAL;
+	}
+	policy->cur = policy->min = policy->max = s5pv210_cpufreq_getspeed(0);
+
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	policy->cpuinfo.transition_latency = 40000;	/* 1us */
+
+	rate = clk_get_rate(mpu_clk);
+	i = 0;
+
+	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
+		if (freq_table[i].frequency * 1000 == rate) {
+			level = freq_table[i].index;
+			break;
+		}
+		i++;
+	}
+
+	if (level == CPUFREQ_TABLE_END) { /* Not found */
+		pr_err("[%s:%d] clock speed does not match: "
+				"%d. Using L1 of 800MHz.\n",
+				__FILE__, __LINE__, rate);
+		level = L1;
+	}
+
+	backup_dmc0_reg = __raw_readl(S5P_VA_DMC0 + 0x30) & 0xFFFF;
+	backup_dmc1_reg = __raw_readl(S5P_VA_DMC1 + 0x30) & 0xFFFF;
+	backup_freq_level = level;
+	mpll_clk = clk_get(NULL, "mout_mpll");
+	mpll_freq = clk_get_rate(mpll_clk) / 1000 / 1000; /* in MHz */
+	clk_put(mpll_clk);
+	i = 0;
+	do {
+		int index = freq_table[i].index;
+		if (apll_freq_max < clk_info[index].fclk)
+			apll_freq_max = clk_info[index].fclk;
+		i++;
+	} while (freq_table[i].frequency != CPUFREQ_TABLE_END);
+	apll_freq_max /= 1000; /* in MHz */
+
+	memcpy(&s3c_freqs.old, &clk_info[level],
+			sizeof(struct s3c_freq));
+	previous_arm_volt = dvs_conf[level].arm_volt;
+
+	return cpufreq_frequency_table_cpuinfo(policy, freq_table);
+}
+
+static struct cpufreq_driver s5pv210_cpufreq_driver = {
+	.flags		= CPUFREQ_STICKY,
+	.verify		= s5pv210_cpufreq_verify_speed,
+	.target		= s5pv210_cpufreq_target,
+	.get		= s5pv210_cpufreq_getspeed,
+	.init		= s5pv210_cpufreq_driver_init,
+	.name		= "s5pv210",
+#ifdef CONFIG_PM
+	.suspend	= s5pv210_cpufreq_suspend,
+	.resume		= s5pv210_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv210_cpufreq_init(void)
+{
+	if (s5pv210_revision_evt0())
+		dvs_conf = dvs_conf_evt0;
+
+	arm_regulator = regulator_get_exclusive(NULL, "vddarm");
+	if (IS_ERR(arm_regulator)) {
+		pr_err("failed to get regulater resource vddarm\n");
+		goto error;
+	}
+	internal_regulator = regulator_get_exclusive(NULL, "vddint");
+	if (IS_ERR(internal_regulator)) {
+		pr_err("failed to get regulater resource vddint\n");
+		goto error;
+	}
+	goto finish;
+error:
+	pr_warn("Cannot get vddarm or vddint. CPUFREQ Will not"
+		       " change the voltage.\n");
+finish:
+	return cpufreq_register_driver(&s5pv210_cpufreq_driver);
+}
+
+late_initcall(s5pv210_cpufreq_init);
diff --git a/arch/arm/mach-s5pv210/include/mach/cpu-freq.h b/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
new file mode 100644
index 0000000..76806ab
--- /dev/null
+++ b/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
@@ -0,0 +1,38 @@
+/* arch/arm/mach-s5pv210/include/mach/cpu-freq.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ *       MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * 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 __ASM_ARCH_CPU_FREQ_H
+#define __ASM_ARCH_CPU_FREQ_H
+
+#include <linux/cpufreq.h>
+
+enum perf_level {
+	L0 = 0,
+	L1,
+	L2,
+	L3,
+	L4,
+};
+
+#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 /* CONFIG_PM */
+
+#endif /* __ASM_ARCH_CPU_FREQ_H */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* RE: [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
  2010-08-03 10:04           ` MyungJoo Ham
@ 2010-08-04 11:17             ` Kukjin Kim
  -1 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:17 UTC (permalink / raw)
  To: 'MyungJoo Ham', linux-arm-kernel
  Cc: kyungmin.park, myungjoo.ham, ben-linux, linux-samsung-soc

MyungJoo Ham wrote:
> 
> 	The CPUFREQ driver requires an access to DMCx registers. We
> define physical addresses and mapping between physical and virtual
> addresses of DMCx registers.
> 
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
>  arch/arm/mach-s5pv210/include/mach/map.h |    4 ++++
>  2 files changed, 15 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
> index 74d4c08..2066695 100644
> --- a/arch/arm/mach-s5pv210/cpu.c
> +++ b/arch/arm/mach-s5pv210/cpu.c
> @@ -60,7 +60,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(S5PV210_PA_DMC0),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	}, {
> +		.virtual	= (unsigned long)S5P_VA_DMC1,
> +		.pfn		= __phys_to_pfn(S5PV210_PA_DMC1),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	},
>  };
> 
>  static void s5pv210_idle(void)
> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
> s5pv210/include/mach/map.h
> index 17687f0..daf6456 100644
> --- a/arch/arm/mach-s5pv210/include/mach/map.h
> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
> @@ -108,4 +108,8 @@
>  #define SAMSUNG_PA_ADC		S5PV210_PA_ADC
>  #define SAMSUNG_PA_KEYPAD	S5PV210_PA_KEYPAD
> 
> +/* DMC */

No need an obvious comment like above...

> +#define S5PV210_PA_DMC0		(0xF0000000)
> +#define S5PV210_PA_DMC1		(0xF1400000)

As I said, if you need adding new definition into the mach/map.h, please
keep the address order like others.
It can help to us for easily reading...

> +
>  #endif /* __ASM_ARCH_MAP_H */
> --

And as I commented, to merge your 4th(previous, just adding VA) and 5th
patch to one is better...just for adding DMC map IO.


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
@ 2010-08-04 11:17             ` Kukjin Kim
  0 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

MyungJoo Ham wrote:
> 
> 	The CPUFREQ driver requires an access to DMCx registers. We
> define physical addresses and mapping between physical and virtual
> addresses of DMCx registers.
> 
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
>  arch/arm/mach-s5pv210/include/mach/map.h |    4 ++++
>  2 files changed, 15 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
> index 74d4c08..2066695 100644
> --- a/arch/arm/mach-s5pv210/cpu.c
> +++ b/arch/arm/mach-s5pv210/cpu.c
> @@ -60,7 +60,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(S5PV210_PA_DMC0),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	}, {
> +		.virtual	= (unsigned long)S5P_VA_DMC1,
> +		.pfn		= __phys_to_pfn(S5PV210_PA_DMC1),
> +		.length		= SZ_4K,
> +		.type		= MT_DEVICE,
> +	},
>  };
> 
>  static void s5pv210_idle(void)
> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
> s5pv210/include/mach/map.h
> index 17687f0..daf6456 100644
> --- a/arch/arm/mach-s5pv210/include/mach/map.h
> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
> @@ -108,4 +108,8 @@
>  #define SAMSUNG_PA_ADC		S5PV210_PA_ADC
>  #define SAMSUNG_PA_KEYPAD	S5PV210_PA_KEYPAD
> 
> +/* DMC */

No need an obvious comment like above...

> +#define S5PV210_PA_DMC0		(0xF0000000)
> +#define S5PV210_PA_DMC1		(0xF1400000)

As I said, if you need adding new definition into the mach/map.h, please
keep the address order like others.
It can help to us for easily reading...

> +
>  #endif /* __ASM_ARCH_MAP_H */
> --

And as I commented, to merge your 4th(previous, just adding VA) and 5th
patch to one is better...just for adding DMC map IO.


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* RE: [PATCH v6 1/7] ARM: S5PV210: Allow to probe EVT revision number.
  2010-08-03 10:04   ` MyungJoo Ham
@ 2010-08-04 11:29     ` Kukjin Kim
  -1 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:29 UTC (permalink / raw)
  To: 'MyungJoo Ham', linux-arm-kernel
  Cc: kyungmin.park, myungjoo.ham, ben-linux, linux-samsung-soc

MyungJoo Ham wrote:
> 
> Early products of S5PV210, EVT0, had several errata that require
> kernel to avoid using some parts/instructions of the CPU or to
> add protection instructions. There are products with such early
> production CPUs; thus, we want to distinguish them in kernel.
> This patch is to distinguish such products.
> 
> Include <mach/hardware.h> and call s5pv210_revision().
> 
> For example,
> 
> 	if (s5pv210_revision(EVT0)) {
> 		... execute code targeted only to EVT0 ...
> 	} else {
> 		... execute normal code ...
> 	}
> 
> Call set_s5pv210_revision(EVTx) when the EVT revision number can be
> identified. We have EVT0, EVT1, and EVT1-Fused avaialble right now and
> only EVT1-Fused has the unique revision number at chipid (PRO_ID
> register). A function, get_s5pv210_revision_chipid(), returns EVT
> revision number if the revision is identified by the chipid; otherwise,
> the function returns EVT_UNKNOWN. When EVT cannot be identified with
> chipid, it can be identified at board support file
> (arch/arm/mach-s5pv210/mach-*.c), not at the cpu file
> (arch/arm/mach-s5pv210/cpu.c).
> 
> For Aquila machine. (mach-aquila.c)
> 
> Part of Aquila machines have the early production CPUs that require
> to address errata issues. Note that we don't do this for GONI machines
> because they have never used early production CPUs with errata. Besides,
> please note that there are other boards that use such early produces
> other than Aquila. However, those boards/machines are not registered at
> the /linux/arch/arm/tools/mach-types, yet; thus, we have omitted them
> in this patch.
> 
> For Goni machine. (mach-goni.c)
> 
> It's either EVT1 or EVT1-Fused; thus, it can be identified by
> get_s5pv210_revision_chipid() function.
> 
I think, your commit description(message) need to update with your changes.

> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> --
> v5 updates:
> 	- rename revision check function.
> 	- revise revision check functions so that it does not access
> 	  board-related information.
> 	- chipid is used to identify EVT revision.
> 	- added "s5pv210_revision_or_later()" function
> v6 updates:
> 	- removed consideration for EVT1-FUSED
> 
> ---
>  arch/arm/mach-s5pv210/cpu.c                   |   13 +++++++++++++
>  arch/arm/mach-s5pv210/include/mach/hardware.h |   12 +++++++++++-
>  arch/arm/mach-s5pv210/mach-aquila.c           |    9 +++++++++
>  arch/arm/mach-s5pv210/mach-goni.c             |    3 +++
>  4 files changed, 36 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
> index 94c632b..74d4c08 100644
> --- a/arch/arm/mach-s5pv210/cpu.c
> +++ b/arch/arm/mach-s5pv210/cpu.c
> @@ -27,6 +27,7 @@
>  #include <asm/proc-fns.h>
>  #include <mach/map.h>
>  #include <mach/regs-clock.h>
> +#include <mach/hardware.h>
> 
>  #include <plat/cpu.h>
>  #include <plat/devs.h>
> @@ -128,6 +129,18 @@ static struct sys_device s5pv210_sysdev = {
>  	.cls	= &s5pv210_sysclass,
>  };
> 
> +static bool s5pv210_evt0;
> +
> +bool s5pv210_revision_evt0(void)
> +{
> +	return s5pv210_evt0 == true;
> +}
> +
> +void set_s5pv210_revision_evt0(bool evt0)
> +{
> +	s5pv210_evt0 = evt0;
> +}
> +

I'm not sure we _really_ need above functions...just one of extern variable
such as 's5pv210_evt_version' can handle this functionality...?

>  static int __init s5pv210_core_init(void)
>  {
>  	return sysdev_class_register(&s5pv210_sysclass);
> diff --git a/arch/arm/mach-s5pv210/include/mach/hardware.h
b/arch/arm/mach-
> s5pv210/include/mach/hardware.h
> index fada7a3..fa50868 100644
> --- a/arch/arm/mach-s5pv210/include/mach/hardware.h
> +++ b/arch/arm/mach-s5pv210/include/mach/hardware.h
> @@ -13,6 +13,16 @@
>  #ifndef __ASM_ARCH_HARDWARE_H
>  #define __ASM_ARCH_HARDWARE_H __FILE__
> 
> -/* currently nothing here, placeholder */
> +extern bool s5pv210_revision_evt0(void);
> +extern void set_s5pv210_revision_evt0(bool);
> +
> +/*
> + * get_s5pv210_revision_chipid returns s5pv210_revision if the
> + * EVT revision can be determined by the chipid(PRO_ID) register.
> + * However, note that only EVT1-FUSED can be identified from it and
> + * it cannot distinguish between EVT0 and EVT1. In such case, it
> + * returns EVT_UNKNOWN. In such case use set_s5pv210_revision() to
> + * set the revision number manually.
> + */
> 
>  #endif /* __ASM_ARCH_HARDWARE_H */
> diff --git a/arch/arm/mach-s5pv210/mach-aquila.c
b/arch/arm/mach-s5pv210/mach-
> aquila.c
> index 46d5c7e..6a8deaa 100644
> --- a/arch/arm/mach-s5pv210/mach-aquila.c
> +++ b/arch/arm/mach-s5pv210/mach-aquila.c
> @@ -30,6 +30,7 @@
>  #include <mach/regs-clock.h>
>  #include <mach/regs-fb.h>
>  #include <mach/gpio.h>
> +#include <mach/hardware.h>
> 
>  #include <plat/gpio-cfg.h>
>  #include <plat/regs-serial.h>
> @@ -536,6 +537,14 @@ static void __init aquila_map_io(void)
> 
>  static void __init aquila_machine_init(void)
>  {
> +	/* CPU Revision (EVTx) */
> +	set_s5pv210_revision_evt0(false);
> +	if (system_rev & 0x0800) {
> +		if ((system_rev & 0xF) < 8)

...

> +			set_s5pv210_revision_evt0(true);
> +	} else if (system_rev & 0x2000)
> +		set_s5pv210_revision_evt0(true);
> +
>  	/* PMIC */
>  	aquila_pmic_init();
>  	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4,
> i2c_gpio_pmic_devs,
> diff --git a/arch/arm/mach-s5pv210/mach-goni.c
b/arch/arm/mach-s5pv210/mach-
> goni.c
> index 380d2ae..08ee3f6 100644
> --- a/arch/arm/mach-s5pv210/mach-goni.c
> +++ b/arch/arm/mach-s5pv210/mach-goni.c
> @@ -32,6 +32,7 @@
>  #include <mach/regs-clock.h>
>  #include <mach/regs-fb.h>
>  #include <mach/gpio.h>
> +#include <mach/hardware.h>
> 
>  #include <plat/gpio-cfg.h>
>  #include <plat/regs-serial.h>
> @@ -520,6 +521,8 @@ static void __init goni_map_io(void)
> 
>  static void __init goni_machine_init(void)
>  {
> +	set_s5pv210_revision_evt0(false);
> +
>  	/* PMIC */
>  	goni_pmic_init();
>  	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4,
> i2c_gpio_pmic_devs,
> --


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 1/7] ARM: S5PV210: Allow to probe EVT revision number.
@ 2010-08-04 11:29     ` Kukjin Kim
  0 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

MyungJoo Ham wrote:
> 
> Early products of S5PV210, EVT0, had several errata that require
> kernel to avoid using some parts/instructions of the CPU or to
> add protection instructions. There are products with such early
> production CPUs; thus, we want to distinguish them in kernel.
> This patch is to distinguish such products.
> 
> Include <mach/hardware.h> and call s5pv210_revision().
> 
> For example,
> 
> 	if (s5pv210_revision(EVT0)) {
> 		... execute code targeted only to EVT0 ...
> 	} else {
> 		... execute normal code ...
> 	}
> 
> Call set_s5pv210_revision(EVTx) when the EVT revision number can be
> identified. We have EVT0, EVT1, and EVT1-Fused avaialble right now and
> only EVT1-Fused has the unique revision number at chipid (PRO_ID
> register). A function, get_s5pv210_revision_chipid(), returns EVT
> revision number if the revision is identified by the chipid; otherwise,
> the function returns EVT_UNKNOWN. When EVT cannot be identified with
> chipid, it can be identified at board support file
> (arch/arm/mach-s5pv210/mach-*.c), not at the cpu file
> (arch/arm/mach-s5pv210/cpu.c).
> 
> For Aquila machine. (mach-aquila.c)
> 
> Part of Aquila machines have the early production CPUs that require
> to address errata issues. Note that we don't do this for GONI machines
> because they have never used early production CPUs with errata. Besides,
> please note that there are other boards that use such early produces
> other than Aquila. However, those boards/machines are not registered at
> the /linux/arch/arm/tools/mach-types, yet; thus, we have omitted them
> in this patch.
> 
> For Goni machine. (mach-goni.c)
> 
> It's either EVT1 or EVT1-Fused; thus, it can be identified by
> get_s5pv210_revision_chipid() function.
> 
I think, your commit description(message) need to update with your changes.

> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> --
> v5 updates:
> 	- rename revision check function.
> 	- revise revision check functions so that it does not access
> 	  board-related information.
> 	- chipid is used to identify EVT revision.
> 	- added "s5pv210_revision_or_later()" function
> v6 updates:
> 	- removed consideration for EVT1-FUSED
> 
> ---
>  arch/arm/mach-s5pv210/cpu.c                   |   13 +++++++++++++
>  arch/arm/mach-s5pv210/include/mach/hardware.h |   12 +++++++++++-
>  arch/arm/mach-s5pv210/mach-aquila.c           |    9 +++++++++
>  arch/arm/mach-s5pv210/mach-goni.c             |    3 +++
>  4 files changed, 36 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
> index 94c632b..74d4c08 100644
> --- a/arch/arm/mach-s5pv210/cpu.c
> +++ b/arch/arm/mach-s5pv210/cpu.c
> @@ -27,6 +27,7 @@
>  #include <asm/proc-fns.h>
>  #include <mach/map.h>
>  #include <mach/regs-clock.h>
> +#include <mach/hardware.h>
> 
>  #include <plat/cpu.h>
>  #include <plat/devs.h>
> @@ -128,6 +129,18 @@ static struct sys_device s5pv210_sysdev = {
>  	.cls	= &s5pv210_sysclass,
>  };
> 
> +static bool s5pv210_evt0;
> +
> +bool s5pv210_revision_evt0(void)
> +{
> +	return s5pv210_evt0 == true;
> +}
> +
> +void set_s5pv210_revision_evt0(bool evt0)
> +{
> +	s5pv210_evt0 = evt0;
> +}
> +

I'm not sure we _really_ need above functions...just one of extern variable
such as 's5pv210_evt_version' can handle this functionality...?

>  static int __init s5pv210_core_init(void)
>  {
>  	return sysdev_class_register(&s5pv210_sysclass);
> diff --git a/arch/arm/mach-s5pv210/include/mach/hardware.h
b/arch/arm/mach-
> s5pv210/include/mach/hardware.h
> index fada7a3..fa50868 100644
> --- a/arch/arm/mach-s5pv210/include/mach/hardware.h
> +++ b/arch/arm/mach-s5pv210/include/mach/hardware.h
> @@ -13,6 +13,16 @@
>  #ifndef __ASM_ARCH_HARDWARE_H
>  #define __ASM_ARCH_HARDWARE_H __FILE__
> 
> -/* currently nothing here, placeholder */
> +extern bool s5pv210_revision_evt0(void);
> +extern void set_s5pv210_revision_evt0(bool);
> +
> +/*
> + * get_s5pv210_revision_chipid returns s5pv210_revision if the
> + * EVT revision can be determined by the chipid(PRO_ID) register.
> + * However, note that only EVT1-FUSED can be identified from it and
> + * it cannot distinguish between EVT0 and EVT1. In such case, it
> + * returns EVT_UNKNOWN. In such case use set_s5pv210_revision() to
> + * set the revision number manually.
> + */
> 
>  #endif /* __ASM_ARCH_HARDWARE_H */
> diff --git a/arch/arm/mach-s5pv210/mach-aquila.c
b/arch/arm/mach-s5pv210/mach-
> aquila.c
> index 46d5c7e..6a8deaa 100644
> --- a/arch/arm/mach-s5pv210/mach-aquila.c
> +++ b/arch/arm/mach-s5pv210/mach-aquila.c
> @@ -30,6 +30,7 @@
>  #include <mach/regs-clock.h>
>  #include <mach/regs-fb.h>
>  #include <mach/gpio.h>
> +#include <mach/hardware.h>
> 
>  #include <plat/gpio-cfg.h>
>  #include <plat/regs-serial.h>
> @@ -536,6 +537,14 @@ static void __init aquila_map_io(void)
> 
>  static void __init aquila_machine_init(void)
>  {
> +	/* CPU Revision (EVTx) */
> +	set_s5pv210_revision_evt0(false);
> +	if (system_rev & 0x0800) {
> +		if ((system_rev & 0xF) < 8)

...

> +			set_s5pv210_revision_evt0(true);
> +	} else if (system_rev & 0x2000)
> +		set_s5pv210_revision_evt0(true);
> +
>  	/* PMIC */
>  	aquila_pmic_init();
>  	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4,
> i2c_gpio_pmic_devs,
> diff --git a/arch/arm/mach-s5pv210/mach-goni.c
b/arch/arm/mach-s5pv210/mach-
> goni.c
> index 380d2ae..08ee3f6 100644
> --- a/arch/arm/mach-s5pv210/mach-goni.c
> +++ b/arch/arm/mach-s5pv210/mach-goni.c
> @@ -32,6 +32,7 @@
>  #include <mach/regs-clock.h>
>  #include <mach/regs-fb.h>
>  #include <mach/gpio.h>
> +#include <mach/hardware.h>
> 
>  #include <plat/gpio-cfg.h>
>  #include <plat/regs-serial.h>
> @@ -520,6 +521,8 @@ static void __init goni_map_io(void)
> 
>  static void __init goni_machine_init(void)
>  {
> +	set_s5pv210_revision_evt0(false);
> +
>  	/* PMIC */
>  	goni_pmic_init();
>  	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4,
> i2c_gpio_pmic_devs,
> --


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* RE: [PATCH v6 6/7] ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
  2010-08-03 10:04             ` MyungJoo Ham
@ 2010-08-04 11:34               ` Kukjin Kim
  -1 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:34 UTC (permalink / raw)
  To: 'MyungJoo Ham', linux-arm-kernel
  Cc: kyungmin.park, myungjoo.ham, ben-linux, linux-samsung-soc

MyungJoo Ham wrote:
> 
> 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. Besides, later, we will probably need to use these macros
> at arch/arm/mach-s5pv210/clock.c as well especially for entries that are
> used out of clock.c as well.
> 
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  arch/arm/mach-s5pv210/include/mach/regs-clock.h |   60
> +++++++++++++++++++++-
>  1 files changed, 57 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
b/arch/arm/mach-
> s5pv210/include/mach/regs-clock.h
> index 2a25ab4..f370ae8 100644
> --- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
> +++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
> @@ -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)

I didn't find anywhere above definitions are used....
As I said, please don't add unnecessary definitions.

> +#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)

Same...unnecessary.

> 
>  /* CLKDIV0 */
>  #define S5P_CLKDIV0_APLL_SHIFT		(0)
> @@ -90,6 +109,41 @@
>  #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)
> +
> +/* CLK_DIV_STAT0 */
> +#define S5P_CLKDIV_STAT0_G3D		(1 << 16)
> +#define S5P_CLKDIV_STAT0_MFC		(1 << 17)
> +
> +/* CLK_DIV_STAT1 */
> +#define S5P_CLKDIV_STAT1_G2D		(1 << 20)
> +
> +/* CLK_MUX_STAT0 */
> +#define S5P_CLKMUX_STAT0_MUX200		(1 << 18)
> +
> +/* CLK_MUX_STAT1 */
> +#define S5P_CLKMUX_STAT1_G3D		(1 << 3)
> +#define S5P_CLKMUX_STAT1_MFC		(1 << 7)
> +#define S5P_CLKMUX_STAT1_G2D		(1 << 27)
> +
>  /* Registers related to power management */
>  #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
>  #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
> --


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 6/7] ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT)
@ 2010-08-04 11:34               ` Kukjin Kim
  0 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

MyungJoo Ham wrote:
> 
> 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. Besides, later, we will probably need to use these macros
> at arch/arm/mach-s5pv210/clock.c as well especially for entries that are
> used out of clock.c as well.
> 
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  arch/arm/mach-s5pv210/include/mach/regs-clock.h |   60
> +++++++++++++++++++++-
>  1 files changed, 57 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
b/arch/arm/mach-
> s5pv210/include/mach/regs-clock.h
> index 2a25ab4..f370ae8 100644
> --- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
> +++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
> @@ -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)

I didn't find anywhere above definitions are used....
As I said, please don't add unnecessary definitions.

> +#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)

Same...unnecessary.

> 
>  /* CLKDIV0 */
>  #define S5P_CLKDIV0_APLL_SHIFT		(0)
> @@ -90,6 +109,41 @@
>  #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)
> +
> +/* CLK_DIV_STAT0 */
> +#define S5P_CLKDIV_STAT0_G3D		(1 << 16)
> +#define S5P_CLKDIV_STAT0_MFC		(1 << 17)
> +
> +/* CLK_DIV_STAT1 */
> +#define S5P_CLKDIV_STAT1_G2D		(1 << 20)
> +
> +/* CLK_MUX_STAT0 */
> +#define S5P_CLKMUX_STAT0_MUX200		(1 << 18)
> +
> +/* CLK_MUX_STAT1 */
> +#define S5P_CLKMUX_STAT1_G3D		(1 << 3)
> +#define S5P_CLKMUX_STAT1_MFC		(1 << 7)
> +#define S5P_CLKMUX_STAT1_G2D		(1 << 27)
> +
>  /* Registers related to power management */
>  #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
>  #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
> --


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* RE: [PATCH v6 7/7] ARM: S5PV210: Initial CPUFREQ Support
  2010-08-03 10:04               ` MyungJoo Ham
@ 2010-08-04 11:44                 ` Kukjin Kim
  -1 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:44 UTC (permalink / raw)
  To: 'MyungJoo Ham', linux-arm-kernel
  Cc: kyungmin.park, myungjoo.ham, ben-linux, linux-samsung-soc

MyungJoo Ham wrote:
> 
> 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.
> 
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> --
> 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
> v3:
> 	- Style corrections (pr_info/pr_err, ...)
> 	- Revised dvs_conf struct
> v4:
> 	- Renamed cpufreq-s5pv210.c -> cpufreq.c
> 	- Style corrections (less #ifdef's, comments)
> 	- Removed unncessary codes
> 	- Remove #ifdef for WORKAROUND, use s5pv210_workaround()
> 	- Renamed some static variables (get rid of s5pv210 prefix)
> 	- Added machine dependency to Kconfig/Makefile
> 	- DMC0, DMC1 refresh counter is not updated by a hardcoded value,
but
> 	with the value given as the default and relative clock speeds.
Besides,
> 	the algorithm to update DMC0/1 refresh counter is reformed.
> v5:
> 	- Remove unnecessary USE_FREQ_TABLE
> 	- Renamed functions
> 	- s5pv210_cpufreq_target's initialization revised. (first_run)
> 	- "workaround" --> "revision"
> 	- CLK_*_STAT register entries use macros: they are used mutiple
> 	  times.
> v6:
> 	- Restyled evt0-related codes.
> 
> ---
>  arch/arm/Kconfig                              |    1 +
>  arch/arm/mach-s5pv210/Kconfig                 |    5 +
>  arch/arm/mach-s5pv210/Makefile                |    2 +
>  arch/arm/mach-s5pv210/cpufreq.c               |  802
> +++++++++++++++++++++++++
>  arch/arm/mach-s5pv210/include/mach/cpu-freq.h |   38 ++
>  5 files changed, 848 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
>  create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 98922f7..d5a5916 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -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
> 
> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
> index 631019a..1c6d3bc 100644
> --- a/arch/arm/mach-s5pv210/Kconfig
> +++ b/arch/arm/mach-s5pv210/Kconfig
> @@ -14,6 +14,7 @@ config CPU_S5PV210
>  	select PLAT_S5P
>  	select S3C_PL330_DMA
>  	select S5P_EXT_INT
> +	select S5PV210_CPU_FREQ if CPU_FREQ

Maybe as you know, can't use this with DDR2...
So right now, the selection should being in each machine config.

>  	help
>  	  Enable S5PV210 CPU support
> 
> @@ -101,4 +102,8 @@ config MACH_SMDKC110
>  	  Machine support for Samsung SMDKC110
>  	  S5PC110(MCP) is one of package option of S5PV210
> 
> +config S5PV210_CPU_FREQ
> +	bool "S5PV210 CPU-FREQ Support"
> +	depends on CPU_S5PV210 && CPU_FREQ
> +
>  endif
> diff --git a/arch/arm/mach-s5pv210/Makefile
b/arch/arm/mach-s5pv210/Makefile
> index aae592a..72ca5ec 100644
> --- a/arch/arm/mach-s5pv210/Makefile
> +++ b/arch/arm/mach-s5pv210/Makefile
> @@ -34,3 +34,5 @@ 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
> +
> +obj-$(CONFIG_S5PV210_CPU_FREQ)		+= cpufreq.o
> diff --git a/arch/arm/mach-s5pv210/cpufreq.c
b/arch/arm/mach-s5pv210/cpufreq.c
> new file mode 100644
> index 0000000..f394007
> --- /dev/null
> +++ b/arch/arm/mach-s5pv210/cpufreq.c
> @@ -0,0 +1,802 @@
> +/*  linux/arch/arm/mach-s5pv210/cpufreq.c
> + *
> + *  Copyright (C) 2010 Samsung Electronics Co., Ltd.
> + *
> + *  CPU frequency scaling for S5PV210/S5PC110
> + *  Based on cpu-sa1110.c and s5pc11x-cpufreq.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;
> +
> +static unsigned long previous_arm_volt;
> +
> +static unsigned int backup_dmc0_reg;
> +static unsigned int backup_dmc1_reg;
> +static unsigned int backup_freq_level;
> +static unsigned int mpll_freq; /* in MHz */
> +static unsigned int apll_freq_max; /* in MHz */
> +
> +/* frequency */
> +static struct cpufreq_frequency_table freq_table[] = {
> +	{L0, 1000*1000},
> +	{L1, 800*1000},
> +	{L2, 400*1000},
> +	{L3, 200*1000},
> +	{L4, 100*1000},
> +	{0, CPUFREQ_TABLE_END},
> +};
> +
> +struct s5pv210_dvs_conf {
> +	unsigned long       arm_volt;   /* uV */
> +	unsigned long       int_volt;   /* uV */
> +};
> +
> +const unsigned long arm_volt_max = 1350000;
> +const unsigned long int_volt_max = 1250000;
> +
> +static struct s5pv210_dvs_conf dvs_conf_evt0[] = {
> +	[L0] = {
> +		.arm_volt   = 1300000,
> +		.int_volt   = 1200000,
> +	},
> +	[L1] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +
> +	},
> +	[L2] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +
> +	},
> +	[L3] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +	},
> +	[L4] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +	},
> +};
> +static struct s5pv210_dvs_conf dvs_conf_default[] = {
> +	[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 struct s5pv210_dvs_conf *dvs_conf = dvs_conf_default;
> +
> +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 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,
> +	},
> +};
> +
> +static int s5pv210_cpufreq_verify_speed(struct cpufreq_policy *policy)
> +{
> +	if (policy->cpu)
> +		return -EINVAL;
> +
> +	return cpufreq_frequency_table_verify(policy, freq_table);
> +}
> +
> +static unsigned int s5pv210_cpufreq_getspeed(unsigned int cpu)
> +{
> +	unsigned long rate;
> +
> +	if (cpu)
> +		return 0;
> +
> +	rate = clk_get_rate(mpu_clk) / 1000;
> +
> +	return rate;
> +}
> +
> +static void s5pv210_cpufreq_clksrcs_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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKDIV2_G2D_MASK;
> +		reg |= (0x2 << S5P_CLKDIV2_G2D_SHIFT);
> +	}
> +
> +	__raw_writel(reg, S5P_CLK_DIV2);
> +
> +	/* Wait for MFC, G3D div changing */
> +	do {
> +		reg = __raw_readl(S5P_CLK_DIV_STAT0);
> +	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
> +	/* Wait for G2D div changing */
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		do {
> +			reg = __raw_readl(S5P_CLK_DIV_STAT1);
> +		} while  (reg & (S5P_CLKDIV_STAT1_G2D));

Maybe you remember Ben's comment in the SRC/DIV status check patch.
I think, in this case, some inline function can reduce duplicate do {} while
().

> +	}
> +
> +	/*
> +	 * 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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKSRC2_G2D_MASK;
> +		reg |= (0x1 << S5P_CLKSRC2_G2D_SHIFT);
> +	}
> +	__raw_writel(reg, S5P_CLK_SRC2);
> +
> +	if (s5pv210_revision_evt0()) {
> +		/* Wait for MFC, G3D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC));

Here...

> +	} else {
> +		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC
> +					| S5P_CLKMUX_STAT1_G2D));

Here...

> +	}
> +
> +	/* 3. msys: 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 & S5P_CLKMUX_STAT0_MUX200);

Here...

> +}
> +
> +static void s5pv210_cpufreq_clksrcs_MPLL2APLL(unsigned int index,
> +		unsigned int bus_speed_changing)
> +{
> +	unsigned int reg;
> +
> +	/*
> +	 * 1. Set Lock time = 30us*24MHz = 02cf (EVT1)
> +	 * EVT0			: Lock time = 300us*24Mhz = 7200(0x1c20)
> +	 * EVT1 and later	: Lock time = 30us*24Mhz = 0x2cf
> +	 */
> +	if (s5pv210_revision_evt0())
> +		__raw_writel(0x1c20, S5P_APLL_LOCK);
> +	else
> +		__raw_writel(0x2cf, S5P_APLL_LOCK);
> +
> +	/*
> +	 * 2. Turn on APLL
> +	 * 2-1. Set PMS values
> +	 */
> +	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);
> +	/* 2-2. Wait until the PLL is locked */
> +	do {
> +		reg = __raw_readl(S5P_APLL_CON);
> +	} while (!(reg & (0x1 << 29)));
> +
> +	/*
> +	 * 3. 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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKSRC2_G2D_MASK;
> +		reg |= 0x1 << S5P_CLKSRC2_G2D_SHIFT;
> +	}
> +	__raw_writel(reg, S5P_CLK_SRC2);
> +
> +	if (s5pv210_revision_evt0()) {
> +		/* Wait for MFC, G3D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC));
> +	} else {
> +		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC
> +					| S5P_CLKMUX_STAT1_G2D));
> +	}
> +
> +	/*
> +	 * 4. 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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKDIV2_G2D_MASK;
> +		reg |= 0x2 << S5P_CLKDIV2_G2D_SHIFT;
> +	}
> +	__raw_writel(reg, S5P_CLK_DIV2);
> +
> +	/* Wait for MFC, G3D div changing */
> +	do {
> +		reg = __raw_readl(S5P_CLK_DIV_STAT0);
> +	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
> +	/* Wait for G2D div changing */
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		do {
> +			reg = __raw_readl(S5P_CLK_DIV_STAT1);
> +		} while  (reg & (S5P_CLKDIV_STAT1_G2D));
> +	}
> +
> +	/* 5. 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 & S5P_CLKMUX_STAT0_MUX200);
> +}
> +
> +#ifdef CONFIG_PM
> +static int no_cpufreq_access;
> +/*
> + * s5pv210_cpufreq_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_cpufreq_target(struct cpufreq_policy *policy,
> +		unsigned int target_freq,
> +		unsigned int relation)
> +{
> +	static bool first_run = true;
> +	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;
> +
> +	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
> +			"cpufreq: Entering for %dkHz\n", target_freq);
> +#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;
> +		pr_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
> +		pr_err("%s:%d denied access to %s as it is disabled"
> +			       " temporarily\n", __FILE__, __LINE__,
__func__);
> +#endif
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +	if (relation & DISABLE_FURTHER_CPUFREQ)
> +		no_cpufreq_access = 1;
> +	relation &= ~MASK_FURTHER_CPUFREQ;
> +#endif
> +
> +	s3c_freqs.freqs.old = s5pv210_cpufreq_getspeed(0);
> +
> +	if (cpufreq_frequency_table_target(policy, freq_table,
> +				target_freq, relation, &index)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	arm_clk = freq_table[index].frequency;
> +
> +	s3c_freqs.freqs.new = arm_clk;
> +	s3c_freqs.freqs.cpu = 0;
> +
> +	/*
> +	 * Run this function unconditionally until s3c_freqs.freqs.new
> +	 * and s3c_freqs.freqs.old are both set by this function.
> +	 */
> +	if (s3c_freqs.freqs.new == s3c_freqs.freqs.old && !first_run)
> +		return 0;
> +
> +	arm_volt = dvs_conf[index].arm_volt;
> +	int_volt = dvs_conf[index].int_volt;
> +
> +	/* New clock information update */
> +	memcpy(&s3c_freqs.new, &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 || first_run)
> +		pll_changing = 1;
> +
> +	if (s3c_freqs.new.hclk_msys != s3c_freqs.old.hclk_msys || first_run)
> +		bus_speed_changing = 1;
> +
> +	/*
> +	 * If ONEDRAM(DMC0)'s clock is getting slower, DMC0's
> +	 * refresh counter should decrease before slowing down
> +	 * DMC0 clock. We assume that DMC0's source clock never
> +	 * changes. This is a temporary setting for the transition.
> +	 * Stable setting is done at the end of this function.
> +	 */
> +	reg = (__raw_readl(S5P_CLK_DIV6) & S5P_CLKDIV6_ONEDRAM_MASK)
> +		>> S5P_CLKDIV6_ONEDRAM_SHIFT;
> +	if (clkdiv_val[index][8] > reg) {
> +		reg = backup_dmc0_reg * (reg + 1) / (clkdiv_val[index][8] +
1);
> +		WARN_ON(reg > 0xFFFF);
> +		reg &= 0xFFFF;
> +		__raw_writel(reg, S5P_VA_DMC0 + 0x30);
> +	}
> +
> +	/*
> +	 * If hclk_msys (for DMC1) is getting slower, DMC1's
> +	 * refresh counter should decrease before slowing down
> +	 * hclk_msys in order to get rid of glitches in the
> +	 * transition. This is temporary setting for the transition.
> +	 * Stable setting is done at the end of this function.
> +	 *
> +	 * Besides, we need to consider the case when PLL speed changes,
> +	 * where the DMC1's source clock hclk_msys is changed from ARMCLK
> +	 * to MPLL temporarily. DMC1 needs to be ready for this
> +	 * transition as well.
> +	 */
> +	if (s3c_freqs.new.hclk_msys < s3c_freqs.old.hclk_msys || first_run)
{
> +		/*
> +		 * hclk_msys is up to 12bit. (200000)
> +		 * reg is 16bit. so no overflow, yet.
> +		 *
> +		 * May need to use div64.h later with larger hclk_msys or
> +		 * DMCx refresh counter. But, we have bugs in do_div and
> +		 * that should be fixed before.
> +		 */
> +		reg = backup_dmc1_reg * s3c_freqs.new.hclk_msys;
> +		reg /= clk_info[backup_freq_level].hclk_msys;
> +
> +		/*
> +		 * When ARM_CLK is absed on APLL->MPLL,
> +		 * hclk_msys becomes hclk_msys *= MPLL/APLL;
> +		 *
> +		 * Based on the worst case scenario, we use MPLL/APLL_MAX
> +		 * assuming that MPLL clock speed does not change.
> +		 *
> +		 * Multiplied first in order to reduce rounding error.
> +		 * because reg has 15b length, using 64b should be enough to
> +		 * prevent overflow.
> +		 */
> +		if (pll_changing) {
> +			reg *= mpll_freq;
> +			reg /= apll_freq_max;
> +		}
> +		WARN_ON(reg > 0xFFFF);
> +		__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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_cpufreq_clksrcs_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_cpufreq_clksrcs_MPLL2APLL(index,
> bus_speed_changing);
> +
> +	/*
> +	 * Adjust DMC0 refresh ratio according to the rate of DMC0
> +	 * The DIV value of DMC0 clock changes and SRC value is not
controlled.
> +	 * We assume that no one changes SRC value of DMC0 clock, either.
> +	 */
> +	reg = __raw_readl(S5P_CLK_DIV6);
> +	reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
> +	reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
> +	/* ONEDRAM(DMC0) Clock Divider Ratio: 7+1 for L4, 3+1 for Others */
> +	__raw_writel(reg, S5P_CLK_DIV6);
> +	do {
> +		reg = __raw_readl(S5P_CLK_DIV_STAT1);
> +	} while (reg & (1 << 15));
> +
> +	/*
> +	 * If DMC0 clock gets slower (by orginal clock speed / n),
> +	 * then, the refresh rate should decrease
> +	 * (by original refresh count / n) (n: divider)
> +	 */
> +	reg = backup_dmc0_reg * (clkdiv_val[backup_freq_level][8] + 1)
> +		/ (clkdiv_val[index][8] + 1);
> +	__raw_writel(reg & 0xFFFF, S5P_VA_DMC0 + 0x30);
> +
> +	/*
> +	 * Adjust DMC1 refresh ratio according to the rate of hclk_msys
> +	 * (L0~L3: 200 <-> L4: 100)
> +	 * If DMC1 clock gets slower (by original clock speed * n),
> +	 * then, the refresh rate should decrease
> +	 * (by original refresh count * n) (n : clock rate)
> +	 */
> +	reg = backup_dmc1_reg * clk_info[index].hclk_msys;
> +	reg /= clk_info[backup_freq_level].hclk_msys;
> +	__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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,
> +					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));
> +	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
> +			"cpufreq: Performance changed[L%d]\n", index);
> +	previous_arm_volt = dvs_conf[index].arm_volt;
> +
> +	if (first_run)
> +		first_run = false;
> +out:
> +	return ret;
> +}
> +
> +#ifdef CONFIG_PM
> +static int previous_frequency;
> +
> +static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
> +		pm_message_t pmsg)
> +{
> +	int ret = 0;
> +	pr_info("cpufreq: Entering suspend.\n");
> +
> +	previous_frequency = cpufreq_get(0);
> +	ret = __cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
> +			DISABLE_FURTHER_CPUFREQ);
> +	return ret;
> +}
> +
> +static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
> +{
> +	int ret = 0;
> +	u32 rate;
> +	int level = CPUFREQ_TABLE_END;
> +	int i = 0;
> +
> +	pr_info("cpufreq: Waking up from a suspend.\n");
> +
> +	__cpufreq_driver_target(cpufreq_cpu_get(0), previous_frequency,
> +			ENABLE_FURTHER_CPUFREQ);
> +
> +	/* Clock information update with wakeup value */
> +	rate = clk_get_rate(mpu_clk);
> +
> +	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
> +		if (freq_table[i].frequency * 1000 == rate) {
> +			level = freq_table[i].index;
> +			break;
> +		}
> +		i++;
> +	}
> +
> +	if (level == CPUFREQ_TABLE_END) { /* Not found */
> +		pr_err("[%s:%d] clock speed does not match: "
> +				"%d. Using L1 of 800MHz.\n",
> +				__FILE__, __LINE__, rate);
> +		level = L1;
> +	}
> +
> +	memcpy(&s3c_freqs.old, &clk_info[level],
> +			sizeof(struct s3c_freq));
> +	previous_arm_volt = dvs_conf[level].arm_volt;
> +	return ret;
> +}
> +#endif
> +
> +static int __init s5pv210_cpufreq_driver_init(struct cpufreq_policy
*policy)
> +{
> +	u32 rate ;
> +	int i, level = CPUFREQ_TABLE_END;
> +	struct clk *mpll_clk;
> +
> +	pr_info("S5PV210 CPUFREQ Initialising...\n");
> +#ifdef CONFIG_PM
> +	no_cpufreq_access = 0;
> +#endif
> +	mpu_clk = clk_get(NULL, "armclk");
> +	if (IS_ERR(mpu_clk)) {
> +		pr_err("S5PV210 CPUFREQ cannot get armclk\n");
> +		return PTR_ERR(mpu_clk);
> +	}
> +
> +	if (policy->cpu != 0) {
> +		pr_err("S5PV210 CPUFREQ cannot get proper cpu(%d)\n",
> +				policy->cpu);
> +		return -EINVAL;
> +	}
> +	policy->cur = policy->min = policy->max =
s5pv210_cpufreq_getspeed(0);
> +
> +	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
> +
> +	policy->cpuinfo.transition_latency = 40000;	/* 1us */
> +
> +	rate = clk_get_rate(mpu_clk);
> +	i = 0;
> +
> +	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
> +		if (freq_table[i].frequency * 1000 == rate) {
> +			level = freq_table[i].index;
> +			break;
> +		}
> +		i++;
> +	}
> +
> +	if (level == CPUFREQ_TABLE_END) { /* Not found */
> +		pr_err("[%s:%d] clock speed does not match: "
> +				"%d. Using L1 of 800MHz.\n",
> +				__FILE__, __LINE__, rate);
> +		level = L1;
> +	}
> +
> +	backup_dmc0_reg = __raw_readl(S5P_VA_DMC0 + 0x30) & 0xFFFF;
> +	backup_dmc1_reg = __raw_readl(S5P_VA_DMC1 + 0x30) & 0xFFFF;
> +	backup_freq_level = level;
> +	mpll_clk = clk_get(NULL, "mout_mpll");
> +	mpll_freq = clk_get_rate(mpll_clk) / 1000 / 1000; /* in MHz */
> +	clk_put(mpll_clk);
> +	i = 0;
> +	do {
> +		int index = freq_table[i].index;
> +		if (apll_freq_max < clk_info[index].fclk)
> +			apll_freq_max = clk_info[index].fclk;
> +		i++;
> +	} while (freq_table[i].frequency != CPUFREQ_TABLE_END);
> +	apll_freq_max /= 1000; /* in MHz */
> +
> +	memcpy(&s3c_freqs.old, &clk_info[level],
> +			sizeof(struct s3c_freq));
> +	previous_arm_volt = dvs_conf[level].arm_volt;
> +
> +	return cpufreq_frequency_table_cpuinfo(policy, freq_table);
> +}
> +
> +static struct cpufreq_driver s5pv210_cpufreq_driver = {
> +	.flags		= CPUFREQ_STICKY,
> +	.verify		= s5pv210_cpufreq_verify_speed,
> +	.target		= s5pv210_cpufreq_target,
> +	.get		= s5pv210_cpufreq_getspeed,
> +	.init		= s5pv210_cpufreq_driver_init,
> +	.name		= "s5pv210",
> +#ifdef CONFIG_PM
> +	.suspend	= s5pv210_cpufreq_suspend,
> +	.resume		= s5pv210_cpufreq_resume,
> +#endif
> +};
> +
> +static int __init s5pv210_cpufreq_init(void)
> +{
> +	if (s5pv210_revision_evt0())
> +		dvs_conf = dvs_conf_evt0;
> +
> +	arm_regulator = regulator_get_exclusive(NULL, "vddarm");
> +	if (IS_ERR(arm_regulator)) {
> +		pr_err("failed to get regulater resource vddarm\n");
> +		goto error;
> +	}
> +	internal_regulator = regulator_get_exclusive(NULL, "vddint");
> +	if (IS_ERR(internal_regulator)) {
> +		pr_err("failed to get regulater resource vddint\n");
> +		goto error;
> +	}
> +	goto finish;
> +error:
> +	pr_warn("Cannot get vddarm or vddint. CPUFREQ Will not"
> +		       " change the voltage.\n");
> +finish:
> +	return cpufreq_register_driver(&s5pv210_cpufreq_driver);
> +}
> +
> +late_initcall(s5pv210_cpufreq_init);
> diff --git a/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
b/arch/arm/mach-
> s5pv210/include/mach/cpu-freq.h
> new file mode 100644
> index 0000000..76806ab
> --- /dev/null
> +++ b/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
> @@ -0,0 +1,38 @@
> +/* arch/arm/mach-s5pv210/include/mach/cpu-freq.h
> + *
> + * Copyright (c) 2010 Samsung Electronics
> + *
> + *       MyungJoo Ham <myungjoo.ham@samsung.com>
> + *
> + * 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 __ASM_ARCH_CPU_FREQ_H
> +#define __ASM_ARCH_CPU_FREQ_H
> +
> +#include <linux/cpufreq.h>
> +
> +enum perf_level {
> +	L0 = 0,
> +	L1,
> +	L2,
> +	L3,
> +	L4,
> +};
> +
> +#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 /* CONFIG_PM */
> +
> +#endif /* __ASM_ARCH_CPU_FREQ_H */
> --


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 7/7] ARM: S5PV210: Initial CPUFREQ Support
@ 2010-08-04 11:44                 ` Kukjin Kim
  0 siblings, 0 replies; 28+ messages in thread
From: Kukjin Kim @ 2010-08-04 11:44 UTC (permalink / raw)
  To: linux-arm-kernel

MyungJoo Ham wrote:
> 
> 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.
> 
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> --
> 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
> v3:
> 	- Style corrections (pr_info/pr_err, ...)
> 	- Revised dvs_conf struct
> v4:
> 	- Renamed cpufreq-s5pv210.c -> cpufreq.c
> 	- Style corrections (less #ifdef's, comments)
> 	- Removed unncessary codes
> 	- Remove #ifdef for WORKAROUND, use s5pv210_workaround()
> 	- Renamed some static variables (get rid of s5pv210 prefix)
> 	- Added machine dependency to Kconfig/Makefile
> 	- DMC0, DMC1 refresh counter is not updated by a hardcoded value,
but
> 	with the value given as the default and relative clock speeds.
Besides,
> 	the algorithm to update DMC0/1 refresh counter is reformed.
> v5:
> 	- Remove unnecessary USE_FREQ_TABLE
> 	- Renamed functions
> 	- s5pv210_cpufreq_target's initialization revised. (first_run)
> 	- "workaround" --> "revision"
> 	- CLK_*_STAT register entries use macros: they are used mutiple
> 	  times.
> v6:
> 	- Restyled evt0-related codes.
> 
> ---
>  arch/arm/Kconfig                              |    1 +
>  arch/arm/mach-s5pv210/Kconfig                 |    5 +
>  arch/arm/mach-s5pv210/Makefile                |    2 +
>  arch/arm/mach-s5pv210/cpufreq.c               |  802
> +++++++++++++++++++++++++
>  arch/arm/mach-s5pv210/include/mach/cpu-freq.h |   38 ++
>  5 files changed, 848 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
>  create mode 100644 arch/arm/mach-s5pv210/include/mach/cpu-freq.h
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 98922f7..d5a5916 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -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
> 
> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
> index 631019a..1c6d3bc 100644
> --- a/arch/arm/mach-s5pv210/Kconfig
> +++ b/arch/arm/mach-s5pv210/Kconfig
> @@ -14,6 +14,7 @@ config CPU_S5PV210
>  	select PLAT_S5P
>  	select S3C_PL330_DMA
>  	select S5P_EXT_INT
> +	select S5PV210_CPU_FREQ if CPU_FREQ

Maybe as you know, can't use this with DDR2...
So right now, the selection should being in each machine config.

>  	help
>  	  Enable S5PV210 CPU support
> 
> @@ -101,4 +102,8 @@ config MACH_SMDKC110
>  	  Machine support for Samsung SMDKC110
>  	  S5PC110(MCP) is one of package option of S5PV210
> 
> +config S5PV210_CPU_FREQ
> +	bool "S5PV210 CPU-FREQ Support"
> +	depends on CPU_S5PV210 && CPU_FREQ
> +
>  endif
> diff --git a/arch/arm/mach-s5pv210/Makefile
b/arch/arm/mach-s5pv210/Makefile
> index aae592a..72ca5ec 100644
> --- a/arch/arm/mach-s5pv210/Makefile
> +++ b/arch/arm/mach-s5pv210/Makefile
> @@ -34,3 +34,5 @@ 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
> +
> +obj-$(CONFIG_S5PV210_CPU_FREQ)		+= cpufreq.o
> diff --git a/arch/arm/mach-s5pv210/cpufreq.c
b/arch/arm/mach-s5pv210/cpufreq.c
> new file mode 100644
> index 0000000..f394007
> --- /dev/null
> +++ b/arch/arm/mach-s5pv210/cpufreq.c
> @@ -0,0 +1,802 @@
> +/*  linux/arch/arm/mach-s5pv210/cpufreq.c
> + *
> + *  Copyright (C) 2010 Samsung Electronics Co., Ltd.
> + *
> + *  CPU frequency scaling for S5PV210/S5PC110
> + *  Based on cpu-sa1110.c and s5pc11x-cpufreq.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;
> +
> +static unsigned long previous_arm_volt;
> +
> +static unsigned int backup_dmc0_reg;
> +static unsigned int backup_dmc1_reg;
> +static unsigned int backup_freq_level;
> +static unsigned int mpll_freq; /* in MHz */
> +static unsigned int apll_freq_max; /* in MHz */
> +
> +/* frequency */
> +static struct cpufreq_frequency_table freq_table[] = {
> +	{L0, 1000*1000},
> +	{L1, 800*1000},
> +	{L2, 400*1000},
> +	{L3, 200*1000},
> +	{L4, 100*1000},
> +	{0, CPUFREQ_TABLE_END},
> +};
> +
> +struct s5pv210_dvs_conf {
> +	unsigned long       arm_volt;   /* uV */
> +	unsigned long       int_volt;   /* uV */
> +};
> +
> +const unsigned long arm_volt_max = 1350000;
> +const unsigned long int_volt_max = 1250000;
> +
> +static struct s5pv210_dvs_conf dvs_conf_evt0[] = {
> +	[L0] = {
> +		.arm_volt   = 1300000,
> +		.int_volt   = 1200000,
> +	},
> +	[L1] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +
> +	},
> +	[L2] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +
> +	},
> +	[L3] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +	},
> +	[L4] = {
> +		.arm_volt   = 1250000,
> +		.int_volt   = 1200000,
> +	},
> +};
> +static struct s5pv210_dvs_conf dvs_conf_default[] = {
> +	[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 struct s5pv210_dvs_conf *dvs_conf = dvs_conf_default;
> +
> +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 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,
> +	},
> +};
> +
> +static int s5pv210_cpufreq_verify_speed(struct cpufreq_policy *policy)
> +{
> +	if (policy->cpu)
> +		return -EINVAL;
> +
> +	return cpufreq_frequency_table_verify(policy, freq_table);
> +}
> +
> +static unsigned int s5pv210_cpufreq_getspeed(unsigned int cpu)
> +{
> +	unsigned long rate;
> +
> +	if (cpu)
> +		return 0;
> +
> +	rate = clk_get_rate(mpu_clk) / 1000;
> +
> +	return rate;
> +}
> +
> +static void s5pv210_cpufreq_clksrcs_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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKDIV2_G2D_MASK;
> +		reg |= (0x2 << S5P_CLKDIV2_G2D_SHIFT);
> +	}
> +
> +	__raw_writel(reg, S5P_CLK_DIV2);
> +
> +	/* Wait for MFC, G3D div changing */
> +	do {
> +		reg = __raw_readl(S5P_CLK_DIV_STAT0);
> +	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
> +	/* Wait for G2D div changing */
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		do {
> +			reg = __raw_readl(S5P_CLK_DIV_STAT1);
> +		} while  (reg & (S5P_CLKDIV_STAT1_G2D));

Maybe you remember Ben's comment in the SRC/DIV status check patch.
I think, in this case, some inline function can reduce duplicate do {} while
().

> +	}
> +
> +	/*
> +	 * 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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKSRC2_G2D_MASK;
> +		reg |= (0x1 << S5P_CLKSRC2_G2D_SHIFT);
> +	}
> +	__raw_writel(reg, S5P_CLK_SRC2);
> +
> +	if (s5pv210_revision_evt0()) {
> +		/* Wait for MFC, G3D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC));

Here...

> +	} else {
> +		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC
> +					| S5P_CLKMUX_STAT1_G2D));

Here...

> +	}
> +
> +	/* 3. msys: 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 & S5P_CLKMUX_STAT0_MUX200);

Here...

> +}
> +
> +static void s5pv210_cpufreq_clksrcs_MPLL2APLL(unsigned int index,
> +		unsigned int bus_speed_changing)
> +{
> +	unsigned int reg;
> +
> +	/*
> +	 * 1. Set Lock time = 30us*24MHz = 02cf (EVT1)
> +	 * EVT0			: Lock time = 300us*24Mhz = 7200(0x1c20)
> +	 * EVT1 and later	: Lock time = 30us*24Mhz = 0x2cf
> +	 */
> +	if (s5pv210_revision_evt0())
> +		__raw_writel(0x1c20, S5P_APLL_LOCK);
> +	else
> +		__raw_writel(0x2cf, S5P_APLL_LOCK);
> +
> +	/*
> +	 * 2. Turn on APLL
> +	 * 2-1. Set PMS values
> +	 */
> +	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);
> +	/* 2-2. Wait until the PLL is locked */
> +	do {
> +		reg = __raw_readl(S5P_APLL_CON);
> +	} while (!(reg & (0x1 << 29)));
> +
> +	/*
> +	 * 3. 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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKSRC2_G2D_MASK;
> +		reg |= 0x1 << S5P_CLKSRC2_G2D_SHIFT;
> +	}
> +	__raw_writel(reg, S5P_CLK_SRC2);
> +
> +	if (s5pv210_revision_evt0()) {
> +		/* Wait for MFC, G3D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC));
> +	} else {
> +		/* EVT1 or later: wait for MFC, G3D, G2D mux changing */
> +		do {
> +			reg = __raw_readl(S5P_CLK_MUX_STAT1);
> +		} while (reg & (S5P_CLKMUX_STAT1_G3D |
> S5P_CLKMUX_STAT1_MFC
> +					| S5P_CLKMUX_STAT1_G2D));
> +	}
> +
> +	/*
> +	 * 4. 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);
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		reg &= ~S5P_CLKDIV2_G2D_MASK;
> +		reg |= 0x2 << S5P_CLKDIV2_G2D_SHIFT;
> +	}
> +	__raw_writel(reg, S5P_CLK_DIV2);
> +
> +	/* Wait for MFC, G3D div changing */
> +	do {
> +		reg = __raw_readl(S5P_CLK_DIV_STAT0);
> +	} while (reg & (S5P_CLKDIV_STAT0_G3D | S5P_CLKDIV_STAT0_MFC));
> +	/* Wait for G2D div changing */
> +	if (s5pv210_revision_evt0()) {
> +		/* Nothing to do for EVT0 */
> +	} else {
> +		do {
> +			reg = __raw_readl(S5P_CLK_DIV_STAT1);
> +		} while  (reg & (S5P_CLKDIV_STAT1_G2D));
> +	}
> +
> +	/* 5. 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 & S5P_CLKMUX_STAT0_MUX200);
> +}
> +
> +#ifdef CONFIG_PM
> +static int no_cpufreq_access;
> +/*
> + * s5pv210_cpufreq_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_cpufreq_target(struct cpufreq_policy *policy,
> +		unsigned int target_freq,
> +		unsigned int relation)
> +{
> +	static bool first_run = true;
> +	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;
> +
> +	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
> +			"cpufreq: Entering for %dkHz\n", target_freq);
> +#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;
> +		pr_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
> +		pr_err("%s:%d denied access to %s as it is disabled"
> +			       " temporarily\n", __FILE__, __LINE__,
__func__);
> +#endif
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +	if (relation & DISABLE_FURTHER_CPUFREQ)
> +		no_cpufreq_access = 1;
> +	relation &= ~MASK_FURTHER_CPUFREQ;
> +#endif
> +
> +	s3c_freqs.freqs.old = s5pv210_cpufreq_getspeed(0);
> +
> +	if (cpufreq_frequency_table_target(policy, freq_table,
> +				target_freq, relation, &index)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	arm_clk = freq_table[index].frequency;
> +
> +	s3c_freqs.freqs.new = arm_clk;
> +	s3c_freqs.freqs.cpu = 0;
> +
> +	/*
> +	 * Run this function unconditionally until s3c_freqs.freqs.new
> +	 * and s3c_freqs.freqs.old are both set by this function.
> +	 */
> +	if (s3c_freqs.freqs.new == s3c_freqs.freqs.old && !first_run)
> +		return 0;
> +
> +	arm_volt = dvs_conf[index].arm_volt;
> +	int_volt = dvs_conf[index].int_volt;
> +
> +	/* New clock information update */
> +	memcpy(&s3c_freqs.new, &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 || first_run)
> +		pll_changing = 1;
> +
> +	if (s3c_freqs.new.hclk_msys != s3c_freqs.old.hclk_msys || first_run)
> +		bus_speed_changing = 1;
> +
> +	/*
> +	 * If ONEDRAM(DMC0)'s clock is getting slower, DMC0's
> +	 * refresh counter should decrease before slowing down
> +	 * DMC0 clock. We assume that DMC0's source clock never
> +	 * changes. This is a temporary setting for the transition.
> +	 * Stable setting is done at the end of this function.
> +	 */
> +	reg = (__raw_readl(S5P_CLK_DIV6) & S5P_CLKDIV6_ONEDRAM_MASK)
> +		>> S5P_CLKDIV6_ONEDRAM_SHIFT;
> +	if (clkdiv_val[index][8] > reg) {
> +		reg = backup_dmc0_reg * (reg + 1) / (clkdiv_val[index][8] +
1);
> +		WARN_ON(reg > 0xFFFF);
> +		reg &= 0xFFFF;
> +		__raw_writel(reg, S5P_VA_DMC0 + 0x30);
> +	}
> +
> +	/*
> +	 * If hclk_msys (for DMC1) is getting slower, DMC1's
> +	 * refresh counter should decrease before slowing down
> +	 * hclk_msys in order to get rid of glitches in the
> +	 * transition. This is temporary setting for the transition.
> +	 * Stable setting is done at the end of this function.
> +	 *
> +	 * Besides, we need to consider the case when PLL speed changes,
> +	 * where the DMC1's source clock hclk_msys is changed from ARMCLK
> +	 * to MPLL temporarily. DMC1 needs to be ready for this
> +	 * transition as well.
> +	 */
> +	if (s3c_freqs.new.hclk_msys < s3c_freqs.old.hclk_msys || first_run)
{
> +		/*
> +		 * hclk_msys is up to 12bit. (200000)
> +		 * reg is 16bit. so no overflow, yet.
> +		 *
> +		 * May need to use div64.h later with larger hclk_msys or
> +		 * DMCx refresh counter. But, we have bugs in do_div and
> +		 * that should be fixed before.
> +		 */
> +		reg = backup_dmc1_reg * s3c_freqs.new.hclk_msys;
> +		reg /= clk_info[backup_freq_level].hclk_msys;
> +
> +		/*
> +		 * When ARM_CLK is absed on APLL->MPLL,
> +		 * hclk_msys becomes hclk_msys *= MPLL/APLL;
> +		 *
> +		 * Based on the worst case scenario, we use MPLL/APLL_MAX
> +		 * assuming that MPLL clock speed does not change.
> +		 *
> +		 * Multiplied first in order to reduce rounding error.
> +		 * because reg has 15b length, using 64b should be enough to
> +		 * prevent overflow.
> +		 */
> +		if (pll_changing) {
> +			reg *= mpll_freq;
> +			reg /= apll_freq_max;
> +		}
> +		WARN_ON(reg > 0xFFFF);
> +		__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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_cpufreq_clksrcs_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_cpufreq_clksrcs_MPLL2APLL(index,
> bus_speed_changing);
> +
> +	/*
> +	 * Adjust DMC0 refresh ratio according to the rate of DMC0
> +	 * The DIV value of DMC0 clock changes and SRC value is not
controlled.
> +	 * We assume that no one changes SRC value of DMC0 clock, either.
> +	 */
> +	reg = __raw_readl(S5P_CLK_DIV6);
> +	reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
> +	reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
> +	/* ONEDRAM(DMC0) Clock Divider Ratio: 7+1 for L4, 3+1 for Others */
> +	__raw_writel(reg, S5P_CLK_DIV6);
> +	do {
> +		reg = __raw_readl(S5P_CLK_DIV_STAT1);
> +	} while (reg & (1 << 15));
> +
> +	/*
> +	 * If DMC0 clock gets slower (by orginal clock speed / n),
> +	 * then, the refresh rate should decrease
> +	 * (by original refresh count / n) (n: divider)
> +	 */
> +	reg = backup_dmc0_reg * (clkdiv_val[backup_freq_level][8] + 1)
> +		/ (clkdiv_val[index][8] + 1);
> +	__raw_writel(reg & 0xFFFF, S5P_VA_DMC0 + 0x30);
> +
> +	/*
> +	 * Adjust DMC1 refresh ratio according to the rate of hclk_msys
> +	 * (L0~L3: 200 <-> L4: 100)
> +	 * If DMC1 clock gets slower (by original clock speed * n),
> +	 * then, the refresh rate should decrease
> +	 * (by original refresh count * n) (n : clock rate)
> +	 */
> +	reg = backup_dmc1_reg * clk_info[index].hclk_msys;
> +	reg /= clk_info[backup_freq_level].hclk_msys;
> +	__raw_writel(reg & 0xFFFF, S5P_VA_DMC1 + 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,
> +					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));
> +	cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, KERN_INFO,
> +			"cpufreq: Performance changed[L%d]\n", index);
> +	previous_arm_volt = dvs_conf[index].arm_volt;
> +
> +	if (first_run)
> +		first_run = false;
> +out:
> +	return ret;
> +}
> +
> +#ifdef CONFIG_PM
> +static int previous_frequency;
> +
> +static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
> +		pm_message_t pmsg)
> +{
> +	int ret = 0;
> +	pr_info("cpufreq: Entering suspend.\n");
> +
> +	previous_frequency = cpufreq_get(0);
> +	ret = __cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ,
> +			DISABLE_FURTHER_CPUFREQ);
> +	return ret;
> +}
> +
> +static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
> +{
> +	int ret = 0;
> +	u32 rate;
> +	int level = CPUFREQ_TABLE_END;
> +	int i = 0;
> +
> +	pr_info("cpufreq: Waking up from a suspend.\n");
> +
> +	__cpufreq_driver_target(cpufreq_cpu_get(0), previous_frequency,
> +			ENABLE_FURTHER_CPUFREQ);
> +
> +	/* Clock information update with wakeup value */
> +	rate = clk_get_rate(mpu_clk);
> +
> +	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
> +		if (freq_table[i].frequency * 1000 == rate) {
> +			level = freq_table[i].index;
> +			break;
> +		}
> +		i++;
> +	}
> +
> +	if (level == CPUFREQ_TABLE_END) { /* Not found */
> +		pr_err("[%s:%d] clock speed does not match: "
> +				"%d. Using L1 of 800MHz.\n",
> +				__FILE__, __LINE__, rate);
> +		level = L1;
> +	}
> +
> +	memcpy(&s3c_freqs.old, &clk_info[level],
> +			sizeof(struct s3c_freq));
> +	previous_arm_volt = dvs_conf[level].arm_volt;
> +	return ret;
> +}
> +#endif
> +
> +static int __init s5pv210_cpufreq_driver_init(struct cpufreq_policy
*policy)
> +{
> +	u32 rate ;
> +	int i, level = CPUFREQ_TABLE_END;
> +	struct clk *mpll_clk;
> +
> +	pr_info("S5PV210 CPUFREQ Initialising...\n");
> +#ifdef CONFIG_PM
> +	no_cpufreq_access = 0;
> +#endif
> +	mpu_clk = clk_get(NULL, "armclk");
> +	if (IS_ERR(mpu_clk)) {
> +		pr_err("S5PV210 CPUFREQ cannot get armclk\n");
> +		return PTR_ERR(mpu_clk);
> +	}
> +
> +	if (policy->cpu != 0) {
> +		pr_err("S5PV210 CPUFREQ cannot get proper cpu(%d)\n",
> +				policy->cpu);
> +		return -EINVAL;
> +	}
> +	policy->cur = policy->min = policy->max =
s5pv210_cpufreq_getspeed(0);
> +
> +	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
> +
> +	policy->cpuinfo.transition_latency = 40000;	/* 1us */
> +
> +	rate = clk_get_rate(mpu_clk);
> +	i = 0;
> +
> +	while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
> +		if (freq_table[i].frequency * 1000 == rate) {
> +			level = freq_table[i].index;
> +			break;
> +		}
> +		i++;
> +	}
> +
> +	if (level == CPUFREQ_TABLE_END) { /* Not found */
> +		pr_err("[%s:%d] clock speed does not match: "
> +				"%d. Using L1 of 800MHz.\n",
> +				__FILE__, __LINE__, rate);
> +		level = L1;
> +	}
> +
> +	backup_dmc0_reg = __raw_readl(S5P_VA_DMC0 + 0x30) & 0xFFFF;
> +	backup_dmc1_reg = __raw_readl(S5P_VA_DMC1 + 0x30) & 0xFFFF;
> +	backup_freq_level = level;
> +	mpll_clk = clk_get(NULL, "mout_mpll");
> +	mpll_freq = clk_get_rate(mpll_clk) / 1000 / 1000; /* in MHz */
> +	clk_put(mpll_clk);
> +	i = 0;
> +	do {
> +		int index = freq_table[i].index;
> +		if (apll_freq_max < clk_info[index].fclk)
> +			apll_freq_max = clk_info[index].fclk;
> +		i++;
> +	} while (freq_table[i].frequency != CPUFREQ_TABLE_END);
> +	apll_freq_max /= 1000; /* in MHz */
> +
> +	memcpy(&s3c_freqs.old, &clk_info[level],
> +			sizeof(struct s3c_freq));
> +	previous_arm_volt = dvs_conf[level].arm_volt;
> +
> +	return cpufreq_frequency_table_cpuinfo(policy, freq_table);
> +}
> +
> +static struct cpufreq_driver s5pv210_cpufreq_driver = {
> +	.flags		= CPUFREQ_STICKY,
> +	.verify		= s5pv210_cpufreq_verify_speed,
> +	.target		= s5pv210_cpufreq_target,
> +	.get		= s5pv210_cpufreq_getspeed,
> +	.init		= s5pv210_cpufreq_driver_init,
> +	.name		= "s5pv210",
> +#ifdef CONFIG_PM
> +	.suspend	= s5pv210_cpufreq_suspend,
> +	.resume		= s5pv210_cpufreq_resume,
> +#endif
> +};
> +
> +static int __init s5pv210_cpufreq_init(void)
> +{
> +	if (s5pv210_revision_evt0())
> +		dvs_conf = dvs_conf_evt0;
> +
> +	arm_regulator = regulator_get_exclusive(NULL, "vddarm");
> +	if (IS_ERR(arm_regulator)) {
> +		pr_err("failed to get regulater resource vddarm\n");
> +		goto error;
> +	}
> +	internal_regulator = regulator_get_exclusive(NULL, "vddint");
> +	if (IS_ERR(internal_regulator)) {
> +		pr_err("failed to get regulater resource vddint\n");
> +		goto error;
> +	}
> +	goto finish;
> +error:
> +	pr_warn("Cannot get vddarm or vddint. CPUFREQ Will not"
> +		       " change the voltage.\n");
> +finish:
> +	return cpufreq_register_driver(&s5pv210_cpufreq_driver);
> +}
> +
> +late_initcall(s5pv210_cpufreq_init);
> diff --git a/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
b/arch/arm/mach-
> s5pv210/include/mach/cpu-freq.h
> new file mode 100644
> index 0000000..76806ab
> --- /dev/null
> +++ b/arch/arm/mach-s5pv210/include/mach/cpu-freq.h
> @@ -0,0 +1,38 @@
> +/* arch/arm/mach-s5pv210/include/mach/cpu-freq.h
> + *
> + * Copyright (c) 2010 Samsung Electronics
> + *
> + *       MyungJoo Ham <myungjoo.ham@samsung.com>
> + *
> + * 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 __ASM_ARCH_CPU_FREQ_H
> +#define __ASM_ARCH_CPU_FREQ_H
> +
> +#include <linux/cpufreq.h>
> +
> +enum perf_level {
> +	L0 = 0,
> +	L1,
> +	L2,
> +	L3,
> +	L4,
> +};
> +
> +#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 /* CONFIG_PM */
> +
> +#endif /* __ASM_ARCH_CPU_FREQ_H */
> --


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
  2010-08-04 11:17             ` Kukjin Kim
@ 2010-08-04 13:36               ` Kyungmin Park
  -1 siblings, 0 replies; 28+ messages in thread
From: Kyungmin Park @ 2010-08-04 13:36 UTC (permalink / raw)
  To: Kukjin Kim
  Cc: MyungJoo Ham, linux-arm-kernel, myungjoo.ham, ben-linux,
	linux-samsung-soc, Marek Szyprowski

On Wed, Aug 4, 2010 at 8:17 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> MyungJoo Ham wrote:
>>
>>       The CPUFREQ driver requires an access to DMCx registers. We
>> define physical addresses and mapping between physical and virtual
>> addresses of DMCx registers.
>>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>  arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
>>  arch/arm/mach-s5pv210/include/mach/map.h |    4 ++++
>>  2 files changed, 15 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
>> index 74d4c08..2066695 100644
>> --- a/arch/arm/mach-s5pv210/cpu.c
>> +++ b/arch/arm/mach-s5pv210/cpu.c
>> @@ -60,7 +60,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(S5PV210_PA_DMC0),
>> +             .length         = SZ_4K,
>> +             .type           = MT_DEVICE,
>> +     }, {
>> +             .virtual        = (unsigned long)S5P_VA_DMC1,
>> +             .pfn            = __phys_to_pfn(S5PV210_PA_DMC1),
>> +             .length         = SZ_4K,
>> +             .type           = MT_DEVICE,
>> +     },
>>  };
>>
>>  static void s5pv210_idle(void)
>> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
>> s5pv210/include/mach/map.h
>> index 17687f0..daf6456 100644
>> --- a/arch/arm/mach-s5pv210/include/mach/map.h
>> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
>> @@ -108,4 +108,8 @@
>>  #define SAMSUNG_PA_ADC               S5PV210_PA_ADC
>>  #define SAMSUNG_PA_KEYPAD    S5PV210_PA_KEYPAD
>>
>> +/* DMC */
>
> No need an obvious comment like above...
>
>> +#define S5PV210_PA_DMC0              (0xF0000000)
>> +#define S5PV210_PA_DMC1              (0xF1400000)
>
> As I said, if you need adding new definition into the mach/map.h, please
> keep the address order like others.
> It can help to us for easily reading...

Good, good, good,

I'm really appreciate it if the same rules apply to LSI internal trees.
I hope you check it LSI codes also.

Thank you,
Kyungmin Park

>
>> +
>>  #endif /* __ASM_ARCH_MAP_H */
>> --
>
> And as I commented, to merge your 4th(previous, just adding VA) and 5th
> patch to one is better...just for adding DMC map IO.
>
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, 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@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
@ 2010-08-04 13:36               ` Kyungmin Park
  0 siblings, 0 replies; 28+ messages in thread
From: Kyungmin Park @ 2010-08-04 13:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 4, 2010 at 8:17 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> MyungJoo Ham wrote:
>>
>> ? ? ? The CPUFREQ driver requires an access to DMCx registers. We
>> define physical addresses and mapping between physical and virtual
>> addresses of DMCx registers.
>>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>> ?arch/arm/mach-s5pv210/cpu.c ? ? ? ? ? ? ?| ? 12 +++++++++++-
>> ?arch/arm/mach-s5pv210/include/mach/map.h | ? ?4 ++++
>> ?2 files changed, 15 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
>> index 74d4c08..2066695 100644
>> --- a/arch/arm/mach-s5pv210/cpu.c
>> +++ b/arch/arm/mach-s5pv210/cpu.c
>> @@ -60,7 +60,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(S5PV210_PA_DMC0),
>> + ? ? ? ? ? ? .length ? ? ? ? = SZ_4K,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? }, {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= (unsigned long)S5P_VA_DMC1,
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(S5PV210_PA_DMC1),
>> + ? ? ? ? ? ? .length ? ? ? ? = SZ_4K,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>> ?};
>>
>> ?static void s5pv210_idle(void)
>> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
>> s5pv210/include/mach/map.h
>> index 17687f0..daf6456 100644
>> --- a/arch/arm/mach-s5pv210/include/mach/map.h
>> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
>> @@ -108,4 +108,8 @@
>> ?#define SAMSUNG_PA_ADC ? ? ? ? ? ? ? S5PV210_PA_ADC
>> ?#define SAMSUNG_PA_KEYPAD ? ?S5PV210_PA_KEYPAD
>>
>> +/* DMC */
>
> No need an obvious comment like above...
>
>> +#define S5PV210_PA_DMC0 ? ? ? ? ? ? ?(0xF0000000)
>> +#define S5PV210_PA_DMC1 ? ? ? ? ? ? ?(0xF1400000)
>
> As I said, if you need adding new definition into the mach/map.h, please
> keep the address order like others.
> It can help to us for easily reading...

Good, good, good,

I'm really appreciate it if the same rules apply to LSI internal trees.
I hope you check it LSI codes also.

Thank you,
Kyungmin Park

>
>> +
>> ?#endif /* __ASM_ARCH_MAP_H */
>> --
>
> And as I commented, to merge your 4th(previous, just adding VA) and 5th
> patch to one is better...just for adding DMC map IO.
>
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, 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
>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
  2010-08-04 11:17             ` Kukjin Kim
@ 2010-08-10  5:29               ` MyungJoo Ham
  -1 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-10  5:29 UTC (permalink / raw)
  To: Kukjin Kim; +Cc: linux-arm-kernel, kyungmin.park, ben-linux, linux-samsung-soc

On Wed, Aug 4, 2010 at 8:17 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> MyungJoo Ham wrote:
>>
>>       The CPUFREQ driver requires an access to DMCx registers. We
>> define physical addresses and mapping between physical and virtual
>> addresses of DMCx registers.
>>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>  arch/arm/mach-s5pv210/cpu.c              |   12 +++++++++++-
>>  arch/arm/mach-s5pv210/include/mach/map.h |    4 ++++
>>  2 files changed, 15 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
>> index 74d4c08..2066695 100644
>> --- a/arch/arm/mach-s5pv210/cpu.c
>> +++ b/arch/arm/mach-s5pv210/cpu.c
>> @@ -60,7 +60,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(S5PV210_PA_DMC0),
>> +             .length         = SZ_4K,
>> +             .type           = MT_DEVICE,
>> +     }, {
>> +             .virtual        = (unsigned long)S5P_VA_DMC1,
>> +             .pfn            = __phys_to_pfn(S5PV210_PA_DMC1),
>> +             .length         = SZ_4K,
>> +             .type           = MT_DEVICE,
>> +     },
>>  };
>>
>>  static void s5pv210_idle(void)
>> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
>> s5pv210/include/mach/map.h
>> index 17687f0..daf6456 100644
>> --- a/arch/arm/mach-s5pv210/include/mach/map.h
>> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
>> @@ -108,4 +108,8 @@
>>  #define SAMSUNG_PA_ADC               S5PV210_PA_ADC
>>  #define SAMSUNG_PA_KEYPAD    S5PV210_PA_KEYPAD
>>
>> +/* DMC */
>
> No need an obvious comment like above...
>
>> +#define S5PV210_PA_DMC0              (0xF0000000)
>> +#define S5PV210_PA_DMC1              (0xF1400000)
>
> As I said, if you need adding new definition into the mach/map.h, please
> keep the address order like others.
> It can help to us for easily reading...


Umm.. where would be the in-order place for these two? The order of
addresses is already mixed up in this file and wherever these two go,
it cannot be "in-order". If we are going to reorder things in this
file, it should be done separately.

>
>> +
>>  #endif /* __ASM_ARCH_MAP_H */
>> --
>
> And as I commented, to merge your 4th(previous, just adding VA) and 5th
> patch to one is better...just for adding DMC map IO.

Ok, will be done at v7.

>
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
>

ps. Anyway, sorry for the late reply, I've been away for a while.

-- 
MyungJoo Ham (함명주), Ph.D.
Mobile Software Platform Lab,
Digital Media and Communications (DMC) Business
Samsung Electronics
cell: 82-10-6714-2858

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers
@ 2010-08-10  5:29               ` MyungJoo Ham
  0 siblings, 0 replies; 28+ messages in thread
From: MyungJoo Ham @ 2010-08-10  5:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Aug 4, 2010 at 8:17 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> MyungJoo Ham wrote:
>>
>> ? ? ? The CPUFREQ driver requires an access to DMCx registers. We
>> define physical addresses and mapping between physical and virtual
>> addresses of DMCx registers.
>>
>> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>> ?arch/arm/mach-s5pv210/cpu.c ? ? ? ? ? ? ?| ? 12 +++++++++++-
>> ?arch/arm/mach-s5pv210/include/mach/map.h | ? ?4 ++++
>> ?2 files changed, 15 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
>> index 74d4c08..2066695 100644
>> --- a/arch/arm/mach-s5pv210/cpu.c
>> +++ b/arch/arm/mach-s5pv210/cpu.c
>> @@ -60,7 +60,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(S5PV210_PA_DMC0),
>> + ? ? ? ? ? ? .length ? ? ? ? = SZ_4K,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? }, {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= (unsigned long)S5P_VA_DMC1,
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(S5PV210_PA_DMC1),
>> + ? ? ? ? ? ? .length ? ? ? ? = SZ_4K,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>> ?};
>>
>> ?static void s5pv210_idle(void)
>> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
>> s5pv210/include/mach/map.h
>> index 17687f0..daf6456 100644
>> --- a/arch/arm/mach-s5pv210/include/mach/map.h
>> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
>> @@ -108,4 +108,8 @@
>> ?#define SAMSUNG_PA_ADC ? ? ? ? ? ? ? S5PV210_PA_ADC
>> ?#define SAMSUNG_PA_KEYPAD ? ?S5PV210_PA_KEYPAD
>>
>> +/* DMC */
>
> No need an obvious comment like above...
>
>> +#define S5PV210_PA_DMC0 ? ? ? ? ? ? ?(0xF0000000)
>> +#define S5PV210_PA_DMC1 ? ? ? ? ? ? ?(0xF1400000)
>
> As I said, if you need adding new definition into the mach/map.h, please
> keep the address order like others.
> It can help to us for easily reading...


Umm.. where would be the in-order place for these two? The order of
addresses is already mixed up in this file and wherever these two go,
it cannot be "in-order". If we are going to reorder things in this
file, it should be done separately.

>
>> +
>> ?#endif /* __ASM_ARCH_MAP_H */
>> --
>
> And as I commented, to merge your 4th(previous, just adding VA) and 5th
> patch to one is better...just for adding DMC map IO.

Ok, will be done at v7.

>
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
>

ps. Anyway, sorry for the late reply, I've been away for a while.

-- 
MyungJoo Ham (???), Ph.D.
Mobile Software Platform Lab,
Digital Media and Communications (DMC) Business
Samsung Electronics
cell: 82-10-6714-2858

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2010-08-10  5:29 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-03 10:04 [PATCH v6 0/7] ARM: S5PV210: CPUFREQ Initial Support MyungJoo Ham
2010-08-03 10:04 ` MyungJoo Ham
2010-08-03 10:04 ` [PATCH v6 1/7] ARM: S5PV210: Allow to probe EVT revision number MyungJoo Ham
2010-08-03 10:04   ` MyungJoo Ham
2010-08-03 10:04   ` [PATCH v6 2/7] ARM: Samsung SoC: added hclk/pclk info to s3c_freq for s5pv210 cpu-freq MyungJoo Ham
2010-08-03 10:04     ` MyungJoo Ham
2010-08-03 10:04     ` [PATCH v6 3/7] ARM: S5P: Added default pll values for APLL 800/1000MHz MyungJoo Ham
2010-08-03 10:04       ` MyungJoo Ham
2010-08-03 10:04       ` [PATCH v6 4/7] ARM: S5P: Virtual Addresses for DMCx registers MyungJoo Ham
2010-08-03 10:04         ` MyungJoo Ham
2010-08-03 10:04         ` [PATCH v6 5/7] ARM: S5PV210: Access " MyungJoo Ham
2010-08-03 10:04           ` MyungJoo Ham
2010-08-03 10:04           ` [PATCH v6 6/7] ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT) MyungJoo Ham
2010-08-03 10:04             ` MyungJoo Ham
2010-08-03 10:04             ` [PATCH v6 7/7] ARM: S5PV210: Initial CPUFREQ Support MyungJoo Ham
2010-08-03 10:04               ` MyungJoo Ham
2010-08-04 11:44               ` Kukjin Kim
2010-08-04 11:44                 ` Kukjin Kim
2010-08-04 11:34             ` [PATCH v6 6/7] ARM: S5PV210: clock registers (CLK_DIV/SRC/STAT) Kukjin Kim
2010-08-04 11:34               ` Kukjin Kim
2010-08-04 11:17           ` [PATCH v6 5/7] ARM: S5PV210: Access for DMCx registers Kukjin Kim
2010-08-04 11:17             ` Kukjin Kim
2010-08-04 13:36             ` Kyungmin Park
2010-08-04 13:36               ` Kyungmin Park
2010-08-10  5:29             ` MyungJoo Ham
2010-08-10  5:29               ` MyungJoo Ham
2010-08-04 11:29   ` [PATCH v6 1/7] ARM: S5PV210: Allow to probe EVT revision number Kukjin Kim
2010-08-04 11:29     ` Kukjin Kim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.