video: rockchip: hdmi: enable hdr when resolution is not 4K
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / rockchip-hdmi-lcdc.c
index a636e7578a953f791c189bd721281069824dde71..45727290b80007dcd631b55e12535c8abac7c643 100644 (file)
@@ -710,7 +710,7 @@ static const struct hdmi_video_timing hdmi_mode[] = {
                        .name = "1440x900p@60Hz",
                        .refresh = 60,
                        .xres = 1440,
-                       .yres = 768,
+                       .yres = 900,
                        .pixclock = 106500000,
                        .left_margin = 232,
                        .right_margin = 80,
@@ -794,34 +794,13 @@ static const struct hdmi_video_timing hdmi_mode[] = {
                .interface = OUT_P888,
        },
        {
+               /* AUO 3.81 */
                .mode = {
-                       .name = "1440x2560@60Hz",
-                       .refresh = 60,
-                       .xres = 1440,
-                       .yres = 2560,
-                       .pixclock = 269390000,
-                       .left_margin = 80,
-                       .right_margin = 180,
-                       .upper_margin = 7,
-                       .lower_margin = 7,
-                       .hsync_len = 40,
-                       .vsync_len = 6,
-                       .sync = 0,
-                       .vmode = 0,
-                       .flag = 0,
-               },
-               .vic = HDMI_VIDEO_DISCRETE_VR | 2,
-               .vic_2nd = 0,
-               .pixelrepeat = 1,
-               .interface = OUT_P888,
-       },
-       {
-               .mode = {
-                       .name = "2160x1200@90Hz",
-                       .refresh = 90,
+                       .name = "2160x1200@75Hz",
+                       .refresh = 75,
                        .xres = 2160,
                        .yres = 1200,
-                       .pixclock = 297000000,
+                       .pixclock = 245000000,
                        .left_margin = 100,
                        .right_margin = 420,
                        .upper_margin = 3,
@@ -838,12 +817,13 @@ static const struct hdmi_video_timing hdmi_mode[] = {
                .interface = OUT_P888,
        },
        {
+               /* sharp 2.89 */
                .mode = {
-                       .name = "2880x1440@90Hz",
-                       .refresh = 90,
+                       .name = "2880x1440@75Hz",
+                       .refresh = 75,
                        .xres = 2880,
                        .yres = 1440,
-                       .pixclock = 403000000,
+                       .pixclock = 340000000,
                        .left_margin = 100,
                        .right_margin = 50,
                        .upper_margin = 8,
@@ -859,11 +839,57 @@ static const struct hdmi_video_timing hdmi_mode[] = {
                .pixelrepeat = 1,
                .interface = OUT_P888,
        },
+       {
+               /* RAYKEN 5.46 */
+               .mode = {
+                       .name = "1440x2560@60Hz",
+                       .refresh = 60,
+                       .xres = 1440,
+                       .yres = 2560,
+                       .pixclock = 268500000,
+                       .left_margin = 50,
+                       .right_margin = 200,
+                       .upper_margin = 20,
+                       .lower_margin = 20,
+                       .hsync_len = 20,
+                       .vsync_len = 10,
+                       .sync = 0,
+                       .vmode = 0,
+                       .flag = 0,
+               },
+               .vic = HDMI_VIDEO_DISCRETE_VR | 5,
+               .vic_2nd = 0,
+               .pixelrepeat = 1,
+               .interface = OUT_P888,
+       },
+       {
+               /* samsung */
+               .mode = {
+                       .name = "1440x2560@70Hz",
+                       .refresh = 70,
+                       .xres = 1440,
+                       .yres = 2560,
+                       .pixclock = 285000000,
+                       .left_margin = 40,
+                       .right_margin = 80,
+                       .upper_margin = 2,
+                       .lower_margin = 6,
+                       .hsync_len = 20,
+                       .vsync_len = 8,
+                       .sync = 0,
+                       .vmode = 0,
+                       .flag = 0,
+               },
+               .vic = HDMI_VIDEO_DISCRETE_VR | 6,
+               .vic_2nd = 0,
+               .pixelrepeat = 1,
+               .interface = OUT_P888,
+       },
 };
 
 static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
 {
-       int i, vic;
+       int i, vic, colorimetry;
        struct fb_videomode *mode;
 
        if (!screen || !hdmi)
@@ -872,10 +898,24 @@ static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
        if (hdmi->vic == 0)
                hdmi->vic = hdmi->property->defaultmode;
 
-       if ((hdmi->vic & HDMI_VIDEO_DMT) || (hdmi->vic & HDMI_VIDEO_DISCRETE_VR))
-               vic = hdmi->vic;
-       else
-               vic = hdmi->vic & HDMI_VIC_MASK;
+       if (hdmi->edid_auto_support) {
+               if ((hdmi->vic & HDMI_VIDEO_DMT) ||
+                   (hdmi->vic & HDMI_VIDEO_DISCRETE_VR)) {
+                       if (hdmi->prop.value.vic)
+                               vic = hdmi->prop.value.vic;
+                       else
+                               vic = hdmi->vic;
+               } else {
+                       vic = hdmi->vic & HDMI_VIC_MASK;
+               }
+       } else {
+               if ((hdmi->vic & HDMI_VIDEO_DMT) ||
+                   (hdmi->vic & HDMI_VIDEO_DISCRETE_VR))
+                       vic = hdmi->vic;
+               else
+                       vic = hdmi->vic & HDMI_VIC_MASK;
+       }
+
        for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
                if (hdmi_mode[i].vic == vic ||
                    hdmi_mode[i].vic_2nd == vic)
@@ -888,10 +928,25 @@ static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
 
        /* screen type & face */
        screen->type = SCREEN_HDMI;
-       if (hdmi->video.color_input == HDMI_COLOR_RGB_0_255)
+       colorimetry = hdmi->video.colorimetry;
+       mode = (struct fb_videomode *)&hdmi_mode[i].mode;
+       if (hdmi->video.color_input == HDMI_COLOR_RGB_0_255) {
                screen->color_mode = COLOR_RGB;
-       else
+       } else if (colorimetry > HDMI_COLORIMETRY_EXTEND_ADOBE_RGB) {
+               screen->color_mode = COLOR_YCBCR_BT2020;
+               if (hdmi->video.eotf == EOTF_ST_2084)
+                       screen->data_space = 1;
+       } else if (colorimetry == HDMI_COLORIMETRY_NO_DATA) {
+               if (mode->xres > 720 && mode->yres > 576)
+                       screen->color_mode = COLOR_YCBCR_BT709;
+               else
+                       screen->color_mode = COLOR_YCBCR;
+       } else if (colorimetry == HDMI_COLORIMETRY_SMTPE_170M) {
                screen->color_mode = COLOR_YCBCR;
+       } else {
+               screen->color_mode = COLOR_YCBCR_BT709;
+       }
+
        if (hdmi->vic & HDMI_VIDEO_YUV420) {
                if (hdmi->video.color_output_depth == 10)
                        screen->face = OUT_YUV_420_10BIT;
@@ -904,8 +959,6 @@ static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
                        screen->face = hdmi_mode[i].interface;
        }
        screen->pixelrepeat = hdmi_mode[i].pixelrepeat - 1;
-       mode = (struct fb_videomode *)&hdmi_mode[i].mode;
-
        screen->mode = *mode;
        if (hdmi->video.format_3d == HDMI_3D_FRAME_PACKING) {
                screen->mode.pixclock = 2 * mode->pixclock;
@@ -956,6 +1009,15 @@ static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
        screen->overscan.top = hdmi->yscale;
        screen->overscan.right = hdmi->xscale;
        screen->overscan.bottom = hdmi->yscale;
+
+       screen->width = hdmi->prop.value.width;
+       screen->height = hdmi->prop.value.height;
+       pr_info("%s:line=%d %d %d %d %d %d %d %d %d\n",
+               __func__, __LINE__, screen->mode.xres, screen->mode.yres,
+               screen->mode.left_margin, screen->mode.right_margin,
+               screen->mode.upper_margin, screen->mode.lower_margin,
+               screen->mode.hsync_len, screen->mode.vsync_len);
+
        return 0;
 }
 
@@ -1077,6 +1139,18 @@ int hdmi_add_vic(int vic, struct list_head *head)
        if (vic == 0)
                return -1;
 
+       if (vic & HDMI_VIDEO_YUV420) {
+               v = vic & 0xff;
+               if (v != HDMI_3840X2160P_50HZ &&
+                   v != HDMI_3840X2160P_60HZ &&
+                   v != HDMI_4096X2160P_50HZ &&
+                   v != HDMI_4096X2160P_60HZ &&
+                   v != HDMI_3840X2160P_50HZ_21_9 &&
+                   v != HDMI_3840X2160P_60HZ_21_9) {
+                       return -1;
+               }
+       }
+
        list_for_each(pos, head) {
                modelist = list_entry(pos, struct display_modelist, list);
                v = modelist->vic;
@@ -1237,6 +1311,66 @@ static void hdmi_sort_modelist(struct hdmi_edid *edid, int feature)
        }
 }
 
+static int edid_select_prop_value(struct hdmi *hdmi)
+{
+       struct edid_prop_value *prop_value = NULL;
+       int nstates = 0;
+       int i, vid, pid, sn, xres, yres, reboot = 0;
+
+       prop_value = hdmi->pvalue;
+       nstates = hdmi->nstates;
+
+       if (!prop_value) {
+               pr_info("%s:pvalue is NULL\n", __func__);
+               return -1;
+       }
+
+       vid = hdmi->edid.value.vid;
+       pid = hdmi->edid.value.pid;
+       sn = hdmi->edid.value.sn;
+       xres = hdmi->edid.value.xres;
+       yres = hdmi->edid.value.yres;
+
+       for (i = 0; i < nstates; i++) {
+               if ((prop_value[i].vid == vid) &&
+                   (prop_value[i].pid == pid) &&
+                   (prop_value[i].sn == sn) &&
+                   (prop_value[i].xres == xres) &&
+                   (prop_value[i].yres == yres)) {
+                       hdmi->edid.value = prop_value[i];
+                       hdmi->prop.value = prop_value[i];
+                       if ((hdmi->prop.valid) &&
+                           ((hdmi->prop.last_vid != vid) ||
+                           (hdmi->prop.last_pid != pid) ||
+                           (hdmi->prop.last_sn != sn) ||
+                           (hdmi->prop.last_xres != xres) ||
+                           (hdmi->prop.last_yres != yres))) {
+                               reboot = 1;
+                       } else {
+                               reboot = 0;
+                       }
+
+                       hdmi->prop.last_vid = vid;
+                       hdmi->prop.last_pid = pid;
+                       hdmi->prop.last_sn = sn;
+                       hdmi->prop.last_xres = xres;
+                       hdmi->prop.last_yres = yres;
+                       hdmi->prop.valid = 1;
+                       pr_info("%s:i=%d reboot=%d,valid=%d\n",
+                               __func__, i, reboot, hdmi->prop.valid);
+
+                       break;
+               }
+       }
+
+       if (reboot) {
+               dev_info(hdmi->dev, "%s:kernel_restart\n", __func__);
+               kernel_restart(NULL);
+       }
+
+       return 0;
+}
+
 /**
  * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
  * @hdmi: handle of hdmi
@@ -1258,6 +1392,9 @@ int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
                hdmi->edid.ycbcr422 = 0;
        }
 
+       if (hdmi->edid_auto_support)
+               edid_select_prop_value(hdmi);
+
        if (head->next == head) {
                dev_info(hdmi->dev,
                         "warning: no CEA video mode parsed from EDID !!!!\n");