From 329f1b1ff70cca751c88d04e7aa3d4d2c9830e22 Mon Sep 17 00:00:00 2001 From: Yakir Yang Date: Sat, 16 Jul 2016 16:44:26 +0800 Subject: [PATCH] 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 --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 34 ++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) 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, -- 2.34.1