diff mbox series

[v2,22/27] drm/i915/lnl: Add CDCLK table

Message ID 20230907153757.2249452-23-lucas.demarchi@intel.com (mailing list archive)
State New, archived
Headers show
Series Enable Lunar Lake display | expand

Commit Message

Lucas De Marchi Sept. 7, 2023, 3:37 p.m. UTC
From: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>

Add a new Lunar Lake CDCLK table from BSpec and also a helper function
in order to be able to find lowest possible CDCLK.

v2:
  - Remove mdclk from the table as it's not needed (Matt Roper)
  - Update waveform values to the latest from spec (Matt Roper)
  - Rename functions and calculation to match by pixel rate (Lucas)

Bspec: 68861
Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
---
 drivers/gpu/drm/i915/display/intel_cdclk.c | 55 +++++++++++++++++++++-
 1 file changed, 53 insertions(+), 2 deletions(-)

Comments

Matt Roper Sept. 7, 2023, 9:52 p.m. UTC | #1
On Thu, Sep 07, 2023 at 08:37:52AM -0700, Lucas De Marchi wrote:
> From: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
> 
> Add a new Lunar Lake CDCLK table from BSpec and also a helper function
> in order to be able to find lowest possible CDCLK.
> 
> v2:
>   - Remove mdclk from the table as it's not needed (Matt Roper)
>   - Update waveform values to the latest from spec (Matt Roper)
>   - Rename functions and calculation to match by pixel rate (Lucas)
> 
> Bspec: 68861
> Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_cdclk.c | 55 +++++++++++++++++++++-
>  1 file changed, 53 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
> index cfd01050f7f1..7307af2a4af5 100644
> --- a/drivers/gpu/drm/i915/display/intel_cdclk.c
> +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
> @@ -1382,6 +1382,31 @@ static const struct intel_cdclk_vals mtl_cdclk_table[] = {
>  	{}
>  };
>  
> +static const struct intel_cdclk_vals lnl_cdclk_table[] = {
> +	{ .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa },
> +	{ .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a },
> +	{ .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 },
> +	{ .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 },
> +	{ .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee },
> +	{ .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de },
> +	{ .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe },
> +	{ .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe },
> +	{ .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff },
> +	{ .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 },
> +	{ .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee },
> +	{ .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de },
> +	{ .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe },
> +	{ .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe },
> +	{ .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff },
> +	{ .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe },
> +	{ .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe },
> +	{ .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff },
> +	{ .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe },
> +	{ .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe },
> +	{ .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff },
> +	{}
> +};
> +
>  static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
>  {
>  	const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
> @@ -2504,12 +2529,35 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
>  	}
>  }
>  
> +static int
> +xe2lpd_cdclk_match_by_pixel_rate(struct drm_i915_private *i915, int pixel_rate)
> +{
> +	const struct intel_cdclk_vals *table = i915->display.cdclk.table;
> +	int i;
> +
> +	for (i = 0; table[i].refclk; i++) {
> +		if (table[i].refclk != i915->display.cdclk.hw.ref)
> +			continue;
> +
> +		if (table[i].refclk * table[i].ratio >= pixel_rate)
> +			return table[i].cdclk;
> +	}
> +
> +	drm_WARN(&i915->drm, 1,
> +		 "Cannot satisfy pixel rate %d with refclk %u\n",
> +		 pixel_rate, i915->display.cdclk.hw.ref);
> +
> +	return 0;
> +}
> +
>  static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
>  	int pixel_rate = crtc_state->pixel_rate;
>  
> -	if (DISPLAY_VER(dev_priv) >= 10)
> +	if (DISPLAY_VER(dev_priv) >= 20)
> +		return xe2lpd_cdclk_match_by_pixel_rate(dev_priv, pixel_rate);

Is this actually what we want to be doing?  Generally this function
returns a minimum possible value cdclk value that could support the
pixel rate (e.g., pixel_rate / 2 on modern platforms), without caring
(yet) about the set of cdclk values that the platform is capable of
generating.  We then do some additional CRTC-level or device-level
adjustments to that minimum in intel_crtc_compute_min_cdclk and
intel_compute_min_cdclk, and only at the very end of the process (in
bxt_calc_cdclk) do we go into the table to find the lowest possible
clock greater than or equal to the adjusted minimum we had calculated.

