This interface allows enabling/disabling of IPS feature.  It allows
to see immediately the power management savings and will allow
to expose this through sysfs interface for powertop to leverage its
functionality.

Signed-off-by: Alexandra Yates <alexandra.ya...@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c  |  5 ++-
 drivers/gpu/drm/i915/i915_drv.h      |  8 ++++
 drivers/gpu/drm/i915/i915_sysfs.c    | 78 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_color.c   | 12 ++++--
 drivers/gpu/drm/i915/intel_display.c | 37 +++++++++++++----
 drivers/gpu/drm/i915/intel_dp.c      | 11 +++--
 drivers/gpu/drm/i915/intel_drv.h     |  4 +-
 7 files changed, 136 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
b/drivers/gpu/drm/i915/i915_debugfs.c
index 2d11b49..e338c8a 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -4022,6 +4022,7 @@ static int pipe_crc_set_source(struct drm_device *dev, 
enum pipe pipe,
        enum intel_display_power_domain power_domain;
        u32 val = 0; /* shut up gcc */
        int ret;
+       bool sysfs_set = false;
 
        if (pipe_crc->source == source)
                return 0;
@@ -4071,7 +4072,7 @@ static int pipe_crc_set_source(struct drm_device *dev, 
enum pipe pipe,
                 * user space can't make reliable use of the CRCs, so let's just
                 * completely disable it.
                 */
-               hsw_disable_ips(crtc);
+               hsw_disable_ips(crtc, sysfs_set);
 
                spin_lock_irq(&pipe_crc->lock);
                kfree(pipe_crc->entries);
@@ -4116,7 +4117,7 @@ static int pipe_crc_set_source(struct drm_device *dev, 
enum pipe pipe,
                else if (IS_HASWELL(dev) && pipe == PIPE_A)
                        hsw_trans_edp_pipe_A_crc_wa(dev, false);
 
-               hsw_enable_ips(crtc);
+               hsw_enable_ips(crtc, sysfs_set);
        }
 
        ret = 0;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4c5eea6..0df0030 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -967,6 +967,12 @@ struct i915_drrs {
        bool sysfs_set;
 };
 
+struct i915_ips {
+       struct mutex lock;
+       int enable;
+       bool sysfs_set;
+};
+
 struct i915_psr {
        struct mutex lock;
        bool sink_support;
@@ -1888,6 +1894,8 @@ struct drm_i915_private {
 
        struct i915_power_domains power_domains;
 
+       struct i915_ips hsw_ips;
+
        struct i915_psr psr;
 
        struct i915_gpu_error gpu_error;
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c 
b/drivers/gpu/drm/i915/i915_sysfs.c
index f489ab6..3bc830b 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -265,6 +265,64 @@ toggle_psr(struct device *kdev, struct device_attribute 
*attr,
 }
 
 static ssize_t
+show_ips(struct device *kdev, struct device_attribute *attr, char *buf)
+{
+       struct drm_minor *dminor = dev_to_drm_minor(kdev);
+       struct drm_device *dev = dminor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       ssize_t ret;
+
+       mutex_lock(&dev_priv->hsw_ips.lock);
+       ret = snprintf(buf, PAGE_SIZE, "%s\n", dev_priv->hsw_ips.enable ?
+                       "enabled":"disabled");
+       mutex_unlock(&dev_priv->hsw_ips.lock);
+       return ret;
+}
+
+static ssize_t
+toggle_ips(struct device *kdev, struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct drm_minor *dminor = dev_to_drm_minor(kdev);
+       struct drm_device *dev = dminor->dev;
+       struct intel_connector *connector;
+       struct intel_encoder *encoder;
+       struct intel_crtc *crtc = NULL;
+       bool sysfs_set = true;
+       u32 val;
+       ssize_t ret;
+
+       ret = kstrtou32(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       for_each_intel_connector(dev, connector) {
+               if (!connector->base.encoder)
+                       continue;
+               encoder = to_intel_encoder(connector->base.encoder);
+               crtc = to_intel_crtc(encoder->base.crtc);
+       }
+       if (!crtc)
+               return -ENODEV;
+
+       switch (val) {
+               case 0:
+                       ret = hsw_disable_ips(crtc, sysfs_set);
+                       if (ret)
+                               return ret;
+                       break;
+               case 1:
+                       ret = hsw_enable_ips(crtc, sysfs_set);
+                       if (ret)
+                               return ret;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       return count;
+}
+
+static ssize_t
 show_drrs(struct device *kdev, struct device_attribute *attr, char *buf)
 {
        struct drm_minor *dminor = dev_to_drm_minor(kdev);
@@ -329,6 +387,7 @@ toggle_drrs(struct device *kdev, struct device_attribute 
*attr,
        return count;
 }
 
+static DEVICE_ATTR(ips_enable, S_IRUGO | S_IWUSR, show_ips, toggle_ips);
 static DEVICE_ATTR(drrs_enable, S_IRUGO | S_IWUSR, show_drrs, toggle_drrs);
 static DEVICE_ATTR(fbc_enable, S_IRUGO | S_IWUSR, show_fbc, toggle_fbc);
 static DEVICE_ATTR(psr_enable, S_IRUGO | S_IWUSR, show_psr, toggle_psr);
@@ -348,6 +407,16 @@ static struct attribute_group fbc_attr_group = {
        .attrs = fbc_attrs
 };
 
+static struct attribute *ips_attrs[] = {
+       &dev_attr_ips_enable.attr,
+       NULL
+};
+
+static struct attribute_group ips_attr_group = {
+       .name = power_group_name,
+       .attrs = ips_attrs
+};
+
 static struct attribute *psr_attrs[] = {
        &dev_attr_psr_enable.attr,
        NULL
@@ -859,6 +928,14 @@ void i915_setup_sysfs(struct drm_device *dev)
                if (ret)
                        DRM_ERROR("FBC sysfs setup failed\n");
        }
+
+       if (HAS_IPS(dev)) {
+               ret = sysfs_merge_group(&dev->primary->kdev->kobj,
+                                       &ips_attr_group);
+               if (ret)
+                       DRM_ERROR("IPS sysfs setup failed\n");
+       }
+
        if (HAS_PSR(dev)) {
                ret = sysfs_merge_group(&dev->primary->kdev->kobj,
                                        &psr_attr_group);
@@ -931,6 +1008,7 @@ void i915_teardown_sysfs(struct drm_device *dev)
 #ifdef CONFIG_PM
        sysfs_unmerge_group(&dev->primary->kdev->kobj, &drrs_attr_group);
        sysfs_unmerge_group(&dev->primary->kdev->kobj, &fbc_attr_group);
+       sysfs_unmerge_group(&dev->primary->kdev->kobj, &ips_attr_group);
        sysfs_unmerge_group(&dev->primary->kdev->kobj, &psr_attr_group);
        sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6_attr_group);
        sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6p_attr_group);
diff --git a/drivers/gpu/drm/i915/intel_color.c 
b/drivers/gpu/drm/i915/intel_color.c
index 1b3f974..27660a6 100644
--- a/drivers/gpu/drm/i915/intel_color.c
+++ b/drivers/gpu/drm/i915/intel_color.c
@@ -325,8 +325,10 @@ static void haswell_load_luts(struct drm_crtc_state 
*crtc_state)
         */
        if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
            (intel_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) {
-               hsw_disable_ips(intel_crtc);
-               reenable_ips = true;
+               if (dev_priv->hsw_ips.sysfs_set != true){
+                       hsw_disable_ips(intel_crtc, 
dev_priv->hsw_ips.sysfs_set);
+                       reenable_ips = true;
+               }
        }
 
        intel_crtc_state->gamma_mode = GAMMA_MODE_MODE_8BIT;
@@ -334,8 +336,10 @@ static void haswell_load_luts(struct drm_crtc_state 
*crtc_state)
 
        i9xx_load_luts(crtc_state);
 
-       if (reenable_ips)
-               hsw_enable_ips(intel_crtc);
+       if (reenable_ips){
+               if (dev_priv->hsw_ips.sysfs_set != true)
+                       hsw_enable_ips(intel_crtc, dev_priv->hsw_ips.sysfs_set);
+       }
 }
 
 /* Loads the palette/gamma unit for the CRTC on Broadwell+. */
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index 4a671e3..7a66d00 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4400,13 +4400,14 @@ static void ironlake_pfit_enable(struct intel_crtc 
*crtc)
        }
 }
 
-void hsw_enable_ips(struct intel_crtc *crtc)
+int hsw_enable_ips(struct intel_crtc *crtc, bool sysfs_set)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
 
        if (!crtc->config->ips_enabled)
-               return;
+               return -EINVAL;
 
        /*
         * We can only enable IPS after we enable a plane and wait for a vblank
@@ -4431,18 +4432,28 @@ void hsw_enable_ips(struct intel_crtc *crtc)
                 * and don't wait for vblanks until the end of crtc_enable, then
                 * the HW state readout code will complain that the expected
                 * IPS_CTL value is not the one we read. */
-               if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50))
+               if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50)){
                        DRM_ERROR("Timed out waiting for IPS enable\n");
+                       ret = -ETIMEDOUT;
+               }
        }
