summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/meson
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/meson')
-rw-r--r--drivers/gpu/drm/meson/meson_dw_hdmi.c24
-rw-r--r--drivers/gpu/drm/meson/meson_vclk.c93
-rw-r--r--drivers/gpu/drm/meson/meson_vclk.h7
-rw-r--r--drivers/gpu/drm/meson/meson_venc_cvbs.c6
4 files changed, 95 insertions, 35 deletions
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index b2105c0fe205..b5b0d45eb314 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -376,15 +376,19 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
{
struct meson_drm *priv = dw_hdmi->priv;
int vic = drm_match_cea_mode(mode);
+ unsigned int phy_freq;
unsigned int vclk_freq;
unsigned int venc_freq;
unsigned int hdmi_freq;
vclk_freq = mode->clock;
+ /* TMDS clock is pixel_clock * 10 */
+ phy_freq = vclk_freq * 10;
+
if (!vic) {
- meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
- vclk_freq, vclk_freq, false);
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq,
+ vclk_freq, vclk_freq, vclk_freq, false);
return;
}
@@ -402,11 +406,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
venc_freq /= 2;
- DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
- vclk_freq, venc_freq, hdmi_freq,
+ DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n",
+ phy_freq, vclk_freq, venc_freq, hdmi_freq,
priv->venc.hdmi_use_enci);
- meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq,
venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
}
@@ -617,6 +621,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode)
{
struct meson_drm *priv = connector->dev->dev_private;
+ unsigned int phy_freq;
unsigned int vclk_freq;
unsigned int venc_freq;
unsigned int hdmi_freq;
@@ -643,6 +648,9 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
vclk_freq = mode->clock;
+ /* TMDS clock is pixel_clock * 10 */
+ phy_freq = vclk_freq * 10;
+
/* 480i/576i needs global pixel doubling */
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
vclk_freq *= 2;
@@ -659,10 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
venc_freq /= 2;
- dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
- vclk_freq, venc_freq, hdmi_freq);
+ dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
+ __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
- return meson_vclk_vic_supported_freq(vclk_freq);
+ return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
}
/* Encoder */
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index f690793ae2d5..fdf26dac9fa8 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -354,12 +354,17 @@ enum {
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
MESON_VCLK_HDMI_297000,
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
- MESON_VCLK_HDMI_594000
+ MESON_VCLK_HDMI_594000,
+/* 2970 /1 /1 /1 /5 /1 => /1 /2 */
+ MESON_VCLK_HDMI_594000_YUV420,
};
struct meson_vclk_params {
+ unsigned int pll_freq;
+ unsigned int phy_freq;
+ unsigned int vclk_freq;
+ unsigned int venc_freq;
unsigned int pixel_freq;
- unsigned int pll_base_freq;
unsigned int pll_od1;
unsigned int pll_od2;
unsigned int pll_od3;
@@ -367,8 +372,11 @@ struct meson_vclk_params {
unsigned int vclk_div;
} params[] = {
[MESON_VCLK_HDMI_ENCI_54000] = {
+ .pll_freq = 4320000,
+ .phy_freq = 270000,
+ .vclk_freq = 54000,
+ .venc_freq = 54000,
.pixel_freq = 54000,
- .pll_base_freq = 4320000,
.pll_od1 = 4,
.pll_od2 = 4,
.pll_od3 = 1,
@@ -376,8 +384,11 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_DDR_54000] = {
- .pixel_freq = 54000,
- .pll_base_freq = 4320000,
+ .pll_freq = 4320000,
+ .phy_freq = 270000,
+ .vclk_freq = 54000,
+ .venc_freq = 54000,
+ .pixel_freq = 27000,
.pll_od1 = 4,
.pll_od2 = 4,
.pll_od3 = 1,
@@ -385,8 +396,11 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_DDR_148500] = {
- .pixel_freq = 148500,
- .pll_base_freq = 2970000,
+ .pll_freq = 2970000,
+ .phy_freq = 742500,
+ .vclk_freq = 148500,
+ .venc_freq = 148500,
+ .pixel_freq = 74250,
.pll_od1 = 4,
.pll_od2 = 1,
.pll_od3 = 1,
@@ -394,8 +408,11 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_74250] = {
+ .pll_freq = 2970000,
+ .phy_freq = 742500,
+ .vclk_freq = 74250,
+ .venc_freq = 74250,
.pixel_freq = 74250,
- .pll_base_freq = 2970000,
.pll_od1 = 2,
.pll_od2 = 2,
.pll_od3 = 2,
@@ -403,8 +420,11 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_148500] = {
+ .pll_freq = 2970000,
+ .phy_freq = 1485000,
+ .vclk_freq = 148500,
+ .venc_freq = 148500,
.pixel_freq = 148500,
- .pll_base_freq = 2970000,
.pll_od1 = 1,
.pll_od2 = 2,
.pll_od3 = 2,
@@ -412,8 +432,11 @@ struct meson_vclk_params {
.vclk_div = 1,
},
[MESON_VCLK_HDMI_297000] = {
+ .pll_freq = 5940000,
+ .phy_freq = 2970000,
+ .venc_freq = 297000,
+ .vclk_freq = 297000,
.pixel_freq = 297000,
- .pll_base_freq = 5940000,
.pll_od1 = 2,
.pll_od2 = 1,
.pll_od3 = 1,
@@ -421,14 +444,29 @@ struct meson_vclk_params {
.vclk_div = 2,
},
[MESON_VCLK_HDMI_594000] = {
+ .pll_freq = 5940000,
+ .phy_freq = 5940000,
+ .venc_freq = 594000,
+ .vclk_freq = 594000,
.pixel_freq = 594000,
- .pll_base_freq = 5940000,
.pll_od1 = 1,
.pll_od2 = 1,
.pll_od3 = 2,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 1,
},
+ [MESON_VCLK_HDMI_594000_YUV420] = {
+ .pll_freq = 5940000,
+ .phy_freq = 2970000,
+ .venc_freq = 594000,
+ .vclk_freq = 594000,
+ .pixel_freq = 297000,
+ .pll_od1 = 2,
+ .pll_od2 = 1,
+ .pll_od3 = 1,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 1,
+ },
{ /* sentinel */ },
};
@@ -701,6 +739,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
unsigned int od, m, frac, od1, od2, od3;
if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
+ /* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */
od3 = 1;
if (od < 4) {
od1 = 2;
@@ -723,21 +762,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
}
enum drm_mode_status
-meson_vclk_vic_supported_freq(unsigned int freq)
+meson_vclk_vic_supported_freq(unsigned int phy_freq,
+ unsigned int vclk_freq)
{
int i;
- DRM_DEBUG_DRIVER("freq = %d\n", freq);
+ DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
+ phy_freq, vclk_freq);
for (i = 0 ; params[i].pixel_freq ; ++i) {
DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
i, params[i].pixel_freq,
FREQ_1000_1001(params[i].pixel_freq));
+ DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
+ i, params[i].phy_freq,
+ FREQ_1000_1001(params[i].phy_freq/10)*10);
/* Match strict frequency */
- if (freq == params[i].pixel_freq)
+ if (phy_freq == params[i].phy_freq &&
+ vclk_freq == params[i].vclk_freq)
return MODE_OK;
/* Match 1000/1001 variant */
- if (freq == FREQ_1000_1001(params[i].pixel_freq))
+ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
+ vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
return MODE_OK;
}
@@ -965,8 +1011,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_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)
+ unsigned int phy_freq, unsigned int vclk_freq,
+ unsigned int venc_freq, unsigned int dac_freq,
+ bool hdmi_use_enci)
{
bool vic_alternate_clock = false;
unsigned int freq;
@@ -986,7 +1033,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
* - venc_div = 1
* - encp encoder
*/
- meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
+ meson_vclk_set(priv, phy_freq, 0, 0, 0,
VID_PLL_DIV_5, 2, 1, 1, false, false);
return;
}
@@ -1008,9 +1055,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
}
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)
+ if ((phy_freq == params[freq].phy_freq ||
+ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
+ (vclk_freq == params[freq].vclk_freq ||
+ vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
+ if (vclk_freq != params[freq].vclk_freq)
vic_alternate_clock = true;
else
vic_alternate_clock = false;
@@ -1039,7 +1088,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
return;
}
- meson_vclk_set(priv, params[freq].pll_base_freq,
+ meson_vclk_set(priv, params[freq].pll_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,
diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
index b62125540aef..aed0ab2efa71 100644
--- a/drivers/gpu/drm/meson/meson_vclk.h
+++ b/drivers/gpu/drm/meson/meson_vclk.h
@@ -25,10 +25,11 @@ enum {
enum drm_mode_status
meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
enum drm_mode_status
-meson_vclk_vic_supported_freq(unsigned int freq);
+meson_vclk_vic_supported_freq(unsigned int phy_freq, 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);
+ unsigned int phy_freq, unsigned int vclk_freq,
+ unsigned int venc_freq, unsigned int dac_freq,
+ bool hdmi_use_enci);
#endif /* __MESON_VCLK_H */
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index 1bd6b6d15ffb..541f9eb2a135 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -213,8 +213,10 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
meson_venci_cvbs_mode_set(priv, meson_mode->enci);
/* Setup 27MHz vclk2 for ENCI and VDAC */
- meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS,
- MESON_VCLK_CVBS, MESON_VCLK_CVBS, true);
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
+ MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+ MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+ true);
}
}