Skip to content

Commit e5fab2e

Browse files
committed
drm/meson: vclk: add support for YUV420 setup
This patch adds clocking support for the YUV420 output from the Amlogic Meson SoCs Video Processing Unit to the HDMI Controller. The YUV420 is obtained by generating a YUV444 pixel stream like the classic HDMI display modes, but then the Video Encoder output can be configured to down-sample the YUV444 pixel stream to a YUV420 stream. This mode needs a different clock generation scheme since the TMDS PHY clock must match the 10x ratio with the YUV420 pixel clock, but the video encoder must run at 2x the pixel clock. This patch adds the TMDS PHY clock value in all the video clock setup in order to better support these specific uses cases and switch to the Common Clock framework for clocks handling in the future. Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Reviewed-by: Jernej Škrabec <jernej.skrabec@siol.net> Link: https://patchwork.freedesktop.org/patch/msgid/20200304104052.17196-11-narmstrong@baylibre.com
1 parent 64db601 commit e5fab2e

File tree

4 files changed

+95
-35
lines changed

4 files changed

+95
-35
lines changed

drivers/gpu/drm/meson/meson_dw_hdmi.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -376,15 +376,19 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
376376
{
377377
struct meson_drm *priv = dw_hdmi->priv;
378378
int vic = drm_match_cea_mode(mode);
379+
unsigned int phy_freq;
379380
unsigned int vclk_freq;
380381
unsigned int venc_freq;
381382
unsigned int hdmi_freq;
382383

383384
vclk_freq = mode->clock;
384385

386+
/* TMDS clock is pixel_clock * 10 */
387+
phy_freq = vclk_freq * 10;
388+
385389
if (!vic) {
386-
meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
387-
vclk_freq, vclk_freq, false);
390+
meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq,
391+
vclk_freq, vclk_freq, vclk_freq, false);
388392
return;
389393
}
390394

@@ -402,11 +406,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
402406
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
403407
venc_freq /= 2;
404408

405-
DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
406-
vclk_freq, venc_freq, hdmi_freq,
409+
DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n",
410+
phy_freq, vclk_freq, venc_freq, hdmi_freq,
407411
priv->venc.hdmi_use_enci);
408412

409-
meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
413+
meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq,
410414
venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
411415
}
412416

@@ -617,6 +621,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
617621
const struct drm_display_mode *mode)
618622
{
619623
struct meson_drm *priv = connector->dev->dev_private;
624+
unsigned int phy_freq;
620625
unsigned int vclk_freq;
621626
unsigned int venc_freq;
622627
unsigned int hdmi_freq;
@@ -643,6 +648,9 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
643648

644649
vclk_freq = mode->clock;
645650

651+
/* TMDS clock is pixel_clock * 10 */
652+
phy_freq = vclk_freq * 10;
653+
646654
/* 480i/576i needs global pixel doubling */
647655
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
648656
vclk_freq *= 2;
@@ -659,10 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
659667
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
660668
venc_freq /= 2;
661669

662-
dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
663-
vclk_freq, venc_freq, hdmi_freq);
670+
dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
671+
__func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
664672

665-
return meson_vclk_vic_supported_freq(vclk_freq);
673+
return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
666674
}
667675

668676
/* Encoder */

drivers/gpu/drm/meson/meson_vclk.c

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -354,81 +354,119 @@ enum {
354354
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
355355
MESON_VCLK_HDMI_297000,
356356
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
357-
MESON_VCLK_HDMI_594000
357+
MESON_VCLK_HDMI_594000,
358+
/* 2970 /1 /1 /1 /5 /1 => /1 /2 */
359+
MESON_VCLK_HDMI_594000_YUV420,
358360
};
359361

