CHROMIUM: drm/exynos: Always DPMS Off in encoder prepare and train dp link in DPMS On
authorDaniel Kurtz <djkurtz@chromium.org>
Wed, 10 Apr 2013 17:42:06 +0000 (01:42 +0800)
committerChromeBot <chrome-bot@google.com>
Fri, 12 Apr 2013 18:14:18 +0000 (11:14 -0700)
commitc69c6fe399235a03d0582d472e91f4272817c7c8
tree28783cb9e0fc0d875c189bf64746ff759f4e9dd8
parentb214028454ab1d3e0b489a162b28f281d1840ebc
CHROMIUM: drm/exynos: Always DPMS Off in encoder prepare and train dp link in DPMS On

In drm_crtc_helper_set_mode(), the basic sequence for encoders and crtcs
is:
->prepare()
->mode_set()
->commit()

For other drm drivers, .prepare does dpms(Off), and .commit does dpms(On).
Thus, the intention is for the .mode_set() callback is supposed to operate properly
in the dpms(Off) state.

For some reason, exynos was not doing dpms(Off) in .prepare, but it was
doing the dpms(On) in .commit, before calling an explicit
panel_ops->commit().

However, the dpms(On) in encoder .commit() never actually does anything,
since the .dpms routines call power on/off routines that are smart and
silently ignore requests that don't change the power state.
In particular, this dpms(On) wasn't able to actually commit changes,
such as enabling video and training the DP link.  Instead, we were
essentially relying on a explicit call to panel_ops->commit() in
encoder->commit() to do the commit.

Also, this means that when exynos_drm_encoder_mode_set calls
panel_ops->set_mode(), the current dpms/power state is whatever it was
before the call to drm_crtc_helper_set_mode().  This is almost always
DPMS(On).

DP link training uses the AUX channel which is only available when
DPMS(On).  A recent change to the dp driver to move link training to the
dp panel_ops->mode_set() seemed to work because, as noted above, we are
almost always in DPMS(On) for DP when we do mode_sets.

There is, however, one exception.  It is possible for userspace to explicit
turn DPMS(Off) the DP pipe.  To save power, for instance.  If this is
followed by a suspend/resume cycle, the resume path, will end up
calling DP mode_set() with dpms(Off).  This causes a soft lockup since the
AUX channel is not enabled when we try to do link training.

Instead, we just always do DPMS(Off) in .prepare(), get rid of the
explicit DP mode_set(), and let the encoder .commit call our DPMS(On)
which will train the link.

Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
BUG=chromium:189108
TEST=(1) On daisy:
  set_short_powerd_timeouts ; echo 1 > /var/lib/power_manager/disable_idle_suspend
  wait ~20 seconds for powerd to turn off the LCD
  ./run_remote_tests.sh --board=daisy --remote=$IP power_Resume/control$
TEST=(2) Same as (1) but with HDMI monitor attached too
  => In this case powerd will switch to "presentation mode", so the turn
   LCD off time is ~45 seconds (and it takes two timeouts).
TEST=(3) suspend_stress_test   should survive even after LCD powers off

Change-Id: I3cd09d5b9555a9e05efc5a66478ab86f2216fc6b
Reviewed-on: https://gerrit.chromium.org/gerrit/47753
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Tested-by: Daniel Kurtz <djkurtz@chromium.org>
Commit-Queue: Daniel Kurtz <djkurtz@chromium.org>
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_drm_encoder.c