HDMI: add support parse 4k_resolution and color_depth from EDID

This commit is contained in:
zwl
2014-04-23 22:42:01 +08:00
parent e678125c33
commit a2aee5d5d8
4 changed files with 157 additions and 56 deletions

View File

@@ -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);

View File

@@ -147,7 +147,11 @@ static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)
for(i = 0; i < count; i++)
{
hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);
#ifndef HDMI_VERSION_2
vic = buf[1 + i] & 0x7f;
#else
vic = buf[1 + i] & 0xff;
#endif
for(j = 0; j < ARRAY_SIZE(double_aspect_vic); j++)
{
if(vic == double_aspect_vic[j])
@@ -192,14 +196,101 @@ static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)
}
return E_HDMI_EDID_SUCCESS;
}
//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.
static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *pedid)
{
unsigned int ddc_offset, native_dtd_num, cur_offset = 4;
unsigned int underscan_support, baseaudio_support;
unsigned int tag, IEEEOUI = 0;
// unsigned int supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444;
// unsigned char vic;
unsigned int tag;
if(buf == NULL)
return E_HDMI_EDID_PARAM;
@@ -238,42 +329,7 @@ static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *
break;
case 0x03: // Vendor Specific Data Block
hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");
IEEEOUI = buf[cur_offset + 2 + 1];
IEEEOUI <<= 8;
IEEEOUI += buf[cur_offset + 1 + 1];
IEEEOUI <<= 8;
IEEEOUI += buf[cur_offset + 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[cur_offset + 5] >> 3) & 0x0F;
// supports_ai = buf[cur_offset + 5] >> 7;
// dc_48bit = (buf[cur_offset + 5] >> 6) & 0x1;
// dc_36bit = (buf[cur_offset + 5] >> 5) & 0x1;
// dc_30bit = (buf[cur_offset + 5] >> 4) & 0x1;
// dc_y444 = (buf[cur_offset + 5] >> 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[cur_offset + 6] * 5000000;
// if(count > 7)
// {
// pedid->latency_fields_present = (buf[cur_offset + 7] & 0x80) ? 1:0;
// pedid->i_latency_fields_present = (buf[cur_offset + 7] & 0x40) ? 1:0;
// }
// if(count > 9 && pedid->latency_fields_present)
// {
// pedid->video_latency = buf[cur_offset + 8];
// pedid->audio_latency = buf[cur_offset + 9];
// }
// if(count > 11 && pedid->i_latency_fields_present)
// {
// pedid->interlaced_video_latency = buf[cur_offset + 10];
// pedid->interlaced_audio_latency = buf[cur_offset + 11];
// }
hdmi_edid_parse_cea_sdb(buf + cur_offset, pedid);
break;
case 0x05: // VESA DTC Data Block
hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");

View File

@@ -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
*

View File

@@ -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)
{