linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110
@ 2010-09-15  7:52 Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table Jaecheol Lee
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Jaecheol Lee @ 2010-09-15  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds CPUFREQ for S5PV210/S5PC110.

[PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table
[PATCH 2/5] ARM: S5PV210: Add struct clk_ops for clk_fout_apll
[PATCH 3/5] ARM: S5PV210: Add Register definition for CMU
[PATCH 4/5] ARM: S5PV210: Add support CPUFREQ
[PATCH 5/5] ARM: S5PV210: Update Kconfig and Makefile for supporting CPUFREQ driver

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

* [PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table
  2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
@ 2010-09-15  7:52 ` Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 2/5] ARM: S5PV210: Add struct clk_ops for clk_fout_apll Jaecheol Lee
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Jaecheol Lee @ 2010-09-15  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds DMC(DRAM Memory Controller) map_desc table.
Because some driver such as CPUFREQ need to access DMC register.

Signed-off-by: Jaecheol Lee <jc.lee@samsung.com>
---
 arch/arm/mach-s5pv210/cpu.c              |   10 ++++++++++
 arch/arm/mach-s5pv210/include/mach/map.h |    3 +++
 arch/arm/plat-s5p/include/plat/map-s5p.h |    2 ++
 3 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index c551ab1..aebbb7f 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -84,6 +84,16 @@ 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,
 	}
 };
 
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index bd9afd5..3e89c22 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -96,6 +96,9 @@
 
 #define S5PV210_PA_ADC		(0xE1700000)
 
+#define S5PV210_PA_DMC0		(0xF0000000)
+#define S5PV210_PA_DMC1		(0xF1400000)
+
 /* compatibiltiy defines. */
 #define S3C_PA_UART		S5PV210_PA_UART
 #define S3C_PA_HSMMC0		S5PV210_PA_HSMMC(0)
diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h
index c4ff88b..2472894 100644
--- a/arch/arm/plat-s5p/include/plat/map-s5p.h
+++ b/arch/arm/plat-s5p/include/plat/map-s5p.h
@@ -18,6 +18,8 @@
 #define S5P_VA_SYSTIMER		S3C_ADDR(0x01200000)
 #define S5P_VA_SROMC		S3C_ADDR(0x01100000)
 #define S5P_VA_SYSRAM		S3C_ADDR(0x01180000)
+#define S5P_VA_DMC0		S3C_ADDR(0x00A00000)
+#define S5P_VA_DMC1		S3C_ADDR(0x00A80000)
 
 #define S5P_VA_COMBINER_BASE	S3C_ADDR(0x00600000)
 #define S5P_VA_COMBINER(x)	(S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10)
-- 
1.6.2.5

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

* [PATCH 2/5] ARM: S5PV210: Add struct clk_ops for clk_fout_apll
  2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table Jaecheol Lee
@ 2010-09-15  7:52 ` Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 3/5] ARM: S5PV210: Add Register definition for CMU Jaecheol Lee
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Jaecheol Lee @ 2010-09-15  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

Current fout_apll has fixed rate value which was set in initializing
S5PV210 clock structures. CPUFREQ driver gets incorrect frequency when
finding current cpu frequency, because some operation level need to
change APLL. Newly added get_rate function for fout_apll can give
correct frequency when calling get_rate function by CPUFREQ driver.

Signed-off-by: Jaecheol Lee <jc.lee@samsung.com>
---
 arch/arm/mach-s5pv210/clock.c |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index d562670..e18e098 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -31,6 +31,8 @@
 #include <plat/clock-clksrc.h>
 #include <plat/s5pv210.h>
 
+static unsigned long xtal;
+
 static struct clksrc_clk clk_mout_apll = {
 	.clk	= {
 		.name		= "mout_apll",
@@ -268,6 +270,15 @@ static struct clk_ops clk_hclk_imem_ops = {
 	.get_rate	= s5pv210_clk_imem_get_rate,
 };
 
+static unsigned long s5pv210_clk_fout_apll_get_rate(struct clk *clk)
+{
+	return s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
+}
+
+static struct clk_ops clk_fout_apll_ops = {
+	.get_rate	= s5pv210_clk_fout_apll_get_rate,
+};
+
 static struct clk init_clocks_disable[] = {
 	{
 		.name		= "rot",
@@ -958,7 +969,6 @@ static struct clksrc_clk *sysclks[] = {
 void __init_or_cpufreq s5pv210_setup_clocks(void)
 {
 	struct clk *xtal_clk;
-	unsigned long xtal;
 	unsigned long vpllsrc;
 	unsigned long armclk;
 	unsigned long hclk_msys;
@@ -996,7 +1006,7 @@ void __init_or_cpufreq s5pv210_setup_clocks(void)
 	vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
 	vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502);
 
-	clk_fout_apll.rate = apll;
+	clk_fout_apll.ops = &clk_fout_apll_ops;
 	clk_fout_mpll.rate = mpll;
 	clk_fout_epll.rate = epll;
 	clk_fout_vpll.rate = vpll;
-- 
1.6.2.5

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

* [PATCH 3/5] ARM: S5PV210: Add Register definition for CMU
  2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 2/5] ARM: S5PV210: Add struct clk_ops for clk_fout_apll Jaecheol Lee
@ 2010-09-15  7:52 ` Jaecheol Lee
  2010-09-15  7:52 ` [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ Jaecheol Lee
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Jaecheol Lee @ 2010-09-15  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds some CMU(Clock Management Unit) registers for
supporting CPUFREQ and some drivers.

Signed-off-by: Jaecheol Lee <jc.lee@samsung.com>
---
 arch/arm/mach-s5pv210/include/mach/regs-clock.h |   31 ++++++++++++++++++++++-
 1 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
index 499aef7..336b1cf 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
@@ -67,11 +67,28 @@
 #define S5P_CLKGATE_BUS1	S5P_CLKREG(0x488)
 #define S5P_CLK_OUT		S5P_CLKREG(0x500)
 
+/* DIV/MUX STATUS */
+#define S5P_CLKDIV_STAT0	S5P_CLKREG(0x1000)
+#define S5P_CLKDIV_STAT1	S5P_CLKREG(0x1004)
+#define S5P_CLKMUX_STAT0	S5P_CLKREG(0x1100)
+#define S5P_CLKMUX_STAT1	S5P_CLKREG(0x1104)
+
 /* CLKSRC0 */
-#define S5P_CLKSRC0_MUX200_MASK		(0x1<<16)
+#define S5P_CLKSRC0_MUX200_SHIFT	(16)
+#define S5P_CLKSRC0_MUX200_MASK		(0x1 << S5P_CLKSRC0_MUX200_SHIFT)
 #define S5P_CLKSRC0_MUX166_MASK		(0x1<<20)
 #define S5P_CLKSRC0_MUX133_MASK		(0x1<<24)
 
+/* CLKSRC2 */
+#define S5P_CLKSRC2_G3D_SHIFT           (0)
+#define S5P_CLKSRC2_G3D_MASK            (0x3 << S5P_CLKSRC2_G3D_SHIFT)
+#define S5P_CLKSRC2_MFC_SHIFT           (4)
+#define S5P_CLKSRC2_MFC_MASK            (0x3 << S5P_CLKSRC2_MFC_SHIFT)
+
+/* CLKSRC6*/
+#define S5P_CLKSRC6_ONEDRAM_SHIFT       (24)
+#define S5P_CLKSRC6_ONEDRAM_MASK        (0x3 << S5P_CLKSRC6_ONEDRAM_SHIFT)
+
 /* CLKDIV0 */
 #define S5P_CLKDIV0_APLL_SHIFT		(0)
 #define S5P_CLKDIV0_APLL_MASK		(0x7 << S5P_CLKDIV0_APLL_SHIFT)
@@ -90,8 +107,20 @@
 #define S5P_CLKDIV0_PCLK66_SHIFT	(28)
 #define S5P_CLKDIV0_PCLK66_MASK		(0x7 << S5P_CLKDIV0_PCLK66_SHIFT)
 
+/* CLKDIV2 */
+#define S5P_CLKDIV2_G3D_SHIFT           (0)
+#define S5P_CLKDIV2_G3D_MASK            (0xF << S5P_CLKDIV2_G3D_SHIFT)
+#define S5P_CLKDIV2_MFC_SHIFT           (4)
+#define S5P_CLKDIV2_MFC_MASK            (0xF << S5P_CLKDIV2_MFC_SHIFT)
+
+/* CLKDIV6 */
+#define S5P_CLKDIV6_ONEDRAM_SHIFT       (28)
+#define S5P_CLKDIV6_ONEDRAM_MASK        (0xF << S5P_CLKDIV6_ONEDRAM_SHIFT)
+
 #define S5P_SWRESET		S5P_CLKREG(0x2000)
 
+#define S5P_ARM_MCS_CON		S5P_CLKREG(0x6100)
+
 /* Registers related to power management */
 #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
 #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
-- 
1.6.2.5

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

* [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ
  2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
                   ` (2 preceding siblings ...)
  2010-09-15  7:52 ` [PATCH 3/5] ARM: S5PV210: Add Register definition for CMU Jaecheol Lee
@ 2010-09-15  7:52 ` Jaecheol Lee
  2010-09-16  0:36   ` MyungJoo Ham
  2010-09-15  7:52 ` [PATCH 5/5] ARM: S5PV210: Update Kconfig and Makefile for supporting CPUFREQ driver Jaecheol Lee
  2010-09-16  0:33 ` [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Kyungmin Park
  5 siblings, 1 reply; 10+ messages in thread
From: Jaecheol Lee @ 2010-09-15  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds CPUFREQ driver for supporting DFS(Dynamic Frequency Scaling).

Signed-off-by: Jaecheol Lee <jc.lee@samsung.com>
---
 arch/arm/mach-s5pv210/cpufreq.c |  415 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 415 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s5pv210/cpufreq.c

diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c
new file mode 100644
index 0000000..aa39c2e
--- /dev/null
+++ b/arch/arm/mach-s5pv210/cpufreq.c
@@ -0,0 +1,415 @@
+/* linux/arch/arm/mach-s5pv210/cpufreq.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * CPU frequency scaling for S5PC110/S5PV210
+ *
+ * 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/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/cpufreq.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+static struct clk *cpu_clk;
+static struct cpufreq_freqs freqs;
+
+/* APLL M,P,S values for 1G/800Mhz */
+#define APLL_VAL_1000	(1 << 31) | (125 << 16) | (3 << 8) | 1
+#define APLL_VAL_800	(1 << 31) | (100 << 16) | (3 << 8) | 1
+
+enum perf_level {
+	L0, L1, L2, L3, L4,
+};
+
+enum s5pv210_mem_type {
+	LPDDR	= 0x1,
+	LPDDR2	= 0x2,
+	DDR2	= 0x4,
+};
+
+static struct cpufreq_frequency_table s5pv210_freq_table[] = {
+	{L0, 1000*1000},
+	{L1, 800*1000},
+	{L2, 400*1000},
+	{L3, 200*1000},
+	{L4, 100*1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+static u32 clkdiv_val[5][11] = {
+	/*
+	 * Clock divider value for following
+	 * { APLL, A2M, HCLK_MSYS, PCLK_MSYS,
+	 *   HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS,
+	 *   ONEDRAM, MFC, G3D }
+	 */
+
+	/* L0 : [1000/200/100][166/83][133/66][200/200] */
+	{0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L1 : [800/200/100][166/83][133/66][200/200] */
+	{0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L2 : [400/200/100][166/83][133/66][200/200] */
+	{1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L3 : [200/200/100][166/83][133/66][200/200] */
+	{3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L4 : [100/100/100][83/83][66/66][100/100] */
+	{7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
+};
+
+int s5pv210_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, s5pv210_freq_table);
+}
+
+unsigned int s5pv210_getspeed(unsigned int cpu)
+{
+	if (cpu)
+		return 0;
+
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int s5pv210_target(struct cpufreq_policy *policy,
+		          unsigned int target_freq,
+		          unsigned int relation)
+{
+	unsigned long reg;
+	unsigned int index, priv_index;
+	unsigned int pll_changing = 0;
+	unsigned int bus_speed_changing = 0;
+
+	freqs.old = s5pv210_getspeed(0);
+
+	if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
+					   target_freq, relation, &index))
+		return -EINVAL;
+
+	freqs.new = s5pv210_freq_table[index].frequency;
+	freqs.cpu = 0;
+
+	if (freqs.new == freqs.old)
+		return 0;
+
+	/* Finding current running level index */
+	if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
+					   freqs.old, relation, &priv_index))
+		return -EINVAL;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	if (freqs.new > freqs.old) {
+		/* Voltage up: will be implemented */
+	}
+
+	/* Check if there need to change PLL */
+	if ((index == L0) || (priv_index == L0))
+		pll_changing = 1;
+
+	/* Check if there need to change System bus clock */
+	if ((index == L4) || (priv_index == L4))
+		bus_speed_changing = 1;
+
+	if (bus_speed_changing) {
+		/*
+		 * Reconfigure DRAM refresh counter value for minimum
+		 * temporary clock while changing divider.
+		 * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287
+		 */
+		if (pll_changing)
+			__raw_writel(0x287, S5P_VA_DMC1 + 0x30);
+		else
+			__raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
+
+		__raw_writel(0x287, S5P_VA_DMC0 + 0x30);
+	}
+
+	/*
+	 * APLL should be changed in this level
+	 * APLL -> MPLL(for stable transition) -> APLL
+	 * Some clock source's clock API are not prepared.
+	 * Do not use clock API in below code.
+	 */
+	if (pll_changing) {
+		/*
+		 * 1. Temporary 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 |= (3 << S5P_CLKDIV2_G3D_SHIFT) |
+			(3 << S5P_CLKDIV2_MFC_SHIFT);
+		__raw_writel(reg, S5P_CLK_DIV2);
+
+		/* For MFC, G3D dividing */
+		do {
+			reg = __raw_readl(S5P_CLKDIV_STAT0);
+		} while (reg & ((1 << 16) | (1 << 17)));
+
+		/*
+		 * 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX
+		 * (200/4=50)->(667/4=166)Mhz
+		 */
+		reg = __raw_readl(S5P_CLK_SRC2);
+		reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+		reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) |
+			(1 << S5P_CLKSRC2_MFC_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC2);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT1);
+		} while (reg & ((1 << 7) | (1 << 3)));
+
+		/*
+		 * 3. DMC1 refresh count for 133Mhz if (index == L4) is
+		 * true refresh counter is already programed in upper
+		 * code. 0x287@83Mhz
+		 */
+		if (!bus_speed_changing)
+			__raw_writel(0x40d, S5P_VA_DMC1 + 0x30);
+
+		/* 4. SCLKAPLL -> SCLKMPLL */
+		reg = __raw_readl(S5P_CLK_SRC0);
+		reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+		reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC0);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT0);
+		} while (reg & (0x1 << 18));
+
+	}
+
+	/* Change divider */
+	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_CLKDIV_STAT0);
+	} while (reg & 0xff);
+
+	/* ARM MCS value changed */
+	reg = __raw_readl(S5P_ARM_MCS_CON);
+	reg &= ~0x3;
+	if (index >= L3)
+		reg |= 0x3;
+	else
+		reg |= 0x1;
+
+	__raw_writel(reg, S5P_ARM_MCS_CON);
+
+	if (pll_changing) {
+		/* 5. Set Lock time = 30us*24Mhz = 0x2cf */
+		__raw_writel(0x2cf, S5P_APLL_LOCK);
+
+		/*
+		 * 6. Turn on APLL
+		 * 6-1. Set PMS values
+		 * 6-2. Wait untile the PLL is locked
+		 */
+		if (index == L0)
+			__raw_writel(APLL_VAL_1000, S5P_APLL_CON);
+		else
+			__raw_writel(APLL_VAL_800, S5P_APLL_CON);
+
+		do {
+			reg = __raw_readl(S5P_APLL_CON);
+		} while (!(reg & (0x1 << 29)));
+
+		/*
+		 * 7. Change souce 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);
+		__raw_writel(reg, S5P_CLK_SRC2);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT1);
+		} while (reg & ((1 << 7) | (1 << 3)));
+
+		/*
+		 * 8. 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);
+		__raw_writel(reg, S5P_CLK_DIV2);
+
+		/* For MFC, G3D dividing */
+		do {
+			reg = __raw_readl(S5P_CLKDIV_STAT0);
+		} while (reg & ((1 << 16) | (1 << 17)));
+
+		/* 9. Change MPLL to APLL in MSYS_MUX */
+		reg = __raw_readl(S5P_CLK_SRC0);
+		reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+		reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC0);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT0);
+		} while (reg & (0x1 << 18));
+
+		/*
+		 * 10. DMC1 refresh counter
+		 * L4 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c
+		 * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618
+		 */
+		if (!bus_speed_changing)
+			__raw_writel(0x618, S5P_VA_DMC1 + 0x30);
+	}
+
+	/*
+	 * L4 level need to change memory bus speed, hence onedram clock divier
+	 * and memory refresh parameter should be changed
+	 */
+	if (bus_speed_changing) {
+		reg = __raw_readl(S5P_CLK_DIV6);
+		reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
+		reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
+		__raw_writel(reg, S5P_CLK_DIV6);
+
+		do {
+			reg = __raw_readl(S5P_CLKDIV_STAT1);
+		} while (reg & (1 << 15));
+
+		/* Reconfigure DRAM refresh counter value */
+		if (index != L4) {
+			/*
+			 * DMC0 : 166Mhz
+			 * DMC1 : 200Mhz
+			 */
+			__raw_writel(0x618, S5P_VA_DMC1 + 0x30);
+			__raw_writel(0x50e, S5P_VA_DMC0 + 0x30);
+		} else {
+			/*
+			 * DMC0 : 83Mhz
+			 * DMC1 : 100Mhz
+			 */
+			__raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
+			__raw_writel(0x287, S5P_VA_DMC0 + 0x30);
+		}
+	}
+
+	if (freqs.new < freqs.old) {
+		/* Voltage down: will be implemented */
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	printk(KERN_INFO "Perf changed[L%d]\n", index);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
+				   pm_message_t pmsg)
+{
+	return 0;
+}
+
+static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
+{
+	return 0;
+}
+#endif
+
+static int check_mem_type(void __iomem *dmc_reg)
+{
+	unsigned long val;
+
+	val = __raw_readl(dmc_reg + 0x4);
+	val = (val & (0xf << 8));
+
+	return (val >> 8);
+}
+
+static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned long mem_type;
+
+	cpu_clk = clk_get(NULL, "armclk");
+	if (IS_ERR(cpu_clk))
+		return PTR_ERR(cpu_clk);
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	/*
+	 * check_mem_type : This driver only support LPDDR & LPDDR2.
+	 * other memory type is not supported.
+	 */
+	mem_type = check_mem_type(S5P_VA_DMC0);
+
+	if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
+		printk(KERN_ERR "CPUFreq doesn't support this memory type\n");
+		return -EINVAL;
+	}
+
+	policy->cur = policy->min = policy->max = s5pv210_getspeed(0);
+
+	cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu);
+
+	policy->cpuinfo.transition_latency = 40000;
+
+	return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table);
+}
+
+static struct cpufreq_driver s5pv210_driver = {
+	.flags		= CPUFREQ_STICKY,
+	.verify		= s5pv210_verify_speed,
+	.target		= s5pv210_target,
+	.get		= s5pv210_getspeed,
+	.init		= s5pv210_cpu_init,
+	.name		= "s5pv210",
+#ifdef CONFIG_PM
+	.suspend	= s5pv210_cpufreq_suspend,
+	.resume		= s5pv210_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv210_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&s5pv210_driver);
+}
+
+late_initcall(s5pv210_cpufreq_init);
-- 
1.6.2.5

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

* [PATCH 5/5] ARM: S5PV210: Update Kconfig and Makefile for supporting CPUFREQ driver
  2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
                   ` (3 preceding siblings ...)
  2010-09-15  7:52 ` [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ Jaecheol Lee
@ 2010-09-15  7:52 ` Jaecheol Lee
  2010-09-16  0:33 ` [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Kyungmin Park
  5 siblings, 0 replies; 10+ messages in thread
From: Jaecheol Lee @ 2010-09-15  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds ARCH_HAS_CPUFREQ in arch/arm/Kconfig for S5PV210,
and updates mach-s5pv210/Makefile for supporting build CPUFREQ driver.

Signed-off-by: Jaecheol Lee <jc.lee@samsung.com>
---
 arch/arm/Kconfig               |    1 +
 arch/arm/mach-s5pv210/Makefile |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index bce9193..7bff1d2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -721,6 +721,7 @@ config ARCH_S5PV210
 	select GENERIC_GPIO
 	select HAVE_CLK
 	select ARM_L1_CACHE_SHIFT_6
+	select ARCH_HAS_CPUFREQ
 	select ARCH_USES_GETTIMEOFFSET
 	select HAVE_S3C2410_I2C
 	select HAVE_S3C_RTC
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index 7045489..833d803 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -14,6 +14,7 @@ obj-				:=
 
 obj-$(CONFIG_CPU_S5PV210)	+= cpu.o init.o clock.o dma.o gpiolib.o
 obj-$(CONFIG_CPU_S5PV210)	+= setup-i2c0.o
+obj-$(CONFIG_CPU_FREQ)		+= cpufreq.o
 
 # machine support
 
-- 
1.6.2.5

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

* [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110
  2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
                   ` (4 preceding siblings ...)
  2010-09-15  7:52 ` [PATCH 5/5] ARM: S5PV210: Update Kconfig and Makefile for supporting CPUFREQ driver Jaecheol Lee
@ 2010-09-16  0:33 ` Kyungmin Park
  2010-09-17  4:24   ` Kukjin Kim
  5 siblings, 1 reply; 10+ messages in thread
From: Kyungmin Park @ 2010-09-16  0:33 UTC (permalink / raw)
  To: linux-arm-kernel

First thank you for posting the patches.
but I'm worry about sending the same feature patches from different divisions.

I'm not sure you're talking with kgene. but there are some codes
posted by Mr. Ham and get feedback and reviewed with kgene.
http://git.infradead.org/users/kmpark/linux-2.6-samsung/shortlog/refs/heads/cpufreq

To kgene,
One code from DMC(me), another code from System LSI(you). then which
codes do you pick up and apply to mainline?
and what's rules or principles?

Thank you,
Kyungmin Park

On Wed, Sep 15, 2010 at 4:52 PM, Jaecheol Lee <jc.lee@samsung.com> wrote:
> This patch adds CPUFREQ for S5PV210/S5PC110.
>
> [PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table
> [PATCH 2/5] ARM: S5PV210: Add struct clk_ops for clk_fout_apll
> [PATCH 3/5] ARM: S5PV210: Add Register definition for CMU
> [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ
> [PATCH 5/5] ARM: S5PV210: Update Kconfig and Makefile for supporting CPUFREQ driver
> --
> 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] 10+ messages in thread

* [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ
  2010-09-15  7:52 ` [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ Jaecheol Lee
@ 2010-09-16  0:36   ` MyungJoo Ham
  0 siblings, 0 replies; 10+ messages in thread
From: MyungJoo Ham @ 2010-09-16  0:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, Sep 15, 2010 at 4:52 PM, Jaecheol Lee <jc.lee@samsung.com> wrote:
> This patch adds CPUFREQ driver for supporting DFS(Dynamic Frequency Scaling).
>
> Signed-off-by: Jaecheol Lee <jc.lee@samsung.com>
> ---
> ?arch/arm/mach-s5pv210/cpufreq.c | ?415 +++++++++++++++++++++++++++++++++++++++
> ?1 files changed, 415 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/mach-s5pv210/cpufreq.c
>
> diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c
> new file mode 100644
> index 0000000..aa39c2e

(snip)

> +static int s5pv210_target(struct cpufreq_policy *policy,
> + ? ? ? ? ? ? ? ? ? ? ? ? unsigned int target_freq,
> + ? ? ? ? ? ? ? ? ? ? ? ? unsigned int relation)
> +{
> + ? ? ? unsigned long reg;
> + ? ? ? unsigned int index, priv_index;
> + ? ? ? unsigned int pll_changing = 0;
> + ? ? ? unsigned int bus_speed_changing = 0;
> +
> + ? ? ? freqs.old = s5pv210_getspeed(0);
> +
> + ? ? ? if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?target_freq, relation, &index))
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? freqs.new = s5pv210_freq_table[index].frequency;
> + ? ? ? freqs.cpu = 0;
> +
> + ? ? ? if (freqs.new == freqs.old)
> + ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? /* Finding current running level index */
> + ? ? ? if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?freqs.old, relation, &priv_index))
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +
> + ? ? ? if (freqs.new > freqs.old) {
> + ? ? ? ? ? ? ? /* Voltage up: will be implemented */

This could be crucial to the system stability. It is usually not optional.

> + ? ? ? }
> +
> + ? ? ? /* Check if there need to change PLL */
> + ? ? ? if ((index == L0) || (priv_index == L0))
> + ? ? ? ? ? ? ? pll_changing = 1;
> +
> + ? ? ? /* Check if there need to change System bus clock */
> + ? ? ? if ((index == L4) || (priv_index == L4))
> + ? ? ? ? ? ? ? bus_speed_changing = 1;
> +
> + ? ? ? if (bus_speed_changing) {
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* Reconfigure DRAM refresh counter value for minimum
> + ? ? ? ? ? ? ? ?* temporary clock while changing divider.
> + ? ? ? ? ? ? ? ?* expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287
> + ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? if (pll_changing)
> + ? ? ? ? ? ? ? ? ? ? ? __raw_writel(0x287, S5P_VA_DMC1 + 0x30);
> + ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? ? ? ? __raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
> +
> + ? ? ? ? ? ? ? __raw_writel(0x287, S5P_VA_DMC0 + 0x30);

It'd be better to set values based on the real MPLL, APLL clock
speeds, not hard-coding them.

> + ? ? ? }
> +

(snip)

> +
> + ? ? ? /*
> + ? ? ? ?* L4 level need to change memory bus speed, hence onedram clock divier
> + ? ? ? ?* and memory refresh parameter should be changed
> + ? ? ? ?*/
> + ? ? ? if (bus_speed_changing) {
> + ? ? ? ? ? ? ? reg = __raw_readl(S5P_CLK_DIV6);
> + ? ? ? ? ? ? ? reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
> + ? ? ? ? ? ? ? reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
> + ? ? ? ? ? ? ? __raw_writel(reg, S5P_CLK_DIV6);
> +
> + ? ? ? ? ? ? ? do {
> + ? ? ? ? ? ? ? ? ? ? ? reg = __raw_readl(S5P_CLKDIV_STAT1);
> + ? ? ? ? ? ? ? } while (reg & (1 << 15));
> +
> + ? ? ? ? ? ? ? /* Reconfigure DRAM refresh counter value */
> + ? ? ? ? ? ? ? if (index != L4) {
> + ? ? ? ? ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ? ? ? ? ?* DMC0 : 166Mhz
> + ? ? ? ? ? ? ? ? ? ? ? ?* DMC1 : 200Mhz
> + ? ? ? ? ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? ? ? ? ? __raw_writel(0x618, S5P_VA_DMC1 + 0x30);
> + ? ? ? ? ? ? ? ? ? ? ? __raw_writel(0x50e, S5P_VA_DMC0 + 0x30);
> + ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ? ? ? ? ?* DMC0 : 83Mhz
> + ? ? ? ? ? ? ? ? ? ? ? ?* DMC1 : 100Mhz
> + ? ? ? ? ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? ? ? ? ? __raw_writel(0x30c, S5P_VA_DMC1 + 0x30);
> + ? ? ? ? ? ? ? ? ? ? ? __raw_writel(0x287, S5P_VA_DMC0 + 0x30);
> + ? ? ? ? ? ? ? }

Same here. It'd better not be hard coded. We can't sure about the
clock speeds for different boards.

> + ? ? ? }
> +
> + ? ? ? if (freqs.new < freqs.old) {
> + ? ? ? ? ? ? ? /* Voltage down: will be implemented */
> + ? ? ? }
> +
> + ? ? ? cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> +
> + ? ? ? printk(KERN_INFO "Perf changed[L%d]\n", index);

This may incur too many clutters.

> +
> + ? ? ? return 0;
> +}
> +
(snip)

>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

Overall, this patch appears to be subset of the previous "[PATCH v7
6/6] ARM: S5PV210: Initial CPUFREQ Support" and things omitted (and
should be added) are already implemented there.



