drm/msm/sde: reset drm state on suspend/resume

Explicitly disable connector DPMS and CRTC active states on
system suspend, and restore the previous state during a
system resume. This allows the underlying drivers to trigger
a DPMS callback for handling any panel related power disables
while still preserving the DRM atomic state.

CRs-Fixed: 2019307
Change-Id: Ib9933e4bc8b43c64def777b081d4315e5dbb7365
Signed-off-by: Clarence Ip <cip@codeaurora.org>
This commit is contained in:
Clarence Ip 2016-11-19 18:02:23 -05:00
parent 1331c9a856
commit 4fc53f0d46
2 changed files with 102 additions and 2 deletions

View file

@ -1923,8 +1923,75 @@ static struct drm_driver msm_driver = {
#ifdef CONFIG_PM_SLEEP
static int msm_pm_suspend(struct device *dev)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct drm_device *ddev;
struct drm_modeset_acquire_ctx *ctx;
struct drm_connector *conn;
struct drm_atomic_state *state;
struct drm_crtc_state *crtc_state;
struct msm_drm_private *priv;
int ret = 0;
if (!dev)
return -EINVAL;
ddev = dev_get_drvdata(dev);
if (!ddev || !ddev->dev_private)
return -EINVAL;
priv = ddev->dev_private;
SDE_EVT32(0);
/* acquire modeset lock(s) */
drm_modeset_lock_all(ddev);
ctx = ddev->mode_config.acquire_ctx;
/* save current state for resume */
if (priv->suspend_state)
drm_atomic_state_free(priv->suspend_state);
priv->suspend_state = drm_atomic_helper_duplicate_state(ddev, ctx);
if (IS_ERR_OR_NULL(priv->suspend_state)) {
DRM_ERROR("failed to back up suspend state\n");
priv->suspend_state = NULL;
goto unlock;
}
/* create atomic state to disable all CRTCs */
state = drm_atomic_state_alloc(ddev);
if (IS_ERR_OR_NULL(state)) {
DRM_ERROR("failed to allocate crtc disable state\n");
goto unlock;
}
state->acquire_ctx = ctx;
drm_for_each_connector(conn, ddev) {
if (!conn->state || !conn->state->crtc ||
conn->dpms != DRM_MODE_DPMS_ON)
continue;
/* force CRTC to be inactive */
crtc_state = drm_atomic_get_crtc_state(state,
conn->state->crtc);
if (IS_ERR_OR_NULL(crtc_state)) {
DRM_ERROR("failed to get crtc %d state\n",
conn->state->crtc->base.id);
drm_atomic_state_free(state);
goto unlock;
}
crtc_state->active = false;
}
/* commit the "disable all" state */
ret = drm_atomic_commit(state);
if (ret < 0) {
DRM_ERROR("failed to disable crtcs, %d\n", ret);
drm_atomic_state_free(state);
}
unlock:
drm_modeset_unlock_all(ddev);
/* disable hot-plug polling */
drm_kms_helper_poll_disable(ddev);
return 0;
@ -1932,8 +1999,38 @@ static int msm_pm_suspend(struct device *dev)
static int msm_pm_resume(struct device *dev)
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct drm_device *ddev;
struct msm_drm_private *priv;
int ret;
if (!dev)
return -EINVAL;
ddev = dev_get_drvdata(dev);
if (!ddev || !ddev->dev_private)
return -EINVAL;
priv = ddev->dev_private;
SDE_EVT32(priv->suspend_state != NULL);
drm_mode_config_reset(ddev);
drm_modeset_lock_all(ddev);
if (priv->suspend_state) {
priv->suspend_state->acquire_ctx =
ddev->mode_config.acquire_ctx;
ret = drm_atomic_commit(priv->suspend_state);
if (ret < 0) {
DRM_ERROR("failed to restore state, %d\n", ret);
drm_atomic_state_free(priv->suspend_state);
}
priv->suspend_state = NULL;
}
drm_modeset_unlock_all(ddev);
/* enable hot-plug polling */
drm_kms_helper_poll_enable(ddev);
return 0;

View file

@ -367,6 +367,9 @@ struct msm_drm_private {
struct msm_vblank_ctrl vblank_ctrl;
/* saved atomic state during system suspend */
struct drm_atomic_state *suspend_state;
/* list of clients waiting for events */
struct list_head client_event_list;
};