From 83a7280ebc359726d4b79b8772c9fddd7fd03f43 Mon Sep 17 00:00:00 2001 From: Pradeep Bhat Date: Fri, 28 Mar 2014 10:14:57 +0530 Subject: drm/i915: Adding VBT fields to support eDP DRRS feature This patch reads the DRRS support and Mode type from VBT fields. The read information will be stored in VBT struct during BIOS parsing. The above functionality is needed for decision making whether DRRS feature is supported in i915 driver for eDP panels. This information helps us decide if seamless DRRS can be done at runtime to support certain power saving features. This patch was tested by setting necessary bit in VBT struct and merging the new VBT with system BIOS so that we can read the value. v2: Incorporated review comments from Chris Wilson Removed "intel_" as a prefix for DRRS specific declarations. v3: Incorporated Jani's review comments Removed function which deducts drrs mode from panel_type. Modified some print statements. Made changes to use DRRS_NOT_SUPPORTED as 0 instead of -1. v4: Incorporated Jani's review comments. Modifications around setting vbt drrs_type. Signed-off-by: Pradeep Bhat Signed-off-by: Vandana Kannan Acked-by: Jesse Barnes Cc: Jani Nikula [danvet: Drop the misleading/redundant comment about the added drrs field in the vbt struct as discussed with Jani on irc.] Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_bios.c') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 4867f4cc093..9b986775c4b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -206,7 +206,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, const struct lvds_dvo_timing *panel_dvo_timing; const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; - int i, downclock; + int i, downclock, drrs_mode; lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); if (!lvds_options) @@ -218,6 +218,28 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, panel_type = lvds_options->panel_type; + drrs_mode = (lvds_options->dps_panel_type_bits + >> (panel_type * 2)) & MODE_MASK; + /* + * VBT has static DRRS = 0 and seamless DRRS = 2. + * The below piece of code is required to adjust vbt.drrs_type + * to match the enum drrs_support_type. + */ + switch (drrs_mode) { + case 0: + dev_priv->vbt.drrs_type = STATIC_DRRS_SUPPORT; + DRM_DEBUG_KMS("DRRS supported mode is static\n"); + break; + case 2: + dev_priv->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT; + DRM_DEBUG_KMS("DRRS supported mode is seamless\n"); + break; + default: + dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; + DRM_DEBUG_KMS("DRRS not supported (VBT input)\n"); + break; + } + lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); if (!lvds_lfp_data) return; @@ -516,6 +538,16 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (driver->dual_frequency) dev_priv->render_reclock_avail = true; + + DRM_DEBUG_KMS("DRRS State Enabled:%d\n", driver->drrs_enabled); + /* + * If DRRS is not supported, drrs_type has to be set to 0. + * This is because, VBT is configured in such a way that + * static DRRS is 0 and DRRS not supported is represented by + * driver->drrs_enabled=false + */ + if (!driver->drrs_enabled) + dev_priv->vbt.drrs_type = DRRS_NOT_SUPPORTED; } static void -- cgit v1.2.3-70-g09d2 From d3b542fcfc72d7724585e3fd2c5e75351bc3df47 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Mon, 14 Apr 2014 11:00:34 +0530 Subject: drm/i915: Add parsing support for new MIPI blocks in VBT The parser extracts the config block(#52) and sequence(#53) data and store in private data structures. v2: Address review comments by Jani - adjust code for the structure changes for bdb_mipi_config - add boundry and buffer overflow checks as suggested - use kmemdup instead of kmalloc and memcpy v3: More strict check while parsing VBT - Ensure that at anytime we do not go beyond sequence block while parsing - On unknown element fail the whole parsing v4: Style changes and spell check mostly as suggested by Jani Signed-off-by: Shobhit Kumar Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++ drivers/gpu/drm/i915/intel_bios.c | 204 +++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_bios.h | 31 ++++++ 3 files changed, 236 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_bios.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 761fc53e604..92c30950c2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1169,6 +1169,12 @@ struct intel_vbt_data { /* MIPI DSI */ struct { u16 panel_id; + struct mipi_config *config; + struct mipi_pps_data *pps; + u8 seq_version; + u32 size; + u8 *data; + u8 *sequence[MIPI_SEQ_MAX]; } dsi; int crt_ddc_pin; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 9b986775c4b..f491e363e84 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -626,19 +626,213 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) } } +static u8 *goto_next_sequence(u8 *data, int *size) +{ + u16 len; + int tmp = *size; + + if (--tmp < 0) + return NULL; + + /* goto first element */ + data++; + while (1) { + switch (*data) { + case MIPI_SEQ_ELEM_SEND_PKT: + /* + * skip by this element payload size + * skip elem id, command flag and data type + */ + if ((tmp = tmp - 5) < 0) + return NULL; + + data += 3; + len = *((u16 *)data); + + if ((tmp = tmp - len) < 0) + return NULL; + + /* skip by len */ + data = data + 2 + len; + break; + case MIPI_SEQ_ELEM_DELAY: + /* skip by elem id, and delay is 4 bytes */ + if ((tmp = tmp - 5) < 0) + return NULL; + + data += 5; + break; + case MIPI_SEQ_ELEM_GPIO: + if ((tmp = tmp - 3) < 0) + return NULL; + + data += 3; + break; + default: + DRM_ERROR("Unknown element\n"); + return NULL; + } + + /* end of sequence ? */ + if (*data == 0) + break; + } + + /* goto next sequence or end of block byte */ + if (--tmp < 0) + return NULL; + + 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) { - struct bdb_mipi *mipi; + struct bdb_mipi_config *start; + struct bdb_mipi_sequence *sequence; + struct mipi_config *config; + struct mipi_pps_data *pps; + u8 *data, *seq_data; + int i, panel_id, seq_size; + u16 block_size; + + /* Initialize this to undefined indicating no generic MIPI support */ + dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; + + /* Block #40 is already parsed and panel_fixed_mode is + * stored in dev_priv->lfp_lvds_vbt_mode + * resuse this when needed + */ - mipi = find_section(bdb, BDB_MIPI_CONFIG); - if (!mipi) { - DRM_DEBUG_KMS("No MIPI BDB found"); + /* Parse #52 for panel index used from panel_type already + * parsed + */ + start = find_section(bdb, BDB_MIPI_CONFIG); + if (!start) { + DRM_DEBUG_KMS("No MIPI config BDB found"); return; } - /* XXX: add more info */ + DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n", + panel_type); + + /* + * get hold of the correct configuration block and pps data as per + * the panel_type as index + */ + config = &start->config[panel_type]; + pps = &start->pps[panel_type]; + + /* store as of now full data. Trim when we realise all is not needed */ + dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); + if (!dev_priv->vbt.dsi.config) + return; + + dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); + if (!dev_priv->vbt.dsi.pps) { + kfree(dev_priv->vbt.dsi.config); + return; + } + + /* We have mandatory mipi config blocks. Initialize as generic panel */ dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; + + /* Check if we have sequence block as well */ + sequence = find_section(bdb, BDB_MIPI_SEQUENCE); + if (!sequence) { + DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n"); + return; + } + + 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]; + + /* + * 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)); + if (panel_id == panel_type) + break; + + /* skip the sequence including seq header of 3 bytes */ + seq_data = seq_data + 3 + seq_size; + if ((seq_data - &sequence->data[0]) > block_size) { + DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n"); + return; + } + } + + if (i == MAX_MIPI_CONFIGURATIONS) { + DRM_ERROR("Sequence block detected but no valid configuration\n"); + return; + } + + /* check if found sequence is completely within the sequence block + * just being paranoid */ + if (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); + if (!dev_priv->vbt.dsi.data) + return; + + /* + * loop into the sequence data and split into multiple sequneces + * There are only 5 types of sequences as of now + */ + data = dev_priv->vbt.dsi.data; + dev_priv->vbt.dsi.size = seq_size; + + /* two consecutive 0x00 indicate end of all sequences */ + while (1) { + int seq_id = *data; + 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; + } + + /* partial parsing to skip elements */ + data = goto_next_sequence(data, &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"); + return; +err: + kfree(dev_priv->vbt.dsi.data); + dev_priv->vbt.dsi.data = NULL; + + /* error during parsing so set all pointers to null + * because of partial parsing */ + memset(dev_priv->vbt.dsi.sequence, 0, MIPI_SEQ_MAX); } static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index d02e5f93c36..15ae3b50528 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -896,4 +896,35 @@ struct bdb_mipi_sequence { u8 data[0]; }; +/* MIPI Sequnece Block definitions */ +enum mipi_seq { + MIPI_SEQ_UNDEFINED = 0, + MIPI_SEQ_ASSERT_RESET, + MIPI_SEQ_INIT_OTP, + MIPI_SEQ_DISPLAY_ON, + MIPI_SEQ_DISPLAY_OFF, + MIPI_SEQ_DEASSERT_RESET, + MIPI_SEQ_MAX +}; + +enum mipi_seq_element { + MIPI_SEQ_ELEM_UNDEFINED = 0, + MIPI_SEQ_ELEM_SEND_PKT, + MIPI_SEQ_ELEM_DELAY, + MIPI_SEQ_ELEM_GPIO, + MIPI_SEQ_ELEM_STATUS, + MIPI_SEQ_ELEM_MAX +}; + +enum mipi_gpio_pin_index { + MIPI_GPIO_UNDEFINED = 0, + MIPI_GPIO_PANEL_ENABLE, + MIPI_GPIO_BL_ENABLE, + MIPI_GPIO_PWM_ENABLE, + MIPI_GPIO_RESET_N, + MIPI_GPIO_PWR_DOWN_R, + MIPI_GPIO_STDBY_RST_N, + MIPI_GPIO_MAX +}; + #endif /* _I830_BIOS_H_ */ -- cgit v1.2.3-70-g09d2 From b0256cdcb4c3aa1fe141d30cbf232872282cbb64 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 15 Apr 2014 13:54:07 +0530 Subject: drm/i915: Code cleanup patch to fix checkpatch errors This cleans up the checkpatch errors for the merged commit - commit d3b542fcfc72d7724585e3fd2c5e75351bc3df47 Author: Shobhit Kumar Date: Mon Apr 14 11:00:34 2014 +0530 drm/i915: Add parsing support for new MIPI blocks in VBT Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_bios.c') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index f491e363e84..054dbe7fdf9 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -643,13 +643,15 @@ static u8 *goto_next_sequence(u8 *data, int *size) * skip by this element payload size * skip elem id, command flag and data type */ - if ((tmp = tmp - 5) < 0) + tmp -= 5; + if (tmp < 0) return NULL; data += 3; len = *((u16 *)data); - if ((tmp = tmp - len) < 0) + tmp -= len; + if (tmp < 0) return NULL; /* skip by len */ @@ -657,13 +659,15 @@ static u8 *goto_next_sequence(u8 *data, int *size) break; case MIPI_SEQ_ELEM_DELAY: /* skip by elem id, and delay is 4 bytes */ - if ((tmp = tmp - 5) < 0) + tmp -= 5; + if (tmp < 0) return NULL; data += 5; break; case MIPI_SEQ_ELEM_GPIO: - if ((tmp = tmp - 3) < 0) + tmp -= 3; + if (tmp < 0) return NULL; data += 3; -- cgit v1.2.3-70-g09d2 From d1f13fd261f4490b3b69c1da87711fd3813c2a9f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 18 Apr 2014 18:04:23 -0300 Subject: drm/i915: Validate BDB section before reading Make sure that the whole BDB section is within the MMIO region prior to accessing it contents. That we don't read outside of the secion is left up to the individual section parsers. Signed-off-by: Chris Wilson Signed-off-by: Rodrigo Vivi Reviewed-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_bios.c') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index fba9efd09e8..148d8a786c8 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -49,13 +49,19 @@ find_section(struct bdb_header *bdb, int section_id) total = bdb->bdb_size; /* walk the sections looking for section_id */ - while (index < total) { + while (index + 3 < total) { current_id = *(base + index); index++; + current_size = *((u16 *)(base + index)); index += 2; + + if (index + current_size > total) + return NULL; + if (current_id == section_id) return base + index; + index += current_size; } -- cgit v1.2.3-70-g09d2 From 3dd4e846042063bf5481df87a00356ee820288de Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 18 Apr 2014 18:04:22 -0300 Subject: drm/i915: Validate VBT header before trusting it Be we read and chase pointers from the VBT, it is prudent to make sure that those accesses are wholly contained within the MMIO region, or else we may cause a kernel panic during boot. Signed-off-by: Chris Wilson Signed-off-by: Rodrigo Vivi Reviewed-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.c | 68 ++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_bios.c') diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 148d8a786c8..2945f57c53e 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1105,6 +1105,46 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = { { } }; +static struct bdb_header *validate_vbt(char *base, size_t size, + struct vbt_header *vbt, + const char *source) +{ + size_t offset; + struct bdb_header *bdb; + + if (vbt == NULL) { + DRM_DEBUG_DRIVER("VBT signature missing\n"); + return NULL; + } + + offset = (char *)vbt - base; + if (offset + sizeof(struct vbt_header) > size) { + DRM_DEBUG_DRIVER("VBT header incomplete\n"); + return NULL; + } + + if (memcmp(vbt->signature, "$VBT", 4)) { + DRM_DEBUG_DRIVER("VBT invalid signature\n"); + return NULL; + } + + offset += vbt->bdb_offset; + if (offset + sizeof(struct bdb_header) > size) { + DRM_DEBUG_DRIVER("BDB header incomplete\n"); + return NULL; + } + + bdb = (struct bdb_header *)(base + offset); + if (offset + bdb->bdb_size > size) { + DRM_DEBUG_DRIVER("BDB incomplete\n"); + return NULL; + } + + DRM_DEBUG_KMS("Using VBT from %s: %20s\n", + source, vbt->signature); + return bdb; +} + /** * intel_parse_bios - find VBT and initialize settings from the BIOS * @dev: DRM device @@ -1128,20 +1168,13 @@ intel_parse_bios(struct drm_device *dev) init_vbt_defaults(dev_priv); /* XXX Should this validation be moved to intel_opregion.c? */ - if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) { - struct vbt_header *vbt = dev_priv->opregion.vbt; - if (memcmp(vbt->signature, "$VBT", 4) == 0) { - DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n", - vbt->signature); - bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset); - } else - dev_priv->opregion.vbt = NULL; - } + if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) + bdb = validate_vbt((char *)dev_priv->opregion.header, OPREGION_SIZE, + (struct vbt_header *)dev_priv->opregion.vbt, + "OpRegion"); if (bdb == NULL) { - struct vbt_header *vbt = NULL; - size_t size; - int i; + size_t i, size; bios = pci_map_rom(pdev, &size); if (!bios) @@ -1149,19 +1182,18 @@ intel_parse_bios(struct drm_device *dev) /* Scour memory looking for the VBT signature */ for (i = 0; i + 4 < size; i++) { - if (!memcmp(bios + i, "$VBT", 4)) { - vbt = (struct vbt_header *)(bios + i); + if (memcmp(bios + i, "$VBT", 4) == 0) { + bdb = validate_vbt(bios, size, + (struct vbt_header *)(bios + i), + "PCI ROM"); break; } } - if (!vbt) { - DRM_DEBUG_DRIVER("VBT signature missing\n"); + if (!bdb) { pci_unmap_rom(pdev, bios); return -1; } - - bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); } /* Grab useful general definitions */ -- cgit v1.2.3-70-g09d2 From 3e6bd01178928cae58354ce7a6d18ade8b7b4be7 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Tue, 27 May 2014 19:33:59 +0530 Subject: drm/i915: Detect if MIPI panel based on VBT and initialize only if present It seems by default the VBT has MIPI configuration block as well. The Generic driver will assume always MIPI if MIPI configuration block is found. This is causing probelm when actually there is eDP. Fix this by looking into general definition block which will have device configurations. From here we can figure out what is the LFP type and initialize MIPI only if MIPI is found. v2: Addressed review comments by Damien - Moved PORT definitions to intel_bios.h and renamed as DVO_PORT_MIPIA - renamed is_mipi to has_mipi and moved definition as suggested - Check has_mipi inside parse_mipi and intel_dsi_init insted of outside v3: Make has_mipi as a bitfield as suggested Signed-off-by: Shobhit Kumar Reviewed-by: Damien Lespiau [danvet: fold in conditions to pack everything neatly below 80 chars.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_bios.c | 13 +++++++++++++ drivers/gpu/drm/i915/intel_bios.h | 4 ++++ drivers/gpu/drm/i915/intel_dsi.c | 4 ++++ 4 files changed, 23 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_bios.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8f68678f361..4063ee1dec1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1222,6 +1222,7 @@ struct intel_vbt_data { unsigned int lvds_use_ssc:1; unsigned int display_clock_mode:1; unsigned int fdi_rx_polarity_inverted:1; + unsigned int has_mipi:1; int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ @@ -1245,6 +1246,7 @@ struct intel_vbt_data { /* MIPI DSI */ struct { + u16 port; u16 panel_id; struct mipi_config *config; struct mipi_pps_data *pps; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 2945f57c53e..3d43da6d348 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -720,6 +720,10 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) int i, panel_id, seq_size; u16 block_size; + /* parse MIPI blocks only if LFP type is MIPI */ + if (!dev_priv->vbt.has_mipi) + return; + /* Initialize this to undefined indicating no generic MIPI support */ dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; @@ -1035,6 +1039,15 @@ parse_device_mapping(struct drm_i915_private *dev_priv, /* skip the device block if device type is invalid */ continue; } + + if (p_child->common.dvo_port >= DVO_PORT_MIPIA + && p_child->common.dvo_port <= DVO_PORT_MIPID + &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) { + DRM_DEBUG_KMS("Found MIPI as LFP\n"); + dev_priv->vbt.has_mipi = 1; + dev_priv->vbt.dsi.port = p_child->common.dvo_port; + } + child_dev_ptr = dev_priv->vbt.child_dev + count; count++; memcpy((void *)child_dev_ptr, (void *)p_child, diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 6009debebaa..b9866779633 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -743,6 +743,10 @@ int intel_parse_bios(struct drm_device *dev); #define DVO_PORT_DPC 8 #define DVO_PORT_DPD 9 #define DVO_PORT_DPA 10 +#define DVO_PORT_MIPIA 21 +#define DVO_PORT_MIPIB 22 +#define DVO_PORT_MIPIC 23 +#define DVO_PORT_MIPID 24 /* Block 52 contains MIPI Panel info * 6 such enteries will there. Index into correct diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index e73bec61690..944a4211aa9 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -660,6 +660,10 @@ bool intel_dsi_init(struct drm_device *dev) DRM_DEBUG_KMS("\n"); + /* There is no detection method for MIPI so rely on VBT */ + if (!dev_priv->vbt.has_mipi) + return false; + intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL); if (!intel_dsi) return false; -- cgit v1.2.3-70-g09d2