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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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