aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2443/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2443/clock.c')
-rw-r--r--arch/arm/mach-s3c2443/clock.c91
1 files changed, 85 insertions, 6 deletions
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index b42f956738d0..17f064fabdaf 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -81,7 +81,7 @@ static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
else
clkcon &= ~clocks;
- __raw_writel(clkcon, S3C2443_HCLKCON);
+ __raw_writel(clkcon, S3C2443_PCLKCON);
return 0;
}
@@ -221,7 +221,6 @@ static struct clk clk_mdivclk = {
.get_rate = s3c2443_getrate_mdivclk,
};
-
static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
@@ -249,6 +248,46 @@ static struct clk clk_msysclk = {
.set_parent = s3c2443_setparent_msysclk,
};
+/* armdiv
+ *
+ * this clock is sourced from msysclk and can have a number of
+ * divider values applied to it to then be fed into armclk.
+*/
+
+static struct clk clk_armdiv = {
+ .name = "armdiv",
+ .id = -1,
+ .parent = &clk_msysclk,
+};
+
+/* armclk
+ *
+ * this is the clock fed into the ARM core itself, either from
+ * armdiv or from hclk.
+ */
+
+static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent)
+{
+ unsigned long clkdiv0;
+
+ clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+ if (parent == &clk_armdiv)
+ clkdiv0 &= ~S3C2443_CLKDIV0_DVS;
+ else if (parent == &clk_h)
+ clkdiv0 |= S3C2443_CLKDIV0_DVS;
+ else
+ return -EINVAL;
+
+ __raw_writel(clkdiv0, S3C2443_CLKDIV0);
+ return 0;
+}
+
+static struct clk clk_arm = {
+ .name = "armclk",
+ .id = -1,
+ .set_parent = s3c2443_setparent_armclk,
+};
/* esysclk
*
@@ -639,6 +678,29 @@ static struct clk clk_display = {
.round_rate = s3c2443_roundrate_clksrc256,
};
+/* prediv
+ *
+ * this divides the msysclk down to pass to h/p/etc.
+ */
+
+static unsigned long s3c2443_prediv_getrate(struct clk *clk)
+{
+ unsigned long rate = clk_get_rate(clk->parent);
+ unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+
+ clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
+ clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
+
+ return rate / (clkdiv0 + 1);
+}
+
+static struct clk clk_prediv = {
+ .name = "prediv",
+ .id = -1,
+ .parent = &clk_msysclk,
+ .get_rate = s3c2443_prediv_getrate,
+};
+
/* standard clock definitions */
static struct clk init_clocks_disable[] = {
@@ -887,6 +949,15 @@ static void __init s3c2443_clk_initparents(void)
}
clk_init_set_parent(&clk_msysclk, parent);
+
+ /* arm */
+
+ if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS)
+ parent = &clk_h;
+ else
+ parent = &clk_armdiv;
+
+ clk_init_set_parent(&clk_arm, parent);
}
/* armdiv divisor table */
@@ -909,10 +980,9 @@ static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
}
-static inline unsigned long s3c2443_get_prediv(unsigned long clkcon0)
+static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
{
- clkcon0 &= S3C2443_CLKDIV0_PREDIV_MASK;
- clkcon0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
+ clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
return clkcon0 + 1;
}
@@ -936,6 +1006,9 @@ static struct clk *clks[] __initdata = {
&clk_hsspi,
&clk_hsmmc_div,
&clk_hsmmc,
+ &clk_armdiv,
+ &clk_arm,
+ &clk_prediv,
};
void __init s3c2443_init_clocks(int xtal)
@@ -951,10 +1024,16 @@ void __init s3c2443_init_clocks(int xtal)
int ret;
int ptr;
+ /* s3c2443 parents h and p clocks from prediv */
+ clk_h.parent = &clk_prediv;
+ clk_p.parent = &clk_prediv;
+
pll = s3c2443_get_mpll(mpllcon, xtal);
+ clk_msysclk.rate = pll;
fclk = pll / s3c2443_fclk_div(clkdiv0);
- hclk = fclk / s3c2443_get_prediv(clkdiv0);
+ hclk = s3c2443_prediv_getrate(&clk_prediv);
+ hclk = hclk / s3c2443_get_hdiv(clkdiv0);
hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1);
pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);