xref: /openbmc/linux/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
161890ccaSMoudy Ho // SPDX-License-Identifier: GPL-2.0-only
261890ccaSMoudy Ho /*
361890ccaSMoudy Ho  * Copyright (c) 2022 MediaTek Inc.
461890ccaSMoudy Ho  * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
561890ccaSMoudy Ho  */
661890ccaSMoudy Ho 
761890ccaSMoudy Ho #include <linux/mailbox_controller.h>
861890ccaSMoudy Ho #include <linux/platform_device.h>
961890ccaSMoudy Ho #include "mtk-mdp3-cmdq.h"
1061890ccaSMoudy Ho #include "mtk-mdp3-comp.h"
1161890ccaSMoudy Ho #include "mtk-mdp3-core.h"
1261890ccaSMoudy Ho #include "mtk-mdp3-m2m.h"
1309e694f1SMoudy Ho #include "mtk-img-ipi.h"
1461890ccaSMoudy Ho 
1561890ccaSMoudy Ho #define MDP_PATH_MAX_COMPS	IMG_MAX_COMPONENTS
1661890ccaSMoudy Ho 
1761890ccaSMoudy Ho struct mdp_path {
1861890ccaSMoudy Ho 	struct mdp_dev		*mdp_dev;
1961890ccaSMoudy Ho 	struct mdp_comp_ctx	comps[MDP_PATH_MAX_COMPS];
2061890ccaSMoudy Ho 	u32			num_comps;
2161890ccaSMoudy Ho 	const struct img_config	*config;
2261890ccaSMoudy Ho 	const struct img_ipi_frameparam *param;
2361890ccaSMoudy Ho 	const struct v4l2_rect	*composes[IMG_MAX_HW_OUTPUTS];
2461890ccaSMoudy Ho 	struct v4l2_rect	bounds[IMG_MAX_HW_OUTPUTS];
2561890ccaSMoudy Ho };
2661890ccaSMoudy Ho 
2761890ccaSMoudy Ho #define has_op(ctx, op) \
2861890ccaSMoudy Ho 	((ctx)->comp->ops && (ctx)->comp->ops->op)
2961890ccaSMoudy Ho  #define call_op(ctx, op, ...) \
3061890ccaSMoudy Ho 	(has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
3161890ccaSMoudy Ho 
is_output_disabled(int p_id,const struct img_compparam * param,u32 count)3209e694f1SMoudy Ho static bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count)
3361890ccaSMoudy Ho {
3409e694f1SMoudy Ho 	u32 num = 0;
3509e694f1SMoudy Ho 	bool dis_output = false;
3609e694f1SMoudy Ho 	bool dis_tile = false;
3709e694f1SMoudy Ho 
3809e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id)) {
3909e694f1SMoudy Ho 		num = CFG_COMP(MT8183, param, num_subfrms);
4009e694f1SMoudy Ho 		dis_output = CFG_COMP(MT8183, param, frame.output_disable);
4109e694f1SMoudy Ho 		dis_tile = CFG_COMP(MT8183, param, frame.output_disable);
4209e694f1SMoudy Ho 	}
4309e694f1SMoudy Ho 
4409e694f1SMoudy Ho 	return (count < num) ? (dis_output || dis_tile) : true;
4561890ccaSMoudy Ho }
4661890ccaSMoudy Ho 
mdp_path_subfrm_require(const struct mdp_path * path,struct mdp_cmdq_cmd * cmd,s32 * mutex_id,u32 count)4761890ccaSMoudy Ho static int mdp_path_subfrm_require(const struct mdp_path *path,
4861890ccaSMoudy Ho 				   struct mdp_cmdq_cmd *cmd,
4961890ccaSMoudy Ho 				   s32 *mutex_id, u32 count)
5061890ccaSMoudy Ho {
5109e694f1SMoudy Ho 	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
5261890ccaSMoudy Ho 	const struct mdp_comp_ctx *ctx;
5361890ccaSMoudy Ho 	const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;
5461890ccaSMoudy Ho 	struct device *dev = &path->mdp_dev->pdev->dev;
5561890ccaSMoudy Ho 	struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
5661890ccaSMoudy Ho 	int id, index;
5709e694f1SMoudy Ho 	u32 num_comp = 0;
5809e694f1SMoudy Ho 
5909e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
6009e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
6161890ccaSMoudy Ho 
6261890ccaSMoudy Ho 	/* Decide which mutex to use based on the current pipeline */
63b59ed26fSMoudy Ho 	switch (path->comps[0].comp->public_id) {
6461890ccaSMoudy Ho 	case MDP_COMP_RDMA0:
6550709e63SMoudy Ho 		index = MDP_PIPE_RDMA0;
6661890ccaSMoudy Ho 		break;
6761890ccaSMoudy Ho 	case MDP_COMP_ISP_IMGI:
6850709e63SMoudy Ho 		index = MDP_PIPE_IMGI;
6961890ccaSMoudy Ho 		break;
7061890ccaSMoudy Ho 	case MDP_COMP_WPEI:
7150709e63SMoudy Ho 		index = MDP_PIPE_WPEI;
7261890ccaSMoudy Ho 		break;
7361890ccaSMoudy Ho 	case MDP_COMP_WPEI2:
7450709e63SMoudy Ho 		index = MDP_PIPE_WPEI2;
7561890ccaSMoudy Ho 		break;
7661890ccaSMoudy Ho 	default:
7761890ccaSMoudy Ho 		dev_err(dev, "Unknown pipeline and no mutex is assigned");
7861890ccaSMoudy Ho 		return -EINVAL;
7961890ccaSMoudy Ho 	}
8050709e63SMoudy Ho 	*mutex_id = data->pipe_info[index].mutex_id;
8161890ccaSMoudy Ho 
8261890ccaSMoudy Ho 	/* Set mutex mod */
8309e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
8461890ccaSMoudy Ho 		ctx = &path->comps[index];
8509e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
8661890ccaSMoudy Ho 			continue;
87b59ed26fSMoudy Ho 		id = ctx->comp->public_id;
8861890ccaSMoudy Ho 		mtk_mutex_write_mod(mutex[*mutex_id],
8961890ccaSMoudy Ho 				    data->mdp_mutex_table_idx[id], false);
9061890ccaSMoudy Ho 	}
9161890ccaSMoudy Ho 
9261890ccaSMoudy Ho 	mtk_mutex_write_sof(mutex[*mutex_id],
9361890ccaSMoudy Ho 			    MUTEX_SOF_IDX_SINGLE_MODE);
9461890ccaSMoudy Ho 
9561890ccaSMoudy Ho 	return 0;
9661890ccaSMoudy Ho }
9761890ccaSMoudy Ho 
mdp_path_subfrm_run(const struct mdp_path * path,struct mdp_cmdq_cmd * cmd,s32 * mutex_id,u32 count)9861890ccaSMoudy Ho static int mdp_path_subfrm_run(const struct mdp_path *path,
9961890ccaSMoudy Ho 			       struct mdp_cmdq_cmd *cmd,
10061890ccaSMoudy Ho 			       s32 *mutex_id, u32 count)
10161890ccaSMoudy Ho {
10209e694f1SMoudy Ho 	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
10361890ccaSMoudy Ho 	const struct mdp_comp_ctx *ctx;
10461890ccaSMoudy Ho 	struct device *dev = &path->mdp_dev->pdev->dev;
10561890ccaSMoudy Ho 	struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
10661890ccaSMoudy Ho 	int index;
10709e694f1SMoudy Ho 	u32 num_comp = 0;
10861890ccaSMoudy Ho 	s32 event;
10961890ccaSMoudy Ho 
11061890ccaSMoudy Ho 	if (-1 == *mutex_id) {
11161890ccaSMoudy Ho 		dev_err(dev, "Incorrect mutex id");
11261890ccaSMoudy Ho 		return -EINVAL;
11361890ccaSMoudy Ho 	}
11461890ccaSMoudy Ho 
11509e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
11609e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
11709e694f1SMoudy Ho 
11861890ccaSMoudy Ho 	/* Wait WROT SRAM shared to DISP RDMA */
11961890ccaSMoudy Ho 	/* Clear SOF event for each engine */
12009e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
12161890ccaSMoudy Ho 		ctx = &path->comps[index];
12209e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
12361890ccaSMoudy Ho 			continue;
12461890ccaSMoudy Ho 		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
12561890ccaSMoudy Ho 		if (event != MDP_GCE_NO_EVENT)
12661890ccaSMoudy Ho 			MM_REG_CLEAR(cmd, event);
12761890ccaSMoudy Ho 	}
12861890ccaSMoudy Ho 
12961890ccaSMoudy Ho 	/* Enable the mutex */
13061890ccaSMoudy Ho 	mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt);
13161890ccaSMoudy Ho 
13261890ccaSMoudy Ho 	/* Wait SOF events and clear mutex modules (optional) */
13309e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
13461890ccaSMoudy Ho 		ctx = &path->comps[index];
13509e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
13661890ccaSMoudy Ho 			continue;
13761890ccaSMoudy Ho 		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
13861890ccaSMoudy Ho 		if (event != MDP_GCE_NO_EVENT)
13961890ccaSMoudy Ho 			MM_REG_WAIT(cmd, event);
14061890ccaSMoudy Ho 	}
14161890ccaSMoudy Ho 
14261890ccaSMoudy Ho 	return 0;
14361890ccaSMoudy Ho }
14461890ccaSMoudy Ho 
mdp_path_ctx_init(struct mdp_dev * mdp,struct mdp_path * path)14561890ccaSMoudy Ho static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
14661890ccaSMoudy Ho {
14709e694f1SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
14809e694f1SMoudy Ho 	void *param = NULL;
14961890ccaSMoudy Ho 	int index, ret;
15009e694f1SMoudy Ho 	u32 num_comp = 0;
15161890ccaSMoudy Ho 
15209e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
15309e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
15409e694f1SMoudy Ho 
15509e694f1SMoudy Ho 	if (num_comp < 1)
15661890ccaSMoudy Ho 		return -EINVAL;
15761890ccaSMoudy Ho 
15809e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
15909e694f1SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
16009e694f1SMoudy Ho 			param = (void *)CFG_ADDR(MT8183, path->config, components[index]);
16161890ccaSMoudy Ho 		ret = mdp_comp_ctx_config(mdp, &path->comps[index],
16209e694f1SMoudy Ho 					  param, path->param);
16361890ccaSMoudy Ho 		if (ret)
16461890ccaSMoudy Ho 			return ret;
16561890ccaSMoudy Ho 	}
16661890ccaSMoudy Ho 
16761890ccaSMoudy Ho 	return 0;
16861890ccaSMoudy Ho }
16961890ccaSMoudy Ho 
mdp_path_config_subfrm(struct mdp_cmdq_cmd * cmd,struct mdp_path * path,u32 count)17061890ccaSMoudy Ho static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
17161890ccaSMoudy Ho 				  struct mdp_path *path, u32 count)
17261890ccaSMoudy Ho {
17309e694f1SMoudy Ho 	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
17409e694f1SMoudy Ho 	const struct img_mmsys_ctrl *ctrl = NULL;
17561890ccaSMoudy Ho 	const struct img_mux *set;
17661890ccaSMoudy Ho 	struct mdp_comp_ctx *ctx;
17761890ccaSMoudy Ho 	s32 mutex_id;
17861890ccaSMoudy Ho 	int index, ret;
17909e694f1SMoudy Ho 	u32 num_comp = 0;
18009e694f1SMoudy Ho 
18109e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
18209e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
18309e694f1SMoudy Ho 
18409e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
18509e694f1SMoudy Ho 		ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]);
18661890ccaSMoudy Ho 
18761890ccaSMoudy Ho 	/* Acquire components */
18861890ccaSMoudy Ho 	ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count);
18961890ccaSMoudy Ho 	if (ret)
19061890ccaSMoudy Ho 		return ret;
19161890ccaSMoudy Ho 	/* Enable mux settings */
19261890ccaSMoudy Ho 	for (index = 0; index < ctrl->num_sets; index++) {
19361890ccaSMoudy Ho 		set = &ctrl->sets[index];
19461890ccaSMoudy Ho 		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
19561890ccaSMoudy Ho 				    set->value, 0xFFFFFFFF);
19661890ccaSMoudy Ho 	}
19761890ccaSMoudy Ho 	/* Config sub-frame information */
19809e694f1SMoudy Ho 	for (index = (num_comp - 1); index >= 0; index--) {
19961890ccaSMoudy Ho 		ctx = &path->comps[index];
20009e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
20161890ccaSMoudy Ho 			continue;
20261890ccaSMoudy Ho 		ret = call_op(ctx, config_subfrm, cmd, count);
20361890ccaSMoudy Ho 		if (ret)
20461890ccaSMoudy Ho 			return ret;
20561890ccaSMoudy Ho 	}
20661890ccaSMoudy Ho 	/* Run components */
20761890ccaSMoudy Ho 	ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count);
20861890ccaSMoudy Ho 	if (ret)
20961890ccaSMoudy Ho 		return ret;
21061890ccaSMoudy Ho 	/* Wait components done */
21109e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
21261890ccaSMoudy Ho 		ctx = &path->comps[index];
21309e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
21461890ccaSMoudy Ho 			continue;
21561890ccaSMoudy Ho 		ret = call_op(ctx, wait_comp_event, cmd);
21661890ccaSMoudy Ho 		if (ret)
21761890ccaSMoudy Ho 			return ret;
21861890ccaSMoudy Ho 	}
21961890ccaSMoudy Ho 	/* Advance to the next sub-frame */
22009e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
22161890ccaSMoudy Ho 		ctx = &path->comps[index];
22261890ccaSMoudy Ho 		ret = call_op(ctx, advance_subfrm, cmd, count);
22361890ccaSMoudy Ho 		if (ret)
22461890ccaSMoudy Ho 			return ret;
22561890ccaSMoudy Ho 	}
22661890ccaSMoudy Ho 	/* Disable mux settings */
22761890ccaSMoudy Ho 	for (index = 0; index < ctrl->num_sets; index++) {
22861890ccaSMoudy Ho 		set = &ctrl->sets[index];
22961890ccaSMoudy Ho 		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
23061890ccaSMoudy Ho 				    0, 0xFFFFFFFF);
23161890ccaSMoudy Ho 	}
23261890ccaSMoudy Ho 
23361890ccaSMoudy Ho 	return 0;
23461890ccaSMoudy Ho }
23561890ccaSMoudy Ho 
mdp_path_config(struct mdp_dev * mdp,struct mdp_cmdq_cmd * cmd,struct mdp_path * path)23661890ccaSMoudy Ho static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
23761890ccaSMoudy Ho 			   struct mdp_path *path)
23861890ccaSMoudy Ho {
23909e694f1SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
24061890ccaSMoudy Ho 	struct mdp_comp_ctx *ctx;
24161890ccaSMoudy Ho 	int index, count, ret;
24209e694f1SMoudy Ho 	u32 num_comp = 0;
24309e694f1SMoudy Ho 	u32 num_sub = 0;
24409e694f1SMoudy Ho 
24509e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
24609e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
24709e694f1SMoudy Ho 
24809e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
24909e694f1SMoudy Ho 		num_sub = CFG_GET(MT8183, path->config, num_subfrms);
25061890ccaSMoudy Ho 
25161890ccaSMoudy Ho 	/* Config path frame */
25261890ccaSMoudy Ho 	/* Reset components */
25309e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
25461890ccaSMoudy Ho 		ctx = &path->comps[index];
25561890ccaSMoudy Ho 		ret = call_op(ctx, init_comp, cmd);
25661890ccaSMoudy Ho 		if (ret)
25761890ccaSMoudy Ho 			return ret;
25861890ccaSMoudy Ho 	}
25961890ccaSMoudy Ho 	/* Config frame mode */
26009e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
26109e694f1SMoudy Ho 		const struct v4l2_rect *compose;
26209e694f1SMoudy Ho 		u32 out = 0;
26361890ccaSMoudy Ho 
264*14e1dbe2SMoudy Ho 		ctx = &path->comps[index];
26509e694f1SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
26609e694f1SMoudy Ho 			out = CFG_COMP(MT8183, ctx->param, outputs[0]);
26709e694f1SMoudy Ho 
26809e694f1SMoudy Ho 		compose = path->composes[out];
26961890ccaSMoudy Ho 		ret = call_op(ctx, config_frame, cmd, compose);
27061890ccaSMoudy Ho 		if (ret)
27161890ccaSMoudy Ho 			return ret;
27261890ccaSMoudy Ho 	}
27361890ccaSMoudy Ho 
27461890ccaSMoudy Ho 	/* Config path sub-frames */
27509e694f1SMoudy Ho 	for (count = 0; count < num_sub; count++) {
27661890ccaSMoudy Ho 		ret = mdp_path_config_subfrm(cmd, path, count);
27761890ccaSMoudy Ho 		if (ret)
27861890ccaSMoudy Ho 			return ret;
27961890ccaSMoudy Ho 	}
28061890ccaSMoudy Ho 	/* Post processing information */
28109e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
28261890ccaSMoudy Ho 		ctx = &path->comps[index];
28361890ccaSMoudy Ho 		ret = call_op(ctx, post_process, cmd);
28461890ccaSMoudy Ho 		if (ret)
28561890ccaSMoudy Ho 			return ret;
28661890ccaSMoudy Ho 	}
28761890ccaSMoudy Ho 	return 0;
28861890ccaSMoudy Ho }
28961890ccaSMoudy Ho 
mdp_cmdq_pkt_create(struct cmdq_client * client,struct cmdq_pkt * pkt,size_t size)29061890ccaSMoudy Ho static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
29161890ccaSMoudy Ho 			       size_t size)
29261890ccaSMoudy Ho {
29361890ccaSMoudy Ho 	struct device *dev;
29461890ccaSMoudy Ho 	dma_addr_t dma_addr;
29561890ccaSMoudy Ho 
29661890ccaSMoudy Ho 	pkt->va_base = kzalloc(size, GFP_KERNEL);
29764e0a080SMoudy Ho 	if (!pkt->va_base)
29861890ccaSMoudy Ho 		return -ENOMEM;
29964e0a080SMoudy Ho 
30061890ccaSMoudy Ho 	pkt->buf_size = size;
30161890ccaSMoudy Ho 	pkt->cl = (void *)client;
30261890ccaSMoudy Ho 
30361890ccaSMoudy Ho 	dev = client->chan->mbox->dev;
30461890ccaSMoudy Ho 	dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
30561890ccaSMoudy Ho 				  DMA_TO_DEVICE);
30661890ccaSMoudy Ho 	if (dma_mapping_error(dev, dma_addr)) {
30761890ccaSMoudy Ho 		dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
30861890ccaSMoudy Ho 		kfree(pkt->va_base);
30961890ccaSMoudy Ho 		return -ENOMEM;
31061890ccaSMoudy Ho 	}
31161890ccaSMoudy Ho 
31261890ccaSMoudy Ho 	pkt->pa_base = dma_addr;
31361890ccaSMoudy Ho 
31461890ccaSMoudy Ho 	return 0;
31561890ccaSMoudy Ho }
31661890ccaSMoudy Ho 
mdp_cmdq_pkt_destroy(struct cmdq_pkt * pkt)31761890ccaSMoudy Ho static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
31861890ccaSMoudy Ho {
31961890ccaSMoudy Ho 	struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
32061890ccaSMoudy Ho 
32161890ccaSMoudy Ho 	dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
32261890ccaSMoudy Ho 			 DMA_TO_DEVICE);
32361890ccaSMoudy Ho 	kfree(pkt->va_base);
32461890ccaSMoudy Ho 	pkt->va_base = NULL;
32561890ccaSMoudy Ho }
32661890ccaSMoudy Ho 
mdp_auto_release_work(struct work_struct * work)32761890ccaSMoudy Ho static void mdp_auto_release_work(struct work_struct *work)
32861890ccaSMoudy Ho {
32961890ccaSMoudy Ho 	struct mdp_cmdq_cmd *cmd;
33061890ccaSMoudy Ho 	struct mdp_dev *mdp;
33150709e63SMoudy Ho 	int id;
33261890ccaSMoudy Ho 
33361890ccaSMoudy Ho 	cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);
33461890ccaSMoudy Ho 	mdp = cmd->mdp;
33561890ccaSMoudy Ho 
33650709e63SMoudy Ho 	id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
33750709e63SMoudy Ho 	mtk_mutex_unprepare(mdp->mdp_mutex[id]);
33861890ccaSMoudy Ho 	mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
33961890ccaSMoudy Ho 			    cmd->num_comps);
34061890ccaSMoudy Ho 
34161890ccaSMoudy Ho 	atomic_dec(&mdp->job_count);
34261890ccaSMoudy Ho 	wake_up(&mdp->callback_wq);
34361890ccaSMoudy Ho 
34461890ccaSMoudy Ho 	mdp_cmdq_pkt_destroy(&cmd->pkt);
34561890ccaSMoudy Ho 	kfree(cmd->comps);
34661890ccaSMoudy Ho 	cmd->comps = NULL;
34761890ccaSMoudy Ho 	kfree(cmd);
34861890ccaSMoudy Ho 	cmd = NULL;
34961890ccaSMoudy Ho }
35061890ccaSMoudy Ho 
mdp_handle_cmdq_callback(struct mbox_client * cl,void * mssg)35161890ccaSMoudy Ho static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
35261890ccaSMoudy Ho {
35361890ccaSMoudy Ho 	struct mdp_cmdq_cmd *cmd;
35461890ccaSMoudy Ho 	struct cmdq_cb_data *data;
35561890ccaSMoudy Ho 	struct mdp_dev *mdp;
35661890ccaSMoudy Ho 	struct device *dev;
35750709e63SMoudy Ho 	int id;
35861890ccaSMoudy Ho 
35961890ccaSMoudy Ho 	if (!mssg) {
36061890ccaSMoudy Ho 		pr_info("%s:no callback data\n", __func__);
36161890ccaSMoudy Ho 		return;
36261890ccaSMoudy Ho 	}
36361890ccaSMoudy Ho 
36461890ccaSMoudy Ho 	data = (struct cmdq_cb_data *)mssg;
36561890ccaSMoudy Ho 	cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt);
36661890ccaSMoudy Ho 	mdp = cmd->mdp;
36761890ccaSMoudy Ho 	dev = &mdp->pdev->dev;
36861890ccaSMoudy Ho 
36961890ccaSMoudy Ho 	if (cmd->mdp_ctx)
37061890ccaSMoudy Ho 		mdp_m2m_job_finish(cmd->mdp_ctx);
37161890ccaSMoudy Ho 
37261890ccaSMoudy Ho 	if (cmd->user_cmdq_cb) {
37361890ccaSMoudy Ho 		struct cmdq_cb_data user_cb_data;
37461890ccaSMoudy Ho 
37561890ccaSMoudy Ho 		user_cb_data.sta = data->sta;
37661890ccaSMoudy Ho 		user_cb_data.pkt = data->pkt;
37761890ccaSMoudy Ho 		cmd->user_cmdq_cb(user_cb_data);
37861890ccaSMoudy Ho 	}
37961890ccaSMoudy Ho 
38061890ccaSMoudy Ho 	INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);
38161890ccaSMoudy Ho 	if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {
38261890ccaSMoudy Ho 		dev_err(dev, "%s:queue_work fail!\n", __func__);
38350709e63SMoudy Ho 		id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
38450709e63SMoudy Ho 		mtk_mutex_unprepare(mdp->mdp_mutex[id]);
38561890ccaSMoudy Ho 		mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
38661890ccaSMoudy Ho 				    cmd->num_comps);
38761890ccaSMoudy Ho 
38861890ccaSMoudy Ho 		atomic_dec(&mdp->job_count);
38961890ccaSMoudy Ho 		wake_up(&mdp->callback_wq);
39061890ccaSMoudy Ho 
39161890ccaSMoudy Ho 		mdp_cmdq_pkt_destroy(&cmd->pkt);
39261890ccaSMoudy Ho 		kfree(cmd->comps);
39361890ccaSMoudy Ho 		cmd->comps = NULL;
39461890ccaSMoudy Ho 		kfree(cmd);
39561890ccaSMoudy Ho 		cmd = NULL;
39661890ccaSMoudy Ho 	}
39761890ccaSMoudy Ho }
39861890ccaSMoudy Ho 
mdp_cmdq_send(struct mdp_dev * mdp,struct mdp_cmdq_param * param)39961890ccaSMoudy Ho int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
40061890ccaSMoudy Ho {
40161890ccaSMoudy Ho 	struct mdp_path *path = NULL;
40261890ccaSMoudy Ho 	struct mdp_cmdq_cmd *cmd = NULL;
40361890ccaSMoudy Ho 	struct mdp_comp *comps = NULL;
40461890ccaSMoudy Ho 	struct device *dev = &mdp->pdev->dev;
40509e694f1SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
40661890ccaSMoudy Ho 	int i, ret;
40709e694f1SMoudy Ho 	u32 num_comp = 0;
40861890ccaSMoudy Ho 
40961890ccaSMoudy Ho 	atomic_inc(&mdp->job_count);
41061890ccaSMoudy Ho 	if (atomic_read(&mdp->suspended)) {
41161890ccaSMoudy Ho 		atomic_dec(&mdp->job_count);
41261890ccaSMoudy Ho 		return -ECANCELED;
41361890ccaSMoudy Ho 	}
41461890ccaSMoudy Ho 
41561890ccaSMoudy Ho 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
41661890ccaSMoudy Ho 	if (!cmd) {
41761890ccaSMoudy Ho 		ret = -ENOMEM;
41864e0a080SMoudy Ho 		goto err_cancel_job;
41961890ccaSMoudy Ho 	}
42061890ccaSMoudy Ho 
42164e0a080SMoudy Ho 	ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K);
42264e0a080SMoudy Ho 	if (ret)
42364e0a080SMoudy Ho 		goto err_free_cmd;
42461890ccaSMoudy Ho 
42509e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id)) {
42609e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, param->config, num_components);
42709e694f1SMoudy Ho 	} else {
42809e694f1SMoudy Ho 		ret = -EINVAL;
42909e694f1SMoudy Ho 		goto err_destroy_pkt;
43009e694f1SMoudy Ho 	}
43109e694f1SMoudy Ho 	comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL);
43261890ccaSMoudy Ho 	if (!comps) {
43361890ccaSMoudy Ho 		ret = -ENOMEM;
43464e0a080SMoudy Ho 		goto err_destroy_pkt;
43561890ccaSMoudy Ho 	}
43661890ccaSMoudy Ho 
43761890ccaSMoudy Ho 	path = kzalloc(sizeof(*path), GFP_KERNEL);
43861890ccaSMoudy Ho 	if (!path) {
43961890ccaSMoudy Ho 		ret = -ENOMEM;
44064e0a080SMoudy Ho 		goto err_free_comps;
44164e0a080SMoudy Ho 	}
44264e0a080SMoudy Ho 
44350709e63SMoudy Ho 	i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
44450709e63SMoudy Ho 	ret = mtk_mutex_prepare(mdp->mdp_mutex[i]);
44564e0a080SMoudy Ho 	if (ret) {
44664e0a080SMoudy Ho 		dev_err(dev, "Fail to enable mutex clk\n");
44764e0a080SMoudy Ho 		goto err_free_path;
44861890ccaSMoudy Ho 	}
44961890ccaSMoudy Ho 
45061890ccaSMoudy Ho 	path->mdp_dev = mdp;
45161890ccaSMoudy Ho 	path->config = param->config;
45261890ccaSMoudy Ho 	path->param = param->param;
45361890ccaSMoudy Ho 	for (i = 0; i < param->param->num_outputs; i++) {
45461890ccaSMoudy Ho 		path->bounds[i].left = 0;
45561890ccaSMoudy Ho 		path->bounds[i].top = 0;
45661890ccaSMoudy Ho 		path->bounds[i].width =
45761890ccaSMoudy Ho 			param->param->outputs[i].buffer.format.width;
45861890ccaSMoudy Ho 		path->bounds[i].height =
45961890ccaSMoudy Ho 			param->param->outputs[i].buffer.format.height;
46061890ccaSMoudy Ho 		path->composes[i] = param->composes[i] ?
46161890ccaSMoudy Ho 			param->composes[i] : &path->bounds[i];
46261890ccaSMoudy Ho 	}
46361890ccaSMoudy Ho 	ret = mdp_path_ctx_init(mdp, path);
46461890ccaSMoudy Ho 	if (ret) {
46561890ccaSMoudy Ho 		dev_err(dev, "mdp_path_ctx_init error\n");
46664e0a080SMoudy Ho 		goto err_free_path;
46761890ccaSMoudy Ho 	}
46861890ccaSMoudy Ho 
46961890ccaSMoudy Ho 	ret = mdp_path_config(mdp, cmd, path);
47061890ccaSMoudy Ho 	if (ret) {
47161890ccaSMoudy Ho 		dev_err(dev, "mdp_path_config error\n");
47264e0a080SMoudy Ho 		goto err_free_path;
47361890ccaSMoudy Ho 	}
47461890ccaSMoudy Ho 	cmdq_pkt_finalize(&cmd->pkt);
47561890ccaSMoudy Ho 
47609e694f1SMoudy Ho 	for (i = 0; i < num_comp; i++)
47761890ccaSMoudy Ho 		memcpy(&comps[i], path->comps[i].comp,
47861890ccaSMoudy Ho 		       sizeof(struct mdp_comp));
47961890ccaSMoudy Ho 
48061890ccaSMoudy Ho 	mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback;
48161890ccaSMoudy Ho 	cmd->mdp = mdp;
48261890ccaSMoudy Ho 	cmd->user_cmdq_cb = param->cmdq_cb;
48361890ccaSMoudy Ho 	cmd->user_cb_data = param->cb_data;
48461890ccaSMoudy Ho 	cmd->comps = comps;
48509e694f1SMoudy Ho 	cmd->num_comps = num_comp;
48661890ccaSMoudy Ho 	cmd->mdp_ctx = param->mdp_ctx;
48761890ccaSMoudy Ho 
48861890ccaSMoudy Ho 	ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
48974a596e7SMoudy Ho 	if (ret)
49064e0a080SMoudy Ho 		goto err_free_path;
49161890ccaSMoudy Ho 
49261890ccaSMoudy Ho 	dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
49361890ccaSMoudy Ho 				   cmd->pkt.pa_base, cmd->pkt.cmd_buf_size,
49461890ccaSMoudy Ho 				   DMA_TO_DEVICE);
49561890ccaSMoudy Ho 	ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt);
49661890ccaSMoudy Ho 	if (ret < 0) {
49761890ccaSMoudy Ho 		dev_err(dev, "mbox send message fail %d!\n", ret);
49861890ccaSMoudy Ho 		goto err_clock_off;
49961890ccaSMoudy Ho 	}
50061890ccaSMoudy Ho 	mbox_client_txdone(mdp->cmdq_clt->chan, 0);
50161890ccaSMoudy Ho 
50261890ccaSMoudy Ho 	kfree(path);
50361890ccaSMoudy Ho 	return 0;
50461890ccaSMoudy Ho 
50561890ccaSMoudy Ho err_clock_off:
50661890ccaSMoudy Ho 	mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
50761890ccaSMoudy Ho 			    cmd->num_comps);
50864e0a080SMoudy Ho err_free_path:
50950709e63SMoudy Ho 	i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
51050709e63SMoudy Ho 	mtk_mutex_unprepare(mdp->mdp_mutex[i]);
51161890ccaSMoudy Ho 	kfree(path);
51264e0a080SMoudy Ho err_free_comps:
51361890ccaSMoudy Ho 	kfree(comps);
51464e0a080SMoudy Ho err_destroy_pkt:
51564e0a080SMoudy Ho 	mdp_cmdq_pkt_destroy(&cmd->pkt);
51664e0a080SMoudy Ho err_free_cmd:
51761890ccaSMoudy Ho 	kfree(cmd);
51864e0a080SMoudy Ho err_cancel_job:
51964e0a080SMoudy Ho 	atomic_dec(&mdp->job_count);
52064e0a080SMoudy Ho 
52161890ccaSMoudy Ho 	return ret;
52261890ccaSMoudy Ho }
52361890ccaSMoudy Ho EXPORT_SYMBOL_GPL(mdp_cmdq_send);
524