summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h3
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c6
-rw-r--r--drivers/gpu/drm/i915/intel_display.c8
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c91
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
5 files changed, 101 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 506386e91ad2..faef035f5a49 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -637,6 +637,9 @@ struct i915_psr {
bool sink_support;
bool source_ok;
bool setup_done;
+ bool enabled;
+ bool active;
+ struct delayed_work work;
};
enum intel_pch {
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index c313cb2b641b..1794a041c13c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1395,6 +1395,8 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
goto unlock;
}
+ intel_edp_psr_exit(dev, true);
+
/* Try to flush the object off the GPU without holding the lock.
* We will repeat the flush holding the lock in the normal manner
* to catch cases where we are gazumped.
@@ -1440,6 +1442,8 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
+ intel_edp_psr_exit(dev, true);
+
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (&obj->base == NULL) {
ret = -ENOENT;
@@ -4236,6 +4240,8 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
+ intel_edp_psr_exit(dev, true);
+
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (&obj->base == NULL) {
ret = -ENOENT;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b9251c863cd2..2fdbedfc970e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8818,12 +8818,15 @@ out:
intel_runtime_pm_put(dev_priv);
}
+
void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
struct intel_engine_cs *ring)
{
struct drm_device *dev = obj->base.dev;
struct drm_crtc *crtc;
+ intel_edp_psr_exit(dev, true);
+
if (!i915.powersave)
return;
@@ -9290,6 +9293,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
if (work == NULL)
return -ENOMEM;
+ /* Exit PSR early in page flip */
+ intel_edp_psr_exit(dev, true);
+
work->event = event;
work->crtc = crtc;
work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
@@ -11581,6 +11587,8 @@ static void intel_setup_outputs(struct drm_device *dev)
if (SUPPORTS_TV(dev))
intel_tv_init(dev);
+ intel_edp_psr_init(dev);
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
encoder->base.possible_crtcs = encoder->crtc_mask;
encoder->base.possible_clones =
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index fc3486aaa286..b6b26407f11b 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1818,10 +1818,11 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
- if (!intel_edp_psr_match_conditions(intel_dp) ||
- intel_edp_is_psr_enabled(dev))
+ if (intel_edp_is_psr_enabled(dev))
return;
/* Enable PSR on the panel */
@@ -1829,6 +1830,9 @@ static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
/* Enable PSR on the host */
intel_edp_psr_enable_source(intel_dp);
+
+ dev_priv->psr.enabled = true;
+ dev_priv->psr.active = true;
}
void intel_edp_psr_enable(struct intel_dp *intel_dp)
@@ -1848,8 +1852,7 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp)
/* Setup PSR once */
intel_edp_psr_setup(intel_dp);
- if (intel_edp_psr_match_conditions(intel_dp) &&
- !intel_edp_is_psr_enabled(dev))
+ if (intel_edp_psr_match_conditions(intel_dp))
intel_edp_psr_do_enable(intel_dp);
}
@@ -1858,7 +1861,7 @@ void intel_edp_psr_disable(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
- if (!intel_edp_is_psr_enabled(dev))
+ if (!dev_priv->psr.enabled)
return;
I915_WRITE(EDP_PSR_CTL(dev),
@@ -1868,13 +1871,13 @@ void intel_edp_psr_disable(struct intel_dp *intel_dp)
if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
DRM_ERROR("Timed out waiting for PSR Idle State\n");
+
+ dev_priv->psr.enabled = false;
}
void intel_edp_psr_update(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *encoder;
- struct intel_dp *intel_dp = NULL;
if (!HAS_PSR(dev))
return;
@@ -1882,6 +1885,17 @@ void intel_edp_psr_update(struct drm_device *dev)
if (!dev_priv->psr.setup_done)
return;
+ intel_edp_psr_exit(dev, true);
+}
+
+void intel_edp_psr_work(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(work, typeof(*dev_priv), psr.work.work);
+ struct drm_device *dev = dev_priv->dev;
+ struct intel_encoder *encoder;
+ struct intel_dp *intel_dp = NULL;
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
if (encoder->type == INTEL_OUTPUT_EDP) {
intel_dp = enc_to_intel_dp(&encoder->base);
@@ -1889,9 +1903,66 @@ void intel_edp_psr_update(struct drm_device *dev)
if (!intel_edp_psr_match_conditions(intel_dp))
intel_edp_psr_disable(intel_dp);
else
- if (!intel_edp_is_psr_enabled(dev))
- intel_edp_psr_do_enable(intel_dp);
+ intel_edp_psr_do_enable(intel_dp);
+ }
+}
+
+void intel_edp_psr_inactivate(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_connector *connector;
+ struct intel_encoder *encoder;
+ struct intel_crtc *intel_crtc;
+ struct intel_dp *intel_dp = NULL;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list,
+ base.head) {
+
+ if (connector->base.dpms != DRM_MODE_DPMS_ON)
+ continue;
+
+ encoder = to_intel_encoder(connector->base.encoder);
+ if (encoder->type == INTEL_OUTPUT_EDP) {
+
+ intel_dp = enc_to_intel_dp(&encoder->base);
+ intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+ dev_priv->psr.active = false;
+
+ I915_WRITE(EDP_PSR_CTL(dev), I915_READ(EDP_PSR_CTL(dev))
+ & ~EDP_PSR_ENABLE);
}
+ }
+}
+
+void intel_edp_psr_exit(struct drm_device *dev, bool schedule_back)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!HAS_PSR(dev))
+ return;
+
+ if (!dev_priv->psr.setup_done)
+ return;
+
+ cancel_delayed_work_sync(&dev_priv->psr.work);
+
+ if (dev_priv->psr.active)
+ intel_edp_psr_inactivate(dev);
+
+ if (schedule_back)
+ schedule_delayed_work(&dev_priv->psr.work,
+ msecs_to_jiffies(100));
+}
+
+void intel_edp_psr_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!HAS_PSR(dev))
+ return;
+
+ INIT_DELAYED_WORK(&dev_priv->psr.work, intel_edp_psr_work);
}
static void intel_disable_dp(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 57a36aba2b2f..9aa95f01b160 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -830,6 +830,9 @@ void intel_edp_psr_enable(struct intel_dp *intel_dp);
void intel_edp_psr_disable(struct intel_dp *intel_dp);
void intel_edp_psr_update(struct drm_device *dev);
void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
+void intel_edp_psr_exit(struct drm_device *dev, bool schedule_back);
+void intel_edp_psr_init(struct drm_device *dev);
+
/* intel_dsi.c */
void intel_dsi_init(struct drm_device *dev);