-- 
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] 10+ messages in thread

* [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110
  2010-09-16  0:33 ` [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Kyungmin Park
@ 2010-09-17  4:24   ` Kukjin Kim
  2010-09-17  4:30     ` Kyungmin Park
  0 siblings, 1 reply; 10+ messages in thread
From: Kukjin Kim @ 2010-09-17  4:24 UTC (permalink / raw)
  To: linux-arm-kernel

Kyungmin Park wrote:
> 
> First thank you for posting the patches.
> but I'm worry about sending the same feature patches from different
divisions.
> 
It doesn't matter which division it is from.
What matters is the quality of the patch.
Any patches can be submitted anytime anywhere.

> I'm not sure you're talking with kgene. but there are some codes
> posted by Mr. Ham and get feedback and reviewed with kgene.
> http://git.infradead.org/users/kmpark/linux-2.6-
> samsung/shortlog/refs/heads/cpufreq
> 
> To kgene,
> One code from DMC(me), another code from System LSI(you). then which
> codes do you pick up and apply to mainline?

As I said, it is not important where it is from.
I will apply the best patch.

> and what's rules or principles?
> 
The best patch will get merged.
And I think that's the purpose of mailing lists
- to put all ideas together and find the best solution.

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] 10+ messages in thread

* [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110
  2010-09-17  4:24   ` Kukjin Kim
@ 2010-09-17  4:30     ` Kyungmin Park
  0 siblings, 0 replies; 10+ messages in thread
From: Kyungmin Park @ 2010-09-17  4:30 UTC (permalink / raw)
  To: linux-arm-kernel

2010/9/17 Kukjin Kim <kgene.kim@samsung.com>:
> Kyungmin Park wrote:
>>
>> First thank you for posting the patches.
>> but I'm worry about sending the same feature patches from different
> divisions.
>>
> It doesn't matter which division it is from.
> What matters is the quality of the patch.
> Any patches can be submitted anytime anywhere.
>
>> I'm not sure you're talking with kgene. but there are some codes
>> posted by Mr. Ham and get feedback and reviewed with kgene.
>> http://git.infradead.org/users/kmpark/linux-2.6-
>> samsung/shortlog/refs/heads/cpufreq
>>
>> To kgene,
>> One code from DMC(me), another code from System LSI(you). then which
>> codes do you pick up and apply to mainline?
>
> As I said, it is not important where it is from.
> I will apply the best patch.
>
>> and what's rules or principles?
>>
> The best patch will get merged.
> And I think that's the purpose of mailing lists
> - to put all ideas together and find the best solution.

But no need to do same things. Look at the patches. do the same
mistake, e.g., hard-corded values. but Mr. Ham's patch already fixed
it and support full features.

>
> 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] 10+ messages in thread

end of thread, other threads:[~2010-09-17  4:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-15  7:52 [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Jaecheol Lee
2010-09-15  7:52 ` [PATCH 1/5] ARM: S5PV210: Add support DMC map_desc table Jaecheol Lee
2010-09-15  7:52 ` [PATCH 2/5] ARM: S5PV210: Add struct clk_ops for clk_fout_apll Jaecheol Lee
2010-09-15  7:52 ` [PATCH 3/5] ARM: S5PV210: Add Register definition for CMU Jaecheol Lee
2010-09-15  7:52 ` [PATCH 4/5] ARM: S5PV210: Add support CPUFREQ Jaecheol Lee
2010-09-16  0:36   ` MyungJoo Ham
2010-09-15  7:52 ` [PATCH 5/5] ARM: S5PV210: Update Kconfig and Makefile for supporting CPUFREQ driver Jaecheol Lee
2010-09-16  0:33 ` [PATCH 0/5] ARM: S5PV210: Add support CPUFREQ for S5PV210/S5PC110 Kyungmin Park
2010-09-17  4:24   ` Kukjin Kim
2010-09-17  4:30     ` Kyungmin Park

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).