diff mbox series

[3/3] drm/i915/display/adlp: Fix programing of PIPE_MBUS_DBOX_CTL

Message ID 20220318195522.456180-3-jose.souza@intel.com (mailing list archive)
State New, archived
Headers show
Series [1/3] drm/i915/display: Program PIPE_MBUS_DBOX_CTL with adl-p values | expand

Commit Message

Souza, Jose March 18, 2022, 7:55 p.m. UTC
PIPE_MBUS_DBOX_CTL was only being programmed when a pipe is being
enabled leaving other pipes with a wrong A_CREDIT value in cases
like when going from one pipe enabled to two pipes and the first
pipe don't need modeset, similar when going from two or more
pipes to ones.

So here moving the PIPE_MBUS_DBOX_CTL programing to be executed before
the function that enables and updates all necessary pipes.
Leaving all pipes with the correct value of A_CREDIT.

As now PIPE_MBUS_DBOX_CTL is being programmed at the right time it
is also waiting the vblanks after adjust PIPE_MBUS_DBOX_CTL
as required by specification.

BSpec: 49213
BSpec: 50343
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c | 36 +------------
 drivers/gpu/drm/i915/intel_pm.c              | 55 +++++++++++++++++++-
 drivers/gpu/drm/i915/intel_pm.h              |  1 +
 3 files changed, 56 insertions(+), 36 deletions(-)

Comments

Ville Syrjälä March 18, 2022, 9:28 p.m. UTC | #1
On Fri, Mar 18, 2022 at 12:55:22PM -0700, José Roberto de Souza wrote:
> PIPE_MBUS_DBOX_CTL was only being programmed when a pipe is being
> enabled leaving other pipes with a wrong A_CREDIT value in cases
> like when going from one pipe enabled to two pipes and the first
> pipe don't need modeset, similar when going from two or more
> pipes to ones.
> 
> So here moving the PIPE_MBUS_DBOX_CTL programing to be executed before
> the function that enables and updates all necessary pipes.
> Leaving all pipes with the correct value of A_CREDIT.
> 
> As now PIPE_MBUS_DBOX_CTL is being programmed at the right time it
> is also waiting the vblanks after adjust PIPE_MBUS_DBOX_CTL
> as required by specification.
> 
> BSpec: 49213
> BSpec: 50343
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
> Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_display.c | 36 +------------
>  drivers/gpu/drm/i915/intel_pm.c              | 55 +++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_pm.h              |  1 +
>  3 files changed, 56 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 2e85ae575423a..4cd2d76058b8c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -1821,34 +1821,6 @@ static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
>  	intel_de_write(dev_priv, CLKGATE_DIS_PSL(pipe), val);
>  }
>  
> -static void icl_pipe_mbus_enable(struct intel_crtc *crtc, bool joined_mbus)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -	enum pipe pipe = crtc->pipe;
> -	u32 val = intel_de_read(dev_priv, PIPE_MBUS_DBOX_CTL(pipe));
> -
> -	val &= ~MBUS_DBOX_A_CREDIT_MASK;
> -	/* Wa_22010947358:adl-p */
> -	if (IS_ALDERLAKE_P(dev_priv))
> -		val |= joined_mbus ? MBUS_DBOX_A_CREDIT(6) : MBUS_DBOX_A_CREDIT(4);
> -	else
> -		val |= MBUS_DBOX_A_CREDIT(2);
> -
> -	val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
> -	if (IS_ALDERLAKE_P(dev_priv)) {
> -		val |= MBUS_DBOX_BW_CREDIT(2);
> -		val |= MBUS_DBOX_B_CREDIT(8);
> -	} else if (DISPLAY_VER(dev_priv) >= 12) {
> -		val |= MBUS_DBOX_BW_CREDIT(2);
> -		val |= MBUS_DBOX_B_CREDIT(12);
> -	} else {
> -		val |= MBUS_DBOX_BW_CREDIT(1);
> -		val |= MBUS_DBOX_B_CREDIT(8);
> -	}
> -
> -	intel_de_write(dev_priv, PIPE_MBUS_DBOX_CTL(pipe), val);
> -}
> -
>  static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state)
>  {
>  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> @@ -1984,13 +1956,6 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
>  
>  	intel_initial_watermarks(state, crtc);
>  
> -	if (DISPLAY_VER(dev_priv) >= 11) {
> -		const struct intel_dbuf_state *dbuf_state =
> -				intel_atomic_get_new_dbuf_state(state);
> -
> -		icl_pipe_mbus_enable(crtc, dbuf_state->joined_mbus);
> -	}
> -
>  	if (intel_crtc_is_bigjoiner_slave(new_crtc_state))
>  		intel_crtc_vblank_on(new_crtc_state);
>  
> @@ -8589,6 +8554,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
>  	intel_encoders_update_prepare(state);
>  
>  	intel_dbuf_pre_plane_update(state);
> +	intel_mbus_dbox_update(state);
>  
>  	for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
>  		if (new_crtc_state->do_async_flip)
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 96bb8ecc11668..08ba32e5eb4ad 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -6172,7 +6172,6 @@ skl_compute_ddb(struct intel_atomic_state *state)
>  			return ret;
>  
>  		if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
> -			/* TODO: Implement vblank synchronized MBUS joining changes */
>  			ret = intel_modeset_all_pipes(state);
>  			if (ret)
>  				return ret;
> @@ -8365,3 +8364,57 @@ void intel_dbuf_post_plane_update(struct intel_atomic_state *state)
>  	gen9_dbuf_slices_update(dev_priv,
>  				new_dbuf_state->enabled_slices);
>  }
> +
> +void intel_mbus_dbox_update(struct intel_atomic_state *state)
> +{
> +	struct drm_i915_private *i915 = to_i915(state->base.dev);
> +	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
> +	struct intel_dbuf_state *old_dbuf_state, *new_dbuf_state;
> +	struct intel_crtc *crtc;
> +	int i;
> +
> +	if (DISPLAY_VER(i915) < 11 || !state->modeset)
> +		return;
> +
> +	if (HAS_MBUS_JOINING(i915)) {
> +		new_dbuf_state = intel_atomic_get_dbuf_state(state);
> +		old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
> +	}
> +
> +	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
> +		u32 val;
> +
> +		val = intel_de_read(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe));

