[Intel-gfx] [PATCH] drm/i915: Parsing logic for the Mipi sequence block

Vandana Kannan vandana.kannan at intel.com
Tue Dec 16 00:05:30 PST 2014


From: vkorjani <vikas.korjani at intel.com>

New parsing logic for the mipi sequence block for GOP
version 3 and above. The new version of the GOP includes
the pmic, power on/off sequence which are newly adding
to the existing sequences which are present.

Also, there are new fields which are added in
the sequence to indicate the sequence size.

Signed-off-by: vkorjani <vikas.korjani at intel.com>
Signed-off-by: Deepak M <m.deepak at intel.com>
Signed-off-by: Rafael Barbalho <rafael.barbalho at intel.com>
Cc:Daniel Vetter <daniel at ffwll.ch>
Cc:Jani Nikula <jani.nikula at intel.com>
---
 drivers/gpu/drm/i915/intel_bios.c          | 112 ++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_dsi_panel_vbt.c |   7 ++
 2 files changed, 100 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 3f17825..42300db 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -41,8 +41,10 @@ find_section(struct bdb_header *bdb, int section_id)
 {
 	u8 *base = (u8 *)bdb;
 	int index = 0;
-	u16 total, current_size;
+	u16 total;
+	u32 current_size;
 	u8 current_id;
+	u8 version;
 
 	/* skip to first section */
 	index += bdb->header_size;
@@ -53,7 +55,16 @@ find_section(struct bdb_header *bdb, int section_id)
 		current_id = *(base + index);
 		index++;
 
-		current_size = *((u16 *)(base + index));
+		if (current_id == BDB_MIPI_SEQUENCE) {
+			version = *(base + index + 2);
+			if (version >= 3)
+				current_size = *((u32 *)(base + index + 3));
+			else
+				current_size = *((u16 *)(base + index));
+		} else {
+			current_size = *((u16 *)(base + index));
+		}
+
 		index += 2;
 
 		if (index + current_size > total)
@@ -775,6 +786,51 @@ static u8 *goto_next_sequence(u8 *data, int *size)
 	return data;
 }
 
+static u8 *goto_next_sequence_v3(u8 *data, int *size)
+{
+	int tmp = *size;
+	int op_size;
+
+	if (--tmp < 0)
+		return NULL;
+
+	/* Skip the panel id and the sequence size */
+	data = data + 5;
+	while (*data != 0) {
+		u8 element_type = *data++;
+		switch (element_type) {
+			default:
+				DRM_ERROR("Unknown element type %d\n", element_type);
+			case MIPI_SEQ_ELEM_SEND_PKT:
+			case MIPI_SEQ_ELEM_DELAY:
+			case MIPI_SEQ_ELEM_GPIO:
+				/*
+				 * skip by this element payload size
+				 * skip elem id, command flag and data type
+				 */
+				op_size = *data++;
+				tmp = tmp - (op_size + 1);
+				if (tmp < 0)
+					return NULL;
+
+				/* skip by len */
+				data += op_size;
+				break;
+		}
+	}
+
+	/* goto next sequence or end of block byte */
+	if (--tmp < 0)
+		return NULL;
+
+	/* Skip the end element marker */
+	data++;
+
+	/* update amount of data left for the sequence block to be parsed */
+	*size = tmp;
+	return data;
+}
+
 static void
 parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 {
@@ -783,7 +839,7 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 	struct mipi_config *config;
 	struct mipi_pps_data *pps;
 	u8 *data, *seq_data;
-	int i, panel_id, seq_size;
+	int i, panel_id, panel_seq_size;
 	u16 block_size;
 
 	/* parse MIPI blocks only if LFP type is MIPI */
@@ -840,29 +896,40 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 
 	DRM_DEBUG_DRIVER("Found MIPI sequence block\n");
 
-	block_size = get_blocksize(sequence);
-
 	/*
 	 * parse the sequence block for individual sequences
 	 */
 	dev_priv->vbt.dsi.seq_version = sequence->version;
 
 	seq_data = &sequence->data[0];
+	if (dev_priv->vbt.dsi.seq_version >= 3) {
+		block_size = *((unsigned int *)seq_data);
+		seq_data = seq_data + 4;
+	} else
+		block_size = get_blocksize(sequence);
 
 	/*
 	 * sequence block is variable length and hence we need to parse and
 	 * get the sequence data for specific panel id
 	 */
 	for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) {
-		panel_id = *seq_data;
-		seq_size = *((u16 *) (seq_data + 1));
+		panel_id = *seq_data++;
+		if (dev_priv->vbt.dsi.seq_version >= 3) {
+			panel_seq_size = *((u32 *)seq_data);
+			seq_data += sizeof(u32);
+		} else {
+			panel_seq_size = *((u16 *)seq_data);
+			seq_data += sizeof(u16);
+		}
+
 		if (panel_id == panel_type)
 			break;
 
-		/* skip the sequence including seq header of 3 bytes */
-		seq_data = seq_data + 3 + seq_size;
+		seq_data += panel_seq_size;
+
 		if ((seq_data - &sequence->data[0]) > block_size) {
-			DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n");
+			DRM_ERROR("Sequence start is beyond seq block size\n");
+			DRM_ERROR("Corrupted sequence block\n");
 			return;
 		}
 	}
