Skip to content

Commit 7eb2c4d

Browse files
ideakjnikula
authored andcommitted
drm/i915: Fix LSPCON TMDS output buffer enabling from low-power state
LSPCON adapters in low-power state may ignore the first I2C write during TMDS output buffer enabling, resulting in a blank screen even with an otherwise enabled pipe. Fix this by reading back and validating the written value a few times. The problem was noticed on GLK machines with an onboard LSPCON adapter after entering/exiting DC5 power state. Doing an I2C read of the adapter ID as the first transaction - instead of the I2C write to enable the TMDS buffers - returns the correct value. Based on this we assume that the transaction itself is sent properly, it's only the adapter that is not ready for some reason to accept this first write after waking from low-power state. In my case the second I2C write attempt always succeeded. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105854 Cc: Clinton Taylor <[email protected]> Cc: Ville Syrjälä <[email protected]> Cc: [email protected] Signed-off-by: Imre Deak <[email protected]> Signed-off-by: Jani Nikula <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent b8e47d8 commit 7eb2c4d

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

drivers/gpu/drm/drm_dp_dual_mode_helper.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -350,19 +350,44 @@ int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type,
350350
{
351351
uint8_t tmds_oen = enable ? 0 : DP_DUAL_MODE_TMDS_DISABLE;
352352
ssize_t ret;
353+
int retry;
353354

354355
if (type < DRM_DP_DUAL_MODE_TYPE2_DVI)
355356
return 0;
356357

357-
ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN,
358-
&tmds_oen, sizeof(tmds_oen));
359-
if (ret) {
360-
DRM_DEBUG_KMS("Failed to %s TMDS output buffers\n",
361-
enable ? "enable" : "disable");
362-
return ret;
358+
/*
359+
* LSPCON adapters in low-power state may ignore the first write, so
360+
* read back and verify the written value a few times.
361+
*/
362+
for (retry = 0; retry < 3; retry++) {
363+
uint8_t tmp;
364+
365+
ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN,
366+
&tmds_oen, sizeof(tmds_oen));
367+
if (ret) {
368+
DRM_DEBUG_KMS("Failed to %s TMDS output buffers (%d attempts)\n",
369+
enable ? "enable" : "disable",
370+
retry + 1);
371+
return ret;
372+
}
373+
374+
ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN,
375+
&tmp, sizeof(tmp));
376+
if (ret) {
377+
DRM_DEBUG_KMS("I2C read failed during TMDS output buffer %s (%d attempts)\n",
378+
enable ? "enabling" : "disabling",
379+
retry + 1);
380+
return ret;
381+
}
382+
383+
if (tmp == tmds_oen)
384+
return 0;
363385
}
364386

365-
return 0;
387+
DRM_DEBUG_KMS("I2C write value mismatch during TMDS output buffer %s\n",
388+
enable ? "enabling" : "disabling");
389+
390+
return -EIO;
366391
}
367392
EXPORT_SYMBOL(drm_dp_dual_mode_set_tmds_output);
368393

0 commit comments

Comments
 (0)