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