From what I can see, the minimum cdclk (as far as this specific function
is concerned) should still be half the pixel rate on Xe2 (bspec 68858:
"Pipe maximum pixel rate = 2 * CDCLK frequency * Pipe Ratio").  The only
thing that really changes with all the mdclk stuff is that cdclk and
mdclk are no longer fundamentally locked together in hardware; that's
why the table of possible cdclk settings in the bspec now has additional
rows where the cdclk value ranges anywhere from mdclk/4 to mdclk/2
(whereas on previous platforms every single row corresponded to an
mdclk/2 value).

tl;dr:  I don't think we want/need this hunk of the patch.


Matt

> +	else if (DISPLAY_VER(dev_priv) >= 10)
>  		return DIV_ROUND_UP(pixel_rate, 2);
>  	else if (DISPLAY_VER(dev_priv) == 9 ||
>  		 IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> @@ -3591,7 +3639,10 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = {
>   */
>  void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
>  {
> -	if (DISPLAY_VER(dev_priv) >= 14) {
> +	if (DISPLAY_VER(dev_priv) >= 20) {
> +		dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
> +		dev_priv->display.cdclk.table = lnl_cdclk_table;
> +	} else if (DISPLAY_VER(dev_priv) >= 14) {
>  		dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
>  		dev_priv->display.cdclk.table = mtl_cdclk_table;
>  	} else if (IS_DG2(dev_priv)) {
> -- 
> 2.40.1
>
Matt Roper Sept. 7, 2023, 10:48 p.m. UTC | #2
On Thu, Sep 07, 2023 at 02:52:06PM -0700, Matt Roper wrote:
> On Thu, Sep 07, 2023 at 08:37:52AM -0700, Lucas De Marchi wrote:
> > From: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
> > 
> > Add a new Lunar Lake CDCLK table from BSpec and also a helper function
> > in order to be able to find lowest possible CDCLK.
> > 
> > v2:
> >   - Remove mdclk from the table as it's not needed (Matt Roper)
> >   - Update waveform values to the latest from spec (Matt Roper)
> >   - Rename functions and calculation to match by pixel rate (Lucas)
> > 
> > Bspec: 68861
> > Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
> > Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_cdclk.c | 55 +++++++++++++++++++++-
> >  1 file changed, 53 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
> > index cfd01050f7f1..7307af2a4af5 100644
> > --- a/drivers/gpu/drm/i915/display/intel_cdclk.c
> > +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
> > @@ -1382,6 +1382,31 @@ static const struct intel_cdclk_vals mtl_cdclk_table[] = {
> >  	{}
> >  };
> >  
> > +static const struct intel_cdclk_vals lnl_cdclk_table[] = {
> > +	{ .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa },
> > +	{ .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a },
> > +	{ .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 },
> > +	{ .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 },
> > +	{ .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee },
> > +	{ .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de },
> > +	{ .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe },
> > +	{ .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe },
> > +	{ .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff },
> > +	{ .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 },
> > +	{ .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee },
> > +	{ .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de },
> > +	{ .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe },
> > +	{ .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe },
> > +	{ .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff },
> > +	{ .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe },
> > +	{ .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe },
> > +	{ .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff },
> > +	{ .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe },
> > +	{ .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe },
> > +	{ .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff },
> > +	{}
> > +};
> > +
> >  static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
> >  {
> >  	const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
> > @@ -2504,12 +2529,35 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
> >  	}
> >  }
> >  
> > +static int
> > +xe2lpd_cdclk_match_by_pixel_rate(struct drm_i915_private *i915, int pixel_rate)
> > +{
> > +	const struct intel_cdclk_vals *table = i915->display.cdclk.table;
> > +	int i;
> > +
> > +	for (i = 0; table[i].refclk; i++) {
> > +		if (table[i].refclk != i915->display.cdclk.hw.ref)
> > +			continue;
> > +
> > +		if (table[i].refclk * table[i].ratio >= pixel_rate)
> > +			return table[i].cdclk;
> > +	}
> > +
> > +	drm_WARN(&i915->drm, 1,
> > +		 "Cannot satisfy pixel rate %d with refclk %u\n",
> > +		 pixel_rate, i915->display.cdclk.hw.ref);
> > +
> > +	return 0;
> > +}
> > +
> >  static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
> >  	int pixel_rate = crtc_state->pixel_rate;
> >  
> > -	if (DISPLAY_VER(dev_priv) >= 10)
> > +	if (DISPLAY_VER(dev_priv) >= 20)
> > +		return xe2lpd_cdclk_match_by_pixel_rate(dev_priv, pixel_rate);
> 
> Is this actually what we want to be doing?  Generally this function
> returns a minimum possible value cdclk value that could support the
> pixel rate (e.g., pixel_rate / 2 on modern platforms), without caring
> (yet) about the set of cdclk values that the platform is capable of
> generating.  We then do some additional CRTC-level or device-level
> adjustments to that minimum in intel_crtc_compute_min_cdclk and
> intel_compute_min_cdclk, and only at the very end of the process (in
> bxt_calc_cdclk) do we go into the table to find the lowest possible
> clock greater than or equal to the adjusted minimum we had calculated.
> 
> From what I can see, the minimum cdclk (as far as this specific function
> is concerned) should still be half the pixel rate on Xe2 (bspec 68858:
> "Pipe maximum pixel rate = 2 * CDCLK frequency * Pipe Ratio").  The only
> thing that really changes with all the mdclk stuff is that cdclk and
> mdclk are no longer fundamentally locked together in hardware; that's
> why the table of possible cdclk settings in the bspec now has additional
> rows where the cdclk value ranges anywhere from mdclk/4 to mdclk/2
> (whereas on previous platforms every single row corresponded to an
> mdclk/2 value).
> 
> tl;dr:  I don't think we want/need this hunk of the patch.
> 

BTW, completely unrelated to this LNL-specific patch, but since I'm
looking at this area of the code again, I'm questioning whether the
general logic in bxt_cdclk_cd2x_div_sel is correct for platforms that
have squashing (DG2, MTL, LNL, etc.).  Now that we can reach multiple
effective cdclk values with a single PLL ratio / VCO setting, it seems
like this logic can no longer going to properly derive the CD2X divider
from VCO.  And we seem to be relying on that function to program
the divider in CDCLK_CTL rather than using the value that was provided
in the table.

If I remember correctly there were some unexplained underruns seen on
DG2 before we hacked the cdclk to a higher value than expected; maybe
this is the explanation for that?  Sometimes you'd get lucky and wind up
with the right divider in the end, other times you'd select it
incorrectly and wind up with something that didn't match the value
specified in the table.


Matt

> 
> Matt
> 
> > +	else if (DISPLAY_VER(dev_priv) >= 10)
> >  		return DIV_ROUND_UP(pixel_rate, 2);
> >  	else if (DISPLAY_VER(dev_priv) == 9 ||
> >  		 IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> > @@ -3591,7 +3639,10 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = {
> >   */
> >  void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
> >  {
> > -	if (DISPLAY_VER(dev_priv) >= 14) {
> > +	if (DISPLAY_VER(dev_priv) >= 20) {
> > +		dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
> > +		dev_priv->display.cdclk.table = lnl_cdclk_table;
> > +	} else if (DISPLAY_VER(dev_priv) >= 14) {
> >  		dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
> >  		dev_priv->display.cdclk.table = mtl_cdclk_table;
> >  	} else if (IS_DG2(dev_priv)) {
> > -- 
> > 2.40.1
> > 
> 
> -- 
> Matt Roper
> Graphics Software Engineer
> Linux GPU Platform Enablement
> Intel Corporation
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index cfd01050f7f1..7307af2a4af5 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -1382,6 +1382,31 @@  static const struct intel_cdclk_vals mtl_cdclk_table[] = {
 	{}
 };
 
+static const struct intel_cdclk_vals lnl_cdclk_table[] = {
+	{ .refclk = 38400, .cdclk = 153600, .divider = 2, .ratio = 16, .waveform = 0xaaaa },
+	{ .refclk = 38400, .cdclk = 172800, .divider = 2, .ratio = 16, .waveform = 0xad5a },
+	{ .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 16, .waveform = 0xb6b6 },
+	{ .refclk = 38400, .cdclk = 211200, .divider = 2, .ratio = 16, .waveform = 0xdbb6 },
+	{ .refclk = 38400, .cdclk = 230400, .divider = 2, .ratio = 16, .waveform = 0xeeee },
+	{ .refclk = 38400, .cdclk = 249600, .divider = 2, .ratio = 16, .waveform = 0xf7de },
+	{ .refclk = 38400, .cdclk = 268800, .divider = 2, .ratio = 16, .waveform = 0xfefe },
+	{ .refclk = 38400, .cdclk = 288000, .divider = 2, .ratio = 16, .waveform = 0xfffe },
+	{ .refclk = 38400, .cdclk = 307200, .divider = 2, .ratio = 16, .waveform = 0xffff },
+	{ .refclk = 38400, .cdclk = 330000, .divider = 2, .ratio = 25, .waveform = 0xdbb6 },
+	{ .refclk = 38400, .cdclk = 360000, .divider = 2, .ratio = 25, .waveform = 0xeeee },
+	{ .refclk = 38400, .cdclk = 390000, .divider = 2, .ratio = 25, .waveform = 0xf7de },
+	{ .refclk = 38400, .cdclk = 420000, .divider = 2, .ratio = 25, .waveform = 0xfefe },
+	{ .refclk = 38400, .cdclk = 450000, .divider = 2, .ratio = 25, .waveform = 0xfffe },
+	{ .refclk = 38400, .cdclk = 480000, .divider = 2, .ratio = 25, .waveform = 0xffff },
+	{ .refclk = 38400, .cdclk = 487200, .divider = 2, .ratio = 29, .waveform = 0xfefe },
+	{ .refclk = 38400, .cdclk = 522000, .divider = 2, .ratio = 29, .waveform = 0xfffe },
+	{ .refclk = 38400, .cdclk = 556800, .divider = 2, .ratio = 29, .waveform = 0xffff },
+	{ .refclk = 38400, .cdclk = 571200, .divider = 2, .ratio = 34, .waveform = 0xfefe },
+	{ .refclk = 38400, .cdclk = 612000, .divider = 2, .ratio = 34, .waveform = 0xfffe },
+	{ .refclk = 38400, .cdclk = 652800, .divider = 2, .ratio = 34, .waveform = 0xffff },
+	{}
+};
+
 static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk)
 {
 	const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table;
@@ -2504,12 +2529,35 @@  intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
 	}
 }
 
+static int
+xe2lpd_cdclk_match_by_pixel_rate(struct drm_i915_private *i915, int pixel_rate)
+{
+	const struct intel_cdclk_vals *table = i915->display.cdclk.table;
+	int i;
+
+	for (i = 0; table[i].refclk; i++) {
+		if (table[i].refclk != i915->display.cdclk.hw.ref)
+			continue;
+
+		if (table[i].refclk * table[i].ratio >= pixel_rate)
+			return table[i].cdclk;
+	}
+
+	drm_WARN(&i915->drm, 1,
+		 "Cannot satisfy pixel rate %d with refclk %u\n",
+		 pixel_rate, i915->display.cdclk.hw.ref);
+
+	return 0;
+}
+
 static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state)
 {
 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
 	int pixel_rate = crtc_state->pixel_rate;
 
-	if (DISPLAY_VER(dev_priv) >= 10)
+	if (DISPLAY_VER(dev_priv) >= 20)
+		return xe2lpd_cdclk_match_by_pixel_rate(dev_priv, pixel_rate);
+	else if (DISPLAY_VER(dev_priv) >= 10)
 		return DIV_ROUND_UP(pixel_rate, 2);
 	else if (DISPLAY_VER(dev_priv) == 9 ||
 		 IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
@@ -3591,7 +3639,10 @@  static const struct intel_cdclk_funcs i830_cdclk_funcs = {
  */
 void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
 {
-	if (DISPLAY_VER(dev_priv) >= 14) {
+	if (DISPLAY_VER(dev_priv) >= 20) {
+		dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
+		dev_priv->display.cdclk.table = lnl_cdclk_table;
+	} else if (DISPLAY_VER(dev_priv) >= 14) {
 		dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs;
 		dev_priv->display.cdclk.table = mtl_cdclk_table;
 	} else if (IS_DG2(dev_priv)) {