From 8ae1574a3e02641fccabf2443180a3280a0bfb9f Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 4 Mar 2015 16:19:37 -0800 Subject: [PATCH] msm: mdss: add async support for hw cursor Reduce dependency between hw cursor updates and display commit. Configure the cursor pipes and flush immediately, rather than waiting for the commit. This would enable multiple cursor updates within a single vsync. However, the screen update would happen only after vsync, which would pick the latest cursor update. The restriction is that after the first cursor update, a display commit is required to stage the cursor pipes. Change-Id: I666856c88b8e2decac6578237e9b93b106378ffa Signed-off-by: Veera Sundaram Sankaran --- drivers/video/fbdev/msm/mdss_mdp.c | 1 + drivers/video/fbdev/msm/mdss_mdp.h | 9 +- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 24 +++- drivers/video/fbdev/msm/mdss_mdp_overlay.c | 141 +++++++++++++++------ drivers/video/fbdev/msm/mdss_mdp_pipe.c | 19 +-- 5 files changed, 140 insertions(+), 54 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 768964d494c5..25f6b2987cea 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1378,6 +1378,7 @@ static ssize_t mdss_mdp_show_capabilities(struct device *dev, SPRINT("dma_pipes=%d\n", mdata->ndma_pipes); SPRINT("blending_stages=%d\n", mdata->max_target_zorder); SPRINT("cursor_pipes=%d\n", mdata->ncursor_pipes); + SPRINT("max_cursor_size=%d\n", mdata->max_cursor_size); SPRINT("smp_count=%d\n", mdata->smp_mb_cnt); SPRINT("smp_size=%d\n", mdata->smp_mb_size); SPRINT("smp_mb_per_pipe=%d\n", mdata->smp_mb_per_pipe); diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 1af4e6876cc9..584dfc96ba21 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -29,9 +29,6 @@ #include "mdss_mdp_cdm.h" #define MDSS_MDP_DEFAULT_INTR_MASK 0 -#define MDSS_MDP_CURSOR_WIDTH 64 -#define MDSS_MDP_CURSOR_HEIGHT 64 -#define MDSS_MDP_CURSOR_SIZE (MDSS_MDP_CURSOR_WIDTH*MDSS_MDP_CURSOR_WIDTH*4) #define MDSS_MDP_PIXEL_RAM_SIZE (50 * 1024) #define PHASE_STEP_SHIFT 21 @@ -280,6 +277,7 @@ struct mdss_mdp_ctl { struct mdss_mdp_cdm *cdm; struct mutex lock; struct mutex offlock; + struct mutex flush_lock; struct mutex *shared_lock; spinlock_t spin_lock; @@ -914,6 +912,11 @@ static inline int mdss_mdp_is_cdm_supported(struct mdss_data_type *mdata, (mixer_type == MDSS_MDP_MIXER_TYPE_INTF))); } +static inline u32 mdss_mdp_get_cursor_frame_size(struct mdss_data_type *mdata) +{ + return mdata->max_cursor_size * mdata->max_cursor_size * 4; +} + irqreturn_t mdss_mdp_isr(int irq, void *ptr); void mdss_mdp_irq_clear(struct mdss_data_type *mdata, u32 intr_type, u32 intf_num); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 1be84e4af446..5c5b03c672e9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -1818,6 +1818,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata, ctl->mdata = mdata; mutex_init(&ctl->lock); mutex_init(&ctl->offlock); + mutex_init(&ctl->flush_lock); spin_lock_init(&ctl->spin_lock); BLOCKING_INIT_NOTIFIER_HEAD(&ctl->notifier_head); pr_debug("alloc ctl_num=%d\n", ctl->num); @@ -3481,8 +3482,7 @@ int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, pr_debug("pnum=%x mixer=%d stage=%d\n", pipe->num, mixer->num, pipe->mixer_stage); - if (mutex_lock_interruptible(&ctl->lock)) - return -EINTR; + mutex_lock(&ctl->flush_lock); if (params_changed) { mixer->params_changed++; @@ -3530,7 +3530,7 @@ int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, else /* RGB/VIG 0-2 pipes */ ctl->flush_bits |= BIT(pipe->num); - mutex_unlock(&ctl->lock); + mutex_unlock(&ctl->flush_lock); return 0; } @@ -3784,6 +3784,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, bool is_bw_released; int split_enable; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + u32 ctl_flush_bits = 0, sctl_flush_bits = 0; if (!ctl) { pr_err("display function not set\n"); @@ -3801,6 +3802,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, sctl = mdss_mdp_get_split_ctl(ctl); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + mutex_lock(&ctl->flush_lock); + /* * We could have released the bandwidth if there were no transactions * pending, so we want to re-calculate the bandwidth in this situation @@ -3838,6 +3841,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, ATRACE_END("prepare_fnc"); if (ret) { pr_err("error preparing display\n"); + mutex_unlock(&ctl->flush_lock); goto done; } @@ -3854,6 +3858,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_TOP, sctl->opmode); sctl->flush_bits |= BIT(17); + sctl_flush_bits = sctl->flush_bits; } ATRACE_END("mixer_programming"); } @@ -3875,9 +3880,14 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, if (sctl && ctl->split_flush_en) { ctl->flush_bits |= sctl->flush_bits; sctl->flush_bits = 0; + sctl_flush_bits = sctl->flush_bits; } + ctl_flush_bits = ctl->flush_bits; + ATRACE_END("postproc_programming"); + mutex_unlock(&ctl->flush_lock); + ATRACE_BEGIN("frame_ready"); mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_CFG_DONE); if (commit_cb) @@ -3974,14 +3984,14 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, mdss_mdp_bwcpanic_ctrl(mdata, true); ATRACE_BEGIN("flush_kickoff"); - mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits); - if (sctl && sctl->flush_bits) { + mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits); + if (sctl && sctl_flush_bits) { mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH, - sctl->flush_bits); + sctl_flush_bits); sctl->flush_bits = 0; } wmb(); - ctl->flush_reg_data = ctl->flush_bits; + ctl->flush_reg_data = ctl_flush_bits; ctl->flush_bits = 0; if (sctl && !ctl->valid_roi && sctl->valid_roi) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index dc9329ca2086..a9c6f8ad4ec7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -761,7 +761,8 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, goto exit_fail; } - if (pipe->mixer_left != mixer) { + if ((pipe->mixer_left != mixer) && + (pipe->type != MDSS_MDP_PIPE_TYPE_CURSOR)) { if (!mixer->ctl || (mixer->ctl->mfd != mfd)) { pr_err("Can't switch mixer %d->%d pnum %d!\n", pipe->mixer_left->num, mixer->num, @@ -848,7 +849,10 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, * staging, same pipe will be stagged on both layer mixers. */ if (mdata->has_src_split) { - if ((mixer_mux == MDSS_MDP_MIXER_MUX_LEFT) && + if ((pipe->type == MDSS_MDP_PIPE_TYPE_CURSOR) && + is_split_lm(mfd)) { + pipe->src_split_req = true; + } else if ((mixer_mux == MDSS_MDP_MIXER_MUX_LEFT) && ((req->dst_rect.x + req->dst_rect.w) > mixer->width)) { if (req->dst_rect.x >= mixer->width) { pr_err("%pS: err dst_x can't lie in right half", @@ -3018,6 +3022,31 @@ static void mdss_mdp_curor_pipe_cleanup(struct msm_fb_data_type *mfd, } } +int mdss_mdp_cursor_flush(struct msm_fb_data_type *mfd, + struct mdss_mdp_pipe *pipe, int cursor_pipe) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + struct mdss_mdp_ctl *sctl = NULL; + u32 flush_bits = BIT(22 + pipe->num - MDSS_MDP_SSPP_CURSOR0); + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + + mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits); + if ((!ctl->split_flush_en) && pipe->mixer_right) { + sctl = mdss_mdp_get_split_ctl(ctl); + if (!sctl) { + pr_err("not able to get the other ctl\n"); + return -ENODEV; + } + mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits); + } + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); + + return 0; +} + static int mdss_mdp_cursor_pipe_setup(struct msm_fb_data_type *mfd, struct mdp_overlay *req, int cursor_pipe) { struct mdss_mdp_pipe *pipe; @@ -3056,12 +3085,23 @@ static int mdss_mdp_cursor_pipe_setup(struct msm_fb_data_type *mfd, ret = -ENOMEM; goto done; } - mdp5_data->cursor_ndx[cursor_pipe] = pipe->ndx; buf->p[0].addr = cursor_addr; - buf->p[0].len = MDSS_MDP_CURSOR_SIZE; + buf->p[0].len = mdss_mdp_get_cursor_frame_size(mdata); buf->num_planes = 1; + buf->state = MDP_BUF_STATE_ACTIVE; + if (!(req->flags & MDP_SOLID_FILL)) + ret = mdss_mdp_pipe_queue_data(pipe, buf); + else + ret = mdss_mdp_pipe_queue_data(pipe, NULL); + + if (ret) { + pr_err("cursor pipe queue data failed in async mode\n"); + return ret; + } + + ret = mdss_mdp_cursor_flush(mfd, pipe, cursor_pipe); done: if (ret && mdp5_data->cursor_ndx[cursor_pipe] == MSMFB_NEW_REQUEST) mdss_mdp_overlay_release(mfd, pipe->ndx); @@ -3079,12 +3119,14 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, struct mdp_overlay *req = NULL; struct mdss_rect roi; int ret = 0; - u32 xres = mfd->fbi->var.xres; - u32 yres = mfd->fbi->var.yres; + struct fb_var_screeninfo *var = &mfd->fbi->var; + u32 xres = var->xres; + u32 yres = var->yres; u32 start_x = img->dx; u32 start_y = img->dy; u32 left_lm_w = left_lm_w_from_mfd(mfd); struct platform_device *pdev = mfd->pdev; + u32 cursor_frame_size = mdss_mdp_get_cursor_frame_size(mdata); ret = mutex_lock_interruptible(&mdp5_data->ov_lock); if (ret) @@ -3109,8 +3151,7 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, if (!mfd->cursor_buf && (cursor->set & FB_CUR_SETIMAGE)) { ret = mdss_smmu_dma_alloc_coherent(&pdev->dev, - MDSS_MDP_CURSOR_SIZE, - (dma_addr_t *) &mfd->cursor_buf_phys, + cursor_frame_size, (dma_addr_t *) &mfd->cursor_buf_phys, &mfd->cursor_buf_iova, mfd->cursor_buf, GFP_KERNEL, MDSS_IOMMU_DOMAIN_UNSECURE); if (ret) { @@ -3122,13 +3163,6 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, mixer->cursor_hoty = 0; } - if ((img->width > MDSS_MDP_CURSOR_WIDTH) || - (img->height > MDSS_MDP_CURSOR_HEIGHT) || - (img->depth != 32) || (start_x >= xres) || (start_y >= yres)) { - ret = -EINVAL; - goto done; - } - pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable, cursor->set); @@ -3163,9 +3197,17 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, roi.w = min(xres - start_x, img->width - roi.x); roi.h = min(yres - start_y, img->height - roi.y); + if ((roi.w > mdata->max_cursor_size) || + (roi.h > mdata->max_cursor_size) || + (img->depth != 32) || (start_x >= xres) || (start_y >= yres)) { + ret = -EINVAL; + goto done; + } + req = kzalloc(sizeof(struct mdp_overlay), GFP_KERNEL); if (!req) { - pr_err("not able to allocate memory for req\n"); + pr_err("not able to allocate memory for cursor req\n"); + ret = -ENOMEM; goto done; } @@ -3174,19 +3216,18 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, req->src.width = img->width; req->src.height = img->height; - req->src.format = MDP_ARGB_8888; + req->src.format = mfd->fb_imgType; - mdss_mdp_set_rect(&req->src_rect, roi.x, roi.y, img->width, - img->height); + mdss_mdp_set_rect(&req->src_rect, roi.x, roi.y, roi.w, roi.h); mdss_mdp_set_rect(&req->dst_rect, start_x, start_y, roi.w, roi.h); req->bg_color = img->bg_color; - req->alpha = (img->fg_color & 0xff000000) >> 24; - if (req->alpha == 0xff) - req->blend_op = BLEND_OP_OPAQUE; + req->alpha = (img->fg_color >> ((32 - var->transp.offset) - 8)) & 0xff; + if (req->alpha) + req->blend_op = BLEND_OP_PREMULTIPLIED; else req->blend_op = BLEND_OP_COVERAGE; - req->transp_mask = (img->bg_color & 0xffffff); + req->transp_mask = img->bg_color & ~(0xff << var->transp.offset); if (mfd->cursor_buf && (cursor->set & FB_CUR_SETIMAGE)) { ret = copy_from_user(mfd->cursor_buf, img->data, @@ -3200,30 +3241,58 @@ static int mdss_mdp_hw_cursor_pipe_update(struct msm_fb_data_type *mfd, mixer->cursor_hoty = 0; } - if (start_x + roi.w <= left_lm_w) { + /* + * When source split is enabled, only CURSOR_PIPE_LEFT is used, + * with both mixers of the pipe staged all the time. + * When source split is disabled, 2 pipes are staged, with one + * pipe containing the actual data and another one a transparent + * solid fill when the data falls only in left or right dsi. + * Both are done to support async cursor functionality. + */ + if (mdata->has_src_split || (!is_split_lm(mfd)) + || (mdata->ncursor_pipes == 1)) { ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_LEFT); - mdss_mdp_curor_pipe_cleanup(mfd, CURSOR_PIPE_RIGHT); + } else if ((start_x + roi.w) <= left_lm_w) { + ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_LEFT); + if (ret) + goto done; + req->bg_color = 0; + req->flags |= MDP_SOLID_FILL; + req->dst_rect.x = left_lm_w; + ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_RIGHT); } else if (start_x >= left_lm_w) { ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_RIGHT); - mdss_mdp_curor_pipe_cleanup(mfd, CURSOR_PIPE_LEFT); - } else { + if (ret) + goto done; + req->bg_color = 0; + req->flags |= MDP_SOLID_FILL; + req->dst_rect.x = 0; + ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_LEFT); + } else if ((start_x <= left_lm_w) && ((start_x + roi.w) >= left_lm_w)) { mdss_mdp_set_rect(&req->dst_rect, start_x, start_y, (left_lm_w - start_x), roi.h); mdss_mdp_set_rect(&req->src_rect, 0, 0, (left_lm_w - - start_x), img->height); + start_x), roi.h); ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_LEFT); if (ret) goto done; - mdss_mdp_set_rect(&req->dst_rect, left_lm_w, start_y, - ((start_x + roi.w) - left_lm_w), roi.h); + mdss_mdp_set_rect(&req->dst_rect, left_lm_w, start_y, ((start_x + + roi.w) - left_lm_w), roi.h); mdss_mdp_set_rect(&req->src_rect, (left_lm_w - start_x), 0, - (img->width - (left_lm_w - start_x)), - img->height); + (roi.w - (left_lm_w - start_x)), roi.h); ret = mdss_mdp_cursor_pipe_setup(mfd, req, CURSOR_PIPE_RIGHT); + } else { + pr_err("Invalid case for cursor pipe setup\n"); + ret = -EINVAL; } done: + if (ret) { + mdss_mdp_curor_pipe_cleanup(mfd, CURSOR_PIPE_LEFT); + mdss_mdp_curor_pipe_cleanup(mfd, CURSOR_PIPE_RIGHT); + } + kfree(req); mutex_unlock(&mdp5_data->ov_lock); return ret; @@ -3246,6 +3315,7 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd, u32 start_y = img->dy; u32 left_lm_w = left_lm_w_from_mfd(mfd); struct platform_device *pdev = mfd->pdev; + u32 cursor_frame_size = mdss_mdp_get_cursor_frame_size(mdata); mixer_left = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_DEFAULT); @@ -3260,8 +3330,7 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd, if (!mfd->cursor_buf && (cursor->set & FB_CUR_SETIMAGE)) { ret = mdss_smmu_dma_alloc_coherent(&pdev->dev, - MDSS_MDP_CURSOR_SIZE, - (dma_addr_t *) &mfd->cursor_buf_phys, + cursor_frame_size, (dma_addr_t *) &mfd->cursor_buf_phys, &mfd->cursor_buf_iova, mfd->cursor_buf, GFP_KERNEL, MDSS_IOMMU_DOMAIN_UNSECURE); if (ret) { @@ -3270,8 +3339,8 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd, } } - if ((img->width > MDSS_MDP_CURSOR_WIDTH) || - (img->height > MDSS_MDP_CURSOR_HEIGHT) || + if ((img->width > mdata->max_cursor_size) || + (img->height > mdata->max_cursor_size) || (img->depth != 32) || (start_x >= xres) || (start_y >= yres)) return -EINVAL; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 51cbdafe0835..2ec4d0c7f991 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -1967,10 +1967,13 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, if (params_changed) { pipe->params_changed = 0; - ret = mdss_mdp_pipe_pp_setup(pipe, &opmode); - if (ret) { - pr_err("pipe pp setup error for pnum=%d\n", pipe->num); - goto done; + if (pipe->type != MDSS_MDP_PIPE_TYPE_CURSOR) { + ret = mdss_mdp_pipe_pp_setup(pipe, &opmode); + if (ret) { + pr_err("pipe pp setup error for pnum=%d\n", + pipe->num); + goto done; + } } ret = mdss_mdp_image_setup(pipe, src_data); @@ -1993,10 +1996,10 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, if (test_bit(MDSS_QOS_PER_PIPE_LUT, mdata->mdss_qos_map)) mdss_mdp_pipe_qos_lut(pipe); - mdss_mdp_pipe_panic_signal_ctrl(pipe, true); - - mdss_mdp_set_ot_limit_pipe(pipe); - + if (pipe->type != MDSS_MDP_PIPE_TYPE_CURSOR) { + mdss_mdp_pipe_panic_signal_ctrl(pipe, true); + mdss_mdp_set_ot_limit_pipe(pipe); + } } if (src_data == NULL) {