Loading drivers/gpu/drm/msm/sde/sde_hw_top.c +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp, new_val = reg_val & ~BIT(bit_off); SDE_REG_WRITE(c, reg_off, new_val); wmb(); /* ensure write finished before progressing */ clk_forced_on = !(reg_val & BIT(bit_off)); Loading drivers/gpu/drm/msm/sde/sde_plane.c +57 −1 Original line number Diff line number Diff line Loading @@ -2868,20 +2868,76 @@ static int sde_plane_prepare_fb(struct drm_plane *plane, return 0; } /** * _sde_plane_fetch_halt - halts vbif transactions for a plane * @plane: Pointer to plane * Returns: 0 on success */ static int _sde_plane_fetch_halt(struct drm_plane *plane) { struct sde_plane *psde; int xin_id; enum sde_clk_ctrl_type clk_ctrl; struct msm_drm_private *priv; struct sde_kms *sde_kms; psde = to_sde_plane(plane); if (!plane || !plane->dev || !psde->pipe_hw) { SDE_ERROR("invalid arguments\n"); return -EINVAL; } priv = plane->dev->dev_private; if (!priv || !priv->kms) { SDE_ERROR("invalid KMS reference\n"); return -EINVAL; } sde_kms = to_sde_kms(priv->kms); clk_ctrl = psde->pipe_hw->cap->clk_ctrl; xin_id = psde->pipe_hw->cap->xin_id; SDE_DEBUG_PLANE(psde, "pipe:%d xin_id:%d clk_ctrl:%d\n", psde->pipe - SSPP_VIG0, xin_id, clk_ctrl); SDE_EVT32_VERBOSE(psde, psde->pipe - SSPP_VIG0, xin_id, clk_ctrl); return sde_vbif_halt_plane_xin(sde_kms, xin_id, clk_ctrl); } static void sde_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sde_plane *psde = to_sde_plane(plane); struct sde_plane_state *old_pstate; struct sde_plane_rot_state *old_rstate; int ret; if (!old_state || !old_state->fb) if (!old_state || !old_state->fb || !plane || !plane->state) return; old_pstate = to_sde_plane_state(old_state); SDE_DEBUG_PLANE(psde, "FB[%u]\n", old_state->fb->base.id); /* * plane->state gets populated for next frame after swap_state. If * plane->state->crtc pointer is not populated then it is not used in * the next frame, hence making it an unused plane. */ if ((plane->state->crtc == NULL) && !psde->is_virtual) { SDE_DEBUG_PLANE(psde, "unused pipe:%u\n", psde->pipe - SSPP_VIG0); /* halt this plane now */ ret = _sde_plane_fetch_halt(plane); if (ret) { SDE_ERROR_PLANE(psde, "unused pipe %u halt failed\n", psde->pipe - SSPP_VIG0); SDE_EVT32(DRMID(plane), psde->pipe - SSPP_VIG0, ret, SDE_EVTLOG_ERROR); } } old_rstate = &old_pstate->rot; msm_framebuffer_cleanup(old_rstate->out_fb, old_pstate->aspace); Loading drivers/gpu/drm/msm/sde/sde_vbif.c +61 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,67 @@ static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id) return rc; } int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) { struct sde_hw_vbif *vbif = NULL; struct sde_hw_mdp *mdp; bool forced_on = false; bool status; int rc = 0; if (!sde_kms) { SDE_ERROR("invalid argument\n"); return -EINVAL; } vbif = sde_kms->hw_vbif[VBIF_RT]; mdp = sde_kms->hw_mdp; if (!vbif || !mdp || !vbif->ops.get_halt_ctrl || !vbif->ops.set_halt_ctrl || !mdp->ops.setup_clk_force_ctrl) { SDE_ERROR("invalid vbif or mdp arguments\n"); return -EINVAL; } /* * If status is 0, then make sure client clock is not gated * while halting by forcing it ON only if it was not previously * forced on. If status is 1 then its already halted. */ status = vbif->ops.get_halt_ctrl(vbif, xin_id); if (status == 0) forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true); else return 0; /* send halt request for unused plane's xin client */ vbif->ops.set_halt_ctrl(vbif, xin_id, true); rc = _sde_vbif_wait_for_xin_halt(vbif, xin_id); if (rc) { SDE_ERROR( "wait failed for pipe halt:xin_id %u, clk_ctrl %u, rc %u\n", xin_id, clk_ctrl, rc); SDE_EVT32(xin_id, clk_ctrl, rc, SDE_EVTLOG_ERROR); return rc; } status = vbif->ops.get_halt_ctrl(vbif, xin_id); if (status == 0) { SDE_ERROR("halt failed for pipe xin_id %u halt clk_ctrl %u\n", xin_id, clk_ctrl); SDE_EVT32(xin_id, clk_ctrl, SDE_EVTLOG_ERROR); return -ETIMEDOUT; } /* open xin client to enable transactions */ vbif->ops.set_halt_ctrl(vbif, xin_id, false); if (forced_on) mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false); return 0; } /** * _sde_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters * @vbif: Pointer to hardware vbif driver Loading drivers/gpu/drm/msm/sde/sde_vbif.h +14 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,20 @@ void sde_vbif_clear_errors(struct sde_kms *sde_kms); */ void sde_vbif_init_memtypes(struct sde_kms *sde_kms); /** * sde_vbif_halt_plane_xin - halts the xin client for the unused plane * On unused plane, check if the vbif for this plane is idle or not. * If not then first force_on the planes clock and then send the * halt request. Wait for some time then check for the vbif idle * or not again. * @sde_kms: SDE handler * @xin_id: xin id of the unused plane * @clk_ctrl: clk ctrl type for the unused plane * Returns: 0 on success, error code otherwise */ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl); #ifdef CONFIG_DEBUG_FS int sde_debugfs_vbif_init(struct sde_kms *sde_kms, struct dentry *debugfs_root); void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms); Loading Loading
drivers/gpu/drm/msm/sde/sde_hw_top.c +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp, new_val = reg_val & ~BIT(bit_off); SDE_REG_WRITE(c, reg_off, new_val); wmb(); /* ensure write finished before progressing */ clk_forced_on = !(reg_val & BIT(bit_off)); Loading
drivers/gpu/drm/msm/sde/sde_plane.c +57 −1 Original line number Diff line number Diff line Loading @@ -2868,20 +2868,76 @@ static int sde_plane_prepare_fb(struct drm_plane *plane, return 0; } /** * _sde_plane_fetch_halt - halts vbif transactions for a plane * @plane: Pointer to plane * Returns: 0 on success */ static int _sde_plane_fetch_halt(struct drm_plane *plane) { struct sde_plane *psde; int xin_id; enum sde_clk_ctrl_type clk_ctrl; struct msm_drm_private *priv; struct sde_kms *sde_kms; psde = to_sde_plane(plane); if (!plane || !plane->dev || !psde->pipe_hw) { SDE_ERROR("invalid arguments\n"); return -EINVAL; } priv = plane->dev->dev_private; if (!priv || !priv->kms) { SDE_ERROR("invalid KMS reference\n"); return -EINVAL; } sde_kms = to_sde_kms(priv->kms); clk_ctrl = psde->pipe_hw->cap->clk_ctrl; xin_id = psde->pipe_hw->cap->xin_id; SDE_DEBUG_PLANE(psde, "pipe:%d xin_id:%d clk_ctrl:%d\n", psde->pipe - SSPP_VIG0, xin_id, clk_ctrl); SDE_EVT32_VERBOSE(psde, psde->pipe - SSPP_VIG0, xin_id, clk_ctrl); return sde_vbif_halt_plane_xin(sde_kms, xin_id, clk_ctrl); } static void sde_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sde_plane *psde = to_sde_plane(plane); struct sde_plane_state *old_pstate; struct sde_plane_rot_state *old_rstate; int ret; if (!old_state || !old_state->fb) if (!old_state || !old_state->fb || !plane || !plane->state) return; old_pstate = to_sde_plane_state(old_state); SDE_DEBUG_PLANE(psde, "FB[%u]\n", old_state->fb->base.id); /* * plane->state gets populated for next frame after swap_state. If * plane->state->crtc pointer is not populated then it is not used in * the next frame, hence making it an unused plane. */ if ((plane->state->crtc == NULL) && !psde->is_virtual) { SDE_DEBUG_PLANE(psde, "unused pipe:%u\n", psde->pipe - SSPP_VIG0); /* halt this plane now */ ret = _sde_plane_fetch_halt(plane); if (ret) { SDE_ERROR_PLANE(psde, "unused pipe %u halt failed\n", psde->pipe - SSPP_VIG0); SDE_EVT32(DRMID(plane), psde->pipe - SSPP_VIG0, ret, SDE_EVTLOG_ERROR); } } old_rstate = &old_pstate->rot; msm_framebuffer_cleanup(old_rstate->out_fb, old_pstate->aspace); Loading
drivers/gpu/drm/msm/sde/sde_vbif.c +61 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,67 @@ static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id) return rc; } int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) { struct sde_hw_vbif *vbif = NULL; struct sde_hw_mdp *mdp; bool forced_on = false; bool status; int rc = 0; if (!sde_kms) { SDE_ERROR("invalid argument\n"); return -EINVAL; } vbif = sde_kms->hw_vbif[VBIF_RT]; mdp = sde_kms->hw_mdp; if (!vbif || !mdp || !vbif->ops.get_halt_ctrl || !vbif->ops.set_halt_ctrl || !mdp->ops.setup_clk_force_ctrl) { SDE_ERROR("invalid vbif or mdp arguments\n"); return -EINVAL; } /* * If status is 0, then make sure client clock is not gated * while halting by forcing it ON only if it was not previously * forced on. If status is 1 then its already halted. */ status = vbif->ops.get_halt_ctrl(vbif, xin_id); if (status == 0) forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true); else return 0; /* send halt request for unused plane's xin client */ vbif->ops.set_halt_ctrl(vbif, xin_id, true); rc = _sde_vbif_wait_for_xin_halt(vbif, xin_id); if (rc) { SDE_ERROR( "wait failed for pipe halt:xin_id %u, clk_ctrl %u, rc %u\n", xin_id, clk_ctrl, rc); SDE_EVT32(xin_id, clk_ctrl, rc, SDE_EVTLOG_ERROR); return rc; } status = vbif->ops.get_halt_ctrl(vbif, xin_id); if (status == 0) { SDE_ERROR("halt failed for pipe xin_id %u halt clk_ctrl %u\n", xin_id, clk_ctrl); SDE_EVT32(xin_id, clk_ctrl, SDE_EVTLOG_ERROR); return -ETIMEDOUT; } /* open xin client to enable transactions */ vbif->ops.set_halt_ctrl(vbif, xin_id, false); if (forced_on) mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false); return 0; } /** * _sde_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters * @vbif: Pointer to hardware vbif driver Loading
drivers/gpu/drm/msm/sde/sde_vbif.h +14 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,20 @@ void sde_vbif_clear_errors(struct sde_kms *sde_kms); */ void sde_vbif_init_memtypes(struct sde_kms *sde_kms); /** * sde_vbif_halt_plane_xin - halts the xin client for the unused plane * On unused plane, check if the vbif for this plane is idle or not. * If not then first force_on the planes clock and then send the * halt request. Wait for some time then check for the vbif idle * or not again. * @sde_kms: SDE handler * @xin_id: xin id of the unused plane * @clk_ctrl: clk ctrl type for the unused plane * Returns: 0 on success, error code otherwise */ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl); #ifdef CONFIG_DEBUG_FS int sde_debugfs_vbif_init(struct sde_kms *sde_kms, struct dentry *debugfs_root); void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms); Loading