• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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