disp: msm: add support for display early wakeup

Display clocks and IRQs are disabled during idle state
on command mode for power saving, and will be enabled
when a new frame commits to display driver. But enable
display clocks and IRQs will cause some latency.
So add a new SDE custom IOCTL for user-space to early wake
up display before first frame commits to kernel.

Change-Id: I6ca0188d321c4964f29c46e588b64d06b9634c59
Signed-off-by: Lei Chen <chenlei@codeaurora.org>
This commit is contained in:
Lei Chen
2020-05-26 16:45:52 +08:00
committed by Gerrit - the friendly Code Review server
parent 2bcfcab1cb
commit eb679f5289
5 changed files with 136 additions and 0 deletions

View File

@@ -1626,6 +1626,57 @@ int msm_ioctl_power_ctrl(struct drm_device *dev, void *data,
return rc; return rc;
} }
/**
* msm_ioctl_display_early_wakeup - early wakeup display.
* @dev: drm device for the ioctl
* @data: data pointer for the ioctl
* @file_priv: drm file for the ioctl call
*
*/
int msm_ioctl_display_hint_ops(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_msm_display_hint *display_hint = data;
struct drm_msm_early_wakeup early_wakeup;
void __user *early_wakeup_usr;
struct msm_drm_private *priv;
struct msm_kms *kms;
priv = dev->dev_private;
kms = priv->kms;
if (unlikely(!display_hint)) {
DRM_ERROR("invalid ioctl data\n");
return -EINVAL;
}
SDE_EVT32(display_hint->hint_flags);
if (display_hint->hint_flags == DRM_MSM_DISPLAY_EARLY_WAKEUP_HINT) {
if (!display_hint->data) {
DRM_ERROR("early_wakeup: wrong parameter\n");
return -EINVAL;
}
early_wakeup_usr =
(void __user *)((uintptr_t)display_hint->data);
if (copy_from_user(&early_wakeup, early_wakeup_usr,
sizeof(early_wakeup))) {
DRM_ERROR("early_wakeup: copy from user failed\n");
return -EINVAL;
}
SDE_EVT32(early_wakeup.wakeup_hint);
if (kms && kms->funcs && kms->funcs->display_early_wakeup
&& early_wakeup.wakeup_hint)
kms->funcs->display_early_wakeup(dev,
early_wakeup.connector_id);
}
return 0;
}
static const struct drm_ioctl_desc msm_ioctls[] = { static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW),
@@ -1639,6 +1690,8 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_IOCTL_DEF_DRV(MSM_RMFB2, msm_ioctl_rmfb2, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(MSM_RMFB2, msm_ioctl_rmfb2, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(MSM_POWER_CTRL, msm_ioctl_power_ctrl, DRM_IOCTL_DEF_DRV(MSM_POWER_CTRL, msm_ioctl_power_ctrl,
DRM_RENDER_ALLOW), DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_DISPLAY_HINT, msm_ioctl_display_hint_ops,
DRM_UNLOCKED),
}; };
static const struct vm_operations_struct vm_ops = { static const struct vm_operations_struct vm_ops = {

View File

@@ -100,6 +100,8 @@ struct msm_kms_funcs {
void (*set_encoder_mode)(struct msm_kms *kms, void (*set_encoder_mode)(struct msm_kms *kms,
struct drm_encoder *encoder, struct drm_encoder *encoder,
bool cmd_mode); bool cmd_mode);
void (*display_early_wakeup)(struct drm_device *dev,
const int32_t connector_id);
/* pm suspend/resume hooks */ /* pm suspend/resume hooks */
int (*pm_suspend)(struct device *dev); int (*pm_suspend)(struct device *dev);
int (*pm_resume)(struct device *dev); int (*pm_resume)(struct device *dev);

View File

@@ -3685,6 +3685,49 @@ static void sde_encoder_input_event_work_handler(struct kthread_work *work)
SDE_ENC_RC_EVENT_EARLY_WAKEUP); SDE_ENC_RC_EVENT_EARLY_WAKEUP);
} }
static void sde_encoder_early_wakeup_work_handler(struct kthread_work *work)
{
struct sde_encoder_virt *sde_enc = container_of(work,
struct sde_encoder_virt, early_wakeup_work);
if (!sde_enc) {
SDE_ERROR("invalid sde encoder\n");
return;
}
sde_encoder_resource_control(&sde_enc->base,
SDE_ENC_RC_EVENT_EARLY_WAKEUP);
}
void sde_encoder_early_wakeup(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = NULL;
struct msm_drm_thread *disp_thread = NULL;
struct msm_drm_private *priv = NULL;
priv = drm_enc->dev->dev_private;
sde_enc = to_sde_encoder_virt(drm_enc);
if (!sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) {
SDE_DEBUG_ENC(sde_enc,
"should only early wake up command mode display\n");
return;
}
if (!sde_enc->crtc || (sde_enc->crtc->index
>= ARRAY_SIZE(priv->event_thread))) {
SDE_ERROR("invalid CRTC: %d or crtc index: %d\n",
sde_enc->crtc == NULL,
sde_enc->crtc ? sde_enc->crtc->index : -EINVAL);
return;
}
disp_thread = &priv->disp_thread[sde_enc->crtc->index];
kthread_queue_work(&disp_thread->worker,
&sde_enc->early_wakeup_work);
}
int sde_encoder_poll_line_counts(struct drm_encoder *drm_enc) int sde_encoder_poll_line_counts(struct drm_encoder *drm_enc)
{ {
static const uint64_t timeout_us = 50000; static const uint64_t timeout_us = 50000;
@@ -4788,6 +4831,9 @@ struct drm_encoder *sde_encoder_init_with_ops(
kthread_init_work(&sde_enc->input_event_work, kthread_init_work(&sde_enc->input_event_work,
sde_encoder_input_event_work_handler); sde_encoder_input_event_work_handler);
kthread_init_work(&sde_enc->early_wakeup_work,
sde_encoder_early_wakeup_work_handler);
kthread_init_work(&sde_enc->esd_trigger_work, kthread_init_work(&sde_enc->esd_trigger_work,
sde_encoder_esd_trigger_work_handler); sde_encoder_esd_trigger_work_handler);

View File

@@ -167,6 +167,7 @@ struct sde_encoder_ops {
* @rc_state: resource controller state * @rc_state: resource controller state
* @delayed_off_work: delayed worker to schedule disabling of * @delayed_off_work: delayed worker to schedule disabling of
* clks and resources after IDLE_TIMEOUT time. * clks and resources after IDLE_TIMEOUT time.
* @early_wakeup_work: worker to handle early wakeup event
* @input_event_work: worker to handle input device touch events * @input_event_work: worker to handle input device touch events
* @esd_trigger_work: worker to handle esd trigger events * @esd_trigger_work: worker to handle esd trigger events
* @input_handler: handler for input device events * @input_handler: handler for input device events
@@ -232,6 +233,7 @@ struct sde_encoder_virt {
struct mutex rc_lock; struct mutex rc_lock;
enum sde_enc_rc_states rc_state; enum sde_enc_rc_states rc_state;
struct kthread_delayed_work delayed_off_work; struct kthread_delayed_work delayed_off_work;
struct kthread_work early_wakeup_work;
struct kthread_work input_event_work; struct kthread_work input_event_work;
struct kthread_work esd_trigger_work; struct kthread_work esd_trigger_work;
struct input_handler *input_handler; struct input_handler *input_handler;
@@ -265,6 +267,12 @@ void sde_encoder_get_hw_resources(struct drm_encoder *encoder,
struct sde_encoder_hw_resources *hw_res, struct sde_encoder_hw_resources *hw_res,
struct drm_connector_state *conn_state); struct drm_connector_state *conn_state);
/**
* sde_encoder_early_wakeup - early wake up display
* @encoder: encoder pointer
*/
void sde_encoder_early_wakeup(struct drm_encoder *drm_enc);
/** /**
* sde_encoder_register_vblank_callback - provide callback to encoder that * sde_encoder_register_vblank_callback - provide callback to encoder that
* will be called on the next vblank. * will be called on the next vblank.

View File

@@ -2659,6 +2659,32 @@ end:
drm_modeset_acquire_fini(&ctx); drm_modeset_acquire_fini(&ctx);
} }
void sde_kms_display_early_wakeup(struct drm_device *dev,
const int32_t connector_id)
{
struct drm_connector_list_iter conn_iter;
struct drm_connector *conn;
struct drm_encoder *drm_enc;
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(conn, &conn_iter) {
if (connector_id != DRM_MSM_WAKE_UP_ALL_DISPLAYS &&
connector_id != conn->base.id)
continue;
if (conn->state && conn->state->best_encoder)
drm_enc = conn->state->best_encoder;
else
drm_enc = conn->encoder;
sde_encoder_early_wakeup(drm_enc);
}
drm_connector_list_iter_end(&conn_iter);
}
static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms, static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms,
struct device *dev) struct device *dev)
{ {
@@ -2933,6 +2959,7 @@ static const struct msm_kms_funcs kms_funcs = {
.atomic_check = sde_kms_atomic_check, .atomic_check = sde_kms_atomic_check,
.get_format = sde_get_msm_format, .get_format = sde_get_msm_format,
.round_pixclk = sde_kms_round_pixclk, .round_pixclk = sde_kms_round_pixclk,
.display_early_wakeup = sde_kms_display_early_wakeup,
.pm_suspend = sde_kms_pm_suspend, .pm_suspend = sde_kms_pm_suspend,
.pm_resume = sde_kms_pm_resume, .pm_resume = sde_kms_pm_resume,
.destroy = sde_kms_destroy, .destroy = sde_kms_destroy,