ARM: mach-shmobile: AG5 clock framework improvements
authorMagnus Damm <damm@opensource.se>
Fri, 3 Dec 2010 07:22:31 +0000 (07:22 +0000)
committerPaul Mundt <lethal@linux-sh.org>
Fri, 3 Dec 2010 07:29:15 +0000 (16:29 +0900)
This patch improves the state of the AG5 clock
framework support. The main clock parent is
automatically detected, but most of the clocks
are not used by any driver or subsystem at this
point. More work is needed for support of multi
media hardware such as FSI and/or LCDC/MIPI-DSI.

Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/include/mach/common.h

index 81fd429..7c8b517 100644 (file)
 #include <mach/common.h>
 #include <asm/clkdev.h>
 
+#define FRQCRA         0xe6150000
+#define FRQCRB         0xe6150004
+#define FRQCRD         0xe61500e4
+#define VCLKCR1                0xe6150008
+#define VCLKCR2                0xe615000C
+#define VCLKCR3                0xe615001C
+#define ZBCKCR         0xe6150010
+#define FLCKCR         0xe6150014
+#define SD0CKCR                0xe6150074
+#define SD1CKCR                0xe6150078
+#define SD2CKCR                0xe615007C
+#define FSIACKCR       0xe6150018
+#define FSIBCKCR       0xe6150090
+#define SUBCKCR                0xe6150080
+#define SPUACKCR       0xe6150084
+#define SPUVCKCR       0xe6150094
+#define MSUCKCR                0xe6150088
+#define HSICKCR                0xe615008C
+#define MFCK1CR                0xe6150098
+#define MFCK2CR                0xe615009C
+#define DSITCKCR       0xe6150060
+#define DSI0PCKCR      0xe6150064
+#define DSI1PCKCR      0xe6150068
+#define DSI0PHYCR      0xe615006C
+#define DSI1PHYCR      0xe6150070
+#define PLLECR         0xe61500d0
+#define PLL0CR         0xe61500d8
+#define PLL1CR         0xe6150028
+#define PLL2CR         0xe615002c
+#define PLL3CR         0xe61500dc
 #define SMSTPCR0       0xe6150130
 #define SMSTPCR1       0xe6150134
 #define SMSTPCR2       0xe6150138
 #define SMSTPCR3       0xe615013c
 #define SMSTPCR4       0xe6150140
 #define SMSTPCR5       0xe6150144
+#define CKSCR          0xe61500c0
 
 /* Fixed 32 KHz root clock from EXTALR pin */
 static struct clk r_clk = {
        .rate           = 32768,
 };
 