+
+       mutex_lock(&dev_priv->hsw_ips.lock);
+       dev_priv->hsw_ips.enable = 1;
+       dev_priv->hsw_ips.sysfs_set = sysfs_set;
+       mutex_unlock(&dev_priv->hsw_ips.lock);
+
+       return ret;
 }
 
-void hsw_disable_ips(struct intel_crtc *crtc)
+int hsw_disable_ips(struct intel_crtc *crtc, bool sysfs_set)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
 
        if (!crtc->config->ips_enabled)
-               return;
+               return -EINVAL;
 
        assert_plane_enabled(dev_priv, crtc->plane);
        if (IS_BROADWELL(dev)) {
@@ -4450,15 +4461,23 @@ void hsw_disable_ips(struct intel_crtc *crtc)
                WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 
0));
                mutex_unlock(&dev_priv->rps.hw_lock);
                /* wait for pcode to finish disabling IPS, which may take up to 
42ms */
-               if (wait_for((I915_READ(IPS_CTL) & IPS_ENABLE) == 0, 42))
+               if (wait_for((I915_READ(IPS_CTL) & IPS_ENABLE) == 0, 42)){
                        DRM_ERROR("Timed out waiting for IPS disable\n");
+                       ret = -ETIMEDOUT;
+               }
        } else {
                I915_WRITE(IPS_CTL, 0);
                POSTING_READ(IPS_CTL);
        }
 
