diff options
author | Todd Poynor <toddpoynor@google.com> | 2012-04-18 19:55:15 -0700 |
---|---|---|
committer | Todd Poynor <toddpoynor@google.com> | 2012-04-18 19:55:15 -0700 |
commit | 0fd69b72de1a40a4c4234ce3e96270253931f348 (patch) | |
tree | ce5deca52631216aec729c72fb814faba75f94c2 /arch/arm | |
parent | 0faf39378fcd3951890e2119f85438668ff8a7c6 (diff) | |
parent | 635aaea87060186666212363e26acc5207873b32 (diff) | |
download | kernel_samsung_tuna-0fd69b72de1a40a4c4234ce3e96270253931f348.zip kernel_samsung_tuna-0fd69b72de1a40a4c4234ce3e96270253931f348.tar.gz kernel_samsung_tuna-0fd69b72de1a40a4c4234ce3e96270253931f348.tar.bz2 |
Merge branch 'android-omap-3.0' into android-omap-tuna-3.0
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/dpll44xx.c | 38 | ||||
-rw-r--r-- | arch/arm/mach-omap2/emif.c | 99 | ||||
-rw-r--r-- | arch/arm/mach-omap2/include/mach/emif.h | 2 |
3 files changed, 139 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 7e509e7..983617f 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -79,6 +79,35 @@ int omap4_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) clkdm_wakeup(l3_emif_clkdm); /* + * Errata ID: i728 + * + * DESCRIPTION: + * + * If during a small window the following three events occur: + * + * 1) The EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM SR_TIMING counter expires + * 2) Frequency change update is requested CM_SHADOW_FREQ_CONFIG1 + * FREQ_UPDATE set to 1 + * 3) OCP access is requested + * + * There will be clock instability on the DDR interface. + * + * WORKAROUND: + * + * Prevent event 1) while event 2) is happening. + * + * Disable the self-refresh when requesting a frequency change. + * Before requesting a frequency change, program + * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0 + * (omap_emif_frequency_pre_notify) + * + * When the frequency change is completed, reprogram + * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2. + * (omap_emif_frequency_post_notify) + */ + omap_emif_frequency_pre_notify(); + + /* * Program EMIF timing parameters in EMIF shadow registers * for targetted DRR clock. * DDR Clock = core_dpll_m2 / 2 @@ -107,6 +136,9 @@ int omap4_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) & OMAP4430_FREQ_UPDATE_MASK) == 0), MAX_FREQ_UPDATE_TIMEOUT, i); + /* Re-enable DDR self refresh */ + omap_emif_frequency_post_notify(); + /* Configures MEMIF domain back to HW_WKUP */ clkdm_allow_idle(l3_emif_clkdm); @@ -150,6 +182,9 @@ int omap4_prcm_freq_update(void) /* Configures MEMIF domain in SW_WKUP */ clkdm_wakeup(l3_emif_clkdm); + /* Disable DDR self refresh (Errata ID: i728) */ + omap_emif_frequency_pre_notify(); + /* * FREQ_UPDATE sequence: * - DLL_OVERRIDE=0 (DLL lock & code must not be overridden @@ -167,6 +202,9 @@ int omap4_prcm_freq_update(void) & OMAP4430_FREQ_UPDATE_MASK) == 0), MAX_FREQ_UPDATE_TIMEOUT, i); + /* Re-enable DDR self refresh */ + omap_emif_frequency_post_notify(); + /* Configures MEMIF domain back to HW_WKUP */ clkdm_allow_idle(l3_emif_clkdm); diff --git a/arch/arm/mach-omap2/emif.c b/arch/arm/mach-omap2/emif.c index 968bcde..8d41bd1 100644 --- a/arch/arm/mach-omap2/emif.c +++ b/arch/arm/mach-omap2/emif.c @@ -38,6 +38,7 @@ struct emif_instance { void __iomem *base; u16 irq; struct platform_device *pdev; + bool ddr_refresh_disabled; }; static struct emif_instance emif[EMIF_NUM_INSTANCES]; static struct emif_regs *emif_curr_regs[EMIF_NUM_INSTANCES]; @@ -534,6 +535,47 @@ static u32 get_ddr_phy_ctrl_1(u32 freq, u8 RL) } /* + * get_lp_mode - Get the LP Mode of a EMIF instance. + * + * It returns the REG_LP_MODE of EMIF_PWR_MGMT_CTRL[10:8] + * for a EMIF. + * + */ +static u32 get_lp_mode(u32 emif_nr) +{ + u32 temp, lpmode; + void __iomem *base = emif[emif_nr].base; + + temp = readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + lpmode = (temp & OMAP44XX_REG_LP_MODE_MASK) >> + OMAP44XX_REG_LP_MODE_SHIFT; + + return lpmode; +} + +/* + * set_lp_mode - Set the LP Mode of a EMIF instance. + * + * It replaces the REG_LP_MODE of EMIF_PWR_MGMT_CTRL[10:8] + * with the new value for a EMIF. + * + */ +static void set_lp_mode(u32 emif_nr, u32 lpmode) +{ + u32 temp; + void __iomem *base = emif[emif_nr].base; + + /* Extract current lp mode value */ + temp = readl(base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + + /* Write out the new lp mode value */ + temp &= ~OMAP44XX_REG_LP_MODE_MASK; + temp |= lpmode << OMAP44XX_REG_LP_MODE_SHIFT; + writel(temp, base + OMAP44XX_EMIF_PWR_MGMT_CTRL); + +} + +/* * Get the temperature level of the EMIF instance: * Reads the MR4 register of attached SDRAM parts to find out the temperature * level. If there are two parts attached(one on each CS), then the temperature @@ -875,6 +917,8 @@ static int __devinit omap_emif_probe(struct platform_device *pdev) pr_info("EMIF%d is enabled with IRQ%d\n", id, emif[id].irq); + emif[id].ddr_refresh_disabled = false; + return 0; } @@ -1278,6 +1322,61 @@ int omap_emif_setup_registers(u32 freq, u32 volt_state) return err; } + +/* + * omap_emif_frequency_pre_notify - Disable DDR self refresh of both EMIFs + * + * It disables the LP mode if the LP mode of EMIFs was LP_MODE_SELF_REFRESH. + * + * It should be called before any PRCM frequency update sequence. + * After the frequency update sequence, omap_emif_frequency_post_notify + * should be called to restore the original LP MODE setting of the EMIFs. + * + */ +void omap_emif_frequency_pre_notify(void) +{ + int emif_num; + + for (emif_num = EMIF1; emif_num < EMIF_NUM_INSTANCES; emif_num++) { + + /* + * Only disable ddr self-refresh + * if ddr self-refresh was enabled + */ + if (likely(LP_MODE_SELF_REFRESH == get_lp_mode(emif_num))) { + + set_lp_mode(emif_num, LP_MODE_DISABLE); + emif[emif_num].ddr_refresh_disabled = true; + } + + } +} + +/* + * omap_emif_frequency_post_notify - Enable DDR self refresh of both EMIFs + * + * It restores the LP mode of the EMIFs back to LP_MODE_SELF_REFRESH if it + * was previously disabled by omap_emif_frequency_pre_notify() + * + */ +void omap_emif_frequency_post_notify(void) +{ + int emif_num; + + for (emif_num = EMIF1; emif_num < EMIF_NUM_INSTANCES; emif_num++) { + + /* + * Only re-enable ddr self-refresh + * if ddr self-refresh was disabled + */ + if (likely(emif[emif_num].ddr_refresh_disabled)) { + + set_lp_mode(emif_num, LP_MODE_SELF_REFRESH); + emif[emif_num].ddr_refresh_disabled = false; + } + } +} + /* * omap_emif_setup_device_details - save the SDRAM device details passed * from the board file diff --git a/arch/arm/mach-omap2/include/mach/emif.h b/arch/arm/mach-omap2/include/mach/emif.h index 99a7c69..d7e1eb9 100644 --- a/arch/arm/mach-omap2/include/mach/emif.h +++ b/arch/arm/mach-omap2/include/mach/emif.h @@ -258,6 +258,8 @@ struct emif_regs { int omap_emif_setup_registers(u32 freq, u32 volt_state); +void omap_emif_frequency_pre_notify(void); +void omap_emif_frequency_post_notify(void); int omap_emif_setup_device_details( const struct emif_device_details *emif1_devices, const struct emif_device_details *emif2_devices); |