diff options
author | Tero Kristo <t-kristo@ti.com> | 2015-11-30 09:43:25 -0500 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2015-11-30 14:34:17 -0500 |
commit | 07ff73a932b725b2a4675bd0cc1a86b4933e433e (patch) | |
tree | da9e26ac88590535060e130e8ce51c4369a7c2a8 | |
parent | cf81a1cf711d71daafe8f1b8eca96b54c3f5c8ed (diff) |
clk: ti: omap5+: dpll: implement errata i810
Errata i810 states that DPLL controller can get stuck while transitioning
to a power saving state, while its M/N ratio is being re-programmed.
As a workaround, before re-programming the M/N ratio, SW has to ensure
the DPLL cannot start an idle state transition. SW can disable DPLL
idling by setting the DPLL AUTO_DPLL_MODE=0 or keeping a clock request
active by setting a dependent clock domain in SW_WKUP.
This errata impacts OMAP5 and DRA7 chips, so enable the errata for these.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 4 | ||||
-rw-r--r-- | drivers/clk/ti/dpll3xxx.c | 25 | ||||
-rw-r--r-- | include/linux/clk/ti.h | 1 |
3 files changed, 29 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index acb60ed17273..d058125876d8 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -225,5 +225,9 @@ void __init ti_clk_init_features(void) | |||
225 | if (omap_rev() == OMAP3430_REV_ES1_0) | 225 | if (omap_rev() == OMAP3430_REV_ES1_0) |
226 | features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; | 226 | features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; |
227 | 227 | ||
228 | /* Errata I810 for omap5 / dra7 */ | ||
229 | if (soc_is_omap54xx() || soc_is_dra7xx()) | ||
230 | features.flags |= TI_CLK_ERRATA_I810; | ||
231 | |||
228 | ti_clk_setup_features(&features); | 232 | ti_clk_setup_features(&features); |
229 | } | 233 | } |
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c index f4dec00fb684..1c300388782b 100644 --- a/drivers/clk/ti/dpll3xxx.c +++ b/drivers/clk/ti/dpll3xxx.c | |||
@@ -305,8 +305,9 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n) | |||
305 | static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) | 305 | static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) |
306 | { | 306 | { |
307 | struct dpll_data *dd = clk->dpll_data; | 307 | struct dpll_data *dd = clk->dpll_data; |
308 | u8 dco, sd_div; | 308 | u8 dco, sd_div, ai = 0; |
309 | u32 v; | 309 | u32 v; |
310 | bool errata_i810; | ||
310 | 311 | ||
311 | /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ | 312 | /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ |
312 | _omap3_noncore_dpll_bypass(clk); | 313 | _omap3_noncore_dpll_bypass(clk); |
@@ -350,6 +351,25 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) | |||
350 | v |= sd_div << __ffs(dd->sddiv_mask); | 351 | v |= sd_div << __ffs(dd->sddiv_mask); |
351 | } | 352 | } |
352 | 353 | ||
354 | /* | ||
355 | * Errata i810 - DPLL controller can get stuck while transitioning | ||
356 | * to a power saving state. Software must ensure the DPLL can not | ||
357 | * transition to a low power state while changing M/N values. | ||
358 | * Easiest way to accomplish this is to prevent DPLL autoidle | ||
359 | * before doing the M/N re-program. | ||
360 | */ | ||
361 | errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810; | ||
362 | |||
363 | if (errata_i810) { | ||
364 | ai = omap3_dpll_autoidle_read(clk); | ||
365 | if (ai) { | ||
366 | omap3_dpll_deny_idle(clk); | ||
367 | |||
368 | /* OCP barrier */ | ||
369 | omap3_dpll_autoidle_read(clk); | ||
370 | } | ||
371 | } | ||
372 | |||
353 | ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg); | 373 | ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg); |
354 | 374 | ||
355 | /* Set 4X multiplier and low-power mode */ | 375 | /* Set 4X multiplier and low-power mode */ |
@@ -379,6 +399,9 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) | |||
379 | 399 | ||
380 | _omap3_noncore_dpll_lock(clk); | 400 | _omap3_noncore_dpll_lock(clk); |
381 | 401 | ||
402 | if (errata_i810 && ai) | ||
403 | omap3_dpll_allow_idle(clk); | ||
404 | |||
382 | return 0; | 405 | return 0; |
383 | } | 406 | } |
384 | 407 | ||
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 223be696df27..75205df29b9c 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h | |||
@@ -286,6 +286,7 @@ struct ti_clk_features { | |||
286 | #define TI_CLK_DPLL_HAS_FREQSEL BIT(0) | 286 | #define TI_CLK_DPLL_HAS_FREQSEL BIT(0) |
287 | #define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1) | 287 | #define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1) |
288 | #define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2) | 288 | #define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2) |
289 | #define TI_CLK_ERRATA_I810 BIT(3) | ||
289 | 290 | ||
290 | void ti_clk_setup_features(struct ti_clk_features *features); | 291 | void ti_clk_setup_features(struct ti_clk_features *features); |
291 | const struct ti_clk_features *ti_clk_get_features(void); | 292 | const struct ti_clk_features *ti_clk_get_features(void); |