@@ -874,13 +941,12 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 
 	/* check if found sequence is completely within the sequence block
 	 * just being paranoid */
-	if (seq_size > block_size) {
+	if (panel_seq_size > block_size) {
 		DRM_ERROR("Corrupted sequence/size, bailing out\n");
 		return;
 	}
 
-	/* skip the panel id(1 byte) and seq size(2 bytes) */
-	dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL);
+	dev_priv->vbt.dsi.data = kmemdup(seq_data, panel_seq_size, GFP_KERNEL);
 	if (!dev_priv->vbt.dsi.data)
 		return;
 
@@ -889,29 +955,37 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 	 * There are only 5 types of sequences as of now
 	 */
 	data = dev_priv->vbt.dsi.data;
-	dev_priv->vbt.dsi.size = seq_size;
+	dev_priv->vbt.dsi.size = panel_seq_size;
 
 	/* two consecutive 0x00 indicate end of all sequences */
-	while (1) {
+	while (*data != 0) {
 		int seq_id = *data;
+		int seq_size;
+
 		if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) {
 			dev_priv->vbt.dsi.sequence[seq_id] = data;
 			DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id);
 		} else {
 			DRM_ERROR("undefined sequence\n");
-			goto err;
+			seq_size = *(data + 1);
+			if (dev_priv->vbt.dsi.seq_version >= 3) {
+				data = data + seq_size + 1;
+				continue;
+			} else
+				goto err;
 		}
 
 		/* partial parsing to skip elements */
-		data = goto_next_sequence(data, &seq_size);
+		if (dev_priv->vbt.dsi.seq_version >= 3)
+			data = goto_next_sequence_v3(data, &panel_seq_size);
+		else
+			data = goto_next_sequence(data, &panel_seq_size);
 
 		if (data == NULL) {
 			DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n");
 			goto err;
 		}
 
-		if (*data == 0)
-			break; /* end of sequence reached */
 	}
 
 	DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n");
diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
index 5493aef..f7e3777b 100644
--- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
@@ -234,6 +234,8 @@ static const char * const seq_name[] = {
 
 static void generic_exec_sequence(struct intel_dsi *intel_dsi, char *sequence)
 {
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	u8 *data = sequence;
 	fn_mipi_elem_exec mipi_elem_exec;
 	int index;
@@ -245,6 +247,8 @@ static void generic_exec_sequence(struct intel_dsi *intel_dsi, char *sequence)
 
 	/* go to the first element of the sequence */
 	data++;
+	if (dev_priv->vbt.dsi.seq_version >= 3)
+		data = data + 4;
 
 	/* parse each byte till we reach end of sequence byte - 0x00 */
 	while (1) {
@@ -258,6 +262,9 @@ static void generic_exec_sequence(struct intel_dsi *intel_dsi, char *sequence)
 		/* goto element payload */
 		data++;
 
+		if (dev_priv->vbt.dsi.seq_version >= 3)
+			data++;
+
 		/* execute the element specific rotines */
 		data = mipi_elem_exec(intel_dsi, data);
 
-- 
2.0.1



More information about the Intel-gfx mailing list