diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index 24b773058f52..a6782ad16a69 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -217,6 +217,47 @@ static int _sde_debugfs_fps_status(struct inode *inode, struct file *file) } #endif +static ssize_t early_wakeup_store(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv; + u32 crtc_id; + bool trigger; + + if (!device || !buf || !count) { + SDE_ERROR("invalid input param(s)\n"); + return -EINVAL; + } + + if (kstrtobool(buf, &trigger) < 0) + return -EINVAL; + + if (!trigger) + return count; + + crtc = dev_get_drvdata(device); + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + priv = crtc->dev->dev_private; + + crtc_id = drm_crtc_index(crtc); + if (crtc_id >= ARRAY_SIZE(priv->disp_thread)) { + SDE_ERROR("invalid crtc index[%d]\n", crtc_id); + return -EINVAL; + } + + kthread_queue_work(&priv->disp_thread[crtc_id].worker, + &sde_crtc->early_wakeup_work); + + return count; +} + static ssize_t fps_periodicity_ms_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { @@ -403,12 +444,14 @@ static DEVICE_ATTR_RO(vsync_event); static DEVICE_ATTR_RO(measured_fps); static DEVICE_ATTR_RW(fps_periodicity_ms); static DEVICE_ATTR_RO(retire_frame_event); +static DEVICE_ATTR_WO(early_wakeup); static struct attribute *sde_crtc_dev_attrs[] = { &dev_attr_vsync_event.attr, &dev_attr_measured_fps.attr, &dev_attr_fps_periodicity_ms.attr, &dev_attr_retire_frame_event.attr, + &dev_attr_early_wakeup.attr, NULL }; @@ -6644,6 +6687,40 @@ void sde_crtc_cancel_delayed_work(struct drm_crtc *crtc) SDE_EVT32(DRMID(crtc), idle_status, cache_status); } +/* + * __sde_crtc_early_wakeup_work - trigger early wakeup from user space + */ +static void __sde_crtc_early_wakeup_work(struct kthread_work *work) +{ + struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc, + early_wakeup_work); + struct drm_crtc *crtc; + struct drm_device *dev; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!sde_crtc) { + SDE_ERROR("invalid sde crtc\n"); + return; + } + + if (!sde_crtc->enabled) { + SDE_INFO("sde crtc is not enabled\n"); + return; + } + + crtc = &sde_crtc->base; + dev = crtc->dev; + if (!dev) { + SDE_ERROR("invalid drm device\n"); + return; + } + + priv = dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + sde_kms_trigger_early_wakeup(sde_kms, crtc); +} + /* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) { @@ -6740,6 +6817,8 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) __sde_crtc_idle_notify_work); kthread_init_delayed_work(&sde_crtc->static_cache_read_work, __sde_crtc_static_cache_read_work); + kthread_init_work(&sde_crtc->early_wakeup_work, + __sde_crtc_early_wakeup_work); SDE_DEBUG("crtc=%d new_llcc=%d, old_llcc=%d\n", crtc->base.id, diff --git a/techpack/display/msm/sde/sde_crtc.h b/techpack/display/msm/sde/sde_crtc.h index 75fb998ed06d..0dc296dc1de8 100644 --- a/techpack/display/msm/sde/sde_crtc.h +++ b/techpack/display/msm/sde/sde_crtc.h @@ -278,6 +278,7 @@ struct sde_crtc_misr_info { * @misr_frame_count : misr frame count provided by client * @misr_data : store misr data before turning off the clocks. * @idle_notify_work: delayed worker to notify idle timeout to user space + * @early_wakeup_work: work to trigger early wakeup * @power_event : registered power event handle * @cur_perf : current performance committed to clock/bandwidth driver * @plane_mask_old: keeps track of the planes used in the previous commit @@ -361,6 +362,7 @@ struct sde_crtc { bool misr_reconfigure; u32 misr_frame_count; struct kthread_delayed_work idle_notify_work; + struct kthread_work early_wakeup_work; struct sde_power_event *power_event; diff --git a/techpack/display/msm/sde/sde_encoder.c b/techpack/display/msm/sde/sde_encoder.c index 9447b8cd6061..a232826ee82d 100644 --- a/techpack/display/msm/sde/sde_encoder.c +++ b/techpack/display/msm/sde/sde_encoder.c @@ -5544,3 +5544,27 @@ void sde_encoder_enable_recovery_event(struct drm_encoder *encoder) sde_enc = to_sde_encoder_virt(encoder); sde_enc->recovery_events_enabled = true; } + +void sde_encoder_trigger_early_wakeup(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + struct msm_drm_private *priv = NULL; + + priv = drm_enc->dev->dev_private; + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc->crtc || (sde_enc->crtc->index + >= ARRAY_SIZE(priv->disp_thread))) { + SDE_DEBUG_ENC(sde_enc, + "invalid cached CRTC: %d or crtc index: %d\n", + sde_enc->crtc == NULL, + sde_enc->crtc ? sde_enc->crtc->index : -EINVAL); + return; + } + + if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { + SDE_ATRACE_BEGIN("sde_encoder_resource_control"); + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_EARLY_WAKEUP); + SDE_ATRACE_END("sde_encoder_resource_control"); + } +} diff --git a/techpack/display/msm/sde/sde_encoder.h b/techpack/display/msm/sde/sde_encoder.h index a1c138c16999..871bd4293bf7 100644 --- a/techpack/display/msm/sde/sde_encoder.h +++ b/techpack/display/msm/sde/sde_encoder.h @@ -640,4 +640,11 @@ static inline bool sde_encoder_is_widebus_enabled(struct drm_encoder *drm_enc) sde_enc = to_sde_encoder_virt(drm_enc); return sde_enc->mode_info.wide_bus_en; } + +/** + * sde_encoder_trigger_early_wakeup - trigger early wake up + * @drm_enc: Pointer to drm encoder structure + */ +void sde_encoder_trigger_early_wakeup(struct drm_encoder *drm_enc); + #endif /* __SDE_ENCODER_H__ */ diff --git a/techpack/display/msm/sde/sde_kms.c b/techpack/display/msm/sde/sde_kms.c index 24b6c11252ef..ee6d24aa8d01 100644 --- a/techpack/display/msm/sde/sde_kms.c +++ b/techpack/display/msm/sde/sde_kms.c @@ -5129,3 +5129,26 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder) SDE_EVT32(DRMID(encoder), MSM_ENC_ACTIVE_REGION); return sde_encoder_wait_for_event(encoder, MSM_ENC_ACTIVE_REGION); } + +void sde_kms_trigger_early_wakeup(struct sde_kms *sde_kms, + struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + struct drm_encoder *drm_enc; + + if (!sde_kms || !crtc) { + SDE_ERROR("invalid argument sde_kms %pK crtc %pK\n", + sde_kms, crtc); + return; + } + + priv = sde_kms->dev->dev_private; + + SDE_ATRACE_BEGIN("sde_kms_trigger_early_wakeup"); + drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc->state->encoder_mask) + sde_encoder_trigger_early_wakeup(drm_enc); + + if (sde_kms->first_kickoff) + sde_power_scale_reg_bus(&priv->phandle, VOTE_INDEX_HIGH, false); + SDE_ATRACE_END("sde_kms_trigger_early_wakeup"); +} diff --git a/techpack/display/msm/sde/sde_kms.h b/techpack/display/msm/sde/sde_kms.h index db50ede366ce..96fa4c744f14 100644 --- a/techpack/display/msm/sde/sde_kms.h +++ b/techpack/display/msm/sde/sde_kms.h @@ -754,4 +754,13 @@ int sde_kms_vm_trusted_prepare_commit(struct sde_kms *sde_kms, */ int sde_kms_vm_primary_prepare_commit(struct sde_kms *sde_kms, struct drm_atomic_state *state); + +/** + * sde_kms_trigger_early_wakeup - trigger early wake up + * @sde_kms: pointer to sde_kms structure + * @crtc: pointer to drm_crtc structure + */ +void sde_kms_trigger_early_wakeup(struct sde_kms *sde_kms, + struct drm_crtc *crtc); + #endif /* __sde_kms_H__ */