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