Kevin, Any comments on this patch? Regards Vishwa > -----Original Message----- > From: Sripathy, Vishwanath > Sent: Thursday, May 27, 2010 6:20 PM > To: linux-omap@xxxxxxxxxxxxxxx > Cc: Sripathy, Vishwanath; Peter 'p2' De Schrijver; Gulati, Shweta > Subject: [PATCH V3] OMAP3: PM: Workaround for DLL Lock issue > > From: Vishwanath BS <vishwanath.bs@xxxxxx> > > OMAP3430/3630 has a Silicon bug because of which SDRC is > released from IDLE even before Core DPLL has locked. This leads > to undefined behaviour of SDRC DLL. > > Bug Descritpion: The root cause of the issue is that SDRC IDLEREQ > is deasserted before DPLL3 has locked. Because of this DLL may/may > not lock based on Process Voltage Temperature conditions. The bug > can occur when DPLL3 automatic transition is enabled. So DPLL3 automatic > transition is disabled by default and it is enabled only when system > is entering ret/off state (to facilitate voltage scaling). So when system > is entering ret/off state, WA is applied (since DPLL3 autoidle is enabled, > we can possibly hit the issue; hence the WA) > > Errata id: i581 > > Workaround Descrioption: > Description of WA for 3430: > Initialization: > Disable DPLL3 automatic mode by default. Issue will not be faced as DPLL3 > is always locked. > > Before CORE Voltage Domain (VDD2) Sleep Transition to RETENTION or OFF mode: > 1. Reduce DPLL3 M2 Frequency to get L3 running at OPP2 Frequency > (by changing M2 Divider value). This is increasing the period duration of > one L3 clock cycle. > o In case of CORE is at OPP3 (166MHz@xxxxx): > " Lower the frequency to 83MHz. > > o In case of CORE is at OPP2 (83MHz@xxxxx): > " Keep the frequency as it is (83MHz). > > 2. Increase CORE Voltage to 1.2V. This is reducing the timing duration of the > critical path signal which will now fit to one L3 clock cycle. > > 3. Enable DPLL3 Automatic mode. This will ensure proper transition to > RETENTION or OFF mode. > > After CORE Voltage Domain Wakeup Transition from RETENTION or OFF mode: > 1. Disable DPLL3 Automatic mode. > 2. Restore previous DPLL3 M2 Frequency and CORE Voltage values. > > Description of WA for 3630: > Initialization: > Disable DPLL3 automatic mode by default. Issue will not be faced as DPLL3 is > always > locked. > > Before CORE Voltage Domain(VDD2) Sleep Transition to RETENTION or OFF mode: > 1. Reduce DPLL3 M2 Frequency to get L3 running at OPP50 Frequency > (by changing M2 Divider value) and set VDD2 Voltage for OPP100. > This is increasing the period duration of one L3 clock cycle and reducing > the timing duration of the critical path signal which will now fit to one > L3 clock cycle. > o In case of CORE is at OPP100 (L3=200MHz, VDD2=1.1375V): > " Lower the frequency to 100MHz. > " Keep the voltage as it is (1.1375V). > > o In case of CORE is at OPP50 (L3=100MHz, VDD2=0.93V): > " Keep the frequency as it is (100MHz). > " Increase the voltage to 1.1375V. > > 2. Enable DPLL3 Automatic mode. This will ensure proper transition to > RETENTION or OFF mode. > > After CORE Voltage Domain Wakeup Transition from RETENTION or OFF mode: > 1. Disable DPLL3 Automatic mode. > 2. Restore previous DPLL3 M2 Frequency and CORE Voltage values. > > Also OSWR should not be attempted if DPLL3 has locked. This should be done as part > of OSWR patch > series. > These patch is based on Thara's Smart Reflex V3 patch series (wip_sr branch) and > Tero's OS Idle changes @ > https://patchwork.kernel.org/patch/85268/ > > Patch tested on 3430SDP and 3630 ZOOM3. > > Changes done in V3: > 1. Addressed comments from Kevin > 2. Optimized the code based on Peter's patch > > Cc: Peter 'p2' De Schrijver <peter.de-schrijver@xxxxxxxxx> > > Signed-off-by: Shweta Gulati <shweta.gulati@xxxxxx> > Signed-off-by: Vishwanath BS <vishwanath.bs@xxxxxx> > --- > arch/arm/mach-omap2/pm34xx.c | 114 > ++++++++++++++++++++++++++++++++++++++++- > arch/arm/mach-omap2/voltage.c | 1 + > 2 files changed, 113 insertions(+), 2 deletions(-) > > diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c > index 9c57081..b0a5d09 100755 > --- a/arch/arm/mach-omap2/pm34xx.c > +++ b/arch/arm/mach-omap2/pm34xx.c > @@ -55,6 +55,7 @@ > #include "pm.h" > #include "sdrc.h" > #include "omap3-opp.h" > +#include "clock3xxx.h" > > #ifdef CONFIG_SUSPEND > static suspend_state_t suspend_state = PM_SUSPEND_ON; > @@ -97,6 +98,15 @@ static int (*_omap_save_secure_sram)(u32 *addr); > > static struct powerdomain *mpu_pwrdm, *neon_pwrdm; > static struct powerdomain *core_pwrdm, *per_pwrdm; > +static struct powerdomain *dss_pwrdm, *usbhost_pwrdm; > +static struct powerdomain *cam_pwrdm, *sgx_pwrdm; > +static struct clk *dpll3_clk; > +static struct omap_opp *vdd2_opp50, *vdd2_opp100; > +static unsigned long vdd2_opp50_volt, vdd2_opp100_volt; > + > +#define DLL_LOCK_ERRATA_581 (1 << 0) > +static u16 pm34xx_errata; > +#define IS_PM34XX_ERRATA(id) (pm34xx_errata & (id)) > > static inline void omap3_per_save_context(void) > { > @@ -367,6 +377,7 @@ void omap_sram_idle(void) > int core_next_state = PWRDM_POWER_ON; > int core_prev_state, per_prev_state; > u32 sdrc_pwr = 0; > + int prev_dpll3_div = 0; > > if (!_omap_sram_idle) > return; > @@ -417,9 +428,43 @@ void omap_sram_idle(void) > */ > if (mpu_next_state <= PWRDM_POWER_RET) > omap_smartreflex_disable(VDD1, 1); > - if (core_next_state <= PWRDM_POWER_RET) > + if (core_next_state <= PWRDM_POWER_RET) { > omap_smartreflex_disable(VDD2, 1); > > + /* Apply the errata if Core is entering RET/OFF */ > + if ((IS_PM34XX_ERRATA(DLL_LOCK_ERRATA_581)) && > + (core_next_state <= PWRDM_POWER_RET)) { > + if (pwrdm_can_idle(core_pwrdm) && > + pwrdm_can_idle(per_pwrdm) && > + pwrdm_can_idle(dss_pwrdm) && > + pwrdm_can_idle(usbhost_pwrdm) && > + pwrdm_can_idle(cam_pwrdm) && > + pwrdm_can_idle(sgx_pwrdm)) { > + u32 clksel1_pll; > + clksel1_pll = cm_read_mod_reg(PLL_MOD, > + OMAP3430_CM_CLKSEL1_PLL); > + prev_dpll3_div = clksel1_pll >> > + OMAP3430_CORE_DPLL_CLKOUT_DIV_SHIFT; > + if (prev_dpll3_div == 1) { > + omap3_core_dpll_m2_set_rate(dpll3_clk, > + opp_get_freq(vdd2_opp50) * 2); > + if (cpu_is_omap343x()) > + omap_voltage_scale(VDD2, 1200000, > + vdd2_opp100_volt); > + } else { > + if (cpu_is_omap3630()) > + omap_voltage_scale(VDD2, > vdd2_opp100_volt, > + vdd2_opp50_volt); > + else if (cpu_is_omap343x()) > + omap_voltage_scale(VDD2, 1200000, > + vdd2_opp50_volt); > + } > + > cm_rmw_mod_reg_bits(OMAP3430_AUTO_CORE_DPLL_MASK, > + 0x1, PLL_MOD, CM_AUTOIDLE); > + } > + } > + } > + > /* CORE */ > if (core_next_state < PWRDM_POWER_ON) { > omap_uart_prepare_idle(0); > @@ -484,6 +529,44 @@ void omap_sram_idle(void) > if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) > restore_table_entry(); > > + if (IS_PM34XX_ERRATA(DLL_LOCK_ERRATA_581) && > + (core_next_state < PWRDM_POWER_INACTIVE)) { > + if (pwrdm_read_prev_pwrst(core_pwrdm) == PWRDM_POWER_OFF) { > + u32 clksel1_pll; > + > + /* ROM code restored the scratchpad settings. So DPLL3 > + * autoidle is disabled and L3 clock is back to the > + * value before entering this function. This means we > + * only have to lower the voltage if L3 runs at OPP50 > + */ > + > + clksel1_pll = cm_read_mod_reg(PLL_MOD, > + OMAP3430_CM_CLKSEL1_PLL); > + if ((clksel1_pll >> OMAP3430_CORE_DPLL_CLKOUT_DIV_SHIFT) > == 2) { > + /* restore VDD2 OPP2 voltage */ > + if (cpu_is_omap3630()) > + omap_voltage_scale(VDD2, vdd2_opp50_volt, > vdd2_opp100_volt); > + else if (cpu_is_omap343x()) > + omap_voltage_scale(VDD2, vdd2_opp50_volt, > 1200000); > + } > + } else { > + /* disable DPLL3 autoidle */ > + cm_rmw_mod_reg_bits(OMAP3430_AUTO_CORE_DPLL_MASK, > + 0x0, PLL_MOD, CM_AUTOIDLE); > + if (prev_dpll3_div == 1) { > + omap3_core_dpll_m2_set_rate(dpll3_clk, > + opp_get_freq(vdd2_opp100) * 2); > + if (cpu_is_omap343x()) > + omap_voltage_scale(VDD2, vdd2_opp100_volt, > 1200000); > + } else { > + if (cpu_is_omap3630()) > + omap_voltage_scale(VDD2, vdd2_opp50_volt, > vdd2_opp100_volt); > + else if (cpu_is_omap343x()) > + omap_voltage_scale(VDD2, vdd2_opp50_volt, > 1200000); > + } > + } > + } > + > /* CORE */ > if (core_next_state < PWRDM_POWER_ON) { > core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); > @@ -1006,7 +1089,12 @@ static void __init prcm_setup_regs(void) > cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT, > MPU_MOD, > CM_AUTOIDLE2); > - cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) | > + if (IS_PM34XX_ERRATA(DLL_LOCK_ERRATA_581)) > + cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT), > + PLL_MOD, > + CM_AUTOIDLE); > + else > + cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) | > (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT), > PLL_MOD, > CM_AUTOIDLE); > @@ -1178,17 +1266,27 @@ void omap_push_sram_idle(void) > save_secure_ram_context_sz); > } > > +void pm_errata_configure() > +{ > + /* TODO: add 3630 && omap_rev() <= OMAP3630_REV_ES1_1 */ > + if (cpu_is_omap343x() || (cpu_is_omap3630())) > + pm34xx_errata |= DLL_LOCK_ERRATA_581; > +} > + > static int __init omap3_pm_init(void) > { > struct power_state *pwrst, *tmp; > struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm; > int ret; > + unsigned long freq = 0; > > if (!cpu_is_omap34xx()) > return -ENODEV; > > printk(KERN_ERR "Power Management for TI OMAP3.\n"); > > + pm_errata_configure(); > + > /* XXX prcm_setup_regs needs to be before enabling hw > * supervised mode for powerdomains */ > prcm_setup_regs(); > @@ -1219,12 +1317,24 @@ static int __init omap3_pm_init(void) > neon_pwrdm = pwrdm_lookup("neon_pwrdm"); > per_pwrdm = pwrdm_lookup("per_pwrdm"); > core_pwrdm = pwrdm_lookup("core_pwrdm"); > + usbhost_pwrdm = pwrdm_lookup("usbhost_pwrdm"); > + sgx_pwrdm = pwrdm_lookup("sgx_pwrdm"); > + dss_pwrdm = pwrdm_lookup("dss_pwrdm"); > + cam_pwrdm = pwrdm_lookup("cam_pwrdm"); > > neon_clkdm = clkdm_lookup("neon_clkdm"); > mpu_clkdm = clkdm_lookup("mpu_clkdm"); > per_clkdm = clkdm_lookup("per_clkdm"); > core_clkdm = clkdm_lookup("core_clkdm"); > > + dpll3_clk = clk_get(NULL, "dpll3_m2_ck"); > + > + vdd2_opp50 = opp_find_freq_ceil(OPP_L3, &freq); > + freq = ULONG_MAX; > + vdd2_opp100 = opp_find_freq_floor(OPP_L3, &freq); > + vdd2_opp50_volt = opp_get_voltage(vdd2_opp50); > + vdd2_opp100_volt = opp_get_voltage(vdd2_opp100); > + > omap_push_sram_idle(); > #ifdef CONFIG_SUSPEND > suspend_set_ops(&omap_pm_ops); > diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c > index c5e9c42..e84a0ff 100644 > --- a/arch/arm/mach-omap2/voltage.c > +++ b/arch/arm/mach-omap2/voltage.c > @@ -173,6 +173,7 @@ static struct omap_volt_data omap34xx_vdd2_volt_data[] = > { > {975000, 0, 0xF4, 0x0C}, > {1050000, 0, 0xF4, 0x0C}, > {1150000, 0, 0xF9, 0x18}, > + {1200000, 0, 0xF9, 0x18}, > }; > > static struct omap_volt_data omap36xx_vdd2_volt_data[] = { > -- > 1.5.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html