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