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