diff mbox series

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

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

Commit Message

Souza, Jose July 22, 2021, 5:43 a.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.

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(-)

Comments

Matt Atwood July 26, 2021, 9:33 p.m. UTC | #1
On Wed, Jul 21, 2021 at 10:43:30PM -0700, José Roberto de Souza wrote:
> 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.
> 
> 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>
Reviewed-by: Matt Atwood <matthew.s.atwood@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 --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
> index 5bc2c944d99b4..2b90efb41ecce 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;
>  
> @@ -2226,13 +2321,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
> @@ -2386,12 +2474,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);
> @@ -3011,3 +3098,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 c386ef8eb2006..79d4e3edb2eef 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -5133,6 +5133,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);
> @@ -5143,7 +5144,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;
>  	}
> @@ -5155,7 +5156,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 0321a1f9738d6..d990ceb23c85e 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -656,6 +656,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 {
> @@ -674,7 +676,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;
> @@ -685,8 +686,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;
> -- 
> 2.32.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Jani Nikula Aug. 16, 2021, 10:09 a.m. UTC | #2
On Wed, 21 Jul 2021, José Roberto de Souza <jose.souza@intel.com> wrote:
> 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.

If you were to get a mysterious bisect result on this patch, would you
know what's wrong?

I think there's too much going on in one patch, and this needs to be
split. Small, incremental changes with functional and non-functional
separated if possible. This is incredibly fragile stuff.

Also, I think we'll need to be able to figure out the panel type based
on EDID, i.e. we need to parse some stuff first, and the panel stuff
only after we've read EDID. Obviously you don't have to do that here,
but this need to be done so that this doesn't become impossible.

BR,
Jani.


>
> 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 --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
> index 5bc2c944d99b4..2b90efb41ecce 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;
>  
> @@ -2226,13 +2321,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
> @@ -2386,12 +2474,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);
> @@ -3011,3 +3098,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 c386ef8eb2006..79d4e3edb2eef 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -5133,6 +5133,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);
> @@ -5143,7 +5144,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;
>  	}
> @@ -5155,7 +5156,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 0321a1f9738d6..d990ceb23c85e 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -656,6 +656,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 {
> @@ -674,7 +676,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;
> @@ -685,8 +686,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;
Ville Syrjälä Aug. 16, 2021, 7:52 p.m. UTC | #3
On Mon, Aug 16, 2021 at 01:09:27PM +0300, Jani Nikula wrote:
> On Wed, 21 Jul 2021, José Roberto de Souza <jose.souza@intel.com> wrote:
> > 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.
> 
> If you were to get a mysterious bisect result on this patch, would you
> know what's wrong?
> 
> I think there's too much going on in one patch, and this needs to be
> split. Small, incremental changes with functional and non-functional
> separated if possible. This is incredibly fragile stuff.
> 
> Also, I think we'll need to be able to figure out the panel type based
> on EDID, i.e. we need to parse some stuff first, and the panel stuff
> only after we've read EDID. Obviously you don't have to do that here,
> but this need to be done so that this doesn't become impossible.

My incredibly incomplete start at that:
git://github.com/vsyrjala/linux.git vbt_panel_type_pnp_id

Totally missing any and all restructuring of the VBT
parsing to happen after we have the EDID.

And apart from that we also have this horrible
chicken vs. egg issue:
1. need the panel type to get power sequencer delays
2. need to turn on the VDD to read the EDID
3. need the EDID to get the panel type
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 5bc2c944d99b4..2b90efb41ecce 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;
 
@@ -2226,13 +2321,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
@@ -2386,12 +2474,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);
@@ -3011,3 +3098,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 c386ef8eb2006..79d4e3edb2eef 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5133,6 +5133,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);
@@ -5143,7 +5144,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;
 	}
@@ -5155,7 +5156,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 0321a1f9738d6..d990ceb23c85e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -656,6 +656,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 {
@@ -674,7 +676,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;
@@ -685,8 +686,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;