brintos

brintos / linux-shallow public Read only

0
0
Text · 20.4 KiB · ea2ea11 Raw
772 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2022 MediaTek Inc.4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>5 */6 7#include <linux/mailbox_controller.h>8#include <linux/platform_device.h>9#include "mtk-mdp3-cfg.h"10#include "mtk-mdp3-cmdq.h"11#include "mtk-mdp3-comp.h"12#include "mtk-mdp3-core.h"13#include "mtk-mdp3-m2m.h"14#include "mtk-img-ipi.h"15 16#define MDP_PATH_MAX_COMPS	IMG_MAX_COMPONENTS17 18struct mdp_path {19	struct mdp_dev		*mdp_dev;20	struct mdp_comp_ctx	comps[MDP_PATH_MAX_COMPS];21	u32			num_comps;22	const struct img_config	*config;23	const struct img_ipi_frameparam *param;24	const struct v4l2_rect	*composes[IMG_MAX_HW_OUTPUTS];25	struct v4l2_rect	bounds[IMG_MAX_HW_OUTPUTS];26};27 28#define has_op(ctx, op) \29	((ctx)->comp->ops && (ctx)->comp->ops->op)30 #define call_op(ctx, op, ...) \31	(has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)32 33static bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count)34{35	u32 num = 0;36	bool dis_output = false;37	bool dis_tile = false;38 39	if (CFG_CHECK(MT8183, p_id)) {40		num = CFG_COMP(MT8183, param, num_subfrms);41		dis_output = CFG_COMP(MT8183, param, frame.output_disable);42		dis_tile = CFG_COMP(MT8183, param, frame.output_disable);43	} else if (CFG_CHECK(MT8195, p_id)) {44		num = CFG_COMP(MT8195, param, num_subfrms);45		dis_output = CFG_COMP(MT8195, param, frame.output_disable);46		dis_tile = CFG_COMP(MT8195, param, frame.output_disable);47	}48 49	return (count < num) ? (dis_output || dis_tile) : true;50}51 52static struct mtk_mutex *__get_mutex(const struct mdp_dev *mdp_dev,53				     const struct mdp_pipe_info *p)54{55	return mdp_dev->mm_subsys[p->sub_id].mdp_mutex[p->mutex_id];56}57 58static u8 __get_pp_num(enum mdp_stream_type type)59{60	switch (type) {61	case MDP_STREAM_TYPE_DUAL_BITBLT:62		return MDP_PP_USED_2;63	default:64		return MDP_PP_USED_1;65	}66}67 68static enum mdp_pipe_id __get_pipe(const struct mdp_dev *mdp_dev,69				   enum mtk_mdp_comp_id id)70{71	enum mdp_pipe_id pipe_id;72 73	switch (id) {74	case MDP_COMP_RDMA0:75		pipe_id = MDP_PIPE_RDMA0;76		break;77	case MDP_COMP_ISP_IMGI:78		pipe_id = MDP_PIPE_IMGI;79		break;80	case MDP_COMP_WPEI:81		pipe_id = MDP_PIPE_WPEI;82		break;83	case MDP_COMP_WPEI2:84		pipe_id = MDP_PIPE_WPEI2;85		break;86	case MDP_COMP_RDMA1:87		pipe_id = MDP_PIPE_RDMA1;88		break;89	case MDP_COMP_RDMA2:90		pipe_id = MDP_PIPE_RDMA2;91		break;92	case MDP_COMP_RDMA3:93		pipe_id = MDP_PIPE_RDMA3;94		break;95	default:96		/* Avoid exceptions when operating MUTEX */97		pipe_id = MDP_PIPE_RDMA0;98		dev_err(&mdp_dev->pdev->dev, "Unknown pipeline id %d", id);99		break;100	}101 102	return pipe_id;103}104 105static struct img_config *__get_config_offset(struct mdp_dev *mdp,106					      struct mdp_cmdq_param *param,107					      u8 pp_idx)108{109	const int p_id = mdp->mdp_data->mdp_plat_id;110	struct device *dev = &mdp->pdev->dev;111	void *cfg_c, *cfg_n;112	long bound = mdp->vpu.config_size;113 114	if (pp_idx >= mdp->mdp_data->pp_used)115		goto err_param;116 117	if (CFG_CHECK(MT8183, p_id))118		cfg_c = CFG_OFST(MT8183, param->config, pp_idx);119	else if (CFG_CHECK(MT8195, p_id))120		cfg_c = CFG_OFST(MT8195, param->config, pp_idx);121	else122		goto err_param;123 124	if (CFG_CHECK(MT8183, p_id))125		cfg_n = CFG_OFST(MT8183, param->config, pp_idx + 1);126	else if (CFG_CHECK(MT8195, p_id))127		cfg_n = CFG_OFST(MT8195, param->config, pp_idx + 1);128	else129		goto err_param;130 131	if ((long)cfg_n - (long)mdp->vpu.config > bound) {132		dev_err(dev, "config offset %ld OOB %ld\n", (long)cfg_n, bound);133		cfg_c = ERR_PTR(-EFAULT);134	}135 136	return (struct img_config *)cfg_c;137 138err_param:139	cfg_c = ERR_PTR(-EINVAL);140	return (struct img_config *)cfg_c;141}142 143static int mdp_path_subfrm_require(const struct mdp_path *path,144				   struct mdp_cmdq_cmd *cmd,145				   struct mdp_pipe_info *p, u32 count)146{147	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;148	const struct mdp_comp_ctx *ctx;149	const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;150	struct mtk_mutex *mutex;151	int id, index;152	u32 num_comp = 0;153 154	if (CFG_CHECK(MT8183, p_id))155		num_comp = CFG_GET(MT8183, path->config, num_components);156	else if (CFG_CHECK(MT8195, p_id))157		num_comp = CFG_GET(MT8195, path->config, num_components);158 159	/* Decide which mutex to use based on the current pipeline */160	index = __get_pipe(path->mdp_dev, path->comps[0].comp->public_id);161	memcpy(p, &data->pipe_info[index], sizeof(struct mdp_pipe_info));162	mutex = __get_mutex(path->mdp_dev, p);163 164	/* Set mutex mod */165	for (index = 0; index < num_comp; index++) {166		s32 inner_id = MDP_COMP_NONE;167		const u32 *mutex_idx;168		const struct mdp_comp_blend *b;169 170		if (CFG_CHECK(MT8183, p_id))171			inner_id = CFG_GET(MT8183, path->config, components[index].type);172		else if (CFG_CHECK(MT8195, p_id))173			inner_id = CFG_GET(MT8195, path->config, components[index].type);174 175		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))176			continue;177 178		ctx = &path->comps[index];179		if (is_output_disabled(p_id, ctx->param, count))180			continue;181 182		mutex_idx = data->mdp_mutex_table_idx;183		id = ctx->comp->public_id;184		mtk_mutex_write_mod(mutex, mutex_idx[id], false);185 186		b = &data->comp_data[id].blend;187		if (b && b->aid_mod)188			mtk_mutex_write_mod(mutex, mutex_idx[b->b_id], false);189	}190 191	mtk_mutex_write_sof(mutex, MUTEX_SOF_IDX_SINGLE_MODE);192 193	return 0;194}195 196static int mdp_path_subfrm_run(const struct mdp_path *path,197			       struct mdp_cmdq_cmd *cmd,198			       struct mdp_pipe_info *p, u32 count)199{200	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;201	const struct mdp_comp_ctx *ctx;202	struct device *dev = &path->mdp_dev->pdev->dev;203	struct mtk_mutex *mutex;204	int index;205	u32 num_comp = 0;206	s32 event;207	s32 inner_id = MDP_COMP_NONE;208 209	if (-1 == p->mutex_id) {210		dev_err(dev, "Incorrect mutex id");211		return -EINVAL;212	}213 214	if (CFG_CHECK(MT8183, p_id))215		num_comp = CFG_GET(MT8183, path->config, num_components);216	else if (CFG_CHECK(MT8195, p_id))217		num_comp = CFG_GET(MT8195, path->config, num_components);218 219	/* Wait WROT SRAM shared to DISP RDMA */220	/* Clear SOF event for each engine */221	for (index = 0; index < num_comp; index++) {222		if (CFG_CHECK(MT8183, p_id))223			inner_id = CFG_GET(MT8183, path->config, components[index].type);224		else if (CFG_CHECK(MT8195, p_id))225			inner_id = CFG_GET(MT8195, path->config, components[index].type);226 227		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))228			continue;229		ctx = &path->comps[index];230		if (is_output_disabled(p_id, ctx->param, count))231			continue;232		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];233		if (event != MDP_GCE_NO_EVENT)234			MM_REG_CLEAR(cmd, event);235	}236 237	/* Enable the mutex */238	mutex = __get_mutex(path->mdp_dev, p);239	mtk_mutex_enable_by_cmdq(mutex, (void *)&cmd->pkt);240 241	/* Wait SOF events and clear mutex modules (optional) */242	for (index = 0; index < num_comp; index++) {243		if (CFG_CHECK(MT8183, p_id))244			inner_id = CFG_GET(MT8183, path->config, components[index].type);245		else if (CFG_CHECK(MT8195, p_id))246			inner_id = CFG_GET(MT8195, path->config, components[index].type);247 248		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))249			continue;250		ctx = &path->comps[index];251		if (is_output_disabled(p_id, ctx->param, count))252			continue;253		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];254		if (event != MDP_GCE_NO_EVENT)255			MM_REG_WAIT(cmd, event);256	}257 258	return 0;259}260 261static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)262{263	const int p_id = mdp->mdp_data->mdp_plat_id;264	void *param = NULL;265	int index, ret;266	u32 num_comp = 0;267 268	if (CFG_CHECK(MT8183, p_id))269		num_comp = CFG_GET(MT8183, path->config, num_components);270	else if (CFG_CHECK(MT8195, p_id))271		num_comp = CFG_GET(MT8195, path->config, num_components);272 273	if (num_comp < 1)274		return -EINVAL;275 276	for (index = 0; index < num_comp; index++) {277		s32 inner_id = MDP_COMP_NONE;278 279		if (CFG_CHECK(MT8183, p_id))280			inner_id = CFG_GET(MT8183, path->config, components[index].type);281		else if (CFG_CHECK(MT8195, p_id))282			inner_id = CFG_GET(MT8195, path->config, components[index].type);283 284		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))285			continue;286		if (CFG_CHECK(MT8183, p_id))287			param = (void *)CFG_ADDR(MT8183, path->config, components[index]);288		else if (CFG_CHECK(MT8195, p_id))289			param = (void *)CFG_ADDR(MT8195, path->config, components[index]);290		ret = mdp_comp_ctx_config(mdp, &path->comps[index],291					  param, path->param);292		if (ret)293			return ret;294	}295 296	return 0;297}298 299static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,300				  struct mdp_path *path, u32 count)301{302	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;303	const struct img_mmsys_ctrl *ctrl = NULL;304	const struct img_mux *set;305	struct mdp_comp_ctx *ctx;306	struct mdp_pipe_info pipe;307	int index, ret;308	u32 num_comp = 0;309	s32 inner_id = MDP_COMP_NONE;310 311	if (CFG_CHECK(MT8183, p_id))312		num_comp = CFG_GET(MT8183, path->config, num_components);313	else if (CFG_CHECK(MT8195, p_id))314		num_comp = CFG_GET(MT8195, path->config, num_components);315 316	if (CFG_CHECK(MT8183, p_id))317		ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]);318	else if (CFG_CHECK(MT8195, p_id))319		ctrl = CFG_ADDR(MT8195, path->config, ctrls[count]);320 321	/* Acquire components */322	ret = mdp_path_subfrm_require(path, cmd, &pipe, count);323	if (ret)324		return ret;325	/* Enable mux settings */326	for (index = 0; index < ctrl->num_sets; index++) {327		set = &ctrl->sets[index];328		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,329				    set->value, 0xFFFFFFFF);330	}331	/* Config sub-frame information */332	for (index = (num_comp - 1); index >= 0; index--) {333		if (CFG_CHECK(MT8183, p_id))334			inner_id = CFG_GET(MT8183, path->config, components[index].type);335		else if (CFG_CHECK(MT8195, p_id))336			inner_id = CFG_GET(MT8195, path->config, components[index].type);337 338		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))339			continue;340		ctx = &path->comps[index];341		if (is_output_disabled(p_id, ctx->param, count))342			continue;343		ret = call_op(ctx, config_subfrm, cmd, count);344		if (ret)345			return ret;346	}347	/* Run components */348	ret = mdp_path_subfrm_run(path, cmd, &pipe, count);349	if (ret)350		return ret;351	/* Wait components done */352	for (index = 0; index < num_comp; index++) {353		if (CFG_CHECK(MT8183, p_id))354			inner_id = CFG_GET(MT8183, path->config, components[index].type);355		else if (CFG_CHECK(MT8195, p_id))356			inner_id = CFG_GET(MT8195, path->config, components[index].type);357 358		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))359			continue;360		ctx = &path->comps[index];361		if (is_output_disabled(p_id, ctx->param, count))362			continue;363		ret = call_op(ctx, wait_comp_event, cmd);364		if (ret)365			return ret;366	}367	/* Advance to the next sub-frame */368	for (index = 0; index < num_comp; index++) {369		if (CFG_CHECK(MT8183, p_id))370			inner_id = CFG_GET(MT8183, path->config, components[index].type);371		else if (CFG_CHECK(MT8195, p_id))372			inner_id = CFG_GET(MT8195, path->config, components[index].type);373 374		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))375			continue;376		ctx = &path->comps[index];377		ret = call_op(ctx, advance_subfrm, cmd, count);378		if (ret)379			return ret;380	}381	/* Disable mux settings */382	for (index = 0; index < ctrl->num_sets; index++) {383		set = &ctrl->sets[index];384		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,385				    0, 0xFFFFFFFF);386	}387 388	return 0;389}390 391static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,392			   struct mdp_path *path)393{394	const int p_id = mdp->mdp_data->mdp_plat_id;395	struct mdp_comp_ctx *ctx;396	int index, count, ret;397	u32 num_comp = 0;398	u32 num_sub = 0;399	s32 inner_id = MDP_COMP_NONE;400 401	if (CFG_CHECK(MT8183, p_id))402		num_comp = CFG_GET(MT8183, path->config, num_components);403	else if (CFG_CHECK(MT8195, p_id))404		num_comp = CFG_GET(MT8195, path->config, num_components);405 406	if (CFG_CHECK(MT8183, p_id))407		num_sub = CFG_GET(MT8183, path->config, num_subfrms);408	else if (CFG_CHECK(MT8195, p_id))409		num_sub = CFG_GET(MT8195, path->config, num_subfrms);410 411	/* Config path frame */412	/* Reset components */413	for (index = 0; index < num_comp; index++) {414		if (CFG_CHECK(MT8183, p_id))415			inner_id = CFG_GET(MT8183, path->config, components[index].type);416		else if (CFG_CHECK(MT8195, p_id))417			inner_id = CFG_GET(MT8195, path->config, components[index].type);418 419		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))420			continue;421		ctx = &path->comps[index];422		ret = call_op(ctx, init_comp, cmd);423		if (ret)424			return ret;425	}426	/* Config frame mode */427	for (index = 0; index < num_comp; index++) {428		const struct v4l2_rect *compose;429		u32 out = 0;430 431		ctx = &path->comps[index];432		if (CFG_CHECK(MT8183, p_id))433			inner_id = CFG_GET(MT8183, path->config, components[index].type);434		else if (CFG_CHECK(MT8195, p_id))435			inner_id = CFG_GET(MT8195, path->config, components[index].type);436 437		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))438			continue;439 440		if (CFG_CHECK(MT8183, p_id))441			out = CFG_COMP(MT8183, ctx->param, outputs[0]);442		else if (CFG_CHECK(MT8195, p_id))443			out = CFG_COMP(MT8195, ctx->param, outputs[0]);444 445		compose = path->composes[out];446		ret = call_op(ctx, config_frame, cmd, compose);447		if (ret)448			return ret;449	}450 451	/* Config path sub-frames */452	for (count = 0; count < num_sub; count++) {453		ret = mdp_path_config_subfrm(cmd, path, count);454		if (ret)455			return ret;456	}457	/* Post processing information */458	for (index = 0; index < num_comp; index++) {459		if (CFG_CHECK(MT8183, p_id))460			inner_id = CFG_GET(MT8183, path->config, components[index].type);461		else if (CFG_CHECK(MT8195, p_id))462			inner_id = CFG_GET(MT8195, path->config, components[index].type);463 464		if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id))465			continue;466		ctx = &path->comps[index];467		ret = call_op(ctx, post_process, cmd);468		if (ret)469			return ret;470	}471	return 0;472}473 474static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,475			       size_t size)476{477	struct device *dev;478	dma_addr_t dma_addr;479 480	pkt->va_base = kzalloc(size, GFP_KERNEL);481	if (!pkt->va_base)482		return -ENOMEM;483 484	pkt->buf_size = size;485	pkt->cl = (void *)client;486 487	dev = client->chan->mbox->dev;488	dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,489				  DMA_TO_DEVICE);490	if (dma_mapping_error(dev, dma_addr)) {491		dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);492		kfree(pkt->va_base);493		return -ENOMEM;494	}495 496	pkt->pa_base = dma_addr;497 498	return 0;499}500 501static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt)502{503	struct cmdq_client *client = (struct cmdq_client *)pkt->cl;504 505	dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,506			 DMA_TO_DEVICE);507	kfree(pkt->va_base);508	pkt->va_base = NULL;509}510 511static void mdp_auto_release_work(struct work_struct *work)512{513	struct mdp_cmdq_cmd *cmd;514	struct mdp_dev *mdp;515	struct mtk_mutex *mutex;516	enum mdp_pipe_id pipe_id;517 518	cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);519	mdp = cmd->mdp;520 521	pipe_id = __get_pipe(mdp, cmd->comps[0].public_id);522	mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]);523	mtk_mutex_unprepare(mutex);524	mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,525			    cmd->num_comps);526 527	if (refcount_dec_and_test(&mdp->job_count)) {528		if (cmd->mdp_ctx)529			mdp_m2m_job_finish(cmd->mdp_ctx);530 531		if (cmd->user_cmdq_cb) {532			struct cmdq_cb_data user_cb_data;533 534			user_cb_data.sta = cmd->data->sta;535			user_cb_data.pkt = cmd->data->pkt;536			cmd->user_cmdq_cb(user_cb_data);537		}538		wake_up(&mdp->callback_wq);539	}540 541	mdp_cmdq_pkt_destroy(&cmd->pkt);542	kfree(cmd->comps);543	cmd->comps = NULL;544	kfree(cmd);545	cmd = NULL;546}547 548static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)549{550	struct mdp_cmdq_cmd *cmd;551	struct cmdq_cb_data *data;552	struct mdp_dev *mdp;553	struct device *dev;554	enum mdp_pipe_id pipe_id;555 556	if (!mssg) {557		pr_info("%s:no callback data\n", __func__);558		return;559	}560 561	data = (struct cmdq_cb_data *)mssg;562	cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt);563	cmd->data = data;564	mdp = cmd->mdp;565	dev = &mdp->pdev->dev;566 567	INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);568	if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {569		struct mtk_mutex *mutex;570 571		dev_err(dev, "%s:queue_work fail!\n", __func__);572		pipe_id = __get_pipe(mdp, cmd->comps[0].public_id);573		mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]);574		mtk_mutex_unprepare(mutex);575		mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,576				    cmd->num_comps);577 578		if (refcount_dec_and_test(&mdp->job_count))579			wake_up(&mdp->callback_wq);580 581		mdp_cmdq_pkt_destroy(&cmd->pkt);582		kfree(cmd->comps);583		cmd->comps = NULL;584		kfree(cmd);585		cmd = NULL;586	}587}588 589static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp,590					     struct mdp_cmdq_param *param,591					     u8 pp_idx)592{593	struct mdp_path *path = NULL;594	struct mdp_cmdq_cmd *cmd = NULL;595	struct mdp_comp *comps = NULL;596	struct device *dev = &mdp->pdev->dev;597	const int p_id = mdp->mdp_data->mdp_plat_id;598	struct img_config *config;599	struct mtk_mutex *mutex = NULL;600	enum mdp_pipe_id pipe_id;601	int i, ret = -ECANCELED;602	u32 num_comp;603 604	config = __get_config_offset(mdp, param, pp_idx);605	if (IS_ERR(config)) {606		ret = PTR_ERR(config);607		goto err_uninit;608	}609 610	if (CFG_CHECK(MT8183, p_id))611		num_comp = CFG_GET(MT8183, config, num_components);612	else if (CFG_CHECK(MT8195, p_id))613		num_comp = CFG_GET(MT8195, config, num_components);614	else615		goto err_uninit;616 617	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);618	if (!cmd) {619		ret = -ENOMEM;620		goto err_uninit;621	}622 623	ret = mdp_cmdq_pkt_create(mdp->cmdq_clt[pp_idx], &cmd->pkt, SZ_16K);624	if (ret)625		goto err_free_cmd;626 627	if (CFG_CHECK(MT8183, p_id)) {628		num_comp = CFG_GET(MT8183, param->config, num_components);629	} else if (CFG_CHECK(MT8195, p_id)) {630		num_comp = CFG_GET(MT8195, param->config, num_components);631	} else {632		ret = -EINVAL;633		goto err_destroy_pkt;634	}635	comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL);636	if (!comps) {637		ret = -ENOMEM;638		goto err_destroy_pkt;639	}640 641	path = kzalloc(sizeof(*path), GFP_KERNEL);642	if (!path) {643		ret = -ENOMEM;644		goto err_free_comps;645	}646 647	path->mdp_dev = mdp;648	path->config = config;649	path->param = param->param;650	for (i = 0; i < param->param->num_outputs; i++) {651		path->bounds[i].left = 0;652		path->bounds[i].top = 0;653		path->bounds[i].width =654			param->param->outputs[i].buffer.format.width;655		path->bounds[i].height =656			param->param->outputs[i].buffer.format.height;657		path->composes[i] = param->composes[i] ?658			param->composes[i] : &path->bounds[i];659	}660	ret = mdp_path_ctx_init(mdp, path);661	if (ret) {662		dev_err(dev, "mdp_path_ctx_init error %d\n", pp_idx);663		goto err_free_path;664	}665 666	pipe_id = __get_pipe(mdp, path->comps[0].comp->public_id);667	mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]);668	ret = mtk_mutex_prepare(mutex);669	if (ret) {670		dev_err(dev, "Fail to enable mutex %d clk\n", pp_idx);671		goto err_free_path;672	}673 674	ret = mdp_path_config(mdp, cmd, path);675	if (ret) {676		dev_err(dev, "mdp_path_config error %d\n", pp_idx);677		goto err_free_path;678	}679	cmdq_pkt_finalize(&cmd->pkt);680 681	for (i = 0; i < num_comp; i++) {682		s32 inner_id = MDP_COMP_NONE;683 684		if (CFG_CHECK(MT8183, p_id))685			inner_id = CFG_GET(MT8183, path->config, components[i].type);686		else if (CFG_CHECK(MT8195, p_id))687			inner_id = CFG_GET(MT8195, path->config, components[i].type);688 689		if (mdp_cfg_comp_is_dummy(mdp, inner_id))690			continue;691		memcpy(&comps[i], path->comps[i].comp,692		       sizeof(struct mdp_comp));693	}694 695	mdp->cmdq_clt[pp_idx]->client.rx_callback = mdp_handle_cmdq_callback;696	cmd->mdp = mdp;697	cmd->user_cmdq_cb = param->cmdq_cb;698	cmd->user_cb_data = param->cb_data;699	cmd->comps = comps;700	cmd->num_comps = num_comp;701	cmd->mdp_ctx = param->mdp_ctx;702 703	kfree(path);704	return cmd;705 706err_free_path:707	if (mutex)708		mtk_mutex_unprepare(mutex);709	kfree(path);710err_free_comps:711	kfree(comps);712err_destroy_pkt:713	mdp_cmdq_pkt_destroy(&cmd->pkt);714err_free_cmd:715	kfree(cmd);716err_uninit:717	return ERR_PTR(ret);718}719 720int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)721{722	struct mdp_cmdq_cmd *cmd[MDP_PP_MAX] = {NULL};723	struct device *dev = &mdp->pdev->dev;724	int i, ret;725	u8 pp_used = __get_pp_num(param->param->type);726 727	refcount_set(&mdp->job_count, pp_used);728	if (atomic_read(&mdp->suspended)) {729		refcount_set(&mdp->job_count, 0);730		return -ECANCELED;731	}732 733	for (i = 0; i < pp_used; i++) {734		cmd[i] = mdp_cmdq_prepare(mdp, param, i);735		if (IS_ERR_OR_NULL(cmd[i])) {736			ret = PTR_ERR(cmd[i]);737			goto err_cancel_job;738		}739	}740 741	for (i = 0; i < pp_used; i++) {742		ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd[i]->comps, cmd[i]->num_comps);743		if (ret)744			goto err_clock_off;745	}746 747	for (i = 0; i < pp_used; i++) {748		dma_sync_single_for_device(mdp->cmdq_clt[i]->chan->mbox->dev,749					   cmd[i]->pkt.pa_base, cmd[i]->pkt.cmd_buf_size,750					   DMA_TO_DEVICE);751 752		ret = mbox_send_message(mdp->cmdq_clt[i]->chan, &cmd[i]->pkt);753		if (ret < 0) {754			dev_err(dev, "mbox send message fail %d!\n", ret);755			i = pp_used;756			goto err_clock_off;757		}758		mbox_client_txdone(mdp->cmdq_clt[i]->chan, 0);759	}760	return 0;761 762err_clock_off:763	while (--i >= 0)764		mdp_comp_clocks_off(&mdp->pdev->dev, cmd[i]->comps,765				    cmd[i]->num_comps);766err_cancel_job:767	refcount_set(&mdp->job_count, 0);768 769	return ret;770}771EXPORT_SYMBOL_GPL(mdp_cmdq_send);772