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@xxxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx