[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