xref: /linux/drivers/gpu/drm/i915/display/intel_wm.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023 Intel Corporation
4  */
5 
6 #include <linux/debugfs.h>
7 
8 #include <drm/drm_file.h>
9 #include <drm/drm_print.h>
10 
11 #include "i9xx_wm.h"
12 #include "intel_display_core.h"
13 #include "intel_display_types.h"
14 #include "intel_wm.h"
15 #include "skl_watermark.h"
16 
17 /**
18  * intel_update_watermarks - update FIFO watermark values based on current modes
19  * @display: display device
20  *
21  * Calculate watermark values for the various WM regs based on current mode
22  * and plane configuration.
23  *
24  * There are several cases to deal with here:
25  *   - normal (i.e. non-self-refresh)
26  *   - self-refresh (SR) mode
27  *   - lines are large relative to FIFO size (buffer can hold up to 2)
28  *   - lines are small relative to FIFO size (buffer can hold more than 2
29  *     lines), so need to account for TLB latency
30  *
31  *   The normal calculation is:
32  *     watermark = dotclock * bytes per pixel * latency
33  *   where latency is platform & configuration dependent (we assume pessimal
34  *   values here).
35  *
36  *   The SR calculation is:
37  *     watermark = (trunc(latency/line time)+1) * surface width *
38  *       bytes per pixel
39  *   where
40  *     line time = htotal / dotclock
41  *     surface width = hdisplay for normal plane and 64 for cursor
42  *   and latency is assumed to be high, as above.
43  *
44  * The final value programmed to the register should always be rounded up,
45  * and include an extra 2 entries to account for clock crossings.
46  *
47  * We don't use the sprite, so we can ignore that.  And on Crestline we have
48  * to set the non-SR watermarks to 8.
49  */
intel_update_watermarks(struct intel_display * display)50 void intel_update_watermarks(struct intel_display *display)
51 {
52 	if (display->funcs.wm->update_wm)
53 		display->funcs.wm->update_wm(display);
54 }
55 
intel_wm_compute(struct intel_atomic_state * state,struct intel_crtc * crtc)56 int intel_wm_compute(struct intel_atomic_state *state,
57 		     struct intel_crtc *crtc)
58 {
59 	struct intel_display *display = to_intel_display(state);
60 
61 	if (!display->funcs.wm->compute_watermarks)
62 		return 0;
63 
64 	return display->funcs.wm->compute_watermarks(state, crtc);
65 }
66 
intel_initial_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)67 bool intel_initial_watermarks(struct intel_atomic_state *state,
68 			      struct intel_crtc *crtc)
69 {
70 	struct intel_display *display = to_intel_display(state);
71 
72 	if (display->funcs.wm->initial_watermarks) {
73 		display->funcs.wm->initial_watermarks(state, crtc);
74 		return true;
75 	}
76 
77 	return false;
78 }
79 
intel_atomic_update_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)80 void intel_atomic_update_watermarks(struct intel_atomic_state *state,
81 				    struct intel_crtc *crtc)
82 {
83 	struct intel_display *display = to_intel_display(state);
84 
85 	if (display->funcs.wm->atomic_update_watermarks)
86 		display->funcs.wm->atomic_update_watermarks(state, crtc);
87 }
88 
intel_optimize_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)89 void intel_optimize_watermarks(struct intel_atomic_state *state,
90 			       struct intel_crtc *crtc)
91 {
92 	struct intel_display *display = to_intel_display(state);
93 
94 	if (display->funcs.wm->optimize_watermarks)
95 		display->funcs.wm->optimize_watermarks(state, crtc);
96 }
97 
intel_compute_global_watermarks(struct intel_atomic_state * state)98 int intel_compute_global_watermarks(struct intel_atomic_state *state)
99 {
100 	struct intel_display *display = to_intel_display(state);
101 
102 	if (display->funcs.wm->compute_global_watermarks)
103 		return display->funcs.wm->compute_global_watermarks(state);
104 
105 	return 0;
106 }
107 
intel_wm_get_hw_state(struct intel_display * display)108 void intel_wm_get_hw_state(struct intel_display *display)
109 {
110 	if (display->funcs.wm->get_hw_state)
111 		return display->funcs.wm->get_hw_state(display);
112 }
113 
intel_wm_sanitize(struct intel_display * display)114 void intel_wm_sanitize(struct intel_display *display)
115 {
116 	if (display->funcs.wm->sanitize)
117 		return display->funcs.wm->sanitize(display);
118 }
119 
intel_wm_plane_visible(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)120 bool intel_wm_plane_visible(const struct intel_crtc_state *crtc_state,
121 			    const struct intel_plane_state *plane_state)
122 {
123 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
124 
125 	/* FIXME check the 'enable' instead */
126 	if (!crtc_state->hw.active)
127 		return false;
128 
129 	/*
130 	 * Treat cursor with fb as always visible since cursor updates
131 	 * can happen faster than the vrefresh rate, and the current
132 	 * watermark code doesn't handle that correctly. Cursor updates
133 	 * which set/clear the fb or change the cursor size are going
134 	 * to get throttled by intel_legacy_cursor_update() to work
135 	 * around this problem with the watermark code.
136 	 */
137 	if (plane->id == PLANE_CURSOR)
138 		return plane_state->hw.fb != NULL;
139 	else
140 		return plane_state->uapi.visible;
141 }
142 
intel_print_wm_latency(struct intel_display * display,const char * name,const u16 wm[])143 void intel_print_wm_latency(struct intel_display *display,
144 			    const char *name, const u16 wm[])
145 {
146 	int level;
147 
148 	for (level = 0; level < display->wm.num_levels; level++) {
149 		unsigned int latency = wm[level];
150 
151 		if (latency == 0) {
152 			drm_dbg_kms(display->drm,
153 				    "%s WM%d latency not provided\n",
154 				    name, level);
155 			continue;
156 		}
157 
158 		/*
159 		 * - latencies are in us on gen9.
160 		 * - before then, WM1+ latency values are in 0.5us units
161 		 */
162 		if (DISPLAY_VER(display) >= 9)
163 			latency *= 10;
164 		else if (level > 0)
165 			latency *= 5;
166 
167 		drm_dbg_kms(display->drm,
168 			    "%s WM%d latency %u (%u.%u usec)\n", name, level,
169 			    wm[level], latency / 10, latency % 10);
170 	}
171 }
172 
intel_wm_init(struct intel_display * display)173 void intel_wm_init(struct intel_display *display)
174 {
175 	if (DISPLAY_VER(display) >= 9)
176 		skl_wm_init(display);
177 	else
178 		i9xx_wm_init(display);
179 }
180 
wm_latency_show(struct seq_file * m,const u16 wm[8])181 static void wm_latency_show(struct seq_file *m, const u16 wm[8])
182 {
183 	struct intel_display *display = m->private;
184 	int level;
185 
186 	drm_modeset_lock_all(display->drm);
187 
188 	for (level = 0; level < display->wm.num_levels; level++) {
189 		unsigned int latency = wm[level];
190 
191 		/*
192 		 * - WM1+ latency values in 0.5us units
193 		 * - latencies are in us on gen9/vlv/chv
194 		 */
195 		if (DISPLAY_VER(display) >= 9 ||
196 		    display->platform.valleyview ||
197 		    display->platform.cherryview ||
198 		    display->platform.g4x)
199 			latency *= 10;
200 		else if (level > 0)
201 			latency *= 5;
202 
203 		seq_printf(m, "WM%d %u (%u.%u usec)\n",
204 			   level, wm[level], latency / 10, latency % 10);
205 	}
206 
207 	drm_modeset_unlock_all(display->drm);
208 }
209 
pri_wm_latency_show(struct seq_file * m,void * data)210 static int pri_wm_latency_show(struct seq_file *m, void *data)
211 {
212 	struct intel_display *display = m->private;
213 	const u16 *latencies;
214 
215 	if (DISPLAY_VER(display) >= 9)
216 		latencies = display->wm.skl_latency;
217 	else
218 		latencies = display->wm.pri_latency;
219 
220 	wm_latency_show(m, latencies);
221 
222 	return 0;
223 }
224 
spr_wm_latency_show(struct seq_file * m,void * data)225 static int spr_wm_latency_show(struct seq_file *m, void *data)
226 {
227 	struct intel_display *display = m->private;
228 	const u16 *latencies;
229 
230 	if (DISPLAY_VER(display) >= 9)
231 		latencies = display->wm.skl_latency;
232 	else
233 		latencies = display->wm.spr_latency;
234 
235 	wm_latency_show(m, latencies);
236 
237 	return 0;
238 }
239 
cur_wm_latency_show(struct seq_file * m,void * data)240 static int cur_wm_latency_show(struct seq_file *m, void *data)
241 {
242 	struct intel_display *display = m->private;
243 	const u16 *latencies;
244 
245 	if (DISPLAY_VER(display) >= 9)
246 		latencies = display->wm.skl_latency;
247 	else
248 		latencies = display->wm.cur_latency;
249 
250 	wm_latency_show(m, latencies);
251 
252 	return 0;
253 }
254 
pri_wm_latency_open(struct inode * inode,struct file * file)255 static int pri_wm_latency_open(struct inode *inode, struct file *file)
256 {
257 	struct intel_display *display = inode->i_private;
258 
259 	if (DISPLAY_VER(display) < 5 && !display->platform.g4x)
260 		return -ENODEV;
261 
262 	return single_open(file, pri_wm_latency_show, display);
263 }
264 
spr_wm_latency_open(struct inode * inode,struct file * file)265 static int spr_wm_latency_open(struct inode *inode, struct file *file)
266 {
267 	struct intel_display *display = inode->i_private;
268 
269 	if (HAS_GMCH(display))
270 		return -ENODEV;
271 
272 	return single_open(file, spr_wm_latency_show, display);
273 }
274 
cur_wm_latency_open(struct inode * inode,struct file * file)275 static int cur_wm_latency_open(struct inode *inode, struct file *file)
276 {
277 	struct intel_display *display = inode->i_private;
278 
279 	if (HAS_GMCH(display))
280 		return -ENODEV;
281 
282 	return single_open(file, cur_wm_latency_show, display);
283 }
284 
wm_latency_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp,u16 wm[8])285 static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
286 				size_t len, loff_t *offp, u16 wm[8])
287 {
288 	struct seq_file *m = file->private_data;
289 	struct intel_display *display = m->private;
290 	u16 new[8] = {};
291 	int level;
292 	int ret;
293 	char tmp[32];
294 
295 	if (len >= sizeof(tmp))
296 		return -EINVAL;
297 
298 	if (copy_from_user(tmp, ubuf, len))
299 		return -EFAULT;
300 
301 	tmp[len] = '\0';
302 
303 	ret = sscanf(tmp, "%hu %hu %hu %hu %hu %hu %hu %hu",
304 		     &new[0], &new[1], &new[2], &new[3],
305 		     &new[4], &new[5], &new[6], &new[7]);
306 	if (ret != display->wm.num_levels)
307 		return -EINVAL;
308 
309 	drm_modeset_lock_all(display->drm);
310 
311 	for (level = 0; level < display->wm.num_levels; level++)
312 		wm[level] = new[level];
313 
314 	drm_modeset_unlock_all(display->drm);
315 
316 	return len;
317 }
318 
pri_wm_latency_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)319 static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf,
320 				    size_t len, loff_t *offp)
321 {
322 	struct seq_file *m = file->private_data;
323 	struct intel_display *display = m->private;
324 	u16 *latencies;
325 
326 	if (DISPLAY_VER(display) >= 9)
327 		latencies = display->wm.skl_latency;
328 	else
329 		latencies = display->wm.pri_latency;
330 
331 	return wm_latency_write(file, ubuf, len, offp, latencies);
332 }
333 
spr_wm_latency_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)334 static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf,
335 				    size_t len, loff_t *offp)
336 {
337 	struct seq_file *m = file->private_data;
338 	struct intel_display *display = m->private;
339 	u16 *latencies;
340 
341 	if (DISPLAY_VER(display) >= 9)
342 		latencies = display->wm.skl_latency;
343 	else
344 		latencies = display->wm.spr_latency;
345 
346 	return wm_latency_write(file, ubuf, len, offp, latencies);
347 }
348 
cur_wm_latency_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)349 static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf,
350 				    size_t len, loff_t *offp)
351 {
352 	struct seq_file *m = file->private_data;
353 	struct intel_display *display = m->private;
354 	u16 *latencies;
355 
356 	if (DISPLAY_VER(display) >= 9)
357 		latencies = display->wm.skl_latency;
358 	else
359 		latencies = display->wm.cur_latency;
360 
361 	return wm_latency_write(file, ubuf, len, offp, latencies);
362 }
363 
364 static const struct file_operations i915_pri_wm_latency_fops = {
365 	.owner = THIS_MODULE,
366 	.open = pri_wm_latency_open,
367 	.read = seq_read,
368 	.llseek = seq_lseek,
369 	.release = single_release,
370 	.write = pri_wm_latency_write
371 };
372 
373 static const struct file_operations i915_spr_wm_latency_fops = {
374 	.owner = THIS_MODULE,
375 	.open = spr_wm_latency_open,
376 	.read = seq_read,
377 	.llseek = seq_lseek,
378 	.release = single_release,
379 	.write = spr_wm_latency_write
380 };
381 
382 static const struct file_operations i915_cur_wm_latency_fops = {
383 	.owner = THIS_MODULE,
384 	.open = cur_wm_latency_open,
385 	.read = seq_read,
386 	.llseek = seq_lseek,
387 	.release = single_release,
388 	.write = cur_wm_latency_write
389 };
390 
intel_wm_debugfs_register(struct intel_display * display)391 void intel_wm_debugfs_register(struct intel_display *display)
392 {
393 	struct drm_minor *minor = display->drm->primary;
394 
395 	debugfs_create_file("i915_pri_wm_latency", 0644, minor->debugfs_root,
396 			    display, &i915_pri_wm_latency_fops);
397 
398 	debugfs_create_file("i915_spr_wm_latency", 0644, minor->debugfs_root,
399 			    display, &i915_spr_wm_latency_fops);
400 
401 	debugfs_create_file("i915_cur_wm_latency", 0644, minor->debugfs_root,
402 			    display, &i915_cur_wm_latency_fops);
403 
404 	skl_watermark_debugfs_register(display);
405 }
406