video: rockchip: hdmi: improve hdr function when out of sink tmds clk
authorZheng Yang <zhengyang@rock-chips.com>
Wed, 16 Nov 2016 09:05:47 +0000 (17:05 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 15 Feb 2017 08:56:48 +0000 (16:56 +0800)
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 <zhengyang@rock-chips.com>
(cherry picked from commit 0c3397a9b8b4da4ca3a67e5a6d88abf20f00f184)

drivers/video/rockchip/hdmi/rockchip-hdmi-core.c
drivers/video/rockchip/hdmi/rockchip-hdmiv2/rockchip_hdmiv2_hw.c

index e6aa989e1660775ce5ef51655161dbd72a34501e..70aa0ff0d23863b629ba17bec0f74eab08875fde 100644 (file)
@@ -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:
index 1d14209de9733ac41f58133751cde223cd2c717d..e364897d7dcac0296e95c16a6361e92f325cc3bd 100644 (file)
@@ -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;
 }