@@ -258,42 +258,53 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
escr = ESCR_DCLKSEL_DCLKIN | div;
} else {
- unsigned long clk;
+ unsigned long dotclkin_rate;
+ struct clk *dotclkin_clk;
+ unsigned long cpg_dist;
u32 div;
/*
* Compute the clock divisor and select the internal or external
* dot clock based on the requested frequency.
*/
- clk = clk_get_rate(rcrtc->clock);
- div = DIV_ROUND_CLOSEST(clk, mode_clock);
- div = clamp(div, 1U, 64U) - 1;
-
+ dotclkin_clk = rcrtc->clock;
+ dotclkin_rate = clk_get_rate(rcrtc->clock);
+ div = clamp(DIV_ROUND_CLOSEST(dotclkin_rate, mode_clock),
+ 1UL, 64UL) - 1;
+ cpg_dist = abs(dotclkin_rate / (div + 1) - mode_clock);
escr = ESCR_DCLKSEL_CLKS | div;
if (rcrtc->extclock) {
- unsigned long extclk;
- unsigned long extrate;
- unsigned long rate;
- u32 extdiv;
-
- extclk = clk_get_rate(rcrtc->extclock);
- extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
- extdiv = clamp(extdiv, 1U, 64U) - 1;
+ unsigned long ext_rate;
+ unsigned long ext_dist;
- extrate = extclk / (extdiv + 1);
- rate = clk / (div + 1);
+ /*
+ * If an external clock source is present ask it
+ * for the exact dot clock rate, and test the
+ * returned value against the cpg provided one.
+ */
+ ext_rate = clk_round_rate(rcrtc->extclock,
+ mode_clock);
- if (abs((long)extrate - (long)mode_clock) <
- abs((long)rate - (long)mode_clock))
- escr = ESCR_DCLKSEL_DCLKIN | extdiv;
+ div = clamp(DIV_ROUND_CLOSEST(ext_rate, mode_clock),
+ 1UL, 64UL) - 1;
+ ext_dist = abs(ext_rate / (div + 1) - mode_clock);
- dev_dbg(rcrtc->group->dev->dev,
- "mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n",
- mode_clock, extrate, rate, escr);
+ if (ext_dist < cpg_dist) {
+ dotclkin_clk = rcrtc->extclock;
+ dotclkin_rate = ext_rate;
+ escr = ESCR_DCLKSEL_DCLKIN | div;
+ }
}
+
+ dev_dbg(rcrtc->group->dev->dev, "mode clock %lu %s rate %lu\n",
+ mode_clock, dotclkin_clk == rcrtc->clock ? "cpg" : "ext",
+ dotclkin_rate);
+ clk_set_rate(dotclkin_clk, dotclkin_rate);
}
+ dev_dbg(rcrtc->group->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
+
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
escr);
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);