clk: ti: omap5+: dpll: implement errata i810
authorTero Kristo <t-kristo@ti.com>
Mon, 30 Nov 2015 14:43:25 +0000 (16:43 +0200)
committerStephen Boyd <sboyd@codeaurora.org>
Mon, 30 Nov 2015 19:34:17 +0000 (11:34 -0800)
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>
arch/arm/mach-omap2/clock.c
drivers/clk/ti/dpll3xxx.c
include/linux/clk/ti.h

index acb60ed172730a12b06f36a02c3175d848d7369c..d058125876d88d159a9e3559f36c297e4a581c4d 100644 (file)
@@ -225,5 +225,9 @@ void __init ti_clk_init_features(void)
        if (omap_rev() == OMAP3430_REV_ES1_0)
                features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
 
+       /* Errata I810 for omap5 / dra7 */
+       if (soc_is_omap54xx() || soc_is_dra7xx())
+               features.flags |= TI_CLK_ERRATA_I810;
+
        ti_clk_setup_features(&features);
 }
index f4dec00fb684f7743b0fcda3df6f245ac46b7b43..1c300388782ba19d1377bdbbbf9ab05a8939791d 100644 (file)
@@ -305,8 +305,9 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
 static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
 {
        struct dpll_data *dd = clk->dpll_data;
-       u8 dco, sd_div;
+       u8 dco, sd_div, ai = 0;
        u32 v;
+       bool errata_i810;
 
        /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
        _omap3_noncore_dpll_bypass(clk);
@@ -350,6 +351,25 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
                v |= sd_div << __ffs(dd->sddiv_mask);
        }
 
+       /*
+        * Errata i810 - DPLL controller can get stuck while transitioning
+        * to a power saving state. Software must ensure the DPLL can not
+        * transition to a low power state while changing M/N values.
+        * Easiest way to accomplish this is to prevent DPLL autoidle
+        * before doing the M/N re-program.
+        */
+       errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810;
+
+       if (errata_i810) {
+               ai = omap3_dpll_autoidle_read(clk);
+               if (ai) {
+                       omap3_dpll_deny_idle(clk);
+
+                       /* OCP barrier */
+                       omap3_dpll_autoidle_read(clk);
+               }
+       }
+
        ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg);
 
        /* Set 4X multiplier and low-power mode */
@@ -379,6 +399,9 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
 
        _omap3_noncore_dpll_lock(clk);
 
+       if (errata_i810 && ai)
+               omap3_dpll_allow_idle(clk);
+
        return 0;
 }
 
index 223be696df275f7bc45df8b330699570ba6ef721..75205df29b9c7733776502c7365d08d5c037bb52 100644 (file)
@@ -286,6 +286,7 @@ struct ti_clk_features {
 #define TI_CLK_DPLL_HAS_FREQSEL                        BIT(0)
 #define TI_CLK_DPLL4_DENY_REPROGRAM            BIT(1)
 #define TI_CLK_DISABLE_CLKDM_CONTROL           BIT(2)
+#define TI_CLK_ERRATA_I810                     BIT(3)
 
 void ti_clk_setup_features(struct ti_clk_features *features);
 const struct ti_clk_features *ti_clk_get_features(void);