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