[Intel-gfx] [PATCH 02/10] drm/i915/bios: Start to support two integrated panels

Matt Atwood matthew.s.atwood at intel.com
Mon Jul 26 21:33:53 UTC 2021


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 at linux.intel.com>
> Cc: Jani Nikula <jani.nikula at intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza at intel.com>
Reviewed-by: Matt Atwood <matthew.s.atwood at 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 at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx


More information about the Intel-gfx mailing list