> -----Original Message-----
> From: Manna, Animesh <[email protected]>
> Sent: Tuesday, June 16, 2026 1:34 AM
> To: [email protected]; [email protected]
> Cc: Shankar, Uma <[email protected]>; Dibin Moolakadan Subrahmanian
> <[email protected]>; [email protected];
> Nikula, Jani <[email protected]>; Manna, Animesh
> <[email protected]>
> Subject: [PATCH v9 21/22] drm/i915/cmtg: Restore CMTG after DC6 exit
>
> Restore CMTG registers after DC6 exit, as they lose their values in the
> low-power
> state.
>
> v2: Introduce intel_cmtg_restore() instead of calling multiple cmtg functions.
> [Uma]
Looks Good to me.
Reviewed-by: Uma Shankar <[email protected]>
> Signed-off-by: Animesh Manna <[email protected]>
> ---
> drivers/gpu/drm/i915/display/intel_cmtg.c | 21 +++++++++++++----
> .../drm/i915/display/intel_display_power.c | 23 +++++++++++++++++++
> .../drm/i915/display/intel_display_power.h | 2 ++
> 3 files changed, 42 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.c
> b/drivers/gpu/drm/i915/display/intel_cmtg.c
> index 8684d2ec2f83..ae59d7e755f3 100644
> --- a/drivers/gpu/drm/i915/display/intel_cmtg.c
> +++ b/drivers/gpu/drm/i915/display/intel_cmtg.c
> @@ -391,20 +391,33 @@ static void intel_cmtg_set_hwgb(const struct
> intel_crtc_state *crtc_state)
> intel_de_write(display, CMTG_HW_GB(cpu_transcoder), val); }
>
> +static void intel_cmtg_restore(const struct intel_crtc_state
> +*crtc_state) {
> + intel_cmtg_set_clk_select(crtc_state);
> + intel_cmtg_set_timings(crtc_state, MODESET);
> + intel_cmtg_set_vrr_timings(crtc_state);
> + intel_cmtg_set_vrr_ctl(crtc_state);
> + intel_cmtg_set_m_n(crtc_state);
> +}
> +
> void intel_cmtg_program(struct intel_atomic_state *state) {
> + struct intel_display *display = to_intel_display(state);
> struct intel_crtc *crtc;
> struct intel_crtc_state *new_crtc_state;
> + bool dc3co_to_dc6 =
> +intel_display_power_get_and_reset_dc3co_to_dc6(display);
>
> for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state) {
> bool modeset = intel_crtc_needs_modeset(new_crtc_state);
>
> if (!intel_cmtg_is_allowed(new_crtc_state))
> continue;
> - /*
> - * TODO: CMTG needs to be restored on DC6 exit.
> - */
> - if (modeset && new_crtc_state->hw.active && !crtc-
> >cmtg.enabled) {
> +
> + if ((modeset || dc3co_to_dc6) &&
> + new_crtc_state->hw.active && !crtc->cmtg.enabled) {
> + if (dc3co_to_dc6)
> + intel_cmtg_restore(new_crtc_state);
> +
> intel_cmtg_enable_sync(new_crtc_state);
> intel_cmtg_set_hwgb(new_crtc_state);
> intel_cmtg_enable_ddi(new_crtc_state);
> diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c
> b/drivers/gpu/drm/i915/display/intel_display_power.c
> index 2e51dfcd5dce..9783257651d2 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_power.c
> +++ b/drivers/gpu/drm/i915/display/intel_display_power.c
> @@ -285,6 +285,19 @@ sanitize_target_dc_state(struct intel_display *display,
> return target_dc_state;
> }
>
> +bool intel_display_power_get_and_reset_dc3co_to_dc6(struct
> +intel_display *display) {
> + struct i915_power_domains *power_domains = &display->power.domains;
> + bool ret;
> +
> + mutex_lock(&power_domains->lock);
> + ret = power_domains->dc3co_to_dc6;
> + power_domains->dc3co_to_dc6 = false;
> + mutex_unlock(&power_domains->lock);
> +
> + return ret;
> +}
> +
> /**
> * intel_display_power_set_target_dc_state - Set target dc state.
> * @display: display device
> @@ -300,6 +313,7 @@ void intel_display_power_set_target_dc_state(struct
> intel_display *display,
> struct i915_power_well *power_well;
> bool dc_off_enabled;
> struct i915_power_domains *power_domains = &display->power.domains;
> + u32 old_target_dc_state;
>
> mutex_lock(&power_domains->lock);
> power_well = lookup_power_well(display, SKL_DISP_DC_OFF); @@ -
> 320,8 +334,17 @@ void intel_display_power_set_target_dc_state(struct
> intel_display *display,
> if (!dc_off_enabled)
> intel_power_well_enable(display, power_well);
>
> + old_target_dc_state = power_domains->target_dc_state;
> power_domains->target_dc_state = state;
>
> + /*
> + * CMTG must be restored explicitly after DC6 exit. The dc3co_to_dc6
> + * flag helps CMTG determine whether restoration is required.
> + */
> + if (old_target_dc_state == DC_STATE_EN_DC3CO &&
> + power_domains->target_dc_state == DC_STATE_EN_UPTO_DC6)
> + power_domains->dc3co_to_dc6 = true;
> +
> if (!dc_off_enabled)
> intel_power_well_disable(display, power_well);
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h
> b/drivers/gpu/drm/i915/display/intel_display_power.h
> index 56dc89eed3f8..b9c9b68072af 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_power.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_power.h
> @@ -138,6 +138,7 @@ struct i915_power_domains {
> */
> bool initializing;
> bool display_core_suspended;
> + bool dc3co_to_dc6;
> int power_well_count;
>
> u32 dc_state;
> @@ -179,6 +180,7 @@ void intel_display_power_sanitize_state(struct
> intel_display *display);
>
> void intel_display_power_suspend_late(struct intel_display *display, bool
> s2idle);
> void intel_display_power_resume_early(struct intel_display *display);
> +bool intel_display_power_get_and_reset_dc3co_to_dc6(struct
> +intel_display *display);
> void intel_display_power_set_target_dc_state(struct intel_display *display,
> u32 state);
> u32 intel_display_power_get_current_dc_state(struct intel_display *display);
> --
> 2.29.0