HDMI: add support parse 4k_resolution and color_depth from EDID
authorzwl <zwl@rock-chips.com>
Wed, 23 Apr 2014 14:42:01 +0000 (22:42 +0800)
committerzwl <zwl@rock-chips.com>
Wed, 23 Apr 2014 14:42:01 +0000 (22:42 +0800)
drivers/video/rockchip/hdmi/rk_hdmi.h
drivers/video/rockchip/hdmi/rk_hdmi_edid.c
drivers/video/rockchip/hdmi/rk_hdmi_lcdc.c
drivers/video/rockchip/hdmi/rk_hdmi_task.c

index 8fa6345db7a13a92ea3cd639ec118414d0e6e41d..ed7b8a199f50f242e1c0fd0e84d89e05539eef6f 100755 (executable)
@@ -139,6 +139,14 @@ enum {
        HDMI_COLOR_YCbCr444
 };
 
+/*HDMI Video Color Depth*/
+enum {
+       HDMI_COLOR_DEPTH_8BIT = 0x1,
+       HDMI_COLOR_DEPTH_10BIT = 0x2,
+       HDMI_COLOR_DEPTH_12BIT = 0x4,
+       HDMI_COLOR_DEPTH_16BIT = 0x8
+};
+
 /* HDMI Audio type */
 enum hdmi_audio_type
 {
@@ -238,6 +246,15 @@ struct hdmi_edid {
        unsigned char ycbcr444;                         //Display device support YCbCr444
        unsigned char ycbcr422;                         //Display device support YCbCr422
        unsigned char deepcolor;                        //bit3:DC_48bit; bit2:DC_36bit; bit1:DC_30bit; bit0:DC_Y444;
+       unsigned char latency_fields_present;
+       unsigned char i_latency_fields_present;
+       unsigned char video_latency;
+       unsigned char audio_latency;
+       unsigned char interlaced_video_latency;
+       unsigned char interlaced_audio_latency;
+       unsigned char video_present;                    //have additional video format abount 4k and/or 3d
+       unsigned char support_3d;                       //3D format support
+       unsigned int maxtmdsclock;                      //max tmds clock freq support
        struct fb_monspecs      *specs;                 //Device spec
        struct list_head modelist;                      //Device supported display mode list
        struct hdmi_audio *audio;                       //Device supported audio info
@@ -252,7 +269,10 @@ struct hdmi_video_para {
        int input_color;        //input video color mode
        int output_mode;        //output hdmi or dvi
        int output_color;       //output video color mode
-       int format_3d;
+       unsigned char format_3d;                //output 3d format
+       unsigned char color_depth;      //color depth: 8bit; 10bit; 12bit; 16bit;
+       unsigned char pixel_repet;      //pixel repettion
+       unsigned char pixel_pack_phase; //pixel packing default phase
 };
 
 struct hdmi {
@@ -337,6 +357,7 @@ extern struct hdmi_video_timing * hdmi_find_mode(int vic);
 extern int hdmi_find_best_mode(struct hdmi* hdmi_drv, int vic);
 extern int hdmi_ouputmode_select(struct hdmi *hdmi_drv, int edid_ok);
 extern int hdmi_switch_fb(struct hdmi *hdmi_drv, int vic);
+extern int hdmi_init_video_para(struct hdmi *hdmi_drv, struct hdmi_video_para *video);
 extern void hdmi_work(struct work_struct *work);
 extern void hdmi_register_display_sysfs(struct hdmi *hdmi_drv, struct device *parent);
 extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi_drv);
index 31ca48b7bbab93d34ba4ac3705e82464467b6439..e4293a14921f3d33f1c2f156c480860c07a6bc01 100755 (executable)
@@ -147,7 +147,11 @@ static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
        for(i = 0; i < count; i++)\r
        {\r
                hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);\r
+       #ifndef HDMI_VERSION_2
                vic = buf[1 + i] & 0x7f;\r
+       #else
+               vic = buf[1 + i] & 0xff;
+       #endif
                for(j = 0; j < ARRAY_SIZE(double_aspect_vic); j++)\r
                {\r
                        if(vic == double_aspect_vic[j])\r
@@ -192,14 +196,101 @@ static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
        }\r
        return E_HDMI_EDID_SUCCESS;\r
 }\r
+
+//Parse CEA Vendor Specific Data Block
+static int hdmi_edid_parse_cea_sdb(unsigned char * buf, struct hdmi_edid *pedid)
+{
+       unsigned int count = 0, cur_offset = 0, i = 0;
+       unsigned int IEEEOUI = 0;
+       unsigned int supports_ai,  dc_48bit, dc_36bit, dc_30bit, dc_y444;
+       unsigned int len_3d, len_4k;
+       unsigned char vic = 0;
+       const struct fb_videomode *mode;
+
+       count = buf[0] & 0x1F;
+       IEEEOUI = buf[3];
+       IEEEOUI <<= 8;
+       IEEEOUI += buf[2];
+       IEEEOUI <<= 8;
+       IEEEOUI += buf[1];
+       hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);
+       if(IEEEOUI == 0x0c03)
+               pedid->sink_hdmi = 1;
+
+       if (count > 5) {
+               pedid->deepcolor = (buf[6] >> 3) & 0x0F;
+               supports_ai = buf[6] >> 7;
+               dc_48bit = (buf[6] >> 6) & 0x1;
+               dc_36bit = (buf[6] >> 5) & 0x1;
+               dc_30bit = (buf[6] >> 4) & 0x1;
+               dc_y444 = (buf[6] >> 3) & 0x1;
+               hdmi_edid_debug("[EDID-CEA] supports_ai %d dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d \n", supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444);
+       }
+       if (count > 6) {
+               pedid->maxtmdsclock = buf[7] * 5000000;
+       }
+       if (count > 7) {
+               pedid->latency_fields_present = (buf[8] & 0x80) ? 1 : 0;
+               pedid->i_latency_fields_present = (buf[8] & 0x40) ? 1 : 0;
+               pedid->video_present = (buf[8] & 0x20) ? 1 : 0;
+       }
+
+       cur_offset = 9;
+       if (count >= cur_offset) {
+               if (pedid->latency_fields_present == 1) {
+                       pedid->video_latency = buf[cur_offset++];
+                       pedid->audio_latency = buf[cur_offset++];
+               }
+               if(count >= cur_offset && pedid->i_latency_fields_present) {
+                       pedid->interlaced_video_latency = buf[cur_offset++];
+                       pedid->interlaced_audio_latency = buf[cur_offset++];
+               }
+       }
+
+       if(pedid->video_present == 0)
+               return E_HDMI_EDID_SUCCESS;
+
+       if (count >= cur_offset) {
+               pedid->support_3d = (buf[cur_offset++] & 0x80) ? 1 : 0;
+
+               len_4k = (buf[cur_offset] >> 5) & 0x07;
+               len_3d = buf[cur_offset] & 0x1F;
+               cur_offset++;
+       }
+       if (count >= cur_offset && len_4k > 0) {
+               for(i = 0; i < len_4k; i++) {
+               #ifndef HDMI_VERSION_2
+                       vic = buf[cur_offset + i] & 0x7f;
+                       if (vic > 0 && vic < 5) {
+                               vic = (vic == 4) ? 98 : (96 - vic);
+                       }
+                       hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[cur_offset + i], vic, buf[cur_offset + i] >> 7);
+               #else
+                       vic = buf[cur_offset + i] & 0xff;
+                       hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[cur_offset + i], vic);
+               #endif
+                       if (vic) {
+                               mode = hdmi_vic_to_videomode(vic);
+                               if (mode) {
+                                       hdmi_add_videomode(mode, &pedid->modelist);
+                               }
+                       }
+               }
+               cur_offset += i;
+       }
+       if (count >= cur_offset && pedid->support_3d && len_3d > 0) {
+               //TODO Daisen wait to add
+       }
+
+       return E_HDMI_EDID_SUCCESS;
+}
+
 // Parse CEA 861 Serial Extension.\r
 static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *pedid)\r
 {\r
        unsigned int ddc_offset, native_dtd_num, cur_offset = 4;\r
        unsigned int underscan_support, baseaudio_support;\r
-       unsigned int tag, IEEEOUI = 0;\r
-//     unsigned int supports_ai,  dc_48bit, dc_36bit, dc_30bit, dc_y444;\r
-//     unsigned char vic;\r
+       unsigned int tag;
        \r
        if(buf == NULL)\r
                return E_HDMI_EDID_PARAM;\r
@@ -238,42 +329,7 @@ static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *
                                break;\r
                        case 0x03:      // Vendor Specific Data Block\r
                                hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");\r
-\r
-                               IEEEOUI = buf[cur_offset + 2 + 1];\r
-                               IEEEOUI <<= 8;\r
-                               IEEEOUI += buf[cur_offset + 1 + 1];\r
-                               IEEEOUI <<= 8;\r
-                               IEEEOUI += buf[cur_offset + 1];\r
-                               hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);\r
-                               if(IEEEOUI == 0x0c03)\r
-                                       pedid->sink_hdmi = 1;\r
-//                             if(count > 5)\r
-//                             {\r
-//                                     pedid->deepcolor = (buf[cur_offset + 5] >> 3) & 0x0F;\r
-//                                     supports_ai = buf[cur_offset + 5] >> 7;\r
-//                                     dc_48bit = (buf[cur_offset + 5] >> 6) & 0x1;\r
-//                                     dc_36bit = (buf[cur_offset + 5] >> 5) & 0x1;\r
-//                                     dc_30bit = (buf[cur_offset + 5] >> 4) & 0x1;\r
-//                                     dc_y444 = (buf[cur_offset + 5] >> 3) & 0x1;\r
-//                                     hdmi_edid_debug("[EDID-CEA] supports_ai %d dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d \n", supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444);\r
-//                             }\r
-//                             if(count > 6)\r
-//                                     pedid->maxtmdsclock = buf[cur_offset + 6] * 5000000;\r
-//                             if(count > 7)\r
-//                             {\r
-//                                     pedid->latency_fields_present = (buf[cur_offset + 7] & 0x80) ? 1:0;\r
-//                                     pedid->i_latency_fields_present = (buf[cur_offset + 7] & 0x40) ? 1:0;\r
-//                             }\r
-//                             if(count > 9 && pedid->latency_fields_present)\r
-//                             {\r
-//                                     pedid->video_latency = buf[cur_offset + 8];\r
-//                                     pedid->audio_latency = buf[cur_offset + 9];\r
-//                             }\r
-//                             if(count > 11 && pedid->i_latency_fields_present)\r
-//                             {\r
-//                                     pedid->interlaced_video_latency = buf[cur_offset + 10];\r
-//                                     pedid->interlaced_audio_latency = buf[cur_offset + 11];\r
-//                             }\r
+                               hdmi_edid_parse_cea_sdb(buf + cur_offset, pedid);
                                break;          \r
                        case 0x05:      // VESA DTC Data Block\r
                                hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");\r
