diff mbox series

[CI,02/10] drm/i915/bios: Start to support two integrated panels

Message ID 20210729215545.192606-2-jose.souza@intel.com (mailing list archive)
State New, archived
Headers show
Series [CI,01/10] drm/i915/bios: Allow DSI ports to be parsed by parse_ddi_port() | expand

Commit Message

Souza, Jose July 29, 2021, 9:55 p.m. UTC
VBT has support for up two integrated panels but i915 only supports one.

So here stating to add the basic support for two integrated panels
and moving the DRRS to ddi_vbt_port_info instead of keeping a global
one.
Other VBT blocks will be converted in following patches.

While at is also nucking lvds_dither as it is not used.

Reviewed-by: Matt Atwood <matthew.s.atwood@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 drivers/gpu/drm/i915/display/intel_bios.c     | 185 +++++++++++++-----
 drivers/gpu/drm/i915/display/intel_bios.h     |   2 +
 drivers/gpu/drm/i915/display/intel_dp.c       |   5 +-
 drivers/gpu/drm/i915/display/intel_vbt_defs.h |   3 +
 drivers/gpu/drm/i915/i915_drv.h               |   5 +-
 5 files changed, 150 insertions(+), 50 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index a6cb33f847a43..9439bfe32b136 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -211,22 +211,20 @@  get_lvds_fp_timing(const struct bdb_header *bdb,
 	return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs);
 }
 
