diff options
author | Tony Lindgren <tony@atomide.com> | 2011-11-04 17:36:34 -0700 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2011-11-04 17:36:34 -0700 |
commit | 8f86f36284547fdd873769a5f190549f3ab69cca (patch) | |
tree | 06791d877fec7a0b3a6059b14ebad9e5ed77b200 /arch/arm | |
parent | 994c0e992522c123298b4a91b72f5e67ba2d1123 (diff) | |
parent | 1194d7b82486ad967db65115559e9ad50a88ba57 (diff) |
Merge branch 'omap_clock_fixes_3.2' of git://git.pwsan.com/linux-2.6 into fixes
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/clkt_dpll.c | 51 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock44xx.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock44xx_data.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-omap2/dpll3xxx.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-omap2/dpll44xx.c | 69 |
6 files changed, 142 insertions, 28 deletions
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index bcffee001bfa..e069a9be93df 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -46,10 +46,19 @@ (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ -#define DPLL_FINT_BAND1_MIN 750000 -#define DPLL_FINT_BAND1_MAX 2100000 -#define DPLL_FINT_BAND2_MIN 7500000 -#define DPLL_FINT_BAND2_MAX 21000000 +#define OMAP3430_DPLL_FINT_BAND1_MIN 750000 +#define OMAP3430_DPLL_FINT_BAND1_MAX 2100000 +#define OMAP3430_DPLL_FINT_BAND2_MIN 7500000 +#define OMAP3430_DPLL_FINT_BAND2_MAX 21000000 + +/* + * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx. + * From device data manual section 4.3 "DPLL and DLL Specifications". + */ +#define OMAP3PLUS_DPLL_FINT_JTYPE_MIN 500000 +#define OMAP3PLUS_DPLL_FINT_JTYPE_MAX 2500000 +#define OMAP3PLUS_DPLL_FINT_MIN 32000 +#define OMAP3PLUS_DPLL_FINT_MAX 52000000 /* _dpll_test_fint() return codes */ #define DPLL_FINT_UNDERFLOW -1 @@ -71,33 +80,43 @@ static int _dpll_test_fint(struct clk *clk, u8 n) { struct dpll_data *dd; - long fint; + long fint, fint_min, fint_max; int ret = 0; dd = clk->dpll_data; /* DPLL divider must result in a valid jitter correction val */ fint = clk->parent->rate / n; - if (fint < DPLL_FINT_BAND1_MIN) { + if (cpu_is_omap24xx()) { + /* Should not be called for OMAP2, so warn if it is called */ + WARN(1, "No fint limits available for OMAP2!\n"); + return DPLL_FINT_INVALID; + } else if (cpu_is_omap3430()) { + fint_min = OMAP3430_DPLL_FINT_BAND1_MIN; + fint_max = OMAP3430_DPLL_FINT_BAND2_MAX; + } else if (dd->flags & DPLL_J_TYPE) { + fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; + fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; + } else { + fint_min = OMAP3PLUS_DPLL_FINT_MIN; + fint_max = OMAP3PLUS_DPLL_FINT_MAX; + } + + if (fint < fint_min) { pr_debug("rejecting n=%d due to Fint failure, " "lowering max_divider\n", n); dd->max_divider = n; ret = DPLL_FINT_UNDERFLOW; - - } else if (fint > DPLL_FINT_BAND1_MAX && - fint < DPLL_FINT_BAND2_MIN) { - - pr_debug("rejecting n=%d due to Fint failure\n", n); - ret = DPLL_FINT_INVALID; - - } else if (fint > DPLL_FINT_BAND2_MAX) { - + } else if (fint > fint_max) { pr_debug("rejecting n=%d due to Fint failure, " "boosting min_divider\n", n); dd->min_divider = n; ret = DPLL_FINT_INVALID; - + } else if (cpu_is_omap3430() && fint > OMAP3430_DPLL_FINT_BAND1_MAX && + fint < OMAP3430_DPLL_FINT_BAND2_MIN) { + pr_debug("rejecting n=%d due to Fint failure\n", n); + ret = DPLL_FINT_INVALID; } return ret; diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 48ac568881bd..2311bc217226 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -66,6 +66,8 @@ void omap3_noncore_dpll_disable(struct clk *clk); int omap4_dpllmx_gatectrl_read(struct clk *clk); void omap4_dpllmx_allow_gatectrl(struct clk *clk); void omap4_dpllmx_deny_gatectrl(struct clk *clk); +long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate); +unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk); #ifdef CONFIG_OMAP_RESET_CLOCKS void omap2_clk_disable_unused(struct clk *clk); diff --git a/arch/arm/mach-omap2/clock44xx.h b/arch/arm/mach-omap2/clock44xx.h index 7ceb870e7ab8..287a46f78d97 100644 --- a/arch/arm/mach-omap2/clock44xx.h +++ b/arch/arm/mach-omap2/clock44xx.h @@ -8,6 +8,13 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H #define __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H +/* + * OMAP4430_REGM4XEN_MULT: If the CM_CLKMODE_DPLL_ABE.DPLL_REGM4XEN bit is + * set, then the DPLL's lock frequency is multiplied by 4 (OMAP4430 TRM + * vV Section 3.6.3.3.1 "DPLLs Output Clocks Parameters") + */ +#define OMAP4430_REGM4XEN_MULT 4 + int omap4xxx_clk_init(void); #endif diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index 946bf04a956d..cbf9b68d4b94 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -270,8 +270,8 @@ static struct clk dpll_abe_ck = { .dpll_data = &dpll_abe_dd, .init = &omap2_init_dpll_parent, .ops = &clkops_omap3_noncore_dpll_ops, - .recalc = &omap3_dpll_recalc, - .round_rate = &omap2_dpll_round_rate, + .recalc = &omap4_dpll_regm4xen_recalc, + .round_rate = &omap4_dpll_regm4xen_round_rate, .set_rate = &omap3_noncore_dpll_set_rate, }; @@ -1195,11 +1195,25 @@ static struct clk l4_wkup_clk_mux_ck = { .recalc = &omap2_clksel_recalc, }; +static const struct clksel_rate div2_2to1_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_4430 }, + { .div = 2, .val = 0, .flags = RATE_IN_4430 }, + { .div = 0 }, +}; + +static const struct clksel ocp_abe_iclk_div[] = { + { .parent = &aess_fclk, .rates = div2_2to1_rates }, + { .parent = NULL }, +}; + static struct clk ocp_abe_iclk = { .name = "ocp_abe_iclk", .parent = &aess_fclk, + .clksel = ocp_abe_iclk_div, + .clksel_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL, + .clksel_mask = OMAP4430_CLKSEL_AESS_FCLK_MASK, .ops = &clkops_null, - .recalc = &followparent_recalc, + .recalc = &omap2_clksel_recalc, }; static struct clk per_abe_24m_fclk = { @@ -1398,9 +1412,9 @@ static struct clk dss_dss_clk = { }; static const struct clksel_rate div3_8to32_rates[] = { - { .div = 8, .val = 0, .flags = RATE_IN_44XX }, - { .div = 16, .val = 1, .flags = RATE_IN_44XX }, - { .div = 32, .val = 2, .flags = RATE_IN_44XX }, + { .div = 8, .val = 0, .flags = RATE_IN_4460 }, + { .div = 16, .val = 1, .flags = RATE_IN_4460 }, + { .div = 32, .val = 2, .flags = RATE_IN_4460 }, { .div = 0 }, }; @@ -3403,12 +3417,12 @@ int __init omap4xxx_clk_init(void) struct omap_clk *c; u32 cpu_clkflg; - if (cpu_is_omap44xx()) { + if (cpu_is_omap443x()) { cpu_mask = RATE_IN_4430; cpu_clkflg = CK_443X; } else if (cpu_is_omap446x()) { - cpu_mask = RATE_IN_4460; - cpu_clkflg = CK_446X; + cpu_mask = RATE_IN_4460 | RATE_IN_4430; + cpu_clkflg = CK_446X | CK_443X; } else { return 0; } diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index f77022be783d..fc56745676fa 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -390,7 +390,8 @@ int omap3_noncore_dpll_enable(struct clk *clk) * propagating? */ if (!r) - clk->rate = omap2_get_dpll_rate(clk); + clk->rate = (clk->recalc) ? clk->recalc(clk) : + omap2_get_dpll_rate(clk); return r; } @@ -424,6 +425,7 @@ void omap3_noncore_dpll_disable(struct clk *clk) int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) { struct clk *new_parent = NULL; + unsigned long hw_rate; u16 freqsel = 0; struct dpll_data *dd; int ret; @@ -435,7 +437,8 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) if (!dd) return -EINVAL; - if (rate == omap2_get_dpll_rate(clk)) + hw_rate = (clk->recalc) ? clk->recalc(clk) : omap2_get_dpll_rate(clk); + if (rate == hw_rate) return 0; /* @@ -455,7 +458,7 @@ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) new_parent = dd->clk_bypass; } else { if (dd->last_rounded_rate != rate) - omap2_dpll_round_rate(clk, rate); + rate = clk->round_rate(clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 4e4da6160d05..9c6a296b3dc3 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -19,6 +19,7 @@ #include <plat/clock.h> #include "clock.h" +#include "clock44xx.h" #include "cm-regbits-44xx.h" /* Supported only on OMAP4 */ @@ -82,3 +83,71 @@ const struct clkops clkops_omap4_dpllmx_ops = { .deny_idle = omap4_dpllmx_deny_gatectrl, }; +/** + * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit + * @clk: struct clk * of the DPLL to compute the rate for + * + * Compute the output rate for the OMAP4 DPLL represented by @clk. + * Takes the REGM4XEN bit into consideration, which is needed for the + * OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers) + * upon success, or 0 upon error. + */ +unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk) +{ + u32 v; + unsigned long rate; + struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return 0; + + dd = clk->dpll_data; + + rate = omap2_get_dpll_rate(clk); + + /* regm4xen adds a multiplier of 4 to DPLL calculations */ + v = __raw_readl(dd->control_reg); + if (v & OMAP4430_DPLL_REGM4XEN_MASK) + rate *= OMAP4430_REGM4XEN_MULT; + + return rate; +} + +/** + * omap4_dpll_regm4xen_round_rate - round DPLL rate, considering REGM4XEN bit + * @clk: struct clk * of the DPLL to round a rate for + * @target_rate: the desired rate of the DPLL + * + * Compute the rate that would be programmed into the DPLL hardware + * for @clk if set_rate() were to be provided with the rate + * @target_rate. Takes the REGM4XEN bit into consideration, which is + * needed for the OMAP4 ABE DPLL. Returns the rounded rate (before + * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or + * ~0 if an error occurred in omap2_dpll_round_rate(). + */ +long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate) +{ + u32 v; + struct dpll_data *dd; + long r; + + if (!clk || !clk->dpll_data) + return -EINVAL; + + dd = clk->dpll_data; + + /* regm4xen adds a multiplier of 4 to DPLL calculations */ + v = __raw_readl(dd->control_reg) & OMAP4430_DPLL_REGM4XEN_MASK; + + if (v) + target_rate = target_rate / OMAP4430_REGM4XEN_MULT; + + r = omap2_dpll_round_rate(clk, target_rate); + if (r == ~0) + return r; + + if (v) + clk->dpll_data->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; + + return clk->dpll_data->last_rounded_rate; +} |