-/* Temporarily fixed 48 MHz SUB clock */
-static struct clk sub_clk = {
-       .rate           = 48000000,
+/*
+ * 26MHz default rate for the EXTAL1 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh73a0_extal1_clk = {
+       .rate           = 26000000,
+};
+
+/*
+ * 48MHz default rate for the EXTAL2 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh73a0_extal2_clk = {
+       .rate           = 48000000,
+};
+
+/* A fixed divide-by-2 block */
+static unsigned long div2_recalc(struct clk *clk)
+{
+       return clk->parent->rate / 2;
+}
+
+static struct clk_ops div2_clk_ops = {
+       .recalc         = div2_recalc,
+};
+
+/* Divide extal1 by two */
+static struct clk extal1_div2_clk = {
+       .ops            = &div2_clk_ops,
+       .parent         = &sh73a0_extal1_clk,
+};
+
+/* Divide extal2 by two */
+static struct clk extal2_div2_clk = {
+       .ops            = &div2_clk_ops,
+       .parent         = &sh73a0_extal2_clk,
+};
+
+static struct clk_ops main_clk_ops = {
+       .recalc         = followparent_recalc,
+};
+
+/* Main clock */
+static struct clk main_clk = {
+       .ops            = &main_clk_ops,
+};
+
+/* PLL0, PLL1, PLL2, PLL3 */
+static unsigned long pll_recalc(struct clk *clk)
+{
+       unsigned long mult = 1;
+
+       if (__raw_readl(PLLECR) & (1 << clk->enable_bit))
+               mult = (((__raw_readl(clk->enable_reg) >> 24) & 0x3f) + 1);
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops pll_clk_ops = {
+       .recalc         = pll_recalc,
+};
+
+static struct clk pll0_clk = {
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+       .parent         = &main_clk,
+       .enable_reg     = (void __iomem *)PLL0CR,
+       .enable_bit     = 0,
 };
 
-/* Temporarily fixed 104 MHz HP clock */
-static struct clk hp_clk = {
-       .rate           = 104000000,
+static struct clk pll1_clk = {
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+       .parent         = &main_clk,
+       .enable_reg     = (void __iomem *)PLL1CR,
+       .enable_bit     = 1,
+};
+
+static struct clk pll2_clk = {
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+       .parent         = &main_clk,
+       .enable_reg     = (void __iomem *)PLL2CR,
+       .enable_bit     = 2,
+};
+
+static struct clk pll3_clk = {
+       .ops            = &pll_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+       .parent         = &main_clk,
+       .enable_reg     = (void __iomem *)PLL3CR,
+       .enable_bit     = 3,
+};
+
+/* Divide PLL1 by two */
+static struct clk pll1_div2_clk = {
+       .ops            = &div2_clk_ops,
+       .parent         = &pll1_clk,
 };
 
 static struct clk *main_clks[] = {
        &r_clk,
-       &sub_clk,
-       &hp_clk,
+       &sh73a0_extal1_clk,
+       &sh73a0_extal2_clk,
+       &extal1_div2_clk,
+       &extal2_div2_clk,
+       &main_clk,
+       &pll0_clk,
+       &pll1_clk,
+       &pll2_clk,
+       &pll3_clk,
+       &pll1_div2_clk,
+};
+
+static void div4_kick(struct clk *clk)
+{
+       unsigned long value;
+
+       /* set KICK bit in FRQCRB to update hardware setting */
+       value = __raw_readl(FRQCRB);
+       value |= (1 << 31);
+       __raw_writel(value, FRQCRB);
+}
+
+static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
+                         24, 0, 36, 48 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+};
+
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
+       .kick = div4_kick,
+};
+
+enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2,
+       DIV4_Z, DIV4_ZTR, DIV4_ZT, DIV4_ZX, DIV4_HP, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+       SH_CLK_DIV4(&pll1_clk, _reg, _bit, _mask, _flags)
+
+static struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I] = DIV4(FRQCRA, 20, 0xfff, CLK_ENABLE_ON_INIT),
+       [DIV4_ZG] = DIV4(FRQCRA, 16, 0xbff, CLK_ENABLE_ON_INIT),
+       [DIV4_M3] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
+       [DIV4_B] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
+       [DIV4_M1] = DIV4(FRQCRA, 4, 0xfff, 0),
+       [DIV4_M2] = DIV4(FRQCRA, 0, 0xfff, 0),
+       [DIV4_Z] = DIV4(FRQCRB, 24, 0xbff, 0),
+       [DIV4_ZTR] = DIV4(FRQCRB, 20, 0xfff, 0),
+       [DIV4_ZT] = DIV4(FRQCRB, 16, 0xfff, 0),
+       [DIV4_ZX] = DIV4(FRQCRB, 12, 0xfff, 0),
+       [DIV4_HP] = DIV4(FRQCRB, 4, 0xfff, 0),
+};
+
+enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1,
+       DIV6_FLCTL, DIV6_SDHI0, DIV6_SDHI1, DIV6_SDHI2,
+       DIV6_FSIA, DIV6_FSIB, DIV6_SUB,
+       DIV6_SPUA, DIV6_SPUV, DIV6_MSU,
+       DIV6_HSI,  DIV6_MFG1, DIV6_MFG2,
+       DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
+       DIV6_NR };
+
+static struct clk div6_clks[DIV6_NR] = {
+       [DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0),
+       [DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0),
+       [DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0),
+       [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, 0),
+       [DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0),
+       [DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0),
+       [DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0),
+       [DIV6_SDHI2] = SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0),
+       [DIV6_FSIA] = SH_CLK_DIV6(&pll1_div2_clk, FSIACKCR, 0),
+       [DIV6_FSIB] = SH_CLK_DIV6(&pll1_div2_clk, FSIBCKCR, 0),
+       [DIV6_SUB] = SH_CLK_DIV6(&sh73a0_extal2_clk, SUBCKCR, 0),
+       [DIV6_SPUA] = SH_CLK_DIV6(&pll1_div2_clk, SPUACKCR, 0),
+       [DIV6_SPUV] = SH_CLK_DIV6(&pll1_div2_clk, SPUVCKCR, 0),
+       [DIV6_MSU] = SH_CLK_DIV6(&pll1_div2_clk, MSUCKCR, 0),
+       [DIV6_HSI] = SH_CLK_DIV6(&pll1_div2_clk, HSICKCR, 0),
+       [DIV6_MFG1] = SH_CLK_DIV6(&pll1_div2_clk, MFCK1CR, 0),
+       [DIV6_MFG2] = SH_CLK_DIV6(&pll1_div2_clk, MFCK2CR, 0),
+       [DIV6_DSIT] = SH_CLK_DIV6(&pll1_div2_clk, DSITCKCR, 0),
+       [DIV6_DSI0P] = SH_CLK_DIV6(&pll1_div2_clk, DSI0PCKCR, 0),
+       [DIV6_DSI1P] = SH_CLK_DIV6(&pll1_div2_clk, DSI1PCKCR, 0),
 };
 