+       mutex_lock(&dev_priv->hsw_ips.lock);
+       dev_priv->hsw_ips.enable = 0;
+       dev_priv->hsw_ips.sysfs_set = sysfs_set;
+       mutex_unlock(&dev_priv->hsw_ips.lock);
+
        /* We need to wait for a vblank before we can disable the plane. */
        intel_wait_for_vblank(dev, crtc->pipe);
+       return ret;
 }
 
 static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc)
@@ -4503,7 +4522,8 @@ intel_post_enable_primary(struct drm_crtc *crtc)
         * when going from primary only to sprite only and vice
         * versa.
         */
-       hsw_enable_ips(intel_crtc);
+       if (dev_priv->hsw_ips.sysfs_set != true)
+               hsw_enable_ips(intel_crtc, dev_priv->hsw_ips.sysfs_set);
 
        /*
         * Gen2 reports pipe underruns whenever all planes are disabled.
@@ -4544,7 +4564,8 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
         * when going from primary only to sprite only and vice
         * versa.
         */
-       hsw_disable_ips(intel_crtc);
+       if (dev_priv->hsw_ips.sysfs_set != true)
+               hsw_disable_ips(intel_crtc, dev_priv->hsw_ips.sysfs_set);
 }
 
 /* FIXME get rid of this and use pre_plane_update */
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index ec4bd12..0fff2bd 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3906,6 +3906,7 @@ static int intel_dp_sink_crc_stop(struct intel_dp 
*intel_dp)
 {
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
        u8 buf;
        int ret = 0;
@@ -3942,7 +3943,8 @@ static int intel_dp_sink_crc_stop(struct intel_dp 
*intel_dp)
        }
 
  out:
-       hsw_enable_ips(intel_crtc);
+       if (dev_priv->hsw_ips.sysfs_set != true)
+               hsw_enable_ips(intel_crtc, dev_priv->hsw_ips.sysfs_set);
        return ret;
 }
 
@@ -3950,6 +3952,7 @@ static int intel_dp_sink_crc_start(struct intel_dp 
*intel_dp)
 {
        struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = dig_port->base.base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
        u8 buf;
        int ret;
@@ -3969,11 +3972,13 @@ static int intel_dp_sink_crc_start(struct intel_dp 
*intel_dp)
                        return ret;
        }
 
-       hsw_disable_ips(intel_crtc);
+       if (dev_priv->hsw_ips.sysfs_set != true)
+               hsw_disable_ips(intel_crtc, dev_priv->hsw_ips.sysfs_set);
 
        if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
                               buf | DP_TEST_SINK_START) < 0) {
-               hsw_enable_ips(intel_crtc);
+               if (dev_priv->hsw_ips.sysfs_set != true)
+                       hsw_enable_ips(intel_crtc, dev_priv->hsw_ips.sysfs_set);
                return -EIO;
        }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index eda84ae..c616cb6 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1244,8 +1244,8 @@ bool bxt_find_best_dpll(struct intel_crtc_state 
*crtc_state, int target_clock,
 int chv_calc_dpll_params(int refclk, intel_clock_t *pll_clock);
 
 bool intel_crtc_active(struct drm_crtc *crtc);
-void hsw_enable_ips(struct intel_crtc *crtc);
-void hsw_disable_ips(struct intel_crtc *crtc);
+int hsw_enable_ips(struct intel_crtc *crtc, bool sysfs_set);
+int hsw_disable_ips(struct intel_crtc *crtc, bool sysfs_set);
 enum intel_display_power_domain
 intel_display_port_power_domain(struct intel_encoder *intel_encoder);
 enum intel_display_power_domain
-- 
2.5.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to