In which power well does that live? and are we guaranteed to
have that enabled here?

I guess tou could just do something like
 if (!hw.active || !needs_modeset)
 	continue;
since I don't think there's much point in programming this
for inactive pipes, or pipes that have already been enabled
earlier. That should also avoid any power well issues.

> +		val &= ~MBUS_DBOX_A_CREDIT_MASK;
> +
> +		/* Wa_22010947358:adl-p */
> +		if (IS_ALDERLAKE_P(i915))
> +			val |= new_dbuf_state->joined_mbus ? MBUS_DBOX_A_CREDIT(6) :
> +							     MBUS_DBOX_A_CREDIT(4);
> +		else
> +			val |= MBUS_DBOX_A_CREDIT(2);
> +
> +		if (IS_ALDERLAKE_P(i915)) {
> +			val |= MBUS_DBOX_BW_CREDIT(2);
> +			val |= MBUS_DBOX_B_CREDIT(8);
> +		} else if (DISPLAY_VER(i915) >= 12) {
> +			val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
> +			val |= MBUS_DBOX_BW_CREDIT(2);
> +			val |= MBUS_DBOX_B_CREDIT(12);
> +		} else {
> +			val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
> +			val |= MBUS_DBOX_BW_CREDIT(1);
> +			val |= MBUS_DBOX_B_CREDIT(8);
> +		}
> +
> +		intel_de_write(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe), val);
> +
> +		/* If going from joined to not joined, wait a vblank */
> +		if (HAS_MBUS_JOINING(i915) &&
> +		    old_crtc_state->hw.active &&
> +		    new_crtc_state->hw.active &&
> +		    old_dbuf_state->joined_mbus &&
> +		    !new_dbuf_state->joined_mbus)
> +			intel_crtc_wait_for_next_vblank(crtc);

