diff options
-rw-r--r-- | drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c | 32 | ||||
-rw-r--r-- | drivers/gpu/imx/lcdifv3/lcdifv3-common.c | 10 | ||||
-rw-r--r-- | include/video/imx-lcdifv3.h | 2 |
3 files changed, 44 insertions, 0 deletions
diff --git a/drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c b/drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c index 6e77ff9357be..0716a317296b 100644 --- a/drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c +++ b/drivers/gpu/drm/imx/lcdifv3/lcdifv3-crtc.c @@ -192,12 +192,44 @@ static void lcdifv3_crtc_atomic_disable(struct drm_crtc *crtc, pm_runtime_put(lcdifv3_crtc->dev->parent); } +static enum drm_mode_status lcdifv3_crtc_mode_valid(struct drm_crtc * crtc, + const struct drm_display_mode *mode) +{ + u8 vic; + long rate; + const struct drm_display_mode *dmt; + struct lcdifv3_crtc *lcdifv3_crtc = to_lcdifv3_crtc(crtc); + struct lcdifv3_soc *lcdifv3 = dev_get_drvdata(lcdifv3_crtc->dev->parent); + + /* check CEA-861 mode */ + vic = drm_match_cea_mode(mode); + if (vic) + goto check_pix_clk; + + /* check DMT mode */ + dmt = drm_mode_find_dmt(crtc->dev, mode->hdisplay, mode->vdisplay, + drm_mode_vrefresh(mode), false); + if (dmt && drm_mode_equal(mode, dmt)) + goto check_pix_clk; + + return MODE_OK; + +check_pix_clk: + rate = lcdifv3_pix_clk_round_rate(lcdifv3, mode->clock * 1000); + + if (rate <= 0 || rate != mode->clock * 1000) + return MODE_BAD; + + return MODE_OK; +} + static const struct drm_crtc_helper_funcs lcdifv3_helper_funcs = { .atomic_check = lcdifv3_crtc_atomic_check, .atomic_begin = lcdifv3_crtc_atomic_begin, .atomic_flush = lcdifv3_crtc_atomic_flush, .atomic_enable = lcdifv3_crtc_atomic_enable, .atomic_disable = lcdifv3_crtc_atomic_disable, + .mode_valid = lcdifv3_crtc_mode_valid, }; static int lcdifv3_enable_vblank(struct drm_crtc *crtc) diff --git a/drivers/gpu/imx/lcdifv3/lcdifv3-common.c b/drivers/gpu/imx/lcdifv3/lcdifv3-common.c index e56b6be9bd24..fa12cc78c550 100644 --- a/drivers/gpu/imx/lcdifv3/lcdifv3-common.c +++ b/drivers/gpu/imx/lcdifv3/lcdifv3-common.c @@ -512,6 +512,16 @@ void lcdifv3_disable_controller(struct lcdifv3_soc *lcdifv3) } EXPORT_SYMBOL(lcdifv3_disable_controller); +long lcdifv3_pix_clk_round_rate(struct lcdifv3_soc *lcdifv3, + unsigned long rate) +{ + if (unlikely(!rate)) + return -EINVAL; + + return clk_round_rate(lcdifv3->clk_pix, rate); +} +EXPORT_SYMBOL(lcdifv3_pix_clk_round_rate); + static int hdmimix_lcdif3_setup(struct lcdifv3_soc *lcdifv3) { struct device *dev = lcdifv3->dev; diff --git a/include/video/imx-lcdifv3.h b/include/video/imx-lcdifv3.h index e8556bea7aed..f201edfe46f9 100644 --- a/include/video/imx-lcdifv3.h +++ b/include/video/imx-lcdifv3.h @@ -30,5 +30,7 @@ void lcdifv3_en_shadow_load(struct lcdifv3_soc *lcdifv3); void lcdifv3_enable_controller(struct lcdifv3_soc *lcdifv3); void lcdifv3_disable_controller(struct lcdifv3_soc *lcdifv3); void lcdifv3_dump_registers(struct lcdifv3_soc *lcdifv3); +long lcdifv3_pix_clk_round_rate(struct lcdifv3_soc *lcdifv3, + unsigned long rate); #endif |