diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_bw.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_bw.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index 972ea887e232..47036d4abb33 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -22,6 +22,8 @@ struct intel_qgv_point { u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd; }; +#define DEPROGBWPCLIMIT 60 + struct intel_psf_gv_point { u8 clk; /* clock in multiples of 16.6666 MHz */ }; @@ -241,6 +243,9 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv, qi->channel_width = 16; qi->deinterleave = 4; break; + case INTEL_DRAM_GDDR: + qi->channel_width = 32; + break; default: MISSING_CASE(dram_info->type); return -EINVAL; @@ -387,6 +392,12 @@ static const struct intel_sa_info mtl_sa_info = { .derating = 10, }; +static const struct intel_sa_info xe2_hpd_sa_info = { + .derating = 30, + .deprogbwlimit = 53, + /* Other values not used by simplified algorithm */ +}; + static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel_sa_info *sa) { struct intel_qgv_info qi = {}; @@ -493,7 +504,7 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel dclk_max = icl_sagv_max_dclk(&qi); peakbw = num_channels * DIV_ROUND_UP(qi.channel_width, 8) * dclk_max; - maxdebw = min(sa->deprogbwlimit * 1000, peakbw * 6 / 10); /* 60% */ + maxdebw = min(sa->deprogbwlimit * 1000, peakbw * DEPROGBWPCLIMIT / 100); ipqdepth = min(ipqdepthpch, sa->displayrtids / num_channels); /* @@ -598,6 +609,54 @@ static void dg2_get_bw_info(struct drm_i915_private *i915) i915->display.sagv.status = I915_SAGV_NOT_CONTROLLED; } +static int xe2_hpd_get_bw_info(struct drm_i915_private *i915, + const struct intel_sa_info *sa) +{ + struct intel_qgv_info qi = {}; + int num_channels = i915->dram_info.num_channels; + int peakbw, maxdebw; + int ret, i; + + ret = icl_get_qgv_points(i915, &qi, true); + if (ret) { + drm_dbg_kms(&i915->drm, + "Failed to get memory subsystem information, ignoring bandwidth limits"); + return ret; + } + + peakbw = num_channels * qi.channel_width / 8 * icl_sagv_max_dclk(&qi); + maxdebw = min(sa->deprogbwlimit * 1000, peakbw * DEPROGBWPCLIMIT / 10); + + for (i = 0; i < qi.num_points; i++) { + const struct intel_qgv_point *point = &qi.points[i]; + int bw = num_channels * (qi.channel_width / 8) * point->dclk; + + i915->display.bw.max[0].deratedbw[i] = + min(maxdebw, (100 - sa->derating) * bw / 100); + i915->display.bw.max[0].peakbw[i] = bw; + + drm_dbg_kms(&i915->drm, "QGV %d: deratedbw=%u peakbw: %u\n", + i, i915->display.bw.max[0].deratedbw[i], + i915->display.bw.max[0].peakbw[i]); + } + + /* Bandwidth does not depend on # of planes; set all groups the same */ + i915->display.bw.max[0].num_planes = 1; + i915->display.bw.max[0].num_qgv_points = qi.num_points; + for (i = 1; i < ARRAY_SIZE(i915->display.bw.max); i++) + memcpy(&i915->display.bw.max[i], &i915->display.bw.max[0], + sizeof(i915->display.bw.max[0])); + + /* + * Xe2_HPD should always have exactly two QGV points representing + * battery and plugged-in operation. + */ + drm_WARN_ON(&i915->drm, qi.num_points != 2); + i915->display.sagv.status = I915_SAGV_ENABLED; + + return 0; +} + static unsigned int icl_max_bw_index(struct drm_i915_private *dev_priv, int num_planes, int qgv_point) { @@ -684,7 +743,9 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; - if (DISPLAY_VER(dev_priv) >= 14) + if (DISPLAY_VER_FULL(dev_priv) >= IP_VER(14, 1) && IS_DGFX(dev_priv)) + xe2_hpd_get_bw_info(dev_priv, &xe2_hpd_sa_info); + else if (DISPLAY_VER(dev_priv) >= 14) tgl_get_bw_info(dev_priv, &mtl_sa_info); else if (IS_DG2(dev_priv)) dg2_get_bw_info(dev_priv); |