Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tero Kristo and committed by
Stephen Boyd
07ff73a9 cf81a1cf

+29 -1
+4
arch/arm/mach-omap2/clock.c
··· 225 225 if (omap_rev() == OMAP3430_REV_ES1_0) 226 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 232 ti_clk_setup_features(&features); 229 233 }
+24 -1
drivers/clk/ti/dpll3xxx.c
··· 305 305 static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) 306 306 { 307 307 struct dpll_data *dd = clk->dpll_data; 308 - u8 dco, sd_div; 308 + u8 dco, sd_div, ai = 0; 309 309 u32 v; 310 + bool errata_i810; 310 311 311 312 /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ 312 313 _omap3_noncore_dpll_bypass(clk); ··· 351 350 v |= sd_div << __ffs(dd->sddiv_mask); 352 351 } 353 352 353 + /* 354 + * Errata i810 - DPLL controller can get stuck while transitioning 355 + * to a power saving state. Software must ensure the DPLL can not 356 + * transition to a low power state while changing M/N values. 357 + * Easiest way to accomplish this is to prevent DPLL autoidle 358 + * before doing the M/N re-program. 359 + */ 360 + errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810; 361 + 362 + if (errata_i810) { 363 + ai = omap3_dpll_autoidle_read(clk); 364 + if (ai) { 365 + omap3_dpll_deny_idle(clk); 366 + 367 + /* OCP barrier */ 368 + omap3_dpll_autoidle_read(clk); 369 + } 370 + } 371 + 354 372 ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg); 355 373 356 374 /* Set 4X multiplier and low-power mode */ ··· 398 378 /* REVISIT: Set ramp-up delay? */ 399 379 400 380 _omap3_noncore_dpll_lock(clk); 381 + 382 + if (errata_i810 && ai) 383 + omap3_dpll_allow_idle(clk); 401 384 402 385 return 0; 403 386 }
+1
include/linux/clk/ti.h
··· 286 286 #define TI_CLK_DPLL_HAS_FREQSEL BIT(0) 287 287 #define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1) 288 288 #define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2) 289 + #define TI_CLK_ERRATA_I810 BIT(3) 289 290 290 291 void ti_clk_setup_features(struct ti_clk_features *features); 291 292 const struct ti_clk_features *ti_clk_get_features(void);