diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 81fd429c3c24c7c8821c4881f7abc3b507937a91..7c8b5179e444634e66a8d6ae5fb0264711e6199c 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -23,37 +23,241 @@ #include #include +#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); diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index d8f91a5f692f83f7777e1b2f0a0f12b858730130..15932fd2435e58a9f91c28862d88c068d854ee7d 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -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 */