linux/drivers/gpu/drm/i915/display/intel_dsb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * Copyright © 2019 Intel Corporation
   4 *
   5 */
   6
   7#include "i915_drv.h"
   8#include "intel_de.h"
   9#include "intel_display_types.h"
  10
  11#define DSB_BUF_SIZE    (2 * PAGE_SIZE)
  12
  13/**
  14 * DOC: DSB
  15 *
  16 * A DSB (Display State Buffer) is a queue of MMIO instructions in the memory
  17 * which can be offloaded to DSB HW in Display Controller. DSB HW is a DMA
  18 * engine that can be programmed to download the DSB from memory.
  19 * It allows driver to batch submit display HW programming. This helps to
  20 * reduce loading time and CPU activity, thereby making the context switch
  21 * faster. DSB Support added from Gen12 Intel graphics based platform.
  22 *
  23 * DSB's can access only the pipe, plane, and transcoder Data Island Packet
  24 * registers.
  25 *
  26 * DSB HW can support only register writes (both indexed and direct MMIO
  27 * writes). There are no registers reads possible with DSB HW engine.
  28 */
  29
  30/* DSB opcodes. */
  31#define DSB_OPCODE_SHIFT                24
  32#define DSB_OPCODE_MMIO_WRITE           0x1
  33#define DSB_OPCODE_INDEXED_WRITE        0x9
  34#define DSB_BYTE_EN                     0xF
  35#define DSB_BYTE_EN_SHIFT               20
  36#define DSB_REG_VALUE_MASK              0xfffff
  37
  38static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe,
  39                        enum dsb_id id)
  40{
  41        return DSB_STATUS & intel_de_read(i915, DSB_CTRL(pipe, id));
  42}
  43
  44static bool intel_dsb_enable_engine(struct drm_i915_private *i915,
  45                                    enum pipe pipe, enum dsb_id id)
  46{
  47        u32 dsb_ctrl;
  48
  49        dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
  50        if (DSB_STATUS & dsb_ctrl) {
  51                drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
  52                return false;
  53        }
  54
  55        dsb_ctrl |= DSB_ENABLE;
  56        intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
  57
  58        intel_de_posting_read(i915, DSB_CTRL(pipe, id));
  59        return true;
  60}
  61
  62static bool intel_dsb_disable_engine(struct drm_i915_private *i915,
  63                                     enum pipe pipe, enum dsb_id id)
  64{
  65        u32 dsb_ctrl;
  66
  67        dsb_ctrl = intel_de_read(i915, DSB_CTRL(pipe, id));
  68        if (DSB_STATUS & dsb_ctrl) {
  69                drm_dbg_kms(&i915->drm, "DSB engine is busy.\n");
  70                return false;
  71        }
  72
  73        dsb_ctrl &= ~DSB_ENABLE;
  74        intel_de_write(i915, DSB_CTRL(pipe, id), dsb_ctrl);
  75
  76        intel_de_posting_read(i915, DSB_CTRL(pipe, id));
  77        return true;
  78}
  79
  80/**
  81 * intel_dsb_indexed_reg_write() -Write to the DSB context for auto
  82 * increment register.
  83 * @crtc_state: intel_crtc_state structure
  84 * @reg: register address.
  85 * @val: value.
  86 *
  87 * This function is used for writing register-value pair in command
  88 * buffer of DSB for auto-increment register. During command buffer overflow,
  89 * a warning is thrown and rest all erroneous condition register programming
  90 * is done through mmio write.
  91 */
  92
  93void intel_dsb_indexed_reg_write(const struct intel_crtc_state *crtc_state,
  94                                 i915_reg_t reg, u32 val)
  95{
  96        struct intel_dsb *dsb = crtc_state->dsb;
  97        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
  98        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
  99        u32 *buf;
 100        u32 reg_val;
 101
 102        if (!dsb) {
 103                intel_de_write(dev_priv, reg, val);
 104                return;
 105        }
 106        buf = dsb->cmd_buf;
 107        if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
 108                drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
 109                return;
 110        }
 111
 112        /*
 113         * For example the buffer will look like below for 3 dwords for auto
 114         * increment register:
 115         * +--------------------------------------------------------+
 116         * | size = 3 | offset &| value1 | value2 | value3 | zero   |
 117         * |          | opcode  |        |        |        |        |
 118         * +--------------------------------------------------------+
 119         * +          +         +        +        +        +        +
 120         * 0          4         8        12       16       20       24
 121         * Byte
 122         *
 123         * As every instruction is 8 byte aligned the index of dsb instruction
 124         * will start always from even number while dealing with u32 array. If
 125         * we are writing odd no of dwords, Zeros will be added in the end for
 126         * padding.
 127         */
 128        reg_val = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK;
 129        if (reg_val != i915_mmio_reg_offset(reg)) {
 130                /* Every instruction should be 8 byte aligned. */
 131                dsb->free_pos = ALIGN(dsb->free_pos, 2);
 132
 133                dsb->ins_start_offset = dsb->free_pos;
 134
 135                /* Update the size. */
 136                buf[dsb->free_pos++] = 1;
 137
 138                /* Update the opcode and reg. */
 139                buf[dsb->free_pos++] = (DSB_OPCODE_INDEXED_WRITE  <<
 140                                        DSB_OPCODE_SHIFT) |
 141                                        i915_mmio_reg_offset(reg);
 142
 143                /* Update the value. */
 144                buf[dsb->free_pos++] = val;
 145        } else {
 146                /* Update the new value. */
 147                buf[dsb->free_pos++] = val;
 148
 149                /* Update the size. */
 150                buf[dsb->ins_start_offset]++;
 151        }
 152
 153        /* if number of data words is odd, then the last dword should be 0.*/
 154        if (dsb->free_pos & 0x1)
 155                buf[dsb->free_pos] = 0;
 156}
 157
 158/**
 159 * intel_dsb_reg_write() -Write to the DSB context for normal
 160 * register.
 161 * @crtc_state: intel_crtc_state structure
 162 * @reg: register address.
 163 * @val: value.
 164 *
 165 * This function is used for writing register-value pair in command
 166 * buffer of DSB. During command buffer overflow, a warning  is thrown
 167 * and rest all erroneous condition register programming is done
 168 * through mmio write.
 169 */
 170void intel_dsb_reg_write(const struct intel_crtc_state *crtc_state,
 171                         i915_reg_t reg, u32 val)
 172{
 173        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 174        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 175        struct intel_dsb *dsb;
 176        u32 *buf;
 177
 178        dsb = crtc_state->dsb;
 179        if (!dsb) {
 180                intel_de_write(dev_priv, reg, val);
 181                return;
 182        }
 183
 184        buf = dsb->cmd_buf;
 185        if (drm_WARN_ON(&dev_priv->drm, dsb->free_pos >= DSB_BUF_SIZE)) {
 186                drm_dbg_kms(&dev_priv->drm, "DSB buffer overflow\n");
 187                return;
 188        }
 189
 190        dsb->ins_start_offset = dsb->free_pos;
 191        buf[dsb->free_pos++] = val;
 192        buf[dsb->free_pos++] = (DSB_OPCODE_MMIO_WRITE  << DSB_OPCODE_SHIFT) |
 193                               (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) |
 194                               i915_mmio_reg_offset(reg);
 195}
 196
 197/**
 198 * intel_dsb_commit() - Trigger workload execution of DSB.
 199 * @crtc_state: intel_crtc_state structure
 200 *
 201 * This function is used to do actual write to hardware using DSB.
 202 * On errors, fall back to MMIO. Also this function help to reset the context.
 203 */
 204void intel_dsb_commit(const struct intel_crtc_state *crtc_state)
 205{
 206        struct intel_dsb *dsb = crtc_state->dsb;
 207        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 208        struct drm_device *dev = crtc->base.dev;
 209        struct drm_i915_private *dev_priv = to_i915(dev);
 210        enum pipe pipe = crtc->pipe;
 211        u32 tail;
 212
 213        if (!(dsb && dsb->free_pos))
 214                return;
 215
 216        if (!intel_dsb_enable_engine(dev_priv, pipe, dsb->id))
 217                goto reset;
 218
 219        if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
 220                drm_err(&dev_priv->drm,
 221                        "HEAD_PTR write failed - dsb engine is busy.\n");
 222                goto reset;
 223        }
 224        intel_de_write(dev_priv, DSB_HEAD(pipe, dsb->id),
 225                       i915_ggtt_offset(dsb->vma));
 226
 227        tail = ALIGN(dsb->free_pos * 4, CACHELINE_BYTES);
 228        if (tail > dsb->free_pos * 4)
 229                memset(&dsb->cmd_buf[dsb->free_pos], 0,
 230                       (tail - dsb->free_pos * 4));
 231
 232        if (is_dsb_busy(dev_priv, pipe, dsb->id)) {
 233                drm_err(&dev_priv->drm,
 234                        "TAIL_PTR write failed - dsb engine is busy.\n");
 235                goto reset;
 236        }
 237        drm_dbg_kms(&dev_priv->drm,
 238                    "DSB execution started - head 0x%x, tail 0x%x\n",
 239                    i915_ggtt_offset(dsb->vma), tail);
 240        intel_de_write(dev_priv, DSB_TAIL(pipe, dsb->id),
 241                       i915_ggtt_offset(dsb->vma) + tail);
 242        if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) {
 243                drm_err(&dev_priv->drm,
 244                        "Timed out waiting for DSB workload completion.\n");
 245                goto reset;
 246        }
 247
 248reset:
 249        dsb->free_pos = 0;
 250        dsb->ins_start_offset = 0;
 251        intel_dsb_disable_engine(dev_priv, pipe, dsb->id);
 252}
 253
 254/**
 255 * intel_dsb_prepare() - Allocate, pin and map the DSB command buffer.
 256 * @crtc_state: intel_crtc_state structure to prepare associated dsb instance.
 257 *
 258 * This function prepare the command buffer which is used to store dsb
 259 * instructions with data.
 260 */
 261void intel_dsb_prepare(struct intel_crtc_state *crtc_state)
 262{
 263        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 264        struct drm_i915_private *i915 = to_i915(crtc->base.dev);
 265        struct intel_dsb *dsb;
 266        struct drm_i915_gem_object *obj;
 267        struct i915_vma *vma;
 268        u32 *buf;
 269        intel_wakeref_t wakeref;
 270
 271        if (!HAS_DSB(i915))
 272                return;
 273
 274        dsb = kmalloc(sizeof(*dsb), GFP_KERNEL);
 275        if (!dsb) {
 276                drm_err(&i915->drm, "DSB object creation failed\n");
 277                return;
 278        }
 279
 280        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 281
 282        obj = i915_gem_object_create_internal(i915, DSB_BUF_SIZE);
 283        if (IS_ERR(obj)) {
 284                drm_err(&i915->drm, "Gem object creation failed\n");
 285                kfree(dsb);
 286                goto out;
 287        }
 288
 289        vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
 290        if (IS_ERR(vma)) {
 291                drm_err(&i915->drm, "Vma creation failed\n");
 292                i915_gem_object_put(obj);
 293                kfree(dsb);
 294                goto out;
 295        }
 296
 297        buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC);
 298        if (IS_ERR(buf)) {
 299                drm_err(&i915->drm, "Command buffer creation failed\n");
 300                i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
 301                kfree(dsb);
 302                goto out;
 303        }
 304
 305        dsb->id = DSB1;
 306        dsb->vma = vma;
 307        dsb->cmd_buf = buf;
 308        dsb->free_pos = 0;
 309        dsb->ins_start_offset = 0;
 310        crtc_state->dsb = dsb;
 311out:
 312        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 313}
 314
 315/**
 316 * intel_dsb_cleanup() - To cleanup DSB context.
 317 * @crtc_state: intel_crtc_state structure to cleanup associated dsb instance.
 318 *
 319 * This function cleanup the DSB context by unpinning and releasing
 320 * the VMA object associated with it.
 321 */
 322void intel_dsb_cleanup(struct intel_crtc_state *crtc_state)
 323{
 324        if (!crtc_state->dsb)
 325                return;
 326
 327        i915_vma_unpin_and_release(&crtc_state->dsb->vma, I915_VMA_RELEASE_MAP);
 328        kfree(crtc_state->dsb);
 329        crtc_state->dsb = NULL;
 330}
 331