]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/i915/dmc: Hook up PIPEDMC interrupts
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 14 May 2025 17:42:57 +0000 (20:42 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 16 May 2025 08:31:11 +0000 (11:31 +0300)
Hook up PIPEDMC interrupts. We'll need these for:
- flip queue signalling
- GTT/ATS faults on LNL+
- unclaimed register access errors (supposedly that is what
  the error interrupt indicated according to Windows code).

On LNL+ we get a new level of interrupts registers PIPEDMC_INTERRUPT*.
On earlier platforms we only have the INT_VECTOR field in the
PIPEDMC_STATUS registers, whose values are defined by the firmware.

For now we'll enable the interrupts on LNL+ only. For earlier platforms
it's not clear that there is any use for these interrupts, and some
ADL machines have exhibited spurious DE_PIPE interrupts with the
PIPEDMC interrupts unmasked/enabled. We can revisit enabling these
for earlier platforms in the future.

For some unknown reason LNL pipe B triggers the error interrupt
during the first DC state transition (subsequent transitions are
maybe OK?). No clear idea what's going on here yet, so keep the
error interrupt disabled for now.

Similar to DSB interrupt registers, the unused bits in
PIPEDMC_INTERRUPT* seem to act like randomg r/w bits (instead
of being hardwired to 0 like one would expect), and so we'll try
to avoid setting them so that we don't mistake them for real
interrupts.

v2: Only enable/unmask for LNL+
    Keep the flip queue interrupt masked off for now since
    we don't have a use for it yet
v3: Also keep the error interrupt masked off for now due to
    LNL pipe B triggering it

Reviewed-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250514174257.8708-1-ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/intel_display_device.h
drivers/gpu/drm/i915/display/intel_display_irq.c
drivers/gpu/drm/i915/display/intel_dmc.c
drivers/gpu/drm/i915/display/intel_dmc.h
drivers/gpu/drm/i915/display/intel_dmc_regs.h
drivers/gpu/drm/i915/i915_reg.h

index fe14a92ae8c6530f95e763a00df9c4d3ea5db2c2..f0ea56cc5def5e7e4f56a87073bb9e749b31a6e8 100644 (file)
@@ -182,6 +182,7 @@ struct intel_display_platforms {
 #define HAS_MBUS_JOINING(__display)    ((__display)->platform.alderlake_p || DISPLAY_VER(__display) >= 14)
 #define HAS_MSO(__display)             (DISPLAY_VER(__display) >= 12)
 #define HAS_OVERLAY(__display)         (DISPLAY_INFO(__display)->has_overlay)
+#define HAS_PIPEDMC(__display)         (DISPLAY_VER(__display) >= 12)
 #define HAS_PSR(__display)             (DISPLAY_INFO(__display)->has_psr)
 #define HAS_PSR_HW_TRACKING(__display) (DISPLAY_INFO(__display)->has_psr_hw_tracking)
 #define HAS_PSR2_SEL_FETCH(__display)  (DISPLAY_VER(__display) >= 12)
index a7130b14aaceeecd6969b0979be36c6583e6a6fc..c24841f57aac4aef2c279d1a964e7e093b108dfa 100644 (file)
@@ -17,6 +17,7 @@
 #include "intel_display_rps.h"
 #include "intel_display_trace.h"
 #include "intel_display_types.h"
+#include "intel_dmc.h"
 #include "intel_dmc_wl.h"
 #include "intel_dp_aux.h"
 #include "intel_dsb.h"
@@ -1449,6 +1450,9 @@ void gen8_de_irq_handler(struct intel_display *display, u32 master_ctl)
                                intel_dsb_irq_handler(display, pipe, INTEL_DSB_2);
                }
 
+               if (HAS_PIPEDMC(display) && iir & GEN12_PIPEDMC_INTERRUPT)
+                       intel_pipedmc_irq_handler(display, pipe);
+
                if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
                        hsw_pipe_crc_irq_handler(display, pipe);
 
@@ -2266,6 +2270,10 @@ void gen8_de_irq_postinstall(struct intel_display *display)
                        GEN12_DSB_INT(INTEL_DSB_1) |
                        GEN12_DSB_INT(INTEL_DSB_2);
 
+       /* TODO figure PIPEDMC interrupts for pre-LNL */
+       if (DISPLAY_VER(display) >= 20)
+               de_pipe_masked |= GEN12_PIPEDMC_INTERRUPT;
+
        de_pipe_enables = de_pipe_masked |
                GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN |
                gen8_de_pipe_flip_done_mask(display);
index b58189d24e7e404442482a98c26897242d806665..16dc52a8302c8b70d74d154e953225ecc41974ca 100644 (file)
 
 #include "i915_drv.h"
 #include "i915_reg.h"
+#include "intel_crtc.h"
 #include "intel_de.h"
 #include "intel_display_rpm.h"
 #include "intel_display_power_well.h"
+#include "intel_display_types.h"
 #include "intel_dmc.h"
 #include "intel_dmc_regs.h"
 #include "intel_step.h"
@@ -490,6 +492,17 @@ static void pipedmc_clock_gating_wa(struct intel_display *display, bool enable)
                adlp_pipedmc_clock_gating_wa(display, enable);
 }
 
