[Intel-gfx] [PATCH 14/31] drm/i915: Create intel_drrs.c
Rodrigo Vivi
rodrigo.vivi at intel.com
Thu Nov 5 10:50:06 PST 2015
No functional change. Jusr organizing display pm features
in a standardized and uniform way.
This first step allow us to fix drrs initialization that
is broken with fastboot by default.
Signed-off-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
---
drivers/gpu/drm/i915/Makefile | 3 +-
drivers/gpu/drm/i915/intel_ddi.c | 4 +-
drivers/gpu/drm/i915/intel_dp.c | 386 +----------------------------
drivers/gpu/drm/i915/intel_drrs.c | 408 +++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 15 +-
drivers/gpu/drm/i915/intel_frontbuffer.c | 4 +-
6 files changed, 426 insertions(+), 394 deletions(-)
create mode 100644 drivers/gpu/drm/i915/intel_drrs.c
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 5c92a47..da3d2cc 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -51,7 +51,8 @@ i915-y += intel_renderstate_gen6.o \
intel_renderstate_gen9.o
# display pm
-i915-y += intel_fbc.o \
+i915-y += intel_drrs.o \
+ intel_fbc.o \
intel_ips.o \
intel_psr.o
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 36db970..972acef 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2404,7 +2404,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
intel_dp_stop_link_train(intel_dp);
intel_edp_backlight_on(intel_dp);
- intel_edp_drrs_enable(intel_dp);
+ intel_drrs_enable(intel_dp);
}
if (intel_crtc->config->has_audio) {
@@ -2430,7 +2430,7 @@ 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);
+ intel_drrs_disable(intel_dp);
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 f0ee497..a421c17 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -5212,388 +5212,6 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
I915_READ(pp_div_reg));
}
-/**
- * intel_dp_set_drrs_state - program registers for RR switch to take effect
- * @dev: DRM device
- * @refresh_rate: RR to be programmed
- *
- * This function gets called when refresh rate (RR) has to be changed from
- * one frequency to another. Switches can be between high and low RR
- * supported by the panel or to any other RR based on media playback (in
- * this case, RR value needs to be passed from user space).
- *
- * The caller of this function needs to take a lock on dev_priv->drrs.
- */
-static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *encoder;
- struct intel_digital_port *dig_port = NULL;
- struct intel_dp *intel_dp = dev_priv->drrs.dp;
- struct intel_crtc_state *config = NULL;
- struct intel_crtc *intel_crtc = NULL;
- enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
-
- if (refresh_rate <= 0) {
- DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
- return;
- }
-
- if (intel_dp == NULL) {
- DRM_DEBUG_KMS("DRRS not supported.\n");
- return;
- }
-
- dig_port = dp_to_dig_port(intel_dp);
- encoder = &dig_port->base;
- intel_crtc = to_intel_crtc(encoder->base.crtc);
-
- if (!intel_crtc) {
- DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
- return;
- }
-
- config = intel_crtc->config;
-
- if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
- DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
- return;
- }
-
- if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
- refresh_rate)
- index = DRRS_LOW_RR;
-
- if (index == dev_priv->drrs.refresh_rate_type) {
- DRM_DEBUG_KMS(
- "DRRS requested for previously set RR...ignoring\n");
- return;
- }
-
- if (!intel_crtc->active) {
- DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
- return;
- }
-
- if (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)) {
- switch (index) {
- case DRRS_HIGH_RR:
- intel_dp_set_m_n(intel_crtc, M1_N1);
- break;
- case DRRS_LOW_RR:
- intel_dp_set_m_n(intel_crtc, M2_N2);
- break;
- case DRRS_MAX_RR:
- default:
- DRM_ERROR("Unsupported refreshrate type\n");
- }
- } else if (INTEL_INFO(dev)->gen > 6) {
- u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder);
- u32 val;
-
- val = I915_READ(reg);
- if (index > DRRS_HIGH_RR) {
- if (IS_VALLEYVIEW(dev))
- val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
- else
- val |= PIPECONF_EDP_RR_MODE_SWITCH;
- } else {
- if (IS_VALLEYVIEW(dev))
- val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
- else
- val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
- }
- I915_WRITE(reg, val);
- }
-
- dev_priv->drrs.refresh_rate_type = index;
-
- DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
-}
-
-/**
- * intel_edp_drrs_enable - init drrs struct if supported
- * @intel_dp: DP struct
- *
- * Initializes frontbuffer_bits and drrs.dp
- */
-void intel_edp_drrs_enable(struct intel_dp *intel_dp)
-{
- 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);
-
- if (!intel_crtc->config->has_drrs) {
- DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
- return;
- }
-
- if (intel_crtc->config->psr_ready && i915.enable_psr) {
- DRM_DEBUG_KMS("DRRS: PSR will be enabled on this crtc\n");
- return;
- }
-
- mutex_lock(&dev_priv->drrs.mutex);
- if (WARN_ON(dev_priv->drrs.dp)) {
- DRM_ERROR("DRRS already enabled\n");
- goto unlock;
- }
-
- dev_priv->drrs.busy_frontbuffer_bits = 0;
-
- dev_priv->drrs.dp = intel_dp;
-
-unlock:
- mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_disable - Disable DRRS
- * @intel_dp: DP struct
- *
- */
-void intel_edp_drrs_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;
- 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);
-
- if (!intel_crtc->config->has_drrs)
- return;
-
- mutex_lock(&dev_priv->drrs.mutex);
- if (!dev_priv->drrs.dp) {
- mutex_unlock(&dev_priv->drrs.mutex);
- return;
- }
-
- if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
- intel_dp_set_drrs_state(dev_priv->dev,
- intel_dp->attached_connector->panel.
- fixed_mode->vrefresh);
-
- dev_priv->drrs.dp = NULL;
- mutex_unlock(&dev_priv->drrs.mutex);
-
- cancel_delayed_work_sync(&dev_priv->drrs.work);
-}
-
-static void intel_edp_drrs_downclock_work(struct work_struct *work)
-{
- struct drm_i915_private *dev_priv =
- container_of(work, typeof(*dev_priv), drrs.work.work);
- struct intel_dp *intel_dp;
-
- mutex_lock(&dev_priv->drrs.mutex);
-
- intel_dp = dev_priv->drrs.dp;
-
- if (!intel_dp)
- goto unlock;
-
- /*
- * The delayed work can race with an invalidate hence we need to
- * recheck.
- */
-
- if (dev_priv->drrs.busy_frontbuffer_bits)
- goto unlock;
-
- if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
- intel_dp_set_drrs_state(dev_priv->dev,
- intel_dp->attached_connector->panel.
- downclock_mode->vrefresh);
-
-unlock:
- mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_invalidate - Disable Idleness DRRS
- * @dev: DRM device
- * @frontbuffer_bits: frontbuffer plane tracking bits
- *
- * This function gets called everytime rendering on the given planes start.
- * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
- *
- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
- */
-void intel_edp_drrs_invalidate(struct drm_device *dev,
- unsigned frontbuffer_bits)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- enum pipe pipe;
-
- if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
- return;
-
- cancel_delayed_work(&dev_priv->drrs.work);
-
- mutex_lock(&dev_priv->drrs.mutex);
- if (!dev_priv->drrs.dp) {
- mutex_unlock(&dev_priv->drrs.mutex);
- return;
- }
-
- crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
- pipe = to_intel_crtc(crtc)->pipe;
-
- frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
- dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
-
- /* invalidate means busy screen hence upclock */
- if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
- intel_dp_set_drrs_state(dev_priv->dev,
- dev_priv->drrs.dp->attached_connector->panel.
- fixed_mode->vrefresh);
-
- mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * intel_edp_drrs_flush - Restart Idleness DRRS
- * @dev: DRM device
- * @frontbuffer_bits: frontbuffer plane tracking bits
- *
- * This function gets called every time rendering on the given planes has
- * completed or flip on a crtc is completed. So DRRS should be upclocked
- * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
- * if no other planes are dirty.
- *
- * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
- */
-void intel_edp_drrs_flush(struct drm_device *dev,
- unsigned frontbuffer_bits)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- enum pipe pipe;
-
- if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
- return;
-
- cancel_delayed_work(&dev_priv->drrs.work);
-
- mutex_lock(&dev_priv->drrs.mutex);
- if (!dev_priv->drrs.dp) {
- mutex_unlock(&dev_priv->drrs.mutex);
- return;
- }
-
- crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
- pipe = to_intel_crtc(crtc)->pipe;
-
- frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
- dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
-
- /* flush means busy screen hence upclock */
- if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
- intel_dp_set_drrs_state(dev_priv->dev,
- dev_priv->drrs.dp->attached_connector->panel.
- fixed_mode->vrefresh);
-
- /*
- * flush also means no more activity hence schedule downclock, if all
- * other fbs are quiescent too
- */
- if (!dev_priv->drrs.busy_frontbuffer_bits)
- schedule_delayed_work(&dev_priv->drrs.work,
- msecs_to_jiffies(1000));
- mutex_unlock(&dev_priv->drrs.mutex);
-}
-
-/**
- * DOC: Display Refresh Rate Switching (DRRS)
- *
- * Display Refresh Rate Switching (DRRS) is a power conservation feature
- * which enables swtching between low and high refresh rates,
- * dynamically, based on the usage scenario. This feature is applicable
- * for internal panels.
- *
- * Indication that the panel supports DRRS is given by the panel EDID, which
- * would list multiple refresh rates for one resolution.
- *
- * DRRS is of 2 types - static and seamless.
- * Static DRRS involves changing refresh rate (RR) by doing a full modeset
- * (may appear as a blink on screen) and is used in dock-undock scenario.
- * Seamless DRRS involves changing RR without any visual effect to the user
- * and can be used during normal system usage. This is done by programming
- * certain registers.
- *
- * Support for static/seamless DRRS may be indicated in the VBT based on
- * inputs from the panel spec.
- *
- * DRRS saves power by switching to low RR based on usage scenarios.
- *
- * eDP DRRS:-
- * The implementation is based on frontbuffer tracking implementation.
- * When there is a disturbance on the screen triggered by user activity or a
- * periodic system activity, DRRS is disabled (RR is changed to high RR).
- * When there is no movement on screen, after a timeout of 1 second, a switch
- * to low RR is made.
- * For integration with frontbuffer tracking code,
- * intel_edp_drrs_invalidate() and intel_edp_drrs_flush() are called.
- *
- * DRRS can be further extended to support other internal panels and also
- * the scenario of video playback wherein RR is set based on the rate
- * requested by userspace.
- */
-
-/**
- * intel_dp_drrs_init - Init basic DRRS work and mutex.
- * @intel_connector: eDP connector
- * @fixed_mode: preferred mode of panel
- *
- * This function is called only once at driver load to initialize basic
- * DRRS stuff.
- *
- * Returns:
- * Downclock mode if panel supports it, else return NULL.
- * DRRS support is determined by the presence of downclock mode (apart
- * from VBT setting).
- */
-static struct drm_display_mode *
-intel_dp_drrs_init(struct intel_connector *intel_connector,
- struct drm_display_mode *fixed_mode)
-{
- struct drm_connector *connector = &intel_connector->base;
- struct drm_device *dev = connector->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *downclock_mode = NULL;
-
- INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
- mutex_init(&dev_priv->drrs.mutex);
-
- if (INTEL_INFO(dev)->gen <= 6) {
- DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n");
- return NULL;
- }
-
- if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
- DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
- return NULL;
- }
-
- downclock_mode = intel_find_panel_downclock
- (dev, fixed_mode, connector);
-
- if (!downclock_mode) {
- DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
- return NULL;
- }
-
- dev_priv->drrs.type = dev_priv->vbt.drrs_type;
-
- dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
- DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
- return downclock_mode;
-}
-
static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct intel_connector *intel_connector)
{
@@ -5655,8 +5273,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
list_for_each_entry(scan, &connector->probed_modes, head) {
if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
fixed_mode = drm_mode_duplicate(dev, scan);
- downclock_mode = intel_dp_drrs_init(
- intel_connector, fixed_mode);
+ downclock_mode = intel_drrs_init(intel_connector,
+ fixed_mode);
break;
}
}
diff --git a/drivers/gpu/drm/i915/intel_drrs.c b/drivers/gpu/drm/i915/intel_drrs.c
new file mode 100644
index 0000000..dce16ea
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_drrs.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "intel_drv.h"
+#include "i915_drv.h"
+
+/**
+ * DOC: Display Refresh Rate Switching (DRRS)
+ *
+ * Display Refresh Rate Switching (DRRS) is a power conservation feature
+ * which enables swtching between low and high refresh rates,
+ * dynamically, based on the usage scenario. This feature is applicable
+ * for internal panels.
+ *
+ * Indication that the panel supports DRRS is given by the panel EDID, which
+ * would list multiple refresh rates for one resolution.
+ *
+ * DRRS is of 2 types - static and seamless.
+ * Static DRRS involves changing refresh rate (RR) by doing a full modeset
+ * (may appear as a blink on screen) and is used in dock-undock scenario.
+ * Seamless DRRS involves changing RR without any visual effect to the user
+ * and can be used during normal system usage. This is done by programming
+ * certain registers.
+ *
+ * Support for static/seamless DRRS may be indicated in the VBT based on
+ * inputs from the panel spec.
+ *
+ * DRRS saves power by switching to low RR based on usage scenarios.
+ *
+ * eDP DRRS:-
+ * The implementation is based on frontbuffer tracking implementation.
+ * When there is a disturbance on the screen triggered by user activity or a
+ * periodic system activity, DRRS is disabled (RR is changed to high RR).
+ * When there is no movement on screen, after a timeout of 1 second, a switch
+ * to low RR is made.
+ * For integration with frontbuffer tracking code,
+ * intel_edp_drrs_invalidate() and intel_edp_drrs_flush() are called.
+ *
+ * DRRS can be further extended to support other internal panels and also
+ * the scenario of video playback wherein RR is set based on the rate
+ * requested by userspace.
+ */
+
+/**
+ * intel_drrs_set_state - program registers for RR switch to take effect
+ * @dev: DRM device
+ * @refresh_rate: RR to be programmed
+ *
+ * This function gets called when refresh rate (RR) has to be changed from
+ * one frequency to another. Switches can be between high and low RR
+ * supported by the panel or to any other RR based on media playback (in
+ * this case, RR value needs to be passed from user space).
+ *
+ * The caller of this function needs to take a lock on dev_priv->drrs.
+ */
+static void intel_drrs_set_state(struct drm_device *dev, int refresh_rate)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_encoder *encoder;
+ struct intel_digital_port *dig_port = NULL;
+ struct intel_dp *intel_dp = dev_priv->drrs.dp;
+ struct intel_crtc_state *config = NULL;
+ struct intel_crtc *intel_crtc = NULL;
+ enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
+
+ if (refresh_rate <= 0) {
+ DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
+ return;
+ }
+
+ if (intel_dp == NULL) {
+ DRM_DEBUG_KMS("DRRS not supported.\n");
+ return;
+ }
+
+ dig_port = dp_to_dig_port(intel_dp);
+ encoder = &dig_port->base;
+ intel_crtc = to_intel_crtc(encoder->base.crtc);
+
+ if (!intel_crtc) {
+ DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n");
+ return;
+ }
+
+ config = intel_crtc->config;
+
+ if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
+ DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
+ return;
+ }
+
+ if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
+ refresh_rate)
+ index = DRRS_LOW_RR;
+
+ if (index == dev_priv->drrs.refresh_rate_type) {
+ DRM_DEBUG_KMS(
+ "DRRS requested for previously set RR...ignoring\n");
+ return;
+ }
+
+ if (!intel_crtc->active) {
+ DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
+ return;
+ }
+
+ if (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)) {
+ switch (index) {
+ case DRRS_HIGH_RR:
+ intel_dp_set_m_n(intel_crtc, M1_N1);
+ break;
+ case DRRS_LOW_RR:
+ intel_dp_set_m_n(intel_crtc, M2_N2);
+ break;
+ case DRRS_MAX_RR:
+ default:
+ DRM_ERROR("Unsupported refreshrate type\n");
+ }
+ } else if (INTEL_INFO(dev)->gen > 6) {
+ u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder);
+ u32 val;
+
+ val = I915_READ(reg);
+ if (index > DRRS_HIGH_RR) {
+ if (IS_VALLEYVIEW(dev))
+ val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+ else
+ val |= PIPECONF_EDP_RR_MODE_SWITCH;
+ } else {
+ if (IS_VALLEYVIEW(dev))
+ val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
+ else
+ val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+ }
+ I915_WRITE(reg, val);
+ }
+
+ dev_priv->drrs.refresh_rate_type = index;
+
+ DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+}
+
+/**
+ * intel_drrs_enable - init drrs struct if supported
+ * @intel_dp: DP struct
+ *
+ * Initializes frontbuffer_bits and drrs.dp
+ */
+void intel_drrs_enable(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 drm_crtc *crtc = dig_port->base.base.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ if (!intel_crtc->config->has_drrs) {
+ DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
+ return;
+ }
+
+ if (intel_crtc->config->psr_ready && i915.enable_psr) {
+ DRM_DEBUG_KMS("DRRS: PSR will be enabled on this crtc\n");
+ return;
+ }
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ if (WARN_ON(dev_priv->drrs.dp)) {
+ DRM_ERROR("DRRS already enabled\n");
+ goto unlock;
+ }
+
+ dev_priv->drrs.busy_frontbuffer_bits = 0;
+
+ dev_priv->drrs.dp = intel_dp;
+
+unlock:
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_edp_drrs_disable - Disable DRRS
+ * @intel_dp: DP struct
+ *
+ */
+void intel_drrs_disable(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 drm_crtc *crtc = dig_port->base.base.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_panel *panel = &intel_dp->attached_connector->panel;
+
+ if (!intel_crtc->config->has_drrs)
+ return;
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ if (!dev_priv->drrs.dp) {
+ mutex_unlock(&dev_priv->drrs.mutex);
+ return;
+ }
+
+ if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+ intel_drrs_set_state(dev_priv->dev,
+ panel->fixed_mode->vrefresh);
+
+ dev_priv->drrs.dp = NULL;
+ mutex_unlock(&dev_priv->drrs.mutex);
+
+ cancel_delayed_work_sync(&dev_priv->drrs.work);
+}
+
+static void intel_drrs_downclock_work(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(work, typeof(*dev_priv), drrs.work.work);
+ struct intel_dp *intel_dp;
+ struct intel_panel *panel;
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ intel_dp = dev_priv->drrs.dp;
+
+ if (!intel_dp)
+ goto unlock;
+
+ panel = &intel_dp->attached_connector->panel;
+ /*
+ * The delayed work can race with an invalidate hence we need to
+ * recheck.
+ */
+
+ if (dev_priv->drrs.busy_frontbuffer_bits)
+ goto unlock;
+
+ if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
+ intel_drrs_set_state(dev_priv->dev,
+ panel->fixed_mode->vrefresh);
+
+unlock:
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_drrs_invalidate - Disable Idleness DRRS
+ * @dev: DRM device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * This function gets called everytime rendering on the given planes start.
+ * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR).
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_drrs_invalidate(struct drm_device *dev,
+ unsigned frontbuffer_bits)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ struct intel_panel *panel;
+ enum pipe pipe;
+
+ if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
+ return;
+
+ cancel_delayed_work(&dev_priv->drrs.work);
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ if (!dev_priv->drrs.dp) {
+ mutex_unlock(&dev_priv->drrs.mutex);
+ return;
+ }
+
+ panel = &dev_priv->drrs.dp->attached_connector->panel;
+ crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+ pipe = to_intel_crtc(crtc)->pipe;
+
+ frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+ dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
+
+ /* invalidate means busy screen hence upclock */
+ if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+ intel_drrs_set_state(dev_priv->dev,
+ panel->fixed_mode->vrefresh);
+
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_drrs_flush - Restart Idleness DRRS
+ * @dev: DRM device
+ * @frontbuffer_bits: frontbuffer plane tracking bits
+ *
+ * This function gets called every time rendering on the given planes has
+ * completed or flip on a crtc is completed. So DRRS should be upclocked
+ * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again,
+ * if no other planes are dirty.
+ *
+ * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits.
+ */
+void intel_drrs_flush(struct drm_device *dev,
+ unsigned frontbuffer_bits)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ struct intel_panel *panel;
+ enum pipe pipe;
+
+ if (dev_priv->drrs.type == DRRS_NOT_SUPPORTED)
+ return;
+
+ cancel_delayed_work(&dev_priv->drrs.work);
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ if (!dev_priv->drrs.dp) {
+ mutex_unlock(&dev_priv->drrs.mutex);
+ return;
+ }
+ panel = &dev_priv->drrs.dp->attached_connector->panel;
+ crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+ pipe = to_intel_crtc(crtc)->pipe;
+
+ frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+ dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
+
+ /* flush means busy screen hence upclock */
+ if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+ intel_drrs_set_state(dev_priv->dev,
+ panel->fixed_mode->vrefresh);
+
+ /*
+ * flush also means no more activity hence schedule downclock, if all
+ * other fbs are quiescent too
+ */
+ if (!dev_priv->drrs.busy_frontbuffer_bits)
+ schedule_delayed_work(&dev_priv->drrs.work,
+ msecs_to_jiffies(1000));
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+/**
+ * intel_drrs_init - Init basic DRRS work and mutex.
+ * @intel_connector: eDP connector
+ * @fixed_mode: preferred mode of panel
+ *
+ * This function is called only once at driver load to initialize basic
+ * DRRS stuff.
+ *
+ * Returns:
+ * Downclock mode if panel supports it, else return NULL.
+ * DRRS support is determined by the presence of downclock mode (apart
+ * from VBT setting).
+ */
+struct drm_display_mode *
+intel_drrs_init(struct intel_connector *intel_connector,
+ struct drm_display_mode *fixed_mode)
+{
+ struct drm_connector *connector = &intel_connector->base;
+ struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_display_mode *downclock_mode = NULL;
+
+ INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_drrs_downclock_work);
+ mutex_init(&dev_priv->drrs.mutex);
+
+ if (INTEL_INFO(dev)->gen <= 6) {
+ DRM_DEBUG_KMS("DRRS supported for Gen7 and above\n");
+ return NULL;
+ }
+
+ if (dev_priv->vbt.drrs_type != SEAMLESS_DRRS_SUPPORT) {
+ DRM_DEBUG_KMS("VBT doesn't support DRRS\n");
+ return NULL;
+ }
+
+ downclock_mode = intel_find_panel_downclock
+ (dev, fixed_mode, connector);
+
+ if (!downclock_mode) {
+ DRM_DEBUG_KMS("Downclock mode is not found. DRRS not supported\n");
+ return NULL;
+ }
+
+ dev_priv->drrs.type = dev_priv->vbt.drrs_type;
+
+ dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
+ DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
+ return downclock_mode;
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d599d54..73406c3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1209,6 +1209,16 @@ u32 skl_plane_ctl_format(uint32_t pixel_format);
u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
u32 skl_plane_ctl_rotation(unsigned int rotation);
+/* intel_drrs.c */
+void intel_drrs_enable(struct intel_dp *intel_dp);
+void intel_drrs_disable(struct intel_dp *intel_dp);
+void intel_drrs_invalidate(struct drm_device *dev,
+ unsigned frontbuffer_bits);
+void intel_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
+struct drm_display_mode *
+intel_drrs_init(struct intel_connector *intel_connector,
+ struct drm_display_mode *fixed_mode);
+
/* intel_ips.c */
bool intel_ips_ready(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state);
@@ -1256,11 +1266,6 @@ 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);
-void intel_edp_drrs_invalidate(struct drm_device *dev,
- unsigned frontbuffer_bits);
-void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
struct intel_digital_port *port);
void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c
index ac85357..f76952a 100644
--- a/drivers/gpu/drm/i915/intel_frontbuffer.c
+++ b/drivers/gpu/drm/i915/intel_frontbuffer.c
@@ -97,7 +97,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
}
intel_psr_invalidate(dev, obj->frontbuffer_bits);
- intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits);
+ intel_drrs_invalidate(dev, obj->frontbuffer_bits);
intel_fbc_invalidate(dev_priv, obj->frontbuffer_bits, origin);
}
@@ -127,7 +127,7 @@ static void intel_frontbuffer_flush(struct drm_device *dev,
if (!frontbuffer_bits)
return;
- intel_edp_drrs_flush(dev, frontbuffer_bits);
+ intel_drrs_flush(dev, frontbuffer_bits);
intel_psr_flush(dev, frontbuffer_bits, origin);
intel_fbc_flush(dev_priv, frontbuffer_bits, origin);
}
--
2.4.3
More information about the Intel-gfx
mailing list