@@ -258,6 +258,7 @@ static int program_opp_freq(int res, int target_level, int current_level)
#ifdef CONFIG_PM
omap3_save_scratchpad_contents();
#endif
+
*curr_opp = target_level;
return target_level;
}
@@ -267,9 +268,10 @@ static int program_opp(int res, struct omap_opp *opp, int target_level,
{
int i, ret = 0, raise;
#ifdef CONFIG_OMAP_SMARTREFLEX
- unsigned long t_opp;
+ unsigned long t_opp, c_opp;
t_opp = ID_VDD(res) | ID_OPP_NO(opp[target_level].opp_id);
+ c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id);
#endif
if (target_level > current_level)
raise = 1;
@@ -282,8 +284,9 @@ static int program_opp(int res, struct omap_opp *opp, int target_level,
current_level);
#ifdef CONFIG_OMAP_SMARTREFLEX
else
- sr_voltagescale_vcbypass(t_opp,
- opp[target_level].vsel);
+ sr_voltagescale_vcbypass(t_opp, c_opp,
+ opp[target_level].vsel,
+ opp[current_level].vsel);
#endif
}
@@ -28,7 +28,7 @@
#include <mach/omap-pm.h>
#include <mach/omap34xx.h>
-extern int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel);
+extern int sr_voltagescale_vcbypass(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);
/*
* mpu_latency/core_latency are used to control the cpuidle C state.
@@ -449,6 +449,9 @@ static int sr_reset_voltage(int srid)
u32 reg_addr = 0;
u32 loop_cnt = 0, retries_cnt = 0;
u32 vc_bypass_value;
+ u32 t2_smps_steps = 0;
+ u32 t2_smps_delay = 0;
+ u32 prm_vp1_voltage, prm_vp2_voltage;
if (srid == SR1) {
target_opp_no = get_vdd1_opp();
@@ -458,6 +461,9 @@ static int sr_reset_voltage(int srid)
}
vsel = mpu_opps[target_opp_no].vsel;
reg_addr = R_VDD1_SR_CONTROL;
+ prm_vp1_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
+ OMAP3_PRM_VP1_VOLTAGE_OFFSET);
+ t2_smps_steps = abs(vsel - prm_vp1_voltage);
} else if (srid == SR2) {
target_opp_no = get_vdd2_opp();
if (!target_opp_no) {
@@ -466,6 +472,9 @@ static int sr_reset_voltage(int srid)
}
vsel = l3_opps[target_opp_no].vsel;
reg_addr = R_VDD2_SR_CONTROL;
+ prm_vp2_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
+ OMAP3_PRM_VP2_VOLTAGE_OFFSET);
+ t2_smps_steps = abs(vsel - prm_vp2_voltage);
}
vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) |
@@ -493,6 +502,14 @@ static int sr_reset_voltage(int srid)
vc_bypass_value = prm_read_mod_reg(OMAP3430_GR_MOD,
OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
}
+
+ /*
+ * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV,
+ * 2us added as buffer.
+ */
+ t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
+ udelay(t2_smps_delay);
+
return 0;
}
@@ -751,37 +768,43 @@ void disable_smartreflex(int srid)
}
/* Voltage Scaling using SR VCBYPASS */
-int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel)
+int sr_voltagescale_vcbypass(u32 target_opp, u32 current_opp,
+ u8 target_vsel, u8 current_vsel)
{
int sr_status = 0;
- u32 vdd, target_opp_no;
+ u32 vdd, target_opp_no, current_opp_no;
u32 vc_bypass_value;
u32 reg_addr = 0;
u32 loop_cnt = 0, retries_cnt = 0;
+ u32 t2_smps_steps = 0;
+ u32 t2_smps_delay = 0;
vdd = get_vdd(target_opp);
target_opp_no = get_opp_no(target_opp);
+ current_opp_no = get_opp_no(current_opp);
if (vdd == VDD1_OPP) {
sr_status = sr_stop_vddautocomap(SR1);
+ t2_smps_steps = abs(target_vsel - current_vsel);
prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
- (vsel << OMAP3430_VC_CMD_ON_SHIFT),
- OMAP3430_GR_MOD,
- OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+ (target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
reg_addr = R_VDD1_SR_CONTROL;
} else if (vdd == VDD2_OPP) {
sr_status = sr_stop_vddautocomap(SR2);
+ t2_smps_steps = abs(target_vsel - current_vsel);
prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
- (vsel << OMAP3430_VC_CMD_ON_SHIFT),
- OMAP3430_GR_MOD,
- OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+ (target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
reg_addr = R_VDD2_SR_CONTROL;
}
- vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) |
+ vc_bypass_value = (target_vsel << OMAP3430_DATA_SHIFT) |
(reg_addr << OMAP3430_REGADDR_SHIFT) |
(R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT);
@@ -807,7 +830,12 @@ int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel)
OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
}
- udelay(T2_SMPS_UPDATE_DELAY);
+ /*
+ * T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV,
+ * 2us added as buffer.
+ */
+ t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
+ udelay(t2_smps_delay);
if (sr_status) {
if (vdd == VDD1_OPP)
@@ -245,7 +245,7 @@ extern u32 current_vdd2_opp;
#ifdef CONFIG_OMAP_SMARTREFLEX
void enable_smartreflex(int srid);
void disable_smartreflex(int srid);
-int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel);
+int sr_voltagescale_vcbypass(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);
void sr_start_vddautocomap(int srid, u32 target_opp_no);
int sr_stop_vddautocomap(int srid);
#else
This patch removes the worst case T2 SMPS stabilization delay of 360 us (needed for a 0v to 1.35 switch) and adds calculated delay based on the actual volatge switch. The delay is based on the T2 SMPS slew rate of 4mV/uS. Each step based on VSEL difference corresponds to 12.5 mv Hence the formula used: delay = (steps * 12.5)/4 + (2 us of buffer). This also adds a SMPS stabilization delay in the sr_reset_voltage() function which seems to be needed. Signed-off-by: Rajendra Nayak <rnayak@ti.com> --- arch/arm/mach-omap2/resource34xx.c | 9 ++++-- arch/arm/mach-omap2/resource34xx.h | 2 +- arch/arm/mach-omap2/smartreflex.c | 48 ++++++++++++++++++++++++++++------- arch/arm/mach-omap2/smartreflex.h | 2 +- 4 files changed, 46 insertions(+), 15 deletions(-)