#include <linux/debugfs.h>
#include <drm/drm_print.h>
#include "i9xx_wm.h"
#include "intel_display_core.h"
#include "intel_display_types.h"
#include "intel_wm.h"
#include "skl_watermark.h"
void intel_update_watermarks(struct intel_display *display)
{
if (display->funcs.wm->update_wm)
display->funcs.wm->update_wm(display);
}
int intel_wm_compute(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct intel_display *display = to_intel_display(state);
if (!display->funcs.wm->compute_watermarks)
return 0;
return display->funcs.wm->compute_watermarks(state, crtc);
}
bool intel_initial_watermarks(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct intel_display *display = to_intel_display(state);
if (display->funcs.wm->initial_watermarks) {
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 intel_display *display = to_intel_display(state);
if (display->funcs.wm->atomic_update_watermarks)
display->funcs.wm->atomic_update_watermarks(state, crtc);
}
void intel_optimize_watermarks(struct intel_atomic_state *state,
struct intel_crtc *crtc)
{
struct intel_display *display = to_intel_display(state);
if (display->funcs.wm->optimize_watermarks)
display->funcs.wm->optimize_watermarks(state, crtc);
}
int intel_compute_global_watermarks(struct intel_atomic_state *state)
{
struct intel_display *display = to_intel_display(state);
if (display->funcs.wm->compute_global_watermarks)
return display->funcs.wm->compute_global_watermarks(state);
return 0;
}
void intel_wm_get_hw_state(struct intel_display *display)
{
if (display->funcs.wm->get_hw_state)
return display->funcs.wm->get_hw_state(display);
}
void intel_wm_sanitize(struct intel_display *display)
{
if (display->funcs.wm->sanitize)
return display->funcs.wm->sanitize(display);
}
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);
if (!crtc_state->hw.active)
return false;
if (plane->id == PLANE_CURSOR)
return plane_state->hw.fb != NULL;
else
return plane_state->uapi.visible;
}
void intel_print_wm_latency(struct intel_display *display,
const char *name, const u16 wm[])
{
int level;
for (level = 0; level < display->wm.num_levels; level++) {
unsigned int latency = wm[level];
if (latency == 0) {
drm_dbg_kms(display->drm,
"%s WM%d latency not provided\n",
name, level);
continue;
}
if (DISPLAY_VER(display) >= 9)
latency *= 10;
else if (level > 0)
latency *= 5;
drm_dbg_kms(display->drm,
"%s WM%d latency %u (%u.%u usec)\n", name, level,
wm[level], latency / 10, latency % 10);
}
}
void intel_wm_init(struct intel_display *display)
{
if (DISPLAY_VER(display) >= 9)
skl_wm_init(display);
else
i9xx_wm_init(display);
}
static void wm_latency_show(struct seq_file *m, const u16 wm[8])
{
struct intel_display *display = m->private;
int level;
drm_modeset_lock_all(display->drm);
for (level = 0; level < display->wm.num_levels; level++) {
unsigned int latency = wm[level];
if (DISPLAY_VER(display) >= 9 ||
display->platform.valleyview ||
display->platform.cherryview ||
display->platform.g4x)
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(display->drm);
}
static int pri_wm_latency_show(struct seq_file *m, void *data)
{
struct intel_display *display = m->private;
const u16 *latencies;
if (DISPLAY_VER(display) >= 9)
latencies = display->wm.skl_latency;
else
latencies = display->wm.pri_latency;
wm_latency_show(m, latencies);
return 0;
}
static int spr_wm_latency_show(struct seq_file *m, void *data)
{
struct intel_display *display = m->private;
const u16 *latencies;
if (DISPLAY_VER(display) >= 9)
latencies = display->wm.skl_latency;
else
latencies = display->wm.spr_latency;
wm_latency_show(m, latencies);
return 0;
}
static int cur_wm_latency_show(struct seq_file *m, void *data)
{
struct intel_display *display = m->private;
const u16 *latencies;
if (DISPLAY_VER(display) >= 9)
latencies = display->wm.skl_latency;
else
latencies = display->wm.cur_latency;
wm_latency_show(m, latencies);
return 0;
}
static int pri_wm_latency_open(struct inode *inode, struct file *file)
{
struct intel_display *display = inode->i_private;
if (DISPLAY_VER(display) < 5 && !display->platform.g4x)
return -ENODEV;
return single_open(file, pri_wm_latency_show, display);
}
static int spr_wm_latency_open(struct inode *inode, struct file *file)
{
struct intel_display *display = inode->i_private;
if (HAS_GMCH(display))
return -ENODEV;
return single_open(file, spr_wm_latency_show, display);
}
static int cur_wm_latency_open(struct inode *inode, struct file *file)
{
struct intel_display *display = inode->i_private;
if (HAS_GMCH(display))
return -ENODEV;
return single_open(file, cur_wm_latency_show, display);
}
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 intel_display *display = 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 != display->wm.num_levels)
return -EINVAL;
drm_modeset_lock_all(display->drm);
for (level = 0; level < display->wm.num_levels; level++)
wm[level] = new[level];
drm_modeset_unlock_all(display->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 intel_display *display = m->private;
u16 *latencies;
if (DISPLAY_VER(display) >= 9)
latencies = display->wm.skl_latency;
else
latencies = 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 intel_display *display = m->private;
u16 *latencies;
if (DISPLAY_VER(display) >= 9)
latencies = display->wm.skl_latency;
else
latencies = 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 intel_display *display = m->private;
u16 *latencies;
if (DISPLAY_VER(display) >= 9)
latencies = display->wm.skl_latency;
else
latencies = 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 intel_display *display)
{
struct dentry *debugfs_root = display->drm->debugfs_root;
debugfs_create_file("i915_pri_wm_latency", 0644, debugfs_root,
display, &i915_pri_wm_latency_fops);
debugfs_create_file("i915_spr_wm_latency", 0644, debugfs_root,
display, &i915_spr_wm_latency_fops);
debugfs_create_file("i915_cur_wm_latency", 0644, debugfs_root,
display, &i915_cur_wm_latency_fops);
skl_watermark_debugfs_register(display);
}