[PATCH] drm/meson: Add support for DMT modes on HDMI

From: Neil Armstrong
Date: Thu Mar 08 2018 - 14:56:16 EST


This patch adds support for DMT display modes over HDMI.
The modes timings configurations are from the Amlogic Vendor linux tree
and tested over multiples monitors.
Previously only a selected number of CEA modes were supported.

Only these following modes are supported with these changes:
- 640x480@60Hz
- 800x600@60Hz
- 1024x768@60Hz
- 1152x864@75Hz
- 1280x1024@60Hz
- 1600x1200@60Hz
- 1920x1080@60Hz

The associated code to handle the clock rates is also added.

Signed-off-by: Neil Armstrong <narmstrong@xxxxxxxxxxxx>
---
drivers/gpu/drm/meson/meson_dw_hdmi.c | 21 +-
drivers/gpu/drm/meson/meson_vclk.c | 219 ++++++++++++++++++++-
drivers/gpu/drm/meson/meson_venc.c | 347 +++++++++++++++++++++++++++++++++-
drivers/gpu/drm/meson/meson_venc.h | 1 +
4 files changed, 570 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 17de3af..fd1d365 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -554,12 +554,12 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
mode->vdisplay, mode->vsync_start,
mode->vsync_end, mode->vtotal, mode->type, mode->flags);

- /* For now, only accept VIC modes */
- if (!vic)
- return MODE_BAD;
-
- /* For now, filter by supported VIC modes */
- if (!meson_venc_hdmi_supported_vic(vic))
+ /* Check against non-VIC supported modes */
+ if (!vic) {
+ if (!meson_venc_hdmi_supported_mode(mode))
+ return MODE_BAD;
+ /* Check against supported VIC modes */
+ } else if (meson_venc_hdmi_supported_vic(vic))
return MODE_BAD;

vclk_freq = mode->clock;
@@ -585,9 +585,14 @@ dw_hdmi_mode_valid(struct drm_connector *connector,

/* Finally filter by configurable vclk frequencies */
switch (vclk_freq) {
+ case 25175:
+ case 40000:
case 54000:
+ case 65000:
case 74250:
+ case 108000:
case 148500:
+ case 162000:
case 297000:
case 594000:
return MODE_OK;
@@ -652,10 +657,6 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
mode->base.id, mode->name, vic);

- /* Should have been filtered */
- if (!vic)
- return;
-
/* VENC + VENC-DVI Mode setup */
meson_venc_hdmi_mode_set(priv, vic, mode);

diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index 4767704..f051122 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -328,14 +328,24 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
#define MESON_VCLK_HDMI_DDR_54000 2
/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
#define MESON_VCLK_HDMI_DDR_148500 3
+/* 4028 /4 /4 /1 /5 /2 => /1 /1 */
+#define MESON_VCLK_HDMI_25175 4
+/* 3200 /4 /2 /1 /5 /2 => /1 /1 */
+#define MESON_VCLK_HDMI_40000 5
+/* 5200 /4 /2 /1 /5 /2 => /1 /1 */
+#define MESON_VCLK_HDMI_65000 6
/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
-#define MESON_VCLK_HDMI_74250 4
+#define MESON_VCLK_HDMI_74250 7
+/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
+#define MESON_VCLK_HDMI_108000 8
/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
-#define MESON_VCLK_HDMI_148500 5
+#define MESON_VCLK_HDMI_148500 9
+/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
+#define MESON_VCLK_HDMI_162000 10
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_297000 6
+#define MESON_VCLK_HDMI_297000 11
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
-#define MESON_VCLK_HDMI_594000 7
+#define MESON_VCLK_HDMI_594000 12

struct meson_vclk_params {
unsigned int pll_base_freq;
@@ -401,6 +411,46 @@ struct meson_vclk_params {
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 1,
},
+ [MESON_VCLK_HDMI_25175] = {
+ .pll_base_freq = 4028000,
+ .pll_od1 = 4,
+ .pll_od2 = 4,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
+ [MESON_VCLK_HDMI_40000] = {
+ .pll_base_freq = 3200000,
+ .pll_od1 = 4,
+ .pll_od2 = 2,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
+ [MESON_VCLK_HDMI_65000] = {
+ .pll_base_freq = 5200000,
+ .pll_od1 = 4,
+ .pll_od2 = 2,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
+ [MESON_VCLK_HDMI_108000] = {
+ .pll_base_freq = 4320000,
+ .pll_od1 = 4,
+ .pll_od2 = 1,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
+ [MESON_VCLK_HDMI_162000] = {
+ .pll_base_freq = 3240000,
+ .pll_od1 = 2,
+ .pll_od2 = 1,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
};

static inline unsigned int pll_od_to_reg(unsigned int od)
@@ -451,6 +501,90 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
0xFFFF, 0x4e00);
break;

+ case 3200000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+ /* unreset */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+ BIT(28), 0);
+
+ /* Poll for lock bit */
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+ val, (val & HDMI_PLL_LOCK), 10, 0);
+
+ /* div_frac */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+ 0xFFFF, 0x4aab);
+ break;
+
+ case 3240000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+ /* unreset */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+ BIT(28), 0);
+
+ /* Poll for lock bit */
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+ val, (val & HDMI_PLL_LOCK), 10, 0);
+
+ /* div_frac */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+ 0xFFFF, 0x4800);
+ break;
+
+ case 3865000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+ /* unreset */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+ BIT(28), 0);
+
+ /* Poll for lock bit */
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+ val, (val & HDMI_PLL_LOCK), 10, 0);
+
+ /* div_frac */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+ 0xFFFF, 0x4855);
+ break;
+
+ case 4028000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+ /* unreset */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+ BIT(28), 0);
+
+ /* Poll for lock bit */
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+ val, (val & HDMI_PLL_LOCK), 10, 0);
+
+ /* div_frac */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+ 0xFFFF, 0x4eab);
+ break;
+
case 4320000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
@@ -485,6 +619,23 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
break;
+
+ case 5200000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+ /* unreset */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+ BIT(28), 0);
+
+ /* Poll for lock bit */
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+ val, (val & HDMI_PLL_LOCK), 10, 0);
+ break;
};
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
@@ -498,6 +649,42 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;

