[Intel-gfx] [PATCH 2/2] drm/i915: Implement PSF GV point support

Matt Roper matthew.d.roper at intel.com
Wed Jun 23 22:19:54 UTC 2021


On Mon, May 31, 2021 at 09:48:45AM +0300, Stanislav Lisovskiy wrote:
> PSF GV points are an additional factor that can limit the
> bandwidth available to display, separate from the traditional
> QGV points.  Whereas traditional QGV points represent possible
> memory clock frequencies, PSF GV points reflect possible
> frequencies of the memory fabric.
> 
> Switching between PSF GV points has the advantage of incurring
> almost no memory access block time and thus does not need to be
> accounted for in watermark calculations.
> 
> This patch adds support for those on top of regular QGV points.
> Those are supposed to be used simultaneously, i.e we are always
> at some QGV and some PSF GV point, based on the current video
> mode requirements.
> Bspec: 64631, 53998
> 
> v2: Seems that initial assumption made during ml conversation
>     was wrong, PCode rejects any masks containing points beyond
>     the ones returned, so even though BSpec says we have around
>     8 points theoretically, we can mask/unmask only those which
>     are returned, trying to manipulate those beyond causes a
>     failure from PCode. So switched back to generating mask
>     from 1 - num_qgv_points, where num_qgv_points is the actual
>     amount of points, advertised by PCode.
> 
> v3: - Extended restricted qgv point mask to 0xf, as we have now
>       3:2 bits for PSF GV points(Matt Roper)
>     - Replaced val2 with NULL from PCode request, since its not being
>       used(Matt Roper)
>     - Replaced %d to 0x%x for better readability(thanks for spotting)
> 
> Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy at intel.com>
> Cc: Matt Roper <matthew.d.roper at intel.com>

Reviewed-by: Matt Roper <matthew.d.roper at intel.com>

Sorry for the delay with the review.  I overlooked this version when you
initially sent it.


Matt

