|
@@ -947,6 +947,86 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Get len of pre-fixed deassert fragment from a v1 init OTP sequence,
|
|
|
+ * skip all delay + gpio operands and stop at the first DSI packet op.
|
|
|
+ */
|
|
|
+static int get_init_otp_deassert_fragment_len(struct drm_i915_private *dev_priv)
|
|
|
+{
|
|
|
+ const u8 *data = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
|
|
|
+ int index, len;
|
|
|
+
|
|
|
+ if (WARN_ON(!data || dev_priv->vbt.dsi.seq_version != 1))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* index = 1 to skip sequence byte */
|
|
|
+ for (index = 1; data[index] != MIPI_SEQ_ELEM_END; index += len) {
|
|
|
+ switch (data[index]) {
|
|
|
+ case MIPI_SEQ_ELEM_SEND_PKT:
|
|
|
+ return index == 1 ? 0 : index;
|
|
|
+ case MIPI_SEQ_ELEM_DELAY:
|
|
|
+ len = 5; /* 1 byte for operand + uint32 */
|
|
|
+ break;
|
|
|
+ case MIPI_SEQ_ELEM_GPIO:
|
|
|
+ len = 3; /* 1 byte for op, 1 for gpio_nr, 1 for value */
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence.
|
|
|
+ * The deassert must be done before calling intel_dsi_device_ready, so for
|
|
|
+ * these devices we split the init OTP sequence into a deassert sequence and
|
|
|
+ * the actual init OTP part.
|
|
|
+ */
|
|
|
+static void fixup_mipi_sequences(struct drm_i915_private *dev_priv)
|
|
|
+{
|
|
|
+ u8 *init_otp;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ /* Limit this to VLV for now. */
|
|
|
+ if (!IS_VALLEYVIEW(dev_priv))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Limit this to v1 vid-mode sequences */
|
|
|
+ if (dev_priv->vbt.dsi.config->is_cmd_mode ||
|
|
|
+ dev_priv->vbt.dsi.seq_version != 1)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Only do this if there are otp and assert seqs and no deassert seq */
|
|
|
+ if (!dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] ||
|
|
|
+ !dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] ||
|
|
|
+ dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET])
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* The deassert-sequence ends at the first DSI packet */
|
|
|
+ len = get_init_otp_deassert_fragment_len(dev_priv);
|
|
|
+ if (!len)
|
|
|
+ return;
|
|
|
+
|
|
|
+ DRM_DEBUG_KMS("Using init OTP fragment to deassert reset\n");
|
|
|
+
|
|
|
+ /* Copy the fragment, update seq byte and terminate it */
|
|
|
+ init_otp = (u8 *)dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
|
|
|
+ dev_priv->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL);
|
|
|
+ if (!dev_priv->vbt.dsi.deassert_seq)
|
|
|
+ return;
|
|
|
+ dev_priv->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET;
|
|
|
+ dev_priv->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END;
|
|
|
+ /* Use the copy for deassert */
|
|
|
+ dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] =
|
|
|
+ dev_priv->vbt.dsi.deassert_seq;
|
|
|
+ /* Replace the last byte of the fragment with init OTP seq byte */
|
|
|
+ init_otp[len - 1] = MIPI_SEQ_INIT_OTP;
|
|
|
+ /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */
|
|
|
+ dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
parse_mipi_sequence(struct drm_i915_private *dev_priv,
|
|
|
const struct bdb_header *bdb)
|
|
@@ -1016,6 +1096,8 @@ parse_mipi_sequence(struct drm_i915_private *dev_priv,
|
|
|
dev_priv->vbt.dsi.size = seq_size;
|
|
|
dev_priv->vbt.dsi.seq_version = sequence->version;
|
|
|
|
|
|
+ fixup_mipi_sequences(dev_priv);
|
|
|
+
|
|
|
DRM_DEBUG_DRIVER("MIPI related VBT parsing complete\n");
|
|
|
return;
|
|
|
|
|
@@ -1629,6 +1711,8 @@ void intel_bios_cleanup(struct drm_i915_private *dev_priv)
|
|
|
dev_priv->vbt.dsi.pps = NULL;
|
|
|
kfree(dev_priv->vbt.dsi.config);
|
|
|
dev_priv->vbt.dsi.config = NULL;
|
|
|
+ kfree(dev_priv->vbt.dsi.deassert_seq);
|
|
|
+ dev_priv->vbt.dsi.deassert_seq = NULL;
|
|
|
}
|
|
|
|
|
|
/**
|