That check does not guarantee the pipe is active when you call this.
It could be doing a enabled->enabled modeset. In fact that is guaranteed
to be the case since we anyway force a full modeset on everything when
changing mbus joining. So you can just nuke this vblank wait.

> +	}
> +}
> diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h
> index 51705151b842f..50604cf7398c4 100644
> --- a/drivers/gpu/drm/i915/intel_pm.h
> +++ b/drivers/gpu/drm/i915/intel_pm.h
> @@ -94,5 +94,6 @@ intel_atomic_get_dbuf_state(struct intel_atomic_state *state);
>  int intel_dbuf_init(struct drm_i915_private *dev_priv);
>  void intel_dbuf_pre_plane_update(struct intel_atomic_state *state);
>  void intel_dbuf_post_plane_update(struct intel_atomic_state *state);
> +void intel_mbus_dbox_update(struct intel_atomic_state *state);

AFAICS you could just call this from intel_dbuf_pre_plane_update()
instead of making the high level modeset code have to deal with it.

>  
>  #endif /* __INTEL_PM_H__ */
> -- 
> 2.35.1
Souza, Jose March 22, 2022, 5:07 p.m. UTC | #2
On Fri, 2022-03-18 at 23:28 +0200, Ville Syrjälä wrote:
> On Fri, Mar 18, 2022 at 12:55:22PM -0700, José Roberto de Souza wrote:
> > PIPE_MBUS_DBOX_CTL was only being programmed when a pipe is being
> > enabled leaving other pipes with a wrong A_CREDIT value in cases
> > like when going from one pipe enabled to two pipes and the first
> > pipe don't need modeset, similar when going from two or more
> > pipes to ones.
> > 
> > So here moving the PIPE_MBUS_DBOX_CTL programing to be executed before
> > the function that enables and updates all necessary pipes.
> > Leaving all pipes with the correct value of A_CREDIT.
> > 
> > As now PIPE_MBUS_DBOX_CTL is being programmed at the right time it
> > is also waiting the vblanks after adjust PIPE_MBUS_DBOX_CTL
> > as required by specification.
> > 
> > BSpec: 49213
> > BSpec: 50343
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
> > Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_display.c | 36 +------------
> >  drivers/gpu/drm/i915/intel_pm.c              | 55 +++++++++++++++++++-
> >  drivers/gpu/drm/i915/intel_pm.h              |  1 +
> >  3 files changed, 56 insertions(+), 36 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> > index 2e85ae575423a..4cd2d76058b8c 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display.c
> > +++ b/drivers/gpu/drm/i915/display/intel_display.c
> > @@ -1821,34 +1821,6 @@ static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
> >  	intel_de_write(dev_priv, CLKGATE_DIS_PSL(pipe), val);
> >  }
> >  
> > -static void icl_pipe_mbus_enable(struct intel_crtc *crtc, bool joined_mbus)
> > -{
> > -	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> > -	enum pipe pipe = crtc->pipe;
> > -	u32 val = intel_de_read(dev_priv, PIPE_MBUS_DBOX_CTL(pipe));
> > -
> > -	val &= ~MBUS_DBOX_A_CREDIT_MASK;
> > -	/* Wa_22010947358:adl-p */
> > -	if (IS_ALDERLAKE_P(dev_priv))
> > -		val |= joined_mbus ? MBUS_DBOX_A_CREDIT(6) : MBUS_DBOX_A_CREDIT(4);
> > -	else
> > -		val |= MBUS_DBOX_A_CREDIT(2);
> > -
> > -	val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
> > -	if (IS_ALDERLAKE_P(dev_priv)) {
> > -		val |= MBUS_DBOX_BW_CREDIT(2);
> > -		val |= MBUS_DBOX_B_CREDIT(8);
> > -	} else if (DISPLAY_VER(dev_priv) >= 12) {
> > -		val |= MBUS_DBOX_BW_CREDIT(2);
> > -		val |= MBUS_DBOX_B_CREDIT(12);
> > -	} else {
> > -		val |= MBUS_DBOX_BW_CREDIT(1);
> > -		val |= MBUS_DBOX_B_CREDIT(8);
> > -	}
> > -
> > -	intel_de_write(dev_priv, PIPE_MBUS_DBOX_CTL(pipe), val);
> > -}
> > -
> >  static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state)
> >  {
> >  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> > @@ -1984,13 +1956,6 @@ static void hsw_crtc_enable(struct intel_atomic_state *state,
> >  
> >  	intel_initial_watermarks(state, crtc);
> >  
> > -	if (DISPLAY_VER(dev_priv) >= 11) {
> > -		const struct intel_dbuf_state *dbuf_state =
> > -				intel_atomic_get_new_dbuf_state(state);
> > -
> > -		icl_pipe_mbus_enable(crtc, dbuf_state->joined_mbus);
> > -	}
> > -
> >  	if (intel_crtc_is_bigjoiner_slave(new_crtc_state))
> >  		intel_crtc_vblank_on(new_crtc_state);
> >  
> > @@ -8589,6 +8554,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
> >  	intel_encoders_update_prepare(state);
> >  
> >  	intel_dbuf_pre_plane_update(state);
> > +	intel_mbus_dbox_update(state);
> >  
> >  	for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
> >  		if (new_crtc_state->do_async_flip)
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 96bb8ecc11668..08ba32e5eb4ad 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -6172,7 +6172,6 @@ skl_compute_ddb(struct intel_atomic_state *state)
> >  			return ret;
> >  
> >  		if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
> > -			/* TODO: Implement vblank synchronized MBUS joining changes */
> >  			ret = intel_modeset_all_pipes(state);
> >  			if (ret)
> >  				return ret;
> > @@ -8365,3 +8364,57 @@ void intel_dbuf_post_plane_update(struct intel_atomic_state *state)
> >  	gen9_dbuf_slices_update(dev_priv,
> >  				new_dbuf_state->enabled_slices);
> >  }
> > +
> > +void intel_mbus_dbox_update(struct intel_atomic_state *state)
> > +{
> > +	struct drm_i915_private *i915 = to_i915(state->base.dev);
> > +	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
> > +	struct intel_dbuf_state *old_dbuf_state, *new_dbuf_state;
> > +	struct intel_crtc *crtc;
> > +	int i;
> > +
> > +	if (DISPLAY_VER(i915) < 11 || !state->modeset)
> > +		return;
> > +
> > +	if (HAS_MBUS_JOINING(i915)) {
> > +		new_dbuf_state = intel_atomic_get_dbuf_state(state);
> > +		old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
> > +	}
> > +
> > +	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
> > +		u32 val;
> > +
> > +		val = intel_de_read(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe));
> 
> In which power well does that live? and are we guaranteed to
> have that enabled here?

No guarantee, I missed that and CI caught it too.

> 
> I guess tou could just do something like
>  if (!hw.active || !needs_modeset)
>  	continue;
> since I don't think there's much point in programming this
> for inactive pipes, or pipes that have already been enabled
> earlier. That should also avoid any power well issues.
> 
> > +		val &= ~MBUS_DBOX_A_CREDIT_MASK;
> > +
> > +		/* Wa_22010947358:adl-p */
> > +		if (IS_ALDERLAKE_P(i915))
> > +			val |= new_dbuf_state->joined_mbus ? MBUS_DBOX_A_CREDIT(6) :
> > +							     MBUS_DBOX_A_CREDIT(4);
> > +		else
> > +			val |= MBUS_DBOX_A_CREDIT(2);
> > +
> > +		if (IS_ALDERLAKE_P(i915)) {
> > +			val |= MBUS_DBOX_BW_CREDIT(2);
> > +			val |= MBUS_DBOX_B_CREDIT(8);
> > +		} else if (DISPLAY_VER(i915) >= 12) {
> > +			val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
> > +			val |= MBUS_DBOX_BW_CREDIT(2);
> > +			val |= MBUS_DBOX_B_CREDIT(12);
> > +		} else {
> > +			val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
> > +			val |= MBUS_DBOX_BW_CREDIT(1);
> > +			val |= MBUS_DBOX_B_CREDIT(8);
> > +		}
> > +
> > +		intel_de_write(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe), val);
> > +
> > +		/* If going from joined to not joined, wait a vblank */
> > +		if (HAS_MBUS_JOINING(i915) &&
> > +		    old_crtc_state->hw.active &&
> > +		    new_crtc_state->hw.active &&
> > +		    old_dbuf_state->joined_mbus &&
> > +		    !new_dbuf_state->joined_mbus)
> > +			intel_crtc_wait_for_next_vblank(crtc);
> 
> That check does not guarantee the pipe is active when you call this.
> It could be doing a enabled->enabled modeset. In fact that is guaranteed
> to be the case since we anyway force a full modeset on everything when
> changing mbus joining. So you can just nuke this vblank wait.

