diff options
| author | Terence Hampson <thampson@codeaurora.org> | 2013-05-08 19:01:51 -0400 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:17:35 -0700 |
| commit | 705f82de26a28e113e1c321488b8e57eb4132844 (patch) | |
| tree | 4d31a346cba82c73f6b8beb1316dcff3188fd23d | |
| parent | 8f86ee9d1669a7af3dd79051a1dc810f30f1f1b5 (diff) | |
mdss: ppp: add sync point to ppp, allowing for async ppp blit
It is a requirement that PPP be async and should use sync points
and fences to wait for buffers and communicate that it is done
using release fence
Change-Id: I35663737dd4bd4a52bb12b2a31ed06f3d5a69f31
Signed-off-by: Terence Hampson <thampson@codeaurora.org>
[cip@codeaurora.org: Updated sync.h/sw_sync.h include]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3.c | 18 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3.h | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_ctrl.c | 74 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_ppp.c | 425 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_ppp.h | 9 | ||||
| -rw-r--r-- | include/uapi/linux/msm_mdp.h | 7 |
6 files changed, 429 insertions, 106 deletions
diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c index 1a602e252c52..58d4fd7adc0f 100644 --- a/drivers/video/fbdev/msm/mdp3.c +++ b/drivers/video/fbdev/msm/mdp3.c @@ -394,7 +394,8 @@ static int mdp3_clk_update(u32 clk_idx, u32 enable) -int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate) +int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, + int client) { int ret = 0; unsigned long rounded_rate; @@ -408,6 +409,19 @@ int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate) mutex_unlock(&mdp3_res->res_mutex); return -EINVAL; } + if (clk_type == MDP3_CLK_CORE) { + if (client == MDP3_CLIENT_DMA_P) { + mdp3_res->dma_core_clk_request = rounded_rate; + } else if (client == MDP3_CLIENT_PPP) { + mdp3_res->ppp_core_clk_request = rounded_rate; + } else { + pr_err("unrecognized client=%d\n", client); + mutex_unlock(&mdp3_res->res_mutex); + return -EINVAL; + } + rounded_rate = max(mdp3_res->dma_core_clk_request, + mdp3_res->ppp_core_clk_request); + } if (rounded_rate != clk_get_rate(clk)) { ret = clk_set_rate(clk, rounded_rate); if (ret) @@ -949,7 +963,7 @@ static int mdp3_init(struct msm_fb_data_type *mfd) { int rc; rc = mdp3_ctrl_init(mfd); - rc |= mdp3_ppp_res_init(); + rc |= mdp3_ppp_res_init(mfd); return rc; } diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h index 47635811064c..7b775f9e46ef 100644 --- a/drivers/video/fbdev/msm/mdp3.h +++ b/drivers/video/fbdev/msm/mdp3.h @@ -137,7 +137,7 @@ void mdp3_irq_enable(int type); void mdp3_irq_disable(int type); void mdp3_irq_disable_nosync(int type); int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb); -int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate); +int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client); int mdp3_clk_enable(int enable); int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota); int mdp3_put_img(struct mdp3_img_data *data); diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 9c572a5ee928..ce68013c945f 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -130,52 +130,41 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) return 0; } -static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p) +static int mdp3_ctrl_async_blit_req(struct msm_fb_data_type *mfd, + void __user *p) { - const int MAX_LIST_WINDOW = 16; - struct mdp_blit_req req_list[MAX_LIST_WINDOW]; - struct mdp_blit_req_list req_list_header; - int rc, count, i, req_list_count; + struct mdp_async_blit_req_list req_list_header; + int rc, count; + void __user *p_req; if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) return -EFAULT; - p += sizeof(req_list_header); + p_req = p + sizeof(req_list_header); count = req_list_header.count; if (count < 0 || count >= MAX_BLIT_REQ) return -EINVAL; - while (count > 0) { - /* - * Access the requests through a narrow window to decrease copy - * overhead and make larger requests accessible to the - * coherency management code. - * NOTE: The window size is intended to be larger than the - * typical request size, but not require more than 2 - * kbytes of stack storage. - */ - req_list_count = count; - if (req_list_count > MAX_LIST_WINDOW) - req_list_count = MAX_LIST_WINDOW; - if (copy_from_user(&req_list, p, - sizeof(struct mdp_blit_req)*req_list_count)) - return -EFAULT; - /* - * Do the blit DMA, if required -- returning early only if - * there is a failure. - */ - for (i = 0; i < req_list_count; i++) { - if (!(req_list[i].flags & MDP_NO_BLIT)) { - /* Do the actual blit. */ - rc = mdp3_ppp_start_blit(mfd, &(req_list[i])); - if (rc) - return rc; - } - } + rc = mdp3_ppp_parse_req(p_req, &req_list_header, 1); + if (!rc) + rc = copy_to_user(p, &req_list_header, sizeof(req_list_header)); + return rc; +} - /* Go to next window of requests. */ - count -= req_list_count; - p += sizeof(struct mdp_blit_req)*req_list_count; - } - return 0; +static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p) +{ + struct mdp_async_blit_req_list req_list_header; + int rc, count; + void __user *p_req; + + if (copy_from_user(&(req_list_header.count), p, + sizeof(struct mdp_blit_req_list))) + return -EFAULT; + p_req = p + sizeof(struct mdp_blit_req_list); + count = req_list_header.count; + if (count < 0 || count >= MAX_BLIT_REQ) + return -EINVAL; + req_list_header.sync.acq_fen_fd_cnt = 0; + rc = mdp3_ppp_parse_req(p_req, &req_list_header, 0); + return rc; } static ssize_t mdp3_vsync_show_event(struct device *dev, @@ -239,8 +228,10 @@ static int mdp3_ctrl_res_req_clk(struct msm_fb_data_type *mfd, int status) int rc = 0; if (status) { - mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE); - mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE); + mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE, + MDP3_CLIENT_DMA_P); + mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE, + MDP3_CLIENT_DMA_P); rc = mdp3_clk_enable(true); if (rc) @@ -745,6 +736,9 @@ static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd, rc = -EFAULT; } break; + case MSMFB_ASYNC_BLIT: + rc = mdp3_ctrl_async_blit_req(mfd, argp); + break; case MSMFB_BLIT: rc = mdp3_ctrl_blit_req(mfd, argp); break; diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c index 7164086a3ecd..e82fcba72f9f 100644 --- a/drivers/video/fbdev/msm/mdp3_ppp.c +++ b/drivers/video/fbdev/msm/mdp3_ppp.c @@ -20,6 +20,10 @@ #include <linux/uaccess.h> #include <linux/sched.h> #include <linux/mutex.h> + +#include <sync.h> +#include <sw_sync.h> + #include "linux/proc_fs.h" #include "mdss_fb.h" @@ -28,6 +32,10 @@ #include "mdp3.h" #define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT) +#define MDP_BLIT_CLK_RATE 200000000 +#define MDP_PPP_MAX_BPP 4 +#define MDP_PPP_DYNAMIC_FACTOR 3 +#define MDP_PPP_MAX_READ_WRITE 3 static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = { [MDP_RGB_565] = true, @@ -47,11 +55,45 @@ static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = { [MDP_Y_CRCB_H2V1] = true, }; +#define MAX_LIST_WINDOW 16 +#define MDP3_PPP_MAX_LIST_REQ 8 + +struct blit_req_list { + int count; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp3_img_data src_data[MAX_LIST_WINDOW]; + struct mdp3_img_data dst_data[MAX_LIST_WINDOW]; + struct sync_fence *acq_fen[MDP_MAX_FENCE_FD]; + u32 acq_fen_cnt; + int cur_rel_fen_fd; + struct sync_pt *cur_rel_sync_pt; + struct sync_fence *cur_rel_fence; + struct sync_fence *last_rel_fence; +}; + +struct blit_req_queue { + struct blit_req_list req[MDP3_PPP_MAX_LIST_REQ]; + int count; + int push_idx; + int pop_idx; +}; + struct ppp_status { int busy; + bool wait_for_pop; spinlock_t ppp_lock; struct completion ppp_comp; - struct mutex config_mutex; + struct completion pop_q_comp; + struct mutex req_mutex; /* Protect request queue */ + struct mutex config_ppp_mutex; /* Only one client configure register */ + struct msm_fb_data_type *mfd; + + struct work_struct blit_work; + struct blit_req_queue req_q; + + struct sw_sync_timeline *timeline; + int timeline_value; + }; static struct ppp_status *ppp_stat; @@ -295,24 +337,22 @@ void mdp3_ppp_kickoff(void) mdp3_ppp_pipe_wait(); } -int mdp3_ppp_turnon(struct ppp_blit_op *blit_op, int on_off) +int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off) { - unsigned long clk_rate = 0, dst_rate = 0, src_rate = 0; - int ab = 0; - int ib = 0; + struct mdss_panel_info *panel_info = mfd->panel_info; + int ab = 0, ib = 0; + int rate = 0; + if (on_off) { - dst_rate = blit_op->dst.roi.width * blit_op->dst.roi.height; - src_rate = blit_op->src.roi.width * blit_op->src.roi.height; - clk_rate = max(dst_rate, src_rate); - clk_rate = clk_rate * 36 * 12; - - ab = blit_op->dst.roi.width * blit_op->dst.roi.height * - ppp_bpp(blit_op->dst.color_fmt) * 2 + - blit_op->src.roi.width * blit_op->src.roi.height * - ppp_bpp(blit_op->src.color_fmt); - ab = ab * 120; + rate = MDP_BLIT_CLK_RATE; + ab = panel_info->xres * panel_info->yres * + panel_info->mipi.frame_rate * + MDP_PPP_MAX_BPP * + MDP_PPP_DYNAMIC_FACTOR * + MDP_PPP_MAX_READ_WRITE; ib = (ab * 3) / 2; } + mdp3_clk_set_rate(MDP3_CLK_CORE, rate, MDP3_CLIENT_PPP); mdp3_clk_enable(on_off); mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib); return 0; @@ -322,10 +362,8 @@ void mdp3_start_ppp(struct ppp_blit_op *blit_op) { /* Wait for the pipe to clear */ do { } while (mdp3_ppp_pipe_wait() <= 0); - mutex_lock(&ppp_stat->config_mutex); config_ppp_op_mode(blit_op); mdp3_ppp_kickoff(); - mutex_unlock(&ppp_stat->config_mutex); } static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op, @@ -504,7 +542,7 @@ static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op, } } -static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd, +static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req, struct mdp3_img_data *src_data, struct mdp3_img_data *dst_data) { @@ -524,8 +562,6 @@ static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd, mdp3_ppp_process_req(&blit_op, req, src_data, dst_data); - mdp3_ppp_turnon(&blit_op, 1); - if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) || (req->src.format == MDP_ARGB_8888) || (req->src.format == MDP_BGRA_8888) || @@ -536,41 +572,13 @@ static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd, mdp3_start_ppp(&blit_op); } - /* MDP cmd block disable */ - mdp3_ppp_turnon(&blit_op, 0); - return 0; } -static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req) -{ - struct mdp3_img_data src_data; - struct mdp3_img_data dst_data; - int rc; - mdp3_ppp_iommu_attach(); - - mdp3_ppp_get_img(&req->src, req, &src_data); - if (src_data.len == 0) { - pr_err("mdp_ppp: couldn't retrieve src img from mem\n"); - return -EINVAL; - } - - mdp3_ppp_get_img(&req->dst, req, &dst_data); - if (dst_data.len == 0) { - mdp3_put_img(&src_data); - pr_err("mdp_ppp: couldn't retrieve dest img from mem\n"); - return -EINVAL; - } - - rc = mdp3_ppp_blit_addr(mfd, req, &src_data, &dst_data); - mdp3_put_img(&src_data); - mdp3_put_img(&dst_data); - mdp3_ppp_iommu_dettach(); - return rc; -} - static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd, - struct mdp_blit_req *req, unsigned int remainder) + struct mdp_blit_req *req, unsigned int remainder, + struct mdp3_img_data *src_data, + struct mdp3_img_data *dst_data) { int ret; struct mdp_blit_req splitreq; @@ -669,7 +677,7 @@ static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd, } /* No need to split in height */ - ret = mdp3_ppp_blit(mfd, &splitreq); + ret = mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data); if (ret) return ret; @@ -698,11 +706,13 @@ static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd, } /* No need to split in height ... just width */ - return mdp3_ppp_blit(mfd, &splitreq); + return mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data); } int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd, - struct mdp_blit_req *req) + struct mdp_blit_req *req, + struct mdp3_img_data *src_data, + struct mdp3_img_data *dst_data) { int ret; unsigned int remainder = 0, is_bpp_4 = 0; @@ -742,19 +752,316 @@ int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd, is_bpp_4 = (ret == 4) ? 1 : 0; if ((is_bpp_4 && (remainder == 6 || remainder == 14))) - ret = mdp3_ppp_blit_workaround(mfd, req, remainder); + ret = mdp3_ppp_blit_workaround(mfd, req, remainder, + src_data, dst_data); else - ret = mdp3_ppp_blit(mfd, req); + ret = mdp3_ppp_blit(mfd, req, src_data, dst_data); + mdp3_put_img(src_data); + mdp3_put_img(dst_data); return ret; } -int mdp3_ppp_res_init(void) +void mdp3_ppp_wait_for_fence(struct blit_req_list *req) { - ppp_stat = kmalloc(sizeof(struct ppp_status), GFP_KERNEL); + int i, ret = 0; + /* buf sync */ + for (i = 0; i < req->acq_fen_cnt; i++) { + ret = sync_fence_wait(req->acq_fen[i], + WAIT_FENCE_FINAL_TIMEOUT); + if (ret < 0) { + pr_err("%s: sync_fence_wait failed! ret = %x\n", + __func__, ret); + break; + } + sync_fence_put(req->acq_fen[i]); + } + + if (ret < 0) { + while (i < req->acq_fen_cnt) { + sync_fence_put(req->acq_fen[i]); + i++; + } + } + req->acq_fen_cnt = 0; +} + +void mdp3_ppp_signal_timeline(struct blit_req_list *req) +{ + sw_sync_timeline_inc(ppp_stat->timeline, 1); + req->last_rel_fence = req->cur_rel_fence; + req->cur_rel_fence = 0; +} + + +static void mdp3_ppp_deinit_buf_sync(struct blit_req_list *req) +{ + int i; + + put_unused_fd(req->cur_rel_fen_fd); + sync_fence_put(req->cur_rel_fence); + req->cur_rel_fence = NULL; + req->cur_rel_fen_fd = 0; + ppp_stat->timeline_value--; + for (i = 0; i < req->acq_fen_cnt; i++) + sync_fence_put(req->acq_fen[i]); + req->acq_fen_cnt = 0; +} + +static int mdp3_ppp_handle_buf_sync(struct blit_req_list *req, + struct mdp_buf_sync *buf_sync) +{ + int i, fence_cnt = 0, ret = 0; + int acq_fen_fd[MDP_MAX_FENCE_FD]; + struct sync_fence *fence; + + if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) || + (ppp_stat->timeline == NULL)) + return -EINVAL; + + if (buf_sync->acq_fen_fd_cnt) + ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd, + buf_sync->acq_fen_fd_cnt * sizeof(int)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) { + fence = sync_fence_fdget(acq_fen_fd[i]); + if (fence == NULL) { + pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, + acq_fen_fd[i]); + ret = -EINVAL; + break; + } + req->acq_fen[i] = fence; + } + fence_cnt = i; + if (ret) + goto buf_sync_err_1; + req->acq_fen_cnt = fence_cnt; + if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT) + mdp3_ppp_wait_for_fence(req); + + req->cur_rel_sync_pt = sw_sync_pt_create(ppp_stat->timeline, + ppp_stat->timeline_value++); + if (req->cur_rel_sync_pt == NULL) { + pr_err("%s: cannot create sync point\n", __func__); + ret = -ENOMEM; + goto buf_sync_err_2; + } + /* create fence */ + req->cur_rel_fence = sync_fence_create("ppp-fence", + req->cur_rel_sync_pt); + if (req->cur_rel_fence == NULL) { + sync_pt_free(req->cur_rel_sync_pt); + req->cur_rel_sync_pt = NULL; + pr_err("%s: cannot create fence\n", __func__); + ret = -ENOMEM; + goto buf_sync_err_2; + } + /* create fd */ + return ret; +buf_sync_err_2: + ppp_stat->timeline_value--; +buf_sync_err_1: + for (i = 0; i < fence_cnt; i++) + sync_fence_put(req->acq_fen[i]); + req->acq_fen_cnt = 0; + return ret; +} + +void mdp3_ppp_req_push(struct blit_req_queue *req_q, struct blit_req_list *req) +{ + int idx = req_q->push_idx; + req_q->req[idx] = *req; + req_q->count++; + req_q->push_idx = (req_q->push_idx + 1) % MDP3_PPP_MAX_LIST_REQ; +} + +struct blit_req_list *mdp3_ppp_next_req(struct blit_req_queue *req_q) +{ + struct blit_req_list *req; + if (req_q->count == 0) + return NULL; + req = &req_q->req[req_q->pop_idx]; + return req; +} + +void mdp3_ppp_req_pop(struct blit_req_queue *req_q) +{ + req_q->count--; + req_q->pop_idx = (req_q->pop_idx + 1) % MDP3_PPP_MAX_LIST_REQ; +} + +static void mdp3_ppp_blit_wq_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = ppp_stat->mfd; + struct blit_req_list *req; + int i, rc; + + req = mdp3_ppp_next_req(&ppp_stat->req_q); + mutex_lock(&ppp_stat->config_ppp_mutex); + + mdp3_ppp_iommu_attach(); + mdp3_ppp_turnon(mfd, 1); + while (req) { + mdp3_ppp_wait_for_fence(req); + for (i = 0; i < req->count; i++) { + if (!(req->req_list[i].flags & MDP_NO_BLIT)) { + /* Do the actual blit. */ + rc = mdp3_ppp_start_blit(mfd, + &(req->req_list[i]), + &req->src_data[i], + &req->dst_data[i]); + if (rc) + break; + } + } + /* Signal to release fence */ + mutex_lock(&ppp_stat->req_mutex); + mdp3_ppp_signal_timeline(req); + mdp3_ppp_req_pop(&ppp_stat->req_q); + req = mdp3_ppp_next_req(&ppp_stat->req_q); + if (ppp_stat->wait_for_pop) + complete(&ppp_stat->pop_q_comp); + mutex_unlock(&ppp_stat->req_mutex); + } + mdp3_ppp_turnon(mfd, 0); + mdp3_ppp_iommu_dettach(); + mutex_unlock(&ppp_stat->config_ppp_mutex); +} + +int mdp3_ppp_parse_req(void __user *p, + struct mdp_async_blit_req_list *req_list_header, + int async) +{ + struct blit_req_list *req; + struct blit_req_queue *req_q = &ppp_stat->req_q; + struct sync_fence *fence = NULL; + int count, rc, idx, i; + count = req_list_header->count; + + mutex_lock(&ppp_stat->req_mutex); + while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) { + ppp_stat->wait_for_pop = true; + mutex_unlock(&ppp_stat->req_mutex); + rc = wait_for_completion_interruptible_timeout( + &ppp_stat->pop_q_comp, 5 * HZ); + if (rc == 0) { + /* This will only occur if there is serious problem */ + pr_err("%s: timeout exiting queuing request\n", + __func__); + return -EBUSY; + } + mutex_lock(&ppp_stat->req_mutex); + ppp_stat->wait_for_pop = false; + } + idx = req_q->push_idx; + req = &req_q->req[idx]; + + if (copy_from_user(&req->req_list, p, + sizeof(struct mdp_blit_req) * count)) + return -EFAULT; + + rc = mdp3_ppp_handle_buf_sync(req, &req_list_header->sync); + if (rc < 0) { + pr_err("%s: Failed create sync point\n", __func__); + return rc; + } + req->count = count; + + /* We need to grab ion handle while client thread */ + for (i = 0; i < count; i++) { + rc = mdp3_ppp_get_img(&req->req_list[i].src, + &req->req_list[i], &req->src_data[i]); + if (rc < 0 || req->src_data[i].len == 0) { + pr_err("mdp_ppp: couldn't retrieve src img from mem\n"); + goto parse_err_1; + } + + rc = mdp3_ppp_get_img(&req->req_list[i].dst, + &req->req_list[i], &req->dst_data[i]); + if (rc < 0 || req->dst_data[i].len == 0) { + mdp3_put_img(&req->src_data[i]); + pr_err("mdp_ppp: couldn't retrieve dest img from mem\n"); + goto parse_err_1; + } + } + + if (async) { + req->cur_rel_fen_fd = get_unused_fd_flags(0); + if (req->cur_rel_fen_fd < 0) { + pr_err("%s: get_unused_fd_flags failed\n", __func__); + rc = -ENOMEM; + goto parse_err_2; + } + sync_fence_install(req->cur_rel_fence, req->cur_rel_fen_fd); + rc = copy_to_user(req_list_header->sync.rel_fen_fd, + &req->cur_rel_fen_fd, sizeof(int)); + if (rc) { + pr_err("%s:copy_to_user failed\n", __func__); + goto parse_err_3; + } + } else { + fence = req->cur_rel_fence; + } + + mdp3_ppp_req_push(req_q, req); + mutex_unlock(&ppp_stat->req_mutex); + schedule_work(&ppp_stat->blit_work); + if (!async) { + /* wait for release fence */ + rc = sync_fence_wait(fence, + 5 * MSEC_PER_SEC); + if (rc < 0) + pr_err("%s: sync blit! rc = %x\n", __func__, rc); + + sync_fence_put(fence); + fence = NULL; + } + return 0; + +parse_err_3: + put_unused_fd(req->cur_rel_fen_fd); +parse_err_2: + sync_fence_put(req->cur_rel_fence); + req->cur_rel_fence = NULL; + req->cur_rel_fen_fd = 0; +parse_err_1: + for (i--; i >= 0; i--) { + mdp3_put_img(&req->src_data[i]); + mdp3_put_img(&req->dst_data[i]); + } + mdp3_ppp_deinit_buf_sync(req); + return rc; +} + +int mdp3_ppp_res_init(struct msm_fb_data_type *mfd) +{ + const char timeline_name[] = "mdp3_ppp"; + ppp_stat = kzalloc(sizeof(struct ppp_status), GFP_KERNEL); + if (!ppp_stat) { + pr_err("%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + + /*Setup sync_pt timeline for ppp*/ + ppp_stat->timeline = sw_sync_timeline_create(timeline_name); + if (ppp_stat->timeline == NULL) { + pr_err("%s: cannot create time line\n", __func__); + return -ENOMEM; + } else { + ppp_stat->timeline_value = 1; + } + + INIT_WORK(&ppp_stat->blit_work, mdp3_ppp_blit_wq_handler); + init_completion(&ppp_stat->pop_q_comp); spin_lock_init(&ppp_stat->ppp_lock); - mutex_init(&ppp_stat->config_mutex); + mutex_init(&ppp_stat->req_mutex); + mutex_init(&ppp_stat->config_ppp_mutex); ppp_stat->busy = false; + ppp_stat->mfd = mfd; mdp3_ppp_callback_setup(); return 0; } diff --git a/drivers/video/fbdev/msm/mdp3_ppp.h b/drivers/video/fbdev/msm/mdp3_ppp.h index afac419e4f3c..b4252cad857a 100644 --- a/drivers/video/fbdev/msm/mdp3_ppp.h +++ b/drivers/video/fbdev/msm/mdp3_ppp.h @@ -18,7 +18,7 @@ #define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val) -#define MAX_BLIT_REQ 256 +#define MAX_BLIT_REQ 16 #define PPP_UPSCALE_MAX 64 #define PPP_BLUR_SCALE_MAX 128 #define PPP_LUT_MAX 256 @@ -403,11 +403,12 @@ void ppp_load_gaussian_lut(void); void ppp_load_x_scale_table(int idx); void ppp_load_y_scale_table(int idx); -int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd, - struct mdp_blit_req *req); -int mdp3_ppp_res_init(void); +int mdp3_ppp_res_init(struct msm_fb_data_type *mfd); int mdp3_ppp_init(void); int config_ppp_op_mode(struct ppp_blit_op *blit_op); void ppp_enable(void); +int mdp3_ppp_parse_req(void __user *p, + struct mdp_async_blit_req_list *req_list_header, + int async); #endif diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h index 85011a0db2af..12cf6b939b4d 100644 --- a/include/uapi/linux/msm_mdp.h +++ b/include/uapi/linux/msm_mdp.h @@ -68,6 +68,7 @@ #define MSMFB_METADATA_GET _IOW(MSMFB_IOCTL_MAGIC, 166, struct msmfb_metadata) #define MSMFB_WRITEBACK_SET_MIRRORING_HINT _IOW(MSMFB_IOCTL_MAGIC, 167, \ unsigned int) +#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int) #define FB_TYPE_3D_PANEL 0x10101010 #define MDP_IMGTYPE2_START 0x10000 @@ -749,6 +750,12 @@ struct mdp_buf_sync { int *rel_fen_fd; }; +struct mdp_async_blit_req_list { + struct mdp_buf_sync sync; + uint32_t count; + struct mdp_blit_req req[]; +}; + #define MDP_DISPLAY_COMMIT_OVERLAY 1 struct mdp_buf_fence { uint32_t flags; |
