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 | |
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
-rw-r--r-- | Documentation/cpu-freq/governors.txt | 16 | ||||
-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 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_interactive.c | 48 |
5 files changed, 197 insertions, 6 deletions
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt index 46abbcb..871ec8e 100644 --- a/Documentation/cpu-freq/governors.txt +++ b/Documentation/cpu-freq/governors.txt @@ -225,11 +225,21 @@ frequency before ramping down. This is to ensure that the governor has seen enough historic cpu load data to determine the appropriate workload. Default is 80000 uS. -go_maxspeed_load: The CPU load at which to ramp to max speed. Default -is 85. +hispeed_freq: An intermediate "hi speed" at which to initially ramp +when CPU load hits the value specified in go_hispeed_load. If load +stays high for the amount of time specified in above_hispeed_delay, +then speed may be bumped higher. Default is maximum speed. + +go_hispeed_load: The CPU load at which to ramp to the intermediate "hi +speed". Default is 85%. + +above_hispeed_delay: Once speed is set to hispeed_freq, wait for this +long before bumping speed higher in response to continued high load. +Default is 20000 uS. timer_rate: Sample rate for reevaluating cpu load when the system is -not idle. Default is 30000 uS. +not idle. Default is 20000 uS. + 2.7 Hotplug ----------- 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); diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 42b9e74..c9f348f 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -66,21 +66,28 @@ static struct mutex set_speed_lock; static u64 hispeed_freq; /* Go to hi speed when CPU load at or above this value. */ -#define DEFAULT_GO_HISPEED_LOAD 95 +#define DEFAULT_GO_HISPEED_LOAD 85 static unsigned long go_hispeed_load; /* * The minimum amount of time to spend at a frequency before we can ramp down. */ -#define DEFAULT_MIN_SAMPLE_TIME 20 * USEC_PER_MSEC +#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC) static unsigned long min_sample_time; /* * The sample rate of the timer used to increase frequency */ -#define DEFAULT_TIMER_RATE 20 * USEC_PER_MSEC +#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC) static unsigned long timer_rate; +/* + * Wait this long before raising speed above hispeed, by default a single + * timer interval. + */ +#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE +static unsigned long above_hispeed_delay_val; + static int cpufreq_governor_interactive(struct cpufreq_policy *policy, unsigned int event); @@ -174,6 +181,17 @@ static void cpufreq_interactive_timer(unsigned long data) if (new_freq < hispeed_freq) new_freq = hispeed_freq; + + if (pcpu->target_freq == hispeed_freq && + new_freq > hispeed_freq && + cputime64_sub(pcpu->timer_run_time, + pcpu->target_set_time) + < above_hispeed_delay_val) { + trace_cpufreq_interactive_notyet(data, cpu_load, + pcpu->target_freq, + new_freq); + goto rearm; + } } } else { new_freq = pcpu->policy->max * cpu_load / 100; @@ -515,6 +533,28 @@ static ssize_t store_min_sample_time(struct kobject *kobj, static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, show_min_sample_time, store_min_sample_time); +static ssize_t show_above_hispeed_delay(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%lu\n", above_hispeed_delay_val); +} + +static ssize_t store_above_hispeed_delay(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long val; + + ret = strict_strtoul(buf, 0, &val); + if (ret < 0) + return ret; + above_hispeed_delay_val = val; + return count; +} + +define_one_global_rw(above_hispeed_delay); + static ssize_t show_timer_rate(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -540,6 +580,7 @@ static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644, static struct attribute *interactive_attributes[] = { &hispeed_freq_attr.attr, &go_hispeed_load_attr.attr, + &above_hispeed_delay.attr, &min_sample_time_attr.attr, &timer_rate_attr.attr, NULL, @@ -660,6 +701,7 @@ static int __init cpufreq_interactive_init(void) go_hispeed_load = DEFAULT_GO_HISPEED_LOAD; min_sample_time = DEFAULT_MIN_SAMPLE_TIME; + above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY; timer_rate = DEFAULT_TIMER_RATE; /* Initalize per-cpu timers */ |