]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/i915/dsb: Indexed register write function for DSB.
authorAnimesh Manna <animesh.manna@intel.com>
Fri, 20 Sep 2019 11:59:24 +0000 (17:29 +0530)
committerJani Nikula <jani.nikula@intel.com>
Mon, 23 Sep 2019 07:09:46 +0000 (10:09 +0300)
DSB can program large set of data through indexed register write
(opcode 0x9) in one shot. DSB feature can be used for bulk register
programming e.g. gamma lut programming, HDR meta data programming.

v1: initial version.
v2: simplified code by using ALIGN(). (Chris)
v3: ascii table added as code comment. (Shashank)
v4: cosmetic changes done. (Shashank)
v5: reset ins_start_offset. (Jani)
v6: update ins_start_offset in inel_dsb_reg_write.

Cc: Shashank Sharma <shashank.sharma@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: Jani Nikula <jani.nikula@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Shashank Sharma <shashank.sharma@intel.com>
Signed-off-by: Animesh Manna <animesh.manna@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190920115930.27829-5-animesh.manna@intel.com
drivers/gpu/drm/i915/display/intel_dsb.c
drivers/gpu/drm/i915/display/intel_dsb.h

index f94cd6dc98b6d58910a5c4b1ee453fd1d05da8e6..faa853b084586e0864a6a8e242a93f778d122f6a 100644 (file)
 /* DSB opcodes. */
 #define DSB_OPCODE_SHIFT               24
 #define DSB_OPCODE_MMIO_WRITE          0x1
+#define DSB_OPCODE_INDEXED_WRITE       0x9
 #define DSB_BYTE_EN                    0xF
 #define DSB_BYTE_EN_SHIFT              20
+#define DSB_REG_VALUE_MASK             0xfffff
 
 struct intel_dsb *
 intel_dsb_get(struct intel_crtc *crtc)
@@ -83,9 +85,74 @@ void intel_dsb_put(struct intel_dsb *dsb)
                mutex_unlock(&i915->drm.struct_mutex);
                dsb->cmd_buf = NULL;
                dsb->free_pos = 0;
+               dsb->ins_start_offset = 0;
        }
 }
 
+void intel_dsb_indexed_reg_write(struct intel_dsb *dsb, i915_reg_t reg,
+                                u32 val)
+{
+       struct intel_crtc *crtc = container_of(dsb, typeof(*crtc), dsb);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       u32 *buf = dsb->cmd_buf;
+       u32 reg_val;
+
+       if (!buf) {
+               I915_WRITE(reg, val);
+               return;
+       }
+
+       if (WARN_ON(dsb->free_pos >= DSB_BUF_SIZE)) {
+               DRM_DEBUG_KMS("DSB buffer overflow\n");
+               return;
+       }
+
+       /*
+        * For example the buffer will look like below for 3 dwords for auto
+        * increment register:
+        * +--------------------------------------------------------+
+        * | size = 3 | offset &| value1 | value2 | value3 | zero   |
+        * |          | opcode  |        |        |        |        |
+        * +--------------------------------------------------------+
+        * +          +         +        +        +        +        +
+        * 0          4         8        12       16       20       24
+        * Byte
+        *
+        * As every instruction is 8 byte aligned the index of dsb instruction
+        * will start always from even number while dealing with u32 array. If
+        * we are writing odd no of dwords, Zeros will be added in the end for
+        * padding.
+        */
+       reg_val = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
+       if (reg_val != i915_mmio_reg_offset(reg)) {
+               /* Every instruction should be 8 byte aligned. */
+               dsb->free_pos = ALIGN(dsb->free_pos, 2);
+
+               dsb->ins_start_offset = dsb->free_pos;
+
+               /* Update the size. */
+               buf[dsb->free_pos++] = 1;
+
+               /* Update the opcode and reg. */
+               buf[dsb->free_pos++] = (DSB_OPCODE_INDEXED_WRITE  <<
+                                       DSB_OPCODE_SHIFT) |
+                                       i915_mmio_reg_offset(reg);
+
+               /* Update the value. */
+               buf[dsb->free_pos++] = val;
+       } else {
+               /* Update the new value. */
+               buf[dsb->free_pos++] = val;
+
+               /* Update the size. */
+               buf[dsb->ins_start_offset]++;
+       }
+
+       /* if number of data words is odd, then the last dword should be 0.*/
+       if (dsb->free_pos & 0x1)
+               buf[dsb->free_pos] = 0;
+}
+
 void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val)
 {
        struct intel_crtc *crtc = container_of(dsb, typeof(*crtc), dsb);
@@ -102,6 +169,7 @@ void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val)
                return;
        }
 
+       dsb->ins_start_offset = dsb->free_pos;
        buf[dsb->free_pos++] = val;
        buf[dsb->free_pos++] = (DSB_OPCODE_MMIO_WRITE  << DSB_OPCODE_SHIFT) |
                               (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
index 839cbf621fa271dad656b9584f771ff99c28fcda..e4dd0ab799ec6120901eec552aa31edcb4ef3e0c 100644 (file)
@@ -32,11 +32,20 @@ struct intel_dsb {
         * and help in calculating tail of command buffer.
         */
        int free_pos;
+
+       /*
+        * ins_start_offset will help to store start address of the dsb
+        * instuction and help in identifying the batch of auto-increment
+        * register.
+        */
+       u32 ins_start_offset;
 };
 
 struct intel_dsb *
 intel_dsb_get(struct intel_crtc *crtc);
 void intel_dsb_put(struct intel_dsb *dsb);
 void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val);
+void intel_dsb_indexed_reg_write(struct intel_dsb *dsb, i915_reg_t reg,
+                                u32 val);
 
 #endif