.write = display_crc_ctl_write
 };
 
+static void wm_latency_show(struct seq_file *m, const uint16_t wm[5])
+{
+       struct drm_device *dev = m->private;
+       int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
+       int level;
+
+       drm_modeset_lock_all(dev);
+
+       for (level = 0; level < num_levels; level++) {
+               unsigned int latency = wm[level];
+
+               /* WM1+ latency values in 0.5us units */
+               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);
+}
+
+static int pri_wm_latency_show(struct seq_file *m, void *data)
+{
+       struct drm_device *dev = m->private;
+
+       wm_latency_show(m, to_i915(dev)->wm.pri_latency);
+
+       return 0;
+}
+
+static int spr_wm_latency_show(struct seq_file *m, void *data)
+{
+       struct drm_device *dev = m->private;
+
+       wm_latency_show(m, to_i915(dev)->wm.spr_latency);
+
+       return 0;
+}
+
+static int cur_wm_latency_show(struct seq_file *m, void *data)
+{
+       struct drm_device *dev = m->private;
+
+       wm_latency_show(m, to_i915(dev)->wm.cur_latency);
+
+       return 0;
+}
+
+static int pri_wm_latency_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return -ENODEV;
+
+       return single_open(file, pri_wm_latency_show, dev);
+}
+
+static int spr_wm_latency_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return -ENODEV;
+
+       return single_open(file, spr_wm_latency_show, dev);
+}
+
+static int cur_wm_latency_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return -ENODEV;
+
+       return single_open(file, cur_wm_latency_show, dev);
+}
+
+static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
+                               size_t len, loff_t *offp, uint16_t wm[5])
+{
+       struct seq_file *m = file->private_data;
+       struct drm_device *dev = m->private;
+       uint16_t new[5] = { 0 };
+       int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
+       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", &new[0], &new[1], &new[2], &new[3], &new[4]);
+       if (ret != num_levels)
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+
+       for (level = 0; level < num_levels; level++)
+               wm[level] = new[level];
+
+       drm_modeset_unlock_all(dev);
+
+       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_device *dev = m->private;
+
+       return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.pri_latency);
+}
+
+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_device *dev = m->private;
+
+       return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.spr_latency);
+}
+
+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_device *dev = m->private;
+
+       return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.cur_latency);
+}
+
+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
+};
+
 static int
 i915_wedged_get(void *data, u64 *val)
 {
        {"i915_error_state", &i915_error_state_fops},
        {"i915_next_seqno", &i915_next_seqno_fops},
        {"i915_display_crc_ctl", &i915_display_crc_ctl_fops},
+       {"i915_pri_wm_latency", &i915_pri_wm_latency_fops},
+       {"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
+       {"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
 };
 
 void intel_display_crc_init(struct drm_device *dev)