-enum { MSTP001,
+enum { MSTP001,
        MSTP116,
-       MSTP219, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
+       MSTP219,
+       MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
        MSTP331, MSTP329, MSTP323,
        MSTP411, MSTP410, MSTP403,
        MSTP_NR };
@@ -62,27 +266,30 @@ enum {     MSTP001,
        SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
 
 static struct clk mstp_clks[MSTP_NR] = {
-       [MSTP001] = MSTP(&hp_clk, SMSTPCR0, 1, 0), /* I2C2 */
-       [MSTP116] = MSTP(&hp_clk, SMSTPCR1, 16, 0), /* I2C0 */
-       [MSTP219] = MSTP(&sub_clk, SMSTPCR2, 19, 0), /* SCIFA7 */
-       [MSTP207] = MSTP(&sub_clk, SMSTPCR2, 7, 0), /* SCIFA5 */
-       [MSTP206] = MSTP(&sub_clk, SMSTPCR2, 6, 0), /* SCIFB */
-       [MSTP204] = MSTP(&sub_clk, SMSTPCR2, 4, 0), /* SCIFA0 */
-       [MSTP203] = MSTP(&sub_clk, SMSTPCR2, 3, 0), /* SCIFA1 */
-       [MSTP202] = MSTP(&sub_clk, SMSTPCR2, 2, 0), /* SCIFA2 */
-       [MSTP201] = MSTP(&sub_clk, SMSTPCR2, 1, 0), /* SCIFA3 */
-       [MSTP200] = MSTP(&sub_clk, SMSTPCR2, 0, 0), /* SCIFA4 */
-       [MSTP331] = MSTP(&sub_clk, SMSTPCR3, 31, 0), /* SCIFA6 */
+       [MSTP001] = MSTP(&div4_clks[DIV4_HP], SMSTPCR0, 1, 0), /* IIC2 */
+       [MSTP116] = MSTP(&div4_clks[DIV4_HP], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */
+       [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
+       [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
+       [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
+       [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
+       [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
+       [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
+       [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
+       [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
        [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
-       [MSTP323] = MSTP(&hp_clk, SMSTPCR3, 23, 0), /* I2C1 */
-       [MSTP411] = MSTP(&hp_clk, SMSTPCR4, 11, 0), /* I2C3 */
-       [MSTP410] = MSTP(&hp_clk, SMSTPCR4, 10, 0), /* I2C4 */
-       [MSTP403] = MSTP(&r_clk, SMSTPCR4, 0, 0), /* KEYSC0 */
+       [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
+       [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
+       [MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */
 };
 
+#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
+       /* main clocks */
+       CLKDEV_CON_ID("r_clk", &r_clk),
+
        /* MSTP32 clocks */
        CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */
@@ -106,9 +313,31 @@ void __init sh73a0_clock_init(void)
 {
        int k, ret = 0;
 
+       /* detect main clock parent */
+       switch ((__raw_readl(CKSCR) >> 24) & 0x03) {
+       case 0:
+               main_clk.parent = &sh73a0_extal1_clk;
+               break;
+       case 1:
+               main_clk.parent = &extal1_div2_clk;
+               break;
+       case 2:
+               main_clk.parent = &sh73a0_extal2_clk;
+               break;
+       case 3:
+               main_clk.parent = &extal2_div2_clk;
+               break;
+       }
+
        for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
                ret = clk_register(main_clks[k]);
 
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+
        if (!ret)
                ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
index d8f91a5..15932fd 100644 (file)
@@ -34,5 +34,7 @@ extern void sh73a0_add_early_devices(void);
 extern void sh73a0_add_standard_devices(void);
 extern void sh73a0_clock_init(void);
 extern void sh73a0_pinmux_init(void);
+extern struct clk sh73a0_extal1_clk;
+extern struct clk sh73a0_extal2_clk;
 
 #endif /* __ARCH_MACH_COMMON_H */