From: Yakir Yang Date: Sat, 16 Jul 2016 08:44:26 +0000 (+0800) Subject: CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Fixup the clock to be what we expect X-Git-Tag: firefly_0821_release~2130 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=329f1b1ff70cca751c88d04e7aa3d4d2c9830e22;p=firefly-linux-kernel-4.4.55.git CHROMIUM: drm: rockchip/dw_hdmi-rockchip: Fixup the clock to be what we expect 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 Signed-off-by: Yakir Yang Reviewed-on: https://chromium-review.googlesource.com/284376 Reviewed-by: Alexandru Stan --- diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 1e500e76e608..f168f4b457b4 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -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,