From d6cb5b5fe7c6049a0099b1a722211110f9cdf5da Mon Sep 17 00:00:00 2001 From: Teknoman117 <linux.robotdude@gmail.com> Date: Wed, 24 Jul 2013 17:25:46 -0700 Subject: [PATCH] hack: omap: clockk: dpll5: apply sprz319e 2.1 erratum (compatible with v3.11-rc2) Signed-off-by: Teknoman117 <linux.robotdude@gmail.com> --- arch/arm/mach-omap2/cclock3xxx_data.c | 19 +++++++++- arch/arm/mach-omap2/clkt_dpll.c | 68 +++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/clock.h | 2 ++ arch/arm/mach-omap2/clock3xxx.c | 9 ++++- 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c index 334b767..60fa6bd 100644 --- a/arch/arm/mach-omap2/cclock3xxx_data.c +++ b/arch/arm/mach-omap2/cclock3xxx_data.c @@ -250,7 +250,9 @@ static struct dpll_data dpll1_dd = { static struct clk dpll1_ck; -static const struct clk_ops dpll1_ck_ops = { +static struct clk_ops dpll1_ck_ops; + +static struct clk_ops dpll1_ck_ops_34xx __initdata = { .init = &omap2_init_clk_clkdm, .enable = &omap3_noncore_dpll_enable, .disable = &omap3_noncore_dpll_disable, @@ -260,6 +262,16 @@ static const struct clk_ops dpll1_ck_ops = { .round_rate = &omap2_dpll_round_rate, }; +static struct clk_ops dpll5_ck_ops_3630 __initdata = { + .init = &omap2_init_clk_clkdm, + .enable = &omap3_noncore_dpll_enable, + .disable = &omap3_noncore_dpll_disable, + .get_parent = &omap2_init_dpll_parent, + .recalc_rate = &omap3_dpll_recalc, + .set_rate = &omap3_noncore_dpll_set_rate, + .round_rate = &omap2_dpll5_round_rate, +}; + static struct clk_hw_omap dpll1_ck_hw = { .hw = { .clk = &dpll1_ck, @@ -3560,6 +3572,11 @@ int __init omap3xxx_clk_init(void) else dpll4_dd = dpll4_dd_34xx; + if (cpu_is_omap3630()) + dpll1_ck_ops = dpll5_ck_ops_3630; + else + dpll1_ck_ops = dpll1_ck_ops_34xx; + /* * 3505 must be tested before 3517, since 3517 returns true diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index 924c230..5100d46 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -63,6 +63,15 @@ #define DPLL_FINT_UNDERFLOW -1 #define DPLL_FINT_INVALID -2 +/* copied from clock3xxx.c */ +/* + * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks + * that are sourced by DPLL5, and both of these require this clock + * to be at 120 MHz for proper operation. + */ +#define DPLL5_FREQ_FOR_USBHOST 120000000 + + /* Private functions */ /* @@ -362,3 +371,62 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, return target_rate; } +struct sprz319e_2_1_values { + unsigned long sys_clk_rate; + int m, n, div120m; +}; + +/** + * omap2_dpll5_round_rate - round a target rate for OMAP DPLL5 + * according to DM37xx sprz319e 2.1 erratum + * + * @clk: struct clk * for a DPLL (presumably DPLL5) + * @target_rate: desired DPLL clock rate + * + * The erratum applies only for DM37xx, desired clock rates of + * div120m times 120 MHz and specified sys_clks. + */ +long omap2_dpll5_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + const char *clk_name; + int i; + + /* erratum tables */ + const struct sprz319e_2_1_values sprz319e_2_1_table[] = { + /* table 35 */ + { 12000000, 80, 0, 8 }, + { 19200000, 50, 0, 8 }, + { 38400000, 25, 0, 8 }, + /* table 36 */ + { 13000000, 443, 5, 8 }, + { 26000000, 443, 11, 8 }, + }; + + if (!clk || !clk->dpll_data) + return ~0; + + dd = clk->dpll_data; + + clk_name = __clk_get_name(hw->clk); + + for (i = 0; i < (sizeof(sprz319e_2_1_table)/sizeof(struct sprz319e_2_1_values)); i++) { + const struct sprz319e_2_1_values *v = &sprz319e_2_1_table[i]; + + if (*parent_rate == v->sys_clk_rate && + target_rate == DPLL5_FREQ_FOR_USBHOST * v->div120m) { + + pr_info("clock: dpll5: Applying SPRZ319E 2.1: %8lu, %3d, %3d, %3d\n", + v->sys_clk_rate, v->m, v->n, v->div120m); + + dd->last_rounded_m = v->m; + dd->last_rounded_n = v->n + 1; + dd->last_rounded_rate = v->sys_clk_rate * v->m / (v->n + 1); + + return dd->last_rounded_rate; + } + } + return target_rate; +} diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 7aa32cd..56a50a7 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -358,6 +358,8 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw, long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); +long omap2_dpll5_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); int omap3_noncore_dpll_enable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw); diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index 0b02b41..8ccf7c6 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -60,7 +60,14 @@ void __init omap3_clk_lock_dpll5(void) struct clk *dpll5_m2_clk; dpll5_clk = clk_get(NULL, "dpll5_ck"); - clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); + + if (cpu_is_omap3630()) { + pr_info("clock: dpll5: dpll5_clk omap3630\n"); + clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST * 8); + } else { + clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); + } + clk_prepare_enable(dpll5_clk); /* Program dpll5_m2_clk divider for no division */ -- 1.8.4.rc3