[Intel-gfx] [PATCH] drm/i915/vbt: Handle generic DTD block

Matt Roper matthew.d.roper at intel.com
Thu Oct 10 01:03:56 UTC 2019


VBT revision 229 adds a new "Generic DTD" block 58 and deprecates the
old LFP panel mode data in block 42.  Let's start parsing this block to
fill in the panel fixed mode on devices with a >=229 VBT.

Bspec: 54751
Bspec: 20148
Signed-off-by: Matt Roper <matthew.d.roper at intel.com>
---
I don't think we've encountered any devices that actually have a >=229
VBT yet, so this is just written to the spec and untested at the moment.

 drivers/gpu/drm/i915/display/intel_bios.c     | 84 ++++++++++++++++++-
 drivers/gpu/drm/i915/display/intel_vbt_defs.h | 32 +++++++
 2 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 9628b485b179..113911f050ee 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -202,6 +202,69 @@ get_lvds_fp_timing(const struct bdb_header *bdb,
 	return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs);
 }
 
+static struct drm_display_mode *
+parse_generic_dtd(struct drm_i915_private *dev_priv,
+		  const struct bdb_generic_dtd *generic_dtd)
+{
+	const struct bdb_generic_dtd_entry *dtd;
+	struct drm_display_mode *panel_fixed_mode;
+	int num_dtd;
+
+	if (generic_dtd->gdtd_size < sizeof(struct bdb_generic_dtd_entry)) {
+		DRM_ERROR("GDTD size %u is too small.\n",
+			  generic_dtd->gdtd_size);
+		return NULL;
+	} else if (generic_dtd->gdtd_size !=
+		   sizeof(struct bdb_generic_dtd_entry)) {
+		DRM_ERROR("Unexpected GDTD size %u\n", generic_dtd->gdtd_size);
+		/* DTD has unknown fields, but keep going */
+	}
+
+	num_dtd = (get_blocksize(generic_dtd) - sizeof(struct bdb_generic_dtd)) /
+		generic_dtd->gdtd_size;
+	if (dev_priv->vbt.panel_type > num_dtd) {
+		DRM_ERROR("Panel type %d not found in table of %d DTD's\n",
+			  dev_priv->vbt.panel_type, num_dtd);
+		return NULL;
+	} else {
+		dtd = &generic_dtd->dtd[dev_priv->vbt.panel_type];
+	}
+
+	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
+	if (!panel_fixed_mode)
+		return NULL;
+
+	panel_fixed_mode->hdisplay = dtd->hactive;
+	panel_fixed_mode->hsync_start =
+		panel_fixed_mode->hdisplay + dtd->hfront_porch;
+	panel_fixed_mode->hsync_end =
+		panel_fixed_mode->hsync_start + dtd->hsync;
+	panel_fixed_mode->htotal = panel_fixed_mode->hsync_end;
+
+	panel_fixed_mode->vdisplay = dtd->vactive;
+	panel_fixed_mode->vsync_start =
+		panel_fixed_mode->vdisplay + dtd->vfront_porch;
+	panel_fixed_mode->vsync_end =
+		panel_fixed_mode->vsync_start + dtd->vsync;
+	panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end;
+
+	panel_fixed_mode->clock = dtd->pixel_clock;
+	panel_fixed_mode->width_mm = dtd->width_mm;
+	panel_fixed_mode->height_mm = dtd->height_mm;
+
+	panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
+	drm_mode_set_name(panel_fixed_mode);
+
+	/*
+	 * FIXME: We probably need to set FLAG_[P/N][H/V]SYNC according to the
+	 * value in dtd->[h/v]sync_polarity, but the bspec doesn't tell us how
+	 * to actually interpret those bits yet.
+	 */
+
+	return panel_fixed_mode;
+}
+
+
 /* Try to find integrated panel data */
 static void
 parse_lfp_panel_data(struct drm_i915_private *dev_priv,
@@ -210,6 +273,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 	const struct bdb_lvds_options *lvds_options;
 	const struct bdb_lvds_lfp_data *lvds_lfp_data;
 	const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
+	const struct bdb_generic_dtd *generic_dtd;
 	const struct lvds_dvo_timing *panel_dvo_timing;
 	const struct lvds_fp_timing *fp_timing;
 	struct drm_display_mode *panel_fixed_mode;
@@ -262,6 +326,18 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 		break;
 	}
 
+	if (bdb->version >= 229) {
+		generic_dtd = find_section(bdb, BDB_GENERIC_DTD);
+		if (!generic_dtd)
+			return;
+
+		panel_fixed_mode = parse_generic_dtd(dev_priv, generic_dtd);
+		if (!ret)
+			return;
+
+		goto skip_legacy_lfp;
+	}
+
 	lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
 	if (!lvds_lfp_data)
 		return;
@@ -282,9 +358,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 
 	dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
 
-	DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
-	drm_mode_debug_printmodeline(panel_fixed_mode);
-
 	fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data,
 				       lvds_lfp_data_ptrs,
 				       panel_type);
@@ -297,6 +370,11 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 				      dev_priv->vbt.bios_lvds_val);
 		}
 	}
+
+skip_legacy_lfp:
+	DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
+	drm_mode_debug_printmodeline(panel_fixed_mode);
+
 }
 
 static void
diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
index dfcd156b5094..a508817f9df8 100644
--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
@@ -114,6 +114,7 @@ enum bdb_block_id {
 	BDB_LVDS_POWER			= 44,
 	BDB_MIPI_CONFIG			= 52,
 	BDB_MIPI_SEQUENCE		= 53,
+	BDB_GENERIC_DTD			= 58,
 	BDB_SKIP			= 254, /* VBIOS private block, ignore */
 };
 
@@ -808,4 +809,35 @@ struct bdb_mipi_sequence {
 	u8 data[0]; /* up to 6 variable length blocks */
 } __packed;
 
+/*
+ * Block 58 - Generic DTD Block
+ */
+
+struct bdb_generic_dtd_entry {
+	u32 pixel_clock;
+	u16 hactive;
+	u16 hblank;
+	u16 hfront_porch;
+	u16 hsync;
+	u16 vactive;
+	u16 vblank;
+	u16 vfront_porch;
+	u16 vsync;
+	u16 width_mm;
+	u16 height_mm;
+
+	/* Flags */
+	u8 rsvd_flags:4;
+	u8 vsync_polarity:2;
+	u8 hysnc_polarity:2;
+
+	u32 rsvd:24;
+} __packed;
+
+struct bdb_generic_dtd {
+	u32 gdtd_size:24;
+	struct bdb_generic_dtd_entry dtd[0];	/* up to 24 DTD's */
+} __packed;
+
+
 #endif /* _INTEL_VBT_DEFS_H_ */
-- 
2.21.0



More information about the Intel-gfx mailing list