CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Fixup the clock to be what we expect
authorYakir Yang <ykk@rock-chips.com>
Sat, 16 Jul 2016 08:44:26 +0000 (16:44 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 19 Jul 2016 07:23:31 +0000 (15:23 +0800)
We allow some amount of slop in dw_hdmi_rockchip_mode_valid().  That's
a good thing since allowing a little bit of slop lets us support a
bunch of extra resolutions.

Originally, we also made a change to the VOP code to add the concept
of slop in there.  That was reasonable, but there was a problem: it
would tend to request clock rates that weren't _exactly_ clock rates
that we thought about.  It's possible that the common clock framework
would map these to PLL rates that we haven't thought about and we
haven't tested for jitter.

Instead of changing VOP, we should probably adjust the clock ourselves
in the mode_fixup function.  That way we'll request the exact clock we
tested and we'll know how the common clock framework will map it.

Change-Id: I56c2b046f76d554aab5eaed7a6b171ea074d6a62
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Yakir Yang <ykk@rock-chips.com>
Reviewed-on: https://chromium-review.googlesource.com/284376
Reviewed-by: Alexandru Stan <amstan@chromium.org>
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c

index 1e500e76e60836dc4df473f820bae25fc313f077..f168f4b457b4dd9ae61aba35188ded884bddb4ab 100644 (file)
@@ -275,7 +275,39 @@ dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
                                    const struct drm_display_mode *mode,
                                    struct drm_display_mode *adj_mode)
 {
-       return true;
+       struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+       int pclk = adj_mode->clock * 1000;
+       int best_diff = INT_MAX;
+       int best_clock = 0;
+       int slop;
+       int i;
+
+       /* Pick the best clock */
+       for (i = 0; i < ARRAY_SIZE(dw_hdmi_rates); i++) {
+               int diff = dw_hdmi_rates[i] - pclk;
+
+               if (diff < 0)
+                       diff = -diff;
+               if (diff < best_diff) {
+                       best_diff = diff;
+                       best_clock = dw_hdmi_rates[i];
+
+                       /* Bail early if we're exact */
+                       if (best_diff == 0)
+                               return true;
+               }
+       }
+
+       /* Double check that it's OK */
+       slop = CLK_SLOP(pclk);
+       if ((pclk >= best_clock - slop) && (pclk <= best_clock + slop)) {
+               adj_mode->clock = DIV_ROUND_UP(best_clock, 1000);
+               return true;
+       }
+
+       /* Shoudn't be here; we should have said rate wasn't valid */
+       dev_warn(hdmi->dev, "tried to set invalid rate %d\n", adj_mode->clock);
+       return false;
 }
 
 static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,