Commit 3273fc63 authored by Neil Armstrong's avatar Neil Armstrong

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 patch is an intermediate step towards usage of the Common Clock
Framwework for PLL setup, by reworking the code to have common
sel_pll() function called by the CEA (HDMI) freq setup and the generic
DMT frequencies setup, we should be able to simply call clk_set_rate()
on the PLL clock handle in a near future.

The CEA (HDMI) and CVBS modes needs very specific clock paths that CCF will
never be able to determine by itself, so there is still some work to do for
a full handoff to CCF handling the clocks.

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: default avatarNeil Armstrong <narmstrong@baylibre.com>
Acked-by: default avatarJerome Brunet <jbrunet@baylibre.com>
[narmstrong: fixed trivial checkpatch issues]
Link: https://patchwork.freedesktop.org/patch/msgid/1531726814-14638-1-git-send-email-narmstrong@baylibre.com
parent 620eec75
...@@ -329,6 +329,12 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, ...@@ -329,6 +329,12 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
vclk_freq = mode->clock; 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) if (mode->flags & DRM_MODE_FLAG_DBLCLK)
vclk_freq *= 2; vclk_freq *= 2;
...@@ -542,10 +548,12 @@ static enum drm_mode_status ...@@ -542,10 +548,12 @@ static enum drm_mode_status
dw_hdmi_mode_valid(struct drm_connector *connector, dw_hdmi_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
struct meson_drm *priv = connector->dev->dev_private;
unsigned int vclk_freq; unsigned int vclk_freq;
unsigned int venc_freq; unsigned int venc_freq;
unsigned int hdmi_freq; unsigned int hdmi_freq;
int vic = drm_match_cea_mode(mode); 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", 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, mode->base.id, mode->name, mode->vrefresh, mode->clock,
...@@ -556,8 +564,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, ...@@ -556,8 +564,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
/* Check against non-VIC supported modes */ /* Check against non-VIC supported modes */
if (!vic) { if (!vic) {
if (!meson_venc_hdmi_supported_mode(mode)) status = meson_venc_hdmi_supported_mode(mode);
return MODE_BAD; if (status != MODE_OK)
return status;
return meson_vclk_dmt_supported_freq(priv, mode->clock);
/* Check against supported VIC modes */ /* Check against supported VIC modes */
} else if (!meson_venc_hdmi_supported_vic(vic)) } else if (!meson_venc_hdmi_supported_vic(vic))
return MODE_BAD; return MODE_BAD;
...@@ -583,16 +594,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, ...@@ -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__, dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
vclk_freq, venc_freq, hdmi_freq); vclk_freq, venc_freq, hdmi_freq);
/* Finally filter by configurable vclk frequencies */ /* Finally filter by configurable vclk frequencies for VIC modes */
switch (vclk_freq) { switch (vclk_freq) {
case 25175:
case 40000:
case 54000: case 54000:
case 65000:
case 74250: case 74250:
case 108000:
case 148500: case 148500:
case 162000:
case 297000: case 297000:
case 594000: case 594000:
return MODE_OK; return MODE_OK;
......
...@@ -320,32 +320,23 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) ...@@ -320,32 +320,23 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
CTS_VDAC_EN, CTS_VDAC_EN); CTS_VDAC_EN, CTS_VDAC_EN);
} }
enum {
/* PLL O1 O2 O3 VP DV EN TX */ /* PLL O1 O2 O3 VP DV EN TX */
/* 4320 /4 /4 /1 /5 /1 => /2 /2 */ /* 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 */ /* 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 */ /* 2970 /4 /1 /1 /5 /1 => /1 /2 */
#define MESON_VCLK_HDMI_DDR_148500 3 MESON_VCLK_HDMI_DDR_148500,
/* 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 */ /* 2970 /2 /2 /2 /5 /1 => /1 /1 */
#define MESON_VCLK_HDMI_74250 7 MESON_VCLK_HDMI_74250,
/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_108000 8
/* 2970 /1 /2 /2 /5 /1 => /1 /1 */ /* 2970 /1 /2 /2 /5 /1 => /1 /1 */
#define MESON_VCLK_HDMI_148500 9 MESON_VCLK_HDMI_148500,
/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_162000 10
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */ /* 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 */ /* 5940 /1 /1 /2 /5 /1 => /1 /1 */
#define MESON_VCLK_HDMI_594000 12 MESON_VCLK_HDMI_594000
};
struct meson_vclk_params { struct meson_vclk_params {
unsigned int pll_base_freq; unsigned int pll_base_freq;
...@@ -411,46 +402,6 @@ struct meson_vclk_params { ...@@ -411,46 +402,6 @@ struct meson_vclk_params {
.vid_pll_div = VID_PLL_DIV_5, .vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 1, .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) static inline unsigned int pll_od_to_reg(unsigned int od)
...@@ -470,19 +421,20 @@ static inline unsigned int pll_od_to_reg(unsigned int od) ...@@ -470,19 +421,20 @@ static inline unsigned int pll_od_to_reg(unsigned int od)
return 0; return 0;
} }
void meson_hdmi_pll_set(struct meson_drm *priv, void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
unsigned int base, unsigned int frac, unsigned int od1,
unsigned int od1, unsigned int od2, unsigned int od3)
unsigned int od2,
unsigned int od3)
{ {
unsigned int val; unsigned int val;
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
switch (base) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
case 2970000: if (frac)
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); 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_CNTL3, 0x0d5c5091);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); 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_CNTL5, 0x71486980);
...@@ -495,224 +447,14 @@ void meson_hdmi_pll_set(struct meson_drm *priv, ...@@ -495,224 +447,14 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
/* Poll for lock bit */ /* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0); 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;
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;
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") || } 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")) {
switch (base) { regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
case 2970000: regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
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_CNTL3, 0x860f30c4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); 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_CNTL5, 0x001fa729);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); 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;
};
/* Reset PLL */ /* Reset PLL */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
...@@ -723,7 +465,7 @@ void meson_hdmi_pll_set(struct meson_drm *priv, ...@@ -723,7 +465,7 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
/* Poll for lock bit */ /* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
(val & HDMI_PLL_LOCK), 10, 0); (val & HDMI_PLL_LOCK), 10, 0);
}; }
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
...@@ -748,80 +490,148 @@ void meson_hdmi_pll_set(struct meson_drm *priv, ...@@ -748,80 +490,148 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
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, 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, #define XTAL_FREQ 24000
unsigned int vclk_freq, unsigned int venc_freq,
unsigned int dac_freq, bool hdmi_use_enci) static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv,
unsigned int pll_freq)
{ {
unsigned int freq; /* The GXBB PLL has a /2 pre-multiplier */
unsigned int hdmi_tx_div; if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
unsigned int venc_div; pll_freq /= 2;
if (target == MESON_VCLK_TARGET_CVBS) { return pll_freq / XTAL_FREQ;
meson_venci_cvbs_clock_config(priv); }
return;
#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) { frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq);
pr_err("Fatal Error, invalid HDMI-TX freq %d\n", frac_m = m * frac_max;
dac_freq); if (frac_m > frac)
return; 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) { static bool meson_hdmi_pll_find_params(struct meson_drm *priv,
pr_err("Fatal Error, invalid HDMI venc freq %d\n", unsigned int freq,
venc_freq); unsigned int *m,
return; 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) { return false;
case 54000: }
if (hdmi_use_enci)
freq = MESON_VCLK_HDMI_ENCI_54000; /* pll_freq is the frequency after the OD dividers */
else enum drm_mode_status
freq = MESON_VCLK_HDMI_DDR_54000; meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq)
break; {
case 25175: unsigned int od, m, frac;
freq = MESON_VCLK_HDMI_25175;
break; /* In DMT mode, path after PLL is always /10 */
case 40000: freq *= 10;
freq = MESON_VCLK_HDMI_40000;
break; if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
case 65000: return MODE_OK;
freq = MESON_VCLK_HDMI_65000;
break; return MODE_CLOCK_RANGE;
case 74250: }
freq = MESON_VCLK_HDMI_74250; EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq);
break;
case 108000: /* pll_freq is the frequency after the OD dividers */
freq = MESON_VCLK_HDMI_108000; static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
break; unsigned int pll_freq)
case 148500: {
if (dac_freq != 148500) unsigned int od, m, frac, od1, od2, od3;
freq = MESON_VCLK_HDMI_DDR_148500;
else if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
freq = MESON_VCLK_HDMI_148500; od3 = 1;
break; if (od < 4) {
case 162000: od1 = 2;
freq = MESON_VCLK_HDMI_162000; od2 = 1;
break; } else {
case 297000: od2 = od / 4;
freq = MESON_VCLK_HDMI_297000; od1 = od / od2;
break; }
case 594000:
freq = MESON_VCLK_HDMI_594000; DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n",
break; pll_freq, m, frac, od1, od2, od3);
default:
pr_err("Fatal Error, invalid HDMI vclk freq %d\n", meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
vclk_freq);
return; 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 */ /* Set HDMI-TX sys clock */
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
CTS_HDMI_SYS_SEL_MASK, 0); CTS_HDMI_SYS_SEL_MASK, 0);
...@@ -831,19 +641,49 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ...@@ -831,19 +641,49 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
/* Set HDMI PLL rate */ /* Set HDMI PLL rate */
meson_hdmi_pll_set(priv, params[freq].pll_base_freq, if (!od1 && !od2 && !od3) {
params[freq].pll_od1, meson_hdmi_pll_generic_set(priv, pll_base_freq);
params[freq].pll_od2, } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
params[freq].pll_od3); 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 */ /* 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 */ /* Set VCLK div */
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
VCLK_SEL_MASK, 0); VCLK_SEL_MASK, 0);
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, 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 */ /* Set HDMI-TX source */
switch (hdmi_tx_div) { switch (hdmi_tx_div) {
...@@ -981,4 +821,80 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, ...@@ -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); 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); EXPORT_SYMBOL_GPL(meson_vclk_setup);
...@@ -24,11 +24,15 @@ ...@@ -24,11 +24,15 @@
enum { enum {
MESON_VCLK_TARGET_CVBS = 0, MESON_VCLK_TARGET_CVBS = 0,
MESON_VCLK_TARGET_HDMI = 1, MESON_VCLK_TARGET_HDMI = 1,
MESON_VCLK_TARGET_DMT = 2,
}; };
/* 27MHz is the CVBS Pixel Clock */ /* 27MHz is the CVBS Pixel Clock */
#define MESON_VCLK_CVBS 27000 #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, void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int vclk_freq, unsigned int venc_freq, unsigned int vclk_freq, unsigned int venc_freq,
unsigned int dac_freq, bool hdmi_use_enci); unsigned int dac_freq, bool hdmi_use_enci);
......
...@@ -697,314 +697,6 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { ...@@ -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 { struct meson_hdmi_venc_vic_mode {
unsigned int vic; unsigned int vic;
union meson_hdmi_venc_mode *mode; union meson_hdmi_venc_mode *mode;
...@@ -1044,17 +736,20 @@ static unsigned long modulo(unsigned long a, unsigned long b) ...@@ -1044,17 +736,20 @@ static unsigned long modulo(unsigned long a, unsigned long b)
return a; 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 (mode->hdisplay < 640 || mode->hdisplay > 1920)
if (drm_mode_equal(&vmode->drm_mode, mode)) return MODE_BAD_HVALUE;
return true;
vmode++;
}
return false; if (mode->vdisplay < 480 || mode->vdisplay > 1200)
return MODE_BAD_VVALUE;
return MODE_OK;
} }
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode); EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
...@@ -1072,18 +767,29 @@ bool meson_venc_hdmi_supported_vic(int vic) ...@@ -1072,18 +767,29 @@ bool meson_venc_hdmi_supported_vic(int vic)
} }
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
static union meson_hdmi_venc_mode void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode,
*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; memset(dmt_mode, 0, sizeof(*dmt_mode));
while (vmode->mode) { dmt_mode->encp.dvi_settings = 0x21;
if (drm_mode_equal(&vmode->drm_mode, mode)) dmt_mode->encp.video_mode = 0x4040;
return vmode->mode; dmt_mode->encp.video_mode_adv = 0x18;
vmode++; 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 +
return NULL; 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) 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, ...@@ -1120,6 +826,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
union meson_hdmi_venc_mode *vmode = NULL; union meson_hdmi_venc_mode *vmode = NULL;
union meson_hdmi_venc_mode vmode_dmt;
bool use_enci = false; bool use_enci = false;
bool venc_repeat = false; bool venc_repeat = false;
bool hdmi_repeat = false; bool hdmi_repeat = false;
...@@ -1147,15 +854,18 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, ...@@ -1147,15 +854,18 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
unsigned int sof_lines; unsigned int sof_lines;
unsigned int vsync_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); vmode = meson_venc_hdmi_get_vic_vmode(vic);
else
vmode = meson_venc_hdmi_get_dmt_vmode(mode);
if (!vmode) { if (!vmode) {
dev_err(priv->dev, "%s: Fatal Error, unsupported mode " dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode)); DRM_MODE_FMT "\n", __func__,
DRM_MODE_ARG(mode));
return; return;
} }
} else {
meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt);
vmode = &vmode_dmt;
}
/* Use VENCI for 480i and 576i and double HDMI pixels */ /* Use VENCI for 480i and 576i and double HDMI pixels */
if (mode->flags & DRM_MODE_FLAG_DBLCLK) { if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
......
...@@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode { ...@@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode {
}; };
/* HDMI Clock parameters */ /* 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_supported_vic(int vic);
bool meson_venc_hdmi_venc_repeat(int vic); bool meson_venc_hdmi_venc_repeat(int vic);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment