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