oh okay, missed that intel_compute_global_watermarks() is called after intel_crtc_check_fastset().
So yep, all active pipes will be disabled when joined_mbus changes.

Will send a new version shortly, thanks for the feedback.

> 
> > +	}
> > +}
> > diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h
> > index 51705151b842f..50604cf7398c4 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.h
> > +++ b/drivers/gpu/drm/i915/intel_pm.h
> > @@ -94,5 +94,6 @@ intel_atomic_get_dbuf_state(struct intel_atomic_state *state);
> >  int intel_dbuf_init(struct drm_i915_private *dev_priv);
> >  void intel_dbuf_pre_plane_update(struct intel_atomic_state *state);
> >  void intel_dbuf_post_plane_update(struct intel_atomic_state *state);
> > +void intel_mbus_dbox_update(struct intel_atomic_state *state);
> 
> AFAICS you could just call this from intel_dbuf_pre_plane_update()
> instead of making the high level modeset code have to deal with it.
> 
> >  
> >  #endif /* __INTEL_PM_H__ */
> > -- 
> > 2.35.1
>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 2e85ae575423a..4cd2d76058b8c 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -1821,34 +1821,6 @@  static void glk_pipe_scaler_clock_gating_wa(struct drm_i915_private *dev_priv,
 	intel_de_write(dev_priv, CLKGATE_DIS_PSL(pipe), val);
 }
 
