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) {