diff mbox

[RFC,v3] OMAP3:PM: Fix OPP scale logic

Message ID 1249400032-23759-1-git-send-email-nm@ti.com (mailing list archive)
State Changes Requested
Delegated to: Kevin Hilman
Headers show

Commit Message

Nishanth Menon Aug. 4, 2009, 3:33 p.m. UTC
While switching from higher OPP to lower OPP,
current scale logic can fail by switching to lower
voltage while frequency remains at old value.

This patch adds a cleaner recovery logic and
additional freq dpll checks. This changes
program_freq_opp return type in the process
for program_opp to handle error in a consistent
manner.

NOTE: I moved the *cur_opp setting to under the
scratchpad locked region to allow for code
simplicity - i wonder if anyone sees an issue with it

Thanks to Roger in patiently catching my goofups :(

Tested on:rx-51, ported to pm branch - untested linux-omap
Patch generated on linux-omap pm branch, commit:
7e7377395d6b4576341a6939bf2179f3946f2ea0

Signed-off-by: Nishanth Menon <nm@ti.com>
Cc: Roger Quadros <ext-roger.quadros@nokia.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com> 
Cc: Paul Walmsley <paul@pwsan.com>
---
 arch/arm/mach-omap2/resource34xx.c |   61 +++++++++++++++++++++++++++---------
 1 files changed, 46 insertions(+), 15 deletions(-)

Comments

Kevin Hilman Aug. 28, 2009, 9:13 a.m. UTC | #1
Nishanth Menon <nm@ti.com> writes:

> While switching from higher OPP to lower OPP,
> current scale logic can fail by switching to lower
> voltage while frequency remains at old value.
>
> This patch adds a cleaner recovery logic and
> additional freq dpll checks. This changes
> program_freq_opp return type in the process
> for program_opp to handle error in a consistent
> manner.
>
> NOTE: I moved the *cur_opp setting to under the
> scratchpad locked region to allow for code
> simplicity - i wonder if anyone sees an issue with it
>
> Thanks to Roger in patiently catching my goofups :(
>
> Tested on:rx-51, ported to pm branch - untested linux-omap
> Patch generated on linux-omap pm branch, commit:
> 7e7377395d6b4576341a6939bf2179f3946f2ea0
>
> Signed-off-by: Nishanth Menon <nm@ti.com>
> Cc: Roger Quadros <ext-roger.quadros@nokia.com>
> Cc: Kevin Hilman <khilman@deeprootsystems.com> 
> Cc: Paul Walmsley <paul@pwsan.com>
> ---
>  arch/arm/mach-omap2/resource34xx.c |   61 +++++++++++++++++++++++++++---------
>  1 files changed, 46 insertions(+), 15 deletions(-)

The fix looks good for adding the extra checks, but can you do some
more testing on current PM branch?  This currently doesn't even
compile on current PM branch.

Thanks,

Kevin


[...]
  CC      arch/arm/mach-omap2/resource34xx.o
distcc[24405] ERROR: compile /tmp/khilman/.ccache/resource34.tmp.vence.24379.i on localhost failed
/opt/home/khilman/work.local/kernel/omap/pm-next/arch/arm/mach-omap2/resource34xx.c: In function 'program_opp':
/opt/home/khilman/work.local/kernel/omap/pm-next/arch/arm/mach-omap2/resource34xx.c:333: error: 'PRCM_VDD1' undeclared (first use in this function)
/opt/home/khilman/work.local/kernel/omap/pm-next/arch/arm/mach-omap2/resource34xx.c:333: error: (Each undeclared identifier is reported only once
/opt/home/khilman/work.local/kernel/omap/pm-next/arch/arm/mach-omap2/resource34xx.c:333: error: for each function it appears in.)
make[2]: *** [arch/arm/mach-omap2/resource34xx.o] Error 1
make[1]: *** [arch/arm/mach-omap2] Error 2
make[1]: *** Waiting for unfinished jobs....

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

Patch

diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c
index 25535a3..9766d55 100644
--- a/arch/arm/mach-omap2/resource34xx.c
+++ b/arch/arm/mach-omap2/resource34xx.c
@@ -240,13 +240,23 @@  static int program_opp_freq(int res, int target_level, int current_level)
 	lock_scratchpad_sem();
 	if (res == VDD1_OPP) {
 		curr_opp = &curr_vdd1_opp;
-		clk_set_rate(dpll1_clk, mpu_opps[target_level].rate);
-		clk_set_rate(dpll2_clk, dsp_opps[target_level].rate);
+		ret = clk_set_rate(dpll1_clk, mpu_opps[target_level].rate);
+		if (unlikely(ret))
+			goto out;
+
+		ret = clk_set_rate(dpll2_clk, dsp_opps[target_level].rate);
+		if (unlikely(ret))
+			/* reset the dpll1 if failed */
+			clk_set_rate(dpll1_clk, mpu_opps[current_level].rate);
 #ifndef CONFIG_CPU_FREQ
-		/*Update loops_per_jiffy if processor speed is being changed*/
-		loops_per_jiffy = compute_lpj(loops_per_jiffy,
-			mpu_opps[current_level].rate/1000,
-			mpu_opps[target_level].rate/1000);
+		else
+			/*
+			 * Update loops_per_jiffy if processor speed
+			 * is being changed
+			 */
+			loops_per_jiffy = compute_lpj(loops_per_jiffy,
+				mpu_opps[current_level].rate/1000,
+				mpu_opps[target_level].rate/1000);
 #endif
 	} else {
 		curr_opp = &curr_vdd2_opp;
@@ -255,17 +265,16 @@  static int program_opp_freq(int res, int target_level, int current_level)
 		ret = clk_set_rate(dpll3_clk,
 				l3_opps[target_level].rate * l3_div);
 	}
-	if (ret) {
-		unlock_scratchpad_sem();
-		return current_level;
-	}
+out:
+	if (!ret) {
 #ifdef CONFIG_PM
-	omap3_save_scratchpad_contents();
+		omap3_save_scratchpad_contents();
 #endif
+		*curr_opp = target_level;
+	}
 	unlock_scratchpad_sem();
 
-	*curr_opp = target_level;
-	return target_level;
+	return ret;
 }
 
 static int program_opp(int res, struct omap_opp *opp, int target_level,
@@ -289,13 +298,35 @@  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, c_opp,
+			ret = sr_voltagescale_vcbypass(t_opp, c_opp,
 				opp[target_level].vsel,
 				opp[current_level].vsel);
+		if (ret) {
+			int ret1 = 0;
+			/*
+			 * If something did not work, put me back to old state.
+			 * Recover the other guy if at least 1 prev iteration
+			 * had run
+			 */
+			if (i && raise)
+				ret1 = sr_voltagescale_vcbypass(c_opp, t_opp,
+					opp[current_level].vsel,
+					opp[target_level].vsel);
+			else if (i)
+				ret1 = program_opp_freq(res, current_level,
+						target_level);
+			/*
+			 * If I could not reset my old state back.. system
+			 * is no longer in a controlled state.. bug me
+			 */
+			if (unlikely(ret1))
+				BUG();
+			break;
+		}
 #endif
 	}
 
-	return ret;
+	return (res == PRCM_VDD1) ?  curr_vdd1_opp : curr_vdd2_opp;
 }
 
 int resource_set_opp_level(int res, u32 target_level, int flags)