diff options
Diffstat (limited to 'testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch')
-rw-r--r-- | testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch | 1314 |
1 files changed, 1314 insertions, 0 deletions
diff --git a/testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch b/testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch new file mode 100644 index 0000000000..7625f11f5b --- /dev/null +++ b/testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch @@ -0,0 +1,1314 @@ +From 8ea8dd0432a9964e3e2642433d942c3aa9116fd3 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong <narmstrong@baylibre.com> +Date: Fri, 27 Apr 2018 17:19:46 +0200 +Subject: [PATCH] drm/meson: Make DMT timings parameters and pixel clock + generic + +Remove the modes timings tables for DMT modes and calculate the HW +paremeters from the modes timings. + +Switch the DMT modes pixel clock calculation out of the static frequency +list to a generic calculation from a range of possible PLL dividers. + +This setup permits setting non-CEA modes like : +- 1600x900-60Hz +- 1280x1024-75Hz +- 1280x1024-60Hz +- 1440x900-60Hz +- 1366x768-60Hz +- 1280x800-60Hz +- 1152x864-75Hz +- 1024x768-75Hz +- 1024x768-70Hz +- 1024x768-60Hz +- 832x624-75Hz +- 800x600-75Hz +- 800x600-72Hz +- 800x600-60Hz +- 640x480-75Hz +- 640x480-73Hz +- 640x480-67Hz + +Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 22 +- + drivers/gpu/drm/meson/meson_vclk.c | 658 +++++++++++++++------------------- + drivers/gpu/drm/meson/meson_vclk.h | 4 + + drivers/gpu/drm/meson/meson_venc.c | 379 +++----------------- + drivers/gpu/drm/meson/meson_venc.h | 3 +- + 5 files changed, 352 insertions(+), 714 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index c9ad456..df7247c 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -329,6 +329,12 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + + vclk_freq = mode->clock; + ++ if (!vic) { ++ meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq, ++ vclk_freq, vclk_freq, false); ++ return; ++ } ++ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + vclk_freq *= 2; + +@@ -542,10 +548,12 @@ static enum drm_mode_status + dw_hdmi_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) + { ++ struct meson_drm *priv = connector->dev->dev_private; + unsigned int vclk_freq; + unsigned int venc_freq; + unsigned int hdmi_freq; + int vic = drm_match_cea_mode(mode); ++ enum drm_mode_status status; + + DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", + mode->base.id, mode->name, mode->vrefresh, mode->clock, +@@ -556,8 +564,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + + /* Check against non-VIC supported modes */ + if (!vic) { +- if (!meson_venc_hdmi_supported_mode(mode)) +- return MODE_BAD; ++ status = meson_venc_hdmi_supported_mode(mode); ++ if (status != MODE_OK) ++ return status; ++ ++ return meson_vclk_dmt_supported_freq(priv, mode->clock); + /* Check against supported VIC modes */ + } else if (!meson_venc_hdmi_supported_vic(vic)) + return MODE_BAD; +@@ -583,16 +594,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, + vclk_freq, venc_freq, hdmi_freq); + +- /* Finally filter by configurable vclk frequencies */ ++ /* Finally filter by configurable vclk frequencies for VIC modes */ + 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; +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index f051122..0b17788 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -320,32 +320,23 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) + CTS_VDAC_EN, CTS_VDAC_EN); + } + +- ++enum { + /* PLL O1 O2 O3 VP DV EN TX */ + /* 4320 /4 /4 /1 /5 /1 => /2 /2 */ +-#define MESON_VCLK_HDMI_ENCI_54000 1 ++ MESON_VCLK_HDMI_ENCI_54000 = 1, + /* 4320 /4 /4 /1 /5 /1 => /1 /2 */ +-#define MESON_VCLK_HDMI_DDR_54000 2 ++ MESON_VCLK_HDMI_DDR_54000, + /* 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 ++ MESON_VCLK_HDMI_DDR_148500, + /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ +-#define MESON_VCLK_HDMI_74250 7 +-/* 4320 /4 /1 /1 /5 /2 => /1 /1 */ +-#define MESON_VCLK_HDMI_108000 8 ++ MESON_VCLK_HDMI_74250, + /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ +-#define MESON_VCLK_HDMI_148500 9 +-/* 3240 /2 /1 /1 /5 /2 => /1 /1 */ +-#define MESON_VCLK_HDMI_162000 10 ++ MESON_VCLK_HDMI_148500, + /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ +-#define MESON_VCLK_HDMI_297000 11 ++ MESON_VCLK_HDMI_297000, + /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ +-#define MESON_VCLK_HDMI_594000 12 ++ MESON_VCLK_HDMI_594000 ++}; + + struct meson_vclk_params { + unsigned int pll_base_freq; +@@ -411,46 +402,6 @@ 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) +@@ -470,358 +421,217 @@ static inline unsigned int pll_od_to_reg(unsigned int od) + return 0; + } + +-void meson_hdmi_pll_set(struct meson_drm *priv, +- unsigned int base, +- unsigned int od1, +- unsigned int od2, +- unsigned int od3) ++void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, ++ unsigned int frac, unsigned int od1, ++ unsigned int od2, unsigned int od3) + { + unsigned int val; + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { +- switch (base) { +- case 2970000: +- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); +- 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); +- +- /* Enable and unreset */ +- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, +- 0x7 << 28, 0x4 << 28); +- +- /* 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, 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); +- 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); +- break; ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m); ++ if (frac) ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, ++ 0x00004000 | frac); ++ else ++ 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); + +- case 5940000: +- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b); +- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, +- 0xFFFF, 0x4c00); +- 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; ++ /* Enable and unreset */ ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ 0x7 << 28, 0x4 << 28); + +- 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; +- }; ++ /* Poll for lock bit */ ++ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, ++ val, (val & HDMI_PLL_LOCK), 10, 0); + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { +- switch (base) { +- case 2970000: +- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); +- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); +- 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 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); +- 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 5940000: +- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7); +- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200); +- 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 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; +- +- }; ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac); ++ 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); + + /* Reset PLL */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, +- HDMI_PLL_RESET, HDMI_PLL_RESET); ++ HDMI_PLL_RESET, HDMI_PLL_RESET); + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, +- HDMI_PLL_RESET, 0); ++ HDMI_PLL_RESET, 0); + + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, + (val & HDMI_PLL_LOCK), 10, 0); +- }; ++ } + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, +- 3 << 16, pll_od_to_reg(od1) << 16); ++ 3 << 16, pll_od_to_reg(od1) << 16); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, +- 3 << 21, pll_od_to_reg(od1) << 21); ++ 3 << 21, pll_od_to_reg(od1) << 21); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, +- 3 << 22, pll_od_to_reg(od2) << 22); ++ 3 << 22, pll_od_to_reg(od2) << 22); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, +- 3 << 23, pll_od_to_reg(od2) << 23); ++ 3 << 23, pll_od_to_reg(od2) << 23); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, +- 3 << 18, pll_od_to_reg(od3) << 18); ++ 3 << 18, pll_od_to_reg(od3) << 18); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, +- 3 << 19, pll_od_to_reg(od3) << 19); ++ 3 << 19, pll_od_to_reg(od3) << 19); ++ + } + +-void meson_vclk_setup(struct meson_drm *priv, unsigned int target, +- unsigned int vclk_freq, unsigned int venc_freq, +- unsigned int dac_freq, bool hdmi_use_enci) ++#define XTAL_FREQ 24000 ++ ++static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, ++ unsigned int pll_freq) + { +- unsigned int freq; +- unsigned int hdmi_tx_div; +- unsigned int venc_div; ++ /* The GXBB PLL has a /2 pre-multiplier */ ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) ++ pll_freq /= 2; + +- if (target == MESON_VCLK_TARGET_CVBS) { +- meson_venci_cvbs_clock_config(priv); +- return; ++ return pll_freq / XTAL_FREQ; ++} ++ ++#define HDMI_FRAC_MAX_GXBB 4096 ++#define HDMI_FRAC_MAX_GXL 1024 ++ ++static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, ++ unsigned int m, ++ unsigned int pll_freq) ++{ ++ unsigned int parent_freq = XTAL_FREQ; ++ unsigned int frac_max = HDMI_FRAC_MAX_GXL; ++ unsigned int frac_m; ++ unsigned int frac; ++ ++ /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */ ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { ++ frac_max = HDMI_FRAC_MAX_GXBB; ++ parent_freq *= 2; + } + +- hdmi_tx_div = vclk_freq / dac_freq; ++ /* We can have a perfect match !*/ ++ if (pll_freq / m == parent_freq && ++ pll_freq % m == 0) ++ return 0; + +- if (hdmi_tx_div == 0) { +- pr_err("Fatal Error, invalid HDMI-TX freq %d\n", +- dac_freq); +- return; ++ frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq); ++ frac_m = m * frac_max; ++ if (frac_m > frac) ++ return frac_max; ++ frac -= frac_m; ++ ++ return min((u16)frac, (u16)(frac_max - 1)); ++} ++ ++static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, ++ unsigned int m, ++ unsigned int frac) ++{ ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { ++ /* Empiric supported min/max dividers */ ++ if (m < 53 || m > 123) ++ return false; ++ if (frac >= HDMI_FRAC_MAX_GXBB) ++ return false; ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { ++ /* Empiric supported min/max dividers */ ++ if (m < 106 || m > 247) ++ return false; ++ if (frac >= HDMI_FRAC_MAX_GXL) ++ return false; + } + +- venc_div = vclk_freq / venc_freq; ++ return true; ++} + +- if (venc_div == 0) { +- pr_err("Fatal Error, invalid HDMI venc freq %d\n", +- venc_freq); +- return; ++static bool meson_hdmi_pll_find_params(struct meson_drm *priv, ++ unsigned int freq, ++ unsigned int *m, ++ unsigned int *frac, ++ unsigned int *od) ++{ ++ /* Cycle from /16 to /2 */ ++ for (*od = 16 ; *od > 1 ; *od >>= 1) { ++ *m = meson_hdmi_pll_get_m(priv, freq * *od); ++ if (!*m) ++ continue; ++ *frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od); ++ ++ DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d\n", ++ freq, *m, *frac, *od); ++ ++ if (meson_hdmi_pll_validate_params(priv, *m, *frac)) ++ return true; + } + +- switch (vclk_freq) { +- case 54000: +- if (hdmi_use_enci) +- freq = MESON_VCLK_HDMI_ENCI_54000; +- 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; +- case 594000: +- freq = MESON_VCLK_HDMI_594000; +- break; +- default: +- pr_err("Fatal Error, invalid HDMI vclk freq %d\n", +- vclk_freq); ++ return false; ++} ++ ++/* pll_freq is the frequency after the OD dividers */ ++enum drm_mode_status ++meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq) ++{ ++ unsigned int od, m, frac; ++ ++ /* In DMT mode, path after PLL is always /10 */ ++ freq *= 10; ++ ++ if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od)) ++ return MODE_OK; ++ ++ return MODE_CLOCK_RANGE; ++} ++EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq); ++ ++/* pll_freq is the frequency after the OD dividers */ ++static void meson_hdmi_pll_generic_set(struct meson_drm *priv, ++ unsigned int pll_freq) ++{ ++ unsigned int od, m, frac, od1, od2, od3; ++ ++ if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) { ++ od3 = 1; ++ if (od < 4) { ++ od1 = 2; ++ od2 = 1; ++ } else { ++ od2 = od / 4; ++ od1 = od / od2; ++ } ++ ++ DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n", ++ pll_freq, m, frac, od1, od2, od3); ++ ++ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); ++ + return; + } + ++ DRM_ERROR("Fatal, unable to find parameters for PLL freq %d\n", ++ pll_freq); ++} ++ ++static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, ++ unsigned int od1, unsigned int od2, unsigned int od3, ++ unsigned int vid_pll_div, unsigned int vclk_div, ++ unsigned int hdmi_tx_div, unsigned int venc_div, ++ bool hdmi_use_enci) ++{ + /* Set HDMI-TX sys clock */ + regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, + CTS_HDMI_SYS_SEL_MASK, 0); +@@ -831,19 +641,49 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); + + /* Set HDMI PLL rate */ +- meson_hdmi_pll_set(priv, params[freq].pll_base_freq, +- params[freq].pll_od1, +- params[freq].pll_od2, +- params[freq].pll_od3); ++ if (!od1 && !od2 && !od3) ++ meson_hdmi_pll_generic_set(priv, pll_base_freq); ++ else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { ++ switch (pll_base_freq) { ++ case 2970000: ++ meson_hdmi_pll_set_params(priv, 0x3d, 0xe00, ++ od1, od2, od3); ++ break; ++ case 4320000: ++ meson_hdmi_pll_set_params(priv, 0x5a, 0, ++ od1, od2, od3); ++ break; ++ case 5940000: ++ meson_hdmi_pll_set_params(priv, 0x7b, 0xc00, ++ od1, od2, od3); ++ break; ++ } ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { ++ switch (pll_base_freq) { ++ case 2970000: ++ meson_hdmi_pll_set_params(priv, 0x7b, 0x300, ++ od1, od2, od3); ++ break; ++ case 4320000: ++ meson_hdmi_pll_set_params(priv, 0xb4, 0, ++ od1, od2, od3); ++ break; ++ case 5940000: ++ meson_hdmi_pll_set_params(priv, 0xf7, 0x200, ++ od1, od2, od3); ++ break; ++ } ++ } + + /* Setup vid_pll divider */ +- meson_vid_pll_set(priv, params[freq].vid_pll_div); ++ meson_vid_pll_set(priv, vid_pll_div); + + /* Set VCLK div */ + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, + VCLK_SEL_MASK, 0); + regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, +- VCLK_DIV_MASK, params[freq].vclk_div - 1); ++ VCLK_DIV_MASK, vclk_div - 1); + + /* Set HDMI-TX source */ + switch (hdmi_tx_div) { +@@ -981,4 +821,80 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + + regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN); + } ++ ++void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ++ unsigned int vclk_freq, unsigned int venc_freq, ++ unsigned int dac_freq, bool hdmi_use_enci) ++{ ++ unsigned int freq; ++ unsigned int hdmi_tx_div; ++ unsigned int venc_div; ++ ++ if (target == MESON_VCLK_TARGET_CVBS) { ++ meson_venci_cvbs_clock_config(priv); ++ return; ++ } else if (target == MESON_VCLK_TARGET_DMT) { ++ /* The DMT clock path is fixed after the PLL: ++ * - automatic PLL freq + OD management ++ * - vid_pll_div = VID_PLL_DIV_5 ++ * - vclk_div = 2 ++ * - hdmi_tx_div = 1 ++ * - venc_div = 1 ++ * - encp encoder ++ */ ++ meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, ++ VID_PLL_DIV_5, 2, 1, 1, false); ++ return; ++ } ++ ++ hdmi_tx_div = vclk_freq / dac_freq; ++ ++ if (hdmi_tx_div == 0) { ++ pr_err("Fatal Error, invalid HDMI-TX freq %d\n", ++ dac_freq); ++ return; ++ } ++ ++ venc_div = vclk_freq / venc_freq; ++ ++ if (venc_div == 0) { ++ pr_err("Fatal Error, invalid HDMI venc freq %d\n", ++ venc_freq); ++ return; ++ } ++ ++ switch (vclk_freq) { ++ case 54000: ++ if (hdmi_use_enci) ++ freq = MESON_VCLK_HDMI_ENCI_54000; ++ else ++ freq = MESON_VCLK_HDMI_DDR_54000; ++ break; ++ case 74250: ++ freq = MESON_VCLK_HDMI_74250; ++ break; ++ case 148500: ++ if (dac_freq != 148500) ++ freq = MESON_VCLK_HDMI_DDR_148500; ++ else ++ freq = MESON_VCLK_HDMI_148500; ++ break; ++ case 297000: ++ freq = MESON_VCLK_HDMI_297000; ++ break; ++ case 594000: ++ freq = MESON_VCLK_HDMI_594000; ++ break; ++ default: ++ pr_err("Fatal Error, invalid HDMI vclk freq %d\n", ++ vclk_freq); ++ return; ++ } ++ ++ meson_vclk_set(priv, params[freq].pll_base_freq, ++ params[freq].pll_od1, params[freq].pll_od2, ++ params[freq].pll_od3, params[freq].vid_pll_div, ++ params[freq].vclk_div, hdmi_tx_div, venc_div, ++ hdmi_use_enci); ++} + EXPORT_SYMBOL_GPL(meson_vclk_setup); +diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h +index 0401b52..869fa3a 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.h ++++ b/drivers/gpu/drm/meson/meson_vclk.h +@@ -24,11 +24,15 @@ + enum { + MESON_VCLK_TARGET_CVBS = 0, + MESON_VCLK_TARGET_HDMI = 1, ++ MESON_VCLK_TARGET_DMT = 2, + }; + + /* 27MHz is the CVBS Pixel Clock */ + #define MESON_VCLK_CVBS 27000 + ++enum drm_mode_status ++meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); ++ + void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + unsigned int vclk_freq, unsigned int venc_freq, + unsigned int dac_freq, bool hdmi_use_enci); +diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c +index 6e27013..d9f33b0 100644 +--- a/drivers/gpu/drm/meson/meson_venc.c ++++ b/drivers/gpu/drm/meson/meson_venc.c +@@ -697,314 +697,6 @@ 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; +@@ -1044,17 +736,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) ++enum drm_mode_status ++meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) + { +- struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; ++ if (mode->flags & ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC | ++ DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)) ++ return MODE_BAD; + +- while (vmode->mode) { +- if (drm_mode_equal(&vmode->drm_mode, mode)) +- return true; +- vmode++; +- } ++ if (mode->hdisplay < 640 || mode->hdisplay > 1920) ++ return MODE_BAD_HVALUE; + +- return false; ++ if (mode->vdisplay < 480 || mode->vdisplay > 1200) ++ return MODE_BAD_VVALUE; ++ ++ return MODE_OK; + } + EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode); + +@@ -1072,18 +767,29 @@ 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) ++void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode, ++ union meson_hdmi_venc_mode *dmt_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; ++ memset(dmt_mode, 0, sizeof(*dmt_mode)); ++ ++ dmt_mode->encp.dvi_settings = 0x21; ++ dmt_mode->encp.video_mode = 0x4040; ++ dmt_mode->encp.video_mode_adv = 0x18; ++ dmt_mode->encp.max_pxcnt = mode->htotal - 1; ++ dmt_mode->encp.havon_begin = mode->htotal - mode->hsync_start; ++ dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin + ++ mode->hdisplay - 1; ++ dmt_mode->encp.vavon_bline = mode->vtotal - mode->vsync_start; ++ dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline + ++ mode->vdisplay - 1; ++ dmt_mode->encp.hso_begin = 0; ++ dmt_mode->encp.hso_end = mode->hsync_end - mode->hsync_start; ++ dmt_mode->encp.vso_begin = 30; ++ dmt_mode->encp.vso_end = 50; ++ dmt_mode->encp.vso_bline = 0; ++ dmt_mode->encp.vso_eline = mode->vsync_end - mode->vsync_start; ++ dmt_mode->encp.vso_eline_present = true; ++ dmt_mode->encp.max_lncnt = mode->vtotal - 1; + } + + static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) +@@ -1120,6 +826,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + struct drm_display_mode *mode) + { + union meson_hdmi_venc_mode *vmode = NULL; ++ union meson_hdmi_venc_mode vmode_dmt; + bool use_enci = false; + bool venc_repeat = false; + bool hdmi_repeat = false; +@@ -1147,14 +854,18 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + unsigned int sof_lines; + unsigned int vsync_lines; + +- if (meson_venc_hdmi_supported_vic(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 mode " +- DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode)); +- return; ++ if (!vmode) { ++ dev_err(priv->dev, "%s: Fatal Error, unsupported mode " ++ DRM_MODE_FMT "\n", __func__, ++ DRM_MODE_ARG(mode)); ++ return; ++ } ++ } ++ else { ++ meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt); ++ vmode = &vmode_dmt; + } + + /* Use VENCI for 480i and 576i and double HDMI pixels */ +diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h +index 7c18a36..97eaebb 100644 +--- a/drivers/gpu/drm/meson/meson_venc.h ++++ b/drivers/gpu/drm/meson/meson_venc.h +@@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode { + }; + + /* HDMI Clock parameters */ +-bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); ++enum drm_mode_status ++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); + |