1 // SPDX-License-Identifier: MIT
3 * Copyright © 2023 Intel Corporation
8 #include "intel_display_types.h"
10 #include "skl_watermark.h"
13 * intel_update_watermarks - update FIFO watermark values based on current modes
16 * Calculate watermark values for the various WM regs based on current mode
17 * and plane configuration.
19 * There are several cases to deal with here:
20 * - normal (i.e. non-self-refresh)
21 * - self-refresh (SR) mode
22 * - lines are large relative to FIFO size (buffer can hold up to 2)
23 * - lines are small relative to FIFO size (buffer can hold more than 2
24 * lines), so need to account for TLB latency
26 * The normal calculation is:
27 * watermark = dotclock * bytes per pixel * latency
28 * where latency is platform & configuration dependent (we assume pessimal
31 * The SR calculation is:
32 * watermark = (trunc(latency/line time)+1) * surface width *
35 * line time = htotal / dotclock
36 * surface width = hdisplay for normal plane and 64 for cursor
37 * and latency is assumed to be high, as above.
39 * The final value programmed to the register should always be rounded up,
40 * and include an extra 2 entries to account for clock crossings.
42 * We don't use the sprite, so we can ignore that. And on Crestline we have
43 * to set the non-SR watermarks to 8.
45 void intel_update_watermarks(struct drm_i915_private *i915)
47 if (i915->display.funcs.wm->update_wm)
48 i915->display.funcs.wm->update_wm(i915);
51 int intel_compute_pipe_wm(struct intel_atomic_state *state,
52 struct intel_crtc *crtc)
54 struct drm_i915_private *i915 = to_i915(state->base.dev);
56 if (i915->display.funcs.wm->compute_pipe_wm)
57 return i915->display.funcs.wm->compute_pipe_wm(state, crtc);
62 int intel_compute_intermediate_wm(struct intel_atomic_state *state,
63 struct intel_crtc *crtc)
65 struct drm_i915_private *i915 = to_i915(state->base.dev);
67 if (!i915->display.funcs.wm->compute_intermediate_wm)
70 if (drm_WARN_ON(&i915->drm, !i915->display.funcs.wm->compute_pipe_wm))
73 return i915->display.funcs.wm->compute_intermediate_wm(state, crtc);
76 bool intel_initial_watermarks(struct intel_atomic_state *state,
77 struct intel_crtc *crtc)
79 struct drm_i915_private *i915 = to_i915(state->base.dev);
81 if (i915->display.funcs.wm->initial_watermarks) {
82 i915->display.funcs.wm->initial_watermarks(state, crtc);
89 void intel_atomic_update_watermarks(struct intel_atomic_state *state,
90 struct intel_crtc *crtc)
92 struct drm_i915_private *i915 = to_i915(state->base.dev);
94 if (i915->display.funcs.wm->atomic_update_watermarks)
95 i915->display.funcs.wm->atomic_update_watermarks(state, crtc);
98 void intel_optimize_watermarks(struct intel_atomic_state *state,
99 struct intel_crtc *crtc)
101 struct drm_i915_private *i915 = to_i915(state->base.dev);
103 if (i915->display.funcs.wm->optimize_watermarks)
104 i915->display.funcs.wm->optimize_watermarks(state, crtc);
107 int intel_compute_global_watermarks(struct intel_atomic_state *state)
109 struct drm_i915_private *i915 = to_i915(state->base.dev);
111 if (i915->display.funcs.wm->compute_global_watermarks)
112 return i915->display.funcs.wm->compute_global_watermarks(state);
117 void intel_wm_get_hw_state(struct drm_i915_private *i915)
119 if (i915->display.funcs.wm->get_hw_state)
120 return i915->display.funcs.wm->get_hw_state(i915);
123 bool intel_wm_plane_visible(const struct intel_crtc_state *crtc_state,
124 const struct intel_plane_state *plane_state)
126 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
128 /* FIXME check the 'enable' instead */
129 if (!crtc_state->hw.active)
133 * Treat cursor with fb as always visible since cursor updates
134 * can happen faster than the vrefresh rate, and the current
135 * watermark code doesn't handle that correctly. Cursor updates
136 * which set/clear the fb or change the cursor size are going
137 * to get throttled by intel_legacy_cursor_update() to work
138 * around this problem with the watermark code.
140 if (plane->id == PLANE_CURSOR)
141 return plane_state->hw.fb != NULL;
143 return plane_state->uapi.visible;
146 void intel_print_wm_latency(struct drm_i915_private *dev_priv,
147 const char *name, const u16 wm[])
151 for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
152 unsigned int latency = wm[level];
155 drm_dbg_kms(&dev_priv->drm,
156 "%s WM%d latency not provided\n",
162 * - latencies are in us on gen9.
163 * - before then, WM1+ latency values are in 0.5us units
165 if (DISPLAY_VER(dev_priv) >= 9)
170 drm_dbg_kms(&dev_priv->drm,
171 "%s WM%d latency %u (%u.%u usec)\n", name, level,
172 wm[level], latency / 10, latency % 10);
176 void intel_wm_init(struct drm_i915_private *i915)
178 if (DISPLAY_VER(i915) >= 9)
184 static void wm_latency_show(struct seq_file *m, const u16 wm[8])
186 struct drm_i915_private *dev_priv = m->private;
189 drm_modeset_lock_all(&dev_priv->drm);
191 for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
192 unsigned int latency = wm[level];
195 * - WM1+ latency values in 0.5us units
196 * - latencies are in us on gen9/vlv/chv
198 if (DISPLAY_VER(dev_priv) >= 9 ||
199 IS_VALLEYVIEW(dev_priv) ||
200 IS_CHERRYVIEW(dev_priv) ||
206 seq_printf(m, "WM%d %u (%u.%u usec)\n",
207 level, wm[level], latency / 10, latency % 10);
210 drm_modeset_unlock_all(&dev_priv->drm);
213 static int pri_wm_latency_show(struct seq_file *m, void *data)
215 struct drm_i915_private *dev_priv = m->private;
216 const u16 *latencies;
218 if (DISPLAY_VER(dev_priv) >= 9)
219 latencies = dev_priv->display.wm.skl_latency;
221 latencies = dev_priv->display.wm.pri_latency;
223 wm_latency_show(m, latencies);
228 static int spr_wm_latency_show(struct seq_file *m, void *data)
230 struct drm_i915_private *dev_priv = m->private;
231 const u16 *latencies;
233 if (DISPLAY_VER(dev_priv) >= 9)
234 latencies = dev_priv->display.wm.skl_latency;
236 latencies = dev_priv->display.wm.spr_latency;
238 wm_latency_show(m, latencies);
243 static int cur_wm_latency_show(struct seq_file *m, void *data)
245 struct drm_i915_private *dev_priv = m->private;
246 const u16 *latencies;
248 if (DISPLAY_VER(dev_priv) >= 9)
249 latencies = dev_priv->display.wm.skl_latency;
251 latencies = dev_priv->display.wm.cur_latency;
253 wm_latency_show(m, latencies);
258 static int pri_wm_latency_open(struct inode *inode, struct file *file)
260 struct drm_i915_private *dev_priv = inode->i_private;
262 if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv))
265 return single_open(file, pri_wm_latency_show, dev_priv);
268 static int spr_wm_latency_open(struct inode *inode, struct file *file)
270 struct drm_i915_private *dev_priv = inode->i_private;
272 if (HAS_GMCH(dev_priv))
275 return single_open(file, spr_wm_latency_show, dev_priv);
278 static int cur_wm_latency_open(struct inode *inode, struct file *file)
280 struct drm_i915_private *dev_priv = inode->i_private;
282 if (HAS_GMCH(dev_priv))
285 return single_open(file, cur_wm_latency_show, dev_priv);
288 static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
289 size_t len, loff_t *offp, u16 wm[8])
291 struct seq_file *m = file->private_data;
292 struct drm_i915_private *dev_priv = m->private;
298 if (len >= sizeof(tmp))
301 if (copy_from_user(tmp, ubuf, len))
306 ret = sscanf(tmp, "%hu %hu %hu %hu %hu %hu %hu %hu",
307 &new[0], &new[1], &new[2], &new[3],
308 &new[4], &new[5], &new[6], &new[7]);
309 if (ret != dev_priv->display.wm.num_levels)
312 drm_modeset_lock_all(&dev_priv->drm);
314 for (level = 0; level < dev_priv->display.wm.num_levels; level++)
315 wm[level] = new[level];
317 drm_modeset_unlock_all(&dev_priv->drm);
322 static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf,
323 size_t len, loff_t *offp)
325 struct seq_file *m = file->private_data;
326 struct drm_i915_private *dev_priv = m->private;
329 if (DISPLAY_VER(dev_priv) >= 9)
330 latencies = dev_priv->display.wm.skl_latency;
332 latencies = dev_priv->display.wm.pri_latency;
334 return wm_latency_write(file, ubuf, len, offp, latencies);
337 static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf,
338 size_t len, loff_t *offp)
340 struct seq_file *m = file->private_data;
341 struct drm_i915_private *dev_priv = m->private;
344 if (DISPLAY_VER(dev_priv) >= 9)
345 latencies = dev_priv->display.wm.skl_latency;
347 latencies = dev_priv->display.wm.spr_latency;
349 return wm_latency_write(file, ubuf, len, offp, latencies);
352 static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf,
353 size_t len, loff_t *offp)
355 struct seq_file *m = file->private_data;
356 struct drm_i915_private *dev_priv = m->private;
359 if (DISPLAY_VER(dev_priv) >= 9)
360 latencies = dev_priv->display.wm.skl_latency;
362 latencies = dev_priv->display.wm.cur_latency;
364 return wm_latency_write(file, ubuf, len, offp, latencies);
367 static const struct file_operations i915_pri_wm_latency_fops = {
368 .owner = THIS_MODULE,
369 .open = pri_wm_latency_open,
372 .release = single_release,
373 .write = pri_wm_latency_write
376 static const struct file_operations i915_spr_wm_latency_fops = {
377 .owner = THIS_MODULE,
378 .open = spr_wm_latency_open,
381 .release = single_release,
382 .write = spr_wm_latency_write
385 static const struct file_operations i915_cur_wm_latency_fops = {
386 .owner = THIS_MODULE,
387 .open = cur_wm_latency_open,
390 .release = single_release,
391 .write = cur_wm_latency_write
394 void intel_wm_debugfs_register(struct drm_i915_private *i915)
396 struct drm_minor *minor = i915->drm.primary;
398 debugfs_create_file("i915_pri_wm_latency", 0644, minor->debugfs_root,
399 i915, &i915_pri_wm_latency_fops);
401 debugfs_create_file("i915_spr_wm_latency", 0644, minor->debugfs_root,
402 i915, &i915_spr_wm_latency_fops);
404 debugfs_create_file("i915_cur_wm_latency", 0644, minor->debugfs_root,
405 i915, &i915_cur_wm_latency_fops);
407 skl_watermark_debugfs_register(i915);