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 <[email protected]>
---
 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(-)

diff --git a/arch/arm/mach-omap2/resource34xx.c 
b/arch/arm/mach-omap2/resource34xx.c
index 4c87436..82405b6 100644
--- a/arch/arm/mach-omap2/resource34xx.c
+++ b/arch/arm/mach-omap2/resource34xx.c
@@ -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
        }
 
diff --git a/arch/arm/mach-omap2/resource34xx.h 
b/arch/arm/mach-omap2/resource34xx.h
index 8d95a00..a160665 100644
--- a/arch/arm/mach-omap2/resource34xx.h
+++ b/arch/arm/mach-omap2/resource34xx.h
@@ -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.
diff --git a/arch/arm/mach-omap2/smartreflex.c 
b/arch/arm/mach-omap2/smartreflex.c
index 422c917..a2fe00e 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -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)
diff --git a/arch/arm/mach-omap2/smartreflex.h 
b/arch/arm/mach-omap2/smartreflex.h
index 94e522b..2a0e823 100644
--- a/arch/arm/mach-omap2/smartreflex.h
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -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
-- 
1.5.4.7

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to