Loading drivers/gpu/drm/msm/msm_drv.c +99 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading drivers/gpu/drm/msm/msm_drv.h +12 −0 Original line number Diff line number Diff line Loading @@ -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; }; Loading Loading @@ -414,6 +417,15 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) static inline bool msm_is_suspend_state(struct drm_device *dev) { if (!dev || !dev->dev_private) return false; return ((struct msm_drm_private *)dev->dev_private)->suspend_state != NULL; } int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async); Loading drivers/gpu/drm/msm/sde/sde_crtc.c +150 −27 Original line number Diff line number Diff line Loading @@ -57,7 +57,17 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) { struct msm_drm_private *priv = crtc->dev->dev_private; struct msm_drm_private *priv; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); return NULL; } priv = crtc->dev->dev_private; if (!priv || !priv->kms) { SDE_ERROR("invalid kms\n"); return NULL; } return to_sde_kms(priv->kms); } Loading @@ -77,10 +87,10 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) sde_cp_crtc_destroy_properties(crtc); debugfs_remove_recursive(sde_crtc->debugfs_root); mutex_destroy(&sde_crtc->crtc_lock); sde_fence_deinit(&sde_crtc->output_fence); drm_crtc_cleanup(crtc); mutex_destroy(&sde_crtc->crtc_lock); kfree(sde_crtc); } Loading Loading @@ -940,6 +950,112 @@ end: return; } /** * _sde_crtc_vblank_enable_nolock - update power resource and vblank request * @sde_crtc: Pointer to sde crtc structure * @enable: Whether to enable/disable vblanks */ static void _sde_crtc_vblank_enable_nolock( struct sde_crtc *sde_crtc, bool enable) { struct drm_device *dev; struct drm_crtc *crtc; struct drm_encoder *enc; struct msm_drm_private *priv; struct sde_kms *sde_kms; if (!sde_crtc) { SDE_ERROR("invalid crtc\n"); return; } crtc = &sde_crtc->base; dev = crtc->dev; priv = dev->dev_private; if (!priv->kms) { SDE_ERROR("invalid kms\n"); return; } sde_kms = to_sde_kms(priv->kms); if (enable) { sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { if (enc->crtc != crtc) continue; SDE_EVT32(DRMID(crtc), DRMID(enc), enable); sde_encoder_register_vblank_callback(enc, sde_crtc_vblank_cb, (void *)crtc); } } else { list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { if (enc->crtc != crtc) continue; SDE_EVT32(DRMID(crtc), DRMID(enc), enable); sde_encoder_register_vblank_callback(enc, NULL, NULL); } sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); } } /** * _sde_crtc_set_suspend - notify crtc of suspend enable/disable * @crtc: Pointer to drm crtc object * @enable: true to enable suspend, false to indicate resume */ static void _sde_crtc_set_suspend(struct drm_crtc *crtc, bool enable) { struct sde_crtc *sde_crtc; struct msm_drm_private *priv; struct sde_kms *sde_kms; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); return; } sde_crtc = to_sde_crtc(crtc); priv = crtc->dev->dev_private; if (!priv->kms) { SDE_ERROR("invalid crtc kms\n"); return; } sde_kms = to_sde_kms(priv->kms); SDE_DEBUG("crtc%d suspend = %d\n", crtc->base.id, enable); mutex_lock(&sde_crtc->crtc_lock); /* * Update CP on suspend/resume transitions */ if (enable && !sde_crtc->suspend) sde_cp_crtc_suspend(crtc); else if (!enable && sde_crtc->suspend) sde_cp_crtc_resume(crtc); /* * If the vblank refcount != 0, release a power reference on suspend * and take it back during resume (if it is still != 0). */ if (sde_crtc->suspend == enable) SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n", crtc->base.id, enable); else if (atomic_read(&sde_crtc->vblank_refcount) != 0) _sde_crtc_vblank_enable_nolock(sde_crtc, !enable); sde_crtc->suspend = enable; mutex_unlock(&sde_crtc->crtc_lock); } /** * sde_crtc_duplicate_state - state duplicate hook * @crtc: Pointer to drm crtc structure Loading Loading @@ -990,6 +1106,10 @@ static void sde_crtc_reset(struct drm_crtc *crtc) return; } /* revert suspend actions, if necessary */ if (msm_is_suspend_state(crtc->dev)) _sde_crtc_set_suspend(crtc, false); /* remove previous state, if present */ if (crtc->state) { sde_crtc_destroy_state(crtc, crtc->state); Loading @@ -1015,25 +1135,32 @@ static void sde_crtc_reset(struct drm_crtc *crtc) static void sde_crtc_disable(struct drm_crtc *crtc) { struct msm_drm_private *priv; struct sde_crtc *sde_crtc; struct drm_encoder *encoder; struct sde_crtc *sde_crtc; struct sde_kms *sde_kms; struct msm_drm_private *priv; if (!crtc) { if (!crtc || !crtc->dev || !crtc->state) { SDE_ERROR("invalid crtc\n"); return; } sde_crtc = to_sde_crtc(crtc); sde_kms = _sde_crtc_get_kms(crtc); if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { SDE_ERROR("invalid kms handle\n"); return; } priv = sde_kms->dev->dev_private; SDE_DEBUG("crtc%d\n", crtc->base.id); if (msm_is_suspend_state(crtc->dev)) _sde_crtc_set_suspend(crtc, true); mutex_lock(&sde_crtc->crtc_lock); SDE_EVT32(DRMID(crtc)); if (atomic_read(&sde_crtc->vblank_refcount)) { if (atomic_read(&sde_crtc->vblank_refcount) && !sde_crtc->suspend) { SDE_ERROR("crtc%d invalid vblank refcount\n", crtc->base.id); SDE_EVT32(DRMID(crtc)); Loading Loading @@ -1262,40 +1389,36 @@ end: int sde_crtc_vblank(struct drm_crtc *crtc, bool en) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct drm_encoder *encoder; struct drm_device *dev = crtc->dev; struct sde_crtc *sde_crtc; int rc = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); return -EINVAL; } sde_crtc = to_sde_crtc(crtc); mutex_lock(&sde_crtc->crtc_lock); if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) { SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id); if (!sde_crtc->suspend) _sde_crtc_vblank_enable_nolock(sde_crtc, true); } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) { SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id); return -EINVAL; rc = -EINVAL; } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) { SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id); if (!sde_crtc->suspend) _sde_crtc_vblank_enable_nolock(sde_crtc, false); } else { SDE_DEBUG("crtc%d vblank %s refcount:%d\n", crtc->base.id, en ? "enable" : "disable", atomic_read(&sde_crtc->vblank_refcount)); return 0; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc != crtc) continue; SDE_EVT32(DRMID(crtc), en); if (en) sde_encoder_register_vblank_callback(encoder, sde_crtc_vblank_cb, (void *)crtc); else sde_encoder_register_vblank_callback(encoder, NULL, NULL); } return 0; mutex_unlock(&sde_crtc->crtc_lock); return rc; } void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, Loading Loading @@ -1739,6 +1862,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, crtc->dev = dev; atomic_set(&sde_crtc->vblank_refcount, 0); mutex_init(&sde_crtc->crtc_lock); spin_lock_init(&sde_crtc->spin_lock); atomic_set(&sde_crtc->frame_pending, 0); Loading @@ -1760,7 +1884,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize output fence support */ mutex_init(&sde_crtc->crtc_lock); sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id); /* initialize debugfs support */ Loading drivers/gpu/drm/msm/sde/sde_crtc.h +2 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ struct sde_crtc_frame_event { * @vblank_cb_count : count of vblank callback since last reset * @vblank_cb_time : ktime at vblank count reset * @vblank_refcount : reference count for vblank enable request * @suspend : whether or not a suspend operation is in progress * @feature_list : list of color processing features supported on a crtc * @active_list : list of color processing features are active * @dirty_list : list of color processing features are dirty Loading Loading @@ -117,6 +118,7 @@ struct sde_crtc { u32 vblank_cb_count; ktime_t vblank_cb_time; atomic_t vblank_refcount; bool suspend; struct list_head feature_list; struct list_head active_list; Loading drivers/gpu/drm/msm/sde/sde_kms.c +0 −12 Original line number Diff line number Diff line Loading @@ -328,24 +328,12 @@ static int sde_debugfs_danger_init(struct sde_kms *sde_kms, static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); return sde_crtc_vblank(crtc, true); } static void sde_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; sde_crtc_vblank(crtc, false); sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); } static void sde_kms_prepare_commit(struct msm_kms *kms, Loading Loading
drivers/gpu/drm/msm/msm_drv.c +99 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading
drivers/gpu/drm/msm/msm_drv.h +12 −0 Original line number Diff line number Diff line Loading @@ -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; }; Loading Loading @@ -414,6 +417,15 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) static inline bool msm_is_suspend_state(struct drm_device *dev) { if (!dev || !dev->dev_private) return false; return ((struct msm_drm_private *)dev->dev_private)->suspend_state != NULL; } int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async); Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +150 −27 Original line number Diff line number Diff line Loading @@ -57,7 +57,17 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) { struct msm_drm_private *priv = crtc->dev->dev_private; struct msm_drm_private *priv; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); return NULL; } priv = crtc->dev->dev_private; if (!priv || !priv->kms) { SDE_ERROR("invalid kms\n"); return NULL; } return to_sde_kms(priv->kms); } Loading @@ -77,10 +87,10 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) sde_cp_crtc_destroy_properties(crtc); debugfs_remove_recursive(sde_crtc->debugfs_root); mutex_destroy(&sde_crtc->crtc_lock); sde_fence_deinit(&sde_crtc->output_fence); drm_crtc_cleanup(crtc); mutex_destroy(&sde_crtc->crtc_lock); kfree(sde_crtc); } Loading Loading @@ -940,6 +950,112 @@ end: return; } /** * _sde_crtc_vblank_enable_nolock - update power resource and vblank request * @sde_crtc: Pointer to sde crtc structure * @enable: Whether to enable/disable vblanks */ static void _sde_crtc_vblank_enable_nolock( struct sde_crtc *sde_crtc, bool enable) { struct drm_device *dev; struct drm_crtc *crtc; struct drm_encoder *enc; struct msm_drm_private *priv; struct sde_kms *sde_kms; if (!sde_crtc) { SDE_ERROR("invalid crtc\n"); return; } crtc = &sde_crtc->base; dev = crtc->dev; priv = dev->dev_private; if (!priv->kms) { SDE_ERROR("invalid kms\n"); return; } sde_kms = to_sde_kms(priv->kms); if (enable) { sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { if (enc->crtc != crtc) continue; SDE_EVT32(DRMID(crtc), DRMID(enc), enable); sde_encoder_register_vblank_callback(enc, sde_crtc_vblank_cb, (void *)crtc); } } else { list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { if (enc->crtc != crtc) continue; SDE_EVT32(DRMID(crtc), DRMID(enc), enable); sde_encoder_register_vblank_callback(enc, NULL, NULL); } sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); } } /** * _sde_crtc_set_suspend - notify crtc of suspend enable/disable * @crtc: Pointer to drm crtc object * @enable: true to enable suspend, false to indicate resume */ static void _sde_crtc_set_suspend(struct drm_crtc *crtc, bool enable) { struct sde_crtc *sde_crtc; struct msm_drm_private *priv; struct sde_kms *sde_kms; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); return; } sde_crtc = to_sde_crtc(crtc); priv = crtc->dev->dev_private; if (!priv->kms) { SDE_ERROR("invalid crtc kms\n"); return; } sde_kms = to_sde_kms(priv->kms); SDE_DEBUG("crtc%d suspend = %d\n", crtc->base.id, enable); mutex_lock(&sde_crtc->crtc_lock); /* * Update CP on suspend/resume transitions */ if (enable && !sde_crtc->suspend) sde_cp_crtc_suspend(crtc); else if (!enable && sde_crtc->suspend) sde_cp_crtc_resume(crtc); /* * If the vblank refcount != 0, release a power reference on suspend * and take it back during resume (if it is still != 0). */ if (sde_crtc->suspend == enable) SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n", crtc->base.id, enable); else if (atomic_read(&sde_crtc->vblank_refcount) != 0) _sde_crtc_vblank_enable_nolock(sde_crtc, !enable); sde_crtc->suspend = enable; mutex_unlock(&sde_crtc->crtc_lock); } /** * sde_crtc_duplicate_state - state duplicate hook * @crtc: Pointer to drm crtc structure Loading Loading @@ -990,6 +1106,10 @@ static void sde_crtc_reset(struct drm_crtc *crtc) return; } /* revert suspend actions, if necessary */ if (msm_is_suspend_state(crtc->dev)) _sde_crtc_set_suspend(crtc, false); /* remove previous state, if present */ if (crtc->state) { sde_crtc_destroy_state(crtc, crtc->state); Loading @@ -1015,25 +1135,32 @@ static void sde_crtc_reset(struct drm_crtc *crtc) static void sde_crtc_disable(struct drm_crtc *crtc) { struct msm_drm_private *priv; struct sde_crtc *sde_crtc; struct drm_encoder *encoder; struct sde_crtc *sde_crtc; struct sde_kms *sde_kms; struct msm_drm_private *priv; if (!crtc) { if (!crtc || !crtc->dev || !crtc->state) { SDE_ERROR("invalid crtc\n"); return; } sde_crtc = to_sde_crtc(crtc); sde_kms = _sde_crtc_get_kms(crtc); if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { SDE_ERROR("invalid kms handle\n"); return; } priv = sde_kms->dev->dev_private; SDE_DEBUG("crtc%d\n", crtc->base.id); if (msm_is_suspend_state(crtc->dev)) _sde_crtc_set_suspend(crtc, true); mutex_lock(&sde_crtc->crtc_lock); SDE_EVT32(DRMID(crtc)); if (atomic_read(&sde_crtc->vblank_refcount)) { if (atomic_read(&sde_crtc->vblank_refcount) && !sde_crtc->suspend) { SDE_ERROR("crtc%d invalid vblank refcount\n", crtc->base.id); SDE_EVT32(DRMID(crtc)); Loading Loading @@ -1262,40 +1389,36 @@ end: int sde_crtc_vblank(struct drm_crtc *crtc, bool en) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct drm_encoder *encoder; struct drm_device *dev = crtc->dev; struct sde_crtc *sde_crtc; int rc = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); return -EINVAL; } sde_crtc = to_sde_crtc(crtc); mutex_lock(&sde_crtc->crtc_lock); if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) { SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id); if (!sde_crtc->suspend) _sde_crtc_vblank_enable_nolock(sde_crtc, true); } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) { SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id); return -EINVAL; rc = -EINVAL; } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) { SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id); if (!sde_crtc->suspend) _sde_crtc_vblank_enable_nolock(sde_crtc, false); } else { SDE_DEBUG("crtc%d vblank %s refcount:%d\n", crtc->base.id, en ? "enable" : "disable", atomic_read(&sde_crtc->vblank_refcount)); return 0; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc != crtc) continue; SDE_EVT32(DRMID(crtc), en); if (en) sde_encoder_register_vblank_callback(encoder, sde_crtc_vblank_cb, (void *)crtc); else sde_encoder_register_vblank_callback(encoder, NULL, NULL); } return 0; mutex_unlock(&sde_crtc->crtc_lock); return rc; } void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, Loading Loading @@ -1739,6 +1862,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, crtc->dev = dev; atomic_set(&sde_crtc->vblank_refcount, 0); mutex_init(&sde_crtc->crtc_lock); spin_lock_init(&sde_crtc->spin_lock); atomic_set(&sde_crtc->frame_pending, 0); Loading @@ -1760,7 +1884,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize output fence support */ mutex_init(&sde_crtc->crtc_lock); sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id); /* initialize debugfs support */ Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +2 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,7 @@ struct sde_crtc_frame_event { * @vblank_cb_count : count of vblank callback since last reset * @vblank_cb_time : ktime at vblank count reset * @vblank_refcount : reference count for vblank enable request * @suspend : whether or not a suspend operation is in progress * @feature_list : list of color processing features supported on a crtc * @active_list : list of color processing features are active * @dirty_list : list of color processing features are dirty Loading Loading @@ -117,6 +118,7 @@ struct sde_crtc { u32 vblank_cb_count; ktime_t vblank_cb_time; atomic_t vblank_refcount; bool suspend; struct list_head feature_list; struct list_head active_list; Loading
drivers/gpu/drm/msm/sde/sde_kms.c +0 −12 Original line number Diff line number Diff line Loading @@ -328,24 +328,12 @@ static int sde_debugfs_danger_init(struct sde_kms *sde_kms, static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); return sde_crtc_vblank(crtc, true); } static void sde_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; sde_crtc_vblank(crtc, false); sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); } static void sde_kms_prepare_commit(struct msm_kms *kms, Loading