Loading drivers/gpu/drm/msm/msm_drv.c +11 −0 Original line number Diff line number Diff line Loading @@ -126,10 +126,21 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { struct msm_drm_private *priv; if (!dev) return -EINVAL; if (msm_is_suspend_blocked(dev)) { DRM_DEBUG("rejecting commit during suspend\n"); return -EBUSY; } priv = dev->dev_private; if (priv && priv->kms && priv->kms->funcs && priv->kms->funcs->atomic_check) return priv->kms->funcs->atomic_check(priv->kms, state); return drm_atomic_helper_check(dev, state); } Loading drivers/gpu/drm/msm/msm_kms.h +3 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,9 @@ struct msm_kms_funcs { const struct msm_format *msm_fmt, const struct drm_mode_fb_cmd2 *cmd, struct drm_gem_object **bos); /* perform complete atomic check of given atomic state */ int (*atomic_check)(struct msm_kms *kms, struct drm_atomic_state *state); /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); Loading drivers/gpu/drm/msm/sde/sde_crtc.c +24 −1 Original line number Diff line number Diff line Loading @@ -2328,6 +2328,8 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) _sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); cstate->idle_pc = sde_crtc->idle_pc; return &cstate->base; } Loading Loading @@ -2428,6 +2430,24 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_encoder_virt_restore(encoder); } } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) { /* * Serialize h/w idle state update with crtc atomic check. * Grab the modeset lock to ensure that there is no on-going * atomic check, then increment the idle_pc counter. The next * atomic check will detect a new idle_pc since the counter * has advanced between the old_state and new_state, and * therefore properly reprogram all relevant drm objects' * hardware. */ drm_modeset_lock_crtc(crtc, NULL); sde_crtc->idle_pc++; SDE_DEBUG("crtc%d idle_pc:%d\n", crtc->base.id, sde_crtc->idle_pc); SDE_EVT32(DRMID(crtc), sde_crtc->idle_pc); } else if (event_type == SDE_POWER_EVENT_POST_DISABLE) { struct drm_plane *plane; Loading @@ -2437,6 +2457,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) */ drm_atomic_crtc_for_each_plane(plane, crtc) sde_plane_set_revalidate(plane, true); drm_modeset_unlock_crtc(crtc); } mutex_unlock(&sde_crtc->crtc_lock); Loading Loading @@ -2565,7 +2587,8 @@ static void sde_crtc_enable(struct drm_crtc *crtc) sde_crtc->power_event = sde_power_handle_register_event( &priv->phandle, SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE, SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE | SDE_POWER_EVENT_PRE_DISABLE, sde_crtc_handle_power_event, crtc, sde_crtc->name); } Loading drivers/gpu/drm/msm/sde/sde_crtc.h +5 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ struct sde_crtc_event { * @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 * @idle_pc : count of current idle power collapse request * @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 @@ -173,6 +174,7 @@ struct sde_crtc { ktime_t vblank_cb_time; atomic_t vblank_refcount; bool suspend; u32 idle_pc; struct list_head feature_list; struct list_head active_list; Loading Loading @@ -278,6 +280,7 @@ struct sde_crtc_respool { * @sbuf_cfg: stream buffer configuration * @sbuf_prefill_line: number of line for inline rotator prefetch * @sbuf_flush_mask: flush mask for inline rotator * @idle_pc: count of idle power collapse request when state is duplicated */ struct sde_crtc_state { struct drm_crtc_state base; Loading Loading @@ -307,6 +310,8 @@ struct sde_crtc_state { u32 sbuf_prefill_line; u32 sbuf_flush_mask; u32 idle_pc; struct sde_crtc_respool rp; }; Loading drivers/gpu/drm/msm/sde/sde_kms.c +43 −0 Original line number Diff line number Diff line Loading @@ -1370,6 +1370,48 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) sde_crtc_cancel_pending_flip(priv->crtcs[i], file); } static int sde_kms_atomic_check(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev = sde_kms->dev; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int rc, i; if (!kms || !state) return -EINVAL; /* * Add planes (and other affected DRM objects, if any) to new state * if idle power collapse occurred since previous commit. * Since atomic state is a delta from the last, if the user-space * did not request any changes on a plane/connector, that object * will not be included in the new atomic state. Idle power collapse * is driver-autonomous, so the driver needs to ensure that all * hardware is reprogrammed as the power comes back on by forcing * the drm objects attached to the CRTC into the new atomic state. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); struct sde_crtc_state *old_cstate = to_sde_crtc_state(crtc->state); if (cstate->idle_pc != old_cstate->idle_pc) { SDE_DEBUG("crtc%d idle_pc:%d/%d\n", crtc->base.id, cstate->idle_pc, old_cstate->idle_pc); SDE_EVT32(DRMID(crtc), cstate->idle_pc, old_cstate->idle_pc); rc = drm_atomic_add_affected_planes(state, crtc); if (rc) return rc; } } return drm_atomic_helper_check(dev, state); } static const struct msm_kms_funcs kms_funcs = { .hw_init = sde_kms_hw_init, .postinit = sde_kms_postinit, Loading @@ -1387,6 +1429,7 @@ static const struct msm_kms_funcs kms_funcs = { .enable_vblank = sde_kms_enable_vblank, .disable_vblank = sde_kms_disable_vblank, .check_modified_format = sde_format_check_modified_format, .atomic_check = sde_kms_atomic_check, .get_format = sde_get_msm_format, .round_pixclk = sde_kms_round_pixclk, .destroy = sde_kms_destroy, Loading Loading
drivers/gpu/drm/msm/msm_drv.c +11 −0 Original line number Diff line number Diff line Loading @@ -126,10 +126,21 @@ static void msm_fb_output_poll_changed(struct drm_device *dev) int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { struct msm_drm_private *priv; if (!dev) return -EINVAL; if (msm_is_suspend_blocked(dev)) { DRM_DEBUG("rejecting commit during suspend\n"); return -EBUSY; } priv = dev->dev_private; if (priv && priv->kms && priv->kms->funcs && priv->kms->funcs->atomic_check) return priv->kms->funcs->atomic_check(priv->kms, state); return drm_atomic_helper_check(dev, state); } Loading
drivers/gpu/drm/msm/msm_kms.h +3 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,9 @@ struct msm_kms_funcs { const struct msm_format *msm_fmt, const struct drm_mode_fb_cmd2 *cmd, struct drm_gem_object **bos); /* perform complete atomic check of given atomic state */ int (*atomic_check)(struct msm_kms *kms, struct drm_atomic_state *state); /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +24 −1 Original line number Diff line number Diff line Loading @@ -2328,6 +2328,8 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) _sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); cstate->idle_pc = sde_crtc->idle_pc; return &cstate->base; } Loading Loading @@ -2428,6 +2430,24 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) sde_encoder_virt_restore(encoder); } } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) { /* * Serialize h/w idle state update with crtc atomic check. * Grab the modeset lock to ensure that there is no on-going * atomic check, then increment the idle_pc counter. The next * atomic check will detect a new idle_pc since the counter * has advanced between the old_state and new_state, and * therefore properly reprogram all relevant drm objects' * hardware. */ drm_modeset_lock_crtc(crtc, NULL); sde_crtc->idle_pc++; SDE_DEBUG("crtc%d idle_pc:%d\n", crtc->base.id, sde_crtc->idle_pc); SDE_EVT32(DRMID(crtc), sde_crtc->idle_pc); } else if (event_type == SDE_POWER_EVENT_POST_DISABLE) { struct drm_plane *plane; Loading @@ -2437,6 +2457,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) */ drm_atomic_crtc_for_each_plane(plane, crtc) sde_plane_set_revalidate(plane, true); drm_modeset_unlock_crtc(crtc); } mutex_unlock(&sde_crtc->crtc_lock); Loading Loading @@ -2565,7 +2587,8 @@ static void sde_crtc_enable(struct drm_crtc *crtc) sde_crtc->power_event = sde_power_handle_register_event( &priv->phandle, SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE, SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE | SDE_POWER_EVENT_PRE_DISABLE, sde_crtc_handle_power_event, crtc, sde_crtc->name); } Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +5 −0 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ struct sde_crtc_event { * @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 * @idle_pc : count of current idle power collapse request * @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 @@ -173,6 +174,7 @@ struct sde_crtc { ktime_t vblank_cb_time; atomic_t vblank_refcount; bool suspend; u32 idle_pc; struct list_head feature_list; struct list_head active_list; Loading Loading @@ -278,6 +280,7 @@ struct sde_crtc_respool { * @sbuf_cfg: stream buffer configuration * @sbuf_prefill_line: number of line for inline rotator prefetch * @sbuf_flush_mask: flush mask for inline rotator * @idle_pc: count of idle power collapse request when state is duplicated */ struct sde_crtc_state { struct drm_crtc_state base; Loading Loading @@ -307,6 +310,8 @@ struct sde_crtc_state { u32 sbuf_prefill_line; u32 sbuf_flush_mask; u32 idle_pc; struct sde_crtc_respool rp; }; Loading
drivers/gpu/drm/msm/sde/sde_kms.c +43 −0 Original line number Diff line number Diff line Loading @@ -1370,6 +1370,48 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) sde_crtc_cancel_pending_flip(priv->crtcs[i], file); } static int sde_kms_atomic_check(struct msm_kms *kms, struct drm_atomic_state *state) { struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev = sde_kms->dev; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int rc, i; if (!kms || !state) return -EINVAL; /* * Add planes (and other affected DRM objects, if any) to new state * if idle power collapse occurred since previous commit. * Since atomic state is a delta from the last, if the user-space * did not request any changes on a plane/connector, that object * will not be included in the new atomic state. Idle power collapse * is driver-autonomous, so the driver needs to ensure that all * hardware is reprogrammed as the power comes back on by forcing * the drm objects attached to the CRTC into the new atomic state. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); struct sde_crtc_state *old_cstate = to_sde_crtc_state(crtc->state); if (cstate->idle_pc != old_cstate->idle_pc) { SDE_DEBUG("crtc%d idle_pc:%d/%d\n", crtc->base.id, cstate->idle_pc, old_cstate->idle_pc); SDE_EVT32(DRMID(crtc), cstate->idle_pc, old_cstate->idle_pc); rc = drm_atomic_add_affected_planes(state, crtc); if (rc) return rc; } } return drm_atomic_helper_check(dev, state); } static const struct msm_kms_funcs kms_funcs = { .hw_init = sde_kms_hw_init, .postinit = sde_kms_postinit, Loading @@ -1387,6 +1429,7 @@ static const struct msm_kms_funcs kms_funcs = { .enable_vblank = sde_kms_enable_vblank, .disable_vblank = sde_kms_disable_vblank, .check_modified_format = sde_format_check_modified_format, .atomic_check = sde_kms_atomic_check, .get_format = sde_get_msm_format, .round_pixclk = sde_kms_round_pixclk, .destroy = sde_kms_destroy, Loading