[PATCH] ARM: EXYNOS5: Add g3d clock hierarchy

Abhilash Kesavan a.kesavan at samsung.com
Wed Jan 9 02:03:42 EST 2013


Add G3D clock support for Exynos5.
To setup an initial frequency of 533MHz for the G3D block we need
to have the parent source clock of MOUTACLK_400_G3D as sclk_gpll
and the divisor register as 0.

Signed-off-by: Abhilash Kesavan <a.kesavan at samsung.com>
---
 arch/arm/mach-exynos/clock-exynos5.c           |  150 ++++++++++++++++++++++--
 arch/arm/mach-exynos/include/mach/regs-clock.h |    4 +
 arch/arm/plat-samsung/include/plat/s5p-clock.h |    1 +
 3 files changed, 146 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
index 0208c3a..9b2bbf0 100644
--- a/arch/arm/mach-exynos/clock-exynos5.c
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -173,6 +173,11 @@ static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable)
 	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable);
 }
 
+static int exynos5_clk_ip_g3d_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_G3D, clk, enable);
+}
+
 static int exynos5_clk_ip_peric_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIC, clk, enable);
@@ -205,6 +210,23 @@ static int exynos5_clk_hdmiphy_ctrl(struct clk *clk, int enable)
 
 /* Core list of CMU_CPU side */
 
