diff options
-rw-r--r-- | drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c index 3bc4d011b4c6..114d883c65dc 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c @@ -915,6 +915,28 @@ static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } +static long cdns_dsi_round_pclk(struct cdns_dsi *dsi, unsigned long pclk) +{ + struct cdns_dsi_output *output = &dsi->output; + unsigned int nlanes = output->dev->lanes; + union phy_configure_opts phy_opts = { 0 }; + u32 bitspp; + int ret; + + bitspp = mipi_dsi_pixel_format_to_bpp(output->dev->format); + + ret = phy_mipi_dphy_get_default_config(pclk, bitspp, nlanes, + &phy_opts.mipi_dphy); + if (ret) + return ret; + + ret = phy_validate(dsi->dphy, PHY_MODE_MIPI_DPHY, 0, &phy_opts); + if (ret) + return ret; + + return div_u64((u64)phy_opts.mipi_dphy.hs_clk_rate * nlanes, bitspp); +} + static int cdns_dsi_bridge_atomic_check(struct drm_bridge *bridge, struct drm_bridge_state *bridge_state, struct drm_crtc_state *crtc_state, @@ -926,11 +948,26 @@ static int cdns_dsi_bridge_atomic_check(struct drm_bridge *bridge, struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; struct cdns_dsi_cfg *dsi_cfg = &dsi_state->dsi_cfg; struct videomode vm; + long pclk; /* cdns-dsi requires negative syncs */ adjusted_mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC; + /* + * The DPHY PLL has quite a coarsely grained clock rate options. See + * what hsclk rate we can achieve based on the pixel clock, convert it + * back to pixel clock, set that to the adjusted_mode->clock. This is + * all in hopes that the CRTC will be able to provide us the requested + * clock, as otherwise the DPI and DSI clocks will be out of sync. + */ + + pclk = cdns_dsi_round_pclk(dsi, adjusted_mode->clock * 1000); + if (pclk < 0) + return (int)pclk; + + adjusted_mode->clock = pclk / 1000; + drm_display_mode_to_videomode(adjusted_mode, &vm); return cdns_dsi_check_conf(dsi, &vm, dsi_cfg); |