drm/i915: Match all PSR mode entry conditions before enabling it.

v2: Prefer seq_puts to seq_printf by Paulo Zanoni.
v3: small changes like avoiding calling dp_to_dig_port twice as noticed by
    Paulo Zanoni.
v4: Avoiding reading non-existent registers - noticed by Paulo
    on first psr debugfs patch.
v5: Accepting more suggestions from Paulo:
    * check sw interlace flag instead of i915_read
    * introduce PSR_S3D_ENABLED to avoid forgeting it whenever added.

Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Shobhit Kumar <shobhit.kumar@intel.com>
[danvet: Fix up debugfs output (spotted by Paulo) and rip out the
power well check since we really can't do that in a race-free manner,
so it's bogus.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Rodrigo Vivi 2013-07-11 18:45:00 -03:00 committed by Daniel Vetter
parent e91fd8c6de
commit 3f51e4713f
4 changed files with 123 additions and 6 deletions

View File

@ -1550,17 +1550,49 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 psrctl, psrstat, psrperf;
u32 psrstat, psrperf;
if (!IS_HASWELL(dev)) {
seq_puts(m, "PSR not supported on this platform\n");
} else if (IS_HASWELL(dev) && I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE) {
seq_puts(m, "PSR enabled\n");
} else {
seq_puts(m, "PSR disabled: ");
switch (dev_priv->no_psr_reason) {
case PSR_NO_SOURCE:
seq_puts(m, "not supported on this platform");
break;
case PSR_NO_SINK:
seq_puts(m, "not supported by panel");
break;
case PSR_CRTC_NOT_ACTIVE:
seq_puts(m, "crtc not active");
break;
case PSR_PWR_WELL_ENABLED:
seq_puts(m, "power well enabled");
break;
case PSR_NOT_TILED:
seq_puts(m, "not tiled");
break;
case PSR_SPRITE_ENABLED:
seq_puts(m, "sprite enabled");
break;
case PSR_S3D_ENABLED:
seq_puts(m, "stereo 3d enabled");
break;
case PSR_INTERLACED_ENABLED:
seq_puts(m, "interlaced enabled");
break;
case PSR_HSW_NOT_DDIA:
seq_puts(m, "HSW ties PSR to DDI A (eDP)");
break;
default:
seq_puts(m, "unknown reason");
}
seq_puts(m, "\n");
return 0;
}
psrctl = I915_READ(EDP_PSR_CTL);
seq_printf(m, "PSR Enabled: %s\n",
yesno(psrctl & EDP_PSR_ENABLE));
psrstat = I915_READ(EDP_PSR_STATUS_CTL);
seq_puts(m, "PSR Current State: ");

View File

@ -593,6 +593,17 @@ struct i915_fbc {
} no_fbc_reason;
};
enum no_psr_reason {
PSR_NO_SOURCE, /* Not supported on platform */
PSR_NO_SINK, /* Not supported by panel */
PSR_CRTC_NOT_ACTIVE,
PSR_PWR_WELL_ENABLED,
PSR_NOT_TILED,
PSR_SPRITE_ENABLED,
PSR_S3D_ENABLED,
PSR_INTERLACED_ENABLED,
PSR_HSW_NOT_DDIA,
};
enum intel_pch {
PCH_NONE = 0, /* No PCH present */
@ -1173,6 +1184,8 @@ typedef struct drm_i915_private {
/* Haswell power well */
struct i915_power_well power_well;
enum no_psr_reason no_psr_reason;
struct i915_gpu_error gpu_error;
struct drm_i915_gem_object *vlv_pctx;

View File

@ -4150,6 +4150,13 @@
#define HSW_TVIDEO_DIP_VSC_DATA(trans) \
_TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
#define HSW_STEREO_3D_CTL_A 0x70020
#define S3D_ENABLE (1<<31)
#define HSW_STEREO_3D_CTL_B 0x71020
#define HSW_STEREO_3D_CTL(trans) \
_TRANSCODER(trans, HSW_STEREO_3D_CTL_A, HSW_STEREO_3D_CTL_A)
#define _PCH_TRANS_HTOTAL_B 0xe1000
#define _PCH_TRANS_HBLANK_B 0xe1004
#define _PCH_TRANS_HSYNC_B 0xe1008

View File

@ -1492,11 +1492,76 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
EDP_PSR_ENABLE);
}
static bool intel_edp_psr_match_conditions(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 drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
if (!IS_HASWELL(dev)) {
DRM_DEBUG_KMS("PSR not supported on this platform\n");
dev_priv->no_psr_reason = PSR_NO_SOURCE;
return false;
}
if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
(dig_port->port != PORT_A)) {
DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
dev_priv->no_psr_reason = PSR_HSW_NOT_DDIA;
return false;
}
if (!is_edp_psr(intel_dp)) {
DRM_DEBUG_KMS("PSR not supported by this panel\n");
dev_priv->no_psr_reason = PSR_NO_SINK;
return false;
}
if (!intel_crtc->active || !crtc->fb || !crtc->mode.clock) {
DRM_DEBUG_KMS("crtc not active for PSR\n");
dev_priv->no_psr_reason = PSR_CRTC_NOT_ACTIVE;
return false;
}
if (obj->tiling_mode != I915_TILING_X ||
obj->fence_reg == I915_FENCE_REG_NONE) {
DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
dev_priv->no_psr_reason = PSR_NOT_TILED;
return false;
}
if (I915_READ(SPRCTL(intel_crtc->pipe)) & SPRITE_ENABLE) {
DRM_DEBUG_KMS("PSR condition failed: Sprite is Enabled\n");
dev_priv->no_psr_reason = PSR_SPRITE_ENABLED;
return false;
}
if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) &
S3D_ENABLE) {
DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
dev_priv->no_psr_reason = PSR_S3D_ENABLED;
return false;
}
if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
dev_priv->no_psr_reason = PSR_INTERLACED_ENABLED;
return false;
}
return true;
}
void intel_edp_psr_enable(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(dev))
if (!intel_edp_psr_match_conditions(intel_dp) ||
intel_edp_is_psr_enabled(dev))
return;
/* Setup PSR once */