]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/i915/dmc: Clear HRR EVT_CTL/HTP to zero on ADL-S
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 22 Oct 2025 10:07:16 +0000 (13:07 +0300)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Tue, 28 Oct 2025 20:00:19 +0000 (16:00 -0400)
On ADL-S the main DMC HRR event DMC_EVT_CTL/HTP are never
restored to their previous values during DC6 exit. This
angers assert_dmc_loaded(), and basically makes the HRR
handler unusable because we don't rewrite EVT_HTP when
enabling DMC events.

Let's just clear the HRR EVT_CTL/HTP to zero from the
beginnning so that the expected value matches the post-DC6
reality.

I suppose if we ever had actual use for HRR we'd have to both,
reject HRR+PSR, and reprogram EVT_HTP when enabling the event.
But for now we don't care about HRR so keeping both registers
zeroed is fine.

Cc: stable@vger.kernel.org
Tested-by: Petr Vorel <pvorel@suse.cz>
Fixes: 43175c92d403 ("drm/i915/dmc: Assert DMC is loaded harder")
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15153
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20251022100718.24803-2-ville.syrjala@linux.intel.com
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Tested-by: Imre Deak <imre.deak@intel.com>
(cherry picked from commit 4df3b340ff6e9f499735d8b52b96a9257fde3918)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/i915/display/intel_dmc.c

index 77a0199f9ea5f1a4d84c820e07127ed80f04080c..4a4cace1f879d15f1d370a873124a355d409b99b 100644 (file)
@@ -546,6 +546,36 @@ static bool is_event_handler(struct intel_display *display,
                REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == event_id;
 }
 
+static bool fixup_dmc_evt(struct intel_display *display,
+                         enum intel_dmc_id dmc_id,
+                         i915_reg_t reg_ctl, u32 *data_ctl,
+                         i915_reg_t reg_htp, u32 *data_htp)
+{
+       if (!is_dmc_evt_ctl_reg(display, dmc_id, reg_ctl))
+               return false;
+
+       if (!is_dmc_evt_htp_reg(display, dmc_id, reg_htp))
+               return false;
+
+       /* make sure reg_ctl and reg_htp are for the same event */
+       if (i915_mmio_reg_offset(reg_ctl) - i915_mmio_reg_offset(DMC_EVT_CTL(display, dmc_id, 0)) !=
+           i915_mmio_reg_offset(reg_htp) - i915_mmio_reg_offset(DMC_EVT_HTP(display, dmc_id, 0)))
+               return false;
+
+       /*
+        * On ADL-S the HRR event handler is not restored after DC6.
+        * Clear it to zero from the beginning to avoid mismatches later.
+        */
+       if (display->platform.alderlake_s && dmc_id == DMC_FW_MAIN &&
+           is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg_ctl, *data_ctl)) {
+               *data_ctl = 0;
+               *data_htp = 0;
+               return true;
+       }
+
+       return false;
+}
+
 static bool disable_dmc_evt(struct intel_display *display,
                            enum intel_dmc_id dmc_id,
                            i915_reg_t reg, u32 data)
@@ -1064,9 +1094,32 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc,
        for (i = 0; i < mmio_count; i++) {
                dmc_info->mmioaddr[i] = _MMIO(mmioaddr[i]);
                dmc_info->mmiodata[i] = mmiodata[i];
+       }
+
+       for (i = 0; i < mmio_count - 1; i++) {
+               u32 orig_mmiodata[2] = {
+                       dmc_info->mmiodata[i],
+                       dmc_info->mmiodata[i+1],
+               };
+
+               if (!fixup_dmc_evt(display, dmc_id,
+                                  dmc_info->mmioaddr[i], &dmc_info->mmiodata[i],
+                                  dmc_info->mmioaddr[i+1], &dmc_info->mmiodata[i+1]))
+                       continue;
+
+               drm_dbg_kms(display->drm,
+                           " mmio[%d]: 0x%x = 0x%x->0x%x (EVT_CTL)\n",
+                           i, i915_mmio_reg_offset(dmc_info->mmioaddr[i]),
+                           orig_mmiodata[0], dmc_info->mmiodata[i]);
+               drm_dbg_kms(display->drm,
+                           " mmio[%d]: 0x%x = 0x%x->0x%x (EVT_HTP)\n",
+                           i+1, i915_mmio_reg_offset(dmc_info->mmioaddr[i+1]),
+                           orig_mmiodata[1], dmc_info->mmiodata[i+1]);
+       }
 
+       for (i = 0; i < mmio_count; i++) {
                drm_dbg_kms(display->drm, " mmio[%d]: 0x%x = 0x%x%s%s\n",
-                           i, mmioaddr[i], mmiodata[i],
+                           i, i915_mmio_reg_offset(dmc_info->mmioaddr[i]), dmc_info->mmiodata[i],
                            is_dmc_evt_ctl_reg(display, dmc_id, dmc_info->mmioaddr[i]) ? " (EVT_CTL)" :
                            is_dmc_evt_htp_reg(display, dmc_id, dmc_info->mmioaddr[i]) ? " (EVT_HTP)" : "",
                            disable_dmc_evt(display, dmc_id, dmc_info->mmioaddr[i],