diff mbox

[MIPI,SEQ,PARSING,v3,07/13] drm/i915: Added support the v3 mipi sequence block

Message ID 1448923632-16760-8-git-send-email-m.deepak@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Deepak M Nov. 30, 2015, 10:47 p.m. UTC
From: vkorjani <vikas.korjani@intel.com>

The Block 53 of the VBT, which is the MIPI sequence block
has undergone a design change because of which the parsing
logic has to be changed.

The current code will handle the parsing of v3 and other
lower versions of the MIPI sequence block.

v2: rebase
v3: minor comments fixed.

Cc: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: vkorjani <vikas.korjani@intel.com>
Signed-off-by: Deepak M <m.deepak@intel.com>
---

Addressed most of the minor comments in this version,
except the one where Jani had suggested to change the
logic in the goto_next_sequence(), Thought of handling
this as a new patch after this series.

http://lists.freedesktop.org/archives/intel-gfx/2015-September/076273.html

 drivers/gpu/drm/i915/intel_bios.c          | 125 ++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/intel_bios.h          |   9 ++-
 drivers/gpu/drm/i915/intel_dsi_panel_vbt.c |   7 ++
 3 files changed, 120 insertions(+), 21 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 98b0e2a..5cfb862 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -745,6 +745,72 @@  static u8 *goto_next_sequence(u8 *data, int *size)
 	return data;
 }
 
+
+/*
+ *	Structure of single sequence in v3 version.
+ *	 ___________ _________ __________ ________ ________ 	_________
+ *	|	    |         | First    |Size of |Payload |	|End of |
+ *	| Sequence  | Size of | Opreation|First Op|First Op|	|Current|
+ *	| byte	    | Sequence|	byte     |byte    |byte    |	|Seq(00)|
+ *	|___________|_________|__________|________|________| ...|_______|
+ *	|  1 byte   | 4 Bytes | 1 byte   |1 bytes | Y byte |	|1 byte	|
+ *	|	    |	(X)   |		 |  (Y)   |	   |	|	|
+ *	|___________|_________|__________|________|________|    |_______|
+ *
+ *					 	  |<--Y--->|
+ *			      |<-----------------------X--------------->|
+ */
+
+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 byte */
+	data = data + 5;
+	tmp = tmp - 5;
+	while (*data != 0) {
+		u8 operation_type = *data++;
+
+		switch (operation_type) {
+		default:
+			DRM_ERROR("Unknown operation type %d\n", operation_type);
+		case MIPI_SEQ_ELEM_SEND_PKT:
+		case MIPI_SEQ_ELEM_DELAY:
+		case MIPI_SEQ_ELEM_GPIO:
+		case MIPI_SEQ_ELEM_I2C:
+		case MIPI_SEQ_ELEM_SPI:
+		case MIPI_SEQ_ELEM_PMIC:
+			/*
+			 * 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, const struct bdb_header *bdb)
 {
@@ -754,8 +820,8 @@  parse_mipi(struct drm_i915_private *dev_priv, const struct bdb_header *bdb)
 	const struct mipi_pps_data *pps;
 	u8 *data;
 	const u8 *seq_data;
-	int i, panel_id, seq_size;
-	u16 block_size;
+	int i, panel_id, panel_seq_size;
+	u32 block_size;
 
 	/* parse MIPI blocks only if LFP type is MIPI */
 	if (!dev_priv->vbt.has_mipi)
@@ -817,29 +883,40 @@  parse_mipi(struct drm_i915_private *dev_priv, const 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 \
+					corrupted sequence block\n");
 			return;
 		}
 	}
@@ -851,13 +928,14 @@  parse_mipi(struct drm_i915_private *dev_priv, const 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;
 
@@ -866,29 +944,36 @@  parse_mipi(struct drm_i915_private *dev_priv, const 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;
+			DRM_ERROR("undefined sequence - %d\n", seq_id);
+			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_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 4ec73f5..2422221 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -946,6 +946,12 @@  enum mipi_seq {
 	MIPI_SEQ_DISPLAY_ON,
 	MIPI_SEQ_DISPLAY_OFF,
 	MIPI_SEQ_DEASSERT_RESET,
+	MIPI_SEQ_BACKLIGHT_ON,
+	MIPI_SEQ_BACKLIGHT_OFF,
+	MIPI_SEQ_TEAR_ON,
+	MIPI_SEQ_TEAR_OFF,
+	MIPI_SEQ_POWER_ON,
+	MIPI_SEQ_POWER_OFF,
 	MIPI_SEQ_MAX
 };
 
@@ -955,7 +961,8 @@  enum mipi_seq_element {
 	MIPI_SEQ_ELEM_DELAY,
 	MIPI_SEQ_ELEM_GPIO,
 	MIPI_SEQ_ELEM_I2C,
-	MIPI_SEQ_ELEM_STATUS,
+	MIPI_SEQ_ELEM_SPI,
+	MIPI_SEQ_ELEM_PMIC,
 	MIPI_SEQ_ELEM_MAX
 };
 
diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
index 92d619a..eb0697b 100644
--- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
@@ -316,6 +316,8 @@  static const char * const seq_name[] = {
 
 static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
 {
+	struct drm_device *dev = intel_dsi->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	fn_mipi_elem_exec mipi_elem_exec;
 	int index;
 
@@ -326,6 +328,8 @@  static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
 
 	/* 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) {
@@ -339,6 +343,9 @@  static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
 		/* 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);