[PATCH v2 9/9] media: platform: mtk-mdp3: Add dual pipe feature support
roy-cw.yeh
roy-cw.yeh at mediatek.com
Wed Oct 20 00:14:48 PDT 2021
From: "Roy-CW.Yeh" <roy-cw.yeh at mediatek.com>
Add dual pipe feature which uses two svpp to execute dma
Signed-off-by: Roy-CW.Yeh <roy-cw.yeh at mediatek.com>
---
.../media/platform/mtk-mdp3/mtk-mdp3-cmdq.c | 191 ++++++++++++++----
.../media/platform/mtk-mdp3/mtk-mdp3-cmdq.h | 1 +
.../media/platform/mtk-mdp3/mtk-mdp3-core.c | 11 +-
.../media/platform/mtk-mdp3/mtk-mdp3-core.h | 3 +
.../media/platform/mtk-mdp3/mtk-mdp3-m2m.c | 4 +
.../media/platform/mtk-mdp3/mtk-mdp3-regs.c | 18 ++
.../media/platform/mtk-mdp3/mtk-mdp3-regs.h | 4 +
7 files changed, 189 insertions(+), 43 deletions(-)
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
index afa114fe9817..37bd7c4b9ded 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.c
@@ -10,7 +10,10 @@
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-m2m.h"
-#define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS
+#define PATH_0 0
+#define PATH_1 1
+#define MDP_DUAL_PIPE 2
+#define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS
struct mdp_path {
struct mdp_dev *mdp_dev;
@@ -30,6 +33,9 @@ struct mdp_path {
#define is_dummy_engine(mdp, id) \
((mdp)->mdp_data->comp_data[id].match.type == MDP_COMP_TYPE_DUMMY)
+#define is_dual_pipe(scenario) \
+ ((scenario) == MDP_STREAM_TYPE_DUAL_BITBLT)
+
struct mdp_path_subfrm {
s32 mutex_id;
u32 mutex_mod;
@@ -733,26 +739,31 @@ static void mdp_auto_release_work(struct work_struct *work)
struct mdp_cmdq_cb_param *cb_param;
struct mdp_dev *mdp;
int i;
+ bool finalize;
cb_param = container_of(work, struct mdp_cmdq_cb_param,
auto_release_work);
mdp = cb_param->mdp;
+ finalize = cb_param->finalize;
- i = mdp_get_mutex_idx(mdp->mdp_data, MDP_PIPE_RDMA0);
- mtk_mutex_unprepare(mdp->mdp_mutex[mdp->mdp_data->pipe_info[i].mutex_id]);
-
- i = mdp_get_mutex_idx(mdp->mdp_data, MDP_PIPE_RDMA1);
- if (i >= 0)
- mtk_mutex_unprepare(mdp->mdp_mutex2[mdp->mdp_data->pipe_info[i].mutex_id]);
+ if (finalize) {
+ i = mdp_get_mutex_idx(mdp->mdp_data, MDP_PIPE_RDMA0);
+ mtk_mutex_unprepare(mdp->mdp_mutex[mdp->mdp_data->pipe_info[i].mutex_id]);
+ i = mdp_get_mutex_idx(mdp->mdp_data, MDP_PIPE_RDMA1);
+ if (i >= 0)
+ mtk_mutex_unprepare(mdp->mdp_mutex2[mdp->mdp_data->pipe_info[i].mutex_id]);
+ }
mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
cb_param->num_comps);
kfree(cb_param->comps);
kfree(cb_param);
- atomic_dec(&mdp->job_count);
- wake_up(&mdp->callback_wq);
+ if (finalize) {
+ atomic_dec(&mdp->job_count);
+ wake_up(&mdp->callback_wq);
+ }
}
static void mdp_handle_cmdq_callback(struct cmdq_cb_data data)
@@ -770,7 +781,9 @@ static void mdp_handle_cmdq_callback(struct cmdq_cb_data data)
mdp = cb_param->mdp;
dev = &mdp->pdev->dev;
- if (cb_param->mdp_ctx)
+ cb_param->finalize = (atomic_dec_and_test(&mdp->cmdq_count));
+
+ if (cb_param->finalize && cb_param->mdp_ctx)
mdp_m2m_job_finish(cb_param->mdp_ctx);
if (cb_param->user_cmdq_cb) {
@@ -805,12 +818,15 @@ static void mdp_handle_cmdq_callback(struct cmdq_cb_data data)
int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
{
- struct mmsys_cmdq_cmd cmd;
- struct mdp_path path;
+ struct mmsys_cmdq_cmd cmd, cmd_d;
+ static struct mdp_path path[MDP_DUAL_PIPE];
struct mdp_cmdq_cb_param *cb_param = NULL;
+ struct mdp_cmdq_cb_param *cb_param_d = NULL;
struct mdp_comp *comps = NULL;
+ struct mdp_comp *comps_d = NULL;
struct device *dev = &mdp->pdev->dev;
- int i, ret;
+ enum mdp_stream_type scenario = param->param->type;
+ int i, ret, path_id;
if (atomic_read(&mdp->suspended))
return -ECANCELED;
@@ -825,24 +841,39 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
}
cmd.event = &mdp->event[0];
- path.mdp_dev = mdp;
- path.config = param->config;
- path.param = param->param;
- for (i = 0; i < param->param->num_outputs; i++) {
- path.bounds[i].left = 0;
- path.bounds[i].top = 0;
- path.bounds[i].width =
- param->param->outputs[i].buffer.format.width;
- path.bounds[i].height =
- param->param->outputs[i].buffer.format.height;
- path.composes[i] = param->composes[i] ?
- param->composes[i] : &path.bounds[i];
- }
-
- ret = mdp_path_ctx_init(mdp, &path);
- if (ret) {
- dev_info(dev, "%s mdp_path_ctx_init error\n", __func__);
- goto err_destroy_pkt;
+ if (is_dual_pipe(scenario)) {
+ cmd_d.pkt = cmdq_pkt_create(mdp->cmdq_d_clt, SZ_16K);
+ if (IS_ERR(cmd_d.pkt)) {
+ atomic_dec(&mdp->job_count);
+ wake_up(&mdp->callback_wq);
+ return PTR_ERR(cmd_d.pkt);
+ }
+ cmd_d.event = &mdp->event[0];
+ }
+
+ for (path_id = 0; path_id < MDP_DUAL_PIPE; path_id++) {
+ if (path_id != 0 && (!is_dual_pipe(scenario)))
+ break;
+
+ path[path_id].mdp_dev = mdp;
+ path[path_id].config = ¶m->config[path_id];
+ path[path_id].param = param->param;
+ for (i = 0; i < param->param->num_outputs; i++) {
+ path[path_id].bounds[i].left = 0;
+ path[path_id].bounds[i].top = 0;
+ path[path_id].bounds[i].width =
+ param->param->outputs[i].buffer.format.width;
+ path[path_id].bounds[i].height =
+ param->param->outputs[i].buffer.format.height;
+ path[path_id].composes[i] = param->composes[i] ?
+ param->composes[i] : &path[path_id].bounds[i];
+ }
+
+ ret = mdp_path_ctx_init(mdp, &path[path_id]);
+ if (ret) {
+ dev_info(dev, "%s mdp_path_ctx_init error at path %d\n", __func__, path_id);
+ goto err_destroy_pkt;
+ }
}
i = mdp_get_mutex_idx(mdp->mdp_data, MDP_PIPE_RDMA0);
@@ -852,44 +883,61 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
if (i >= 0)
mtk_mutex_prepare(mdp->mdp_mutex2[mdp->mdp_data->pipe_info[i].mutex_id]);
- for (i = 0; i < param->config->num_components; i++) {
- if (is_dummy_engine(mdp, path.config->components[i].type))
+ for (i = 0; i < param->config[PATH_0].num_components; i++) {
+ if (is_dummy_engine(mdp, path[PATH_0].config->components[i].type))
continue;
- mdp_comp_clock_on(&mdp->pdev->dev, path.comps[i].comp);
+ mdp_comp_clock_on(&mdp->pdev->dev, path[PATH_0].comps[i].comp);
+ }
+
+ if (is_dual_pipe(scenario)) {
+ for (i = 0; i < param->config[PATH_1].num_components; i++) {
+ if (is_dummy_engine(mdp, path[PATH_1].config->components[i].type))
+ continue;
+
+ mdp_comp_clock_on(&mdp->pdev->dev, path[PATH_1].comps[i].comp);
+ }
}
if (mdp->mdp_data->mdp_cfg->version == MTK_MDP_VERSION_8195) {
/* HYFBC Patch */
- ret = mdp_hyfbc_config(mdp, &cmd, &path, param);
+ ret = mdp_hyfbc_config(mdp, &cmd, &path[PATH_0], param);
if (ret)
dev_info(dev, "%s:mdp_hyfbc_config fail!\n", __func__);
}
- ret = mdp_path_config(mdp, &cmd, &path);
+ ret = mdp_path_config(mdp, &cmd, &path[PATH_0]);
if (ret) {
- dev_info(dev, "%s mdp_path_config error\n", __func__);
+ dev_info(dev, "%s path 0 mdp_path_config error\n", __func__);
goto err_destroy_pkt;
}
+ if (is_dual_pipe(scenario)) {
+ ret = mdp_path_config(mdp, &cmd_d, &path[PATH_1]);
+ if (ret) {
+ pr_info("%s path 1 mdp_path_config error\n", __func__);
+ goto err_destroy_pkt;
+ }
+ }
+
cb_param = kzalloc(sizeof(*cb_param), GFP_KERNEL);
if (!cb_param) {
ret = -ENOMEM;
goto err_destroy_pkt;
}
- comps = kcalloc(param->config->num_components, sizeof(*comps),
+ comps = kcalloc(param->config[PATH_0].num_components, sizeof(*comps),
GFP_KERNEL);
if (!comps) {
ret = -ENOMEM;
goto err_destroy_pkt;
}
- for (i = 0; i < param->config->num_components; i++) {
- if (is_dummy_engine(mdp, path.config->components[i].type))
+ for (i = 0; i < param->config[PATH_0].num_components; i++) {
+ if (is_dummy_engine(mdp, path[PATH_0].config->components[i].type))
continue;
- memcpy(&comps[i], path.comps[i].comp,
+ memcpy(&comps[i], path[PATH_0].comps[i].comp,
sizeof(struct mdp_comp));
}
cb_param->mdp = mdp;
@@ -897,10 +945,49 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
cb_param->user_cb_data = param->cb_data;
cb_param->pkt = cmd.pkt;
cb_param->comps = comps;
- cb_param->num_comps = param->config->num_components;
+ cb_param->num_comps = param->config[PATH_0].num_components;
cb_param->mdp_ctx = param->mdp_ctx;
+ if (is_dual_pipe(scenario)) {
+ cb_param_d = kzalloc(sizeof(*cb_param_d), GFP_KERNEL);
+ if (!cb_param_d) {
+ ret = -ENOMEM;
+ goto err_destroy_pkt;
+ }
+ comps_d = kcalloc(param->config[PATH_1].num_components, sizeof(*comps_d),
+ GFP_KERNEL);
+ if (!comps_d) {
+ ret = -ENOMEM;
+ goto err_destroy_pkt;
+ }
+
+ for (i = 0; i < param->config[PATH_1].num_components; i++) {
+ if (is_dummy_engine(mdp, path[PATH_1].config->components[i].type))
+ continue;
+
+ memcpy(&comps_d[i], path[PATH_1].comps[i].comp,
+ sizeof(struct mdp_comp));
+ }
+ cb_param_d->mdp = mdp;
+ cb_param_d->user_cmdq_cb = param->cmdq_cb;
+ cb_param_d->user_cb_data = param->cb_data;
+ cb_param_d->pkt = cmd_d.pkt;
+ cb_param_d->comps = comps_d;
+ cb_param_d->num_comps = param->config[PATH_1].num_components;
+ cb_param_d->mdp_ctx = param->mdp_ctx;
+ }
+
+ if (atomic_read(&mdp->cmdq_count))
+ pr_info("%s: Warning: cmdq_count:%d !\n", __func__, atomic_read(&mdp->cmdq_count));
+
cmdq_pkt_finalize(cmd.pkt);
+ atomic_inc(&mdp->cmdq_count);
+
+ if (is_dual_pipe(scenario)) {
+ cmdq_pkt_finalize(cmd_d.pkt);
+ atomic_inc(&mdp->cmdq_count);
+ }
+
ret = cmdq_pkt_flush_async(cmd.pkt,
mdp_handle_cmdq_callback,
(void *)cb_param);
@@ -908,6 +995,16 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
dev_info(dev, "cmdq_pkt_flush_async fail!\n");
goto err_clock_off;
}
+
+ if (is_dual_pipe(scenario)) {
+ ret = cmdq_pkt_flush_async(cmd_d.pkt,
+ mdp_handle_cmdq_callback,
+ (void *)cb_param_d);
+ if (ret) {
+ dev_err(dev, "cmdq_dual_pkt_flush_async fail!\n");
+ goto err_clock_off;
+ }
+ }
return 0;
err_clock_off:
@@ -920,12 +1017,22 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
mdp_comp_clocks_off(&mdp->pdev->dev, cb_param->comps,
cb_param->num_comps);
+ if (cb_param_d)
+ mdp_comp_clocks_off(&mdp->pdev->dev, cb_param_d->comps,
+ cb_param_d->num_comps);
err_destroy_pkt:
cmdq_pkt_destroy(cmd.pkt);
+ if (is_dual_pipe(scenario)) {
+ cmdq_pkt_destroy(cmd_d.pkt);
+ atomic_inc(&mdp->cmdq_count);
+ }
atomic_dec(&mdp->job_count);
+ atomic_dec(&mdp->cmdq_count);
wake_up(&mdp->callback_wq);
kfree(comps);
+ kfree(comps_d);
kfree(cb_param);
+ kfree(cb_param_d);
return ret;
}
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
index 16933507333b..0a0e88cef6b5 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-cmdq.h
@@ -37,6 +37,7 @@ struct mdp_cmdq_cb_param {
struct mdp_comp *comps;
u8 num_comps;
void *mdp_ctx;
+ bool finalize;
};
struct mdp_dev;
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
index 524c852e584b..1c8baa33ecc6 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.c
@@ -40,6 +40,7 @@ static const struct mdp_platform_config mt8195_plat_cfg = {
.wrot_filter_constraint = false,
.tdshp_1_1 = true,
.tdshp_dyn_contrast_version = 2,
+ .support_dual_pipe = true,
.gce_event_offset = 0,
.version = MTK_MDP_VERSION_8195,
};
@@ -1263,6 +1264,12 @@ static int mdp_probe(struct platform_device *pdev)
goto err_put_scp;
}
+ mdp->cmdq_d_clt = cmdq_mbox_create(dev, 1);
+ if (IS_ERR(mdp->cmdq_d_clt)) {
+ ret = PTR_ERR(mdp->cmdq_d_clt);
+ goto err_mbox_destroy;
+ }
+
init_waitqueue_head(&mdp->callback_wq);
ida_init(&mdp->mdp_ida);
platform_set_drvdata(pdev, mdp);
@@ -1273,7 +1280,7 @@ static int mdp_probe(struct platform_device *pdev)
if (ret) {
dev_err(dev, "Failed to register v4l2 device\n");
ret = -EINVAL;
- goto err_mbox_destroy;
+ goto err_dual_mbox_destroy;
}
ret = mdp_m2m_device_register(mdp);
@@ -1287,6 +1294,8 @@ static int mdp_probe(struct platform_device *pdev)
err_unregister_device:
v4l2_device_unregister(&mdp->v4l2_dev);
+err_dual_mbox_destroy:
+ cmdq_mbox_destroy(mdp->cmdq_d_clt);
err_mbox_destroy:
cmdq_mbox_destroy(mdp->cmdq_clt);
err_put_scp:
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
index 055812140366..5091fdacc5c6 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-core.h
@@ -45,6 +45,7 @@ struct mdp_platform_config {
bool wrot_filter_constraint;
bool wrot_support_afbc;
bool wrot_support_10bit;
+ bool support_dual_pipe;
u8 tdshp_dyn_contrast_version;
u32 gce_event_offset;
u32 version;
@@ -87,6 +88,7 @@ struct mdp_dev {
u32 id_count;
struct ida mdp_ida;
struct cmdq_client *cmdq_clt;
+ struct cmdq_client *cmdq_d_clt;
wait_queue_head_t callback_wq;
struct v4l2_device v4l2_dev;
@@ -96,6 +98,7 @@ struct mdp_dev {
struct mutex m2m_lock;
atomic_t suspended;
atomic_t job_count;
+ atomic_t cmdq_count;
};
struct mdp_pipe_info {
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
index 1eaeaf58906a..55384bb812cf 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-m2m.c
@@ -116,6 +116,10 @@ static void mdp_m2m_worker(struct work_struct *work)
frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
mdp_set_src_config(¶m.inputs[0], frame, &src_vb->vb2_buf);
+ mdp_set_scenario(ctx->mdp_dev, ¶m, frame);
+ if (param.frame_change)
+ dev_info(&ctx->mdp_dev->pdev->dev,
+ "MDP Scenario: %d\n", param.type);
frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
index 7d26c5d8df7f..92f337077411 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.c
@@ -10,6 +10,8 @@
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-regs.h"
+#define QHD (2560 * 1440)
+
static const struct mdp_limit mdp_def_limit = {
.out_limit = {
.wmin = 16,
@@ -432,6 +434,22 @@ static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt,
return 0;
}
+void mdp_set_scenario(struct mdp_dev *mdp,
+ struct img_ipi_frameparam *param,
+ struct mdp_frame *frame)
+{
+ u32 width = frame->format.fmt.pix_mp.width;
+ u32 height = frame->format.fmt.pix_mp.height;
+
+ if (!mdp)
+ return;
+
+ if (mdp->mdp_data->mdp_cfg->support_dual_pipe) {
+ if ((width * height) >= QHD)
+ param->type = MDP_STREAM_TYPE_DUAL_BITBLT;
+ }
+}
+
static void mdp_prepare_buffer(struct img_image_buffer *b,
struct mdp_frame *frame, struct vb2_buffer *vb)
{
diff --git a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
index 8a3d430dca36..7979ad60ab87 100644
--- a/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
+++ b/drivers/media/platform/mtk-mdp3/mtk-mdp3-regs.h
@@ -10,6 +10,7 @@
#include <linux/videodev2.h>
#include <media/videobuf2-core.h>
#include "mtk-img-ipi.h"
+#include "mtk-mdp3-cmdq.h"
/*
* MDP native color code
@@ -340,6 +341,9 @@ int mdp_try_crop(struct v4l2_rect *r, const struct v4l2_selection *s,
int mdp_check_scaling_ratio(const struct v4l2_rect *crop,
const struct v4l2_rect *compose, s32 rotation,
const struct mdp_limit *limit);
+void mdp_set_scenario(struct mdp_dev *mdp,
+ struct img_ipi_frameparam *param,
+ struct mdp_frame *frame);
void mdp_set_src_config(struct img_input *in,
struct mdp_frame *frame, struct vb2_buffer *vb);
void mdp_set_dst_config(struct img_output *out,
--
2.18.0
More information about the Linux-mediatek
mailing list