summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFancy Fang <chen.fang@nxp.com>2020-11-16 15:27:55 +0800
committerFancy Fang <chen.fang@nxp.com>2020-11-19 13:51:02 +0800
commitd7e6489482b8342d593d1158cbd06419aa7b4b1b (patch)
tree04ba9b7da3e3dafa4828e02dd1fb1920c283d058
parent76bc28934e53a86ec13875674893a85d7dcac87f (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.c32
-rw-r--r--drivers/gpu/imx/lcdifv3/lcdifv3-common.c10
-rw-r--r--include/video/imx-lcdifv3.h2
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