360362
struct meson_vclk_params {
363+
unsigned int pll_freq;
364+
unsigned int phy_freq;
365+
unsigned int vclk_freq;
366+
unsigned int venc_freq;
361367
unsigned int pixel_freq;
362-
unsigned int pll_base_freq;
363368
unsigned int pll_od1;
364369
unsigned int pll_od2;
365370
unsigned int pll_od3;
366371
unsigned int vid_pll_div;
367372
unsigned int vclk_div;
368373
} params[] = {
369374
[MESON_VCLK_HDMI_ENCI_54000] = {
375+
.pll_freq = 4320000,
376+
.phy_freq = 270000,
377+
.vclk_freq = 54000,
378+
.venc_freq = 54000,
370379
.pixel_freq = 54000,
371-
.pll_base_freq = 4320000,
372380
.pll_od1 = 4,
373381
.pll_od2 = 4,
374382
.pll_od3 = 1,
375383
.vid_pll_div = VID_PLL_DIV_5,
376384
.vclk_div = 1,
377385
},
378386
[MESON_VCLK_HDMI_DDR_54000] = {
379-
.pixel_freq = 54000,
380-
.pll_base_freq = 4320000,
387+
.pll_freq = 4320000,
388+
.phy_freq = 270000,
389+
.vclk_freq = 54000,
390+
.venc_freq = 54000,
391+
.pixel_freq = 27000,
381392
.pll_od1 = 4,
382393
.pll_od2 = 4,
383394
.pll_od3 = 1,
384395
.vid_pll_div = VID_PLL_DIV_5,
385396
.vclk_div = 1,
386397
},
387398
[MESON_VCLK_HDMI_DDR_148500] = {
388-
.pixel_freq = 148500,
389-
.pll_base_freq = 2970000,
399+
.pll_freq = 2970000,
400+
.phy_freq = 742500,
401+
.vclk_freq = 148500,
402+
.venc_freq = 148500,
403+
.pixel_freq = 74250,
390404
.pll_od1 = 4,
391405
.pll_od2 = 1,
392406
.pll_od3 = 1,
393407
.vid_pll_div = VID_PLL_DIV_5,
394408
.vclk_div = 1,
395409
},
396410
[MESON_VCLK_HDMI_74250] = {
411+
.pll_freq = 2970000,
412+
.phy_freq = 742500,
413+
.vclk_freq = 74250,
414+
.venc_freq = 74250,
397415
.pixel_freq = 74250,
398-
.pll_base_freq = 2970000,
399416
.pll_od1 = 2,
400417
.pll_od2 = 2,
401418
.pll_od3 = 2,
402419
.vid_pll_div = VID_PLL_DIV_5,
403420
.vclk_div = 1,
404421
},
405422
[MESON_VCLK_HDMI_148500] = {
423+
.pll_freq = 2970000,
424+
.phy_freq = 1485000,
425+
.vclk_freq = 148500,
426+
.venc_freq = 148500,
406427
.pixel_freq = 148500,
407-
.pll_base_freq = 2970000,
408428
.pll_od1 = 1,
409429
.pll_od2 = 2,
410430
.pll_od3 = 2,
411431
.vid_pll_div = VID_PLL_DIV_5,
412432
.vclk_div = 1,
413433
},
414434
[MESON_VCLK_HDMI_297000] = {
435+
.pll_freq = 5940000,
436+
.phy_freq = 2970000,
437+
.venc_freq = 297000,
438+
.vclk_freq = 297000,
415439
.pixel_freq = 297000,
416-
.pll_base_freq = 5940000,
417440
.pll_od1 = 2,
418441
.pll_od2 = 1,
419442
.pll_od3 = 1,
420443
.vid_pll_div = VID_PLL_DIV_5,
421444
.vclk_div = 2,
422445
},
423446
[MESON_VCLK_HDMI_594000] = {
447+
.pll_freq = 5940000,
448+
.phy_freq = 5940000,
449+
.venc_freq = 594000,
450+
.vclk_freq = 594000,
424451
.pixel_freq = 594000,
425-
.pll_base_freq = 5940000,
426452
.pll_od1 = 1,
427453
.pll_od2 = 1,
428454
.pll_od3 = 2,
429455
.vid_pll_div = VID_PLL_DIV_5,
430456
.vclk_div = 1,
431457
},
458+
[MESON_VCLK_HDMI_594000_YUV420] = {
459+
.pll_freq = 5940000,
460+
.phy_freq = 2970000,
461+
.venc_freq = 594000,
462+
.vclk_freq = 594000,
463+
.pixel_freq = 297000,
464+
.pll_od1 = 2,
465+
.pll_od2 = 1,
466+
.pll_od3 = 1,
467+
.vid_pll_div = VID_PLL_DIV_5,
468+
.vclk_div = 1,
469+
},
432470
{ /* sentinel */ },
433471
};
434472

@@ -701,6 +739,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
701739
unsigned int od, m, frac, od1, od2, od3;
702740

