Skip to content

Commit ba9877e

Browse files
superna9999Andrzej Hajda
authored andcommitted
drm/bridge: dw-hdmi: add support for YUV420 output
In order to support the HDMI2.0 YUV420 display modes, this patch adds support for the YUV420 TMDS Clock divided by 2 and the controller passthrough mode. YUV420 Synopsys PHY support will need some specific configuration table to support theses modes. This patch is based on work from Zheng Yang <zhengyang@rock-chips.com> in the Rockchip Linux 4.4 BSP at [1] [1] https://github.com/rockchip-linux/kernel/tree/release-4.4 Cc: Zheng Yang <zhengyang@rock-chips.com> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Tested-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/1549022873-40549-5-git-send-email-narmstrong@baylibre.com
1 parent 74f6d1e commit ba9877e

File tree

1 file changed

+51
-14
lines changed

1 file changed

+51
-14
lines changed

drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ struct hdmi_vmode {
9999
unsigned int mpixelclock;
100100
unsigned int mpixelrepetitioninput;
101101
unsigned int mpixelrepetitionoutput;
102+
unsigned int mtmdsclock;
102103
};
103104

104105
struct hdmi_data_info {
@@ -543,7 +544,7 @@ static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
543544
static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
544545
{
545546
mutex_lock(&hdmi->audio_mutex);
546-
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
547+
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
547548
hdmi->sample_rate);
548549
mutex_unlock(&hdmi->audio_mutex);
549550
}
@@ -552,7 +553,7 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
552553
{
553554
mutex_lock(&hdmi->audio_mutex);
554555
hdmi->sample_rate = rate;
555-
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
556+
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
556557
hdmi->sample_rate);
557558
mutex_unlock(&hdmi->audio_mutex);
558559
}
@@ -653,6 +654,20 @@ static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
653654
}
654655
}
655656

657+
static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
658+
{
659+
switch (bus_format) {
660+
case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
661+
case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
662+
case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
663+
case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
664+
return true;
665+
666+
default:
667+
return false;
668+
}
669+
}
670+
656671
static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
657672
{
658673
switch (bus_format) {
@@ -882,7 +897,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
882897
u8 val, vp_conf;
883898

884899
if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
885-
hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) {
900+
hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) ||
901+
hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
886902
switch (hdmi_bus_fmt_color_depth(
887903
hdmi->hdmi_data.enc_out_bus_format)) {
888904
case 8:
@@ -1036,7 +1052,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
10361052
*/
10371053
void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
10381054
{
1039-
unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
1055+
unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
10401056

10411057
/* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
10421058
if (hdmi->connector.display_info.hdmi.scdc.supported) {
@@ -1198,6 +1214,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
11981214
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
11991215
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
12001216

1217+
/* TOFIX Will need 420 specific PHY configuration tables */
1218+
12011219
/* PLL/MPLL Cfg - always match on final entry */
12021220
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
12031221
if (mpixelclock <= mpll_config->mpixelclock)
@@ -1245,6 +1263,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
12451263
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
12461264
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
12471265
unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
1266+
unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
12481267
int ret;
12491268

12501269
dw_hdmi_phy_power_off(hdmi);
@@ -1273,7 +1292,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
12731292
}
12741293

12751294
/* Wait for resuming transmission of TMDS clock and data */
1276-
if (mpixelclock > HDMI14_MAX_TMDSCLK)
1295+
if (mtmdsclock > HDMI14_MAX_TMDSCLK)
12771296
msleep(100);
12781297

12791298
return dw_hdmi_phy_power_on(hdmi);
@@ -1390,6 +1409,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
13901409
frame.colorspace = HDMI_COLORSPACE_YUV444;
13911410
else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
13921411
frame.colorspace = HDMI_COLORSPACE_YUV422;
1412+
else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
1413+
frame.colorspace = HDMI_COLORSPACE_YUV420;
13931414
else
13941415
frame.colorspace = HDMI_COLORSPACE_RGB;
13951416

@@ -1547,15 +1568,18 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
15471568
struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
15481569
struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
15491570
int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
1550-
unsigned int vdisplay;
1571+
unsigned int vdisplay, hdisplay;
15511572

1552-
vmode->mpixelclock = mode->clock * 1000;
1573+
vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
15531574

15541575
dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
15551576

1577+
if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
1578+
vmode->mtmdsclock /= 2;
1579+
15561580
/* Set up HDMI_FC_INVIDCONF */
15571581
inv_val = (hdmi->hdmi_data.hdcp_enable ||
1558-
vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
1582+
vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
15591583
hdmi_info->scdc.scrambling.low_rates ?
15601584
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
15611585
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
@@ -1589,6 +1613,22 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
15891613

15901614
hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
15911615

1616+
hdisplay = mode->hdisplay;
1617+
hblank = mode->htotal - mode->hdisplay;
1618+
h_de_hs = mode->hsync_start - mode->hdisplay;
1619+
hsync_len = mode->hsync_end - mode->hsync_start;
1620+
1621+
/*
1622+
* When we're setting a YCbCr420 mode, we need
1623+
* to adjust the horizontal timing to suit.
1624+
*/
1625+
if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
1626+
hdisplay /= 2;
1627+
hblank /= 2;
1628+
h_de_hs /= 2;
1629+
hsync_len /= 2;
1630+
}
1631+
15921632
vdisplay = mode->vdisplay;
15931633
vblank = mode->vtotal - mode->vdisplay;
15941634
v_de_vs = mode->vsync_start - mode->vdisplay;
@@ -1607,7 +1647,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
16071647

16081648
/* Scrambling Control */
16091649
if (hdmi_info->scdc.supported) {
1610-
if (vmode->mpixelclock > HDMI14_MAX_TMDSCLK ||
1650+
if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK ||
16111651
hdmi_info->scdc.scrambling.low_rates) {
16121652
/*
16131653
* HDMI2.0 Specifies the following procedure:
@@ -1645,31 +1685,28 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
16451685
}
16461686

16471687
/* Set up horizontal active pixel width */
1648-
hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
1649-
hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
1688+
hdmi_writeb(hdmi, hdisplay >> 8, HDMI_FC_INHACTV1);
1689+
hdmi_writeb(hdmi, hdisplay, HDMI_FC_INHACTV0);
16501690

16511691
/* Set up vertical active lines */
16521692
hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1);
16531693
hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0);
16541694

16551695
/* Set up horizontal blanking pixel region width */
1656-
hblank = mode->htotal - mode->hdisplay;
16571696
hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
16581697
hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
16591698

16601699
/* Set up vertical blanking pixel region width */
16611700
hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
16621701

16631702
/* Set up HSYNC active edge delay width (in pixel clks) */
1664-
h_de_hs = mode->hsync_start - mode->hdisplay;
16651703
hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
16661704
hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
16671705

16681706
/* Set up VSYNC active edge delay (in lines) */
16691707
hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
16701708

16711709
/* Set up HSYNC active pulse width (in pixel clks) */
1672-
hsync_len = mode->hsync_end - mode->hsync_start;
16731710
hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
16741711
hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
16751712

0 commit comments

Comments
 (0)