-/* Parse general panel options */
-static void
-parse_panel_options(struct drm_i915_private *i915,
-		    const struct bdb_header *bdb)
+/*
+ * Parse and set vbt.panel_type, it will be used by the VBT blocks that are
+ * not being called from parse_integrated_panel() yet.
+ */
+static void parse_panel_type(struct drm_i915_private *i915,
+			     const struct bdb_header *bdb)
 {
 	const struct bdb_lvds_options *lvds_options;
-	int panel_type;
-	int drrs_mode;
-	int ret;
+	int ret, panel_type;
 
 	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
 	if (!lvds_options)
 		return;
 
-	i915->vbt.lvds_dither = lvds_options->pixel_dither;
-
 	ret = intel_opregion_get_panel_type(i915);
 	if (ret >= 0) {
 		drm_WARN_ON(&i915->drm, ret > 0xf);
@@ -246,9 +244,25 @@  parse_panel_options(struct drm_i915_private *i915,
 	}
 
 	i915->vbt.panel_type = panel_type;
+}
+
+/* Parse general panel options */
+static void
+parse_panel_options(struct drm_i915_private *i915,
+		    const struct bdb_header *bdb,
+		    struct ddi_vbt_port_info *info,
+		    int panel_index)
+{
+	const struct bdb_lvds_options *lvds_options;
+	int drrs_mode;
+
+	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
+	if (!lvds_options)
+		return;
+
+	drrs_mode = lvds_options->dps_panel_type_bits >> (panel_index * 2);
+	drrs_mode &= MODE_MASK;
 
-	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
@@ -256,16 +270,16 @@  parse_panel_options(struct drm_i915_private *i915,
 	 */
 	switch (drrs_mode) {
 	case 0:
-		i915->vbt.drrs_type = STATIC_DRRS_SUPPORT;
+		info->drrs_type = STATIC_DRRS_SUPPORT;
 		drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n");
 		break;
 	case 2:
-		i915->vbt.drrs_type = SEAMLESS_DRRS_SUPPORT;
+		info->drrs_type = SEAMLESS_DRRS_SUPPORT;
 		drm_dbg_kms(&i915->drm,
 			    "DRRS supported mode is seamless\n");
 		break;
 	default:
-		i915->vbt.drrs_type = DRRS_NOT_SUPPORTED;
+		info->drrs_type = DRRS_NOT_SUPPORTED;
 		drm_dbg_kms(&i915->drm,
 			    "DRRS not supported (VBT input)\n");
 		break;
@@ -710,28 +724,42 @@  parse_driver_features(struct drm_i915_private *i915,
 			i915->vbt.int_lvds_support = 0;
 	}
 
-	if (bdb->version < 228) {
-		drm_dbg_kms(&i915->drm, "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)
-			i915->vbt.drrs_type = DRRS_NOT_SUPPORTED;
-
+	if (bdb->version < 228)
 		i915->vbt.psr.enable = driver->psr_enabled;
-	}
+}
+
+static void
+parse_driver_features_drrs_only(struct drm_i915_private *i915,
+				const struct bdb_header *bdb,
+				struct ddi_vbt_port_info *info)
+{
+	const struct bdb_driver_features *driver;
+
+	if (bdb->version >= 228)
+		return;
+
+	driver = find_section(bdb, BDB_DRIVER_FEATURES);
+	if (!driver)
+		return;
+
+	drm_dbg_kms(&i915->drm, "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)
+		info->drrs_type = DRRS_NOT_SUPPORTED;
 }
 
 static void
 parse_power_conservation_features(struct drm_i915_private *i915,
-				  const struct bdb_header *bdb)
+				  const struct bdb_header *bdb,
+				  struct ddi_vbt_port_info *info,
+				  int panel_index)
 {
 	const struct bdb_lfp_power *power;
-	u8 panel_type = i915->vbt.panel_type;
 
 	if (bdb->version < 228)
 		return;
@@ -740,7 +768,7 @@  parse_power_conservation_features(struct drm_i915_private *i915,
 	if (!power)
 		return;
 
-	i915->vbt.psr.enable = power->psr & BIT(panel_type);
+	i915->vbt.psr.enable = power->psr & BIT(panel_index);
 
 	/*
 	 * If DRRS is not supported, drrs_type has to be set to 0.
@@ -748,11 +776,11 @@  parse_power_conservation_features(struct drm_i915_private *i915,
 	 * static DRRS is 0 and DRRS not supported is represented by
 	 * power->drrs & BIT(panel_type)=false
 	 */
-	if (!(power->drrs & BIT(panel_type)))
-		i915->vbt.drrs_type = DRRS_NOT_SUPPORTED;
+	if (!(power->drrs & BIT(panel_index)))
+		info->drrs_type = DRRS_NOT_SUPPORTED;
 
 	if (bdb->version >= 232)
-		i915->vbt.edp.hobl = power->hobl & BIT(panel_type);
+		i915->vbt.edp.hobl = power->hobl & BIT(panel_index);
 }
 
 static void
@@ -1887,6 +1915,74 @@  static bool is_port_valid(struct drm_i915_private *i915, enum port port)
 	return true;
 }
 
+static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt)
+{
+	const void *_vbt = vbt;
+
+	return _vbt + vbt->bdb_offset;
+}
+
+static int
+get_lfp_panel_index(struct drm_i915_private *i915,
+		    const struct bdb_header *bdb, int lfp_panel_instance)
+{
+	const struct bdb_lvds_options *lvds_options;
+
+	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
+	if (!lvds_options)
+		return -1;
+
+	switch (lfp_panel_instance) {
+	case 1:
+		return lvds_options->panel_type;
+	case 2:
+		return lvds_options->panel_type2;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+static void parse_integrated_panel(struct drm_i915_private *i915,
+				   struct intel_bios_encoder_data *devdata,
+				   struct ddi_vbt_port_info *info)
+{
+	const struct vbt_header *vbt = i915->opregion.vbt;
+	const struct bdb_header *bdb;
+	int lfp_inst = 0, panel_index, opregion_panel_index;
+
+	if (devdata->child.handle == HANDLE_LFP_1)
+		lfp_inst = 1;
+	else if (devdata->child.handle == HANDLE_LFP_2)
+		lfp_inst = 2;
+
+	if (lfp_inst == 0)
+		return;
+
+	bdb = get_bdb_header(vbt);
+	panel_index = get_lfp_panel_index(i915, bdb, lfp_inst);
+
+	opregion_panel_index = intel_opregion_get_panel_type(i915);
+	/*
+	 * TODO: the current implementation always use the panel index from
+	 * opregion if available due to issues with old platforms.
+	 * But this do not supports two panels and in SKL or newer I never saw a
+	 * system were this call returns a valid value.
+	 * So will change this to only use opregion up to BDW in a separated
+	 * commit.
+	 */
+	if (opregion_panel_index >= 0)
+		panel_index = opregion_panel_index;
+
+	if (panel_index == -1)
+		return;
+
+	parse_panel_options(i915, bdb, info, panel_index);
+	parse_power_conservation_features(i915, bdb, info, panel_index);
+	parse_driver_features_drrs_only(i915, bdb, info);
+}
+
 static void parse_ddi_port(struct drm_i915_private *i915,
 			   struct intel_bios_encoder_data *devdata)
 {
@@ -2018,6 +2114,8 @@  static void parse_ddi_port(struct drm_i915_private *i915,
 			    port_name(port), info->dp_max_link_rate);
 	}
 
+	parse_integrated_panel(i915, devdata, info);
+
 	info->devdata = devdata;
 }
 
@@ -2144,9 +2242,6 @@  init_vbt_defaults(struct drm_i915_private *i915)
 	/* Default to having backlight */
 	i915->vbt.backlight.present = true;
 
-	/* LFP panel data */
-	i915->vbt.lvds_dither = 1;
-
 	/* SDVO panel data */
 	i915->vbt.sdvo_lvds_vbt_mode = NULL;
 
@@ -2227,13 +2322,6 @@  init_vbt_missing_defaults(struct drm_i915_private *i915)
 	i915->vbt.version = 155;
 }
 
-static const struct bdb_header *get_bdb_header(const struct vbt_header *vbt)
-{
-	const void *_vbt = vbt;
-
-	return _vbt + vbt->bdb_offset;
-}
-
 /**
  * intel_bios_is_valid_vbt - does the given buffer contain a valid VBT
  * @buf:	pointer to a buffer to validate
@@ -2387,12 +2475,11 @@  void intel_bios_init(struct drm_i915_private *i915)
 	/* Grab useful general definitions */
 	parse_general_features(i915, bdb);
 	parse_general_definitions(i915, bdb);
-	parse_panel_options(i915, bdb);
+	parse_panel_type(i915, bdb);
 	parse_panel_dtd(i915, bdb);
 	parse_lfp_backlight(i915, bdb);
 	parse_sdvo_panel_data(i915, bdb);
 	parse_driver_features(i915, bdb);
-	parse_power_conservation_features(i915, bdb);
 	parse_edp(i915, bdb);
 	parse_psr(i915, bdb);
 	parse_mipi_config(i915, bdb);
@@ -3012,3 +3099,11 @@  intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port)
 {
 	return i915->vbt.ddi_port_info[port].devdata;
 }
+
+enum drrs_support_type
+intel_bios_drrs_type(struct intel_encoder *encoder)
+{
+	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
+
+	return i915->vbt.ddi_port_info[encoder->port].drrs_type;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index 4709c4d298059..bad282b64c5e6 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -266,4 +266,6 @@  bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devda
 int intel_bios_encoder_dp_boost_level(const struct intel_bios_encoder_data *devdata);
 int intel_bios_encoder_hdmi_boost_level(const struct intel_bios_encoder_data *devdata);
 
+enum drrs_support_type intel_bios_drrs_type(struct intel_encoder *encoder);
+
 #endif /* _INTEL_BIOS_H_ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index a54e339947c65..80a2caf4b8053 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5136,6 +5136,7 @@  intel_dp_drrs_init(struct intel_connector *connector,
 {
 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
 	struct drm_display_mode *downclock_mode = NULL;
+	enum drrs_support_type drrs_type = intel_bios_drrs_type(connector->encoder);
 
 	INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
 	mutex_init(&dev_priv->drrs.mutex);
@@ -5146,7 +5147,7 @@  intel_dp_drrs_init(struct intel_connector *connector,
 		return NULL;
 	}
 
-	if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
+	if (drrs_type != SEAMLESS_DRRS_SUPPORT) {
 		drm_dbg_kms(&dev_priv->drm, "VBT doesn't support DRRS\n");
 		return NULL;
 	}
@@ -5158,7 +5159,7 @@  intel_dp_drrs_init(struct intel_connector *connector,
 		return NULL;
 	}
 
-	dev_priv->drrs.type = dev_priv->vbt.drrs_type;
+	dev_priv->drrs.type = drrs_type;
 
 	dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
 	drm_dbg_kms(&dev_priv->drm,
diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
index dbe24d7e73759..cd927d13250f1 100644
--- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h
+++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h
@@ -359,6 +359,9 @@  enum vbt_gmbus_ddi {
 #define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR13P5	6
 #define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR20	7
 
+#define HANDLE_LFP_1 0x0008
+#define HANDLE_LFP_2 0x0080
+
 /*
  * The child device config, aka the display device data structure, provides a
  * description of a port and its configuration on the platform.
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8bb3661d3b2db..df096a283d52a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -650,6 +650,8 @@  struct ddi_vbt_port_info {
 	u8 alternate_ddc_pin;
 
 	int dp_max_link_rate;		/* 0 for not limited by VBT */
+
+	enum drrs_support_type drrs_type;
 };
 
 enum psr_lines_to_wait {
@@ -668,7 +670,6 @@  struct intel_vbt_data {
 
 	/* Feature bits */
 	unsigned int int_tv_support:1;
-	unsigned int lvds_dither:1;
 	unsigned int int_crt_support:1;
 	unsigned int lvds_use_ssc:1;
 	unsigned int int_lvds_support:1;
@@ -679,8 +680,6 @@  struct intel_vbt_data {
 	unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
 	enum drm_panel_orientation orientation;
 
-	enum drrs_support_type drrs_type;
-
 	struct {
 		int rate;
 		int lanes;