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