+/* GPLL clock output */
+static struct clk clk_fout_gpll = {
+	.name		= "fout_gpll",
+	.id		= -1,
+};
+
+/* Possible clock sources for GPLL Mux */
+static struct clk *clk_src_gpll_list[] = {
+	[0] = &clk_fin_gpll,
+	[1] = &clk_fout_gpll,
+};
+
+static struct clksrc_sources clk_src_gpll = {
+	.sources	= clk_src_gpll_list,
+	.nr_sources	= ARRAY_SIZE(clk_src_gpll_list),
+};
+
 static struct clksrc_clk exynos5_clk_mout_apll = {
 	.clk	= {
 		.name		= "mout_apll",
@@ -484,12 +506,40 @@ static struct clksrc_sources exynos5_clkset_aclk = {
 	.nr_sources	= ARRAY_SIZE(exynos5_clkset_aclk_top_list),
 };
 
-static struct clksrc_clk exynos5_clk_aclk_400 = {
+static struct clksrc_clk exynos5_clk_mout_gpll = {
 	.clk	= {
-		.name		= "aclk_400",
+		.name		= "mout_gpll",
+	},
+	.sources = &clk_src_gpll,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 28, .size = 1 },
+};
+
+/* For ACLK_400_G3D_MID */
+static struct clksrc_clk exynos5_clk_aclk_400_g3d_mid = {
+	.clk	= {
+		.name		= "aclk_400_g3d_mid",
 	},
 	.sources = &exynos5_clkset_aclk,
 	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 },
+};
+
+/* For ACLK_400_G3D */
+struct clk *exynos5_clkset_aclk_g3d_list[] = {
+	[0] = &exynos5_clk_aclk_400_g3d_mid.clk,
+	[1] = &exynos5_clk_mout_gpll.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk_g3d = {
+	.sources	= exynos5_clkset_aclk_g3d_list,
+	.nr_sources	= ARRAY_SIZE(exynos5_clkset_aclk_g3d_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400_g3d = {
+	.clk	= {
+		.name		= "aclk_400_g3d",
+	},
+	.sources = &exynos5_clkset_aclk_g3d,
+	.reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 28, .size = 1 },
 	.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
 };
 
@@ -952,6 +1002,10 @@ static struct clk exynos5_init_clocks_off[] = {
 		.enable		= &exynos5_clk_ip_acp_ctrl,
 		.ops		= &exynos5_gate_clk_ops,
 		.ctrlbit	= (1 << 7)
+	}, {
+		.name		= "g3d",
+		.enable		= exynos5_clk_ip_g3d_ctrl,
+		.ctrlbit	= ((1 << 1) | (1 << 0)),
 	}
 };
 
@@ -1342,6 +1396,7 @@ static struct clksrc_clk *exynos5_sysclks[] = {
 	&exynos5_clk_mout_cpll,
 	&exynos5_clk_mout_epll,
 	&exynos5_clk_mout_mpll,
+	&exynos5_clk_mout_gpll,
 	&exynos5_clk_mout_mpll_fout,
 	&exynos5_clk_mout_mpll_user,
 	&exynos5_clk_vpllsrc,
@@ -1350,7 +1405,8 @@ static struct clksrc_clk *exynos5_sysclks[] = {
 	&exynos5_clk_dout_armclk,
 	&exynos5_clk_dout_arm2clk,
 	&exynos5_clk_cdrex,
-	&exynos5_clk_aclk_400,
+	&exynos5_clk_aclk_400_g3d,
+	&exynos5_clk_aclk_400_g3d_mid,
 	&exynos5_clk_aclk_333,
 	&exynos5_clk_aclk_266,
 	&exynos5_clk_aclk_200,
@@ -1413,6 +1469,76 @@ static struct clk_lookup exynos5_clk_lookup[] = {
 	CLKDEV_INIT("exynos5-fb.1", "lcd", &exynos5_clk_fimd1),
 };
 
+static u32 exynos5_gpll_div[][6] = {
+	/* rate, P, M, S, AFC_DNB, AFC */
+	{1400000000,  3, 175, 0, 0, 0},
+	{ 800000000,  3, 100, 0, 0, 0},
+	{ 667000000,  7, 389, 1, 0, 0},
+	{ 600000000,  4, 200, 1, 0, 0},
+	{ 533000000, 12, 533, 1, 0, 0},
+	{ 450000000, 12, 450, 1, 0, 0},
+	{ 400000000,  3, 100, 1, 0, 0},
+	{ 333000000,  4, 222, 2, 0, 0},
+	{ 200000000,  3, 100, 2, 0, 0},
+};
+
+static unsigned long exynos5_gpll_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+
+static int exynos5_gpll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int gpll_con0;
+	unsigned int locktime;
+	unsigned int tmp;
+	unsigned int i;
+
+	/* Return if no rate changed */
+	if (clk->rate == rate)
+		return 0;
+
+	gpll_con0 = __raw_readl(EXYNOS5_GPLL_CON0);
+	gpll_con0 &= ~(PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT	 |
+			 PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT |
+			 PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
+
+	for (i = 0; i < ARRAY_SIZE(exynos5_gpll_div); i++) {
+		if (exynos5_gpll_div[i][0] == rate) {
+			gpll_con0 |=
+				exynos5_gpll_div[i][1] << PLL35XX_PDIV_SHIFT;
+			gpll_con0 |=
+				exynos5_gpll_div[i][2] << PLL35XX_MDIV_SHIFT;
+			gpll_con0 |=
+				exynos5_gpll_div[i][3] << PLL35XX_SDIV_SHIFT;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(exynos5_gpll_div)) {
+		pr_err("%s: Invalid GPLL clock frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	locktime = 270 * exynos5_gpll_div[i][1] + 1;
+	__raw_writel(locktime, EXYNOS5_GPLL_LOCK);
+
+	__raw_writel(gpll_con0, EXYNOS5_GPLL_CON0);
+
+	do {
+		tmp = __raw_readl(EXYNOS5_GPLL_CON0);
+	} while (!(tmp & (0x1 << EXYNOS5_GPLLCON0_LOCKED_SHIFT)));
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+static struct clk_ops exynos5_gpll_ops = {
+	.get_rate = exynos5_gpll_get_rate,
+	.set_rate = exynos5_gpll_set_rate,
+};
+
 static unsigned long exynos5_epll_get_rate(struct clk *clk)
 {
 	return clk->rate;
@@ -1425,6 +1551,7 @@ static struct clk *exynos5_clks[] __initdata = {
 	&clk_fout_bpll_div2,
 	&clk_fout_cpll,
 	&clk_fout_mpll_div2,
+	&clk_fout_gpll,
 	&exynos5_clk_armclk,
 };
 
@@ -1551,11 +1678,12 @@ void __init_or_cpufreq exynos5_setup_clocks(void)
 	unsigned long mpll;
 	unsigned long epll;
 	unsigned long vpll;
+	unsigned long gpll;
 	unsigned long vpllsrc;
 	unsigned long xtal;
 	unsigned long armclk;
 	unsigned long mout_cdrex;
-	unsigned long aclk_400;
+	unsigned long aclk_400_g3d;
 	unsigned long aclk_333;
 	unsigned long aclk_266;
 	unsigned long aclk_200;
@@ -1587,6 +1715,8 @@ void __init_or_cpufreq exynos5_setup_clocks(void)
 	vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS5_VPLL_CON0),
 			__raw_readl(EXYNOS5_VPLL_CON1));
 
+	gpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_GPLL_CON0));
+
 	clk_fout_apll.ops = &exynos5_fout_apll_ops;
 	clk_fout_bpll.rate = bpll;
 	clk_fout_bpll_div2.rate = bpll >> 1;
@@ -1595,30 +1725,32 @@ void __init_or_cpufreq exynos5_setup_clocks(void)
 	clk_fout_mpll_div2.rate = mpll >> 1;
 	clk_fout_epll.rate = epll;
 	clk_fout_vpll.rate = vpll;
+	clk_fout_gpll.rate = gpll;
 
 	printk(KERN_INFO "EXYNOS5: PLL settings, A=%ld, B=%ld, C=%ld\n"
-			"M=%ld, E=%ld V=%ld",
-			apll, bpll, cpll, mpll, epll, vpll);
+			"M=%ld, E=%ld V=%ld G=%ld",
+			apll, bpll, cpll, mpll, epll, vpll, gpll);
 
 	armclk = clk_get_rate(&exynos5_clk_armclk);
 	mout_cdrex = clk_get_rate(&exynos5_clk_cdrex.clk);
 
-	aclk_400 = clk_get_rate(&exynos5_clk_aclk_400.clk);
+	aclk_400_g3d = clk_get_rate(&exynos5_clk_aclk_400_g3d.clk);
 	aclk_333 = clk_get_rate(&exynos5_clk_aclk_333.clk);
 	aclk_266 = clk_get_rate(&exynos5_clk_aclk_266.clk);
 	aclk_200 = clk_get_rate(&exynos5_clk_aclk_200.clk);
 	aclk_166 = clk_get_rate(&exynos5_clk_aclk_166.clk);
 	aclk_66 = clk_get_rate(&exynos5_clk_aclk_66.clk);
 
-	printk(KERN_INFO "EXYNOS5: ARMCLK=%ld, CDREX=%ld, ACLK400=%ld\n"
+	printk(KERN_INFO "EXYNOS5: ARMCLK=%ld, CDREX=%ld, ACLK400G3D=%ld\n"
 			"ACLK333=%ld, ACLK266=%ld, ACLK200=%ld\n"
 			"ACLK166=%ld, ACLK66=%ld\n",
-			armclk, mout_cdrex, aclk_400,
+			armclk, mout_cdrex, aclk_400_g3d,
 			aclk_333, aclk_266, aclk_200,
 			aclk_166, aclk_66);
 
 
 	clk_fout_epll.ops = &exynos5_epll_ops;
+	clk_fout_gpll.ops = &exynos5_gpll_ops;
 
 	if (clk_set_parent(&exynos5_clk_mout_epll.clk, &clk_fout_epll))
 		printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h
index d36ad76..60ebf87 100644
--- a/arch/arm/mach-exynos/include/mach/regs-clock.h
+++ b/arch/arm/mach-exynos/include/mach/regs-clock.h
@@ -283,6 +283,8 @@
 #define EXYNOS5_VPLL_CON0			EXYNOS_CLKREG(0x10140)
 #define EXYNOS5_VPLL_CON1			EXYNOS_CLKREG(0x10144)
 #define EXYNOS5_VPLL_CON2			EXYNOS_CLKREG(0x10148)
+#define EXYNOS5_GPLL_CON0			EXYNOS_CLKREG(0x10150)
+#define EXYNOS5_GPLL_CON1			EXYNOS_CLKREG(0x10154)
 #define EXYNOS5_CPLL_CON0			EXYNOS_CLKREG(0x10120)
 
 #define EXYNOS5_CLKSRC_TOP0			EXYNOS_CLKREG(0x10210)
@@ -344,8 +346,10 @@
 #define EXYNOS5_PLL_DIV2_SEL			EXYNOS_CLKREG(0x20A24)
 
 #define EXYNOS5_EPLL_LOCK			EXYNOS_CLKREG(0x10030)
+#define EXYNOS5_GPLL_LOCK			EXYNOS_CLKREG(0x10050)
 
 #define EXYNOS5_EPLLCON0_LOCKED_SHIFT		(29)
+#define EXYNOS5_GPLLCON0_LOCKED_SHIFT		(29)
 
 #define PWR_CTRL1_CORE2_DOWN_RATIO		(7 << 28)
 #define PWR_CTRL1_CORE1_DOWN_RATIO		(7 << 16)
diff --git a/arch/arm/plat-samsung/include/plat/s5p-clock.h b/arch/arm/plat-samsung/include/plat/s5p-clock.h
index 8364b4b..aa8dcdd 100644
--- a/arch/arm/plat-samsung/include/plat/s5p-clock.h
+++ b/arch/arm/plat-samsung/include/plat/s5p-clock.h
@@ -19,6 +19,7 @@
 
 #define clk_fin_apll clk_ext_xtal_mux
 #define clk_fin_bpll clk_ext_xtal_mux
+#define clk_fin_gpll clk_ext_xtal_mux
 #define clk_fin_cpll clk_ext_xtal_mux
 #define clk_fin_mpll clk_ext_xtal_mux
 #define clk_fin_epll clk_ext_xtal_mux
-- 
1.7.9.5




More information about the linux-arm-kernel mailing list