[Intel-gfx] [PATCH] Implement PSF GV point support

2021-04-27 Thread Stanislav Lisovskiy
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

Signed-off-by: Stanislav Lisovskiy 
Cc: Matt Roper 
---
 drivers/gpu/drm/i915/display/intel_bw.c | 100 +++-
 drivers/gpu/drm/i915/i915_drv.h |   7 ++
 drivers/gpu/drm/i915/i915_reg.h |   3 +
 drivers/gpu/drm/i915/intel_dram.c   |   1 +
 4 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bw.c 
b/drivers/gpu/drm/i915/display/intel_bw.c
index d96b9bf6c197..fdee6dcff70c 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. 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, val2 = 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, &val2);
+   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)
 {
@@ -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 (IS_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;
@@ -188,6 +240,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];
@@ -211,6 +264,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);
+
+   

[Intel-gfx] [PATCH] Implement PSF GV point support

2021-04-26 Thread Stanislav Lisovskiy
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: - Removed redundant HAS_DISPLAY13 check and started using
  amount of PSF GV points retrieved from PCode instead.(Matt)
- Added QGV/PSF point mask definitions to i915_reg.h(Matt)
- Minor fixes to cover letter and commit message(Matt)

v3: - s/adl_/adls_/ - Matt Roper
- Do not return error but just zero qi->num_psf_points,
  if we can't get PSF GV points(Matt Roper)
- s/GEN13_/ADLS_/ - Matt Roper

Signed-off-by: Stanislav Lisovskiy 
Reviewed-by: Matt Roper 
---
 drivers/gpu/drm/i915/display/intel_bw.c | 100 +++-
 drivers/gpu/drm/i915/i915_drv.h |   7 ++
 drivers/gpu/drm/i915/i915_reg.h |   3 +
 drivers/gpu/drm/i915/intel_dram.c   |   1 +
 4 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bw.c 
b/drivers/gpu/drm/i915/display/intel_bw.c
index d96b9bf6c197..fdee6dcff70c 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. 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, val2 = 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, &val2);
+   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)
 {
@@ -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 (IS_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;
@@ -188,6 +240,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