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