]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/i915/dsb: Implement intel_dsb_gosub()
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 23 May 2025 06:20:34 +0000 (11:50 +0530)
committerAnimesh Manna <animesh.manna@intel.com>
Mon, 26 May 2025 07:48:15 +0000 (13:18 +0530)
Add support for the new GOSUB DSB instruction (available on ptl+),
which instructs the DSB to jump to a different buffer, execute
the commands there, and then return execution to the next
instruction in the original buffer.

There are a few alignment related workarounds that need to
be dealt with when emitting GOSUB instruction.

v2: Right shift head and tail pointer passed to gosub command (chaitanya)
v3: Add macro for right shifting head/tail pointers (Animesh)
v4: Fix typo in commit message (Uma)
    Add comments explaining why right shifting htp is needed (Animesh)

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Chaitanya Kumar Borah <chaitanya.kumar.borah@intel.com>
Reviewed-by: Uma Shankar <uma.shankar@intel.com>
Reviewed-by: Animesh Manna <animesh.manna@intel.com>
Signed-off-by: Animesh Manna <animesh.manna@intel.com>
Link: https://lore.kernel.org/r/20250523062041.166468-5-chaitanya.kumar.borah@intel.com
drivers/gpu/drm/i915/display/intel_dsb.c
drivers/gpu/drm/i915/display/intel_dsb.h

index 9b2de4e7e681ebaf7a81f72104840f80dbad83ee..cd32b59adf18751ad0627c2f3472f5583084aa90 100644 (file)
@@ -93,6 +93,10 @@ struct intel_dsb {
 /* see DSB_REG_VALUE_MASK */
 #define DSB_OPCODE_POLL                        0xA
 /* see DSB_REG_VALUE_MASK */
+#define DSB_OPCODE_GOSUB               0xC /* ptl+ */
+#define   DSB_GOSUB_HEAD_SHIFT         26
+#define   DSB_GOSUB_TAIL_SHIFT         0
+#define   DSB_GOSUB_CONVERT_ADDR(x)    ((x) >> 6)
 
 static bool pre_commit_is_vrr_active(struct intel_atomic_state *state,
                                     struct intel_crtc *crtc)
@@ -533,6 +537,75 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb)
        dsb->free_pos = aligned_tail / 4;
 }
 
+static void intel_dsb_gosub_align(struct intel_dsb *dsb)
+{
+       u32 aligned_tail, tail;
+
+       intel_dsb_ins_align(dsb);
+
+       tail = dsb->free_pos * 4;
+       aligned_tail = ALIGN(tail, CACHELINE_BYTES);
+
+       /*
+        * "The GOSUB instruction cannot be placed in
+        *  cacheline QW slot 6 or 7 (numbered 0-7)"
+        */
+       if (aligned_tail - tail <= 2 * 8)
+               intel_dsb_buffer_memset(&dsb->dsb_buf, dsb->free_pos, 0,
+                                       aligned_tail - tail);
+
+       dsb->free_pos = aligned_tail / 4;
+}
+
+void intel_dsb_gosub(struct intel_dsb *dsb,
+                    struct intel_dsb *sub_dsb)
+{
+       struct intel_crtc *crtc = dsb->crtc;
+       struct intel_display *display = to_intel_display(crtc->base.dev);
+       unsigned int head, tail;
+       u64 head_tail;
+
+       if (drm_WARN_ON(display->drm, dsb->id != sub_dsb->id))
+               return;
+
+       if (!assert_dsb_tail_is_aligned(sub_dsb))
+               return;
+
+       intel_dsb_gosub_align(dsb);
+
+       head = intel_dsb_head(sub_dsb);
+       tail = intel_dsb_tail(sub_dsb);
+
+       /*
+        * The GOSUB instruction has the following memory layout.
+        *
+        * +------------------------------------------------------------+
+        * |  Opcode  |   Rsvd    |      Head Ptr     |     Tail Ptr    |
+        * |   0x0c   |           |                   |                 |
+        * +------------------------------------------------------------+
+        * |<- 8bits->|<- 4bits ->|<--   26bits    -->|<--  26bits   -->|
+        *
+        * We have only 26 bits each to represent the head and  tail
+        * pointers even though the addresses itself are of 32 bit. However, this
+        * is not a problem because the addresses are 64 bit aligned and therefore
+        * the last 6 bits are always Zero's. Therefore, we right shift the address
+        * by 6 before embedding it into the GOSUB instruction.
+        */
+
+       head_tail = ((u64)(DSB_GOSUB_CONVERT_ADDR(head)) << DSB_GOSUB_HEAD_SHIFT) |
+               ((u64)(DSB_GOSUB_CONVERT_ADDR(tail)) << DSB_GOSUB_TAIL_SHIFT);
+
+       intel_dsb_emit(dsb, lower_32_bits(head_tail),
+                      (DSB_OPCODE_GOSUB << DSB_OPCODE_SHIFT) |
+                      upper_32_bits(head_tail));
+
+       /*
+        * "NOTE: the instructions within the cacheline
+        *  FOLLOWING the GOSUB instruction must be NOPs."
+        */
+       intel_dsb_align_tail(dsb);
+}
+
 void intel_dsb_finish(struct intel_dsb *dsb)
 {
        struct intel_crtc *crtc = dsb->crtc;
index e843c52bf97c2b369d98bad8f5b4e1f093170ec4..8b2cf0a7b7e68068436d00300c80e74eb7e5cee3 100644 (file)
@@ -57,6 +57,8 @@ void intel_dsb_vblank_evade(struct intel_atomic_state *state,
 void intel_dsb_poll(struct intel_dsb *dsb,
                    i915_reg_t reg, u32 mask, u32 val,
                    int wait_us, int count);
+void intel_dsb_gosub(struct intel_dsb *dsb,
+                    struct intel_dsb *sub_dsb);
 void intel_dsb_chain(struct intel_atomic_state *state,
                     struct intel_dsb *dsb,
                     struct intel_dsb *chained_dsb,