Merge "msm: drm: add hibernation support"
This commit is contained in:
commit
b8b0a039da
6 changed files with 180 additions and 13 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
|
@ -2134,10 +2134,150 @@ static int msm_pm_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pm_freeze(struct device *dev)
|
||||
{
|
||||
struct drm_device *ddev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_modeset_acquire_ctx *ctx;
|
||||
struct drm_atomic_state *state;
|
||||
struct msm_drm_private *priv;
|
||||
struct msm_kms *kms;
|
||||
int early_display = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
ddev = dev_get_drvdata(dev);
|
||||
if (!ddev || !ddev->dev_private)
|
||||
return -EINVAL;
|
||||
|
||||
priv = ddev->dev_private;
|
||||
|
||||
kms = priv->kms;
|
||||
if (kms && kms->funcs && kms->funcs->early_display_status)
|
||||
early_display = kms->funcs->early_display_status(kms);
|
||||
|
||||
SDE_EVT32(0);
|
||||
|
||||
if (early_display) {
|
||||
/* acquire modeset lock(s) */
|
||||
drm_modeset_lock_all(ddev);
|
||||
ctx = ddev->mode_config.acquire_ctx;
|
||||
|
||||
/* save current state for restore */
|
||||
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 null state to idle CRTCs */
|
||||
state = drm_atomic_state_alloc(ddev);
|
||||
if (IS_ERR_OR_NULL(state)) {
|
||||
DRM_ERROR("failed to allocate null atomic state\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
state->acquire_ctx = ctx;
|
||||
|
||||
/* commit the null state */
|
||||
ret = drm_atomic_commit(state);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to commit null state, %d\n", ret);
|
||||
drm_atomic_state_free(state);
|
||||
}
|
||||
|
||||
drm_for_each_crtc(crtc, ddev)
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
unlock:
|
||||
drm_modeset_unlock_all(ddev);
|
||||
} else {
|
||||
ret = msm_pm_suspend(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pm_restore(struct device *dev)
|
||||
{
|
||||
struct drm_device *ddev;
|
||||
struct drm_crtc *crtc;
|
||||
struct msm_drm_private *priv;
|
||||
struct msm_kms *kms;
|
||||
int early_display = 0;
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
ddev = dev_get_drvdata(dev);
|
||||
if (!ddev || !ddev->dev_private)
|
||||
return -EINVAL;
|
||||
|
||||
priv = ddev->dev_private;
|
||||
|
||||
kms = priv->kms;
|
||||
if (kms && kms->funcs && kms->funcs->early_display_status)
|
||||
early_display = kms->funcs->early_display_status(kms);
|
||||
|
||||
|
||||
SDE_EVT32(priv->suspend_state != NULL);
|
||||
|
||||
if (early_display) {
|
||||
drm_mode_config_reset(ddev);
|
||||
|
||||
drm_modeset_lock_all(ddev);
|
||||
|
||||
drm_for_each_crtc(crtc, ddev)
|
||||
drm_crtc_vblank_on(crtc);
|
||||
|
||||
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);
|
||||
} else {
|
||||
ret = msm_pm_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_pm_thaw(struct device *dev)
|
||||
{
|
||||
msm_pm_restore(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops msm_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume)
|
||||
.suspend = msm_pm_suspend,
|
||||
.resume = msm_pm_resume,
|
||||
.freeze = msm_pm_freeze,
|
||||
.restore = msm_pm_restore,
|
||||
.thaw = msm_pm_thaw,
|
||||
};
|
||||
|
||||
static int msm_drm_bind(struct device *dev)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
|
@ -98,6 +98,7 @@ struct msm_kms_funcs {
|
|||
struct drm_encoder *slave_encoder,
|
||||
bool is_cmd_mode);
|
||||
void (*postopen)(struct msm_kms *kms, struct drm_file *file);
|
||||
bool (*early_display_status)(struct msm_kms *kms);
|
||||
/* cleanup: */
|
||||
void (*preclose)(struct msm_kms *kms, struct drm_file *file);
|
||||
void (*postclose)(struct msm_kms *kms, struct drm_file *file);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -11,6 +11,8 @@
|
|||
*/
|
||||
|
||||
#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
|
||||
#include "sde_kms.h"
|
||||
|
@ -586,11 +588,16 @@ void sde_connector_complete_commit(struct drm_connector *connector)
|
|||
/* signal connector's retire fence */
|
||||
sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
|
||||
|
||||
/*
|
||||
* After LK totally exits, LK's early splash resource
|
||||
* should be released.
|
||||
/* If below both 2 conditions are met, LK's early splash resources
|
||||
* should be freed.
|
||||
* 1) When get_hibernation_status() is returned as true.
|
||||
* a. hibernation image snapshot failed.
|
||||
* b. hibernation restore successful.
|
||||
* c. hibernation restore failed.
|
||||
* 2) After LK totally exits.
|
||||
*/
|
||||
if (sde_splash_get_lk_complete_status(priv->kms)) {
|
||||
if (get_hibernation_status() &&
|
||||
sde_splash_get_lk_complete_status(priv->kms)) {
|
||||
c_conn = to_sde_connector(connector);
|
||||
|
||||
sde_splash_free_resource(priv->kms, &priv->phandle,
|
||||
|
|
|
@ -1171,6 +1171,13 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file)
|
|||
sde_crtc_cancel_pending_flip(priv->crtcs[i], file);
|
||||
}
|
||||
|
||||
static bool sde_kms_early_display_status(struct msm_kms *kms)
|
||||
{
|
||||
struct sde_kms *sde_kms = to_sde_kms(kms);
|
||||
|
||||
return sde_kms->splash_info.handoff;
|
||||
}
|
||||
|
||||
static const struct msm_kms_funcs kms_funcs = {
|
||||
.hw_init = sde_kms_hw_init,
|
||||
.postinit = sde_kms_postinit,
|
||||
|
@ -1190,6 +1197,7 @@ static const struct msm_kms_funcs kms_funcs = {
|
|||
.get_format = sde_get_msm_format,
|
||||
.round_pixclk = sde_kms_round_pixclk,
|
||||
.destroy = sde_kms_destroy,
|
||||
.early_display_status = sde_kms_early_display_status,
|
||||
};
|
||||
|
||||
/* the caller api needs to turn on clock before calling it */
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <soc/qcom/early_domain.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "msm_mmu.h"
|
||||
#include "sde_kms.h"
|
||||
|
@ -759,7 +761,6 @@ bool sde_splash_get_lk_complete_status(struct msm_kms *kms)
|
|||
intr = sde_kms->hw_intr;
|
||||
|
||||
if (sde_kms->splash_info.handoff &&
|
||||
!sde_kms->splash_info.display_splash_enabled &&
|
||||
!_sde_splash_lk_check()) {
|
||||
SDE_DEBUG("LK totally exits\n");
|
||||
return true;
|
||||
|
@ -948,12 +949,20 @@ int sde_splash_lk_stop_splash(struct msm_kms *kms,
|
|||
mutex_lock(&sde_splash_lock);
|
||||
if (_sde_splash_validate_commit(sde_kms, state) &&
|
||||
sinfo->display_splash_enabled) {
|
||||
if (_sde_splash_lk_check())
|
||||
if (_sde_splash_lk_check()) {
|
||||
_sde_splash_notify_lk_stop_splash();
|
||||
error = _sde_splash_clear_mixer_blendstage(kms, state);
|
||||
}
|
||||
|
||||
sinfo->display_splash_enabled = false;
|
||||
|
||||
error = _sde_splash_clear_mixer_blendstage(kms, state);
|
||||
if (get_hibernation_status() == true) {
|
||||
sinfo->display_splash_enabled = false;
|
||||
} else {
|
||||
/* preserve the display_splash_enabled state for
|
||||
* case when system is restoring from hibernation
|
||||
* image and splash is enabled.
|
||||
*/
|
||||
sinfo->display_splash_enabled = true;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sde_splash_lock);
|
||||
|
||||
|
|
|
@ -380,6 +380,7 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
|
|||
extern asmlinkage int swsusp_arch_suspend(void);
|
||||
extern asmlinkage int swsusp_arch_resume(void);
|
||||
|
||||
static inline bool get_hibernation_status(void) { return true; };
|
||||
extern void hibernation_set_ops(const struct platform_hibernation_ops *ops);
|
||||
extern int hibernate(void);
|
||||
extern bool system_entering_hibernation(void);
|
||||
|
@ -393,6 +394,7 @@ static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
|
|||
static inline void swsusp_set_page_free(struct page *p) {}
|
||||
static inline void swsusp_unset_page_free(struct page *p) {}
|
||||
|
||||
static inline bool get_hibernation_status(void) { return true; };
|
||||
static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {}
|
||||
static inline int hibernate(void) { return -ENOSYS; }
|
||||
static inline bool system_entering_hibernation(void) { return false; }
|
||||
|
|
Loading…
Add table
Reference in a new issue