From c22709807462b0dcf62f44f718ed365da9535151 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Wed, 16 Nov 2016 17:05:47 +0800 Subject: [PATCH] video: rockchip: hdmi: improve hdr function when out of sink tmds clk If output tmdsclk is out of sink max tmds clk, we need to set output mode to 8bit or YCbCr422. For example, sink max tmds clk is 600M, but 3840x2160p-60 10bit tmdsclk is 594*1.25 > 600, we set output mode to YCbCr422 10bit which tmds clk is 594, so we can get max picture quality. Change-Id: I13fe30dad06757ec52de8d367f1e10a56e63ad92 Signed-off-by: Zheng Yang (cherry picked from commit 0c3397a9b8b4da4ca3a67e5a6d88abf20f00f184) --- .../video/rockchip/hdmi/rockchip-hdmi-core.c | 73 ++++++++++++++++++- .../hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c | 33 ++++++--- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c b/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c index e6aa989e1660..70aa0ff0d238 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmi-core.c @@ -76,6 +76,63 @@ static inline void hdmi_wq_set_audio(struct hdmi *hdmi) hdmi->ops->setaudio(hdmi, &hdmi->audio); } +static int hdmi_check_format(struct hdmi *hdmi, struct hdmi_video *vpara) +{ + struct hdmi_video_timing *timing; + struct fb_videomode *mode; + int tmdsclk; + + if (!vpara) + return -ENOENT; + timing = (struct hdmi_video_timing *)hdmi_vic2timing(vpara->vic); + if (!timing) { + pr_err("[%s] not found vic %d\n", __func__, vpara->vic); + return -ENOENT; + } + mode = &timing->mode; + if (vpara->color_input == HDMI_COLOR_YCBCR420) + tmdsclk = mode->pixclock / 2; + else if (vpara->format_3d == HDMI_3D_FRAME_PACKING) + tmdsclk = 2 * mode->pixclock; + else + tmdsclk = mode->pixclock; + if (vpara->color_output != HDMI_COLOR_YCBCR422) { + switch (vpara->color_output_depth) { + case 10: + tmdsclk += tmdsclk / 4; + break; + case 12: + tmdsclk += tmdsclk / 2; + break; + case 16: + tmdsclk += tmdsclk; + break; + case 8: + default: + break; + } + } else if (vpara->color_output_depth > 12) { + /* YCbCr422 mode only support up to 12bit */ + vpara->color_output_depth = 12; + } + if ((tmdsclk > 594000000) || + (tmdsclk > 340000000 && + tmdsclk > hdmi->edid.maxtmdsclock)) { + if (vpara->format_3d == HDMI_3D_FRAME_PACKING) { + pr_err("out of max tmdsclk, disable 3d\n"); + vpara->format_3d = 0; + } else if (vpara->color_output == HDMI_COLOR_YCBCR444 && + hdmi->edid.ycbcr422) { + pr_warn("out of max tmdsclk, down to YCbCr422"); + vpara->color_output = HDMI_COLOR_YCBCR422; + } else { + pr_warn("out of max tmds clock, limit to 8bit\n"); + vpara->color_output_depth = 8; + } + } + return 0; +} + static void hdmi_wq_set_video(struct hdmi *hdmi) { struct hdmi_video *video = &hdmi->video; @@ -144,10 +201,19 @@ static void hdmi_wq_set_video(struct hdmi *hdmi) video->eotf = 0; } else { video->vic = hdmi->vic & HDMI_VIC_MASK; - video->eotf = hdmi->eotf; + video->eotf = 0; + if (hdmi->eotf) { + if (hdmi->eotf & hdmi->edid.hdr.hdrinfo.eotf) + video->eotf = hdmi->eotf; + else + pr_err("sink eotf %x not support eotf %x\n", + hdmi->edid.hdr.hdrinfo.eotf, + hdmi->eotf); + } /* ST_2084 must be 10bit and bt2020 */ if (video->eotf & EOTF_ST_2084) { - video->color_output_depth = 10; + if (deepcolor & HDMI_DEEP_COLOR_30BITS) + video->color_output_depth = 10; if (video->color_output > HDMI_COLOR_RGB_16_235) video->colorimetry = HDMI_COLORIMETRY_EXTEND_BT_2020_YCC; @@ -156,7 +222,7 @@ static void hdmi_wq_set_video(struct hdmi *hdmi) HDMI_COLORIMETRY_EXTEND_BT_2020_RGB; } } - + hdmi_check_format(hdmi, video); if (hdmi->uboot) { if ((uboot_vic & HDMI_UBOOT_VIC_MASK) != hdmi->vic) hdmi->uboot = 0; @@ -459,6 +525,7 @@ static void hdmi_work_queue(struct work_struct *work) HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE); msleep(100); hdmi_wq_set_video(hdmi); + hdmi_wq_set_audio(hdmi); hdmi_wq_set_output(hdmi, hdmi->mute); break; case HDMI_ENABLE_HDCP: diff --git a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c index 1d14209de973..e364897d7dca 100644 --- a/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c +++ b/drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c @@ -901,14 +901,22 @@ static int rockchip_hdmiv2_video_framecomposer(struct hdmi *hdmi_drv, if ((tmdsclk > 594000000) || (tmdsclk > 340000000 && tmdsclk > hdmi_drv->edid.maxtmdsclock)) { - pr_warn("out of max tmds clock, limit to 8bit\n"); - vpara->color_output_depth = 8; - if (vpara->color_input == HDMI_COLOR_YCBCR420) - tmdsclk = mode->pixclock / 2; - else if (vpara->format_3d != HDMI_3D_FRAME_PACKING) - tmdsclk = mode->pixclock; - else + if (vpara->format_3d == HDMI_3D_FRAME_PACKING) { + pr_err("3d frame packing mode out of max tmdsclk\n"); return -1; + } else if (vpara->color_output == HDMI_COLOR_YCBCR444 && + hdmi_drv->edid.ycbcr422) { + pr_warn("out of max tmdsclk, down to YCbCr422"); + vpara->color_output = HDMI_COLOR_YCBCR422; + tmdsclk = mode->pixclock; + } else { + pr_warn("out of max tmds clock, limit to 8bit\n"); + vpara->color_output_depth = 8; + if (vpara->color_input == HDMI_COLOR_YCBCR420) + tmdsclk = mode->pixclock / 2; + else + tmdsclk = mode->pixclock; + } } if ((tmdsclk > 340000000) || @@ -1346,7 +1354,7 @@ static int rockchip_hdmiv2_video_csc(struct hdmi_dev *hdmi_dev, csc_scale = 0; } - switch (vpara->color_output_depth) { + switch (vpara->color_output_depth && mode != CSC_BYPASS) { case 10: color_depth = COLOR_DEPTH_30BIT; mode += 1; @@ -1376,9 +1384,12 @@ static int rockchip_hdmiv2_video_csc(struct hdmi_dev *hdmi_dev, m_CSC_COLOR_DEPTH, v_CSC_COLOR_DEPTH(color_depth)); /* enable CSC */ - hdmi_msk_reg(hdmi_dev, MC_FLOWCTRL, - m_FEED_THROUGH_OFF, v_FEED_THROUGH_OFF(1)); - + if (mode == CSC_BYPASS) + hdmi_msk_reg(hdmi_dev, MC_FLOWCTRL, + m_FEED_THROUGH_OFF, v_FEED_THROUGH_OFF(0)); + else + hdmi_msk_reg(hdmi_dev, MC_FLOWCTRL, + m_FEED_THROUGH_OFF, v_FEED_THROUGH_OFF(1)); return 0; } -- 2.34.1