Skip to content

Commit facde55

Browse files
committed
drm/i915/psr: WA for panels stating bad link status after PSR is enabled
We are currently seeing unexpected link trainings with several different eDP panels. These are caused by these panels stating bad link status in their dpcd registers. This can be observed by doing following test: 1. Boot up without Xe module loaded 2. Load Xe module with PSR disabled: $ modprobe xe enable_psr=0 3. Read panel link status register $ dpcd_reg read --offset 0x200e --count=1 0x200e: 00 4. Enable PSR, sleep for 2 seconds and disable PSR again: $ echo 0x1 > /sys/kernel/debug/dri/0/i915_edp_psr_debug $ echo "-1" > /sys/kernel/debug/dri/0000:00:02.0/xe_params/enable_psr $ echo 0x0 > /sys/kernel/debug/dri/0/i915_edp_psr_debug $ sleep 2 $ cat /sys/kernel/debug/dri/0/i915_edp_psr_status | grep status $ echo 0x1 > /sys/kernel/debug/dri/0/i915_edp_psr_debug Source PSR/PanelReplay status: DEEP_SLEEP [0x80310030] 5. Now read panel link status registers again: $ dpcd_reg read --offset 0x200e --count=1 0x200e: 80 Workaround this by not trusting link status registers after PSR is enabled until first short pulse interrupt is received. v2: - clear link_ok flag on pipe disable - remove useless comment - modify intel_dp_needs_link_retrain return statement Signed-off-by: Jouni Högander <jouni.hogander@intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20241029122415.1789528-1-jouni.hogander@intel.com
1 parent ea9f962 commit facde55

File tree

4 files changed

+45
-1
lines changed

4 files changed

+45
-1
lines changed

drivers/gpu/drm/i915/display/intel_display_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,8 @@ struct intel_psr {
16181618
u32 dc3co_exit_delay;
16191619
struct delayed_work dc3co_work;
16201620
u8 entry_setup_frames;
1621+
1622+
bool link_ok;
16211623
};
16221624

16231625
struct intel_dp {

drivers/gpu/drm/i915/display/intel_dp.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5038,7 +5038,8 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
50385038
return true;
50395039

50405040
/* Retrain if link not ok */
5041-
return !intel_dp_link_ok(intel_dp, link_status);
5041+
return !intel_dp_link_ok(intel_dp, link_status) &&
5042+
!intel_psr_link_ok(intel_dp);
50425043
}
50435044

50445045
bool intel_dp_has_connector(struct intel_dp *intel_dp,

drivers/gpu/drm/i915/display/intel_psr.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,6 +2013,15 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp,
20132013
intel_dp->psr.enabled = true;
20142014
intel_dp->psr.paused = false;
20152015

2016+
/*
2017+
* Link_ok is sticky and set here on PSR enable. We can assume link
2018+
* training is complete as we never continue to PSR enable with
2019+
* untrained link. Link_ok is kept as set until first short pulse
2020+
* interrupt. This is targeted to workaround panels stating bad link
2021+
* after PSR is enabled.
2022+
*/
2023+
intel_dp->psr.link_ok = true;
2024+
20162025
intel_psr_activate(intel_dp);
20172026
}
20182027

@@ -2172,6 +2181,8 @@ void intel_psr_disable(struct intel_dp *intel_dp,
21722181

21732182
intel_psr_disable_locked(intel_dp);
21742183

2184+
intel_dp->psr.link_ok = false;
2185+
21752186
mutex_unlock(&intel_dp->psr.lock);
21762187
cancel_work_sync(&intel_dp->psr.work);
21772188
cancel_delayed_work_sync(&intel_dp->psr.dc3co_work);
@@ -3462,6 +3473,8 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp)
34623473

34633474
mutex_lock(&psr->lock);
34643475

3476+
psr->link_ok = false;
3477+
34653478
if (!psr->enabled)
34663479
goto exit;
34673480

@@ -3521,6 +3534,33 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
35213534
return ret;
35223535
}
35233536

3537+
/**
3538+
* intel_psr_link_ok - return psr->link_ok
3539+
* @intel_dp: struct intel_dp
3540+
*
3541+
* We are seeing unexpected link re-trainings with some panels. This is caused
3542+
* by panel stating bad link status after PSR is enabled. Code checking link
3543+
* status can call this to ensure it can ignore bad link status stated by the
3544+
* panel I.e. if panel is stating bad link and intel_psr_link_ok is stating link
3545+
* is ok caller should rely on latter.
3546+
*
3547+
* Return value of link_ok
3548+
*/
3549+
bool intel_psr_link_ok(struct intel_dp *intel_dp)
3550+
{
3551+
bool ret;
3552+
3553+
if ((!CAN_PSR(intel_dp) && !CAN_PANEL_REPLAY(intel_dp)) ||
3554+
!intel_dp_is_edp(intel_dp))
3555+
return false;
3556+
3557+
mutex_lock(&intel_dp->psr.lock);
3558+
ret = intel_dp->psr.link_ok;
3559+
mutex_unlock(&intel_dp->psr.lock);
3560+
3561+
return ret;
3562+
}
3563+
35243564
/**
35253565
* intel_psr_lock - grab PSR lock
35263566
* @crtc_state: the crtc state

drivers/gpu/drm/i915/display/intel_psr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st
5959
void intel_psr_pause(struct intel_dp *intel_dp);
6060
void intel_psr_resume(struct intel_dp *intel_dp);
6161
bool intel_psr_needs_block_dc_vblank(const struct intel_crtc_state *crtc_state);
62+
bool intel_psr_link_ok(struct intel_dp *intel_dp);
6263

6364
void intel_psr_lock(const struct intel_crtc_state *crtc_state);
6465
void intel_psr_unlock(const struct intel_crtc_state *crtc_state);

0 commit comments

Comments
 (0)