[Intel-gfx] [PATCH 5/5] drm-i915: Add sys IPS toggle interface

Alexandra Yates alexandra.yates at linux.intel.com
Tue Apr 12 19:18:48 UTC 2016


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.yates at 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



More information about the Intel-gfx mailing list