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