+static u32 pipedmc_interrupt_mask(struct intel_display *display)
+{
+       /*
+        * FIXME PIPEDMC_ERROR not enabled for now due to LNL pipe B
+        * triggering it during the first DC state transition. Figure
+        * out what is going on...
+        */
+       return PIPEDMC_GTT_FAULT |
+               PIPEDMC_ATS_FAULT;
+}
+
 void intel_dmc_enable_pipe(struct intel_display *display, enum pipe pipe)
 {
        enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe);
@@ -497,6 +510,11 @@ void intel_dmc_enable_pipe(struct intel_display *display, enum pipe pipe)
        if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id))
                return;
 
+       if (DISPLAY_VER(display) >= 20) {
+               intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display));
+               intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~pipedmc_interrupt_mask(display));
+       }
+
        if (DISPLAY_VER(display) >= 14)
                intel_de_rmw(display, MTL_PIPEDMC_CONTROL, 0, PIPEDMC_ENABLE_MTL(pipe));
        else
@@ -514,6 +532,11 @@ void intel_dmc_disable_pipe(struct intel_display *display, enum pipe pipe)
                intel_de_rmw(display, MTL_PIPEDMC_CONTROL, PIPEDMC_ENABLE_MTL(pipe), 0);
        else
                intel_de_rmw(display, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0);
+
+       if (DISPLAY_VER(display) >= 20) {
+               intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~0);
+               intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display));
+       }
 }
 
 /**
@@ -1403,3 +1426,29 @@ void intel_dmc_debugfs_register(struct intel_display *display)
        debugfs_create_file("i915_dmc_info", 0444, minor->debugfs_root,
                            display, &intel_dmc_debugfs_status_fops);
 }
+
+void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe)
+{
+       struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
+       u32 tmp;
+
+       if (DISPLAY_VER(display) >= 20) {
+               tmp = intel_de_read(display, PIPEDMC_INTERRUPT(pipe));
+               intel_de_write(display, PIPEDMC_INTERRUPT(pipe), tmp);
+
+               if (tmp & PIPEDMC_ATS_FAULT)
+                       drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC ATS fault\n",
+                                           crtc->base.base.id, crtc->base.name);
+               if (tmp & PIPEDMC_GTT_FAULT)
+                       drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC GTT fault\n",
+                                           crtc->base.base.id, crtc->base.name);
+               if (tmp & PIPEDMC_ERROR)
+                       drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC error\n",
+                               crtc->base.base.id, crtc->base.name);
+       }
+
+       tmp = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK;
+       if (tmp)
+               drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n",
+                       crtc->base.base.id, crtc->base.name, tmp);
+}
index bd1c459b00757b450af5df9ebaccbf7140da0d55..a98e8deff13aa8927d0fcccb566320db5b38dda9 100644 (file)
@@ -34,4 +34,6 @@ void intel_dmc_update_dc6_allowed_count(struct intel_display *display, bool star
 
 void assert_dmc_loaded(struct intel_display *display);
 
+void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe);
+
 #endif /* __INTEL_DMC_H__ */
index e16ea3f16ed88915f34961b2888088efc85830a0..e8ac0e1be7649eb0c2c1d2617b0abe14046a6e95 100644 (file)
                                                   _MTL_PIPEDMC_EVT_CTL_4_A, \
                                                   _MTL_PIPEDMC_EVT_CTL_4_B)
 
