xref: /linux/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c (revision 6fd600d742744dc7ef7fc65ca26daa2b1163158a)
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>
992cdfc39SMoudy Ho #include "mtk-mdp3-cfg.h"
1061890ccaSMoudy Ho #include "mtk-mdp3-cmdq.h"
1161890ccaSMoudy Ho #include "mtk-mdp3-comp.h"
1261890ccaSMoudy Ho #include "mtk-mdp3-core.h"
1361890ccaSMoudy Ho #include "mtk-mdp3-m2m.h"
1409e694f1SMoudy Ho #include "mtk-img-ipi.h"
1561890ccaSMoudy Ho 
1661890ccaSMoudy Ho #define MDP_PATH_MAX_COMPS	IMG_MAX_COMPONENTS
1761890ccaSMoudy Ho 
1861890ccaSMoudy Ho struct mdp_path {
1961890ccaSMoudy Ho 	struct mdp_dev		*mdp_dev;
2061890ccaSMoudy Ho 	struct mdp_comp_ctx	comps[MDP_PATH_MAX_COMPS];
2161890ccaSMoudy Ho 	u32			num_comps;
2261890ccaSMoudy Ho 	const struct img_config	*config;
2361890ccaSMoudy Ho 	const struct img_ipi_frameparam *param;
2461890ccaSMoudy Ho 	const struct v4l2_rect	*composes[IMG_MAX_HW_OUTPUTS];
2561890ccaSMoudy Ho 	struct v4l2_rect	bounds[IMG_MAX_HW_OUTPUTS];
2661890ccaSMoudy Ho };
2761890ccaSMoudy Ho 
2861890ccaSMoudy Ho #define has_op(ctx, op) \
2961890ccaSMoudy Ho 	((ctx)->comp->ops && (ctx)->comp->ops->op)
3061890ccaSMoudy Ho  #define call_op(ctx, op, ...) \
3161890ccaSMoudy Ho 	(has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
3261890ccaSMoudy Ho 
is_output_disabled(int p_id,const struct img_compparam * param,u32 count)3309e694f1SMoudy Ho static bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count)
3461890ccaSMoudy Ho {
3509e694f1SMoudy Ho 	u32 num = 0;
3609e694f1SMoudy Ho 	bool dis_output = false;
3709e694f1SMoudy Ho 	bool dis_tile = false;
3809e694f1SMoudy Ho 
3909e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id)) {
4009e694f1SMoudy Ho 		num = CFG_COMP(MT8183, param, num_subfrms);
4109e694f1SMoudy Ho 		dis_output = CFG_COMP(MT8183, param, frame.output_disable);
4209e694f1SMoudy Ho 		dis_tile = CFG_COMP(MT8183, param, frame.output_disable);
430e9bd2fcSMoudy Ho 	} else if (CFG_CHECK(MT8195, p_id)) {
440e9bd2fcSMoudy Ho 		num = CFG_COMP(MT8195, param, num_subfrms);
450e9bd2fcSMoudy Ho 		dis_output = CFG_COMP(MT8195, param, frame.output_disable);
460e9bd2fcSMoudy Ho 		dis_tile = CFG_COMP(MT8195, param, frame.output_disable);
4709e694f1SMoudy Ho 	}
4809e694f1SMoudy Ho 
4909e694f1SMoudy Ho 	return (count < num) ? (dis_output || dis_tile) : true;
5061890ccaSMoudy Ho }
5161890ccaSMoudy Ho 
__get_mutex(const struct mdp_dev * mdp_dev,const struct mdp_pipe_info * p)52ee0d0dbbSMoudy Ho static struct mtk_mutex *__get_mutex(const struct mdp_dev *mdp_dev,
53ee0d0dbbSMoudy Ho 				     const struct mdp_pipe_info *p)
54ee0d0dbbSMoudy Ho {
55ee0d0dbbSMoudy Ho 	return mdp_dev->mm_subsys[p->sub_id].mdp_mutex[p->mutex_id];
56ee0d0dbbSMoudy Ho }
57ee0d0dbbSMoudy Ho 
__get_pp_num(enum mdp_stream_type type)589288eae4SMoudy Ho static u8 __get_pp_num(enum mdp_stream_type type)
599288eae4SMoudy Ho {
609288eae4SMoudy Ho 	switch (type) {
619288eae4SMoudy Ho 	case MDP_STREAM_TYPE_DUAL_BITBLT:
629288eae4SMoudy Ho 		return MDP_PP_USED_2;
639288eae4SMoudy Ho 	default:
649288eae4SMoudy Ho 		return MDP_PP_USED_1;
659288eae4SMoudy Ho 	}
669288eae4SMoudy Ho }
679288eae4SMoudy Ho 
__get_pipe(const struct mdp_dev * mdp_dev,enum mtk_mdp_comp_id id)68d9b52f73SMoudy Ho static enum mdp_pipe_id __get_pipe(const struct mdp_dev *mdp_dev,
69d9b52f73SMoudy Ho 				   enum mtk_mdp_comp_id id)
70d9b52f73SMoudy Ho {
71d9b52f73SMoudy Ho 	enum mdp_pipe_id pipe_id;
72d9b52f73SMoudy Ho 
73d9b52f73SMoudy Ho 	switch (id) {
74d9b52f73SMoudy Ho 	case MDP_COMP_RDMA0:
75d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_RDMA0;
76d9b52f73SMoudy Ho 		break;
77d9b52f73SMoudy Ho 	case MDP_COMP_ISP_IMGI:
78d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_IMGI;
79d9b52f73SMoudy Ho 		break;
80d9b52f73SMoudy Ho 	case MDP_COMP_WPEI:
81d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_WPEI;
82d9b52f73SMoudy Ho 		break;
83d9b52f73SMoudy Ho 	case MDP_COMP_WPEI2:
84d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_WPEI2;
85d9b52f73SMoudy Ho 		break;
86d9b52f73SMoudy Ho 	case MDP_COMP_RDMA1:
87d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_RDMA1;
88d9b52f73SMoudy Ho 		break;
89d9b52f73SMoudy Ho 	case MDP_COMP_RDMA2:
90d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_RDMA2;
91d9b52f73SMoudy Ho 		break;
92d9b52f73SMoudy Ho 	case MDP_COMP_RDMA3:
93d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_RDMA3;
94d9b52f73SMoudy Ho 		break;
95d9b52f73SMoudy Ho 	default:
96d9b52f73SMoudy Ho 		/* Avoid exceptions when operating MUTEX */
97d9b52f73SMoudy Ho 		pipe_id = MDP_PIPE_RDMA0;
98d9b52f73SMoudy Ho 		dev_err(&mdp_dev->pdev->dev, "Unknown pipeline id %d", id);
99d9b52f73SMoudy Ho 		break;
100d9b52f73SMoudy Ho 	}
101d9b52f73SMoudy Ho 
102d9b52f73SMoudy Ho 	return pipe_id;
103d9b52f73SMoudy Ho }
104d9b52f73SMoudy Ho 
__get_config_offset(struct mdp_dev * mdp,struct mdp_cmdq_param * param,u8 pp_idx)1059288eae4SMoudy Ho static struct img_config *__get_config_offset(struct mdp_dev *mdp,
1069288eae4SMoudy Ho 					      struct mdp_cmdq_param *param,
1079288eae4SMoudy Ho 					      u8 pp_idx)
1089288eae4SMoudy Ho {
1099288eae4SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
1109288eae4SMoudy Ho 	struct device *dev = &mdp->pdev->dev;
1119288eae4SMoudy Ho 	void *cfg_c, *cfg_n;
1129288eae4SMoudy Ho 	long bound = mdp->vpu.config_size;
1139288eae4SMoudy Ho 
1149288eae4SMoudy Ho 	if (pp_idx >= mdp->mdp_data->pp_used)
1159288eae4SMoudy Ho 		goto err_param;
1169288eae4SMoudy Ho 
1179288eae4SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
1189288eae4SMoudy Ho 		cfg_c = CFG_OFST(MT8183, param->config, pp_idx);
1199288eae4SMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
1209288eae4SMoudy Ho 		cfg_c = CFG_OFST(MT8195, param->config, pp_idx);
1219288eae4SMoudy Ho 	else
1229288eae4SMoudy Ho 		goto err_param;
1239288eae4SMoudy Ho 
1249288eae4SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
1259288eae4SMoudy Ho 		cfg_n = CFG_OFST(MT8183, param->config, pp_idx + 1);
1269288eae4SMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
1279288eae4SMoudy Ho 		cfg_n = CFG_OFST(MT8195, param->config, pp_idx + 1);
1289288eae4SMoudy Ho 	else
1299288eae4SMoudy Ho 		goto err_param;
1309288eae4SMoudy Ho 
1319288eae4SMoudy Ho 	if ((long)cfg_n - (long)mdp->vpu.config > bound) {
1329288eae4SMoudy Ho 		dev_err(dev, "config offset %ld OOB %ld\n", (long)cfg_n, bound);
1339288eae4SMoudy Ho 		cfg_c = ERR_PTR(-EFAULT);
1349288eae4SMoudy Ho 	}
1359288eae4SMoudy Ho 
1369288eae4SMoudy Ho 	return (struct img_config *)cfg_c;
1379288eae4SMoudy Ho 
1389288eae4SMoudy Ho err_param:
1399288eae4SMoudy Ho 	cfg_c = ERR_PTR(-EINVAL);
1409288eae4SMoudy Ho 	return (struct img_config *)cfg_c;
1419288eae4SMoudy Ho }
1429288eae4SMoudy Ho 
mdp_path_subfrm_require(const struct mdp_path * path,struct mdp_cmdq_cmd * cmd,struct mdp_pipe_info * p,u32 count)14361890ccaSMoudy Ho static int mdp_path_subfrm_require(const struct mdp_path *path,
14461890ccaSMoudy Ho 				   struct mdp_cmdq_cmd *cmd,
145ee0d0dbbSMoudy Ho 				   struct mdp_pipe_info *p, u32 count)
14661890ccaSMoudy Ho {
14709e694f1SMoudy Ho 	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
14861890ccaSMoudy Ho 	const struct mdp_comp_ctx *ctx;
14961890ccaSMoudy Ho 	const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;
150ee0d0dbbSMoudy Ho 	struct mtk_mutex *mutex;
15161890ccaSMoudy Ho 	int id, index;
15209e694f1SMoudy Ho 	u32 num_comp = 0;
15309e694f1SMoudy Ho 
15409e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
15509e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
1560e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
1570e9bd2fcSMoudy Ho 		num_comp = CFG_GET(MT8195, path->config, num_components);
15861890ccaSMoudy Ho 
15961890ccaSMoudy Ho 	/* Decide which mutex to use based on the current pipeline */
160d9b52f73SMoudy Ho 	index = __get_pipe(path->mdp_dev, path->comps[0].comp->public_id);
161ee0d0dbbSMoudy Ho 	memcpy(p, &data->pipe_info[index], sizeof(struct mdp_pipe_info));
162ee0d0dbbSMoudy Ho 	mutex = __get_mutex(path->mdp_dev, p);
16361890ccaSMoudy Ho 
16461890ccaSMoudy Ho 	/* Set mutex mod */
16509e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
16692cdfc39SMoudy Ho 		s32 inner_id = MDP_COMP_NONE;
167d97fd41eSMoudy Ho 		const u32 *mutex_idx;
168d97fd41eSMoudy Ho 		const struct mdp_comp_blend *b;
16992cdfc39SMoudy Ho 
17092cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
17192cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
1720e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
1730e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
1740e9bd2fcSMoudy Ho 
17592cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
17692cdfc39SMoudy Ho 			continue;
177d97fd41eSMoudy Ho 
17861890ccaSMoudy Ho 		ctx = &path->comps[index];
17909e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
18061890ccaSMoudy Ho 			continue;
181ee0d0dbbSMoudy Ho 
182d97fd41eSMoudy Ho 		mutex_idx = data->mdp_mutex_table_idx;
183d97fd41eSMoudy Ho 		id = ctx->comp->public_id;
184d97fd41eSMoudy Ho 		mtk_mutex_write_mod(mutex, mutex_idx[id], false);
185d97fd41eSMoudy Ho 
186d97fd41eSMoudy Ho 		b = &data->comp_data[id].blend;
187d97fd41eSMoudy Ho 		if (b && b->aid_mod)
188d97fd41eSMoudy Ho 			mtk_mutex_write_mod(mutex, mutex_idx[b->b_id], false);
18961890ccaSMoudy Ho 	}
19061890ccaSMoudy Ho 
191ee0d0dbbSMoudy Ho 	mtk_mutex_write_sof(mutex, MUTEX_SOF_IDX_SINGLE_MODE);
19261890ccaSMoudy Ho 
19361890ccaSMoudy Ho 	return 0;
19461890ccaSMoudy Ho }
19561890ccaSMoudy Ho 
mdp_path_subfrm_run(const struct mdp_path * path,struct mdp_cmdq_cmd * cmd,struct mdp_pipe_info * p,u32 count)19661890ccaSMoudy Ho static int mdp_path_subfrm_run(const struct mdp_path *path,
19761890ccaSMoudy Ho 			       struct mdp_cmdq_cmd *cmd,
198ee0d0dbbSMoudy Ho 			       struct mdp_pipe_info *p, u32 count)
19961890ccaSMoudy Ho {
20009e694f1SMoudy Ho 	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
20161890ccaSMoudy Ho 	const struct mdp_comp_ctx *ctx;
20261890ccaSMoudy Ho 	struct device *dev = &path->mdp_dev->pdev->dev;
203ee0d0dbbSMoudy Ho 	struct mtk_mutex *mutex;
20461890ccaSMoudy Ho 	int index;
20509e694f1SMoudy Ho 	u32 num_comp = 0;
20661890ccaSMoudy Ho 	s32 event;
20792cdfc39SMoudy Ho 	s32 inner_id = MDP_COMP_NONE;
20861890ccaSMoudy Ho 
209ee0d0dbbSMoudy Ho 	if (-1 == p->mutex_id) {
21061890ccaSMoudy Ho 		dev_err(dev, "Incorrect mutex id");
21161890ccaSMoudy Ho 		return -EINVAL;
21261890ccaSMoudy Ho 	}
21361890ccaSMoudy Ho 
21409e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
21509e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
2160e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
2170e9bd2fcSMoudy Ho 		num_comp = CFG_GET(MT8195, path->config, num_components);
21809e694f1SMoudy Ho 
21961890ccaSMoudy Ho 	/* Wait WROT SRAM shared to DISP RDMA */
22061890ccaSMoudy Ho 	/* Clear SOF event for each engine */
22109e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
22292cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
22392cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
2240e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
2250e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
2260e9bd2fcSMoudy Ho 
22792cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
22892cdfc39SMoudy Ho 			continue;
22961890ccaSMoudy Ho 		ctx = &path->comps[index];
23009e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
23161890ccaSMoudy Ho 			continue;
23261890ccaSMoudy Ho 		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
23361890ccaSMoudy Ho 		if (event != MDP_GCE_NO_EVENT)
23461890ccaSMoudy Ho 			MM_REG_CLEAR(cmd, event);
23561890ccaSMoudy Ho 	}
23661890ccaSMoudy Ho 
23761890ccaSMoudy Ho 	/* Enable the mutex */
238ee0d0dbbSMoudy Ho 	mutex = __get_mutex(path->mdp_dev, p);
239ee0d0dbbSMoudy Ho 	mtk_mutex_enable_by_cmdq(mutex, (void *)&cmd->pkt);
24061890ccaSMoudy Ho 
24161890ccaSMoudy Ho 	/* Wait SOF events and clear mutex modules (optional) */
24209e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
24392cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
24492cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
2450e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
2460e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
2470e9bd2fcSMoudy Ho 
24892cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
24992cdfc39SMoudy Ho 			continue;
25061890ccaSMoudy Ho 		ctx = &path->comps[index];
25109e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
25261890ccaSMoudy Ho 			continue;
25361890ccaSMoudy Ho 		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
25461890ccaSMoudy Ho 		if (event != MDP_GCE_NO_EVENT)
25561890ccaSMoudy Ho 			MM_REG_WAIT(cmd, event);
25661890ccaSMoudy Ho 	}
25761890ccaSMoudy Ho 
25861890ccaSMoudy Ho 	return 0;
25961890ccaSMoudy Ho }
26061890ccaSMoudy Ho 
mdp_path_ctx_init(struct mdp_dev * mdp,struct mdp_path * path)26161890ccaSMoudy Ho static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
26261890ccaSMoudy Ho {
26309e694f1SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
26409e694f1SMoudy Ho 	void *param = NULL;
26561890ccaSMoudy Ho 	int index, ret;
26609e694f1SMoudy Ho 	u32 num_comp = 0;
26761890ccaSMoudy Ho 
26809e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
26909e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
2700e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
2710e9bd2fcSMoudy Ho 		num_comp = CFG_GET(MT8195, path->config, num_components);
27209e694f1SMoudy Ho 
27309e694f1SMoudy Ho 	if (num_comp < 1)
27461890ccaSMoudy Ho 		return -EINVAL;
27561890ccaSMoudy Ho 
27609e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
27792cdfc39SMoudy Ho 		s32 inner_id = MDP_COMP_NONE;
27892cdfc39SMoudy Ho 
27992cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
28092cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
2810e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
2820e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
2830e9bd2fcSMoudy Ho 
28492cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
28592cdfc39SMoudy Ho 			continue;
28609e694f1SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
28709e694f1SMoudy Ho 			param = (void *)CFG_ADDR(MT8183, path->config, components[index]);
2880e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
2890e9bd2fcSMoudy Ho 			param = (void *)CFG_ADDR(MT8195, path->config, components[index]);
29061890ccaSMoudy Ho 		ret = mdp_comp_ctx_config(mdp, &path->comps[index],
29109e694f1SMoudy Ho 					  param, path->param);
29261890ccaSMoudy Ho 		if (ret)
29361890ccaSMoudy Ho 			return ret;
29461890ccaSMoudy Ho 	}
29561890ccaSMoudy Ho 
29661890ccaSMoudy Ho 	return 0;
29761890ccaSMoudy Ho }
29861890ccaSMoudy Ho 
mdp_path_config_subfrm(struct mdp_cmdq_cmd * cmd,struct mdp_path * path,u32 count)29961890ccaSMoudy Ho static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
30061890ccaSMoudy Ho 				  struct mdp_path *path, u32 count)
30161890ccaSMoudy Ho {
30209e694f1SMoudy Ho 	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
30309e694f1SMoudy Ho 	const struct img_mmsys_ctrl *ctrl = NULL;
30461890ccaSMoudy Ho 	const struct img_mux *set;
30561890ccaSMoudy Ho 	struct mdp_comp_ctx *ctx;
306ee0d0dbbSMoudy Ho 	struct mdp_pipe_info pipe;
30761890ccaSMoudy Ho 	int index, ret;
30809e694f1SMoudy Ho 	u32 num_comp = 0;
30992cdfc39SMoudy Ho 	s32 inner_id = MDP_COMP_NONE;
31009e694f1SMoudy Ho 
31109e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
31209e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
3130e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
3140e9bd2fcSMoudy Ho 		num_comp = CFG_GET(MT8195, path->config, num_components);
31509e694f1SMoudy Ho 
31609e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
31709e694f1SMoudy Ho 		ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]);
3180e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
3190e9bd2fcSMoudy Ho 		ctrl = CFG_ADDR(MT8195, path->config, ctrls[count]);
32061890ccaSMoudy Ho 
32161890ccaSMoudy Ho 	/* Acquire components */
322ee0d0dbbSMoudy Ho 	ret = mdp_path_subfrm_require(path, cmd, &pipe, count);
32361890ccaSMoudy Ho 	if (ret)
32461890ccaSMoudy Ho 		return ret;
32561890ccaSMoudy Ho 	/* Enable mux settings */
32661890ccaSMoudy Ho 	for (index = 0; index < ctrl->num_sets; index++) {
32761890ccaSMoudy Ho 		set = &ctrl->sets[index];
32861890ccaSMoudy Ho 		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
32961890ccaSMoudy Ho 				    set->value, 0xFFFFFFFF);
33061890ccaSMoudy Ho 	}
33161890ccaSMoudy Ho 	/* Config sub-frame information */
33209e694f1SMoudy Ho 	for (index = (num_comp - 1); index >= 0; index--) {
33392cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
33492cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
3350e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
3360e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
3370e9bd2fcSMoudy Ho 
33892cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
33992cdfc39SMoudy Ho 			continue;
34061890ccaSMoudy Ho 		ctx = &path->comps[index];
34109e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
34261890ccaSMoudy Ho 			continue;
34361890ccaSMoudy Ho 		ret = call_op(ctx, config_subfrm, cmd, count);
34461890ccaSMoudy Ho 		if (ret)
34561890ccaSMoudy Ho 			return ret;
34661890ccaSMoudy Ho 	}
34761890ccaSMoudy Ho 	/* Run components */
348ee0d0dbbSMoudy Ho 	ret = mdp_path_subfrm_run(path, cmd, &pipe, count);
34961890ccaSMoudy Ho 	if (ret)
35061890ccaSMoudy Ho 		return ret;
35161890ccaSMoudy Ho 	/* Wait components done */
35209e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
35392cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
35492cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
3550e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
3560e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
3570e9bd2fcSMoudy Ho 
35892cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
35992cdfc39SMoudy Ho 			continue;
36061890ccaSMoudy Ho 		ctx = &path->comps[index];
36109e694f1SMoudy Ho 		if (is_output_disabled(p_id, ctx->param, count))
36261890ccaSMoudy Ho 			continue;
36361890ccaSMoudy Ho 		ret = call_op(ctx, wait_comp_event, cmd);
36461890ccaSMoudy Ho 		if (ret)
36561890ccaSMoudy Ho 			return ret;
36661890ccaSMoudy Ho 	}
36761890ccaSMoudy Ho 	/* Advance to the next sub-frame */
36809e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
36992cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
37092cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
3710e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
3720e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
3730e9bd2fcSMoudy Ho 
37492cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
37592cdfc39SMoudy Ho 			continue;
37661890ccaSMoudy Ho 		ctx = &path->comps[index];
37761890ccaSMoudy Ho 		ret = call_op(ctx, advance_subfrm, cmd, count);
37861890ccaSMoudy Ho 		if (ret)
37961890ccaSMoudy Ho 			return ret;
38061890ccaSMoudy Ho 	}
38161890ccaSMoudy Ho 	/* Disable mux settings */
38261890ccaSMoudy Ho 	for (index = 0; index < ctrl->num_sets; index++) {
38361890ccaSMoudy Ho 		set = &ctrl->sets[index];
38461890ccaSMoudy Ho 		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
38561890ccaSMoudy Ho 				    0, 0xFFFFFFFF);
38661890ccaSMoudy Ho 	}
38761890ccaSMoudy Ho 
38861890ccaSMoudy Ho 	return 0;
38961890ccaSMoudy Ho }
39061890ccaSMoudy Ho 
mdp_path_config(struct mdp_dev * mdp,struct mdp_cmdq_cmd * cmd,struct mdp_path * path)39161890ccaSMoudy Ho static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
39261890ccaSMoudy Ho 			   struct mdp_path *path)
39361890ccaSMoudy Ho {
39409e694f1SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
39561890ccaSMoudy Ho 	struct mdp_comp_ctx *ctx;
39661890ccaSMoudy Ho 	int index, count, ret;
39709e694f1SMoudy Ho 	u32 num_comp = 0;
39809e694f1SMoudy Ho 	u32 num_sub = 0;
39992cdfc39SMoudy Ho 	s32 inner_id = MDP_COMP_NONE;
40009e694f1SMoudy Ho 
40109e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
40209e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, path->config, num_components);
4030e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
4040e9bd2fcSMoudy Ho 		num_comp = CFG_GET(MT8195, path->config, num_components);
40509e694f1SMoudy Ho 
40609e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
40709e694f1SMoudy Ho 		num_sub = CFG_GET(MT8183, path->config, num_subfrms);
4080e9bd2fcSMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
4090e9bd2fcSMoudy Ho 		num_sub = CFG_GET(MT8195, path->config, num_subfrms);
41061890ccaSMoudy Ho 
41161890ccaSMoudy Ho 	/* Config path frame */
41261890ccaSMoudy Ho 	/* Reset components */
41309e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
41492cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
41592cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
4160e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
4170e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
4180e9bd2fcSMoudy Ho 
41992cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
42092cdfc39SMoudy Ho 			continue;
42161890ccaSMoudy Ho 		ctx = &path->comps[index];
42261890ccaSMoudy Ho 		ret = call_op(ctx, init_comp, cmd);
42361890ccaSMoudy Ho 		if (ret)
42461890ccaSMoudy Ho 			return ret;
42561890ccaSMoudy Ho 	}
42661890ccaSMoudy Ho 	/* Config frame mode */
42709e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
42809e694f1SMoudy Ho 		const struct v4l2_rect *compose;
42909e694f1SMoudy Ho 		u32 out = 0;
43061890ccaSMoudy Ho 
4312a76e767SMoudy Ho 		ctx = &path->comps[index];
43209e694f1SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
43392cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
4340e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
4350e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
4360e9bd2fcSMoudy Ho 
43792cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
43892cdfc39SMoudy Ho 			continue;
43992cdfc39SMoudy Ho 
44092cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
44109e694f1SMoudy Ho 			out = CFG_COMP(MT8183, ctx->param, outputs[0]);
4420e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
4430e9bd2fcSMoudy Ho 			out = CFG_COMP(MT8195, ctx->param, outputs[0]);
44409e694f1SMoudy Ho 
44509e694f1SMoudy Ho 		compose = path->composes[out];
44661890ccaSMoudy Ho 		ret = call_op(ctx, config_frame, cmd, compose);
44761890ccaSMoudy Ho 		if (ret)
44861890ccaSMoudy Ho 			return ret;
44961890ccaSMoudy Ho 	}
45061890ccaSMoudy Ho 
45161890ccaSMoudy Ho 	/* Config path sub-frames */
45209e694f1SMoudy Ho 	for (count = 0; count < num_sub; count++) {
45361890ccaSMoudy Ho 		ret = mdp_path_config_subfrm(cmd, path, count);
45461890ccaSMoudy Ho 		if (ret)
45561890ccaSMoudy Ho 			return ret;
45661890ccaSMoudy Ho 	}
45761890ccaSMoudy Ho 	/* Post processing information */
45809e694f1SMoudy Ho 	for (index = 0; index < num_comp; index++) {
45992cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
46092cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[index].type);
4610e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
4620e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[index].type);
4630e9bd2fcSMoudy Ho 
46492cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))
46592cdfc39SMoudy Ho 			continue;
46661890ccaSMoudy Ho 		ctx = &path->comps[index];
46761890ccaSMoudy Ho 		ret = call_op(ctx, post_process, cmd);
46861890ccaSMoudy Ho 		if (ret)
46961890ccaSMoudy Ho 			return ret;
47061890ccaSMoudy Ho 	}
47161890ccaSMoudy Ho 	return 0;
47261890ccaSMoudy Ho }
47361890ccaSMoudy Ho 
mdp_cmdq_pkt_create(struct cmdq_client * client,struct cmdq_pkt * pkt,size_t size)47461890ccaSMoudy Ho static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
47561890ccaSMoudy Ho 			       size_t size)
47661890ccaSMoudy Ho {
47761890ccaSMoudy Ho 	struct device *dev;
47861890ccaSMoudy Ho 	dma_addr_t dma_addr;
47961890ccaSMoudy Ho 
48061890ccaSMoudy Ho 	pkt->va_base = kzalloc(size, GFP_KERNEL);
48164e0a080SMoudy Ho 	if (!pkt->va_base)
48261890ccaSMoudy Ho 		return -ENOMEM;
48364e0a080SMoudy Ho 
48461890ccaSMoudy Ho 	pkt->buf_size = size;
48561890ccaSMoudy Ho 	pkt->cl = (void *)client;
48661890ccaSMoudy Ho 
48761890ccaSMoudy Ho 	dev = client->chan->mbox->dev;
48861890ccaSMoudy Ho 	dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
48961890ccaSMoudy Ho 				  DMA_TO_DEVICE);
49061890ccaSMoudy Ho 	if (dma_mapping_error(dev, dma_addr)) {
49161890ccaSMoudy Ho 		dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
49261890ccaSMoudy Ho 		kfree(pkt->va_base);
49361890ccaSMoudy Ho 		return -ENOMEM;
49461890ccaSMoudy Ho 	}
49561890ccaSMoudy Ho 
49661890ccaSMoudy Ho 	pkt->pa_base = dma_addr;
49761890ccaSMoudy Ho 
49861890ccaSMoudy Ho 	return 0;
49961890ccaSMoudy Ho }
50061890ccaSMoudy Ho 
mdp_cmdq_pkt_destroy(struct cmdq_pkt * pkt)50161890ccaSMoudy Ho static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
50261890ccaSMoudy Ho {
50361890ccaSMoudy Ho 	struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
50461890ccaSMoudy Ho 
50561890ccaSMoudy Ho 	dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
50661890ccaSMoudy Ho 			 DMA_TO_DEVICE);
50761890ccaSMoudy Ho 	kfree(pkt->va_base);
50861890ccaSMoudy Ho 	pkt->va_base = NULL;
50961890ccaSMoudy Ho }
51061890ccaSMoudy Ho 
mdp_auto_release_work(struct work_struct * work)51161890ccaSMoudy Ho static void mdp_auto_release_work(struct work_struct *work)
51261890ccaSMoudy Ho {
51361890ccaSMoudy Ho 	struct mdp_cmdq_cmd *cmd;
51461890ccaSMoudy Ho 	struct mdp_dev *mdp;
515ee0d0dbbSMoudy Ho 	struct mtk_mutex *mutex;
516d9b52f73SMoudy Ho 	enum mdp_pipe_id pipe_id;
51761890ccaSMoudy Ho 
51861890ccaSMoudy Ho 	cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);
51961890ccaSMoudy Ho 	mdp = cmd->mdp;
52061890ccaSMoudy Ho 
521d9b52f73SMoudy Ho 	pipe_id = __get_pipe(mdp, cmd->comps[0].public_id);
522d9b52f73SMoudy Ho 	mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]);
523ee0d0dbbSMoudy Ho 	mtk_mutex_unprepare(mutex);
52461890ccaSMoudy Ho 	mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
52561890ccaSMoudy Ho 			    cmd->num_comps);
52661890ccaSMoudy Ho 
527*7aa9066eSRicardo Ribalda 	if (refcount_dec_and_test(&mdp->job_count)) {
5289288eae4SMoudy Ho 		if (cmd->mdp_ctx)
5299288eae4SMoudy Ho 			mdp_m2m_job_finish(cmd->mdp_ctx);
5309288eae4SMoudy Ho 
5319288eae4SMoudy Ho 		if (cmd->user_cmdq_cb) {
5329288eae4SMoudy Ho 			struct cmdq_cb_data user_cb_data;
5339288eae4SMoudy Ho 
5349288eae4SMoudy Ho 			user_cb_data.sta = cmd->data->sta;
5359288eae4SMoudy Ho 			user_cb_data.pkt = cmd->data->pkt;
5369288eae4SMoudy Ho 			cmd->user_cmdq_cb(user_cb_data);
5379288eae4SMoudy Ho 		}
53861890ccaSMoudy Ho 		wake_up(&mdp->callback_wq);
5399288eae4SMoudy Ho 	}
54061890ccaSMoudy Ho 
54161890ccaSMoudy Ho 	mdp_cmdq_pkt_destroy(&cmd->pkt);
54261890ccaSMoudy Ho 	kfree(cmd->comps);
54361890ccaSMoudy Ho 	cmd->comps = NULL;
54461890ccaSMoudy Ho 	kfree(cmd);
54561890ccaSMoudy Ho 	cmd = NULL;
54661890ccaSMoudy Ho }
54761890ccaSMoudy Ho 
mdp_handle_cmdq_callback(struct mbox_client * cl,void * mssg)54861890ccaSMoudy Ho static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
54961890ccaSMoudy Ho {
55061890ccaSMoudy Ho 	struct mdp_cmdq_cmd *cmd;
55161890ccaSMoudy Ho 	struct cmdq_cb_data *data;
55261890ccaSMoudy Ho 	struct mdp_dev *mdp;
55361890ccaSMoudy Ho 	struct device *dev;
554d9b52f73SMoudy Ho 	enum mdp_pipe_id pipe_id;
55561890ccaSMoudy Ho 
55661890ccaSMoudy Ho 	if (!mssg) {
55761890ccaSMoudy Ho 		pr_info("%s:no callback data\n", __func__);
55861890ccaSMoudy Ho 		return;
55961890ccaSMoudy Ho 	}
56061890ccaSMoudy Ho 
56161890ccaSMoudy Ho 	data = (struct cmdq_cb_data *)mssg;
56261890ccaSMoudy Ho 	cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt);
5639288eae4SMoudy Ho 	cmd->data = data;
56461890ccaSMoudy Ho 	mdp = cmd->mdp;
56561890ccaSMoudy Ho 	dev = &mdp->pdev->dev;
56661890ccaSMoudy Ho 
56761890ccaSMoudy Ho 	INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);
56861890ccaSMoudy Ho 	if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {
569ee0d0dbbSMoudy Ho 		struct mtk_mutex *mutex;
570ee0d0dbbSMoudy Ho 
57161890ccaSMoudy Ho 		dev_err(dev, "%s:queue_work fail!\n", __func__);
572d9b52f73SMoudy Ho 		pipe_id = __get_pipe(mdp, cmd->comps[0].public_id);
573d9b52f73SMoudy Ho 		mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]);
574ee0d0dbbSMoudy Ho 		mtk_mutex_unprepare(mutex);
57561890ccaSMoudy Ho 		mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
57661890ccaSMoudy Ho 				    cmd->num_comps);
57761890ccaSMoudy Ho 
578*7aa9066eSRicardo Ribalda 		if (refcount_dec_and_test(&mdp->job_count))
57961890ccaSMoudy Ho 			wake_up(&mdp->callback_wq);
58061890ccaSMoudy Ho 
58161890ccaSMoudy Ho 		mdp_cmdq_pkt_destroy(&cmd->pkt);
58261890ccaSMoudy Ho 		kfree(cmd->comps);
58361890ccaSMoudy Ho 		cmd->comps = NULL;
58461890ccaSMoudy Ho 		kfree(cmd);
58561890ccaSMoudy Ho 		cmd = NULL;
58661890ccaSMoudy Ho 	}
58761890ccaSMoudy Ho }
58861890ccaSMoudy Ho 
mdp_cmdq_prepare(struct mdp_dev * mdp,struct mdp_cmdq_param * param,u8 pp_idx)5899288eae4SMoudy Ho static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp,
5909288eae4SMoudy Ho 					     struct mdp_cmdq_param *param,
5919288eae4SMoudy Ho 					     u8 pp_idx)
59261890ccaSMoudy Ho {
59361890ccaSMoudy Ho 	struct mdp_path *path = NULL;
59461890ccaSMoudy Ho 	struct mdp_cmdq_cmd *cmd = NULL;
59561890ccaSMoudy Ho 	struct mdp_comp *comps = NULL;
59661890ccaSMoudy Ho 	struct device *dev = &mdp->pdev->dev;
59709e694f1SMoudy Ho 	const int p_id = mdp->mdp_data->mdp_plat_id;
5989288eae4SMoudy Ho 	struct img_config *config;
599ee0d0dbbSMoudy Ho 	struct mtk_mutex *mutex = NULL;
600d9b52f73SMoudy Ho 	enum mdp_pipe_id pipe_id;
6019288eae4SMoudy Ho 	int i, ret = -ECANCELED;
6029288eae4SMoudy Ho 	u32 num_comp;
60361890ccaSMoudy Ho 
6049288eae4SMoudy Ho 	config = __get_config_offset(mdp, param, pp_idx);
6059288eae4SMoudy Ho 	if (IS_ERR(config)) {
6069288eae4SMoudy Ho 		ret = PTR_ERR(config);
6079288eae4SMoudy Ho 		goto err_uninit;
60861890ccaSMoudy Ho 	}
60961890ccaSMoudy Ho 
6109288eae4SMoudy Ho 	if (CFG_CHECK(MT8183, p_id))
6119288eae4SMoudy Ho 		num_comp = CFG_GET(MT8183, config, num_components);
6129288eae4SMoudy Ho 	else if (CFG_CHECK(MT8195, p_id))
6139288eae4SMoudy Ho 		num_comp = CFG_GET(MT8195, config, num_components);
6149288eae4SMoudy Ho 	else
6159288eae4SMoudy Ho 		goto err_uninit;
6169288eae4SMoudy Ho 
61761890ccaSMoudy Ho 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
61861890ccaSMoudy Ho 	if (!cmd) {
61961890ccaSMoudy Ho 		ret = -ENOMEM;
6209288eae4SMoudy Ho 		goto err_uninit;
62161890ccaSMoudy Ho 	}
62261890ccaSMoudy Ho 
6239288eae4SMoudy Ho 	ret = mdp_cmdq_pkt_create(mdp->cmdq_clt[pp_idx], &cmd->pkt, SZ_16K);
62464e0a080SMoudy Ho 	if (ret)
62564e0a080SMoudy Ho 		goto err_free_cmd;
62661890ccaSMoudy Ho 
62709e694f1SMoudy Ho 	if (CFG_CHECK(MT8183, p_id)) {
62809e694f1SMoudy Ho 		num_comp = CFG_GET(MT8183, param->config, num_components);
6290e9bd2fcSMoudy Ho 	} else if (CFG_CHECK(MT8195, p_id)) {
6300e9bd2fcSMoudy Ho 		num_comp = CFG_GET(MT8195, param->config, num_components);
63109e694f1SMoudy Ho 	} else {
63209e694f1SMoudy Ho 		ret = -EINVAL;
63309e694f1SMoudy Ho 		goto err_destroy_pkt;
63409e694f1SMoudy Ho 	}
63509e694f1SMoudy Ho 	comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL);
63661890ccaSMoudy Ho 	if (!comps) {
63761890ccaSMoudy Ho 		ret = -ENOMEM;
63864e0a080SMoudy Ho 		goto err_destroy_pkt;
63961890ccaSMoudy Ho 	}
64061890ccaSMoudy Ho 
64161890ccaSMoudy Ho 	path = kzalloc(sizeof(*path), GFP_KERNEL);
64261890ccaSMoudy Ho 	if (!path) {
64361890ccaSMoudy Ho 		ret = -ENOMEM;
64464e0a080SMoudy Ho 		goto err_free_comps;
64564e0a080SMoudy Ho 	}
64664e0a080SMoudy Ho 
64761890ccaSMoudy Ho 	path->mdp_dev = mdp;
6489288eae4SMoudy Ho 	path->config = config;
64961890ccaSMoudy Ho 	path->param = param->param;
65061890ccaSMoudy Ho 	for (i = 0; i < param->param->num_outputs; i++) {
65161890ccaSMoudy Ho 		path->bounds[i].left = 0;
65261890ccaSMoudy Ho 		path->bounds[i].top = 0;
65361890ccaSMoudy Ho 		path->bounds[i].width =
65461890ccaSMoudy Ho 			param->param->outputs[i].buffer.format.width;
65561890ccaSMoudy Ho 		path->bounds[i].height =
65661890ccaSMoudy Ho 			param->param->outputs[i].buffer.format.height;
65761890ccaSMoudy Ho 		path->composes[i] = param->composes[i] ?
65861890ccaSMoudy Ho 			param->composes[i] : &path->bounds[i];
65961890ccaSMoudy Ho 	}
66061890ccaSMoudy Ho 	ret = mdp_path_ctx_init(mdp, path);
66161890ccaSMoudy Ho 	if (ret) {
6629288eae4SMoudy Ho 		dev_err(dev, "mdp_path_ctx_init error %d\n", pp_idx);
66364e0a080SMoudy Ho 		goto err_free_path;
66461890ccaSMoudy Ho 	}
66561890ccaSMoudy Ho 
666d9b52f73SMoudy Ho 	pipe_id = __get_pipe(mdp, path->comps[0].comp->public_id);
667d9b52f73SMoudy Ho 	mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]);
668d9b52f73SMoudy Ho 	ret = mtk_mutex_prepare(mutex);
669d9b52f73SMoudy Ho 	if (ret) {
6709288eae4SMoudy Ho 		dev_err(dev, "Fail to enable mutex %d clk\n", pp_idx);
671d9b52f73SMoudy Ho 		goto err_free_path;
672d9b52f73SMoudy Ho 	}
673d9b52f73SMoudy Ho 
67461890ccaSMoudy Ho 	ret = mdp_path_config(mdp, cmd, path);
67561890ccaSMoudy Ho 	if (ret) {
6769288eae4SMoudy Ho 		dev_err(dev, "mdp_path_config error %d\n", pp_idx);
67764e0a080SMoudy Ho 		goto err_free_path;
67861890ccaSMoudy Ho 	}
67961890ccaSMoudy Ho 	cmdq_pkt_finalize(&cmd->pkt);
68061890ccaSMoudy Ho 
68192cdfc39SMoudy Ho 	for (i = 0; i < num_comp; i++) {
68292cdfc39SMoudy Ho 		s32 inner_id = MDP_COMP_NONE;
68392cdfc39SMoudy Ho 
68492cdfc39SMoudy Ho 		if (CFG_CHECK(MT8183, p_id))
68592cdfc39SMoudy Ho 			inner_id = CFG_GET(MT8183, path->config, components[i].type);
6860e9bd2fcSMoudy Ho 		else if (CFG_CHECK(MT8195, p_id))
6870e9bd2fcSMoudy Ho 			inner_id = CFG_GET(MT8195, path->config, components[i].type);
6880e9bd2fcSMoudy Ho 
68992cdfc39SMoudy Ho 		if (mdp_cfg_comp_is_dummy(mdp, inner_id))
69092cdfc39SMoudy Ho 			continue;
69161890ccaSMoudy Ho 		memcpy(&comps[i], path->comps[i].comp,
69261890ccaSMoudy Ho 		       sizeof(struct mdp_comp));
69392cdfc39SMoudy Ho 	}
69461890ccaSMoudy Ho 
6959288eae4SMoudy Ho 	mdp->cmdq_clt[pp_idx]->client.rx_callback = mdp_handle_cmdq_callback;
69661890ccaSMoudy Ho 	cmd->mdp = mdp;
69761890ccaSMoudy Ho 	cmd->user_cmdq_cb = param->cmdq_cb;
69861890ccaSMoudy Ho 	cmd->user_cb_data = param->cb_data;
69961890ccaSMoudy Ho 	cmd->comps = comps;
70009e694f1SMoudy Ho 	cmd->num_comps = num_comp;
70161890ccaSMoudy Ho 	cmd->mdp_ctx = param->mdp_ctx;
70261890ccaSMoudy Ho 
70361890ccaSMoudy Ho 	kfree(path);
7049288eae4SMoudy Ho 	return cmd;
70561890ccaSMoudy Ho 
70664e0a080SMoudy Ho err_free_path:
707ee0d0dbbSMoudy Ho 	if (mutex)
708ee0d0dbbSMoudy Ho 		mtk_mutex_unprepare(mutex);
70961890ccaSMoudy Ho 	kfree(path);
71064e0a080SMoudy Ho err_free_comps:
71161890ccaSMoudy Ho 	kfree(comps);
71264e0a080SMoudy Ho err_destroy_pkt:
71364e0a080SMoudy Ho 	mdp_cmdq_pkt_destroy(&cmd->pkt);
71464e0a080SMoudy Ho err_free_cmd:
71561890ccaSMoudy Ho 	kfree(cmd);
7169288eae4SMoudy Ho err_uninit:
7179288eae4SMoudy Ho 	return ERR_PTR(ret);
7189288eae4SMoudy Ho }
7199288eae4SMoudy Ho 
mdp_cmdq_send(struct mdp_dev * mdp,struct mdp_cmdq_param * param)7209288eae4SMoudy Ho int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
7219288eae4SMoudy Ho {
7229288eae4SMoudy Ho 	struct mdp_cmdq_cmd *cmd[MDP_PP_MAX] = {NULL};
7239288eae4SMoudy Ho 	struct device *dev = &mdp->pdev->dev;
7249288eae4SMoudy Ho 	int i, ret;
7259288eae4SMoudy Ho 	u8 pp_used = __get_pp_num(param->param->type);
7269288eae4SMoudy Ho 
727*7aa9066eSRicardo Ribalda 	refcount_set(&mdp->job_count, pp_used);
7289288eae4SMoudy Ho 	if (atomic_read(&mdp->suspended)) {
729*7aa9066eSRicardo Ribalda 		refcount_set(&mdp->job_count, 0);
7309288eae4SMoudy Ho 		return -ECANCELED;
7319288eae4SMoudy Ho 	}
7329288eae4SMoudy Ho 
7339288eae4SMoudy Ho 	for (i = 0; i < pp_used; i++) {
7349288eae4SMoudy Ho 		cmd[i] = mdp_cmdq_prepare(mdp, param, i);
7359288eae4SMoudy Ho 		if (IS_ERR_OR_NULL(cmd[i])) {
7369288eae4SMoudy Ho 			ret = PTR_ERR(cmd[i]);
7379288eae4SMoudy Ho 			goto err_cancel_job;
7389288eae4SMoudy Ho 		}
7399288eae4SMoudy Ho 	}
7409288eae4SMoudy Ho 
7419288eae4SMoudy Ho 	for (i = 0; i < pp_used; i++) {
7429288eae4SMoudy Ho 		ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd[i]->comps, cmd[i]->num_comps);
7439288eae4SMoudy Ho 		if (ret)
7449288eae4SMoudy Ho 			goto err_clock_off;
7459288eae4SMoudy Ho 	}
7469288eae4SMoudy Ho 
7479288eae4SMoudy Ho 	for (i = 0; i < pp_used; i++) {
7489288eae4SMoudy Ho 		dma_sync_single_for_device(mdp->cmdq_clt[i]->chan->mbox->dev,
7499288eae4SMoudy Ho 					   cmd[i]->pkt.pa_base, cmd[i]->pkt.cmd_buf_size,
7509288eae4SMoudy Ho 					   DMA_TO_DEVICE);
7519288eae4SMoudy Ho 
7529288eae4SMoudy Ho 		ret = mbox_send_message(mdp->cmdq_clt[i]->chan, &cmd[i]->pkt);
7539288eae4SMoudy Ho 		if (ret < 0) {
7549288eae4SMoudy Ho 			dev_err(dev, "mbox send message fail %d!\n", ret);
7559288eae4SMoudy Ho 			i = pp_used;
7569288eae4SMoudy Ho 			goto err_clock_off;
7579288eae4SMoudy Ho 		}
7589288eae4SMoudy Ho 		mbox_client_txdone(mdp->cmdq_clt[i]->chan, 0);
7599288eae4SMoudy Ho 	}
7609288eae4SMoudy Ho 	return 0;
7619288eae4SMoudy Ho 
7629288eae4SMoudy Ho err_clock_off:
7639288eae4SMoudy Ho 	while (--i >= 0)
7649288eae4SMoudy Ho 		mdp_comp_clocks_off(&mdp->pdev->dev, cmd[i]->comps,
7659288eae4SMoudy Ho 				    cmd[i]->num_comps);
76664e0a080SMoudy Ho err_cancel_job:
767*7aa9066eSRicardo Ribalda 	refcount_set(&mdp->job_count, 0);
76864e0a080SMoudy Ho 
76961890ccaSMoudy Ho 	return ret;
77061890ccaSMoudy Ho }
77161890ccaSMoudy Ho EXPORT_SYMBOL_GPL(mdp_cmdq_send);
772