162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2022 MediaTek Inc.
462306a36Sopenharmony_ci * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/mailbox_controller.h>
862306a36Sopenharmony_ci#include <linux/platform_device.h>
962306a36Sopenharmony_ci#include "mtk-mdp3-cmdq.h"
1062306a36Sopenharmony_ci#include "mtk-mdp3-comp.h"
1162306a36Sopenharmony_ci#include "mtk-mdp3-core.h"
1262306a36Sopenharmony_ci#include "mtk-mdp3-m2m.h"
1362306a36Sopenharmony_ci#include "mtk-img-ipi.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define MDP_PATH_MAX_COMPS	IMG_MAX_COMPONENTS
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct mdp_path {
1862306a36Sopenharmony_ci	struct mdp_dev		*mdp_dev;
1962306a36Sopenharmony_ci	struct mdp_comp_ctx	comps[MDP_PATH_MAX_COMPS];
2062306a36Sopenharmony_ci	u32			num_comps;
2162306a36Sopenharmony_ci	const struct img_config	*config;
2262306a36Sopenharmony_ci	const struct img_ipi_frameparam *param;
2362306a36Sopenharmony_ci	const struct v4l2_rect	*composes[IMG_MAX_HW_OUTPUTS];
2462306a36Sopenharmony_ci	struct v4l2_rect	bounds[IMG_MAX_HW_OUTPUTS];
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define has_op(ctx, op) \
2862306a36Sopenharmony_ci	((ctx)->comp->ops && (ctx)->comp->ops->op)
2962306a36Sopenharmony_ci #define call_op(ctx, op, ...) \
3062306a36Sopenharmony_ci	(has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	u32 num = 0;
3562306a36Sopenharmony_ci	bool dis_output = false;
3662306a36Sopenharmony_ci	bool dis_tile = false;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id)) {
3962306a36Sopenharmony_ci		num = CFG_COMP(MT8183, param, num_subfrms);
4062306a36Sopenharmony_ci		dis_output = CFG_COMP(MT8183, param, frame.output_disable);
4162306a36Sopenharmony_ci		dis_tile = CFG_COMP(MT8183, param, frame.output_disable);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return (count < num) ? (dis_output || dis_tile) : true;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int mdp_path_subfrm_require(const struct mdp_path *path,
4862306a36Sopenharmony_ci				   struct mdp_cmdq_cmd *cmd,
4962306a36Sopenharmony_ci				   s32 *mutex_id, u32 count)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
5262306a36Sopenharmony_ci	const struct mdp_comp_ctx *ctx;
5362306a36Sopenharmony_ci	const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;
5462306a36Sopenharmony_ci	struct device *dev = &path->mdp_dev->pdev->dev;
5562306a36Sopenharmony_ci	struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
5662306a36Sopenharmony_ci	int id, index;
5762306a36Sopenharmony_ci	u32 num_comp = 0;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
6062306a36Sopenharmony_ci		num_comp = CFG_GET(MT8183, path->config, num_components);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* Decide which mutex to use based on the current pipeline */
6362306a36Sopenharmony_ci	switch (path->comps[0].comp->public_id) {
6462306a36Sopenharmony_ci	case MDP_COMP_RDMA0:
6562306a36Sopenharmony_ci		index = MDP_PIPE_RDMA0;
6662306a36Sopenharmony_ci		break;
6762306a36Sopenharmony_ci	case MDP_COMP_ISP_IMGI:
6862306a36Sopenharmony_ci		index = MDP_PIPE_IMGI;
6962306a36Sopenharmony_ci		break;
7062306a36Sopenharmony_ci	case MDP_COMP_WPEI:
7162306a36Sopenharmony_ci		index = MDP_PIPE_WPEI;
7262306a36Sopenharmony_ci		break;
7362306a36Sopenharmony_ci	case MDP_COMP_WPEI2:
7462306a36Sopenharmony_ci		index = MDP_PIPE_WPEI2;
7562306a36Sopenharmony_ci		break;
7662306a36Sopenharmony_ci	default:
7762306a36Sopenharmony_ci		dev_err(dev, "Unknown pipeline and no mutex is assigned");
7862306a36Sopenharmony_ci		return -EINVAL;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci	*mutex_id = data->pipe_info[index].mutex_id;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* Set mutex mod */
8362306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
8462306a36Sopenharmony_ci		ctx = &path->comps[index];
8562306a36Sopenharmony_ci		if (is_output_disabled(p_id, ctx->param, count))
8662306a36Sopenharmony_ci			continue;
8762306a36Sopenharmony_ci		id = ctx->comp->public_id;
8862306a36Sopenharmony_ci		mtk_mutex_write_mod(mutex[*mutex_id],
8962306a36Sopenharmony_ci				    data->mdp_mutex_table_idx[id], false);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	mtk_mutex_write_sof(mutex[*mutex_id],
9362306a36Sopenharmony_ci			    MUTEX_SOF_IDX_SINGLE_MODE);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return 0;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int mdp_path_subfrm_run(const struct mdp_path *path,
9962306a36Sopenharmony_ci			       struct mdp_cmdq_cmd *cmd,
10062306a36Sopenharmony_ci			       s32 *mutex_id, u32 count)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
10362306a36Sopenharmony_ci	const struct mdp_comp_ctx *ctx;
10462306a36Sopenharmony_ci	struct device *dev = &path->mdp_dev->pdev->dev;
10562306a36Sopenharmony_ci	struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
10662306a36Sopenharmony_ci	int index;
10762306a36Sopenharmony_ci	u32 num_comp = 0;
10862306a36Sopenharmony_ci	s32 event;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (-1 == *mutex_id) {
11162306a36Sopenharmony_ci		dev_err(dev, "Incorrect mutex id");
11262306a36Sopenharmony_ci		return -EINVAL;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
11662306a36Sopenharmony_ci		num_comp = CFG_GET(MT8183, path->config, num_components);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* Wait WROT SRAM shared to DISP RDMA */
11962306a36Sopenharmony_ci	/* Clear SOF event for each engine */
12062306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
12162306a36Sopenharmony_ci		ctx = &path->comps[index];
12262306a36Sopenharmony_ci		if (is_output_disabled(p_id, ctx->param, count))
12362306a36Sopenharmony_ci			continue;
12462306a36Sopenharmony_ci		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
12562306a36Sopenharmony_ci		if (event != MDP_GCE_NO_EVENT)
12662306a36Sopenharmony_ci			MM_REG_CLEAR(cmd, event);
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Enable the mutex */
13062306a36Sopenharmony_ci	mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Wait SOF events and clear mutex modules (optional) */
13362306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
13462306a36Sopenharmony_ci		ctx = &path->comps[index];
13562306a36Sopenharmony_ci		if (is_output_disabled(p_id, ctx->param, count))
13662306a36Sopenharmony_ci			continue;
13762306a36Sopenharmony_ci		event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
13862306a36Sopenharmony_ci		if (event != MDP_GCE_NO_EVENT)
13962306a36Sopenharmony_ci			MM_REG_WAIT(cmd, event);
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return 0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	const int p_id = mdp->mdp_data->mdp_plat_id;
14862306a36Sopenharmony_ci	void *param = NULL;
14962306a36Sopenharmony_ci	int index, ret;
15062306a36Sopenharmony_ci	u32 num_comp = 0;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
15362306a36Sopenharmony_ci		num_comp = CFG_GET(MT8183, path->config, num_components);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (num_comp < 1)
15662306a36Sopenharmony_ci		return -EINVAL;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
15962306a36Sopenharmony_ci		if (CFG_CHECK(MT8183, p_id))
16062306a36Sopenharmony_ci			param = (void *)CFG_ADDR(MT8183, path->config, components[index]);
16162306a36Sopenharmony_ci		ret = mdp_comp_ctx_config(mdp, &path->comps[index],
16262306a36Sopenharmony_ci					  param, path->param);
16362306a36Sopenharmony_ci		if (ret)
16462306a36Sopenharmony_ci			return ret;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
17162306a36Sopenharmony_ci				  struct mdp_path *path, u32 count)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	const int p_id = path->mdp_dev->mdp_data->mdp_plat_id;
17462306a36Sopenharmony_ci	const struct img_mmsys_ctrl *ctrl = NULL;
17562306a36Sopenharmony_ci	const struct img_mux *set;
17662306a36Sopenharmony_ci	struct mdp_comp_ctx *ctx;
17762306a36Sopenharmony_ci	s32 mutex_id;
17862306a36Sopenharmony_ci	int index, ret;
17962306a36Sopenharmony_ci	u32 num_comp = 0;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
18262306a36Sopenharmony_ci		num_comp = CFG_GET(MT8183, path->config, num_components);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
18562306a36Sopenharmony_ci		ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	/* Acquire components */
18862306a36Sopenharmony_ci	ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count);
18962306a36Sopenharmony_ci	if (ret)
19062306a36Sopenharmony_ci		return ret;
19162306a36Sopenharmony_ci	/* Enable mux settings */
19262306a36Sopenharmony_ci	for (index = 0; index < ctrl->num_sets; index++) {
19362306a36Sopenharmony_ci		set = &ctrl->sets[index];
19462306a36Sopenharmony_ci		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
19562306a36Sopenharmony_ci				    set->value, 0xFFFFFFFF);
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci	/* Config sub-frame information */
19862306a36Sopenharmony_ci	for (index = (num_comp - 1); index >= 0; index--) {
19962306a36Sopenharmony_ci		ctx = &path->comps[index];
20062306a36Sopenharmony_ci		if (is_output_disabled(p_id, ctx->param, count))
20162306a36Sopenharmony_ci			continue;
20262306a36Sopenharmony_ci		ret = call_op(ctx, config_subfrm, cmd, count);
20362306a36Sopenharmony_ci		if (ret)
20462306a36Sopenharmony_ci			return ret;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci	/* Run components */
20762306a36Sopenharmony_ci	ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count);
20862306a36Sopenharmony_ci	if (ret)
20962306a36Sopenharmony_ci		return ret;
21062306a36Sopenharmony_ci	/* Wait components done */
21162306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
21262306a36Sopenharmony_ci		ctx = &path->comps[index];
21362306a36Sopenharmony_ci		if (is_output_disabled(p_id, ctx->param, count))
21462306a36Sopenharmony_ci			continue;
21562306a36Sopenharmony_ci		ret = call_op(ctx, wait_comp_event, cmd);
21662306a36Sopenharmony_ci		if (ret)
21762306a36Sopenharmony_ci			return ret;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci	/* Advance to the next sub-frame */
22062306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
22162306a36Sopenharmony_ci		ctx = &path->comps[index];
22262306a36Sopenharmony_ci		ret = call_op(ctx, advance_subfrm, cmd, count);
22362306a36Sopenharmony_ci		if (ret)
22462306a36Sopenharmony_ci			return ret;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci	/* Disable mux settings */
22762306a36Sopenharmony_ci	for (index = 0; index < ctrl->num_sets; index++) {
22862306a36Sopenharmony_ci		set = &ctrl->sets[index];
22962306a36Sopenharmony_ci		cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
23062306a36Sopenharmony_ci				    0, 0xFFFFFFFF);
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return 0;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
23762306a36Sopenharmony_ci			   struct mdp_path *path)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	const int p_id = mdp->mdp_data->mdp_plat_id;
24062306a36Sopenharmony_ci	struct mdp_comp_ctx *ctx;
24162306a36Sopenharmony_ci	int index, count, ret;
24262306a36Sopenharmony_ci	u32 num_comp = 0;
24362306a36Sopenharmony_ci	u32 num_sub = 0;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
24662306a36Sopenharmony_ci		num_comp = CFG_GET(MT8183, path->config, num_components);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id))
24962306a36Sopenharmony_ci		num_sub = CFG_GET(MT8183, path->config, num_subfrms);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Config path frame */
25262306a36Sopenharmony_ci	/* Reset components */
25362306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
25462306a36Sopenharmony_ci		ctx = &path->comps[index];
25562306a36Sopenharmony_ci		ret = call_op(ctx, init_comp, cmd);
25662306a36Sopenharmony_ci		if (ret)
25762306a36Sopenharmony_ci			return ret;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci	/* Config frame mode */
26062306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
26162306a36Sopenharmony_ci		const struct v4l2_rect *compose;
26262306a36Sopenharmony_ci		u32 out = 0;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		ctx = &path->comps[index];
26562306a36Sopenharmony_ci		if (CFG_CHECK(MT8183, p_id))
26662306a36Sopenharmony_ci			out = CFG_COMP(MT8183, ctx->param, outputs[0]);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		compose = path->composes[out];
26962306a36Sopenharmony_ci		ret = call_op(ctx, config_frame, cmd, compose);
27062306a36Sopenharmony_ci		if (ret)
27162306a36Sopenharmony_ci			return ret;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* Config path sub-frames */
27562306a36Sopenharmony_ci	for (count = 0; count < num_sub; count++) {
27662306a36Sopenharmony_ci		ret = mdp_path_config_subfrm(cmd, path, count);
27762306a36Sopenharmony_ci		if (ret)
27862306a36Sopenharmony_ci			return ret;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	/* Post processing information */
28162306a36Sopenharmony_ci	for (index = 0; index < num_comp; index++) {
28262306a36Sopenharmony_ci		ctx = &path->comps[index];
28362306a36Sopenharmony_ci		ret = call_op(ctx, post_process, cmd);
28462306a36Sopenharmony_ci		if (ret)
28562306a36Sopenharmony_ci			return ret;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
29162306a36Sopenharmony_ci			       size_t size)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct device *dev;
29462306a36Sopenharmony_ci	dma_addr_t dma_addr;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	pkt->va_base = kzalloc(size, GFP_KERNEL);
29762306a36Sopenharmony_ci	if (!pkt->va_base)
29862306a36Sopenharmony_ci		return -ENOMEM;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	pkt->buf_size = size;
30162306a36Sopenharmony_ci	pkt->cl = (void *)client;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	dev = client->chan->mbox->dev;
30462306a36Sopenharmony_ci	dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
30562306a36Sopenharmony_ci				  DMA_TO_DEVICE);
30662306a36Sopenharmony_ci	if (dma_mapping_error(dev, dma_addr)) {
30762306a36Sopenharmony_ci		dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
30862306a36Sopenharmony_ci		kfree(pkt->va_base);
30962306a36Sopenharmony_ci		return -ENOMEM;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	pkt->pa_base = dma_addr;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
32262306a36Sopenharmony_ci			 DMA_TO_DEVICE);
32362306a36Sopenharmony_ci	kfree(pkt->va_base);
32462306a36Sopenharmony_ci	pkt->va_base = NULL;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void mdp_auto_release_work(struct work_struct *work)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct mdp_cmdq_cmd *cmd;
33062306a36Sopenharmony_ci	struct mdp_dev *mdp;
33162306a36Sopenharmony_ci	int id;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);
33462306a36Sopenharmony_ci	mdp = cmd->mdp;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
33762306a36Sopenharmony_ci	mtk_mutex_unprepare(mdp->mdp_mutex[id]);
33862306a36Sopenharmony_ci	mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
33962306a36Sopenharmony_ci			    cmd->num_comps);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	atomic_dec(&mdp->job_count);
34262306a36Sopenharmony_ci	wake_up(&mdp->callback_wq);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	mdp_cmdq_pkt_destroy(&cmd->pkt);
34562306a36Sopenharmony_ci	kfree(cmd->comps);
34662306a36Sopenharmony_ci	cmd->comps = NULL;
34762306a36Sopenharmony_ci	kfree(cmd);
34862306a36Sopenharmony_ci	cmd = NULL;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct mdp_cmdq_cmd *cmd;
35462306a36Sopenharmony_ci	struct cmdq_cb_data *data;
35562306a36Sopenharmony_ci	struct mdp_dev *mdp;
35662306a36Sopenharmony_ci	struct device *dev;
35762306a36Sopenharmony_ci	int id;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (!mssg) {
36062306a36Sopenharmony_ci		pr_info("%s:no callback data\n", __func__);
36162306a36Sopenharmony_ci		return;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	data = (struct cmdq_cb_data *)mssg;
36562306a36Sopenharmony_ci	cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt);
36662306a36Sopenharmony_ci	mdp = cmd->mdp;
36762306a36Sopenharmony_ci	dev = &mdp->pdev->dev;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (cmd->mdp_ctx)
37062306a36Sopenharmony_ci		mdp_m2m_job_finish(cmd->mdp_ctx);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (cmd->user_cmdq_cb) {
37362306a36Sopenharmony_ci		struct cmdq_cb_data user_cb_data;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		user_cb_data.sta = data->sta;
37662306a36Sopenharmony_ci		user_cb_data.pkt = data->pkt;
37762306a36Sopenharmony_ci		cmd->user_cmdq_cb(user_cb_data);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);
38162306a36Sopenharmony_ci	if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {
38262306a36Sopenharmony_ci		dev_err(dev, "%s:queue_work fail!\n", __func__);
38362306a36Sopenharmony_ci		id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
38462306a36Sopenharmony_ci		mtk_mutex_unprepare(mdp->mdp_mutex[id]);
38562306a36Sopenharmony_ci		mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
38662306a36Sopenharmony_ci				    cmd->num_comps);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		atomic_dec(&mdp->job_count);
38962306a36Sopenharmony_ci		wake_up(&mdp->callback_wq);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		mdp_cmdq_pkt_destroy(&cmd->pkt);
39262306a36Sopenharmony_ci		kfree(cmd->comps);
39362306a36Sopenharmony_ci		cmd->comps = NULL;
39462306a36Sopenharmony_ci		kfree(cmd);
39562306a36Sopenharmony_ci		cmd = NULL;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ciint mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct mdp_path *path = NULL;
40262306a36Sopenharmony_ci	struct mdp_cmdq_cmd *cmd = NULL;
40362306a36Sopenharmony_ci	struct mdp_comp *comps = NULL;
40462306a36Sopenharmony_ci	struct device *dev = &mdp->pdev->dev;
40562306a36Sopenharmony_ci	const int p_id = mdp->mdp_data->mdp_plat_id;
40662306a36Sopenharmony_ci	int i, ret;
40762306a36Sopenharmony_ci	u32 num_comp = 0;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	atomic_inc(&mdp->job_count);
41062306a36Sopenharmony_ci	if (atomic_read(&mdp->suspended)) {
41162306a36Sopenharmony_ci		atomic_dec(&mdp->job_count);
41262306a36Sopenharmony_ci		return -ECANCELED;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
41662306a36Sopenharmony_ci	if (!cmd) {
41762306a36Sopenharmony_ci		ret = -ENOMEM;
41862306a36Sopenharmony_ci		goto err_cancel_job;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K);
42262306a36Sopenharmony_ci	if (ret)
42362306a36Sopenharmony_ci		goto err_free_cmd;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (CFG_CHECK(MT8183, p_id)) {
42662306a36Sopenharmony_ci		num_comp = CFG_GET(MT8183, param->config, num_components);
42762306a36Sopenharmony_ci	} else {
42862306a36Sopenharmony_ci		ret = -EINVAL;
42962306a36Sopenharmony_ci		goto err_destroy_pkt;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci	comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL);
43262306a36Sopenharmony_ci	if (!comps) {
43362306a36Sopenharmony_ci		ret = -ENOMEM;
43462306a36Sopenharmony_ci		goto err_destroy_pkt;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	path = kzalloc(sizeof(*path), GFP_KERNEL);
43862306a36Sopenharmony_ci	if (!path) {
43962306a36Sopenharmony_ci		ret = -ENOMEM;
44062306a36Sopenharmony_ci		goto err_free_comps;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
44462306a36Sopenharmony_ci	ret = mtk_mutex_prepare(mdp->mdp_mutex[i]);
44562306a36Sopenharmony_ci	if (ret) {
44662306a36Sopenharmony_ci		dev_err(dev, "Fail to enable mutex clk\n");
44762306a36Sopenharmony_ci		goto err_free_path;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	path->mdp_dev = mdp;
45162306a36Sopenharmony_ci	path->config = param->config;
45262306a36Sopenharmony_ci	path->param = param->param;
45362306a36Sopenharmony_ci	for (i = 0; i < param->param->num_outputs; i++) {
45462306a36Sopenharmony_ci		path->bounds[i].left = 0;
45562306a36Sopenharmony_ci		path->bounds[i].top = 0;
45662306a36Sopenharmony_ci		path->bounds[i].width =
45762306a36Sopenharmony_ci			param->param->outputs[i].buffer.format.width;
45862306a36Sopenharmony_ci		path->bounds[i].height =
45962306a36Sopenharmony_ci			param->param->outputs[i].buffer.format.height;
46062306a36Sopenharmony_ci		path->composes[i] = param->composes[i] ?
46162306a36Sopenharmony_ci			param->composes[i] : &path->bounds[i];
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	ret = mdp_path_ctx_init(mdp, path);
46462306a36Sopenharmony_ci	if (ret) {
46562306a36Sopenharmony_ci		dev_err(dev, "mdp_path_ctx_init error\n");
46662306a36Sopenharmony_ci		goto err_free_path;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	ret = mdp_path_config(mdp, cmd, path);
47062306a36Sopenharmony_ci	if (ret) {
47162306a36Sopenharmony_ci		dev_err(dev, "mdp_path_config error\n");
47262306a36Sopenharmony_ci		goto err_free_path;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci	cmdq_pkt_finalize(&cmd->pkt);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	for (i = 0; i < num_comp; i++)
47762306a36Sopenharmony_ci		memcpy(&comps[i], path->comps[i].comp,
47862306a36Sopenharmony_ci		       sizeof(struct mdp_comp));
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback;
48162306a36Sopenharmony_ci	cmd->mdp = mdp;
48262306a36Sopenharmony_ci	cmd->user_cmdq_cb = param->cmdq_cb;
48362306a36Sopenharmony_ci	cmd->user_cb_data = param->cb_data;
48462306a36Sopenharmony_ci	cmd->comps = comps;
48562306a36Sopenharmony_ci	cmd->num_comps = num_comp;
48662306a36Sopenharmony_ci	cmd->mdp_ctx = param->mdp_ctx;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
48962306a36Sopenharmony_ci	if (ret)
49062306a36Sopenharmony_ci		goto err_free_path;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
49362306a36Sopenharmony_ci				   cmd->pkt.pa_base, cmd->pkt.cmd_buf_size,
49462306a36Sopenharmony_ci				   DMA_TO_DEVICE);
49562306a36Sopenharmony_ci	ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt);
49662306a36Sopenharmony_ci	if (ret < 0) {
49762306a36Sopenharmony_ci		dev_err(dev, "mbox send message fail %d!\n", ret);
49862306a36Sopenharmony_ci		goto err_clock_off;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci	mbox_client_txdone(mdp->cmdq_clt->chan, 0);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	kfree(path);
50362306a36Sopenharmony_ci	return 0;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cierr_clock_off:
50662306a36Sopenharmony_ci	mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
50762306a36Sopenharmony_ci			    cmd->num_comps);
50862306a36Sopenharmony_cierr_free_path:
50962306a36Sopenharmony_ci	i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id;
51062306a36Sopenharmony_ci	mtk_mutex_unprepare(mdp->mdp_mutex[i]);
51162306a36Sopenharmony_ci	kfree(path);
51262306a36Sopenharmony_cierr_free_comps:
51362306a36Sopenharmony_ci	kfree(comps);
51462306a36Sopenharmony_cierr_destroy_pkt:
51562306a36Sopenharmony_ci	mdp_cmdq_pkt_destroy(&cmd->pkt);
51662306a36Sopenharmony_cierr_free_cmd:
51762306a36Sopenharmony_ci	kfree(cmd);
51862306a36Sopenharmony_cierr_cancel_job:
51962306a36Sopenharmony_ci	atomic_dec(&mdp->job_count);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return ret;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mdp_cmdq_send);
524