]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/i915/dsb: Enable programmable DSB interrupt
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Mon, 30 Sep 2024 17:04:06 +0000 (20:04 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 3 Oct 2024 21:33:02 +0000 (00:33 +0300)
The DSB can signal a programmable interrupt in response to
a specific DSB command getting executed. Hook that up.

For now we'll just use this to signal the completion of the
commit via a vblank event. If, in the future, we'll need to
do other things in response to DSB interrupts we may need to
come up with some kind of fancier DSB interrupt framework where
the caller can specify a custom handler...

Reviewed-by: Animesh Manna <animesh.manna@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240930170415.23841-5-ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dsb.c
drivers/gpu/drm/i915/display/intel_dsb.h

index 17fc21f6ae362d6dac8d8fbd99ace4eb5f9d6d97..e0ec2126604723233e98dad2347bb8fedf97e960 100644 (file)
@@ -1358,6 +1358,8 @@ struct intel_crtc {
 
        /* armed event for async flip */
        struct drm_pending_vblank_event *flip_done_event;
+       /* armed event for DSB based updates */
+       struct drm_pending_vblank_event *dsb_event;
 
        /* Access to these should be protected by dev_priv->irq_lock. */
        bool cpu_fifo_underrun_disabled;
index 1a574c9300b1ef23b2eacc3e270ba93fefeb64ab..8514d721914007ade5c8cea6b43cd88f510c71fd 100644 (file)
@@ -4,6 +4,8 @@
  *
  */
 
+#include <drm/drm_vblank.h>
+
 #include "i915_drv.h"
 #include "i915_irq.h"
 #include "i915_reg.h"
@@ -379,6 +381,12 @@ void intel_dsb_nonpost_end(struct intel_dsb *dsb)
        intel_dsb_noop(dsb, 4);
 }
 
+void intel_dsb_interrupt(struct intel_dsb *dsb)
+{
+       intel_dsb_emit(dsb, 0,
+                      DSB_OPCODE_INTERRUPT << DSB_OPCODE_SHIFT);
+}
+
 static void intel_dsb_emit_wait_dsl(struct intel_dsb *dsb,
                                    u32 opcode, int lower, int upper)
 {
@@ -544,7 +552,7 @@ static void _intel_dsb_chain(struct intel_atomic_state *state,
 
        intel_dsb_reg_write(dsb, DSB_INTERRUPT(pipe, chained_dsb->id),
                            dsb_error_int_status(display) | DSB_PROG_INT_STATUS |
-                           dsb_error_int_en(display));
+                           dsb_error_int_en(display) | DSB_PROG_INT_EN);
 
        if (ctrl & DSB_WAIT_FOR_VBLANK) {
                int dewake_scanline = dsb_dewake_scanline_start(state, crtc);
@@ -612,7 +620,7 @@ static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl,
 
        intel_de_write_fw(display, DSB_INTERRUPT(pipe, dsb->id),
                          dsb_error_int_status(display) | DSB_PROG_INT_STATUS |
-                         dsb_error_int_en(display));
+                         dsb_error_int_en(display) | DSB_PROG_INT_EN);
 
        intel_de_write_fw(display, DSB_HEAD(pipe, dsb->id),
                          intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf));
@@ -779,6 +787,23 @@ void intel_dsb_irq_handler(struct intel_display *display,
        tmp = intel_de_read_fw(display, DSB_INTERRUPT(pipe, dsb_id));
        intel_de_write_fw(display, DSB_INTERRUPT(pipe, dsb_id), tmp);
 
+       if (tmp & DSB_PROG_INT_STATUS) {
+               spin_lock(&display->drm->event_lock);
+
+               if (crtc->dsb_event) {
+                       /*
+                        * Update vblank counter/timestmap in case it
+                        * hasn't been done yet for this frame.
+                        */
+                       drm_crtc_accurate_vblank_count(&crtc->base);
+
+                       drm_crtc_send_vblank_event(&crtc->base, crtc->dsb_event);
+                       crtc->dsb_event = NULL;
+               }
+
+               spin_unlock(&display->drm->event_lock);
+       }
+
        errors = tmp & dsb_error_int_status(display);
        if (errors)
                drm_err(display->drm, "[CRTC:%d:%s] DSB %d error interrupt: 0x%x\n",
index c352c12aa59f9579cecc43c1fa53d32c462ced29..ff3b89dfffc1c35518d5ebefcd04508a90762f29 100644 (file)
@@ -39,6 +39,7 @@ void intel_dsb_reg_write_masked(struct intel_dsb *dsb,
 void intel_dsb_noop(struct intel_dsb *dsb, int count);
 void intel_dsb_nonpost_start(struct intel_dsb *dsb);
 void intel_dsb_nonpost_end(struct intel_dsb *dsb);
+void intel_dsb_interrupt(struct intel_dsb *dsb);
 void intel_dsb_wait_scanline_in(struct intel_atomic_state *state,
                                struct intel_dsb *dsb,
                                int lower, int upper);