index b0a68006e00453cc878f87de8f22ea634c2b8f21..0e5976f5c2067e1fbfc6c17da6cd1b5fc1a5267a 100755 (executable)
@@ -543,6 +543,45 @@ int hdmi_switch_fb(struct hdmi *hdmi, int vic)
        return rc;
 }
 
+/**
+ * hdmi_init_video_para: init video_para variable
+ *
+ * NOTES:
+ *This parameters should be modified according to need by user
+ */
+int hdmi_init_video_para(struct hdmi *hdmi_drv, struct hdmi_video_para *video)
+{
+       memset(video, 0, sizeof(struct hdmi_video_para));
+       video->vic = hdmi_drv->vic;
+       video->input_mode = VIDEO_INPUT_RGB_YCBCR_444;
+       video->input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
+       video->output_mode = hdmi_drv->edid.sink_hdmi;
+       video->format_3d = 0;   /*TODO modify according to EDID if need*/
+       video->pixel_repet = 0;
+
+       if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_16BIT)
+               video->color_depth = HDMI_COLOR_DEPTH_16BIT;
+       else if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_12BIT)
+               video->color_depth = HDMI_COLOR_DEPTH_12BIT;
+       else if (hdmi_drv->edid.deepcolor & HDMI_COLOR_DEPTH_10BIT)
+               video->color_depth = HDMI_COLOR_DEPTH_10BIT;
+       else
+               video->color_depth = HDMI_COLOR_DEPTH_8BIT;
+
+       if (hdmi_drv->edid.ycbcr444)
+               video->output_color = VIDEO_OUTPUT_YCBCR444;
+       else if (hdmi_drv->edid.ycbcr422)
+               video->output_color = VIDEO_OUTPUT_YCBCR422;
+       else
+               video->output_color = VIDEO_OUTPUT_RGB444;
+
+       /*For DVI, output RGB*/
+       if (hdmi_drv->edid.sink_hdmi == 0)
+               video->output_color = VIDEO_OUTPUT_RGB444;
+
+       return 0;
+}
+
 /**
  * hdmi_drv_register: init hdmi_drv variable
  *
index 4a99f1e92f79ee4963e2429499ea74eee9d4e10d..9d5c585f15005f08ab427501cbfc96437e118193 100755 (executable)
@@ -248,22 +248,7 @@ void hdmi_work(struct work_struct *work)
                                break;
                        case CONFIG_VIDEO:
                                hdmi->display = HDMI_DISABLE;
-                               video.vic = hdmi->vic;
-                               video.input_mode = VIDEO_INPUT_RGB_YCBCR_444;
-                               video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
-                               video.output_mode = hdmi->edid.sink_hdmi;
-                               video.format_3d = 0; //TODO modify read from EDID
-                               
-                               if(hdmi->edid.ycbcr444)
-                                       video.output_color = VIDEO_OUTPUT_YCBCR444;
-                               else if(hdmi->edid.ycbcr422)
-                                       video.output_color = VIDEO_OUTPUT_YCBCR422;
-                               else
-                                       video.output_color = VIDEO_OUTPUT_RGB444;
-                               // For DVI, output RGB
-                               if(hdmi->edid.sink_hdmi == 0)
-                                       video.output_color = VIDEO_OUTPUT_RGB444;
-                               
+                               hdmi_init_video_para(hdmi, &video);
                                rc = hdmi->config_video(hdmi, &video);
                                if(rc == HDMI_ERROR_SUCESS)
                                {