[4/5] drm/i915: Add sys drrs toggle interface

Submitted by Alexandra Yates on April 12, 2016, 7:18 p.m.

Details

Message ID 1460488728-23319-5-git-send-email-alexandra.yates@linux.intel.com
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Intel GFX

Not browsing as part of any series.

Commit Message

Alexandra Yates April 12, 2016, 7:18 p.m.
This interface allows enabling/disabling of DRRS 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@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h   |  1 +
 drivers/gpu/drm/i915/i915_sysfs.c | 86 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ddi.c  |  9 +++-
 drivers/gpu/drm/i915/intel_dp.c   | 26 +++++++++---
 drivers/gpu/drm/i915/intel_drv.h  |  4 +-
 5 files changed, 116 insertions(+), 10 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index bbe189f..4c5eea6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -964,6 +964,7 @@  struct i915_drrs {
 	unsigned busy_frontbuffer_bits;
 	enum drrs_refresh_rate_type refresh_rate_type;
 	enum drrs_support_type type;
+	bool sysfs_set;
 };
 
 struct i915_psr {
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 81aa534..f489ab6 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -264,6 +264,72 @@  toggle_psr(struct device *kdev, struct device_attribute *attr,
 	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);
+	struct drm_device *dev = dminor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	ssize_t ret;
+
+	mutex_lock(&dev_priv->drrs.mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", dev_priv->drrs.dp ?
+			"enabled":"disabled");
+	mutex_unlock(&dev_priv->drrs.mutex);
+	return ret;
+}
+
+static ssize_t
+toggle_drrs(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;
+	struct intel_dp *intel_dp = NULL;
+	u32 val;
+	ssize_t ret;
+	bool sysfs_set = true;
+
+	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);
+		intel_dp = enc_to_intel_dp(&encoder->base);
+	}
+	if (!crtc)
+		return -ENODEV;
+
+	switch (val) {
+	case 0:
+		ret = intel_edp_drrs_disable(intel_dp, sysfs_set);
+		if (ret)
+			return ret;
+		break;
+	case 1:
+		if (encoder->type == INTEL_OUTPUT_EDP) {
+			ret = intel_edp_drrs_enable(intel_dp, sysfs_set);
+			if (ret)
+				return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+
+	}
+
+	return count;
+}
+
+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);
 static DEVICE_ATTR(rc6_enable, S_IRUGO | S_IWUSR, show_rc6_mask, toggle_rc6);
@@ -323,6 +389,17 @@  static struct attribute_group media_rc6_attr_group = {
 	.name = power_group_name,
 	.attrs =  media_rc6_attrs
 };
+
+static struct attribute *drrs_attrs[] = {
+	&dev_attr_drrs_enable.attr,
+	NULL
+};
+
+static struct attribute_group drrs_attr_group = {
+	.name = power_group_name,
+	.attrs = drrs_attrs
+};
+
 #endif
 
 static int l3_access_valid(struct drm_device *dev, loff_t offset)
@@ -788,6 +865,14 @@  void i915_setup_sysfs(struct drm_device *dev)
 		if (ret)
 			DRM_ERROR("PSR sysfs setup failed\n");
 	}
+
+	if (HAS_PSR(dev)) {
+		ret = sysfs_merge_group(&dev->primary->kdev->kobj,
+					&drrs_attr_group);
+		if (ret)
+			DRM_ERROR("DRRS sysfs setup failed\n");
+	}
+
 	if (HAS_RC6(dev)) {
 		ret = sysfs_merge_group(&dev->primary->kdev->kobj,
 					&rc6_attr_group);
@@ -844,6 +929,7 @@  void i915_teardown_sysfs(struct drm_device *dev)
 	device_remove_bin_file(dev->primary->kdev,  &dpf_attrs_1);
 	device_remove_bin_file(dev->primary->kdev,  &dpf_attrs);
 #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, &psr_attr_group);
 	sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6_attr_group);
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 8e384e5..eb6f0f9 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1691,7 +1691,9 @@  static void intel_enable_ddi(struct intel_encoder *intel_encoder)
 		intel_edp_backlight_on(intel_dp);
 		if (dev_priv->psr.sysfs_set != true)
 			intel_psr_enable(intel_dp, dev_priv->psr.sysfs_set);
