aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2015-11-30 09:43:25 -0500
committerStephen Boyd <sboyd@codeaurora.org>2015-11-30 14:34:17 -0500
commit07ff73a932b725b2a4675bd0cc1a86b4933e433e (patch)
treeda9e26ac88590535060e130e8ce51c4369a7c2a8
parentcf81a1cf711d71daafe8f1b8eca96b54c3f5c8ed (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.c4
-rw-r--r--drivers/clk/ti/dpll3xxx.c25
-rw-r--r--include/linux/clk/ti.h1
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)
305static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) 305static 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
290void ti_clk_setup_features(struct ti_clk_features *features); 291void ti_clk_setup_features(struct ti_clk_features *features);
291const struct ti_clk_features *ti_clk_get_features(void); 292const struct ti_clk_features *ti_clk_get_features(void);