> ---
>  drivers/gpu/drm/i915/display/intel_bw.c | 113 +++++++++++++++++++++++-
>  drivers/gpu/drm/i915/i915_drv.h         |   7 ++
>  drivers/gpu/drm/i915/i915_reg.h         |   6 +-
>  drivers/gpu/drm/i915/intel_dram.c       |   1 +
>  4 files changed, 122 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c
> index bfb398f0432e..7345746d3a67 100644
> --- a/drivers/gpu/drm/i915/display/intel_bw.c
> +++ b/drivers/gpu/drm/i915/display/intel_bw.c
> @@ -17,9 +17,15 @@ struct intel_qgv_point {
>  	u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd;
>  };
>  
> +struct intel_psf_gv_point {
> +	u8 clk; /* clock in multiples of 16.6666 MHz */
> +};
> +
>  struct intel_qgv_info {
>  	struct intel_qgv_point points[I915_NUM_QGV_POINTS];
> +	struct intel_psf_gv_point psf_points[I915_NUM_PSF_GV_POINTS];
>  	u8 num_points;
> +	u8 num_psf_points;
>  	u8 t_bl;
>  };
>  
> @@ -49,6 +55,28 @@ static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv,
>  	return 0;
>  }
>  
> +static int adls_pcode_read_psf_gv_point_info(struct drm_i915_private *dev_priv,
> +					    struct intel_psf_gv_point *points)
> +{
> +	u32 val = 0;
> +	int ret;
> +	int i;
> +
> +	ret = sandybridge_pcode_read(dev_priv,
> +				     ICL_PCODE_MEM_SUBSYSYSTEM_INFO |
> +				     ADL_PCODE_MEM_SS_READ_PSF_GV_INFO,
> +				     &val, NULL);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < I915_NUM_PSF_GV_POINTS; i++) {
> +		points[i].clk = val & 0xff;
> +		val >>= 8;
> +	}
> +
> +	return 0;
> +}
> +
>  int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
>  				  u32 points_mask)
>  {
> @@ -62,7 +90,7 @@ int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv,
>  				1);
>  
>  	if (ret < 0) {
> -		drm_err(&dev_priv->drm, "Failed to disable qgv points (%d)\n", ret);
> +		drm_err(&dev_priv->drm, "Failed to disable qgv points (%d) points: 0x%x\n", ret, points_mask);
>  		return ret;
>  	}
>  
> @@ -76,6 +104,7 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv,
>  	int i, ret;
>  
>  	qi->num_points = dram_info->num_qgv_points;
> +	qi->num_psf_points = dram_info->num_psf_gv_points;
>  
>  	if (DISPLAY_VER(dev_priv) == 12)
>  		switch (dram_info->type) {
> @@ -109,6 +138,19 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv,
>  			    sp->t_rcd, sp->t_rc);
>  	}
>  
> +	if (qi->num_psf_points > 0) {
> +		ret = adls_pcode_read_psf_gv_point_info(dev_priv, qi->psf_points);
> +		if (ret) {
> +			drm_err(&dev_priv->drm, "Failed to read PSF point data; PSF points will not be considered in bandwidth calculations.\n");
> +			qi->num_psf_points = 0;
> +		}
> +
> +		for (i = 0; i < qi->num_psf_points; i++)
> +			drm_dbg_kms(&dev_priv->drm,
> +				    "PSF GV %d: CLK=%d \n",
> +				    i, qi->psf_points[i].clk);
> +	}
> +
>  	return 0;
>  }
>  
> @@ -118,6 +160,16 @@ static int icl_calc_bw(int dclk, int num, int den)
>  	return DIV_ROUND_CLOSEST(num * dclk * 100, den * 6);
>  }
>  
> +static int adl_calc_psf_bw(int clk)
> +{
> +	/*
> +	 * clk is multiples of 16.666MHz (100/6)
> +	 * According to BSpec PSF GV bandwidth is
> +	 * calculated as BW = 64 * clk * 16.666Mhz
> +	 */
> +	return DIV_ROUND_CLOSEST(64 * clk * 100, 6);
> +}
> +
>  static int icl_sagv_max_dclk(const struct intel_qgv_info *qi)
>  {
>  	u16 dclk = 0;
> @@ -194,6 +246,7 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel
>  		bi->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1;
>  
>  		bi->num_qgv_points = qi.num_points;
> +		bi->num_psf_gv_points = qi.num_psf_points;
>  
>  		for (j = 0; j < qi.num_points; j++) {
>  			const struct intel_qgv_point *sp = &qi.points[j];
> @@ -217,6 +270,16 @@ static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel
>  				    i, j, bi->num_planes, bi->deratedbw[j]);
>  		}
>  
> +		for (j = 0; j < qi.num_psf_points; j++) {
> +			const struct intel_psf_gv_point *sp = &qi.psf_points[j];
> +
> +			bi->psf_bw[j] = adl_calc_psf_bw(sp->clk);
> +
> +			drm_dbg_kms(&dev_priv->drm,
> +				    "BW%d / PSF GV %d: num_planes=%d bw=%u\n",
> +				    i, j, bi->num_planes, bi->psf_bw[j]);
> +		}
> +
>  		if (bi->num_planes == 1)
>  			break;
>  	}
> @@ -262,6 +325,15 @@ static unsigned int icl_max_bw(struct drm_i915_private *dev_priv,
>  	return 0;
>  }
>  
> +static unsigned int adl_psf_bw(struct drm_i915_private *dev_priv,
> +			       int psf_gv_point)
> +{
> +	const struct intel_bw_info *bi =
> +			&dev_priv->max_bw[0];
> +
> +	return bi->psf_bw[psf_gv_point];
> +}
> +
>  void intel_bw_init_hw(struct drm_i915_private *dev_priv)
>  {
>  	if (!HAS_DISPLAY(dev_priv))
> @@ -534,12 +606,24 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
>  	u32 allowed_points = 0;
>  	unsigned int max_bw_point = 0, max_bw = 0;
>  	unsigned int num_qgv_points = dev_priv->max_bw[0].num_qgv_points;
> -	u32 mask = (1 << num_qgv_points) - 1;
> +	unsigned int num_psf_gv_points = dev_priv->max_bw[0].num_psf_gv_points;
> +	u32 mask = 0;
>  
>  	/* FIXME earlier gens need some checks too */
>  	if (DISPLAY_VER(dev_priv) < 11)
>  		return 0;
>  
> +	/*
> +	 * We can _not_ use the whole ADLS_QGV_PT_MASK here, as PCode rejects
> +	 * it with failure if we try masking any unadvertised points.
> +	 * So need to operate only with those returned from PCode.
> +	 */
> +	if (num_qgv_points > 0)
> +		mask |= REG_GENMASK(num_qgv_points - 1, 0);
> +
> +	if (num_psf_gv_points > 0)
> +		mask |= REG_GENMASK(num_psf_gv_points - 1, 0) << ADLS_PSF_PT_SHIFT;
> +
>  	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
>  					    new_crtc_state, i) {
>  		unsigned int old_data_rate =
> @@ -602,23 +686,44 @@ int intel_bw_atomic_check(struct intel_atomic_state *state)
>  			max_bw = max_data_rate;
>  		}
>  		if (max_data_rate >= data_rate)
> -			allowed_points |= BIT(i);
> +			allowed_points |= REG_FIELD_PREP(ADLS_QGV_PT_MASK, BIT(i));
> +
>  		drm_dbg_kms(&dev_priv->drm, "QGV point %d: max bw %d required %d\n",
>  			    i, max_data_rate, data_rate);
>  	}
>  
> +	for (i = 0; i < num_psf_gv_points; i++) {
> +		unsigned int max_data_rate = adl_psf_bw(dev_priv, i);
> +
> +		if (max_data_rate >= data_rate)
> +			allowed_points |= REG_FIELD_PREP(ADLS_PSF_PT_MASK, BIT(i));
> +
> +		drm_dbg_kms(&dev_priv->drm, "PSF GV point %d: max bw %d"
> +			    " required %d\n",
> +			    i, max_data_rate, data_rate);
> +	}
> +
>  	/*
>  	 * BSpec states that we always should have at least one allowed point
>  	 * left, so if we couldn't - simply reject the configuration for obvious
>  	 * reasons.
>  	 */
> -	if (allowed_points == 0) {
> +	if ((allowed_points & ADLS_QGV_PT_MASK) == 0) {
>  		drm_dbg_kms(&dev_priv->drm, "No QGV points provide sufficient memory"
>  			    " bandwidth %d for display configuration(%d active planes).\n",
>  			    data_rate, num_active_planes);
>  		return -EINVAL;
>  	}
>  
> +	if (num_psf_gv_points > 0) {
> +		if ((allowed_points & ADLS_PSF_PT_MASK) == 0) {
> +			drm_dbg_kms(&dev_priv->drm, "No PSF GV points provide sufficient memory"
> +				    " bandwidth %d for display configuration(%d active planes).\n",
> +				    data_rate, num_active_planes);
> +			return -EINVAL;
> +		}
> +	}
> +
>  	/*
>  	 * Leave only single point with highest bandwidth, if
>  	 * we can't enable SAGV due to the increased memory latency it may
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 0f6d27da69ac..8321833292cf 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -591,6 +591,9 @@ i915_fence_timeout(const struct drm_i915_private *i915)
>  
>  #define HAS_HW_SAGV_WM(i915) (DISPLAY_VER(i915) >= 13 && !IS_DGFX(i915))
>  
> +/* Amount of PSF GV points, BSpec precisely defines this */
> +#define I915_NUM_PSF_GV_POINTS 3
> +
>  struct ddi_vbt_port_info {
>  	/* Non-NULL if port present. */
>  	struct intel_bios_encoder_data *devdata;
> @@ -1103,12 +1106,16 @@ struct drm_i915_private {
>  			INTEL_DRAM_LPDDR5,
>  		} type;
>  		u8 num_qgv_points;
> +		u8 num_psf_gv_points;
>  	} dram_info;
>  
>  	struct intel_bw_info {
>  		/* for each QGV point */
>  		unsigned int deratedbw[I915_NUM_QGV_POINTS];
> +		/* for each PSF GV point */
> +		unsigned int psf_bw[I915_NUM_PSF_GV_POINTS];
>  		u8 num_qgv_points;
> +		u8 num_psf_gv_points;
>  		u8 num_planes;
>  	} max_bw[6];
>  
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 0037e3d4049a..32299e60eb26 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -9347,9 +9347,13 @@ enum {
>  #define   ICL_PCODE_MEM_SUBSYSYSTEM_INFO	0xd
>  #define     ICL_PCODE_MEM_SS_READ_GLOBAL_INFO	(0x0 << 8)
>  #define     ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point)	(((point) << 16) | (0x1 << 8))
> +#define     ADL_PCODE_MEM_SS_READ_PSF_GV_INFO	((0) | (0x2 << 8))
>  #define   ICL_PCODE_SAGV_DE_MEM_SS_CONFIG	0xe
>  #define     ICL_PCODE_POINTS_RESTRICTED		0x0
> -#define     ICL_PCODE_POINTS_RESTRICTED_MASK	0x3
> +#define     ICL_PCODE_POINTS_RESTRICTED_MASK	0xf
> +#define   ADLS_PSF_PT_SHIFT			8
> +#define   ADLS_QGV_PT_MASK			REG_GENMASK(7, 0)
> +#define   ADLS_PSF_PT_MASK			REG_GENMASK(10, 8)
>  #define   GEN6_PCODE_READ_D_COMP		0x10
>  #define   GEN6_PCODE_WRITE_D_COMP		0x11
>  #define   ICL_PCODE_EXIT_TCCOLD			0x12
> diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c
> index 1e53c017c30d..53ccd106785f 100644
> --- a/drivers/gpu/drm/i915/intel_dram.c
> +++ b/drivers/gpu/drm/i915/intel_dram.c
> @@ -468,6 +468,7 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv)
>  
>  	dram_info->num_channels = (val & 0xf0) >> 4;
>  	dram_info->num_qgv_points = (val & 0xf00) >> 8;
> +	dram_info->num_psf_gv_points = (val & 0x3000) >> 12;
>  
>  	return 0;
>  }
> -- 
> 2.24.1.485.gad05a3d8e5
> 

-- 
Matt Roper
Graphics Software Engineer
VTT-OSGC Platform Enablement
Intel Corporation
(916) 356-2795


More information about the Intel-gfx mailing list