--- a7972a36b43819435884b04882703f69eac3d595 +++ da51162d5ad0246de7a488ffefec9e192a73472e @@ -27,6 +27,9 @@ #include #include "acpuclock.h" +#ifdef CONFIG_MSM_CPU_AVS +#include "avs.h" +#endif #include "proc_comm.h" #include "clock.h" @@ -76,8 +79,6 @@ struct clkctl_acpu_speed acpu_freq_tbl[] { 19200, CCTL(CLK_TCXO, 1), SRC_RAW, 0, 0, 925, 14000}, { 128000, CCTL(CLK_TCXO, 1), SRC_AXI, 0, 0, 925, 14000 }, { 245000, CCTL(CLK_MODEM_PLL, 1), SRC_RAW, 0, 0, 925, 29000 }, - /* Work arround for acpu resume hung, GPLL is turn off by arm9 */ - /*{ 256000, CCTL(CLK_GLOBAL_PLL, 3), SRC_RAW, 0, 0, 1050, 29000 },*/ { 384000, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0A, 0, 975, 58000 }, { 422400, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0B, 0, 975, 117000 }, { 460800, CCTL(CLK_TCXO, 1), SRC_SCPLL, 0x0C, 0, 1000, 117000 }, @@ -155,14 +156,15 @@ static void __init acpuclk_init_cpufreq_ struct clock_state { struct clkctl_acpu_speed *current_speed; - struct mutex lock; + struct mutex lock; uint32_t acpu_switch_time_us; uint32_t max_speed_delta_khz; uint32_t vdd_switch_time_us; - unsigned long power_collapse_khz; - unsigned long wait_for_irq_khz; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; struct clk* clk_ebi1; - struct regulator *regulator; + struct regulator *regulator; + int (*acpu_set_vdd) (int mvolts); }; static struct clock_state drv_state = { 0 }; @@ -286,27 +288,41 @@ static void select_clock(unsigned src, u writel(val | ((src & 3) << 1), SPSS_CLK_SEL_ADDR); } -static int acpuclk_set_vdd_level(int vdd) +static int acpu_set_vdd(int vdd) { if (!drv_state.regulator || IS_ERR(drv_state.regulator)) { drv_state.regulator = regulator_get(NULL, "acpu_vcore"); if (IS_ERR(drv_state.regulator)) { - pr_info("acpuclk_set_vdd_level %d no regulator\n", vdd); + pr_info("acpu_set_vdd %d no regulator\n", vdd); /* Assume that the PMIC supports scaling the processor * to its maximum frequency at its default voltage. */ - return 0; + return -ENODEV; } - pr_info("acpuclk_set_vdd_level got regulator\n"); + pr_info("acpu_set_vdd got regulator\n"); } vdd *= 1000; /* mV -> uV */ return regulator_set_voltage(drv_state.regulator, vdd, vdd); } +static int acpuclk_set_vdd_level(int vdd) +{ + if (drv_state.acpu_set_vdd) + return drv_state.acpu_set_vdd(vdd); + else { + /* Assume that the PMIC supports scaling the processor + * to its maximum frequency at its default voltage. + */ + return 0; + } +} + int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) { struct clkctl_acpu_speed *cur, *next; unsigned long flags; + int rc = 0; + int freq_index = 0; cur = drv_state.current_speed; @@ -325,16 +341,29 @@ int acpuclk_set_rate(unsigned long rate, if (next->acpu_khz == 0) return -EINVAL; next++; + freq_index++; } if (reason == SETRATE_CPUFREQ) { mutex_lock(&drv_state.lock); +#ifdef CONFIG_MSM_CPU_AVS + /* Notify avs before changing frequency */ + rc = avs_adjust_freq(freq_index, 1); + if (rc) { + printk(KERN_ERR + "acpuclock: Unable to increase ACPU " + "vdd: %d.\n", (int) rate); + mutex_unlock(&drv_state.lock); + return rc; + } +#endif /* Increase VDD if needed. */ if (next->vdd > cur->vdd) { - if (acpuclk_set_vdd_level(next->vdd)) { - pr_err("acpuclock: Unable to increase ACPU VDD.\n"); + rc = acpuclk_set_vdd_level(next->vdd); + if (rc) { + pr_err("acpuclock: Unable to increase ACPU VDD from %d to %d setting rate to %d.\n", cur->vdd, next->vdd, (int) rate); mutex_unlock(&drv_state.lock); - return -EINVAL; + return rc; } } } @@ -367,24 +396,28 @@ int acpuclk_set_rate(unsigned long rate, spin_unlock_irqrestore(&acpu_lock, flags); -#ifndef CONFIG_AXI_SCREEN_POLICY if (reason == SETRATE_CPUFREQ || reason == SETRATE_PC) { if (cur->axiclk_khz != next->axiclk_khz) clk_set_rate(drv_state.clk_ebi1, next->axiclk_khz * 1000); - DEBUG("acpuclk_set_rate switch axi to %d\n", - clk_get_rate(drv_state.clk_ebi1)); } -#endif + if (reason == SETRATE_CPUFREQ) { +#ifdef CONFIG_MSM_CPU_AVS + /* notify avs after changing frequency */ + rc = avs_adjust_freq(freq_index, 0); + if (rc) + printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd: %d.\n", (int) rate); +#endif /* Drop VDD level if we can. */ if (next->vdd < cur->vdd) { - if (acpuclk_set_vdd_level(next->vdd)) - pr_err("acpuclock: Unable to drop ACPU VDD.\n"); + rc = acpuclk_set_vdd_level(next->vdd); + if (rc) + pr_err("acpuclock: Unable to drop ACPU VDD from %d to %d setting rate to %d.\n", cur->vdd, next->vdd, (int) rate); } mutex_unlock(&drv_state.lock); } - return 0; + return rc; } static unsigned __init acpuclk_find_speed(void) @@ -435,15 +468,15 @@ static void __init acpuclk_init(void) BUG(); } - /* Move to 768MHz for boot, which is a safe frequency + /* Move to 998MHz for boot, which is a safe frequency * for all versions of Scorpion at the moment. */ speed = acpu_freq_tbl; for (;;) { - if (speed->acpu_khz == 768000) + if (speed->acpu_khz == 998400) break; if (speed->acpu_khz == 0) { - pr_err("acpuclk_init: cannot find 768MHz\n"); + pr_err("acpuclk_init: cannot find 998MHz\n"); BUG(); } speed++; @@ -501,6 +534,23 @@ unsigned long acpuclk_wait_for_irq(void) return ret * 1000; } +#ifdef CONFIG_MSM_CPU_AVS +static int __init acpu_avs_init(int (*set_vdd) (int), int khz) +{ + int i; + int freq_count = 0; + int freq_index = -1; + + for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) { + freq_count++; + if (acpu_freq_tbl[i].acpu_khz == khz) + freq_index = i; + } + + return avs_init(set_vdd, freq_count, freq_index); +} +#endif + void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) { spin_lock_init(&acpu_lock); @@ -511,14 +561,66 @@ void __init msm_acpu_clock_init(struct m drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; drv_state.power_collapse_khz = clkdata->power_collapse_khz; drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; - + drv_state.acpu_set_vdd = acpu_set_vdd; + if (clkdata->mpll_khz) acpu_mpll->acpu_khz = clkdata->mpll_khz; acpuclk_init(); acpuclk_init_cpufreq_table(); drv_state.clk_ebi1 = clk_get(NULL,"ebi1_clk"); -#ifndef CONFIG_AXI_SCREEN_POLICY clk_set_rate(drv_state.clk_ebi1, drv_state.current_speed->axiclk_khz * 1000); + +#ifdef CONFIG_MSM_CPU_AVS + if (!acpu_avs_init(drv_state.acpu_set_vdd, + drv_state.current_speed->acpu_khz)) { + /* avs init successful. avs will handle voltage changes */ + drv_state.acpu_set_vdd = NULL; + } #endif } + +#ifdef CONFIG_CPU_FREQ_VDD_LEVELS +#ifndef CONFIG_MSM_CPU_AVS +ssize_t acpuclk_get_vdd_levels_str(char *buf) +{ + int i, len = 0; + if (buf) + { + mutex_lock(&drv_state.lock); + for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) + { + if (freq_table[i].frequency != CPUFREQ_ENTRY_INVALID) + len += sprintf(buf + len, "%8u: %4d\n", acpu_freq_tbl[i].acpu_khz, acpu_freq_tbl[i].vdd); + } + mutex_unlock(&drv_state.lock); + } + return len; +} + +void acpuclk_set_vdd(unsigned acpu_khz, int max_vdd) +{ + int i; + struct clkctl_acpu_speed *cur; + cur = drv_state.current_speed; + max_vdd = max_vdd / 25 * 25; //! regulator only accepts multiples of 25 (mV) + mutex_lock(&drv_state.lock); + for (i = 0; acpu_freq_tbl[i].acpu_khz; i++) + { + if (freq_table[i].frequency != CPUFREQ_ENTRY_INVALID) + { + if (acpu_khz == 0) { + acpu_freq_tbl[i].vdd = min(max((acpu_freq_tbl[i].vdd + max_vdd), CONFIG_CPU_FREQ_VDD_LEVELS_MIN), CONFIG_CPU_FREQ_VDD_LEVELS_MAX); + if(cur->acpu_khz == acpu_freq_tbl[i].acpu_khz) + acpuclk_set_vdd_level(acpu_freq_tbl[i].vdd); + } else if (acpu_freq_tbl[i].acpu_khz == acpu_khz) { + acpu_freq_tbl[i].vdd = min(max(max_vdd, CONFIG_CPU_FREQ_VDD_LEVELS_MIN), CONFIG_CPU_FREQ_VDD_LEVELS_MAX); + if(cur->acpu_khz == acpu_freq_tbl[i].acpu_khz) + acpuclk_set_vdd_level(acpu_freq_tbl[i].vdd); + } + } + } + mutex_unlock(&drv_state.lock); +} +#endif +#endif