瀏覽代碼

Merge tag 'for-v3.17/omap-clock-b' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into omap-for-v3.17/soc

Modify OMAP PLL rate rounding function to round to the exact rate requested
or the next one below it.  This is intended to resolve some DSS problems.

Basic build, boot, and PM test results are available here:

http://www.pwsan.com/omap/testlogs/clock-b-v3.17/20140725061121/
Tony Lindgren 11 年之前
父節點
當前提交
d40dbcd57b
共有 2 個文件被更改,包括 32 次插入9 次删除
  1. 21 7
      arch/arm/mach-omap2/clkt_dpll.c
  2. 11 2
      arch/arm/mach-omap2/dpll3xxx.c

+ 21 - 7
arch/arm/mach-omap2/clkt_dpll.c

@@ -285,10 +285,13 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 {
 {
 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 	int m, n, r, scaled_max_m;
 	int m, n, r, scaled_max_m;
+	int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
 	unsigned long scaled_rt_rp;
 	unsigned long scaled_rt_rp;
 	unsigned long new_rate = 0;
 	unsigned long new_rate = 0;
 	struct dpll_data *dd;
 	struct dpll_data *dd;
 	unsigned long ref_rate;
 	unsigned long ref_rate;
+	long delta;
+	long prev_min_delta = LONG_MAX;
 	const char *clk_name;
 	const char *clk_name;
 
 
 	if (!clk || !clk->dpll_data)
 	if (!clk || !clk->dpll_data)
@@ -334,23 +337,34 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 		if (r == DPLL_MULT_UNDERFLOW)
 		if (r == DPLL_MULT_UNDERFLOW)
 			continue;
 			continue;
 
 
+		/* skip rates above our target rate */
+		delta = target_rate - new_rate;
+		if (delta < 0)
+			continue;
+
+		if (delta < prev_min_delta) {
+			prev_min_delta = delta;
+			min_delta_m = m;
+			min_delta_n = n;
+		}
+
 		pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
 		pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
 			 clk_name, m, n, new_rate);
 			 clk_name, m, n, new_rate);
 
 
-		if (target_rate == new_rate) {
-			dd->last_rounded_m = m;
-			dd->last_rounded_n = n;
-			dd->last_rounded_rate = target_rate;
+		if (delta == 0)
 			break;
 			break;
-		}
 	}
 	}
 
 
-	if (target_rate != new_rate) {
+	if (prev_min_delta == LONG_MAX) {
 		pr_debug("clock: %s: cannot round to rate %lu\n",
 		pr_debug("clock: %s: cannot round to rate %lu\n",
 			 clk_name, target_rate);
 			 clk_name, target_rate);
 		return ~0;
 		return ~0;
 	}
 	}
 
 
-	return target_rate;
+	dd->last_rounded_m = min_delta_m;
+	dd->last_rounded_n = min_delta_n;
+	dd->last_rounded_rate = target_rate - prev_min_delta;
+
+	return dd->last_rounded_rate;
 }
 }
 
 

+ 11 - 2
arch/arm/mach-omap2/dpll3xxx.c

@@ -475,6 +475,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
 {
 {
 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
 	struct clk *new_parent = NULL;
 	struct clk *new_parent = NULL;
+	unsigned long rrate;
 	u16 freqsel = 0;
 	u16 freqsel = 0;
 	struct dpll_data *dd;
 	struct dpll_data *dd;
 	int ret;
 	int ret;
@@ -502,8 +503,16 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
 		__clk_prepare(dd->clk_ref);
 		__clk_prepare(dd->clk_ref);
 		clk_enable(dd->clk_ref);
 		clk_enable(dd->clk_ref);
 
 
-		if (dd->last_rounded_rate != rate)
-			rate = __clk_round_rate(hw->clk, rate);
+		/* XXX this check is probably pointless in the CCF context */
+		if (dd->last_rounded_rate != rate) {
+			rrate = __clk_round_rate(hw->clk, rate);
+			if (rrate != rate) {
+				pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
+					__func__, __clk_get_name(hw->clk),
+					rrate, rate);
+				rate = rrate;
+			}
+		}
 
 
 		if (dd->last_rounded_rate == 0)
 		if (dd->last_rounded_rate == 0)
 			return -EINVAL;
 			return -EINVAL;