summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerence Hampson <thampson@codeaurora.org>2013-05-08 19:01:51 -0400
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:17:35 -0700
commit705f82de26a28e113e1c321488b8e57eb4132844 (patch)
tree4d31a346cba82c73f6b8beb1316dcff3188fd23d
parent8f86ee9d1669a7af3dd79051a1dc810f30f1f1b5 (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.c18
-rw-r--r--drivers/video/fbdev/msm/mdp3.h2
-rw-r--r--drivers/video/fbdev/msm/mdp3_ctrl.c74
-rw-r--r--drivers/video/fbdev/msm/mdp3_ppp.c425
-rw-r--r--drivers/video/fbdev/msm/mdp3_ppp.h9
-rw-r--r--include/uapi/linux/msm_mdp.h7
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;