diff options
author | Fancy Fang <chen.fang@nxp.com> | 2020-11-16 15:27:55 +0800 |
---|---|---|
committer | Fancy Fang <chen.fang@nxp.com> | 2020-11-19 13:51:02 +0800 |
commit | d7e6489482b8342d593d1158cbd06419aa7b4b1b (patch) | |
tree | 04ba9b7da3e3dafa4828e02dd1fb1920c283d058 | |
parent | 76bc28934e53a86ec13875674893a85d7dcac87f (diff) |
MLK-24998-7 drm/imx: lcdifv3: implement mode_valid() for CRTC
Add mode_valid() implementation for CRTC to filter out any
mode which cannot be supported by LCDIFv3. Only check the
CEA and DMT modes for pixel clock round rate is same with
the value from mode.
Signed-off-by: Fancy Fang <chen.fang@nxp.com>
Reviewed-by: Liu Ying <victor.liu@nxp.com>
(cherry picked from commit f252a44da9f90951614c0bf513df6bd4d145e76e)
-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 |