703741
if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
742+
/* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */
704743
od3 = 1;
705744
if (od < 4) {
706745
od1 = 2;
@@ -723,21 +762,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
723762
}
724763

725764
enum drm_mode_status
726-
meson_vclk_vic_supported_freq(unsigned int freq)
765+
meson_vclk_vic_supported_freq(unsigned int phy_freq,
766+
unsigned int vclk_freq)
727767
{
728768
int i;
729769

730-
DRM_DEBUG_DRIVER("freq = %d\n", freq);
770+
DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
771+
phy_freq, vclk_freq);
731772

732773
for (i = 0 ; params[i].pixel_freq ; ++i) {
733774
DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
734775
i, params[i].pixel_freq,
735776
FREQ_1000_1001(params[i].pixel_freq));
777+
DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
778+
i, params[i].phy_freq,
779+
FREQ_1000_1001(params[i].phy_freq/10)*10);
736780
/* Match strict frequency */
737-
if (freq == params[i].pixel_freq)
781+
if (phy_freq == params[i].phy_freq &&
782+
vclk_freq == params[i].vclk_freq)
738783
return MODE_OK;
739784
/* Match 1000/1001 variant */
740-
if (freq == FREQ_1000_1001(params[i].pixel_freq))
785+
if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
786+
vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
741787
return MODE_OK;
742788
}
743789

@@ -965,8 +1011,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
9651011
}
9661012

9671013
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
968-
unsigned int vclk_freq, unsigned int venc_freq,
969-
unsigned int dac_freq, bool hdmi_use_enci)
1014+
unsigned int phy_freq, unsigned int vclk_freq,
1015+
unsigned int venc_freq, unsigned int dac_freq,
1016+
bool hdmi_use_enci)
9701017
{
9711018
bool vic_alternate_clock = false;
9721019
unsigned int freq;
@@ -986,7 +1033,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
9861033
* - venc_div = 1
9871034
* - encp encoder
9881035
*/
989-
meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
1036+
meson_vclk_set(priv, phy_freq, 0, 0, 0,
9901037
VID_PLL_DIV_5, 2, 1, 1, false, false);
9911038
return;
9921039
}
@@ -1008,9 +1055,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
10081055
}
10091056

10101057
for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
1011-
if (vclk_freq == params[freq].pixel_freq ||
1012-
vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
1013-
if (vclk_freq != params[freq].pixel_freq)
1058+
if ((phy_freq == params[freq].phy_freq ||
1059+
phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
1060+
(vclk_freq == params[freq].vclk_freq ||
1061+
vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
1062+
if (vclk_freq != params[freq].vclk_freq)
10141063
vic_alternate_clock = true;
10151064
else
10161065
vic_alternate_clock = false;
@@ -1039,7 +1088,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
10391088
return;
10401089
}
10411090

1042-
meson_vclk_set(priv, params[freq].pll_base_freq,
1091+
meson_vclk_set(priv, params[freq].pll_freq,
10431092
params[freq].pll_od1, params[freq].pll_od2,
10441093
params[freq].pll_od3, params[freq].vid_pll_div,
10451094
params[freq].vclk_div, hdmi_tx_div, venc_div,

drivers/gpu/drm/meson/meson_vclk.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ enum {
2525
enum drm_mode_status
2626
meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
2727
enum drm_mode_status
28-
meson_vclk_vic_supported_freq(unsigned int freq);
28+
meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq);
2929

3030
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
31-
unsigned int vclk_freq, unsigned int venc_freq,
32-
unsigned int dac_freq, bool hdmi_use_enci);
31+
unsigned int phy_freq, unsigned int vclk_freq,
32+
unsigned int venc_freq, unsigned int dac_freq,
33+
bool hdmi_use_enci);
3334

3435
#endif /* __MESON_VCLK_H */

drivers/gpu/drm/meson/meson_venc_cvbs.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,10 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
213213
meson_venci_cvbs_mode_set(priv, meson_mode->enci);
214214

215215
/* Setup 27MHz vclk2 for ENCI and VDAC */
216-
meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS,
217-
MESON_VCLK_CVBS, MESON_VCLK_CVBS, true);
216+
meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
217+
MESON_VCLK_CVBS, MESON_VCLK_CVBS,
218+
MESON_VCLK_CVBS, MESON_VCLK_CVBS,
219+
true);
218220
}
219221
}
220222

0 commit comments

Comments
 (0)