Files
operating-system/buildroot-external/board/hardkernel/odroid-c2/patches/linux/070_linux-4.17-amlogic-dmt-extended-1002-custom-mode.patch
2018-12-06 10:09:16 +01:00

548 lines
15 KiB
Diff

diff -ur a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c 2018-06-02 16:39:27.777402009 +0200
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c 2018-06-02 17:25:33.803332054 +0200
@@ -588,22 +588,28 @@
/* Finally filter by configurable vclk frequencies */
switch (vclk_freq) {
case 25175:
- case 40000:
+ case 29750:
case 32000:
case 36000:
case 33750:
case 33900:
+ case 40000:
case 54000:
case 65000:
case 74250:
+ case 106500:
case 108000:
case 148500:
case 162000:
+ case 193250:
case 297000:
case 594000:
return MODE_OK;
}
+ if (meson_vclk_supported(vclk_freq))
+ return MODE_OK;
+
return MODE_CLOCK_RANGE;
}
diff -ur a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
--- a/drivers/gpu/drm/meson/meson_vclk.c 2018-06-02 20:16:44.008061996 +0200
+++ b/drivers/gpu/drm/meson/meson_vclk.c 2018-06-04 03:26:22.092619417 +0200
@@ -321,39 +321,49 @@
}
-/* PLL O1 O2 O3 VP DV EN TX */
-/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
-#define MESON_VCLK_HDMI_ENCI_54000 1
-/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
-#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
-/* 2560 /4 /2 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_32000 5
-/* 2700 /4 /2 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_33750 6
-/* 2712 /4 /2 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_33900 7
-/* 2880 /4 /2 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_36000 8
-/* 3200 /4 /2 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_40000 9
-/* 5200 /4 /2 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_65000 10
-/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
-#define MESON_VCLK_HDMI_74250 11
-/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_108000 12
-/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
-#define MESON_VCLK_HDMI_148500 13
-/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_162000 14
-/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
-#define MESON_VCLK_HDMI_297000 15
-/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
-#define MESON_VCLK_HDMI_594000 16
+enum {
+ /* PLL O1 O2 O3 VP DV EN TX */
+ /* 4320 /4 /4 /1 /5 /1 => /2 /2 */
+ MESON_VCLK_HDMI_ENCI_54000 = 1,
+ /* 4320 /4 /4 /1 /5 /1 => /1 /2 */
+ MESON_VCLK_HDMI_DDR_54000,
+ /* 2970 /4 /1 /1 /5 /1 => /1 /2 */
+ MESON_VCLK_HDMI_DDR_148500,
+ /* 4028 /4 /4 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_25175,
+ /* 4760 /4 /4 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_29750,
+ /* 2560 /4 /2 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_32000,
+ /* 2700 /4 /2 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_33750,
+ /* 2712 /4 /2 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_33900,
+ /* 2880 /4 /2 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_36000,
+ /* 3200 /4 /2 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_40000,
+ /* 5200 /4 /2 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_65000,
+ /* 2970 /2 /2 /2 /5 /1 => /1 /1 */
+ MESON_VCLK_HDMI_74250,
+ /* 4260 /4 /1 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_106500,
+ /* 4320 /4 /1 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_108000,
+ /* 2970 /1 /2 /2 /5 /1 => /1 /1 */
+ MESON_VCLK_HDMI_148500,
+ /* 3240 /2 /1 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_162000,
+ /* 3865 /2 /1 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_193250,
+ /* 2970 /1 /1 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_297000,
+ /* 5940 /1 /1 /2 /5 /1 => /1 /1 */
+ MESON_VCLK_HDMI_594000,
+ /* custom calculated mode */
+ MESON_VCLK_HDMI_CUSTOM,
+};
struct meson_vclk_params {
unsigned int pll_base_freq;
@@ -427,6 +437,14 @@
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
+ [MESON_VCLK_HDMI_29750] = {
+ .pll_base_freq = 4760000,
+ .pll_od1 = 4,
+ .pll_od2 = 4,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
[MESON_VCLK_HDMI_32000] = {
.pll_base_freq = 5120000,
.pll_od1 = 4,
@@ -475,6 +493,14 @@
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
+ [MESON_VCLK_HDMI_106500] = {
+ .pll_base_freq = 4260000,
+ .pll_od1 = 4,
+ .pll_od2 = 1,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 2,
+ },
[MESON_VCLK_HDMI_108000] = {
.pll_base_freq = 4320000,
.pll_od1 = 4,
@@ -491,6 +517,14 @@
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
+ [MESON_VCLK_HDMI_193250] = {
+ .pll_base_freq = 3865000,
+ .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)
@@ -519,6 +553,18 @@
unsigned int val;
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
+ unsigned int step = 48000;
+ unsigned int range = 0x1000;
+ unsigned int round = step / range / 2;
+ unsigned int frac = base % step;
+ unsigned int m = (base - frac) / step;
+
+ frac = (frac + round) * range / step;
+ if (frac >= range)
+ frac = range-1;
+
+ dev_info(priv->dev, "%s: base=%d, m=0x%.2x, frac=0x%.3x\n", __func__, base, m, frac);
+
switch (base) {
case 2700000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000238);
@@ -755,10 +801,49 @@
/* 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, 0x4555);
+ break;
+
+ default:
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
+ 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);
+
+ /* div_frac */
+ if (frac)
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+ 0xFFFF, 0x4000 | frac);
break;
+
};
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
+ unsigned int step = 24000;
+ unsigned int range = 0x400;
+ unsigned int round = step / range / 2;
+ unsigned int frac = base % step;
+ unsigned int m = (base - frac) / step;
+
+ frac = (frac + round) * range / step;
+ if (frac >= range)
+ frac = range-1;
+
+ pr_info("%s: base=%d, m=0x%.2x, frac=0x%.3x", __func__, base, m, frac);
+
switch (base) {
case 2700000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000270);
@@ -868,6 +953,14 @@
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
+ default:
+ 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);
+ break;
};
/* Reset PLL */
@@ -906,6 +999,151 @@
3 << 19, pll_od_to_reg(od3) << 19);
}
+unsigned int meson_vclk_freq_from_params(struct meson_vclk_params* vclk_params)
+{
+ unsigned int vclk_freq = vclk_params->pll_base_freq /
+ vclk_params->pll_od1 / vclk_params->pll_od2 /
+ vclk_params->pll_od3 / vclk_params->vclk_div;
+
+ switch (vclk_params->vid_pll_div) {
+ case VID_PLL_DIV_2:
+ vclk_freq /= 2;
+ break;
+ case VID_PLL_DIV_2p5:
+ vclk_freq *= 4;
+ vclk_freq /= 10;
+ break;
+ case VID_PLL_DIV_3:
+ vclk_freq /= 3;
+ break;
+ case VID_PLL_DIV_3p5:
+ vclk_freq *= 2;
+ vclk_freq /= 7;
+ break;
+ case VID_PLL_DIV_3p75:
+ vclk_freq *= 4;
+ vclk_freq /= 15;
+ break;
+ case VID_PLL_DIV_4:
+ vclk_freq /= 4;
+ break;
+ case VID_PLL_DIV_5:
+ vclk_freq /= 5;
+ break;
+ case VID_PLL_DIV_6:
+ vclk_freq /= 6;
+ break;
+ case VID_PLL_DIV_6p25:
+ vclk_freq *= 8;
+ vclk_freq /= 50;
+ break;
+ case VID_PLL_DIV_7:
+ vclk_freq /= 7;
+ break;
+ case VID_PLL_DIV_7p5:
+ vclk_freq *= 4;
+ vclk_freq /= 30;
+ break;
+ case VID_PLL_DIV_12:
+ vclk_freq /= 12;
+ break;
+ case VID_PLL_DIV_14:
+ vclk_freq /= 14;
+ break;
+ case VID_PLL_DIV_15:
+ vclk_freq /= 15;
+ break;
+ default:
+ return 0;
+ }
+
+ return vclk_freq;
+}
+
+static bool meson_get_vclk_params(unsigned int freq,
+ struct meson_vclk_params* vclk_params)
+{
+ unsigned int vclk_freq = freq;
+ unsigned int base_freq, od1_od2, od3_vpll_vclk;
+ int p, jit;
+ bool found = false;
+
+ if ((vclk_freq < 13500) || (vclk_freq > 594000))
+ return false;
+
+ if (vclk_freq % 25 > 12)
+ vclk_freq += 25;
+ vclk_freq -= vclk_freq % 25;
+
+ for (p = 1; p < sizeof(params) / sizeof(struct meson_vclk_params); p++) {
+ if (params[p].vid_pll_div != VID_PLL_DIV_5)
+ continue;
+
+ od1_od2 = params[p].pll_od1 * params[p].pll_od2;
+ od3_vpll_vclk = params[p].pll_od3 * 5 * params[p].vclk_div;
+
+ if ((od3_vpll_vclk != 10) && (vclk_freq > 54000 + 175))
+ continue;
+
+ base_freq = vclk_freq * od1_od2 * od3_vpll_vclk;
+
+ if ((base_freq < 2700000) || (base_freq > 5940000))
+ continue;
+
+ vclk_params->pll_base_freq = base_freq;
+ vclk_params->pll_od1 = params[p].pll_od1;
+ vclk_params->pll_od2 = params[p].pll_od2;
+ vclk_params->pll_od3 = params[p].pll_od3;
+ vclk_params->vid_pll_div = params[p].vid_pll_div;
+ vclk_params->vclk_div = params[p].vclk_div;
+
+ found = true;
+
+ if (params[p].pll_base_freq > vclk_params->pll_base_freq)
+ jit = params[p].pll_base_freq - vclk_params->pll_base_freq;
+ else
+ jit = vclk_params->pll_base_freq - params[p].pll_base_freq;
+
+ if (jit < 175 * od1_od2 * od3_vpll_vclk) {
+ vclk_params->pll_base_freq = params[p].pll_base_freq;
+ vclk_freq = vclk_params->pll_base_freq / od1_od2 / od3_vpll_vclk;
+ }
+
+ if (jit < 40000)
+ break;
+ }
+
+ return found;
+}
+
+static void meson_print_vclk_params(struct meson_drm *priv, unsigned int freq,
+ struct meson_vclk_params* vclk_params)
+{
+ unsigned int vclk_freq = meson_vclk_freq_from_params(vclk_params);
+
+ if (vclk_params->vid_pll_div != VID_PLL_DIV_5)
+ return;
+
+ if (vclk_freq != freq)
+ dev_info(priv->dev, "adjusted %d -> %d", freq, vclk_freq);
+
+ dev_info(priv->dev, "params %d / %d / %d / %d / %d / %d = %d\n",
+ vclk_params->pll_base_freq,
+ vclk_params->pll_od1,
+ vclk_params->pll_od2,
+ vclk_params->pll_od3,
+ 5, vclk_params->vclk_div,
+ vclk_freq);
+}
+
+bool meson_vclk_supported(unsigned int vclk_freq)
+{
+ struct meson_vclk_params custom_params;
+
+ return (meson_get_vclk_params(vclk_freq, &custom_params));
+}
+EXPORT_SYMBOL_GPL(meson_vclk_supported);
+
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)
@@ -913,6 +1151,8 @@
unsigned int freq;
unsigned int hdmi_tx_div;
unsigned int venc_div;
+ struct meson_vclk_params custom_params;
+ struct meson_vclk_params* vclk_params;
if (target == MESON_VCLK_TARGET_CVBS) {
meson_venci_cvbs_clock_config(priv);
@@ -945,6 +1185,9 @@
case 25175:
freq = MESON_VCLK_HDMI_25175;
break;
+ case 29750:
+ freq = MESON_VCLK_HDMI_29750;
+ break;
case 32000:
freq = MESON_VCLK_HDMI_32000;
break;
@@ -966,6 +1209,9 @@
case 74250:
freq = MESON_VCLK_HDMI_74250;
break;
+ case 106500:
+ freq = MESON_VCLK_HDMI_106500;
+ break;
case 108000:
freq = MESON_VCLK_HDMI_108000;
break;
@@ -978,6 +1224,9 @@
case 162000:
freq = MESON_VCLK_HDMI_162000;
break;
+ case 193250:
+ freq = MESON_VCLK_HDMI_193250;
+ break;
case 297000:
freq = MESON_VCLK_HDMI_297000;
break;
@@ -985,9 +1234,8 @@
freq = MESON_VCLK_HDMI_594000;
break;
default:
- pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
- vclk_freq);
- return;
+ freq = MESON_VCLK_HDMI_CUSTOM;
+ break;
}
/* Set HDMI-TX sys clock */
@@ -998,20 +1246,35 @@
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
+ vclk_params = NULL;
+
+ if (freq != MESON_VCLK_HDMI_CUSTOM)
+ vclk_params = &params[freq];
+ else if (meson_get_vclk_params(vclk_freq, &custom_params))
+ vclk_params = &custom_params;
+
+ if (!vclk_params) {
+ pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
+ vclk_freq);
+ return;
+ }
+
+ meson_print_vclk_params(priv, vclk_freq, vclk_params);
+
/* 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);
+ meson_hdmi_pll_set(priv, vclk_params->pll_base_freq,
+ vclk_params->pll_od1,
+ vclk_params->pll_od2,
+ vclk_params->pll_od3);
/* Setup vid_pll divider */
- meson_vid_pll_set(priv, params[freq].vid_pll_div);
+ meson_vid_pll_set(priv, vclk_params->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_params->vclk_div - 1);
/* Set HDMI-TX source */
switch (hdmi_tx_div) {
diff -ur a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
--- a/drivers/gpu/drm/meson/meson_vclk.h 2018-05-26 22:29:37.112948771 +0200
+++ b/drivers/gpu/drm/meson/meson_vclk.h 2018-05-31 05:15:53.342134304 +0200
@@ -29,6 +29,8 @@
/* 27MHz is the CVBS Pixel Clock */
#define MESON_VCLK_CVBS 27000
+bool meson_vclk_supported(unsigned int vclk_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 -ur a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
--- a/drivers/gpu/drm/meson/meson_venc.c 2018-06-02 20:23:23.744646670 +0200
+++ b/drivers/gpu/drm/meson/meson_venc.c 2018-06-02 17:25:33.807332121 +0200
@@ -707,6 +707,12 @@
752, 800, 0, 480, 490, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
},
+ /* 800x480@60Hz */
+ {
+ { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 29750, 800, 824,
+ 896, 992, 0, 480, 483, 490, 500, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ },
/* 800x600@60Hz */
{
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
@@ -737,6 +743,12 @@
1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
},
+ /* 1440x900@60Hz */
+ {
+ { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440,
+ 1520, 1672, 1904, 0, 900, 903, 909, 934, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ },
/* 1600x1200@60Hz */
{
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
@@ -749,6 +761,12 @@
2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
},
+ /* 1920x1200@60Hz */
+ {
+ { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920,
+ 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ },
{ }, /* sentinel */
};