+#define _PIPEDMC_STATUS_A              0x5f06c
+#define _PIPEDMC_STATUS_B              0x5f46c
+#define PIPEDMC_STATUS(pipe)           _MMIO_PIPE((pipe), _PIPEDMC_STATUS_A, _PIPEDMC_STATUS_B)
+#define   PIPEDMC_SSP                  REG_GENMASK(31, 16)
+#define   PIPEDMC_INT_VECTOR_MASK      REG_GENMASK(15, 8)
+/* PIPEDMC_INT_VECTOR values defined by firmware */
+#define   PIPEDMC_INT_VECTOR_SCANLINE_COMP_ERROR       REG_FIELD_PREP(PIPEDMC_INT_VECTOR_MASK, 0x1)
+#define   PIPEDMC_INT_VECTOR_DC6V_FLIPQ_OVERLAP_ERROR  REG_FIELD_PREP(PIPEDMC_INT_VECTOR_MASK, 0x2)
+#define   PIPEDMC_INT_VECTOR_FLIPQ_PROG_DONE           REG_FIELD_PREP(PIPEDMC_INT_VECTOR_MASK, 0xff) /* Wa_16018781658:lnl[a0] */
+#define   PIPEDMC_EVT_PENDING          REG_GENMASK(7, 0)
+
+#define _PIPEDMC_INTERRUPT_A           0x5f190 /* lnl+ */
+#define _PIPEDMC_INTERRUPT_B           0x5f590 /* lnl+ */
+#define PIPEDMC_INTERRUPT(pipe)                _MMIO_PIPE((pipe), _PIPEDMC_INTERRUPT_A, _PIPEDMC_INTERRUPT_B)
+#define _PIPEDMC_INTERRUPT_MASK_A      0x5f194 /* lnl+ */
+#define _PIPEDMC_INTERRUPT_MASK_B      0x5f594 /* lnl+ */
+#define PIPEDMC_INTERRUPT_MASK(pipe)   _MMIO_PIPE((pipe), _PIPEDMC_INTERRUPT_MASK_A, _PIPEDMC_INTERRUPT_MASK_B)
+#define   PIPEDMC_FLIPQ_PROG_DONE      REG_BIT(3)
+#define   PIPEDMC_ERROR                        REG_BIT(2)
+#define   PIPEDMC_GTT_FAULT            REG_BIT(1)
+#define   PIPEDMC_ATS_FAULT            REG_BIT(0)
+
 #define PIPEDMC_BLOCK_PKGC_SW_A        0x5f1d0
 #define PIPEDMC_BLOCK_PKGC_SW_B        0x5F5d0
 #define PIPEDMC_BLOCK_PKGC_SW(pipe)                            _MMIO_PIPE(pipe, \
index 2d0e04eae7630a16fe28f4591f77dabd5f5c3743..8822c639a4f4bbf3420393f0c10404585d75ea5e 100644 (file)
 #define  GEN12_PIPEDMC_INTERRUPT       REG_BIT(26) /* tgl+ */
 #define  GEN12_PIPEDMC_FAULT           REG_BIT(25) /* tgl-mtl */
 #define  MTL_PIPEDMC_ATS_FAULT         REG_BIT(24) /* mtl */
+#define  GEN12_PIPEDMC_FLIPQ_DONE      REG_BIT(24) /* tgl-adl */
 #define  GEN11_PIPE_PLANE7_FAULT       REG_BIT(22) /* icl/tgl */
 #define  GEN11_PIPE_PLANE6_FAULT       REG_BIT(21) /* icl/tgl */
 #define  GEN11_PIPE_PLANE5_FAULT       REG_BIT(20) /* icl+ */
 #define  GEN12_PIPE_VBLANK_UNMOD       REG_BIT(19) /* tgl+ */
 #define  MTL_PLANE_ATS_FAULT           REG_BIT(18) /* mtl+ */
 #define  GEN11_PIPE_PLANE7_FLIP_DONE   REG_BIT(18) /* icl/tgl */
+#define  MTL_PIPEDMC_FLIPQ_DONE                REG_BIT(17) /* mtl */
 #define  GEN11_PIPE_PLANE6_FLIP_DONE   REG_BIT(17) /* icl/tgl */
 #define  GEN11_PIPE_PLANE5_FLIP_DONE   REG_BIT(16) /* icl+ */
 #define  GEN12_DSB_2_INT               REG_BIT(15) /* tgl+ */