summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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