Skip to content

Commit 357c0ae

Browse files
committed
drm/i915/lspcon: Wait for expected LSPCON mode to settle
Some LSPCON adaptors may return an incorrect LSPCON mode right after waking from DP Sleep state. This is the case at least for the ParadTech PS175 adaptor, both when waking because of exiting the DP Sleep to active state, or due to any other AUX CH transfer. We can determine the current expected mode based on whether the DPCD area is accessible, since according to the LSPCON spec this area is only accesible in PCON mode. This wait will avoid us trying to change the mode, while the current expected mode hasn't settled yet and start link training before the adaptor thinks it's in PCON mode after waking from DP Sleep state. Cc: Shashank Sharma <[email protected]> Cc: Ville Syrjälä <[email protected]> Cc: Jani Nikula <[email protected]> Signed-off-by: Imre Deak <[email protected]> Reviewed-by: Shashank Sharma <[email protected]> Link: http://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent dd75f6d commit 357c0ae

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

drivers/gpu/drm/i915/intel_dp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
24012401
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
24022402
DP_SET_POWER_D3);
24032403
} else {
2404+
struct intel_lspcon *lspcon = dp_to_lspcon(intel_dp);
2405+
24042406
/*
24052407
* When turning on, we need to retry for 1ms to give the sink
24062408
* time to wake up.
@@ -2412,6 +2414,9 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
24122414
break;
24132415
msleep(1);
24142416
}
2417+
2418+
if (ret == 1 && lspcon->active)
2419+
lspcon_wait_pcon_mode(lspcon);
24152420
}
24162421

24172422
if (ret != 1)

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,4 +1830,5 @@ void intel_color_load_luts(struct drm_crtc_state *crtc_state);
18301830
/* intel_lspcon.c */
18311831
bool lspcon_init(struct intel_digital_port *intel_dig_port);
18321832
void lspcon_resume(struct intel_lspcon *lspcon);
1833+
void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
18331834
#endif /* __INTEL_DRV_H__ */

drivers/gpu/drm/i915/intel_lspcon.c

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,54 @@ static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
3535
return &dig_port->dp;
3636
}
3737

38+
static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
39+
{
40+
switch (mode) {
41+
case DRM_LSPCON_MODE_PCON:
42+
return "PCON";
43+
case DRM_LSPCON_MODE_LS:
44+
return "LS";
45+
case DRM_LSPCON_MODE_INVALID:
46+
return "INVALID";
47+
default:
48+
MISSING_CASE(mode);
49+
return "INVALID";
50+
}
51+
}
52+
3853
static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
3954
{
40-
enum drm_lspcon_mode current_mode = DRM_LSPCON_MODE_INVALID;
55+
enum drm_lspcon_mode current_mode;
4156
struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
4257

43-
if (drm_lspcon_get_mode(adapter, &current_mode))
58+
if (drm_lspcon_get_mode(adapter, &current_mode)) {
4459
DRM_ERROR("Error reading LSPCON mode\n");
45-
else
46-
DRM_DEBUG_KMS("Current LSPCON mode %s\n",
47-
current_mode == DRM_LSPCON_MODE_PCON ? "PCON" : "LS");
60+
return DRM_LSPCON_MODE_INVALID;
61+
}
62+
return current_mode;
63+
}
64+
65+
static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
66+
enum drm_lspcon_mode mode)
67+
{
68+
enum drm_lspcon_mode current_mode;
69+
70+
current_mode = lspcon_get_current_mode(lspcon);
71+
if (current_mode == mode || current_mode == DRM_LSPCON_MODE_INVALID)
72+
goto out;
73+
74+
DRM_DEBUG_KMS("Waiting for LSPCON mode %s to settle\n",
75+
lspcon_mode_name(mode));
76+
77+
wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode ||
78+
current_mode == DRM_LSPCON_MODE_INVALID, 100);
79+
if (current_mode != mode)
80+
DRM_DEBUG_KMS("LSPCON mode hasn't settled\n");
81+
82+
out:
83+
DRM_DEBUG_KMS("Current LSPCON mode %s\n",
84+
lspcon_mode_name(current_mode));
85+
4886
return current_mode;
4987
}
5088

@@ -97,8 +135,10 @@ static bool lspcon_probe(struct intel_lspcon *lspcon)
97135
{
98136
enum drm_dp_dual_mode_type adaptor_type;
99137
struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
138+
enum drm_lspcon_mode expected_mode;
100139

101-
lspcon_wake_native_aux_ch(lspcon);
140+
expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
141+
DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
102142

103143
/* Lets probe the adaptor and check its type */
104144
adaptor_type = drm_dp_dual_mode_detect(adapter);
@@ -110,7 +150,7 @@ static bool lspcon_probe(struct intel_lspcon *lspcon)
110150

111151
/* Yay ... got a LSPCON device */
112152
DRM_DEBUG_KMS("LSPCON detected\n");
113-
lspcon->mode = lspcon_get_current_mode(lspcon);
153+
lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
114154
lspcon->active = true;
115155
return true;
116156
}
@@ -150,15 +190,29 @@ static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
150190

151191
void lspcon_resume(struct intel_lspcon *lspcon)
152192
{
153-
if (lspcon_wake_native_aux_ch(lspcon))
193+
enum drm_lspcon_mode expected_mode;
194+
195+
if (lspcon_wake_native_aux_ch(lspcon)) {
196+
expected_mode = DRM_LSPCON_MODE_PCON;
154197
lspcon_resume_in_pcon_wa(lspcon);
198+
} else {
199+
expected_mode = DRM_LSPCON_MODE_LS;
200+
}
201+
202+
if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
203+
return;
155204

156205
if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON, true))
157206
DRM_ERROR("LSPCON resume failed\n");
158207
else
159208
DRM_DEBUG_KMS("LSPCON resume success\n");
160209
}
161210

211+
void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
212+
{
213+
lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
214+
}
215+
162216
bool lspcon_init(struct intel_digital_port *intel_dig_port)
163217
{
164218
struct intel_dp *dp = &intel_dig_port->dp;

0 commit comments

Comments
 (0)