drm/i915/psr: fix blank screen issue for psr2
Psr1 and psr2 are mutually exclusive,ie when psr2 is enabled, psr1 should be disabled.When psr2 is exited , bit 31 of reg PSR2_CTL must be set to 0 but currently bit 31 of SRD_CTL (psr1 control register)is set to 0. Also ,PSR2_IDLE state is looked up from SRD_STATUS(psr1 register) instead of PSR2_STATUS register, which has wrong data, resulting in blankscreen. hsw_enable_source is split into hsw_enable_source_psr1 and hsw_enable_source_psr2 for easier code review and maintenance, as suggested by rodrigo and jim. v2: (Rodrigo) - Rename hsw_enable_source_psr* to intel_enable_source_psr* v3: (Rodrigo) - In hsw_psr_disable , 1) for psr active case, handle psr2 followed by psr1. 2) psr inactive case, handle psr2 followed by psr1 v4:(Rodrigo) - move psr2 restriction(32X20) to match_conditions function returning false and fully blocking PSR to a new patch before this one. v5: in source_psr2, removed val = EDP_PSR_ENABLE Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Jim Bride <jim.bride@linux.intel.com> Signed-off-by: Vathsala Nagaraju <vathsala.nagaraju@intel.com> Signed-off-by: Patil Deepti <deepti.patil@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1484244059-9201-1-git-send-email-vathsala.nagaraju@intel.com
This commit is contained in:
parent
a4dbf7cf17
commit
3fcb0ca1d8
@ -3615,6 +3615,9 @@ enum {
|
|||||||
#define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf<<4)
|
#define EDP_PSR2_FRAME_BEFORE_SU_MASK (0xf<<4)
|
||||||
#define EDP_PSR2_IDLE_MASK 0xf
|
#define EDP_PSR2_IDLE_MASK 0xf
|
||||||
|
|
||||||
|
#define EDP_PSR2_STATUS_CTL _MMIO(0x6f940)
|
||||||
|
#define EDP_PSR2_STATUS_STATE_MASK (0xf<<28)
|
||||||
|
|
||||||
/* VGA port control */
|
/* VGA port control */
|
||||||
#define ADPA _MMIO(0x61100)
|
#define ADPA _MMIO(0x61100)
|
||||||
#define PCH_ADPA _MMIO(0xe1100)
|
#define PCH_ADPA _MMIO(0xe1100)
|
||||||
|
@ -261,7 +261,7 @@ static void vlv_psr_activate(struct intel_dp *intel_dp)
|
|||||||
VLV_EDP_PSR_ACTIVE_ENTRY);
|
VLV_EDP_PSR_ACTIVE_ENTRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hsw_psr_enable_source(struct intel_dp *intel_dp)
|
static void intel_enable_source_psr1(struct intel_dp *intel_dp)
|
||||||
{
|
{
|
||||||
struct intel_digital_port *dig_port = dp_to_dig_port(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_device *dev = dig_port->base.base.dev;
|
||||||
@ -312,14 +312,29 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)
|
|||||||
val |= EDP_PSR_TP1_TP2_SEL;
|
val |= EDP_PSR_TP1_TP2_SEL;
|
||||||
|
|
||||||
I915_WRITE(EDP_PSR_CTL, val);
|
I915_WRITE(EDP_PSR_CTL, val);
|
||||||
|
}
|
||||||
|
|
||||||
if (!dev_priv->psr.psr2_support)
|
static void intel_enable_source_psr2(struct intel_dp *intel_dp)
|
||||||
return;
|
{
|
||||||
|
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 = to_i915(dev);
|
||||||
|
/*
|
||||||
|
* Let's respect VBT in case VBT asks a higher idle_frame value.
|
||||||
|
* Let's use 6 as the minimum to cover all known cases including
|
||||||
|
* the off-by-one issue that HW has in some cases. Also there are
|
||||||
|
* cases where sink should be able to train
|
||||||
|
* with the 5 or 6 idle patterns.
|
||||||
|
*/
|
||||||
|
uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames);
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
val = idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
|
||||||
|
|
||||||
/* FIXME: selective update is probably totally broken because it doesn't
|
/* FIXME: selective update is probably totally broken because it doesn't
|
||||||
* mesh at all with our frontbuffer tracking. And the hw alone isn't
|
* mesh at all with our frontbuffer tracking. And the hw alone isn't
|
||||||
* good enough. */
|
* good enough. */
|
||||||
val = EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE;
|
val |= EDP_PSR2_ENABLE | EDP_SU_TRACK_ENABLE;
|
||||||
|
|
||||||
if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 5)
|
if (dev_priv->vbt.psr.tp2_tp3_wakeup_time > 5)
|
||||||
val |= EDP_PSR2_TP2_TIME_2500;
|
val |= EDP_PSR2_TP2_TIME_2500;
|
||||||
@ -333,6 +348,19 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)
|
|||||||
I915_WRITE(EDP_PSR2_CTL, val);
|
I915_WRITE(EDP_PSR2_CTL, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hsw_psr_enable_source(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 = to_i915(dev);
|
||||||
|
|
||||||
|
/* psr1 and psr2 are mutually exclusive.*/
|
||||||
|
if (dev_priv->psr.psr2_support)
|
||||||
|
intel_enable_source_psr2(intel_dp);
|
||||||
|
else
|
||||||
|
intel_enable_source_psr1(intel_dp);
|
||||||
|
}
|
||||||
|
|
||||||
static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
|
static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
|
||||||
{
|
{
|
||||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||||
@ -417,7 +445,10 @@ static void intel_psr_activate(struct intel_dp *intel_dp)
|
|||||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
|
||||||
WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
|
if (dev_priv->psr.psr2_support)
|
||||||
|
WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE);
|
||||||
|
else
|
||||||
|
WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
|
||||||
WARN_ON(dev_priv->psr.active);
|
WARN_ON(dev_priv->psr.active);
|
||||||
lockdep_assert_held(&dev_priv->psr.lock);
|
lockdep_assert_held(&dev_priv->psr.lock);
|
||||||
|
|
||||||
@ -468,10 +499,11 @@ void intel_psr_enable(struct intel_dp *intel_dp)
|
|||||||
dev_priv->psr.busy_frontbuffer_bits = 0;
|
dev_priv->psr.busy_frontbuffer_bits = 0;
|
||||||
|
|
||||||
if (HAS_DDI(dev_priv)) {
|
if (HAS_DDI(dev_priv)) {
|
||||||
hsw_psr_setup_vsc(intel_dp);
|
|
||||||
|
|
||||||
if (dev_priv->psr.psr2_support) {
|
if (dev_priv->psr.psr2_support) {
|
||||||
skl_psr_setup_su_vsc(intel_dp);
|
skl_psr_setup_su_vsc(intel_dp);
|
||||||
|
} else {
|
||||||
|
/* set up vsc header for psr1 */
|
||||||
|
hsw_psr_setup_vsc(intel_dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -558,20 +590,35 @@ static void hsw_psr_disable(struct intel_dp *intel_dp)
|
|||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
|
|
||||||
if (dev_priv->psr.active) {
|
if (dev_priv->psr.active) {
|
||||||
I915_WRITE(EDP_PSR_CTL,
|
if (dev_priv->psr.psr2_support) {
|
||||||
I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
|
I915_WRITE(EDP_PSR2_CTL,
|
||||||
|
I915_READ(EDP_PSR2_CTL) &
|
||||||
/* Wait till PSR is idle */
|
~(EDP_PSR2_ENABLE |
|
||||||
if (intel_wait_for_register(dev_priv,
|
EDP_SU_TRACK_ENABLE));
|
||||||
EDP_PSR_STATUS_CTL,
|
/* Wait till PSR2 is idle */
|
||||||
EDP_PSR_STATUS_STATE_MASK,
|
if (intel_wait_for_register(dev_priv,
|
||||||
0,
|
EDP_PSR2_STATUS_CTL,
|
||||||
2000))
|
EDP_PSR2_STATUS_STATE_MASK,
|
||||||
|
0,
|
||||||
|
2000))
|
||||||
|
DRM_ERROR("Timed out waiting for PSR2 Idle State\n");
|
||||||
|
} else {
|
||||||
|
I915_WRITE(EDP_PSR_CTL,
|
||||||
|
I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE);
|
||||||
|
/* Wait till PSR1 is idle */
|
||||||
|
if (intel_wait_for_register(dev_priv,
|
||||||
|
EDP_PSR_STATUS_CTL,
|
||||||
|
EDP_PSR_STATUS_STATE_MASK,
|
||||||
|
0,
|
||||||
|
2000))
|
||||||
DRM_ERROR("Timed out waiting for PSR Idle State\n");
|
DRM_ERROR("Timed out waiting for PSR Idle State\n");
|
||||||
|
}
|
||||||
dev_priv->psr.active = false;
|
dev_priv->psr.active = false;
|
||||||
} else {
|
} else {
|
||||||
WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
|
if (dev_priv->psr.psr2_support)
|
||||||
|
WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE);
|
||||||
|
else
|
||||||
|
WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,13 +669,24 @@ static void intel_psr_work(struct work_struct *work)
|
|||||||
* and be ready for re-enable.
|
* and be ready for re-enable.
|
||||||
*/
|
*/
|
||||||
if (HAS_DDI(dev_priv)) {
|
if (HAS_DDI(dev_priv)) {
|
||||||
if (intel_wait_for_register(dev_priv,
|
if (dev_priv->psr.psr2_support) {
|
||||||
EDP_PSR_STATUS_CTL,
|
if (intel_wait_for_register(dev_priv,
|
||||||
EDP_PSR_STATUS_STATE_MASK,
|
EDP_PSR2_STATUS_CTL,
|
||||||
0,
|
EDP_PSR2_STATUS_STATE_MASK,
|
||||||
50)) {
|
0,
|
||||||
DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
|
50)) {
|
||||||
return;
|
DRM_ERROR("Timed out waiting for PSR2 Idle for re-enable\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (intel_wait_for_register(dev_priv,
|
||||||
|
EDP_PSR_STATUS_CTL,
|
||||||
|
EDP_PSR_STATUS_STATE_MASK,
|
||||||
|
0,
|
||||||
|
50)) {
|
||||||
|
DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (intel_wait_for_register(dev_priv,
|
if (intel_wait_for_register(dev_priv,
|
||||||
@ -670,11 +728,15 @@ static void intel_psr_exit(struct drm_i915_private *dev_priv)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (HAS_DDI(dev_priv)) {
|
if (HAS_DDI(dev_priv)) {
|
||||||
val = I915_READ(EDP_PSR_CTL);
|
if (dev_priv->psr.psr2_support) {
|
||||||
|
val = I915_READ(EDP_PSR2_CTL);
|
||||||
WARN_ON(!(val & EDP_PSR_ENABLE));
|
WARN_ON(!(val & EDP_PSR2_ENABLE));
|
||||||
|
I915_WRITE(EDP_PSR2_CTL, val & ~EDP_PSR2_ENABLE);
|
||||||
I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
|
} else {
|
||||||
|
val = I915_READ(EDP_PSR_CTL);
|
||||||
|
WARN_ON(!(val & EDP_PSR_ENABLE));
|
||||||
|
I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val = I915_READ(VLV_PSRCTL(pipe));
|
val = I915_READ(VLV_PSRCTL(pipe));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user