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