Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2019 Intel Corporation
0004  *
0005  */
0006 
0007 #include "gem/i915_gem_internal.h"
0008 
0009 #include "i915_drv.h"
0010 #include "intel_de.h"
0011 #include "intel_display_types.h"
0012 
0013 #define DSB_BUF_SIZE    (2 * PAGE_SIZE)
0014 
0015 /**
0016  * DOC: DSB
0017  *
0018  * A DSB (Display State Buffer) is a queue of MMIO instructions in the memory
0019  * which can be offloaded to DSB HW in Display Controller. DSB HW is a DMA
0020  * engine that can be programmed to download the DSB from memory.
0021  * It allows driver to batch submit display HW programming. This helps to
0022  * reduce loading time and CPU activity, thereby making the context switch
0023  * faster. DSB Support added from Gen12 Intel graphics based platform.
0024  *
0025  * DSB's can access only the pipe, plane, and transcoder Data Island Packet
0026  * registers.
0027  *
0028  * DSB HW can support only register writes (both indexed and direct MMIO
0029  * writes). There are no registers reads possible with DSB HW engine.
0030  */
0031 
0032 /* DSB opcodes. */
0033 #define DSB_OPCODE_SHIFT        24
0034 #define DSB_OPCODE_MMIO_WRITE       0x1
0035 #define DSB_OPCODE_INDEXED_WRITE    0x9
0036 #define DSB_BYTE_EN         0xF
0037 #define DSB_BYTE_EN_SHIFT       20
0038 #define DSB_REG_VALUE_MASK      0xfffff
0039 
0040 static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe,
0041             enum dsb_id id)
0042 {
0043     return DSB_STATUS & intel_de_read(i915, DSB_CTRL(pipe, id));
0044 }
0045 
0046 static bool intel_dsb_enable_engine(struct drm_i915_private *i915,
0047                     enum pipe pipe, enum dsb_id id)
0048 {
0049     u32 dsb_ctrl;
0050 
0051     dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
0052     if (DSB_STATUS & dsb_ctrl) {
0053         drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
0054         return false;
0055     }
0056 
0057     dsb_ctrl |= DSB_ENABLE;
0058     intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
0059 
0060     intel_de_posting_read(i915, DSB_CTRL(pipe, id));
0061     return true;
0062 }
0063 
0064 static bool intel_dsb_disable_engine(struct drm_i915_private *i915,
0065                      enum pipe pipe, enum dsb_id id)
0066 {
0067     u32 dsb_ctrl;
0068 
0069     dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
0070     if (DSB_STATUS & dsb_ctrl) {
0071         drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
0072         return false;
0073     }
0074 
0075     dsb_ctrl &= ~DSB_ENABLE;
0076     intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
0077 
0078     intel_de_posting_read(i915, DSB_CTRL(pipe, id));
0079     return true;
0080 }
0081 
0082 /**
0083  * intel_dsb_indexed_reg_write() -Write to the DSB context for auto
0084  * increment register.
0085  * @crtc_state: intel_crtc_state structure
0086  * @reg: register address.
0087  * @val: value.
0088  *
0089  * This function is used for writing register-value pair in command
0090  * buffer of DSB for auto-increment register. During command buffer overflow,
0091  * a warning is thrown and rest all erroneous condition register programming
0092  * is done through mmio write.
0093  */
0094 
0095 void intel_dsb_indexed_reg_write(const struct intel_crtc_state *crtc_state,
0096                  i915_reg_t reg, u32 val)
0097 {
0098     struct intel_dsb *dsb = crtc_state->dsb;
0099     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0100     struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0101     u32 *buf;
0102     u32 reg_val;
0103 
0104     if (!dsb) {
0105         intel_de_write_fw(dev_priv, reg, val);
0106         return;
0107     }
0108     buf = dsb->cmd_buf;
0109     if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
0110         drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
0111         return;
0112     }
0113 
0114     /*
0115      * For example the buffer will look like below for 3 dwords for auto
0116      * increment register:
0117      * +--------------------------------------------------------+
0118      * | size = 3 | offset &| value1 | value2 | value3 | zero   |
0119      * |          | opcode  |        |        |        |        |
0120      * +--------------------------------------------------------+
0121      * +          +         +        +        +        +        +
0122      * 0          4         8        12       16       20       24
0123      * Byte
0124      *
0125      * As every instruction is 8 byte aligned the index of dsb instruction
0126      * will start always from even number while dealing with u32 array. If
0127      * we are writing odd no of dwords, Zeros will be added in the end for
0128      * padding.
0129      */
0130     reg_val = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
0131     if (reg_val != i915_mmio_reg_offset(reg)) {
0132         /* Every instruction should be 8 byte aligned. */
0133         dsb->free_pos = ALIGN(dsb->free_pos, 2);
0134 
0135         dsb->ins_start_offset = dsb->free_pos;
0136 
0137         /* Update the size. */
0138         buf[dsb->free_pos++] = 1;
0139 
0140         /* Update the opcode and reg. */
0141         buf[dsb->free_pos++] = (DSB_OPCODE_INDEXED_WRITE  <<
0142                     DSB_OPCODE_SHIFT) |
0143                     i915_mmio_reg_offset(reg);
0144 
0145         /* Update the value. */
0146         buf[dsb->free_pos++] = val;
0147     } else {
0148         /* Update the new value. */
0149         buf[dsb->free_pos++] = val;
0150 
0151         /* Update the size. */
0152         buf[dsb->ins_start_offset]++;
0153     }
0154 
0155     /* if number of data words is odd, then the last dword should be 0.*/
0156     if (dsb->free_pos & 0x1)
0157         buf[dsb->free_pos] = 0;
0158 }
0159 
0160 /**
0161  * intel_dsb_reg_write() -Write to the DSB context for normal
0162  * register.
0163  * @crtc_state: intel_crtc_state structure
0164  * @reg: register address.
0165  * @val: value.
0166  *
0167  * This function is used for writing register-value pair in command
0168  * buffer of DSB. During command buffer overflow, a warning  is thrown
0169  * and rest all erroneous condition register programming is done
0170  * through mmio write.
0171  */
0172 void intel_dsb_reg_write(const struct intel_crtc_state *crtc_state,
0173              i915_reg_t reg, u32 val)
0174 {
0175     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0176     struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0177     struct intel_dsb *dsb;
0178     u32 *buf;
0179 
0180     dsb = crtc_state->dsb;
0181     if (!dsb) {
0182         intel_de_write_fw(dev_priv, reg, val);
0183         return;
0184     }
0185 
0186     buf = dsb->cmd_buf;
0187     if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
0188         drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
0189         return;
0190     }
0191 
0192     dsb->ins_start_offset = dsb->free_pos;
0193     buf[dsb->free_pos++] = val;
0194     buf[dsb->free_pos++] = (DSB_OPCODE_MMIO_WRITE  << DSB_OPCODE_SHIFT) |
0195                    (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
0196                    i915_mmio_reg_offset(reg);
0197 }
0198 
0199 /**
0200  * intel_dsb_commit() - Trigger workload execution of DSB.
0201  * @crtc_state: intel_crtc_state structure
0202  *
0203  * This function is used to do actual write to hardware using DSB.
0204  * On errors, fall back to MMIO. Also this function help to reset the context.
0205  */
0206 void intel_dsb_commit(const struct intel_crtc_state *crtc_state)
0207 {
0208     struct intel_dsb *dsb = crtc_state->dsb;
0209     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0210     struct drm_device *dev = crtc->base.dev;
0211     struct drm_i915_private *dev_priv = to_i915(dev);
0212     enum pipe pipe = crtc->pipe;
0213     u32 tail;
0214 
0215     if (!(dsb && dsb->free_pos))
0216         return;
0217 
0218     if (!intel_dsb_enable_engine(dev_priv, pipe, dsb->id))
0219         goto reset;
0220 
0221     if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
0222         drm_err(&dev_priv->drm,
0223             "HEAD_PTR write failed - dsb engine is busy.\n");
0224         goto reset;
0225     }
0226     intel_de_write(dev_priv, DSB_HEAD(pipe, dsb->id),
0227                i915_ggtt_offset(dsb->vma));
0228 
0229     tail = ALIGN(dsb->free_pos * 4, CACHELINE_BYTES);
0230     if (tail > dsb->free_pos * 4)
0231         memset(&dsb->cmd_buf[dsb->free_pos], 0,
0232                (tail - dsb->free_pos * 4));
0233 
0234     if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
0235         drm_err(&dev_priv->drm,
0236             "TAIL_PTR write failed - dsb engine is busy.\n");
0237         goto reset;
0238     }
0239     drm_dbg_kms(&dev_priv->drm,
0240             "DSB execution started - head 0x%x, tail 0x%x\n",
0241             i915_ggtt_offset(dsb->vma), tail);
0242     intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id),
0243                i915_ggtt_offset(dsb->vma) + tail);
0244     if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) {
0245         drm_err(&dev_priv->drm,
0246             "Timed out waiting for DSB workload completion.\n");
0247         goto reset;
0248     }
0249 
0250 reset:
0251     dsb->free_pos = 0;
0252     dsb->ins_start_offset = 0;
0253     intel_dsb_disable_engine(dev_priv, pipe, dsb->id);
0254 }
0255 
0256 /**
0257  * intel_dsb_prepare() - Allocate, pin and map the DSB command buffer.
0258  * @crtc_state: intel_crtc_state structure to prepare associated dsb instance.
0259  *
0260  * This function prepare the command buffer which is used to store dsb
0261  * instructions with data.
0262  */
0263 void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
0264 {
0265     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0266     struct drm_i915_private *i915 = to_i915(crtc->base.dev);
0267     struct intel_dsb *dsb;
0268     struct drm_i915_gem_object *obj;
0269     struct i915_vma *vma;
0270     u32 *buf;
0271     intel_wakeref_t wakeref;
0272 
0273     if (!HAS_DSB(i915))
0274         return;
0275 
0276     dsb = kmalloc(sizeof(*dsb), GFP_KERNEL);
0277     if (!dsb) {
0278         drm_err(&i915->drm, "DSB object creation failed\n");
0279         return;
0280     }
0281 
0282     wakeref = intel_runtime_pm_get(&i915->runtime_pm);
0283 
0284     obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE);
0285     if (IS_ERR(obj)) {
0286         kfree(dsb);
0287         goto out;
0288     }
0289 
0290     vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
0291     if (IS_ERR(vma)) {
0292         i915_gem_object_put(obj);
0293         kfree(dsb);
0294         goto out;
0295     }
0296 
0297     buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC);
0298     if (IS_ERR(buf)) {
0299         i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
0300         kfree(dsb);
0301         goto out;
0302     }
0303 
0304     dsb->id = DSB1;
0305     dsb->vma = vma;
0306     dsb->cmd_buf = buf;
0307     dsb->free_pos = 0;
0308     dsb->ins_start_offset = 0;
0309     crtc_state->dsb = dsb;
0310 out:
0311     if (!crtc_state->dsb)
0312         drm_info(&i915->drm,
0313              "DSB queue setup failed, will fallback to MMIO for display HW programming\n");
0314 
0315     intel_runtime_pm_put(&i915->runtime_pm, wakeref);
0316 }
0317 
0318 /**
0319  * intel_dsb_cleanup() - To cleanup DSB context.
0320  * @crtc_state: intel_crtc_state structure to cleanup associated dsb instance.
0321  *
0322  * This function cleanup the DSB context by unpinning and releasing
0323  * the VMA object associated with it.
0324  */
0325 void intel_dsb_cleanup(struct intel_crtc_state *crtc_state)
0326 {
0327     if (!crtc_state->dsb)
0328         return;
0329 
0330     i915_vma_unpin_and_release(&crtc_state->dsb->vma, I915_VMA_RELEASE_MAP);
0331     kfree(crtc_state->dsb);
0332     crtc_state->dsb = NULL;
0333 }