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