diff options
author | Adrian Salido-Moreno <adrianm@codeaurora.org> | 2014-07-20 16:56:03 -0700 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:37:13 -0700 |
commit | 475788307f7af6027626a90d07bfe5189da8ad12 (patch) | |
tree | 15896362a2d8c18b3b6ea7c44f911ad5358e6c8c | |
parent | b9a2fe27d1ed76162cb2b95cf624055599a9817f (diff) |
msm: mdss: refactor pipe buffer handling
Refactor handling of buffers to maintain a queue instead of allowing
only a single copy to be updated. This allows multiple buffers to be
queued and thus can unblock back to back display updates earlier.
Change-Id: I695c0f37ce209f4728fca5ebcb70b6c67430ea83
Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
-rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 5 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 33 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_debug.c | 52 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c | 5 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 277 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_pipe.c | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_splash_logo.c | 10 |
7 files changed, 286 insertions, 100 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index f66913c64e5e..c4551ea831f9 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -2628,7 +2628,7 @@ static int mdss_fb_pan_display_ex(struct fb_info *info, if (var->yoffset > (info->var.yres_virtual - info->var.yres)) return -EINVAL; - ret = mdss_fb_pan_idle(mfd); + ret = mdss_fb_wait_for_kickoff(mfd); if (ret) { pr_err("Shutdown pending. Aborting operation\n"); return ret; @@ -3291,12 +3291,15 @@ static int __ioctl_wait_idle(struct msm_fb_data_type *mfd, u32 cmd) if (mfd->wait_for_kickoff && ((cmd == MSMFB_OVERLAY_PREPARE) || (cmd == MSMFB_BUFFER_SYNC) || + (cmd == MSMFB_OVERLAY_PLAY) || + (cmd == MSMFB_OVERLAY_UNSET) || (cmd == MSMFB_OVERLAY_SET))) { ret = mdss_fb_wait_for_kickoff(mfd); } else if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) && (cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) && + (cmd != MSMFB_DISPLAY_COMMIT) && (cmd != MSMFB_NOTIFY_UPDATE) && (cmd != MSMFB_OVERLAY_PREPARE)) { ret = mdss_fb_pan_idle(mfd); diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 3d96c657db61..90d5607d6ece 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -338,10 +338,23 @@ struct mdss_mdp_img_data { struct sg_table *srcp_table; }; +enum mdss_mdp_data_state { + MDP_BUF_STATE_UNUSED, + MDP_BUF_STATE_READY, + MDP_BUF_STATE_ACTIVE, + MDP_BUF_STATE_CLEANUP, +}; + struct mdss_mdp_data { + enum mdss_mdp_data_state state; u8 num_planes; - u8 bwc_enabled; struct mdss_mdp_img_data p[MAX_PLANES]; + struct list_head buf_list; + struct list_head pipe_list; + struct list_head chunk_list; + u64 last_alloc; + u64 last_freed; + struct mdss_mdp_pipe *last_pipe; }; struct pp_hist_col_info { @@ -478,9 +491,7 @@ struct mdss_mdp_pipe { struct mdss_mdp_pipe_smp_map smp_map[MAX_PLANES]; - struct mdss_mdp_data back_buf; - struct mdss_mdp_data front_buf; - + struct list_head buf_queue; struct list_head list; struct mdp_overlay_pp_params pp_cfg; @@ -510,14 +521,18 @@ struct mdss_overlay_private { struct mdss_mdp_wb *wb; struct mutex list_lock; - struct list_head overlay_list; struct list_head pipes_used; struct list_head pipes_cleanup; struct list_head rot_proc_list; bool mixer_swap; - struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE]; - int free_list_size; + /* list of buffers that can be reused */ + struct list_head bufs_chunks; + struct list_head bufs_pool; + struct list_head bufs_used; + /* list of buffers which should be freed during cleanup stage */ + struct list_head bufs_freelist; + int ad_state; int dyn_pu_state; @@ -852,6 +867,10 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl); int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl); int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, struct mdp_display_commit *data); +struct mdss_mdp_data *mdss_mdp_overlay_buf_alloc(struct msm_fb_data_type *mfd, + struct mdss_mdp_pipe *pipe); +void mdss_mdp_overlay_buf_free(struct msm_fb_data_type *mfd, + struct mdss_mdp_data *buf); struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, struct msm_fb_data_type *mfd); diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index 7be349cebf48..2e00736b8a15 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,6 +12,7 @@ */ #include <linux/debugfs.h> +#include <linux/time.h> #include <linux/seq_file.h> #include "mdss_mdp.h" @@ -19,9 +20,44 @@ #include "mdss_debug.h" #include "mdss_mdp_debug.h" +static void __print_time(char *buf, u32 size, u64 ts) +{ + unsigned long rem_ns = do_div(ts, NSEC_PER_SEC); + + snprintf(buf, size, "%llu.%06lu", ts, rem_ns); +} + +static void __print_buf(struct seq_file *s, struct mdss_mdp_data *buf, + bool show_pipe) +{ + char tmpbuf[20]; + const char const *stmap[] = { + [MDP_BUF_STATE_UNUSED] = "UNUSED ", + [MDP_BUF_STATE_READY] = "READY ", + [MDP_BUF_STATE_ACTIVE] = "ACTIVE ", + [MDP_BUF_STATE_CLEANUP] = "CLEANUP", + }; + + seq_puts(s, "\t"); + if (show_pipe && buf->last_pipe) + seq_printf(s, "pnum=%d ", buf->last_pipe->num); + + seq_printf(s, "state=%s addr=%pa size=%lu ", + buf->state < ARRAY_SIZE(stmap) ? stmap[buf->state] : "?", + &buf->p[0].addr, buf->p[0].len); + + __print_time(tmpbuf, sizeof(tmpbuf), buf->last_alloc); + seq_printf(s, "alloc_time=%s ", tmpbuf); + if (buf->state == MDP_BUF_STATE_UNUSED) { + __print_time(tmpbuf, sizeof(tmpbuf), buf->last_freed); + seq_printf(s, "freed_time=%s ", tmpbuf); + } + seq_puts(s, "\n"); +} + static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe) { - struct mdss_mdp_img_data *buf; + struct mdss_mdp_data *buf; int format; int smps[4]; @@ -55,17 +91,9 @@ static void __dump_pipe(struct seq_file *s, struct mdss_mdp_pipe *pipe) smps[0], smps[1], smps[2], smps[3]); seq_puts(s, "Data:\n"); - if (pipe->front_buf.num_planes) { - buf = pipe->front_buf.p; - seq_printf(s, "\tfront_buf ihdl=0x%p addr=%pa size=%lu\n", - buf->srcp_dma_buf, &buf->addr, buf->len); - } - if (pipe->back_buf.num_planes) { - buf = pipe->back_buf.p; - seq_printf(s, "\tback_buf ihdl=0x%p addr=%pa size=%lu\n", - buf->srcp_dma_buf, &buf->addr, buf->len); - } + list_for_each_entry(buf, &pipe->buf_queue, pipe_list) + __print_buf(s, buf, false); } static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c index 15910f4d430a..e93d59810d26 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -131,9 +131,6 @@ static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx, pr_debug("wb_num=%d addr=0x%pa\n", ctx->wb_num, &data.p[0].addr); - if (ctx->bwc_mode) - data.bwc_enabled = 1; - ret = mdss_mdp_data_check(&data, &ctx->dst_planes, ctx->dst_fmt); if (ret) return ret; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index e7d1ea7f81c7..f04202b820d7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -44,6 +44,8 @@ #define IS_RIGHT_MIXER_OV(flags, dst_x, left_lm_w) \ ((flags & MDSS_MDP_RIGHT_MIXER) || (dst_x >= left_lm_w)) +#define BUF_POOL_SIZE 32 + static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd); static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd); static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd); @@ -1011,6 +1013,86 @@ static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd, return ret; } +struct mdss_mdp_data *mdss_mdp_overlay_buf_alloc(struct msm_fb_data_type *mfd, + struct mdss_mdp_pipe *pipe) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_data *buf; + int i; + + if (list_empty(&mdp5_data->bufs_pool)) { + pr_debug("allocating %u bufs for fb%d\n", + BUF_POOL_SIZE, mfd->index); + + buf = kzalloc(sizeof(*buf) * BUF_POOL_SIZE, GFP_KERNEL); + if (!buf) { + pr_err("Unable to allocate buffer pool\n"); + return NULL; + } + + list_add(&buf->chunk_list, &mdp5_data->bufs_chunks); + for (i = 0; i < BUF_POOL_SIZE; i++) + list_add(&buf[i].buf_list, &mdp5_data->bufs_pool); + } + + buf = list_first_entry(&mdp5_data->bufs_pool, + struct mdss_mdp_data, buf_list); + list_move_tail(&buf->buf_list, &mdp5_data->bufs_used); + buf->last_alloc = local_clock(); + buf->last_pipe = pipe; + + list_add_tail(&buf->pipe_list, &pipe->buf_queue); + buf->state = MDP_BUF_STATE_READY; + + pr_debug("buffer alloc: %p\n", buf); + + return buf; +} + +static void mdss_mdp_overlay_buf_deinit(struct msm_fb_data_type *mfd) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_data *buf, *t; + + pr_debug("performing cleanup of buffers pool on fb%d\n", mfd->index); + + BUG_ON(!list_empty(&mdp5_data->bufs_used)); + + list_for_each_entry_safe(buf, t, &mdp5_data->bufs_pool, buf_list) + list_del(&buf->buf_list); + + list_for_each_entry_safe(buf, t, &mdp5_data->bufs_chunks, chunk_list) { + list_del(&buf->chunk_list); + kfree(buf); + } +} + +void mdss_mdp_overlay_buf_free(struct msm_fb_data_type *mfd, + struct mdss_mdp_data *buf) +{ + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + + if (!list_empty(&buf->pipe_list)) + list_del_init(&buf->pipe_list); + + mdss_mdp_data_free(buf); + + buf->last_freed = local_clock(); + buf->state = MDP_BUF_STATE_UNUSED; + + pr_debug("buffer freed: %p\n", buf); + + list_move_tail(&buf->buf_list, &mdp5_data->bufs_pool); +} + +static inline void __pipe_buf_mark_cleanup(struct msm_fb_data_type *mfd, + struct mdss_mdp_data *buf) +{ + /* buffer still in bufs_used, marking it as cleanup will clean it up */ + buf->state = MDP_BUF_STATE_CLEANUP; + list_del_init(&buf->pipe_list); +} + /** * __mdss_mdp_overlay_free_list_purge() - clear free list of buffers * @mfd: Msm frame buffer data structure for the associated fb @@ -1020,34 +1102,33 @@ static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd, static void __mdss_mdp_overlay_free_list_purge(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); - int i; + struct mdss_mdp_data *buf, *t; pr_debug("purging fb%d free list\n", mfd->index); - for (i = 0; i < mdp5_data->free_list_size; i++) - mdss_mdp_data_free(&mdp5_data->free_list[i]); - mdp5_data->free_list_size = 0; + + list_for_each_entry_safe(buf, t, &mdp5_data->bufs_freelist, buf_list) + mdss_mdp_overlay_buf_free(mfd, buf); } -/** - * __mdss_mdp_overlay_free_list_add() - add a buffer to free list - * @mfd: Msm frame buffer data structure for the associated fb - */ -static void __mdss_mdp_overlay_free_list_add(struct msm_fb_data_type *mfd, - struct mdss_mdp_data *buf) +static void __overlay_pipe_cleanup(struct msm_fb_data_type *mfd, + struct mdss_mdp_pipe *pipe) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); - int i; + struct mdss_mdp_data *buf, *tmpbuf; + + list_for_each_entry_safe(buf, tmpbuf, &pipe->buf_queue, pipe_list) { + __pipe_buf_mark_cleanup(mfd, buf); + list_move(&buf->buf_list, &mdp5_data->bufs_freelist); - /* if holding too many buffers free current list */ - if (mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE) { - pr_warn("max free list size for fb%d, purging\n", mfd->index); - __mdss_mdp_overlay_free_list_purge(mfd); + /* + * in case of secure UI, the buffer needs to be released as + * soon as session is closed. + */ + if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION) + mdss_mdp_overlay_buf_free(mfd, buf); } - BUG_ON(mdp5_data->free_list_size >= MAX_FREE_LIST_SIZE); - i = mdp5_data->free_list_size++; - mdp5_data->free_list[i] = *buf; - memset(buf, 0, sizeof(*buf)); + mdss_mdp_pipe_destroy(pipe); } /** @@ -1065,6 +1146,7 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd, struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); bool recovery_mode = false; + struct mdss_mdp_data *buf, *tmpbuf; mutex_lock(&mdp5_data->list_lock); list_for_each_entry(pipe, destroy_pipes, list) { @@ -1094,30 +1176,18 @@ static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd, __mdss_mdp_overlay_free_list_purge(mfd); - list_for_each_entry(pipe, &mdp5_data->pipes_used, list) { - if (pipe->back_buf.num_planes) { - /* make back buffer active */ - __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf); - swap(pipe->back_buf, pipe->front_buf); - } + list_for_each_entry_safe(buf, tmpbuf, &mdp5_data->bufs_used, buf_list) { + if (buf->state == MDP_BUF_STATE_CLEANUP) + list_move(&buf->buf_list, &mdp5_data->bufs_freelist); } list_for_each_entry_safe(pipe, tmp, destroy_pipes, list) { - /* - * in case of secure UI, the buffer needs to be released as - * soon as session is closed. - */ - if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION) - mdss_mdp_data_free(&pipe->front_buf); - else - __mdss_mdp_overlay_free_list_add(mfd, &pipe->front_buf); - mdss_mdp_data_free(&pipe->back_buf); list_del_init(&pipe->list); if (recovery_mode) { mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); } - mdss_mdp_pipe_destroy(pipe); + __overlay_pipe_cleanup(mfd, pipe); } mutex_unlock(&mdp5_data->list_lock); } @@ -1322,29 +1392,62 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) MDSS_MDP_MIXER_MUX_DEFAULT); } - /* ensure pipes are always reconfigured after power off/on */ + buf = list_first_entry_or_null(&pipe->buf_queue, + struct mdss_mdp_data, pipe_list); + if (buf) { + switch (buf->state) { + case MDP_BUF_STATE_READY: + pr_debug("pnum=%d buf=%p first buffer ready\n", + pipe->num, buf); + break; + case MDP_BUF_STATE_ACTIVE: + if (list_is_last(&buf->pipe_list, + &pipe->buf_queue)) { + pr_debug("pnum=%d no buf update\n", + pipe->num); + } else { + struct mdss_mdp_data *tmp = buf; + /* + * buffer flip, new buffer will + * replace currently active one, + * mark currently active for cleanup + */ + buf = list_next_entry(tmp, pipe_list); + __pipe_buf_mark_cleanup(mfd, tmp); + } + break; + default: + pr_err("invalid state of buf %p=%d\n", + buf, buf->state); + BUG(); + break; + } + } + + /* ensure pipes are reconfigured after power off/on */ if (ctl->play_cnt == 0) pipe->params_changed++; - if (pipe->back_buf.num_planes) { - buf = &pipe->back_buf; - + if (buf && (buf->state == MDP_BUF_STATE_READY)) { + buf->state = MDP_BUF_STATE_ACTIVE; ret = mdss_mdp_data_map(buf); } else if (!pipe->params_changed) { + /* nothing to update so continue with next */ continue; - } else if (pipe->front_buf.num_planes) { - buf = &pipe->front_buf; - } else { - pr_debug("no buf detected pnum=%d use solid fill\n", - pipe->num); - if ((pipe->flags & MDP_SOLID_FILL) == 0) { - pr_warn("commit without buffer on pipe %d\n", + } else if (buf) { + BUG_ON(buf->state != MDP_BUF_STATE_ACTIVE); + pr_debug("requeueing active buffer on pnum=%d\n", pipe->num); - ret = -EINVAL; - } - buf = NULL; + } else if ((pipe->flags & MDP_SOLID_FILL) == 0) { + pr_warn("commit without buffer on pipe %d\n", + pipe->num); + ret = -EINVAL; } + /* + * if we reach here without errors and buf == NULL + * then solid fill will be set + */ if (!IS_ERR_VALUE(ret)) ret = mdss_mdp_pipe_queue_data(pipe, buf); @@ -1353,6 +1456,9 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) pipe->num); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); + + if (buf) + __pipe_buf_mark_cleanup(mfd, buf); } } @@ -1644,16 +1750,15 @@ int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx) pipe->pid = 0; destroy_pipe = pipe->play_cnt == 0; - - if (destroy_pipe) - list_del_init(&pipe->list); - else + if (!destroy_pipe) list_move(&pipe->list, &mdp5_data->pipes_cleanup); + else + list_del_init(&pipe->list); mdss_mdp_pipe_unmap(pipe); if (destroy_pipe) - mdss_mdp_pipe_destroy(pipe); + __overlay_pipe_cleanup(mfd, pipe); if (unset_ndx == ndx) break; @@ -1789,6 +1894,7 @@ static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd, static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd, struct msmfb_overlay_data *req) { + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_pipe *pipe; struct mdss_mdp_data *src_data; int ret; @@ -1814,17 +1920,20 @@ static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd, flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION); - src_data = &pipe->back_buf; - if (src_data->num_planes) { - pr_warn("dropped buffer pnum=%d play=%d addr=0x%pa\n", - pipe->num, pipe->play_cnt, &src_data->p[0].addr); - mdss_mdp_data_free(src_data); + mutex_lock(&mdp5_data->list_lock); + src_data = mdss_mdp_overlay_buf_alloc(mfd, pipe); + if (!src_data) { + pr_err("unable to allocate source buffer\n"); + ret = -ENOMEM; + } else { + ret = mdss_mdp_data_get(src_data, &req->data, 1, flags, + &mfd->pdev->dev); + if (IS_ERR_VALUE(ret)) { + mdss_mdp_overlay_buf_free(mfd, src_data); + pr_err("src_data pmem error\n"); + } } - - ret = mdss_mdp_data_get(src_data, &req->data, 1, flags, - &mfd->pdev->dev); - if (IS_ERR_VALUE(ret)) - pr_err("src_data pmem error\n"); + mutex_unlock(&mdp5_data->list_lock); mdss_mdp_pipe_unmap(pipe); @@ -1952,7 +2061,7 @@ static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd, static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) { - struct mdss_mdp_data *buf; + struct mdss_mdp_data *buf_l = NULL, *buf_r = NULL; struct mdss_mdp_pipe *pipe; struct fb_info *fbi; struct mdss_overlay_private *mdp5_data; @@ -2023,21 +2132,27 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) goto pan_display_error; } - buf = &pipe->back_buf; + buf_l = mdss_mdp_overlay_buf_alloc(mfd, pipe); + if (!buf_l) { + pr_err("unable to allocate memory for fb buffer\n"); + goto pan_display_error; + } + if (mdata->mdss_util->iommu_attached()) { if (!mfd->iova) { pr_err("mfd iova is zero\n"); mdss_mdp_pipe_unmap(pipe); goto pan_display_error; } - buf->p[0].addr = mfd->iova; + buf_l->p[0].addr = mfd->iova; } else { - buf->p[0].addr = fbi->fix.smem_start; + buf_l->p[0].addr = fbi->fix.smem_start; } - buf->p[0].addr += offset; - buf->p[0].len = fbi->fix.smem_len - offset; - buf->num_planes = 1; + buf_l->p[0].addr += offset; + buf_l->p[0].len = fbi->fix.smem_len - offset; + buf_l->num_planes = 1; + mdss_mdp_pipe_unmap(pipe); if (fbi->var.xres > mdata->max_pipe_width || is_split_lm(mfd)) { @@ -2056,7 +2171,15 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) goto pan_display_error; } - pipe->back_buf = *buf; + buf_r = mdss_mdp_overlay_buf_alloc(mfd, pipe); + if (!buf_r) { + pr_err("unable to allocate memory for fb buffer\n"); + goto pan_display_error; + } + + buf_r->p[0] = buf_l->p[0]; + buf_r->num_planes = 1; + mdss_mdp_pipe_unmap(pipe); } mutex_unlock(&mdp5_data->ov_lock); @@ -2070,6 +2193,10 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd) return; pan_display_error: + if (buf_l) + mdss_mdp_overlay_buf_free(mfd, buf_l); + if (buf_r) + mdss_mdp_overlay_buf_free(mfd, buf_r); mdss_iommu_ctrl(0); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); mutex_unlock(&mdp5_data->ov_lock); @@ -4007,6 +4134,8 @@ ctl_stop: if (mdss_fb_is_power_off(mfd)) { mutex_lock(&mdp5_data->list_lock); __mdss_mdp_overlay_free_list_purge(mfd); + if (!mfd->ref_cnt) + mdss_mdp_overlay_buf_deinit(mfd); mutex_unlock(&mdp5_data->list_lock); mdss_mdp_ctl_notifier_unregister(mdp5_data->ctl, &mfd->mdp_sync_pt_data.notifier); @@ -4351,6 +4480,10 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) INIT_LIST_HEAD(&mdp5_data->pipes_used); INIT_LIST_HEAD(&mdp5_data->pipes_cleanup); + INIT_LIST_HEAD(&mdp5_data->bufs_pool); + INIT_LIST_HEAD(&mdp5_data->bufs_chunks); + INIT_LIST_HEAD(&mdp5_data->bufs_used); + INIT_LIST_HEAD(&mdp5_data->bufs_freelist); INIT_LIST_HEAD(&mdp5_data->rot_proc_list); mutex_init(&mdp5_data->list_lock); mutex_init(&mdp5_data->ov_lock); diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index b094a1406046..10f380111a72 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -903,6 +903,7 @@ static struct mdss_mdp_pipe *mdss_mdp_pipe_init(struct mdss_mdp_mixer *mixer, mutex_init(&pipe->pp_res.hist.hist_mutex); spin_lock_init(&pipe->pp_res.hist.hist_lock); kref_init(&pipe->kref); + INIT_LIST_HEAD(&pipe->buf_queue); is_realtime = !((mixer->ctl->intf_num == MDSS_MDP_NO_INTF) || mixer->rotator_mode); mdss_mdp_qos_vbif_remapper_setup(mdata, pipe, is_realtime); @@ -1333,6 +1334,7 @@ int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe) pipe->is_handed_off = true; pipe->play_cnt = 1; kref_init(&pipe->kref); + INIT_LIST_HEAD(&pipe->buf_queue); error: return rc; @@ -1593,8 +1595,6 @@ static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe, pr_debug("pnum=%d\n", pipe->num); - data.bwc_enabled = pipe->bwc_mode; - ret = mdss_mdp_data_check(&data, &pipe->src_planes, pipe->src_fmt); if (ret) return ret; diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c index 250021d82eeb..6632342c6db4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c +++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -336,7 +336,13 @@ static struct mdss_mdp_pipe *mdss_mdp_splash_get_pipe( return NULL; } - buf = &pipe->back_buf; + buf = mdss_mdp_overlay_buf_alloc(mfd, pipe); + if (!buf) { + pr_err("unable to allocate memory for splash buffer\n"); + mdss_mdp_pipe_unmap(pipe); + return NULL; + } + buf->p[0].addr = mfd->splash_info.iova; buf->p[0].len = image_size; buf->num_planes = 1; |