| From 4bfc497cf1a10b2c08b75afd6efa5702cd7b4e60 Mon Sep 17 00:00:00 2001 |
| From: Douglas Anderson <dianders@chromium.org> |
| Date: Thu, 3 Oct 2019 11:47:30 -0700 |
| Subject: [PATCH] drm/rockchip: Round up _before_ giving to the clock framework |
| |
| commit 287422a95fe28e05c1952de0472e0dfdffa6caae upstream. |
| |
| I'm embarassed to say that even though I've touched |
| vop_crtc_mode_fixup() twice and I swear I tested it, there's still a |
| stupid glaring bug in it. Specifically, on veyron_minnie (with all |
| the latest display timings) we want to be setting our pixel clock to |
| 66,666,666.67 Hz and we tell userspace that's what we set, but we're |
| actually choosing 66,000,000 Hz. This is confirmed by looking at the |
| clock tree. |
| |
| The problem is that in drm_display_mode_from_videomode() we convert |
| from Hz to kHz with: |
| |
| dmode->clock = vm->pixelclock / 1000; |
| |
| ...and drm_display_mode_from_videomode() is called from panel-simple |
| when we have an "override_mode" like we do on veyron_minnie. See |
| commit 123643e5c40a ("ARM: dts: rockchip: Specify |
| rk3288-veyron-minnie's display timings"). |
| |
| ...so when the device tree specifies a clock of 66666667 for the panel |
| then DRM translates that to 66666000. The clock framework will always |
| pick a clock that is _lower_ than the one requested, so it will refuse |
| to pick 66666667 and we'll end up at 66000000. |
| |
| While we could try to fix drm_display_mode_from_videomode() to round |
| to the nearest kHz and it would fix our problem, it wouldn't help if |
| the clock we actually needed was 60,000,001 Hz. We could |
| alternatively have DRM always round up, but maybe this would break |
| someone else who already baked in the assumption that DRM rounds down. |
| Specifically note that clock drivers are not consistent about whether |
| they round up or round down when you call clk_set_rate(). We know how |
| Rockchip's clock driver works, but (for instance) you can see that on |
| most Qualcomm clocks the default is clk_rcg2_ops which rounds up. |
| |
| Let's solve this by just adding 999 Hz before calling |
| clk_round_rate(). This should be safe and work everywhere. As |
| discussed in more detail in comments in the commit, Rockchip's PLLs |
| are configured in a way that there shouldn't be another PLL setting |
| that is only a few kHz off so we won't get mixed up. |
| |
| NOTE: if this is picked to stable, it's probably easiest to first pick |
| commit 527e4ca3b6d1 ("drm/rockchip: Base adjustments of the mode based |
| on prev adjustments") which shouldn't hurt in stable. |
| |
| Fixes: b59b8de31497 ("drm/rockchip: return a true clock rate to adjusted_mode") |
| Signed-off-by: Douglas Anderson <dianders@chromium.org> |
| Reviewed-by: Sean Paul <seanpaul@chromium.org> |
| Signed-off-by: Sean Paul <seanpaul@chromium.org> |
| Link: https://patchwork.freedesktop.org/patch/msgid/20191003114726.v2.1.Ib233b3e706cf6317858384264d5b0ed35657456e@changeid |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c |
| index 46d933d80ba7..f66bdfce1a62 100644 |
| --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c |
| +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c |
| @@ -1009,10 +1009,41 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, |
| struct drm_display_mode *adjusted_mode) |
| { |
| struct vop *vop = to_vop(crtc); |
| + unsigned long rate; |
| |
| - adjusted_mode->clock = |
| - DIV_ROUND_UP(clk_round_rate(vop->dclk, |
| - adjusted_mode->clock * 1000), 1000); |
| + /* |
| + * Clock craziness. |
| + * |
| + * Key points: |
| + * |
| + * - DRM works in in kHz. |
| + * - Clock framework works in Hz. |
| + * - Rockchip's clock driver picks the clock rate that is the |
| + * same _OR LOWER_ than the one requested. |
| + * |
| + * Action plan: |
| + * |
| + * 1. When DRM gives us a mode, we should add 999 Hz to it. That way |
| + * if the clock we need is 60000001 Hz (~60 MHz) and DRM tells us to |
| + * make 60000 kHz then the clock framework will actually give us |
| + * the right clock. |
| + * |
| + * NOTE: if the PLL (maybe through a divider) could actually make |
| + * a clock rate 999 Hz higher instead of the one we want then this |
| + * could be a problem. Unfortunately there's not much we can do |
| + * since it's baked into DRM to use kHz. It shouldn't matter in |
| + * practice since Rockchip PLLs are controlled by tables and |
| + * even if there is a divider in the middle I wouldn't expect PLL |
| + * rates in the table that are just a few kHz different. |
| + * |
| + * 2. Get the clock framework to round the rate for us to tell us |
| + * what it will actually make. |
| + * |
| + * 3. Store the rounded up rate so that we don't need to worry about |
| + * this in the actual clk_set_rate(). |
| + */ |
| + rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000 + 999); |
| + adjusted_mode->clock = DIV_ROUND_UP(rate, 1000); |
| |
| return true; |
| } |
| -- |
| 2.7.4 |
| |