Contributors: 30
Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
Jani Nikula |
1250 |
67.13% |
17 |
23.94% |
Dave Airlie |
243 |
13.05% |
6 |
8.45% |
Ville Syrjälä |
71 |
3.81% |
9 |
12.68% |
Manasi D Navare |
57 |
3.06% |
1 |
1.41% |
Chris Wilson |
56 |
3.01% |
4 |
5.63% |
Vandita Kulkarni |
23 |
1.24% |
1 |
1.41% |
Eric Anholt |
22 |
1.18% |
1 |
1.41% |
Stephen Chandler Paul |
20 |
1.07% |
1 |
1.41% |
Linus Torvalds |
15 |
0.81% |
2 |
2.82% |
Matt Roper |
11 |
0.59% |
3 |
4.23% |
Daniel Vetter |
11 |
0.59% |
2 |
2.82% |
Ben Gamari |
10 |
0.54% |
1 |
1.41% |
Maarten Lankhorst |
9 |
0.48% |
4 |
5.63% |
Arjan van de Ven |
9 |
0.48% |
1 |
1.41% |
Ben Widawsky |
7 |
0.38% |
1 |
1.41% |
Paulo Zanoni |
7 |
0.38% |
2 |
2.82% |
Deepak S |
6 |
0.32% |
1 |
1.41% |
Mika Kuoppala |
5 |
0.27% |
1 |
1.41% |
Zhenyu Wang |
5 |
0.27% |
1 |
1.41% |
Bhanuprakash Modem |
4 |
0.21% |
1 |
1.41% |
José Roberto de Souza |
4 |
0.21% |
2 |
2.82% |
Rafael J. Wysocki |
3 |
0.16% |
1 |
1.41% |
Kristian Högsberg |
3 |
0.16% |
1 |
1.41% |
Lucas De Marchi |
2 |
0.11% |
1 |
1.41% |
Jeff McGee |
2 |
0.11% |
1 |
1.41% |
Imre Deak |
2 |
0.11% |
1 |
1.41% |
Jesse Barnes |
2 |
0.11% |
1 |
1.41% |
Lee Jones |
1 |
0.05% |
1 |
1.41% |
Patnana Venkata Sai |
1 |
0.05% |
1 |
1.41% |
Wayne Boyer |
1 |
0.05% |
1 |
1.41% |
Total |
1862 |
|
71 |
|
// SPDX-License-Identifier: MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include "i915_drv.h"
#include "i9xx_wm.h"
#include "intel_display_types.h"
#include "intel_wm.h"
#include "skl_watermark.h"
/**
* intel_update_watermarks - update FIFO watermark values based on current modes
* @i915: i915 device
*
* Calculate watermark values for the various WM regs based on current mode
* and plane configuration.
*
* There are several cases to deal with here:
* - normal (i.e. non-self-refresh)
* - self-refresh (SR) mode
* - lines are large relative to FIFO size (buffer can hold up to 2)
* - lines are small relative to FIFO size (buffer can hold more than 2
* lines), so need to account for TLB latency
*
* The normal calculation is:
* watermark = dotclock * bytes per pixel * latency
* where latency is platform & configuration dependent (we assume pessimal
* values here).
*
* The SR calculation is:
* watermark = (trunc(latency/line time)+1) * surface width *
* bytes per pixel
* where
* line time = htotal / dotclock
* surface width = hdisplay for normal plane and 64 for cursor
* and latency is assumed to be high, as above.
*
* The final value programmed to the register should always be rounded up,
* and include an extra 2 entries to account for clock crossings.
*
* We don't use the sprite, so we can ignore that. And on Crestline we have
* to set the non-SR watermarks to 8.
*/
void intel_update_watermarks(struct drm_i915_private *i915)
{
if (i915->display.funcs.wm->update_wm)
i915->display.funcs.wm->update_wm(i915);
}
int intel_compute_pipe_wm(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
if (i915->display.funcs.wm->compute_pipe_wm)
return i915->display.funcs.wm->compute_pipe_wm(state, crtc);
return 0;
}
int intel_compute_intermediate_wm(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
if (!i915->display.funcs.wm->compute_intermediate_wm)
return 0;
if (drm_WARN_ON(&i915->drm, !i915->display.funcs.wm->compute_pipe_wm))
return 0;
return i915->display.funcs.wm->compute_intermediate_wm(state, crtc);
}
bool intel_initial_watermarks(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
if (i915->display.funcs.wm->initial_watermarks) {
i915->display.funcs.wm->initial_watermarks(state, crtc);
return true;
}
return false;
}
void intel_atomic_update_watermarks(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
if (i915->display.funcs.wm->atomic_update_watermarks)
i915->display.funcs.wm->atomic_update_watermarks(state, crtc);
}
void intel_optimize_watermarks(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
if (i915->display.funcs.wm->optimize_watermarks)
i915->display.funcs.wm->optimize_watermarks(state, crtc);
}
int intel_compute_global_watermarks(struct intel_atomic_state *state)
{
struct drm_i915_private *i915 = to_i915(state->base.dev);
if (i915->display.funcs.wm->compute_global_watermarks)
return i915->display.funcs.wm->compute_global_watermarks(state);
return 0;
}
void intel_wm_get_hw_state(struct drm_i915_private *i915)
{
if (i915->display.funcs.wm->get_hw_state)
return i915->display.funcs.wm->get_hw_state(i915);
}
bool intel_wm_plane_visible(const struct intel_crtc_state *crtc_state,
const struct intel_plane_state *plane_state)
{
struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
/* FIXME check the 'enable' instead */
if (!crtc_state->hw.active)
return false;
/*
* Treat cursor with fb as always visible since cursor updates
* can happen faster than the vrefresh rate, and the current
* watermark code doesn't handle that correctly. Cursor updates
* which set/clear the fb or change the cursor size are going
* to get throttled by intel_legacy_cursor_update() to work
* around this problem with the watermark code.
*/
if (plane->id == PLANE_CURSOR)
return plane_state->hw.fb != NULL;
else
return plane_state->uapi.visible;
}
void intel_print_wm_latency(struct drm_i915_private *dev_priv,
const char *name, const u16 wm[])
{
int level;
for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
unsigned int latency = wm[level];
if (latency == 0) {
drm_dbg_kms(&dev_priv->drm,
"%s WM%d latency not provided\n",
name, level);
continue;
}
/*
* - latencies are in us on gen9.
* - before then, WM1+ latency values are in 0.5us units
*/
if (DISPLAY_VER(dev_priv) >= 9)
latency *= 10;
else if (level > 0)
latency *= 5;
drm_dbg_kms(&dev_priv->drm,
"%s WM%d latency %u (%u.%u usec)\n", name, level,
wm[level], latency / 10, latency % 10);
}
}
void intel_wm_init(struct drm_i915_private *i915)
{
if (DISPLAY_VER(i915) >= 9)
skl_wm_init(i915);
else
i9xx_wm_init(i915);
}
static void wm_latency_show(struct seq_file *m, const u16 wm[8])
{
struct drm_i915_private *dev_priv = m->private;
int level;
drm_modeset_lock_all(&dev_priv->drm);
for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
unsigned int latency = wm[level];
/*
* - WM1+ latency values in 0.5us units
* - latencies are in us on gen9/vlv/chv
*/
if (DISPLAY_VER(dev_priv) >= 9 ||
IS_VALLEYVIEW(dev_priv) ||
IS_CHERRYVIEW(dev_priv) ||
IS_G4X(dev_priv))
latency *= 10;
else if (level > 0)
latency *= 5;
seq_printf(m, "WM%d %u (%u.%u usec)\n",
level, wm[level], latency / 10, latency % 10);
}
drm_modeset_unlock_all(&dev_priv->drm);
}
static int pri_wm_latency_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
const u16 *latencies;
if (DISPLAY_VER(dev_priv) >= 9)
latencies = dev_priv->display.wm.skl_latency;
else
latencies = dev_priv->display.wm.pri_latency;
wm_latency_show(m, latencies);
return 0;
}
static int spr_wm_latency_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
const u16 *latencies;
if (DISPLAY_VER(dev_priv) >= 9)
latencies = dev_priv->display.wm.skl_latency;
else
latencies = dev_priv->display.wm.spr_latency;
wm_latency_show(m, latencies);
return 0;
}
static int cur_wm_latency_show(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = m->private;
const u16 *latencies;
if (DISPLAY_VER(dev_priv) >= 9)
latencies = dev_priv->display.wm.skl_latency;
else
latencies = dev_priv->display.wm.cur_latency;
wm_latency_show(m, latencies);
return 0;
}
static int pri_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_i915_private *dev_priv = inode->i_private;
if (DISPLAY_VER(dev_priv) < 5 && !IS_G4X(dev_priv))
return -ENODEV;
return single_open(file, pri_wm_latency_show, dev_priv);
}
static int spr_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_i915_private *dev_priv = inode->i_private;
if (HAS_GMCH(dev_priv))
return -ENODEV;
return single_open(file, spr_wm_latency_show, dev_priv);
}
static int cur_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_i915_private *dev_priv = inode->i_private;
if (HAS_GMCH(dev_priv))
return -ENODEV;
return single_open(file, cur_wm_latency_show, dev_priv);
}
static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp, u16 wm[8])
{
struct seq_file *m = file->private_data;
struct drm_i915_private *dev_priv = m->private;
u16 new[8] = {};
int level;
int ret;
char tmp[32];
if (len >= sizeof(tmp))
return -EINVAL;
if (copy_from_user(tmp, ubuf, len))
return -EFAULT;
tmp[len] = '\0';
ret = sscanf(tmp, "%hu %hu %hu %hu %hu %hu %hu %hu",
&new[0], &new[1], &new[2], &new[3],
&new[4], &new[5], &new[6], &new[7]);
if (ret != dev_priv->display.wm.num_levels)
return -EINVAL;
drm_modeset_lock_all(&dev_priv->drm);
for (level = 0; level < dev_priv->display.wm.num_levels; level++)
wm[level] = new[level];
drm_modeset_unlock_all(&dev_priv->drm);
return len;
}
static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct drm_i915_private *dev_priv = m->private;
u16 *latencies;
if (DISPLAY_VER(dev_priv) >= 9)
latencies = dev_priv->display.wm.skl_latency;
else
latencies = dev_priv->display.wm.pri_latency;
return wm_latency_write(file, ubuf, len, offp, latencies);
}
static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct drm_i915_private *dev_priv = m->private;
u16 *latencies;
if (DISPLAY_VER(dev_priv) >= 9)
latencies = dev_priv->display.wm.skl_latency;
else
latencies = dev_priv->display.wm.spr_latency;
return wm_latency_write(file, ubuf, len, offp, latencies);
}
static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct drm_i915_private *dev_priv = m->private;
u16 *latencies;
if (DISPLAY_VER(dev_priv) >= 9)
latencies = dev_priv->display.wm.skl_latency;
else
latencies = dev_priv->display.wm.cur_latency;
return wm_latency_write(file, ubuf, len, offp, latencies);
}
static const struct file_operations i915_pri_wm_latency_fops = {
.owner = THIS_MODULE,
.open = pri_wm_latency_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = pri_wm_latency_write
};
static const struct file_operations i915_spr_wm_latency_fops = {
.owner = THIS_MODULE,
.open = spr_wm_latency_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = spr_wm_latency_write
};
static const struct file_operations i915_cur_wm_latency_fops = {
.owner = THIS_MODULE,
.open = cur_wm_latency_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = cur_wm_latency_write
};
void intel_wm_debugfs_register(struct drm_i915_private *i915)
{
struct drm_minor *minor = i915->drm.primary;
debugfs_create_file("i915_pri_wm_latency", 0644, minor->debugfs_root,
i915, &i915_pri_wm_latency_fops);
debugfs_create_file("i915_spr_wm_latency", 0644, minor->debugfs_root,
i915, &i915_spr_wm_latency_fops);
debugfs_create_file("i915_cur_wm_latency", 0644, minor->debugfs_root,
i915, &i915_cur_wm_latency_fops);
skl_watermark_debugfs_register(i915);
}