-		intel_edp_drrs_enable(intel_dp);
+		if (dev_priv->drrs.sysfs_set != true)
+			intel_edp_drrs_enable(intel_dp,
+						dev_priv->drrs.sysfs_set);
 	}
 
 	if (intel_crtc->config->has_audio) {
@@ -1717,7 +1719,10 @@  static void intel_disable_ddi(struct intel_encoder *intel_encoder)
 	if (type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
-		intel_edp_drrs_disable(intel_dp);
+		if (dev_priv->drrs.sysfs_set != true)
+			intel_edp_drrs_disable(intel_dp,
+						dev_priv->drrs.sysfs_set);
+
 		if (dev_priv->psr.sysfs_set != true)
 			intel_psr_disable(intel_dp, dev_priv->psr.sysfs_set);
 		intel_edp_backlight_off(intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 183a60a..ec4bd12 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -5413,42 +5413,53 @@  static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
 /**
  * intel_edp_drrs_enable - init drrs struct if supported
  * @intel_dp: DP struct
+ * @sysfs_set: Identifies if this featudre is set from sysfs.
  *
  * Initializes frontbuffer_bits and drrs.dp
+ *
+ * Returns:
+ * 0 on success and -errno otherwise.
  */
-void intel_edp_drrs_enable(struct intel_dp *intel_dp)
+int intel_edp_drrs_enable(struct intel_dp *intel_dp, bool sysfs_set)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct drm_crtc *crtc = dig_port->base.base.crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int ret = 0;
 
 	if (!intel_crtc->config->has_drrs) {
 		DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
-		return;
+		return -EINVAL;
 	}
 
 	mutex_lock(&dev_priv->drrs.mutex);
 	if (WARN_ON(dev_priv->drrs.dp)) {
 		DRM_ERROR("DRRS already enabled\n");
+		ret = -EALREADY;
 		goto unlock;
 	}
 
 	dev_priv->drrs.busy_frontbuffer_bits = 0;
 
 	dev_priv->drrs.dp = intel_dp;
-
+	if (sysfs_set)
+		dev_priv->drrs.sysfs_set = sysfs_set;
 unlock:
 	mutex_unlock(&dev_priv->drrs.mutex);
+	return ret;
 }
 
 /**
  * intel_edp_drrs_disable - Disable DRRS
  * @intel_dp: DP struct
+ * @sysfs_set: Identifies if this featudre is set from sysfs.
  *
+ * Returns:
+ * 0 on success and -errno otherwise.
  */
-void intel_edp_drrs_disable(struct intel_dp *intel_dp)
+int intel_edp_drrs_disable(struct intel_dp *intel_dp, bool sysfs_set)
 {
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5457,12 +5468,12 @@  void intel_edp_drrs_disable(struct intel_dp *intel_dp)
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
 	if (!intel_crtc->config->has_drrs)
-		return;
+		return -EINVAL;
 
 	mutex_lock(&dev_priv->drrs.mutex);
 	if (!dev_priv->drrs.dp) {
 		mutex_unlock(&dev_priv->drrs.mutex);
-		return;
+		return -EALREADY;
 	}
 
 	if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
@@ -5471,9 +5482,12 @@  void intel_edp_drrs_disable(struct intel_dp *intel_dp)
 			fixed_mode->vrefresh);
 
 	dev_priv->drrs.dp = NULL;
+	if (sysfs_set)
+		dev_priv->drrs.sysfs_set = sysfs_set;
 	mutex_unlock(&dev_priv->drrs.mutex);
 
 	cancel_delayed_work_sync(&dev_priv->drrs.work);
+	return 0;
 }
 
 static void intel_edp_drrs_downclock_work(struct work_struct *work)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d280847..eda84ae 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1299,8 +1299,8 @@  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
 uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
 void intel_plane_destroy(struct drm_plane *plane);
-void intel_edp_drrs_enable(struct intel_dp *intel_dp);
-void intel_edp_drrs_disable(struct intel_dp *intel_dp);
+int intel_edp_drrs_enable(struct intel_dp *intel_dp, bool sysfs_set);
+int intel_edp_drrs_disable(struct intel_dp *intel_dp, bool sysfs_set);
 void intel_edp_drrs_invalidate(struct drm_device *dev,
 		unsigned frontbuffer_bits);
 void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);