-static void icl_pipe_mbus_enable(struct intel_crtc *crtc, bool joined_mbus)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	enum pipe pipe = crtc->pipe;
-	u32 val = intel_de_read(dev_priv, PIPE_MBUS_DBOX_CTL(pipe));
-
-	val &= ~MBUS_DBOX_A_CREDIT_MASK;
-	/* Wa_22010947358:adl-p */
-	if (IS_ALDERLAKE_P(dev_priv))
-		val |= joined_mbus ? MBUS_DBOX_A_CREDIT(6) : MBUS_DBOX_A_CREDIT(4);
-	else
-		val |= MBUS_DBOX_A_CREDIT(2);
-
-	val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
-	if (IS_ALDERLAKE_P(dev_priv)) {
-		val |= MBUS_DBOX_BW_CREDIT(2);
-		val |= MBUS_DBOX_B_CREDIT(8);
-	} else if (DISPLAY_VER(dev_priv) >= 12) {
-		val |= MBUS_DBOX_BW_CREDIT(2);
-		val |= MBUS_DBOX_B_CREDIT(12);
-	} else {
-		val |= MBUS_DBOX_BW_CREDIT(1);
-		val |= MBUS_DBOX_B_CREDIT(8);
-	}
-
-	intel_de_write(dev_priv, PIPE_MBUS_DBOX_CTL(pipe), val);
-}
-
 static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -1984,13 +1956,6 @@  static void hsw_crtc_enable(struct intel_atomic_state *state,
 
 	intel_initial_watermarks(state, crtc);
 
-	if (DISPLAY_VER(dev_priv) >= 11) {
-		const struct intel_dbuf_state *dbuf_state =
-				intel_atomic_get_new_dbuf_state(state);
-
-		icl_pipe_mbus_enable(crtc, dbuf_state->joined_mbus);
-	}
-
 	if (intel_crtc_is_bigjoiner_slave(new_crtc_state))
 		intel_crtc_vblank_on(new_crtc_state);
 
@@ -8589,6 +8554,7 @@  static void intel_atomic_commit_tail(struct intel_atomic_state *state)
 	intel_encoders_update_prepare(state);
 
 	intel_dbuf_pre_plane_update(state);
+	intel_mbus_dbox_update(state);
 
 	for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
 		if (new_crtc_state->do_async_flip)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 96bb8ecc11668..08ba32e5eb4ad 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -6172,7 +6172,6 @@  skl_compute_ddb(struct intel_atomic_state *state)
 			return ret;
 
 		if (old_dbuf_state->joined_mbus != new_dbuf_state->joined_mbus) {
-			/* TODO: Implement vblank synchronized MBUS joining changes */
 			ret = intel_modeset_all_pipes(state);
 			if (ret)
 				return ret;
@@ -8365,3 +8364,57 @@  void intel_dbuf_post_plane_update(struct intel_atomic_state *state)
 	gen9_dbuf_slices_update(dev_priv,
 				new_dbuf_state->enabled_slices);
 }
+
+void intel_mbus_dbox_update(struct intel_atomic_state *state)
+{
+	struct drm_i915_private *i915 = to_i915(state->base.dev);
+	struct intel_crtc_state *old_crtc_state, *new_crtc_state;
+	struct intel_dbuf_state *old_dbuf_state, *new_dbuf_state;
+	struct intel_crtc *crtc;
+	int i;
+
+	if (DISPLAY_VER(i915) < 11 || !state->modeset)
+		return;
+
+	if (HAS_MBUS_JOINING(i915)) {
+		new_dbuf_state = intel_atomic_get_dbuf_state(state);
+		old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
+	}
+
+	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+		u32 val;
+
+		val = intel_de_read(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe));
+		val &= ~MBUS_DBOX_A_CREDIT_MASK;
+
+		/* Wa_22010947358:adl-p */
+		if (IS_ALDERLAKE_P(i915))
+			val |= new_dbuf_state->joined_mbus ? MBUS_DBOX_A_CREDIT(6) :
+							     MBUS_DBOX_A_CREDIT(4);
+		else
+			val |= MBUS_DBOX_A_CREDIT(2);
+
+		if (IS_ALDERLAKE_P(i915)) {
+			val |= MBUS_DBOX_BW_CREDIT(2);
+			val |= MBUS_DBOX_B_CREDIT(8);
+		} else if (DISPLAY_VER(i915) >= 12) {
+			val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
+			val |= MBUS_DBOX_BW_CREDIT(2);
+			val |= MBUS_DBOX_B_CREDIT(12);
+		} else {
+			val &= ~(MBUS_DBOX_BW_CREDIT_MASK | MBUS_DBOX_B_CREDIT_MASK);
+			val |= MBUS_DBOX_BW_CREDIT(1);
+			val |= MBUS_DBOX_B_CREDIT(8);
+		}
+
+		intel_de_write(i915, PIPE_MBUS_DBOX_CTL(crtc->pipe), val);
+
+		/* If going from joined to not joined, wait a vblank */
+		if (HAS_MBUS_JOINING(i915) &&
+		    old_crtc_state->hw.active &&
+		    new_crtc_state->hw.active &&
+		    old_dbuf_state->joined_mbus &&
+		    !new_dbuf_state->joined_mbus)
+			intel_crtc_wait_for_next_vblank(crtc);
+	}
+}
diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h
index 51705151b842f..50604cf7398c4 100644
--- a/drivers/gpu/drm/i915/intel_pm.h
+++ b/drivers/gpu/drm/i915/intel_pm.h
@@ -94,5 +94,6 @@  intel_atomic_get_dbuf_state(struct intel_atomic_state *state);
 int intel_dbuf_init(struct drm_i915_private *dev_priv);
 void intel_dbuf_pre_plane_update(struct intel_atomic_state *state);
 void intel_dbuf_post_plane_update(struct intel_atomic_state *state);
+void intel_mbus_dbox_update(struct intel_atomic_state *state);
 
 #endif /* __INTEL_PM_H__ */