* [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ @ 2010-09-18 2:45 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel, linux-samsung-soc; +Cc: ben-linux This patch adds support CPUFREQ driver for S5PV310 and S5PC210. NOTE: This patch dependes on following. - ARM: S5PV310: Fix clkset_moutcore_list - ARM: S5PV210: Add DMC map_desc table for supporting DMC access [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ @ 2010-09-18 2:45 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel This patch adds support CPUFREQ driver for S5PV310 and S5PC210. NOTE: This patch dependes on following. - ARM: S5PV310: Fix clkset_moutcore_list - ARM: S5PV210: Add DMC map_desc table for supporting DMC access [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ 2010-09-18 2:45 ` Kukjin Kim @ 2010-09-18 2:45 ` Kukjin Kim -1 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel, linux-samsung-soc; +Cc: ben-linux, Sunyoung Kang, Kukjin Kim From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds CMU(Clock Management Unit) registers for S5PV310/S5PC210 CPUFREQ driver and modifies some register names according to datasheet. Signed-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s5pv310/clock.c | 12 ++-- arch/arm/mach-s5pv310/include/mach/regs-clock.h | 77 ++++++++++++++++++++++- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 32146db..6b528fc 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -244,7 +244,7 @@ static struct clksrc_clk clk_mout_corebus = { .id = -1, }, .sources = &clkset_mout_corebus, - .reg_src = { .reg = S5P_CLKSRC_CORE, .shift = 4, .size = 1 }, + .reg_src = { .reg = S5P_CLKSRC_DMC, .shift = 4, .size = 1 }, }; static struct clksrc_clk clk_sclk_dmc = { @@ -253,7 +253,7 @@ static struct clksrc_clk clk_sclk_dmc = { .id = -1, .parent = &clk_mout_corebus.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 12, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 12, .size = 3 }, }; static struct clksrc_clk clk_aclk_cored = { @@ -262,7 +262,7 @@ static struct clksrc_clk clk_aclk_cored = { .id = -1, .parent = &clk_sclk_dmc.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 16, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 16, .size = 3 }, }; static struct clksrc_clk clk_aclk_corep = { @@ -271,7 +271,7 @@ static struct clksrc_clk clk_aclk_corep = { .id = -1, .parent = &clk_aclk_cored.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 20, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 20, .size = 3 }, }; static struct clksrc_clk clk_aclk_acp = { @@ -280,7 +280,7 @@ static struct clksrc_clk clk_aclk_acp = { .id = -1, .parent = &clk_mout_corebus.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 0, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 0, .size = 3 }, }; static struct clksrc_clk clk_pclk_acp = { @@ -289,7 +289,7 @@ static struct clksrc_clk clk_pclk_acp = { .id = -1, .parent = &clk_aclk_acp.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 4, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 4, .size = 3 }, }; /* Core list of CMU_TOP side */ diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h index 12e983c..5d0bb40 100644 --- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h @@ -19,6 +19,12 @@ #define S5P_INFORM0 S5P_CLKREG(0x800) +#define S5P_CLKDIV_LEFTBUS S5P_CLKREG(0x04500) +#define S5P_CLKDIV_STAT_LEFTBUS S5P_CLKREG(0x04600) + +#define S5P_CLKDIV_RIGHTBUS S5P_CLKREG(0x08500) +#define S5P_CLKDIV_STAT_RIGHTBUS S5P_CLKREG(0x08600) + #define S5P_EPLL_CON0 S5P_CLKREG(0x0C110) #define S5P_EPLL_CON1 S5P_CLKREG(0x0C114) #define S5P_VPLL_CON0 S5P_CLKREG(0x0C120) @@ -58,6 +64,8 @@ #define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) #define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354) +#define S5P_CLKDIV_STAT_TOP S5P_CLKREG(0x0C610) + #define S5P_CLKGATE_IP_CAM S5P_CLKREG(0x0C920) #define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930) #define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934) @@ -66,8 +74,9 @@ #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) #define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960) -#define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) -#define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500) +#define S5P_CLKSRC_DMC S5P_CLKREG(0x10200) +#define S5P_CLKDIV_DMC0 S5P_CLKREG(0x10500) +#define S5P_CLKDIV_STAT_DMC0 S5P_CLKREG(0x10600) #define S5P_APLL_LOCK S5P_CLKREG(0x14000) #define S5P_MPLL_LOCK S5P_CLKREG(0x14004) @@ -84,4 +93,68 @@ #define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800) +/* APLL_LOCK */ +#define S5P_APLL_LOCKTIME (0x1C20) /* 300us */ + +/* APLL_CON0 */ +#define S5P_APLLCON0_ENABLE_SHIFT (31) +#define S5P_APLLCON0_LOCKED_SHIFT (29) +#define S5P_APLL_VAL_1000 ((250 << 16) | (6 << 8) | 1) + +/* CLK_SRC_CPU */ +#define S5P_CLKSRC_CPU_MUXCORE_SHIFT (16) +#define S5P_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT) + +/* CLKDIV_CPU0 */ +#define S5P_CLKDIV_CPU0_CORE_SHIFT (0) +#define S5P_CLKDIV_CPU0_CORE_MASK (0x7 << S5P_CLKDIV_CPU0_CORE_SHIFT) +#define S5P_CLKDIV_CPU0_COREM0_SHIFT (4) +#define S5P_CLKDIV_CPU0_COREM0_MASK (0x7 << S5P_CLKDIV_CPU0_COREM0_SHIFT) +#define S5P_CLKDIV_CPU0_COREM1_SHIFT (8) +#define S5P_CLKDIV_CPU0_COREM1_MASK (0x7 << S5P_CLKDIV_CPU0_COREM1_SHIFT) +#define S5P_CLKDIV_CPU0_PERIPH_SHIFT (12) +#define S5P_CLKDIV_CPU0_PERIPH_MASK (0x7 << S5P_CLKDIV_CPU0_PERIPH_SHIFT) +#define S5P_CLKDIV_CPU0_ATB_SHIFT (16) +#define S5P_CLKDIV_CPU0_ATB_MASK (0x7 << S5P_CLKDIV_CPU0_ATB_SHIFT) +#define S5P_CLKDIV_CPU0_PCLKDBG_SHIFT (20) +#define S5P_CLKDIV_CPU0_PCLKDBG_MASK (0x7 << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) +#define S5P_CLKDIV_CPU0_APLL_SHIFT (24) +#define S5P_CLKDIV_CPU0_APLL_MASK (0x7 << S5P_CLKDIV_CPU0_APLL_SHIFT) + +/* CLKDIV_DMC0 */ +#define S5P_CLKDIV_DMC0_ACP_SHIFT (0) +#define S5P_CLKDIV_DMC0_ACP_MASK (0x7 << S5P_CLKDIV_DMC0_ACP_SHIFT) +#define S5P_CLKDIV_DMC0_ACPPCLK_SHIFT (4) +#define S5P_CLKDIV_DMC0_ACPPCLK_MASK (0x7 << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) +#define S5P_CLKDIV_DMC0_DPHY_SHIFT (8) +#define S5P_CLKDIV_DMC0_DPHY_MASK (0x7 << S5P_CLKDIV_DMC0_DPHY_SHIFT) +#define S5P_CLKDIV_DMC0_DMC_SHIFT (12) +#define S5P_CLKDIV_DMC0_DMC_MASK (0x7 << S5P_CLKDIV_DMC0_DMC_SHIFT) +#define S5P_CLKDIV_DMC0_DMCD_SHIFT (16) +#define S5P_CLKDIV_DMC0_DMCD_MASK (0x7 << S5P_CLKDIV_DMC0_DMCD_SHIFT) +#define S5P_CLKDIV_DMC0_DMCP_SHIFT (20) +#define S5P_CLKDIV_DMC0_DMCP_MASK (0x7 << S5P_CLKDIV_DMC0_DMCP_SHIFT) +#define S5P_CLKDIV_DMC0_COPY2_SHIFT (24) +#define S5P_CLKDIV_DMC0_COPY2_MASK (0x7 << S5P_CLKDIV_DMC0_COPY2_SHIFT) +#define S5P_CLKDIV_DMC0_CORETI_SHIFT (28) +#define S5P_CLKDIV_DMC0_CORETI_MASK (0x7 << S5P_CLKDIV_DMC0_CORETI_SHIFT) + +/* CLKDIV_TOP */ +#define S5P_CLKDIV_TOP_ACLK200_SHIFT (0) +#define S5P_CLKDIV_TOP_ACLK200_MASK (0x7 << S5P_CLKDIV_TOP_ACLK200_SHIFT) +#define S5P_CLKDIV_TOP_ACLK100_SHIFT (4) +#define S5P_CLKDIV_TOP_ACLK100_MASK (0xf << S5P_CLKDIV_TOP_ACLK100_SHIFT) +#define S5P_CLKDIV_TOP_ACLK160_SHIFT (8) +#define S5P_CLKDIV_TOP_ACLK160_MASK (0x7 << S5P_CLKDIV_TOP_ACLK160_SHIFT) +#define S5P_CLKDIV_TOP_ACLK133_SHIFT (12) +#define S5P_CLKDIV_TOP_ACLK133_MASK (0x7 << S5P_CLKDIV_TOP_ACLK133_SHIFT) +#define S5P_CLKDIV_TOP_ONENAND_SHIFT (16) +#define S5P_CLKDIV_TOP_ONENAND_MASK (0x7 << S5P_CLKDIV_TOP_ONENAND_SHIFT) + +/* CLKDIV_LEFTBUS / CLKDIV_RIGHTBUS*/ +#define S5P_CLKDIV_BUS_GDLR_SHIFT (0) +#define S5P_CLKDIV_BUS_GDLR_MASK (0x7 << S5P_CLKDIV_BUS_GDLR_SHIFT) +#define S5P_CLKDIV_BUS_GPLR_SHIFT (4) +#define S5P_CLKDIV_BUS_GPLR_MASK (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT) + #endif /* __ASM_ARCH_REGS_CLOCK_H */ -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ @ 2010-09-18 2:45 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds CMU(Clock Management Unit) registers for S5PV310/S5PC210 CPUFREQ driver and modifies some register names according to datasheet. Signed-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s5pv310/clock.c | 12 ++-- arch/arm/mach-s5pv310/include/mach/regs-clock.h | 77 ++++++++++++++++++++++- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 32146db..6b528fc 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -244,7 +244,7 @@ static struct clksrc_clk clk_mout_corebus = { .id = -1, }, .sources = &clkset_mout_corebus, - .reg_src = { .reg = S5P_CLKSRC_CORE, .shift = 4, .size = 1 }, + .reg_src = { .reg = S5P_CLKSRC_DMC, .shift = 4, .size = 1 }, }; static struct clksrc_clk clk_sclk_dmc = { @@ -253,7 +253,7 @@ static struct clksrc_clk clk_sclk_dmc = { .id = -1, .parent = &clk_mout_corebus.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 12, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 12, .size = 3 }, }; static struct clksrc_clk clk_aclk_cored = { @@ -262,7 +262,7 @@ static struct clksrc_clk clk_aclk_cored = { .id = -1, .parent = &clk_sclk_dmc.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 16, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 16, .size = 3 }, }; static struct clksrc_clk clk_aclk_corep = { @@ -271,7 +271,7 @@ static struct clksrc_clk clk_aclk_corep = { .id = -1, .parent = &clk_aclk_cored.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 20, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 20, .size = 3 }, }; static struct clksrc_clk clk_aclk_acp = { @@ -280,7 +280,7 @@ static struct clksrc_clk clk_aclk_acp = { .id = -1, .parent = &clk_mout_corebus.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 0, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 0, .size = 3 }, }; static struct clksrc_clk clk_pclk_acp = { @@ -289,7 +289,7 @@ static struct clksrc_clk clk_pclk_acp = { .id = -1, .parent = &clk_aclk_acp.clk, }, - .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 4, .size = 3 }, + .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 4, .size = 3 }, }; /* Core list of CMU_TOP side */ diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h index 12e983c..5d0bb40 100644 --- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h @@ -19,6 +19,12 @@ #define S5P_INFORM0 S5P_CLKREG(0x800) +#define S5P_CLKDIV_LEFTBUS S5P_CLKREG(0x04500) +#define S5P_CLKDIV_STAT_LEFTBUS S5P_CLKREG(0x04600) + +#define S5P_CLKDIV_RIGHTBUS S5P_CLKREG(0x08500) +#define S5P_CLKDIV_STAT_RIGHTBUS S5P_CLKREG(0x08600) + #define S5P_EPLL_CON0 S5P_CLKREG(0x0C110) #define S5P_EPLL_CON1 S5P_CLKREG(0x0C114) #define S5P_VPLL_CON0 S5P_CLKREG(0x0C120) @@ -58,6 +64,8 @@ #define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) #define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354) +#define S5P_CLKDIV_STAT_TOP S5P_CLKREG(0x0C610) + #define S5P_CLKGATE_IP_CAM S5P_CLKREG(0x0C920) #define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930) #define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934) @@ -66,8 +74,9 @@ #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) #define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960) -#define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) -#define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500) +#define S5P_CLKSRC_DMC S5P_CLKREG(0x10200) +#define S5P_CLKDIV_DMC0 S5P_CLKREG(0x10500) +#define S5P_CLKDIV_STAT_DMC0 S5P_CLKREG(0x10600) #define S5P_APLL_LOCK S5P_CLKREG(0x14000) #define S5P_MPLL_LOCK S5P_CLKREG(0x14004) @@ -84,4 +93,68 @@ #define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800) +/* APLL_LOCK */ +#define S5P_APLL_LOCKTIME (0x1C20) /* 300us */ + +/* APLL_CON0 */ +#define S5P_APLLCON0_ENABLE_SHIFT (31) +#define S5P_APLLCON0_LOCKED_SHIFT (29) +#define S5P_APLL_VAL_1000 ((250 << 16) | (6 << 8) | 1) + +/* CLK_SRC_CPU */ +#define S5P_CLKSRC_CPU_MUXCORE_SHIFT (16) +#define S5P_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT) + +/* CLKDIV_CPU0 */ +#define S5P_CLKDIV_CPU0_CORE_SHIFT (0) +#define S5P_CLKDIV_CPU0_CORE_MASK (0x7 << S5P_CLKDIV_CPU0_CORE_SHIFT) +#define S5P_CLKDIV_CPU0_COREM0_SHIFT (4) +#define S5P_CLKDIV_CPU0_COREM0_MASK (0x7 << S5P_CLKDIV_CPU0_COREM0_SHIFT) +#define S5P_CLKDIV_CPU0_COREM1_SHIFT (8) +#define S5P_CLKDIV_CPU0_COREM1_MASK (0x7 << S5P_CLKDIV_CPU0_COREM1_SHIFT) +#define S5P_CLKDIV_CPU0_PERIPH_SHIFT (12) +#define S5P_CLKDIV_CPU0_PERIPH_MASK (0x7 << S5P_CLKDIV_CPU0_PERIPH_SHIFT) +#define S5P_CLKDIV_CPU0_ATB_SHIFT (16) +#define S5P_CLKDIV_CPU0_ATB_MASK (0x7 << S5P_CLKDIV_CPU0_ATB_SHIFT) +#define S5P_CLKDIV_CPU0_PCLKDBG_SHIFT (20) +#define S5P_CLKDIV_CPU0_PCLKDBG_MASK (0x7 << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) +#define S5P_CLKDIV_CPU0_APLL_SHIFT (24) +#define S5P_CLKDIV_CPU0_APLL_MASK (0x7 << S5P_CLKDIV_CPU0_APLL_SHIFT) + +/* CLKDIV_DMC0 */ +#define S5P_CLKDIV_DMC0_ACP_SHIFT (0) +#define S5P_CLKDIV_DMC0_ACP_MASK (0x7 << S5P_CLKDIV_DMC0_ACP_SHIFT) +#define S5P_CLKDIV_DMC0_ACPPCLK_SHIFT (4) +#define S5P_CLKDIV_DMC0_ACPPCLK_MASK (0x7 << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) +#define S5P_CLKDIV_DMC0_DPHY_SHIFT (8) +#define S5P_CLKDIV_DMC0_DPHY_MASK (0x7 << S5P_CLKDIV_DMC0_DPHY_SHIFT) +#define S5P_CLKDIV_DMC0_DMC_SHIFT (12) +#define S5P_CLKDIV_DMC0_DMC_MASK (0x7 << S5P_CLKDIV_DMC0_DMC_SHIFT) +#define S5P_CLKDIV_DMC0_DMCD_SHIFT (16) +#define S5P_CLKDIV_DMC0_DMCD_MASK (0x7 << S5P_CLKDIV_DMC0_DMCD_SHIFT) +#define S5P_CLKDIV_DMC0_DMCP_SHIFT (20) +#define S5P_CLKDIV_DMC0_DMCP_MASK (0x7 << S5P_CLKDIV_DMC0_DMCP_SHIFT) +#define S5P_CLKDIV_DMC0_COPY2_SHIFT (24) +#define S5P_CLKDIV_DMC0_COPY2_MASK (0x7 << S5P_CLKDIV_DMC0_COPY2_SHIFT) +#define S5P_CLKDIV_DMC0_CORETI_SHIFT (28) +#define S5P_CLKDIV_DMC0_CORETI_MASK (0x7 << S5P_CLKDIV_DMC0_CORETI_SHIFT) + +/* CLKDIV_TOP */ +#define S5P_CLKDIV_TOP_ACLK200_SHIFT (0) +#define S5P_CLKDIV_TOP_ACLK200_MASK (0x7 << S5P_CLKDIV_TOP_ACLK200_SHIFT) +#define S5P_CLKDIV_TOP_ACLK100_SHIFT (4) +#define S5P_CLKDIV_TOP_ACLK100_MASK (0xf << S5P_CLKDIV_TOP_ACLK100_SHIFT) +#define S5P_CLKDIV_TOP_ACLK160_SHIFT (8) +#define S5P_CLKDIV_TOP_ACLK160_MASK (0x7 << S5P_CLKDIV_TOP_ACLK160_SHIFT) +#define S5P_CLKDIV_TOP_ACLK133_SHIFT (12) +#define S5P_CLKDIV_TOP_ACLK133_MASK (0x7 << S5P_CLKDIV_TOP_ACLK133_SHIFT) +#define S5P_CLKDIV_TOP_ONENAND_SHIFT (16) +#define S5P_CLKDIV_TOP_ONENAND_MASK (0x7 << S5P_CLKDIV_TOP_ONENAND_SHIFT) + +/* CLKDIV_LEFTBUS / CLKDIV_RIGHTBUS*/ +#define S5P_CLKDIV_BUS_GDLR_SHIFT (0) +#define S5P_CLKDIV_BUS_GDLR_MASK (0x7 << S5P_CLKDIV_BUS_GDLR_SHIFT) +#define S5P_CLKDIV_BUS_GPLR_SHIFT (4) +#define S5P_CLKDIV_BUS_GPLR_MASK (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT) + #endif /* __ASM_ARCH_REGS_CLOCK_H */ -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc 2010-09-18 2:45 ` Kukjin Kim @ 2010-09-18 2:45 ` Kukjin Kim -1 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel, linux-samsung-soc; +Cc: ben-linux, Sunyoung Kang, Kukjin Kim From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds DMC io mapping for access it and adds registers. This is used in checking DRAM memory type. Signed-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s5pv310/cpu.c | 5 +++++ arch/arm/mach-s5pv310/include/mach/map.h | 2 ++ arch/arm/mach-s5pv310/include/mach/regs-mem.h | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-s5pv310/include/mach/regs-mem.h diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c index 4add398..225ca53 100644 --- a/arch/arm/mach-s5pv310/cpu.c +++ b/arch/arm/mach-s5pv310/cpu.c @@ -61,6 +61,11 @@ static struct map_desc s5pv310_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, { + .virtual = (unsigned long)S5P_VA_DMC0, + .pfn = __phys_to_pfn(S5PV310_PA_DMC0), + .length = SZ_4K, + .type = MT_DEVICE, + }, { .virtual = (unsigned long)S3C_VA_UART, .pfn = __phys_to_pfn(S3C_PA_UART), .length = SZ_512K, diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index aff6d23..2403abf 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h @@ -41,6 +41,8 @@ #define S5PV310_PA_WATCHDOG (0x10060000) +#define S5PV310_PA_DMC0 (0x10400000) + #define S5PV310_PA_COMBINER (0x10448000) #define S5PV310_PA_COREPERI (0x10500000) diff --git a/arch/arm/mach-s5pv310/include/mach/regs-mem.h b/arch/arm/mach-s5pv310/include/mach/regs-mem.h new file mode 100644 index 0000000..8342271 --- /dev/null +++ b/arch/arm/mach-s5pv310/include/mach/regs-mem.h @@ -0,0 +1,23 @@ +/* linux/arch/arm/mach-s5pv310/include/mach/regs-mem.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5PV310 - SROMC and DMC register definitions + * + * 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_REGS_MEM_H +#define __ASM_ARCH_REGS_MEM_H __FILE__ + +#include <mach/map.h> + +#define S5P_DMC0_MEMCON_OFFSET 0x04 + +#define S5P_DMC0_MEMTYPE_SHIFT 8 +#define S5P_DMC0_MEMTYPE_MASK 0xF + +#endif /* __ASM_ARCH_REGS_MEM_H */ -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc @ 2010-09-18 2:45 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds DMC io mapping for access it and adds registers. This is used in checking DRAM memory type. Signed-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s5pv310/cpu.c | 5 +++++ arch/arm/mach-s5pv310/include/mach/map.h | 2 ++ arch/arm/mach-s5pv310/include/mach/regs-mem.h | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-s5pv310/include/mach/regs-mem.h diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c index 4add398..225ca53 100644 --- a/arch/arm/mach-s5pv310/cpu.c +++ b/arch/arm/mach-s5pv310/cpu.c @@ -61,6 +61,11 @@ static struct map_desc s5pv310_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, { + .virtual = (unsigned long)S5P_VA_DMC0, + .pfn = __phys_to_pfn(S5PV310_PA_DMC0), + .length = SZ_4K, + .type = MT_DEVICE, + }, { .virtual = (unsigned long)S3C_VA_UART, .pfn = __phys_to_pfn(S3C_PA_UART), .length = SZ_512K, diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index aff6d23..2403abf 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h @@ -41,6 +41,8 @@ #define S5PV310_PA_WATCHDOG (0x10060000) +#define S5PV310_PA_DMC0 (0x10400000) + #define S5PV310_PA_COMBINER (0x10448000) #define S5PV310_PA_COREPERI (0x10500000) diff --git a/arch/arm/mach-s5pv310/include/mach/regs-mem.h b/arch/arm/mach-s5pv310/include/mach/regs-mem.h new file mode 100644 index 0000000..8342271 --- /dev/null +++ b/arch/arm/mach-s5pv310/include/mach/regs-mem.h @@ -0,0 +1,23 @@ +/* linux/arch/arm/mach-s5pv310/include/mach/regs-mem.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5PV310 - SROMC and DMC register definitions + * + * 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_REGS_MEM_H +#define __ASM_ARCH_REGS_MEM_H __FILE__ + +#include <mach/map.h> + +#define S5P_DMC0_MEMCON_OFFSET 0x04 + +#define S5P_DMC0_MEMTYPE_SHIFT 8 +#define S5P_DMC0_MEMTYPE_MASK 0xF + +#endif /* __ASM_ARCH_REGS_MEM_H */ -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ 2010-09-18 2:45 ` Kukjin Kim @ 2010-09-18 2:45 ` Kukjin Kim -1 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel, linux-samsung-soc Cc: ben-linux, Sunyoung Kang, Jaecheol Lee, Kukjin Kim From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds support CPUFREQ driver for S5PV310 and S5PC210. This can support DVFS(Dynamic Voltage and Frequency Scaling). The voltage scaling depends on existence of regulator. Sigend-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Jaecheol Lee <jc.lee@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s5pv310/cpufreq.c | 561 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 561 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-s5pv310/cpufreq.c diff --git a/arch/arm/mach-s5pv310/cpufreq.c b/arch/arm/mach-s5pv310/cpufreq.c new file mode 100644 index 0000000..bcd4ebf --- /dev/null +++ b/arch/arm/mach-s5pv310/cpufreq.c @@ -0,0 +1,561 @@ +/* linux/arch/arm/mach-s5pv310/cpufreq.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5PV310 - 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. +*/ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/cpufreq.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> +#include <mach/regs-mem.h> + +#include <plat/clock.h> + +static struct clk *cpu_clk; +static struct clk *moutcore; +static struct clk *mout_mpll; +static struct clk *mout_apll; + +#ifdef CONFIG_REGULATOR +static struct regulator *arm_regulator; +static struct regulator *int_regulator; +#endif + +static struct cpufreq_freqs freqs; +static unsigned int armclk_use_apll; +static unsigned int memtype; + +enum s5pv310_memory_type { + DDR2 = 4, + LPDDR2, + DDR3, +}; + +enum cpufreq_level_index { + L0, L1, L2, L3, L4, CPUFREQ_LEVEL_END, +}; + +static struct cpufreq_frequency_table s5pv310_freq_table[] = { + {L0, 1000*1000}, + {L1, 800*1000}, + {L2, 400*1000}, + {L3, 200*1000}, + {L4, 100*1000}, + {0, CPUFREQ_TABLE_END}, +}; + +static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END + 1][7] = { + /* + * Clock divider value for following + * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH, + * DIVATB, DIVPCLK_DBG, DIVAPLL } + */ + + /* ARM L0: 1000MHz */ + { 0, 3, 7, 3, 3, 0, 0 }, + + /* ARM L1: 800MHz */ + { 0, 3, 7, 3, 3, 0, 0 }, + + /* ARM L2: 400MHz */ + { 1, 1, 3, 1, 1, 0, 0 }, + + /* ARM L3: 200MHz */ + { 3, 0, 1, 0, 0, 0, 0 }, + + /* ARM L4A: 100MHz, for DDR2/3 */ + { 7, 0, 1, 0, 0, 0, 0 }, + + /* ARM L4B: 100MHz, for LPDDR2 (SMDKV310 has LPDDR2) */ + { 7, 0, 1, 0, 0, 0, 0 }, +}; + +static unsigned int clkdiv_dmc0[CPUFREQ_LEVEL_END + 1][8] = { + /* + * Clock divider value for following + * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD + * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS } + */ + + /* DMC L0: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L1: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L2: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L3: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L4A: 400MHz, for DDR2/3 */ + { 7, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L4B: 200MHz, for LPDDR2 */ + { 7, 1, 1, 3, 1, 1, 3, 1 }, +}; + +static unsigned int clkdiv_top[CPUFREQ_LEVEL_END + 1][5] = { + /* + * Clock divider value for following + * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND } + */ + + /* ACLK200 L0: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L1: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L2: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L3: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L4A: 100MHz */ + { 7, 7, 7, 7, 1 }, + + /* ACLK200 L4B: 100MHz */ + { 7, 7, 7, 7, 1 }, +}; + +static unsigned int clkdiv_lr_bus[CPUFREQ_LEVEL_END + 1][2] = { + /* + * Clock divider value for following + * { DIVGDL/R, DIVGPL/R } + */ + + /* ACLK_GDL/R L0: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L1: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L2: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L3: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L4A: 100MHz */ + { 7, 1 }, + + /* ACLK_GDL/R L4B: 100MHz */ + { 7, 1 }, +}; + +struct cpufreq_voltage_table { + unsigned int index; /* any */ + unsigned int arm_volt; /* uV */ + unsigned int int_volt; +}; + +static struct cpufreq_voltage_table s5pv310_volt_table[] = { + { + .index = L0, + .arm_volt = 1200000, + .int_volt = 1100000, + }, { + .index = L1, + .arm_volt = 1100000, + .int_volt = 1100000, + }, { + .index = L2, + .arm_volt = 1050000, + .int_volt = 1100000, + }, { + .index = L3, + .arm_volt = 1050000, + .int_volt = 1100000, + }, { + .index = L4, + .arm_volt = 1000000, + .int_volt = 1000000, + }, +}; + +int s5pv310_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, s5pv310_freq_table); +} + +unsigned int s5pv310_getspeed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +void s5pv310_set_clkdiv(unsigned int div_index) +{ + unsigned int tmp; + + /* Change Divider - CPU0 */ + + tmp = __raw_readl(S5P_CLKDIV_CPU); + + tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK | S5P_CLKDIV_CPU0_COREM0_MASK | + S5P_CLKDIV_CPU0_COREM1_MASK | S5P_CLKDIV_CPU0_PERIPH_MASK | + S5P_CLKDIV_CPU0_ATB_MASK | S5P_CLKDIV_CPU0_PCLKDBG_MASK | + S5P_CLKDIV_CPU0_APLL_MASK); + + tmp |= ((clkdiv_cpu0[div_index][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) | + (clkdiv_cpu0[div_index][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) | + (clkdiv_cpu0[div_index][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) | + (clkdiv_cpu0[div_index][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) | + (clkdiv_cpu0[div_index][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) | + (clkdiv_cpu0[div_index][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) | + (clkdiv_cpu0[div_index][6] << S5P_CLKDIV_CPU0_APLL_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_CPU); + + do { + tmp = __raw_readl(S5P_CLKDIV_STATCPU); + } while (tmp & 0x1111111); + + /* Change Divider - DMC0 */ + + tmp = __raw_readl(S5P_CLKDIV_DMC0); + + tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK | S5P_CLKDIV_DMC0_ACPPCLK_MASK | + S5P_CLKDIV_DMC0_DPHY_MASK | S5P_CLKDIV_DMC0_DMC_MASK | + S5P_CLKDIV_DMC0_DMCD_MASK | S5P_CLKDIV_DMC0_DMCP_MASK | + S5P_CLKDIV_DMC0_COPY2_MASK | S5P_CLKDIV_DMC0_CORETI_MASK); + + tmp |= ((clkdiv_dmc0[div_index][0] << S5P_CLKDIV_DMC0_ACP_SHIFT) | + (clkdiv_dmc0[div_index][1] << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) | + (clkdiv_dmc0[div_index][2] << S5P_CLKDIV_DMC0_DPHY_SHIFT) | + (clkdiv_dmc0[div_index][3] << S5P_CLKDIV_DMC0_DMC_SHIFT) | + (clkdiv_dmc0[div_index][4] << S5P_CLKDIV_DMC0_DMCD_SHIFT) | + (clkdiv_dmc0[div_index][5] << S5P_CLKDIV_DMC0_DMCP_SHIFT) | + (clkdiv_dmc0[div_index][6] << S5P_CLKDIV_DMC0_COPY2_SHIFT) | + (clkdiv_dmc0[div_index][7] << S5P_CLKDIV_DMC0_CORETI_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_DMC0); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0); + } while (tmp & 0x11111111); + + /* Change Divider - TOP */ + + tmp = __raw_readl(S5P_CLKDIV_TOP); + + tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK | S5P_CLKDIV_TOP_ACLK100_MASK | + S5P_CLKDIV_TOP_ACLK160_MASK | S5P_CLKDIV_TOP_ACLK133_MASK | + S5P_CLKDIV_TOP_ONENAND_MASK); + + tmp |= ((clkdiv_top[div_index][0] << S5P_CLKDIV_TOP_ACLK200_SHIFT) | + (clkdiv_top[div_index][1] << S5P_CLKDIV_TOP_ACLK100_SHIFT) | + (clkdiv_top[div_index][2] << S5P_CLKDIV_TOP_ACLK160_SHIFT) | + (clkdiv_top[div_index][3] << S5P_CLKDIV_TOP_ACLK133_SHIFT) | + (clkdiv_top[div_index][4] << S5P_CLKDIV_TOP_ONENAND_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_TOP); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_TOP); + } while (tmp & 0x11111); + + /* Change Divider - LEFTBUS */ + + tmp = __raw_readl(S5P_CLKDIV_LEFTBUS); + + tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK); + + tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) | + (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_LEFTBUS); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS); + } while (tmp & 0x11); + + /* Change Divider - RIGHTBUS */ + + tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS); + + tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK); + + tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) | + (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS); + } while (tmp & 0x11); +} + +static int s5pv310_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int index, div_index, tmp; + unsigned int arm_volt, int_volt; + unsigned int need_apll = 0; + + freqs.old = s5pv310_getspeed(policy->cpu); + + if (cpufreq_frequency_table_target(policy, s5pv310_freq_table, + target_freq, relation, &index)) + return -EINVAL; + + freqs.new = s5pv310_freq_table[index].frequency; + freqs.cpu = policy->cpu; + + if (freqs.new == freqs.old) + return 0; + + /* + * If freqs.new is higher than 800MHz + * cpufreq driver should turn on apll + */ + if (index < L1) + need_apll = 1; + + /* If the memory type is LPDDR2, use L4-B instead of L4-A */ + if ((index == L4) && (memtype == LPDDR2)) + div_index = index + 1; + else + div_index = index; + + /* get the voltage value */ + arm_volt = s5pv310_volt_table[index].arm_volt; + int_volt = s5pv310_volt_table[index].int_volt; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* control regulator */ + if (freqs.new > freqs.old) { + /* Voltage up */ +#ifdef CONFIG_REGULATOR + regulator_set_voltage(arm_regulator, arm_volt, arm_volt); + regulator_set_voltage(int_regulator, int_volt, int_volt); +#endif + } + + /* Clock Configuration Procedure */ + + /* 1. Change the system clock divider values */ + s5pv310_set_clkdiv(div_index); + + /* 2. Change the divider values for special clocks in CMU_TOP */ + /* currently nothing */ + + /* 3. Change the XPLL values or Select the parent XPLL */ + if (need_apll) { + if (!armclk_use_apll) { + /* + * If the parent clock of armclk isn't apll + * here need to set apll (include m,p,s value) + */ + + /* a. MUX_CORE_SEL = MPLL, + * ARMCLK uses MPLL for lock time */ + clk_set_parent(moutcore, mout_mpll); + + do { + tmp = (__raw_readl(S5P_CLKMUX_STATCPU) + >> S5P_CLKSRC_CPU_MUXCORE_SHIFT); + tmp &= 0x7; + } while (tmp != 0x2); + + /* b. Set APLL Lock time */ + __raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK); + + /* c. Change PLL PMS values */ + __raw_writel(S5P_APLL_VAL_1000, S5P_APLL_CON0); + + /* d. Turn on a PLL */ + tmp = __raw_readl(S5P_APLL_CON0); + tmp |= (0x1 << S5P_APLLCON0_ENABLE_SHIFT); + __raw_writel(tmp, S5P_APLL_CON0); + + /* e. wait_lock_time */ + do { + tmp = __raw_readl(S5P_APLL_CON0); + } while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT))); + + armclk_use_apll = 1; + + } + + /* MUX_CORE_SEL = APLL */ + clk_set_parent(moutcore, mout_apll); + + do { + tmp = __raw_readl(S5P_CLKMUX_STATCPU); + tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK; + } while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)); + + } else { + if (clk_get_parent(moutcore) != mout_mpll) { + clk_set_parent(moutcore, mout_mpll); + + do { + tmp = __raw_readl(S5P_CLKMUX_STATCPU); + tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK; + } while (tmp != (0x2 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)); + } + } + + /* control regulator */ + if (freqs.new < freqs.old) { + /* Voltage down */ +#ifdef CONFIG_REGULATOR + regulator_set_voltage(arm_regulator, arm_volt, arm_volt); + regulator_set_voltage(int_regulator, int_volt, int_volt); +#endif + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +#ifdef CONFIG_PM +static int s5pv310_cpufreq_suspend(struct cpufreq_policy *policy, + pm_message_t pmsg) +{ + return 0; +} + +static int s5pv310_cpufreq_resume(struct cpufreq_policy *policy) +{ + return 0; +} +#endif + +static int s5pv310_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + policy->cur = policy->min = policy->max = s5pv310_getspeed(policy->cpu); + + cpufreq_frequency_table_get_attr(s5pv310_freq_table, policy->cpu); + + /* set the transition latency value */ + policy->cpuinfo.transition_latency = 100000; + + /* + * S5PV310 multi-core processors has 2 cores + * that the frequency cannot be set independently. + * Each cpu is bound to the same speed. + * So the affected cpu is all of the cpus. + */ + cpumask_setall(policy->cpus); + + return cpufreq_frequency_table_cpuinfo(policy, s5pv310_freq_table); +} + +static struct cpufreq_driver s5pv310_driver = { + .flags = CPUFREQ_STICKY, + .verify = s5pv310_verify_speed, + .target = s5pv310_target, + .get = s5pv310_getspeed, + .init = s5pv310_cpufreq_cpu_init, + .name = "s5pv310_cpufreq", +#ifdef CONFIG_PM + .suspend = s5pv310_cpufreq_suspend, + .resume = s5pv310_cpufreq_resume, +#endif +}; + +static int __init s5pv310_cpufreq_init(void) +{ + unsigned int tmp; + + cpu_clk = clk_get(NULL, "armclk"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + moutcore = clk_get(NULL, "moutcore"); + if (IS_ERR(moutcore)) + goto out; + + mout_mpll = clk_get(NULL, "mout_mpll"); + if (IS_ERR(mout_mpll)) + goto out; + + mout_apll = clk_get(NULL, "mout_apll"); + if (IS_ERR(mout_apll)) + goto out; + +#ifdef CONFIG_REGULATOR + arm_regulator = regulator_get(NULL, "vdd_arm"); + if (IS_ERR(arm_regulator)) { + printk(KERN_ERR "failed to get resource %s\n", "vdd_arm"); + goto out; + } + + int_regulator = regulator_get(NULL, "vdd_int"); + if (IS_ERR(int_regulator)) { + printk(KERN_ERR "failed to get resource %s\n", "vdd_int"); + goto out; + } +#endif + + /* check parent clock of armclk */ + tmp = __raw_readl(S5P_CLKSRC_CPU); + if (tmp & S5P_CLKSRC_CPU_MUXCORE_SHIFT) + armclk_use_apll = 0; + else + armclk_use_apll = 1; + + /* + * Check DRAM type. + * Because DVFS level is different according to DRAM type. + */ + memtype = __raw_readl(S5P_VA_DMC0 + S5P_DMC0_MEMCON_OFFSET); + memtype = (memtype >> S5P_DMC0_MEMTYPE_SHIFT); + memtype &= S5P_DMC0_MEMTYPE_MASK; + + if ((memtype < DDR2) && (memtype > DDR3)) { + printk(KERN_ERR "%s: wrong memtype= 0x%x\n", __func__, memtype); + goto out; + } else { + printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype); + } + + return cpufreq_register_driver(&s5pv310_driver); + +out: + if (!IS_ERR(cpu_clk)) + clk_put(cpu_clk); + + if (!IS_ERR(moutcore)) + clk_put(moutcore); + + if (!IS_ERR(mout_mpll)) + clk_put(mout_mpll); + + if (!IS_ERR(mout_apll)) + clk_put(mout_apll); + +#ifdef CONFIG_REGULATOR + if (!IS_ERR(arm_regulator)) + regulator_put(arm_regulator); + + if (!IS_ERR(int_regulator)) + regulator_put(int_regulator); +#endif + + printk(KERN_ERR "%s: failed initialization\n", __func__); + + return -EINVAL; +} +late_initcall(s5pv310_cpufreq_init); -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ @ 2010-09-18 2:45 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds support CPUFREQ driver for S5PV310 and S5PC210. This can support DVFS(Dynamic Voltage and Frequency Scaling). The voltage scaling depends on existence of regulator. Sigend-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Jaecheol Lee <jc.lee@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s5pv310/cpufreq.c | 561 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 561 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-s5pv310/cpufreq.c diff --git a/arch/arm/mach-s5pv310/cpufreq.c b/arch/arm/mach-s5pv310/cpufreq.c new file mode 100644 index 0000000..bcd4ebf --- /dev/null +++ b/arch/arm/mach-s5pv310/cpufreq.c @@ -0,0 +1,561 @@ +/* linux/arch/arm/mach-s5pv310/cpufreq.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * S5PV310 - 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. +*/ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/cpufreq.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> +#include <mach/regs-mem.h> + +#include <plat/clock.h> + +static struct clk *cpu_clk; +static struct clk *moutcore; +static struct clk *mout_mpll; +static struct clk *mout_apll; + +#ifdef CONFIG_REGULATOR +static struct regulator *arm_regulator; +static struct regulator *int_regulator; +#endif + +static struct cpufreq_freqs freqs; +static unsigned int armclk_use_apll; +static unsigned int memtype; + +enum s5pv310_memory_type { + DDR2 = 4, + LPDDR2, + DDR3, +}; + +enum cpufreq_level_index { + L0, L1, L2, L3, L4, CPUFREQ_LEVEL_END, +}; + +static struct cpufreq_frequency_table s5pv310_freq_table[] = { + {L0, 1000*1000}, + {L1, 800*1000}, + {L2, 400*1000}, + {L3, 200*1000}, + {L4, 100*1000}, + {0, CPUFREQ_TABLE_END}, +}; + +static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END + 1][7] = { + /* + * Clock divider value for following + * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH, + * DIVATB, DIVPCLK_DBG, DIVAPLL } + */ + + /* ARM L0: 1000MHz */ + { 0, 3, 7, 3, 3, 0, 0 }, + + /* ARM L1: 800MHz */ + { 0, 3, 7, 3, 3, 0, 0 }, + + /* ARM L2: 400MHz */ + { 1, 1, 3, 1, 1, 0, 0 }, + + /* ARM L3: 200MHz */ + { 3, 0, 1, 0, 0, 0, 0 }, + + /* ARM L4A: 100MHz, for DDR2/3 */ + { 7, 0, 1, 0, 0, 0, 0 }, + + /* ARM L4B: 100MHz, for LPDDR2 (SMDKV310 has LPDDR2) */ + { 7, 0, 1, 0, 0, 0, 0 }, +}; + +static unsigned int clkdiv_dmc0[CPUFREQ_LEVEL_END + 1][8] = { + /* + * Clock divider value for following + * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD + * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS } + */ + + /* DMC L0: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L1: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L2: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L3: 400MHz */ + { 3, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L4A: 400MHz, for DDR2/3 */ + { 7, 1, 1, 1, 1, 1, 3, 1 }, + + /* DMC L4B: 200MHz, for LPDDR2 */ + { 7, 1, 1, 3, 1, 1, 3, 1 }, +}; + +static unsigned int clkdiv_top[CPUFREQ_LEVEL_END + 1][5] = { + /* + * Clock divider value for following + * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND } + */ + + /* ACLK200 L0: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L1: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L2: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L3: 200MHz */ + { 3, 7, 4, 5, 1 }, + + /* ACLK200 L4A: 100MHz */ + { 7, 7, 7, 7, 1 }, + + /* ACLK200 L4B: 100MHz */ + { 7, 7, 7, 7, 1 }, +}; + +static unsigned int clkdiv_lr_bus[CPUFREQ_LEVEL_END + 1][2] = { + /* + * Clock divider value for following + * { DIVGDL/R, DIVGPL/R } + */ + + /* ACLK_GDL/R L0: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L1: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L2: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L3: 200MHz */ + { 3, 1 }, + + /* ACLK_GDL/R L4A: 100MHz */ + { 7, 1 }, + + /* ACLK_GDL/R L4B: 100MHz */ + { 7, 1 }, +}; + +struct cpufreq_voltage_table { + unsigned int index; /* any */ + unsigned int arm_volt; /* uV */ + unsigned int int_volt; +}; + +static struct cpufreq_voltage_table s5pv310_volt_table[] = { + { + .index = L0, + .arm_volt = 1200000, + .int_volt = 1100000, + }, { + .index = L1, + .arm_volt = 1100000, + .int_volt = 1100000, + }, { + .index = L2, + .arm_volt = 1050000, + .int_volt = 1100000, + }, { + .index = L3, + .arm_volt = 1050000, + .int_volt = 1100000, + }, { + .index = L4, + .arm_volt = 1000000, + .int_volt = 1000000, + }, +}; + +int s5pv310_verify_speed(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, s5pv310_freq_table); +} + +unsigned int s5pv310_getspeed(unsigned int cpu) +{ + return clk_get_rate(cpu_clk) / 1000; +} + +void s5pv310_set_clkdiv(unsigned int div_index) +{ + unsigned int tmp; + + /* Change Divider - CPU0 */ + + tmp = __raw_readl(S5P_CLKDIV_CPU); + + tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK | S5P_CLKDIV_CPU0_COREM0_MASK | + S5P_CLKDIV_CPU0_COREM1_MASK | S5P_CLKDIV_CPU0_PERIPH_MASK | + S5P_CLKDIV_CPU0_ATB_MASK | S5P_CLKDIV_CPU0_PCLKDBG_MASK | + S5P_CLKDIV_CPU0_APLL_MASK); + + tmp |= ((clkdiv_cpu0[div_index][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) | + (clkdiv_cpu0[div_index][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) | + (clkdiv_cpu0[div_index][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) | + (clkdiv_cpu0[div_index][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) | + (clkdiv_cpu0[div_index][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) | + (clkdiv_cpu0[div_index][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) | + (clkdiv_cpu0[div_index][6] << S5P_CLKDIV_CPU0_APLL_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_CPU); + + do { + tmp = __raw_readl(S5P_CLKDIV_STATCPU); + } while (tmp & 0x1111111); + + /* Change Divider - DMC0 */ + + tmp = __raw_readl(S5P_CLKDIV_DMC0); + + tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK | S5P_CLKDIV_DMC0_ACPPCLK_MASK | + S5P_CLKDIV_DMC0_DPHY_MASK | S5P_CLKDIV_DMC0_DMC_MASK | + S5P_CLKDIV_DMC0_DMCD_MASK | S5P_CLKDIV_DMC0_DMCP_MASK | + S5P_CLKDIV_DMC0_COPY2_MASK | S5P_CLKDIV_DMC0_CORETI_MASK); + + tmp |= ((clkdiv_dmc0[div_index][0] << S5P_CLKDIV_DMC0_ACP_SHIFT) | + (clkdiv_dmc0[div_index][1] << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) | + (clkdiv_dmc0[div_index][2] << S5P_CLKDIV_DMC0_DPHY_SHIFT) | + (clkdiv_dmc0[div_index][3] << S5P_CLKDIV_DMC0_DMC_SHIFT) | + (clkdiv_dmc0[div_index][4] << S5P_CLKDIV_DMC0_DMCD_SHIFT) | + (clkdiv_dmc0[div_index][5] << S5P_CLKDIV_DMC0_DMCP_SHIFT) | + (clkdiv_dmc0[div_index][6] << S5P_CLKDIV_DMC0_COPY2_SHIFT) | + (clkdiv_dmc0[div_index][7] << S5P_CLKDIV_DMC0_CORETI_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_DMC0); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0); + } while (tmp & 0x11111111); + + /* Change Divider - TOP */ + + tmp = __raw_readl(S5P_CLKDIV_TOP); + + tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK | S5P_CLKDIV_TOP_ACLK100_MASK | + S5P_CLKDIV_TOP_ACLK160_MASK | S5P_CLKDIV_TOP_ACLK133_MASK | + S5P_CLKDIV_TOP_ONENAND_MASK); + + tmp |= ((clkdiv_top[div_index][0] << S5P_CLKDIV_TOP_ACLK200_SHIFT) | + (clkdiv_top[div_index][1] << S5P_CLKDIV_TOP_ACLK100_SHIFT) | + (clkdiv_top[div_index][2] << S5P_CLKDIV_TOP_ACLK160_SHIFT) | + (clkdiv_top[div_index][3] << S5P_CLKDIV_TOP_ACLK133_SHIFT) | + (clkdiv_top[div_index][4] << S5P_CLKDIV_TOP_ONENAND_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_TOP); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_TOP); + } while (tmp & 0x11111); + + /* Change Divider - LEFTBUS */ + + tmp = __raw_readl(S5P_CLKDIV_LEFTBUS); + + tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK); + + tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) | + (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_LEFTBUS); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS); + } while (tmp & 0x11); + + /* Change Divider - RIGHTBUS */ + + tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS); + + tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK); + + tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) | + (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT)); + + __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS); + + do { + tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS); + } while (tmp & 0x11); +} + +static int s5pv310_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int index, div_index, tmp; + unsigned int arm_volt, int_volt; + unsigned int need_apll = 0; + + freqs.old = s5pv310_getspeed(policy->cpu); + + if (cpufreq_frequency_table_target(policy, s5pv310_freq_table, + target_freq, relation, &index)) + return -EINVAL; + + freqs.new = s5pv310_freq_table[index].frequency; + freqs.cpu = policy->cpu; + + if (freqs.new == freqs.old) + return 0; + + /* + * If freqs.new is higher than 800MHz + * cpufreq driver should turn on apll + */ + if (index < L1) + need_apll = 1; + + /* If the memory type is LPDDR2, use L4-B instead of L4-A */ + if ((index == L4) && (memtype == LPDDR2)) + div_index = index + 1; + else + div_index = index; + + /* get the voltage value */ + arm_volt = s5pv310_volt_table[index].arm_volt; + int_volt = s5pv310_volt_table[index].int_volt; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* control regulator */ + if (freqs.new > freqs.old) { + /* Voltage up */ +#ifdef CONFIG_REGULATOR + regulator_set_voltage(arm_regulator, arm_volt, arm_volt); + regulator_set_voltage(int_regulator, int_volt, int_volt); +#endif + } + + /* Clock Configuration Procedure */ + + /* 1. Change the system clock divider values */ + s5pv310_set_clkdiv(div_index); + + /* 2. Change the divider values for special clocks in CMU_TOP */ + /* currently nothing */ + + /* 3. Change the XPLL values or Select the parent XPLL */ + if (need_apll) { + if (!armclk_use_apll) { + /* + * If the parent clock of armclk isn't apll + * here need to set apll (include m,p,s value) + */ + + /* a. MUX_CORE_SEL = MPLL, + * ARMCLK uses MPLL for lock time */ + clk_set_parent(moutcore, mout_mpll); + + do { + tmp = (__raw_readl(S5P_CLKMUX_STATCPU) + >> S5P_CLKSRC_CPU_MUXCORE_SHIFT); + tmp &= 0x7; + } while (tmp != 0x2); + + /* b. Set APLL Lock time */ + __raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK); + + /* c. Change PLL PMS values */ + __raw_writel(S5P_APLL_VAL_1000, S5P_APLL_CON0); + + /* d. Turn on a PLL */ + tmp = __raw_readl(S5P_APLL_CON0); + tmp |= (0x1 << S5P_APLLCON0_ENABLE_SHIFT); + __raw_writel(tmp, S5P_APLL_CON0); + + /* e. wait_lock_time */ + do { + tmp = __raw_readl(S5P_APLL_CON0); + } while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT))); + + armclk_use_apll = 1; + + } + + /* MUX_CORE_SEL = APLL */ + clk_set_parent(moutcore, mout_apll); + + do { + tmp = __raw_readl(S5P_CLKMUX_STATCPU); + tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK; + } while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)); + + } else { + if (clk_get_parent(moutcore) != mout_mpll) { + clk_set_parent(moutcore, mout_mpll); + + do { + tmp = __raw_readl(S5P_CLKMUX_STATCPU); + tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK; + } while (tmp != (0x2 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)); + } + } + + /* control regulator */ + if (freqs.new < freqs.old) { + /* Voltage down */ +#ifdef CONFIG_REGULATOR + regulator_set_voltage(arm_regulator, arm_volt, arm_volt); + regulator_set_voltage(int_regulator, int_volt, int_volt); +#endif + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +#ifdef CONFIG_PM +static int s5pv310_cpufreq_suspend(struct cpufreq_policy *policy, + pm_message_t pmsg) +{ + return 0; +} + +static int s5pv310_cpufreq_resume(struct cpufreq_policy *policy) +{ + return 0; +} +#endif + +static int s5pv310_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + policy->cur = policy->min = policy->max = s5pv310_getspeed(policy->cpu); + + cpufreq_frequency_table_get_attr(s5pv310_freq_table, policy->cpu); + + /* set the transition latency value */ + policy->cpuinfo.transition_latency = 100000; + + /* + * S5PV310 multi-core processors has 2 cores + * that the frequency cannot be set independently. + * Each cpu is bound to the same speed. + * So the affected cpu is all of the cpus. + */ + cpumask_setall(policy->cpus); + + return cpufreq_frequency_table_cpuinfo(policy, s5pv310_freq_table); +} + +static struct cpufreq_driver s5pv310_driver = { + .flags = CPUFREQ_STICKY, + .verify = s5pv310_verify_speed, + .target = s5pv310_target, + .get = s5pv310_getspeed, + .init = s5pv310_cpufreq_cpu_init, + .name = "s5pv310_cpufreq", +#ifdef CONFIG_PM + .suspend = s5pv310_cpufreq_suspend, + .resume = s5pv310_cpufreq_resume, +#endif +}; + +static int __init s5pv310_cpufreq_init(void) +{ + unsigned int tmp; + + cpu_clk = clk_get(NULL, "armclk"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + moutcore = clk_get(NULL, "moutcore"); + if (IS_ERR(moutcore)) + goto out; + + mout_mpll = clk_get(NULL, "mout_mpll"); + if (IS_ERR(mout_mpll)) + goto out; + + mout_apll = clk_get(NULL, "mout_apll"); + if (IS_ERR(mout_apll)) + goto out; + +#ifdef CONFIG_REGULATOR + arm_regulator = regulator_get(NULL, "vdd_arm"); + if (IS_ERR(arm_regulator)) { + printk(KERN_ERR "failed to get resource %s\n", "vdd_arm"); + goto out; + } + + int_regulator = regulator_get(NULL, "vdd_int"); + if (IS_ERR(int_regulator)) { + printk(KERN_ERR "failed to get resource %s\n", "vdd_int"); + goto out; + } +#endif + + /* check parent clock of armclk */ + tmp = __raw_readl(S5P_CLKSRC_CPU); + if (tmp & S5P_CLKSRC_CPU_MUXCORE_SHIFT) + armclk_use_apll = 0; + else + armclk_use_apll = 1; + + /* + * Check DRAM type. + * Because DVFS level is different according to DRAM type. + */ + memtype = __raw_readl(S5P_VA_DMC0 + S5P_DMC0_MEMCON_OFFSET); + memtype = (memtype >> S5P_DMC0_MEMTYPE_SHIFT); + memtype &= S5P_DMC0_MEMTYPE_MASK; + + if ((memtype < DDR2) && (memtype > DDR3)) { + printk(KERN_ERR "%s: wrong memtype= 0x%x\n", __func__, memtype); + goto out; + } else { + printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype); + } + + return cpufreq_register_driver(&s5pv310_driver); + +out: + if (!IS_ERR(cpu_clk)) + clk_put(cpu_clk); + + if (!IS_ERR(moutcore)) + clk_put(moutcore); + + if (!IS_ERR(mout_mpll)) + clk_put(mout_mpll); + + if (!IS_ERR(mout_apll)) + clk_put(mout_apll); + +#ifdef CONFIG_REGULATOR + if (!IS_ERR(arm_regulator)) + regulator_put(arm_regulator); + + if (!IS_ERR(int_regulator)) + regulator_put(int_regulator); +#endif + + printk(KERN_ERR "%s: failed initialization\n", __func__); + + return -EINVAL; +} +late_initcall(s5pv310_cpufreq_init); -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ 2010-09-18 2:45 ` Kukjin Kim @ 2010-09-18 2:45 ` Kukjin Kim -1 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel, linux-samsung-soc; +Cc: ben-linux, Sunyoung Kang, Kukjin Kim From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds ARCH_HAS_CPUFREQ in Kconfig of ARCH_S5PV310 and updates Makefile for supporting build S5PV310 CPUFREQ driver. Signed-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/Kconfig | 1 + arch/arm/mach-s5pv310/Makefile | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bce9193..6424eec 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -733,6 +733,7 @@ config ARCH_S5PV310 select CPU_V7 select GENERIC_GPIO select HAVE_CLK + select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS help Samsung S5PV310 series based systems diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile index aefb14f..d17c8c7 100644 --- a/arch/arm/mach-s5pv310/Makefile +++ b/arch/arm/mach-s5pv310/Makefile @@ -14,6 +14,7 @@ obj- := obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ @ 2010-09-18 2:45 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-09-18 2:45 UTC (permalink / raw) To: linux-arm-kernel From: Sunyoung Kang <sy0816.kang@samsung.com> This patch adds ARCH_HAS_CPUFREQ in Kconfig of ARCH_S5PV310 and updates Makefile for supporting build S5PV310 CPUFREQ driver. Signed-off-by: Sunyoung Kang <sy0816.kang@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/Kconfig | 1 + arch/arm/mach-s5pv310/Makefile | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index bce9193..6424eec 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -733,6 +733,7 @@ config ARCH_S5PV310 select CPU_V7 select GENERIC_GPIO select HAVE_CLK + select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS help Samsung S5PV310 series based systems diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile index aefb14f..d17c8c7 100644 --- a/arch/arm/mach-s5pv310/Makefile +++ b/arch/arm/mach-s5pv310/Makefile @@ -14,6 +14,7 @@ obj- := obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o -- 1.6.2.5 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* RE: [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ 2010-09-18 2:45 ` Kukjin Kim @ 2010-10-20 6:48 ` Kukjin Kim -1 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-10-20 6:48 UTC (permalink / raw) To: 'Kukjin Kim', linux-arm-kernel, linux-samsung-soc; +Cc: ben-linux Kukjin Kim wrote: > > This patch adds support CPUFREQ driver for S5PV310 and S5PC210. > > NOTE: This patch dependes on following. > - ARM: S5PV310: Fix clkset_moutcore_list > - ARM: S5PV210: Add DMC map_desc table for supporting DMC access > > [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ > [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc > [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ > [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ > -- > 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 Hi, Basically, this CPUFREQ functionality has no problem, however, now ARCH_S5PV310 uses ARM private timer(localtimer) as event tick on each CPU core. It means that we need some handling on localtimer or anywhere about ARM clock changing by CPUFREQ driver...now it is not implemented..so I will drop this patches for -next...I think we can do it at 37-rc. 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] 12+ messages in thread
* [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ @ 2010-10-20 6:48 ` Kukjin Kim 0 siblings, 0 replies; 12+ messages in thread From: Kukjin Kim @ 2010-10-20 6:48 UTC (permalink / raw) To: linux-arm-kernel Kukjin Kim wrote: > > This patch adds support CPUFREQ driver for S5PV310 and S5PC210. > > NOTE: This patch dependes on following. > - ARM: S5PV310: Fix clkset_moutcore_list > - ARM: S5PV210: Add DMC map_desc table for supporting DMC access > > [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ > [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc > [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ > [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ > -- > 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 Hi, Basically, this CPUFREQ functionality has no problem, however, now ARCH_S5PV310 uses ARM private timer(localtimer) as event tick on each CPU core. It means that we need some handling on localtimer or anywhere about ARM clock changing by CPUFREQ driver...now it is not implemented..so I will drop this patches for -next...I think we can do it at 37-rc. 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] 12+ messages in thread
end of thread, other threads:[~2010-10-20 6:48 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-09-18 2:45 [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ Kukjin Kim 2010-09-18 2:45 ` Kukjin Kim 2010-09-18 2:45 ` [PATCH 1/4] ARM: S5PV310: Update CMU registers for CPUFREQ Kukjin Kim 2010-09-18 2:45 ` Kukjin Kim 2010-09-18 2:45 ` [PATCH 2/4] ARM: S5PV310: Add DMC registers and map_desc Kukjin Kim 2010-09-18 2:45 ` Kukjin Kim 2010-09-18 2:45 ` [PATCH 3/4] ARM: S5PV310: Add support CPUFREQ Kukjin Kim 2010-09-18 2:45 ` Kukjin Kim 2010-09-18 2:45 ` [PATCH 4/4] ARM: S5PV310: Update Kconfig and Makefile for supporting CPUFREQ Kukjin Kim 2010-09-18 2:45 ` Kukjin Kim 2010-10-20 6:48 ` [PATCH 0/4] ARM: S5PV310: Add support S5PV310/S5PC210 CPUFREQ Kukjin Kim 2010-10-20 6:48 ` 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.