msm:display:hdmi: Fix for EDID read/parse block[1]
HDCP enabled DVI monitors with block 0 and block 1 EDID always
switched to 640x480 even though they supported higher resolutions.
This patch reads DTD data from the correct offset from block[1]
and reads correct bits for interlaced format recognition.
CRs-Fixed: 290391
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 694450a..4203779 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -15,7 +15,7 @@
#include <linux/bitops.h>
#include <linux/mutex.h>
-#define DEBUG
+/* #define DEBUG */
#define DEV_DBG_PREFIX "EXT_COMMON: "
#include "msm_fb.h"
@@ -41,6 +41,36 @@
}
}
+#ifdef DEBUG_EDID
+/*
+ * Block 0 - 1920x1080p, 1360x768p
+ * Block 1 - 1280x720p, 1920x540i, 720x480p
+ */
+const char edid_blk0[0x100] = {
+0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x4C, 0x2D, 0x03, 0x05, 0x00,
+0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, 0x0A, 0xEE,
+0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54, 0xBD, 0xEF, 0x80, 0x71,
+0x4F, 0x81, 0x00, 0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0x95, 0x0F, 0xB3, 0x00,
+0xA9, 0x40, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45,
+0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x66, 0x21, 0x50, 0xB0, 0x51, 0x00,
+0x1B, 0x30, 0x40, 0x70, 0x36, 0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x00,
+0x00, 0x00, 0xFD, 0x00, 0x18, 0x4B, 0x1A, 0x51, 0x17, 0x00, 0x0A, 0x20, 0x20,
+0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x53, 0x41, 0x4D, 0x53,
+0x55, 0x4E, 0x47, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x8F};
+
+const char edid_blk1[0x100] = {
+0x02, 0x03, 0x1E, 0xF1, 0x46, 0x90, 0x04, 0x05, 0x03, 0x20, 0x22, 0x23, 0x09,
+0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0xE2, 0x00, 0x0F, 0x67, 0x03, 0x0C, 0x00,
+0x10, 0x00, 0xB8, 0x2D, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E,
+0x28, 0x55, 0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x01, 0x1D, 0x80, 0x18,
+0x71, 0x1C, 0x16, 0x20, 0x58, 0x2C, 0x25, 0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00,
+0x9E, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00,
+0xA0, 0x5A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF};
+#endif /* DEBUG_EDID */
+
const char *video_format_2string(uint32 format)
{
switch (format) {
@@ -644,7 +674,7 @@
uint32 offset = 4;
*len = 0;
- if (in_buf[2] == 4) { /* no non-DTD data present */
+ if ((in_buf[2] == 4) && (type != 2)) { /* no non-DTD data present */
DEV_WARN("EDID: no non-DTD data present\n");
return NULL;
}
@@ -658,7 +688,7 @@
}
offset += 1 + block_len;
}
- DEV_WARN("EDID: block=%d not found in EDID block\n", type);
+ DEV_WARN("EDID: type=%d block not found in EDID block\n", type);
return NULL;
}
@@ -823,13 +853,13 @@
max_num_of_elements = sizeof(hdmi_edid_disp_mode_lut)
/ sizeof(*hdmi_edid_disp_mode_lut);
- /* Break table in half and search using H Active */
- ndx = active_h < hdmi_edid_disp_mode_lut[max_num_of_elements / 2]
- .active_h ? 0 : max_num_of_elements / 2;
-
- /* EDID_TIMING_DESC_INTERLACE[0xD:8]: Relative Offset to the EDID
+ /* EDID_TIMING_DESC_INTERLACE[0x11:7]: Relative Offset to the EDID
* detailed timing descriptors - Interlace flag */
- interlaced = (data_buf[0xD] & 0x80) >> 7;
+ DEV_DBG("Interlaced mode byte data_buf[0x11]=[%x]\n", data_buf[0x11]);
+ /*
+ * CEA 861-D: interlaced bit is bit[7] of byte[0x11]
+ */
+ interlaced = (data_buf[0x11] & 0x80) >> 7;
DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__,
active_h, active_v, blank_h, blank_v, img_size_h, img_size_v,
@@ -890,6 +920,8 @@
uint32 video_format = HDMI_VFRMT_640x480p60_4_3;
boolean has480p = FALSE;
uint8 len;
+ const uint8 *edid_blk0 = &data_buf[0x0];
+ const uint8 *edid_blk1 = &data_buf[0x80];
const uint8 *svd = num_og_cea_blocks ?
hdmi_edid_find_block(data_buf+0x80, 2, &len) : NULL;
@@ -915,9 +947,12 @@
* descriptor */
/* EDID_DETAIL_TIMING_DESC_BLCK_SZ[0x12] - Each detailed timing
* descriptor has block size of 18 */
- while (4 > i && 0 != data_buf[0x36+desc_offset]) {
- hdmi_edid_detail_desc(data_buf+0x36+desc_offset,
+ while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+ hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
&video_format);
+ DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ video_format_2string(video_format));
add_supported_video_format(disp_mode_list,
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
@@ -927,6 +962,25 @@
}
} else if (1 == num_og_cea_blocks) {
uint32 desc_offset = 0;
+
+ /*
+ * Read from both block 0 and block 1
+ * Read EDID block[0] as above
+ */
+ while (4 > i && 0 != edid_blk0[0x36+desc_offset]) {
+ hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset,
+ &video_format);
+ DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ video_format_2string(video_format));
+ add_supported_video_format(disp_mode_list,
+ video_format);
+ if (video_format == HDMI_VFRMT_640x480p60_4_3)
+ has480p = TRUE;
+ desc_offset += 0x12;
+ ++i;
+ }
+
/* Parse block 1 - CEA extension byte offset of first
* detailed timing generation - offset is relevant to
* the offset of block 1 */
@@ -935,10 +989,13 @@
* extension first timing desc - indicate the offset of
* the first detailed timing descriptor */
/* EDID_BLOCK_SIZE = 0x80 Each page size in the EDID ROM */
- desc_offset = data_buf[0x82];
- while (0 != data_buf[0x80 + desc_offset]) {
- hdmi_edid_detail_desc(data_buf+0x36+desc_offset,
+ desc_offset = edid_blk1[0x02];
+ while (0 != edid_blk1[desc_offset]) {
+ hdmi_edid_detail_desc(edid_blk1+desc_offset,
&video_format);
+ DEV_DBG("[%s:%d] Block-1 Adding vid fmt = [%s]\n",
+ __func__, __LINE__,
+ video_format_2string(video_format));
add_supported_video_format(disp_mode_list,
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
@@ -958,9 +1015,12 @@
static int hdmi_common_read_edid_block(int block, uint8 *edid_buf)
{
- uint32 ndx, check_sum;
+ uint32 ndx, check_sum, print_len;
+#ifdef DEBUG
+ const u8 *b = edid_buf;
+#endif
int status = external_common_state->read_edid_block(block, edid_buf);
- if (status || block > 0)
+ if (status)
goto error;
/* Calculate checksum */
@@ -969,12 +1029,8 @@
check_sum += edid_buf[ndx];
if (check_sum & 0xFF) {
-#ifdef DEBUG
- const u8 *b = edid_buf;
-#endif
DEV_ERR("%s: failed CHECKSUM (read:%x, expected:%x)\n",
__func__, (uint8)edid_buf[0x7F], (uint8)check_sum);
-
#ifdef DEBUG
for (ndx = 0; ndx < 0x100; ndx += 16)
DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x "
@@ -988,6 +1044,16 @@
status = -EPROTO;
goto error;
}
+ print_len = 0x80;
+ for (ndx = 0; ndx < print_len; ndx += 16)
+ DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n", ndx, ndx+15,
+ b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3],
+ b[ndx+4], b[ndx+5], b[ndx+6], b[ndx+7],
+ b[ndx+8], b[ndx+9], b[ndx+10], b[ndx+11],
+ b[ndx+12], b[ndx+13], b[ndx+14], b[ndx+15]);
+
error:
return status;
@@ -1043,7 +1109,7 @@
external_common_state->hdmi_sink ? "no" : "yes");
break;
case 1: /* Read block 1 */
- status = hdmi_common_read_edid_block(1, edid_buf+0x80);
+ status = hdmi_common_read_edid_block(1, &edid_buf[0x80]);
if (status) {
DEV_ERR("%s: ddc read block(1) failed: %d\n", __func__,
status);