summaryrefslogtreecommitdiff
path: root/drivers/video/meson/meson_vclk.c
diff options
context:
space:
mode:
authorNeil Armstrong <narmstrong@baylibre.com>2019-08-30 14:09:24 +0200
committerNeil Armstrong <narmstrong@baylibre.com>2019-10-18 11:42:55 +0200
commit573687c3be80be60f678597757814f9644c99ae6 (patch)
tree8c86df9a231ac09e2cb924048a1b71a9f050d660 /drivers/video/meson/meson_vclk.c
parent0a3561119faac22be5befdbe3fe261c0dfbe8011 (diff)
video: meson: sync with linux drm-misc tree
Synchronize the Amlogic Meson Video driver back with the latest DRM misc tree, adding G12A platform support, from the latest commit: 528a25d040bc ("drm: meson: use match data to detect vpu compatibility") The sync includes the following changes from Linux adapted to U-Boot: - Add support for VIC alternate timings - Switch PLL to 5.94GHz base for 297Mhz pixel clock - Add registers for G12A SoC - Add G12A Support for VPP setup - Add G12A Support for VIU setup - Add G12A support for OSD1 Plane - Add G12A support for plane handling in CRTC driver - Add G12A support for CVBS Encoder - Add G12A Video Clock setup - Add G12A support for the DW-HDMI Glue - fix G12A HDMI PLL settings for 4K60 1000/1001 variations - fix primary plane disabling - fix G12A primary plane disabling - mask value when writing bits relaxed - crtc: drv: vpp: viu: venc: use proper macros instead of magic constants - global clean-up - add macro used to enable HDMI PLL - venc: set the correct macrovision max amplitude value Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Reviewed-by: Anatolij Gustschin <agust@denx.de>
Diffstat (limited to 'drivers/video/meson/meson_vclk.c')
-rw-r--r--drivers/video/meson/meson_vclk.c233
1 files changed, 178 insertions, 55 deletions
diff --git a/drivers/video/meson/meson_vclk.c b/drivers/video/meson/meson_vclk.c
index 693e0ebe39..0f628e920b 100644
--- a/drivers/video/meson/meson_vclk.c
+++ b/drivers/video/meson/meson_vclk.c
@@ -68,14 +68,20 @@ enum {
#define CTS_HDMI_SYS_EN BIT(8)
#define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
+#define HHI_HDMI_PLL_CNTL_EN BIT(30)
#define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */
#define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */
#define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */
#define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */
#define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */
+#define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */
#define HDMI_PLL_RESET BIT(28)
+#define HDMI_PLL_RESET_G12A BIT(29)
#define HDMI_PLL_LOCK BIT(31)
+#define HDMI_PLL_LOCK_G12A (3 << 30)
+
+#define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001)
/* VID PLL Dividers */
enum {
@@ -206,8 +212,6 @@ static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
{
unsigned int val;
- debug("%s:%d\n", __func__, __LINE__);
-
/* Setup PLL to output 1.485GHz */
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
hhi_write(HHI_HDMI_PLL_CNTL, 0x5800023d);
@@ -217,6 +221,10 @@ static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
hhi_write(HHI_HDMI_PLL_CNTL5, 0x71486980);
hhi_write(HHI_HDMI_PLL_CNTL6, 0x00000e55);
hhi_write(HHI_HDMI_PLL_CNTL, 0x4800023d);
+
+ /* Poll for lock bit */
+ readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
+ (val & HDMI_PLL_LOCK), 10);
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
hhi_write(HHI_HDMI_PLL_CNTL, 0x4000027b);
@@ -231,13 +239,26 @@ static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
HDMI_PLL_RESET, HDMI_PLL_RESET);
hhi_update_bits(HHI_HDMI_PLL_CNTL,
HDMI_PLL_RESET, 0);
- }
- debug("%s:%d\n", __func__, __LINE__);
+ /* Poll for lock bit */
+ readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
+ (val & HDMI_PLL_LOCK), 10);
+ } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
+ hhi_write(HHI_HDMI_PLL_CNTL, 0x1a0504f7);
+ hhi_write(HHI_HDMI_PLL_CNTL2, 0x00010000);
+ hhi_write(HHI_HDMI_PLL_CNTL3, 0x00000000);
+ hhi_write(HHI_HDMI_PLL_CNTL4, 0x6a28dc00);
+ hhi_write(HHI_HDMI_PLL_CNTL5, 0x65771290);
+ hhi_write(HHI_HDMI_PLL_CNTL6, 0x39272000);
+ hhi_write(HHI_HDMI_PLL_CNTL7, 0x56540000);
+ hhi_write(HHI_HDMI_PLL_CNTL, 0x3a0504f7);
+ hhi_write(HHI_HDMI_PLL_CNTL, 0x1a0504f7);
- /* Poll for lock bit */
- readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
- (val & HDMI_PLL_LOCK), 10);
+ /* Poll for lock bit */
+ readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
+ ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A),
+ 10);
+ }
/* Disable VCLK2 */
hhi_update_bits(HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
@@ -250,8 +271,13 @@ static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
VCLK2_DIV_MASK, (55 - 1));
/* select vid_pll for vclk2 */
- hhi_update_bits(HHI_VIID_CLK_CNTL,
- VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+ hhi_update_bits(HHI_VIID_CLK_CNTL,
+ VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT));
+ else
+ hhi_update_bits(HHI_VIID_CLK_CNTL,
+ VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT));
+
/* enable vclk2 gate */
hhi_update_bits(HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN);
@@ -282,14 +308,12 @@ static void meson_venci_cvbs_clock_config(struct meson_vpu_priv *priv)
/* enable vdac_clk */
hhi_update_bits(HHI_VID_CLK_CNTL2,
CTS_VDAC_EN, CTS_VDAC_EN);
-
- debug("%s:%d\n", __func__, __LINE__);
}
enum {
/* PLL O1 O2 O3 VP DV EN TX */
/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
- MESON_VCLK_HDMI_ENCI_54000 = 1,
+ MESON_VCLK_HDMI_ENCI_54000 = 0,
/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
MESON_VCLK_HDMI_DDR_54000,
/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
@@ -305,6 +329,7 @@ enum {
};
struct meson_vclk_params {
+ unsigned int pixel_freq;
unsigned int pll_base_freq;
unsigned int pll_od1;
unsigned int pll_od2;
@@ -313,6 +338,7 @@ struct meson_vclk_params {
unsigned int vclk_div;
} params[] = {
[MESON_VCLK_HDMI_ENCI_54000] = {
+ .pixel_freq = 54000,
.pll_base_freq = 4320000,
.pll_od1 = 4,
.pll_od2 = 4,
@@ -321,6 +347,7 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_DDR_54000] = {
+ .pixel_freq = 54000,
.pll_base_freq = 4320000,
.pll_od1 = 4,
.pll_od2 = 4,
@@ -329,6 +356,7 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_DDR_148500] = {
+ .pixel_freq = 148500,
.pll_base_freq = 2970000,
.pll_od1 = 4,
.pll_od2 = 1,
@@ -337,6 +365,7 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_74250] = {
+ .pixel_freq = 74250,
.pll_base_freq = 2970000,
.pll_od1 = 2,
.pll_od2 = 2,
@@ -345,6 +374,7 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_148500] = {
+ .pixel_freq = 148500,
.pll_base_freq = 2970000,
.pll_od1 = 1,
.pll_od2 = 2,
@@ -353,14 +383,16 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_297000] = {
- .pll_base_freq = 2970000,
- .pll_od1 = 1,
+ .pixel_freq = 297000,
+ .pll_base_freq = 5940000,
+ .pll_od1 = 2,
.pll_od2 = 1,
.pll_od3 = 1,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
[MESON_VCLK_HDMI_594000] = {
+ .pixel_freq = 594000,
.pll_base_freq = 5940000,
.pll_od1 = 1,
.pll_od2 = 1,
@@ -368,6 +400,7 @@ struct meson_vclk_params {
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 1,
},
+ { /* sentinel */ },
};
static inline unsigned int pll_od_to_reg(unsigned int od)
@@ -431,6 +464,50 @@ void meson_hdmi_pll_set_params(struct meson_vpu_priv *priv, unsigned int m,
/* Poll for lock bit */
readl_poll_timeout(priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
(val & HDMI_PLL_LOCK), 10);
+ } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
+ hhi_write(HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m);
+
+ /* Enable and reset */
+ hhi_update_bits(HHI_HDMI_PLL_CNTL, 0x3 << 28, 0x3 << 28);
+
+ hhi_write(HHI_HDMI_PLL_CNTL2, frac);
+ hhi_write(HHI_HDMI_PLL_CNTL3, 0x00000000);
+
+ /* G12A HDMI PLL Needs specific parameters for 5.4GHz */
+ if (m >= 0xf7) {
+ if (frac < 0x10000) {
+ hhi_write(HHI_HDMI_PLL_CNTL4, 0x6a685c00);
+ hhi_write(HHI_HDMI_PLL_CNTL5, 0x11551293);
+ } else {
+ hhi_write(HHI_HDMI_PLL_CNTL4, 0xea68dc00);
+ hhi_write(HHI_HDMI_PLL_CNTL5, 0x65771290);
+ }
+ hhi_write(HHI_HDMI_PLL_CNTL6, 0x39272000);
+ hhi_write(HHI_HDMI_PLL_CNTL7, 0x55540000);
+ } else {
+ hhi_write(HHI_HDMI_PLL_CNTL4, 0x0a691c00);
+ hhi_write(HHI_HDMI_PLL_CNTL5, 0x33771290);
+ hhi_write(HHI_HDMI_PLL_CNTL6, 0x39270000);
+ hhi_write(HHI_HDMI_PLL_CNTL7, 0x50540000);
+ }
+
+ do {
+ /* Reset PLL */
+ hhi_update_bits(HHI_HDMI_PLL_CNTL,
+ HDMI_PLL_RESET_G12A,
+ HDMI_PLL_RESET_G12A);
+
+ /* UN-Reset PLL */
+ hhi_update_bits(HHI_HDMI_PLL_CNTL,
+ HDMI_PLL_RESET_G12A, 0);
+
+ /* Poll for lock bits */
+ if (!readl_poll_timeout(
+ priv->hhi_base + HHI_HDMI_PLL_CNTL, val,
+ ((val & HDMI_PLL_LOCK_G12A)
+ == HDMI_PLL_LOCK_G12A), 100))
+ break;
+ } while (1);
}
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
@@ -440,6 +517,9 @@ void meson_hdmi_pll_set_params(struct meson_vpu_priv *priv, unsigned int m,
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
hhi_update_bits(HHI_HDMI_PLL_CNTL3,
3 << 21, pll_od_to_reg(od1) << 21);
+ else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+ hhi_update_bits(HHI_HDMI_PLL_CNTL,
+ 3 << 16, pll_od_to_reg(od1) << 16);
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
hhi_update_bits(HHI_HDMI_PLL_CNTL2,
@@ -448,6 +528,9 @@ void meson_hdmi_pll_set_params(struct meson_vpu_priv *priv, unsigned int m,
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
hhi_update_bits(HHI_HDMI_PLL_CNTL3,
3 << 23, pll_od_to_reg(od2) << 23);
+ else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+ hhi_update_bits(HHI_HDMI_PLL_CNTL,
+ 3 << 18, pll_od_to_reg(od2) << 18);
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
hhi_update_bits(HHI_HDMI_PLL_CNTL2,
@@ -456,6 +539,9 @@ void meson_hdmi_pll_set_params(struct meson_vpu_priv *priv, unsigned int m,
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
hhi_update_bits(HHI_HDMI_PLL_CNTL3,
3 << 19, pll_od_to_reg(od3) << 19);
+ else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+ hhi_update_bits(HHI_HDMI_PLL_CNTL,
+ 3 << 20, pll_od_to_reg(od3) << 20);
}
#define XTAL_FREQ 24000
@@ -472,6 +558,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_vpu_priv *priv,
#define HDMI_FRAC_MAX_GXBB 4096
#define HDMI_FRAC_MAX_GXL 1024
+#define HDMI_FRAC_MAX_G12A 131072
static unsigned int meson_hdmi_pll_get_frac(struct meson_vpu_priv *priv,
unsigned int m,
@@ -488,6 +575,9 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_vpu_priv *priv,
parent_freq *= 2;
}
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
+ frac_max = HDMI_FRAC_MAX_G12A;
+
/* We can have a perfect match !*/
if (pll_freq / m == parent_freq &&
pll_freq % m == 0)
@@ -519,6 +609,12 @@ static bool meson_hdmi_pll_validate_params(struct meson_vpu_priv *priv,
return false;
if (frac >= HDMI_FRAC_MAX_GXL)
return false;
+ } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
+ /* Empiric supported min/max dividers */
+ if (m < 106 || m > 247)
+ return false;
+ if (frac >= HDMI_FRAC_MAX_G12A)
+ return false;
}
return true;
@@ -595,8 +691,10 @@ meson_vclk_set(struct meson_vpu_priv *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)
+ bool hdmi_use_enci, bool vic_alternate_clock)
{
+ unsigned int m = 0, frac = 0;
+
/* Set HDMI-TX sys clock */
hhi_update_bits(HHI_HDMI_CLK_CNTL,
CTS_HDMI_SYS_SEL_MASK, 0);
@@ -611,34 +709,55 @@ meson_vclk_set(struct meson_vpu_priv *priv, unsigned int pll_base_freq,
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
switch (pll_base_freq) {
case 2970000:
- meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
- od1, od2, od3);
+ m = 0x3d;
+ frac = vic_alternate_clock ? 0xd02 : 0xe00;
break;
case 4320000:
- meson_hdmi_pll_set_params(priv, 0x5a, 0,
- od1, od2, od3);
+ m = vic_alternate_clock ? 0x59 : 0x5a;
+ frac = vic_alternate_clock ? 0xe8f : 0;
break;
case 5940000:
- meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
- od1, od2, od3);
+ m = 0x7b;
+ frac = vic_alternate_clock ? 0xa05 : 0xc00;
break;
}
+
+ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
switch (pll_base_freq) {
case 2970000:
- meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
- od1, od2, od3);
+ m = 0x7b;
+ frac = vic_alternate_clock ? 0x281 : 0x300;
+ break;
+ case 4320000:
+ m = vic_alternate_clock ? 0xb3 : 0xb4;
+ frac = vic_alternate_clock ? 0x347 : 0;
+ break;
+ case 5940000:
+ m = 0xf7;
+ frac = vic_alternate_clock ? 0x102 : 0x200;
+ break;
+ }
+
+ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
+ } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
+ switch (pll_base_freq) {
+ case 2970000:
+ m = 0x7b;
+ frac = vic_alternate_clock ? 0x140b4 : 0x18000;
break;
case 4320000:
- meson_hdmi_pll_set_params(priv, 0xb4, 0,
- od1, od2, od3);
+ m = vic_alternate_clock ? 0xb3 : 0xb4;
+ frac = vic_alternate_clock ? 0x1a3ee : 0;
break;
case 5940000:
- meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
- od1, od2, od3);
+ m = 0xf7;
+ frac = vic_alternate_clock ? 0x8148 : 0x10000;
break;
}
+
+ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
}
/* Setup vid_pll divider */
@@ -803,6 +922,7 @@ static void meson_vclk_setup(struct meson_vpu_priv *priv, unsigned int target,
unsigned int vclk_freq, unsigned int venc_freq,
unsigned int dac_freq, bool hdmi_use_enci)
{
+ bool vic_alternate_clock = false;
unsigned int freq;
unsigned int hdmi_tx_div;
unsigned int venc_div;
@@ -820,8 +940,7 @@ static void meson_vclk_setup(struct meson_vpu_priv *priv, unsigned int target,
* - encp encoder
*/
meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
- VID_PLL_DIV_5, 2, 1, 1, false);
-
+ VID_PLL_DIV_5, 2, 1, 1, false, false);
return;
}
@@ -841,31 +960,35 @@ static void meson_vclk_setup(struct meson_vpu_priv *priv, unsigned int target,
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:
- printf("Fatal Error, invalid HDMI vclk freq %d\n",
- vclk_freq);
+ for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
+ if (vclk_freq == params[freq].pixel_freq ||
+ vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
+ if (vclk_freq != params[freq].pixel_freq)
+ vic_alternate_clock = true;
+ else
+ vic_alternate_clock = false;
+
+ if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
+ !hdmi_use_enci)
+ continue;
+
+ if (freq == MESON_VCLK_HDMI_DDR_54000 &&
+ hdmi_use_enci)
+ continue;
+
+ if (freq == MESON_VCLK_HDMI_DDR_148500 &&
+ dac_freq == vclk_freq)
+ continue;
+
+ if (freq == MESON_VCLK_HDMI_148500 &&
+ dac_freq != vclk_freq)
+ continue;
+ break;
+ }
+ }
+
+ if (!params[freq].pixel_freq) {
+ pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
return;
}
@@ -873,7 +996,7 @@ static void meson_vclk_setup(struct meson_vpu_priv *priv, unsigned int target,
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);
+ hdmi_use_enci, vic_alternate_clock);
}
void meson_vpu_setup_vclk(struct udevice *dev,