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