diff mbox series

[02/13] drm/i915/cdclk: Fix voltage_level programming edge case

Message ID 20240327174544.983-3-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915: Implemnt vblank sycnhronized mbus joining changes | expand

Commit Message

Ville Syrjälä March 27, 2024, 5:45 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Currently we only consider the relationship of the
old and new CDCLK frequencies when determining whether
to do the repgramming from intel_set_cdclk_pre_plane_update()
or intel_set_cdclk_post_plane_update().

It is technically possible to have a situation where the
CDCLK frequency is decreasing, but the voltage_level is
increasing due a DDI port. In this case we should bump
the voltage level already in intel_set_cdclk_pre_plane_update()
(so that the voltage_level will have been increased by the
time the port gets enabled), while leaving the CDCLK frequency
unchanged (as active planes/etc. may still depend on it).
We can then reduce the CDCLK frequency to its final value
from intel_set_cdclk_post_plane_update().

In order to handle that correctly we shall construct a
suitable amalgam of the old and new cdclk states in
intel_set_cdclk_pre_plane_update().

And we can simply call intel_set_cdclk() unconditionally
in both places as it will not do anything if nothing actually
changes vs. the current hw state.

v2: Handle cdclk_state->disable_pipes

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/display/intel_cdclk.c | 27 +++++++++++++---------
 1 file changed, 16 insertions(+), 11 deletions(-)

Comments

Shankar, Uma March 28, 2024, 11:40 a.m. UTC | #1
> -----Original Message-----
> From: Intel-gfx <intel-gfx-bounces@lists.freedesktop.org> On Behalf Of Ville
> Syrjala
> Sent: Wednesday, March 27, 2024 11:16 PM
> To: intel-gfx@lists.freedesktop.org
> Subject: [PATCH 02/13] drm/i915/cdclk: Fix voltage_level programming edge case
> 
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Currently we only consider the relationship of the old and new CDCLK frequencies
> when determining whether to do the repgramming from
> intel_set_cdclk_pre_plane_update()
> or intel_set_cdclk_post_plane_update().
> 
> It is technically possible to have a situation where the CDCLK frequency is
> decreasing, but the voltage_level is increasing due a DDI port. In this case we
> should bump the voltage level already in intel_set_cdclk_pre_plane_update()
> (so that the voltage_level will have been increased by the time the port gets
> enabled), while leaving the CDCLK frequency unchanged (as active planes/etc.
> may still depend on it).
> We can then reduce the CDCLK frequency to its final value from
> intel_set_cdclk_post_plane_update().
> 
> In order to handle that correctly we shall construct a suitable amalgam of the old
> and new cdclk states in intel_set_cdclk_pre_plane_update().
> 
> And we can simply call intel_set_cdclk() unconditionally in both places as it will
> not do anything if nothing actually changes vs. the current hw state.
> 
> v2: Handle cdclk_state->disable_pipes

Looks Good to me.
Reviewed-by: Uma Shankar <uma.shankar@intel.com>

> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_cdclk.c | 27 +++++++++++++---------
>  1 file changed, 16 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c
> b/drivers/gpu/drm/i915/display/intel_cdclk.c
> index 619529dba095..504c5cbbcfff 100644
> --- a/drivers/gpu/drm/i915/display/intel_cdclk.c
> +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
> @@ -2600,6 +2600,7 @@ intel_set_cdclk_pre_plane_update(struct
> intel_atomic_state *state)
>  		intel_atomic_get_old_cdclk_state(state);
>  	const struct intel_cdclk_state *new_cdclk_state =
>  		intel_atomic_get_new_cdclk_state(state);
> +	struct intel_cdclk_config cdclk_config;
> 
>  	if (!intel_cdclk_changed(&old_cdclk_state->actual,
>  				 &new_cdclk_state->actual))
> @@ -2608,13 +2609,21 @@ intel_set_cdclk_pre_plane_update(struct
> intel_atomic_state *state)
>  	if (IS_DG2(i915))
>  		intel_cdclk_pcode_pre_notify(state);
> 
> -	if (new_cdclk_state->disable_pipes ||
> -	    old_cdclk_state->actual.cdclk <= new_cdclk_state->actual.cdclk) {
> -		drm_WARN_ON(&i915->drm, !new_cdclk_state-
> >base.changed);
> +	if (new_cdclk_state->disable_pipes) {
> +		cdclk_config = new_cdclk_state->actual;
> +	} else {
> +		if (new_cdclk_state->actual.cdclk >= old_cdclk_state-
> >actual.cdclk)
> +			cdclk_config = new_cdclk_state->actual;
> +		else
> +			cdclk_config = old_cdclk_state->actual;
> 
> -		intel_set_cdclk(i915, &new_cdclk_state->actual,
> -				new_cdclk_state->pipe);
> +		cdclk_config.voltage_level = max(new_cdclk_state-
> >actual.voltage_level,
> +						 old_cdclk_state-
> >actual.voltage_level);
>  	}
> +
> +	drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
> +
> +	intel_set_cdclk(i915, &cdclk_config, new_cdclk_state->pipe);
>  }
> 
>  /**
> @@ -2640,13 +2649,9 @@ intel_set_cdclk_post_plane_update(struct
> intel_atomic_state *state)
>  	if (IS_DG2(i915))
>  		intel_cdclk_pcode_post_notify(state);
> 
> -	if (!new_cdclk_state->disable_pipes &&
> -	    old_cdclk_state->actual.cdclk > new_cdclk_state->actual.cdclk) {
> -		drm_WARN_ON(&i915->drm, !new_cdclk_state-
> >base.changed);
> +	drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
> 
> -		intel_set_cdclk(i915, &new_cdclk_state->actual,
> -				new_cdclk_state->pipe);
> -	}
> +	intel_set_cdclk(i915, &new_cdclk_state->actual,
> +new_cdclk_state->pipe);
>  }
> 
>  static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state)
> --
> 2.43.2
Gustavo Sousa March 29, 2024, 5:04 p.m. UTC | #2
Quoting Ville Syrjala (2024-03-27 14:45:33-03:00)
>From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
>Currently we only consider the relationship of the
>old and new CDCLK frequencies when determining whether
>to do the repgramming from intel_set_cdclk_pre_plane_update()
>or intel_set_cdclk_post_plane_update().
>
>It is technically possible to have a situation where the
>CDCLK frequency is decreasing, but the voltage_level is
>increasing due a DDI port. In this case we should bump
>the voltage level already in intel_set_cdclk_pre_plane_update()
>(so that the voltage_level will have been increased by the
>time the port gets enabled), while leaving the CDCLK frequency
>unchanged (as active planes/etc. may still depend on it).
>We can then reduce the CDCLK frequency to its final value
>from intel_set_cdclk_post_plane_update().
>
>In order to handle that correctly we shall construct a
>suitable amalgam of the old and new cdclk states in
>intel_set_cdclk_pre_plane_update().
>
>And we can simply call intel_set_cdclk() unconditionally
>in both places as it will not do anything if nothing actually
>changes vs. the current hw state.
>
>v2: Handle cdclk_state->disable_pipes
>
>Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>---
> drivers/gpu/drm/i915/display/intel_cdclk.c | 27 +++++++++++++---------
> 1 file changed, 16 insertions(+), 11 deletions(-)
>
>diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
>index 619529dba095..504c5cbbcfff 100644
>--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
>+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
>@@ -2600,6 +2600,7 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
>                 intel_atomic_get_old_cdclk_state(state);
>         const struct intel_cdclk_state *new_cdclk_state =
>                 intel_atomic_get_new_cdclk_state(state);
>+        struct intel_cdclk_config cdclk_config;
> 
>         if (!intel_cdclk_changed(&old_cdclk_state->actual,
>                                  &new_cdclk_state->actual))
>@@ -2608,13 +2609,21 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
>         if (IS_DG2(i915))
>                 intel_cdclk_pcode_pre_notify(state);
> 
>-        if (new_cdclk_state->disable_pipes ||
>-            old_cdclk_state->actual.cdclk <= new_cdclk_state->actual.cdclk) {
>-                drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
>+        if (new_cdclk_state->disable_pipes) {
>+                cdclk_config = new_cdclk_state->actual;
>+        } else {
>+                if (new_cdclk_state->actual.cdclk >= old_cdclk_state->actual.cdclk)
>+                        cdclk_config = new_cdclk_state->actual;
>+                else
>+                        cdclk_config = old_cdclk_state->actual;
> 
>-                intel_set_cdclk(i915, &new_cdclk_state->actual,
>-                                new_cdclk_state->pipe);
>+                cdclk_config.voltage_level = max(new_cdclk_state->actual.voltage_level,
>+                                                 old_cdclk_state->actual.voltage_level);
>         }
>+
>+        drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
>+
>+        intel_set_cdclk(i915, &cdclk_config, new_cdclk_state->pipe);

Not sure if there could be unwanted side effects with passing
new_cdclk_state->pipe when using old_cdclk_state->actual. Because
voltage_level might have changed, parts of the cdclk change sequence end
up being exercised even when cdclk_config == old_cdclk_state->actual.

Well, even if those side effects might be harmless, I wonder if it would
be better if we used INVALID_PIPE when using old_cdclk_state->actual.

--
Gustavo Sousa

> }
> 
> /**
>@@ -2640,13 +2649,9 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
>         if (IS_DG2(i915))
>                 intel_cdclk_pcode_post_notify(state);
> 
>-        if (!new_cdclk_state->disable_pipes &&
>-            old_cdclk_state->actual.cdclk > new_cdclk_state->actual.cdclk) {
>-                drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
>+        drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
> 
>-                intel_set_cdclk(i915, &new_cdclk_state->actual,
>-                                new_cdclk_state->pipe);
>-        }
>+        intel_set_cdclk(i915, &new_cdclk_state->actual, new_cdclk_state->pipe);
> }
> 
> static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state)
>-- 
>2.43.2
>
Ville Syrjälä April 2, 2024, 2:56 p.m. UTC | #3
On Fri, Mar 29, 2024 at 02:04:55PM -0300, Gustavo Sousa wrote:
> Quoting Ville Syrjala (2024-03-27 14:45:33-03:00)
> >From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> >Currently we only consider the relationship of the
> >old and new CDCLK frequencies when determining whether
> >to do the repgramming from intel_set_cdclk_pre_plane_update()
> >or intel_set_cdclk_post_plane_update().
> >
> >It is technically possible to have a situation where the
> >CDCLK frequency is decreasing, but the voltage_level is
> >increasing due a DDI port. In this case we should bump
> >the voltage level already in intel_set_cdclk_pre_plane_update()
> >(so that the voltage_level will have been increased by the
> >time the port gets enabled), while leaving the CDCLK frequency
> >unchanged (as active planes/etc. may still depend on it).
> >We can then reduce the CDCLK frequency to its final value
> >from intel_set_cdclk_post_plane_update().
> >
> >In order to handle that correctly we shall construct a
> >suitable amalgam of the old and new cdclk states in
> >intel_set_cdclk_pre_plane_update().
> >
> >And we can simply call intel_set_cdclk() unconditionally
> >in both places as it will not do anything if nothing actually
> >changes vs. the current hw state.
> >
> >v2: Handle cdclk_state->disable_pipes
> >
> >Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >---
> > drivers/gpu/drm/i915/display/intel_cdclk.c | 27 +++++++++++++---------
> > 1 file changed, 16 insertions(+), 11 deletions(-)
> >
> >diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
> >index 619529dba095..504c5cbbcfff 100644
> >--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
> >+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
> >@@ -2600,6 +2600,7 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
> >                 intel_atomic_get_old_cdclk_state(state);
> >         const struct intel_cdclk_state *new_cdclk_state =
> >                 intel_atomic_get_new_cdclk_state(state);
> >+        struct intel_cdclk_config cdclk_config;
> > 
> >         if (!intel_cdclk_changed(&old_cdclk_state->actual,
> >                                  &new_cdclk_state->actual))
> >@@ -2608,13 +2609,21 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
> >         if (IS_DG2(i915))
> >                 intel_cdclk_pcode_pre_notify(state);
> > 
> >-        if (new_cdclk_state->disable_pipes ||
> >-            old_cdclk_state->actual.cdclk <= new_cdclk_state->actual.cdclk) {
> >-                drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
> >+        if (new_cdclk_state->disable_pipes) {
> >+                cdclk_config = new_cdclk_state->actual;
> >+        } else {
> >+                if (new_cdclk_state->actual.cdclk >= old_cdclk_state->actual.cdclk)
> >+                        cdclk_config = new_cdclk_state->actual;
> >+                else
> >+                        cdclk_config = old_cdclk_state->actual;
> > 
> >-                intel_set_cdclk(i915, &new_cdclk_state->actual,
> >-                                new_cdclk_state->pipe);
> >+                cdclk_config.voltage_level = max(new_cdclk_state->actual.voltage_level,
> >+                                                 old_cdclk_state->actual.voltage_level);
> >         }
> >+
> >+        drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
> >+
> >+        intel_set_cdclk(i915, &cdclk_config, new_cdclk_state->pipe);
> 
> Not sure if there could be unwanted side effects with passing
> new_cdclk_state->pipe when using old_cdclk_state->actual. Because
> voltage_level might have changed, parts of the cdclk change sequence end
> up being exercised even when cdclk_config == old_cdclk_state->actual.
> 
> Well, even if those side effects might be harmless, I wonder if it would
> be better if we used INVALID_PIPE when using old_cdclk_state->actual.

Yeah. I doubt there should be any really bad side effects, but
probably a good idea to sidestep the whole question by passing
in INVALID_PIPE.
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 619529dba095..504c5cbbcfff 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -2600,6 +2600,7 @@  intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
 		intel_atomic_get_old_cdclk_state(state);
 	const struct intel_cdclk_state *new_cdclk_state =
 		intel_atomic_get_new_cdclk_state(state);
+	struct intel_cdclk_config cdclk_config;
 
 	if (!intel_cdclk_changed(&old_cdclk_state->actual,
 				 &new_cdclk_state->actual))
@@ -2608,13 +2609,21 @@  intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
 	if (IS_DG2(i915))
 		intel_cdclk_pcode_pre_notify(state);
 
-	if (new_cdclk_state->disable_pipes ||
-	    old_cdclk_state->actual.cdclk <= new_cdclk_state->actual.cdclk) {
-		drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
+	if (new_cdclk_state->disable_pipes) {
+		cdclk_config = new_cdclk_state->actual;
+	} else {
+		if (new_cdclk_state->actual.cdclk >= old_cdclk_state->actual.cdclk)
+			cdclk_config = new_cdclk_state->actual;
+		else
+			cdclk_config = old_cdclk_state->actual;
 
-		intel_set_cdclk(i915, &new_cdclk_state->actual,
-				new_cdclk_state->pipe);
+		cdclk_config.voltage_level = max(new_cdclk_state->actual.voltage_level,
+						 old_cdclk_state->actual.voltage_level);
 	}
+
+	drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
+
+	intel_set_cdclk(i915, &cdclk_config, new_cdclk_state->pipe);
 }
 
 /**
@@ -2640,13 +2649,9 @@  intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)
 	if (IS_DG2(i915))
 		intel_cdclk_pcode_post_notify(state);
 
-	if (!new_cdclk_state->disable_pipes &&
-	    old_cdclk_state->actual.cdclk > new_cdclk_state->actual.cdclk) {
-		drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
+	drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed);
 
-		intel_set_cdclk(i915, &new_cdclk_state->actual,
-				new_cdclk_state->pipe);
-	}
+	intel_set_cdclk(i915, &new_cdclk_state->actual, new_cdclk_state->pipe);
 }
 
 static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state)