+ case 3200000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+ break;
+
+ case 3240000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+ break;
+
+ case 3865000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+ break;
+
+ case 4028000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+ break;
+
case 4320000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
@@ -516,6 +703,15 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;

+ case 5200000:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+ break;
+
};

/* Reset PLL */
@@ -590,15 +786,30 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
else
freq = MESON_VCLK_HDMI_DDR_54000;
break;
+ case 25175:
+ freq = MESON_VCLK_HDMI_25175;
+ break;
+ case 40000:
+ freq = MESON_VCLK_HDMI_40000;
+ break;
+ case 65000:
+ freq = MESON_VCLK_HDMI_65000;
+ break;
case 74250:
freq = MESON_VCLK_HDMI_74250;
break;
+ case 108000:
+ freq = MESON_VCLK_HDMI_108000;
+ break;
case 148500:
if (dac_freq != 148500)
freq = MESON_VCLK_HDMI_DDR_148500;
else
freq = MESON_VCLK_HDMI_148500;
break;
+ case 162000:
+ freq = MESON_VCLK_HDMI_162000;
+ break;
case 297000:
freq = MESON_VCLK_HDMI_297000;
break;
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 9509017..6e27013 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -697,6 +697,314 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
},
};

+union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ /* yfp1_htime */
+ /* yfp2_htime */
+ .max_pxcnt = 0x31f,
+ /* hspuls_begin */
+ /* hspuls_end */
+ /* hspuls_switch */
+ /* vspuls_begin */
+ /* vspuls_end */
+ /* vspuls_bline */
+ /* vspuls_eline */
+ .havon_begin = 0x90,
+ .havon_end = 0x30f,
+ .vavon_bline = 0x23,
+ .vavon_eline = 0x202,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0,
+ .hso_end = 0x60,
+ .vso_begin = 0x1e,
+ .vso_end = 0x32,
+ .vso_bline = 0,
+ .vso_eline = 2,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 0x20c,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ /* yfp1_htime */
+ /* yfp2_htime */
+ .max_pxcnt = 0x41f,
+ /* hspuls_begin */
+ /* hspuls_end */
+ /* hspuls_switch */
+ /* vspuls_begin */
+ /* vspuls_end */
+ /* vspuls_bline */
+ /* vspuls_eline */
+ .havon_begin = 0xD8,
+ .havon_end = 0x3f7,
+ .vavon_bline = 0x1b,
+ .vavon_eline = 0x272,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0,
+ .hso_end = 0x80,
+ .vso_begin = 0x1e,
+ .vso_end = 0x32,
+ .vso_bline = 0,
+ .vso_eline = 4,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 0x273,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ /* yfp1_htime */
+ /* yfp2_htime */
+ .max_pxcnt = 1343,
+ /* hspuls_begin */
+ /* hspuls_end */
+ /* hspuls_switch */
+ /* vspuls_begin */
+ /* vspuls_end */
+ /* vspuls_bline */
+ /* vspuls_eline */
+ .havon_begin = 296,
+ .havon_end = 1319,
+ .vavon_bline = 35,
+ .vavon_eline = 802,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0,
+ .hso_end = 136,
+ .vso_begin = 30,
+ .vso_end = 50,
+ .vso_bline = 0,
+ .vso_eline = 6,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 805,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ /* yfp1_htime */
+ /* yfp2_htime */
+ .max_pxcnt = 0x63f,
+ /* hspuls_begin */
+ /* hspuls_end */
+ /* hspuls_switch */
+ /* vspuls_begin */
+ /* vspuls_end */
+ /* vspuls_bline */
+ /* vspuls_eline */
+ .havon_begin = 0x180,
+ .havon_end = 0x5ff,
+ .vavon_bline = 0x23,
+ .vavon_eline = 0x382,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0,
+ .hso_end = 0x80,
+ .vso_begin = 0x1e,
+ .vso_end = 0x32,
+ .vso_bline = 0,
+ .vso_eline = 3,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 0x383,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ /* yfp1_htime */
+ /* yfp2_htime */
+ .max_pxcnt = 0x697,
+ /* hspuls_begin */
+ /* hspuls_end */
+ /* hspuls_switch */
+ /* vspuls_begin */
+ /* vspuls_end */
+ /* vspuls_bline */
+ /* vspuls_eline */
+ .havon_begin = 0x168,
+ .havon_end = 0x667,
+ .vavon_bline = 0x29,
+ .vavon_eline = 0x428,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0,
+ .hso_end = 0x70,
+ .vso_begin = 0x1e,
+ .vso_end = 0x32,
+ .vso_bline = 0,
+ .vso_eline = 3,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 0x429,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ /* yfp1_htime */
+ /* yfp2_htime */
+ .max_pxcnt = 0x86f,
+ /* hspuls_begin */
+ /* hspuls_end */
+ /* hspuls_switch */
+ /* vspuls_begin */
+ /* vspuls_end */
+ /* vspuls_bline */
+ /* vspuls_eline */
+ .havon_begin = 0x1f0,
+ .havon_end = 0x82f,
+ .vavon_bline = 0x31,
+ .vavon_eline = 0x4e0,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0,
+ .hso_end = 0xc0,
+ .vso_begin = 0x1e,
+ .vso_end = 0x32,
+ .vso_bline = 0,
+ .vso_eline = 3,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 0x4e1,
+ },
+};
+
+struct meson_hdmi_venc_dmt_mode {
+ struct drm_display_mode drm_mode;
+ union meson_hdmi_venc_mode *mode;
+} meson_hdmi_venc_dmt_modes[] = {
+ /* 640x480@60Hz */
+ {
+ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+ 752, 800, 0, 480, 490, 492, 525, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ &meson_hdmi_encp_mode_640x480_60,
+ },
+ /* 800x600@60Hz */
+ {
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+ 968, 1056, 0, 600, 601, 605, 628, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ &meson_hdmi_encp_mode_800x600_60,
+ },
+ /* 1024x768@60Hz */
+ {
+ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024,
+ 1048, 1184, 1344, 0, 768, 771, 777, 806, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ &meson_hdmi_encp_mode_1024x768_60,
+ },
+ /* 1152x864@75Hz */
+ {
+ { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152,
+ 1216, 1344, 1600, 0, 864, 865, 868, 900, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ &meson_hdmi_encp_mode_1152x864_75,
+ },
+ /* 1280x1024@60Hz */
+ {
+ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280,
+ 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ &meson_hdmi_encp_mode_1280x1024_60,
+ },
+ /* 1600x1200@60Hz */
+ {
+ { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
+ 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ &meson_hdmi_encp_mode_1600x1200_60,
+ },
+ /* 1920x1080@60Hz */
+ {
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920,
+ 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ &meson_hdmi_encp_mode_1080p60
+ },
+ { }, /* sentinel */
+};
+
struct meson_hdmi_venc_vic_mode {
unsigned int vic;
union meson_hdmi_venc_mode *mode;
@@ -736,6 +1044,20 @@ static unsigned long modulo(unsigned long a, unsigned long b)
return a;
}

+bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
+{
+ struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
+
+ while (vmode->mode) {
+ if (drm_mode_equal(&vmode->drm_mode, mode))
+ return true;
+ vmode++;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
+
bool meson_venc_hdmi_supported_vic(int vic)
{
struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
@@ -750,6 +1072,20 @@ bool meson_venc_hdmi_supported_vic(int vic)
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);

+static union meson_hdmi_venc_mode
+*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode)
+{
+ struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
+
+ while (vmode->mode) {
+ if (drm_mode_equal(&vmode->drm_mode, mode))
+ return vmode->mode;
+ vmode++;
+ }
+
+ return NULL;
+}
+
static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
{
struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
@@ -811,10 +1147,13 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
unsigned int sof_lines;
unsigned int vsync_lines;

- vmode = meson_venc_hdmi_get_vic_vmode(vic);
+ if (meson_venc_hdmi_supported_vic(vic))
+ vmode = meson_venc_hdmi_get_vic_vmode(vic);
+ else
+ vmode = meson_venc_hdmi_get_dmt_vmode(mode);
if (!vmode) {
- dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n",
- __func__, vic);
+ dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
+ DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode));
return;
}

@@ -864,7 +1203,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
hsync_pixels_venc *= 2;

/* Disable VDACs */
- writel_bits_relaxed(0x1f, 0x1f,
+ writel_bits_relaxed(0xff, 0xff,
priv->io_base + _REG(VENC_VDAC_SETTING));

writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
index a1b96e8..7c18a36 100644
--- a/drivers/gpu/drm/meson/meson_venc.h
+++ b/drivers/gpu/drm/meson/meson_venc.h
@@ -58,6 +58,7 @@ struct meson_cvbs_enci_mode {
};

/* HDMI Clock parameters */
+bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
bool meson_venc_hdmi_supported_vic(int vic);
bool meson_venc_hdmi_venc_repeat(int vic);

--
2.7.4