xref: /linux/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c (revision a23e1966932464e1c5226cb9ac4ce1d5fc10ba22)
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/remoteproc.h>
861890ccaSMoudy Ho #include <linux/remoteproc/mtk_scp.h>
961890ccaSMoudy Ho #include "mtk-mdp3-vpu.h"
1061890ccaSMoudy Ho #include "mtk-mdp3-core.h"
1161890ccaSMoudy Ho 
1261890ccaSMoudy Ho #define MDP_VPU_MESSAGE_TIMEOUT 500U
1361890ccaSMoudy Ho 
vpu_to_mdp(struct mdp_vpu_dev * vpu)1461890ccaSMoudy Ho static inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu)
1561890ccaSMoudy Ho {
1661890ccaSMoudy Ho 	return container_of(vpu, struct mdp_dev, vpu);
1761890ccaSMoudy Ho }
1861890ccaSMoudy Ho 
mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev * vpu)1961890ccaSMoudy Ho static int mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev *vpu)
2061890ccaSMoudy Ho {
21b4e52199SMoudy Ho 	struct device *dev;
2261890ccaSMoudy Ho 
23b4e52199SMoudy Ho 	if (IS_ERR_OR_NULL(vpu))
24b4e52199SMoudy Ho 		goto err_return;
25b4e52199SMoudy Ho 
26b4e52199SMoudy Ho 	dev = scp_get_device(vpu->scp);
27b4e52199SMoudy Ho 
28b4e52199SMoudy Ho 	if (!vpu->param) {
29b4e52199SMoudy Ho 		vpu->param = dma_alloc_wc(dev, vpu->param_size,
30b4e52199SMoudy Ho 					  &vpu->param_addr, GFP_KERNEL);
31b4e52199SMoudy Ho 		if (!vpu->param)
32b4e52199SMoudy Ho 			goto err_return;
33b4e52199SMoudy Ho 	}
34b4e52199SMoudy Ho 
35b4e52199SMoudy Ho 	if (!vpu->work) {
36b4e52199SMoudy Ho 		vpu->work = dma_alloc_wc(dev, vpu->work_size,
3761890ccaSMoudy Ho 					 &vpu->work_addr, GFP_KERNEL);
3861890ccaSMoudy Ho 		if (!vpu->work)
39b4e52199SMoudy Ho 			goto err_free_param;
40b4e52199SMoudy Ho 	}
41b4e52199SMoudy Ho 
42b4e52199SMoudy Ho 	if (!vpu->config) {
43b4e52199SMoudy Ho 		vpu->config = dma_alloc_wc(dev, vpu->config_size,
44b4e52199SMoudy Ho 					   &vpu->config_addr, GFP_KERNEL);
45b4e52199SMoudy Ho 		if (!vpu->config)
46b4e52199SMoudy Ho 			goto err_free_work;
47b4e52199SMoudy Ho 	}
48b4e52199SMoudy Ho 
4961890ccaSMoudy Ho 	return 0;
50b4e52199SMoudy Ho 
51b4e52199SMoudy Ho err_free_work:
52b4e52199SMoudy Ho 	dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr);
53b4e52199SMoudy Ho 	vpu->work = NULL;
54b4e52199SMoudy Ho err_free_param:
55b4e52199SMoudy Ho 	dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr);
56b4e52199SMoudy Ho 	vpu->param = NULL;
57b4e52199SMoudy Ho err_return:
58b4e52199SMoudy Ho 	return -ENOMEM;
5961890ccaSMoudy Ho }
6061890ccaSMoudy Ho 
mdp_vpu_shared_mem_free(struct mdp_vpu_dev * vpu)6161890ccaSMoudy Ho void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu)
6261890ccaSMoudy Ho {
63b4e52199SMoudy Ho 	struct device *dev;
64b4e52199SMoudy Ho 
65b4e52199SMoudy Ho 	if (IS_ERR_OR_NULL(vpu))
66b4e52199SMoudy Ho 		return;
67b4e52199SMoudy Ho 
68b4e52199SMoudy Ho 	dev = scp_get_device(vpu->scp);
69b4e52199SMoudy Ho 
70b4e52199SMoudy Ho 	if (vpu->param && vpu->param_addr)
71b4e52199SMoudy Ho 		dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr);
72b4e52199SMoudy Ho 
7361890ccaSMoudy Ho 	if (vpu->work && vpu->work_addr)
74b4e52199SMoudy Ho 		dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr);
75b4e52199SMoudy Ho 
76b4e52199SMoudy Ho 	if (vpu->config && vpu->config_addr)
77b4e52199SMoudy Ho 		dma_free_wc(dev, vpu->config_size, vpu->config, vpu->config_addr);
7861890ccaSMoudy Ho }
7961890ccaSMoudy Ho 
mdp_vpu_ipi_handle_init_ack(void * data,unsigned int len,void * priv)8061890ccaSMoudy Ho static void mdp_vpu_ipi_handle_init_ack(void *data, unsigned int len,
8161890ccaSMoudy Ho 					void *priv)
8261890ccaSMoudy Ho {
8361890ccaSMoudy Ho 	struct mdp_ipi_init_msg *msg = (struct mdp_ipi_init_msg *)data;
8461890ccaSMoudy Ho 	struct mdp_vpu_dev *vpu =
8561890ccaSMoudy Ho 		(struct mdp_vpu_dev *)(unsigned long)msg->drv_data;
8661890ccaSMoudy Ho 
8761890ccaSMoudy Ho 	if (!vpu->work_size)
8861890ccaSMoudy Ho 		vpu->work_size = msg->work_size;
8961890ccaSMoudy Ho 
9061890ccaSMoudy Ho 	vpu->status = msg->status;
9161890ccaSMoudy Ho 	complete(&vpu->ipi_acked);
9261890ccaSMoudy Ho }
9361890ccaSMoudy Ho 
mdp_vpu_ipi_handle_deinit_ack(void * data,unsigned int len,void * priv)9461890ccaSMoudy Ho static void mdp_vpu_ipi_handle_deinit_ack(void *data, unsigned int len,
9561890ccaSMoudy Ho 					  void *priv)
9661890ccaSMoudy Ho {
9761890ccaSMoudy Ho 	struct mdp_ipi_deinit_msg *msg = (struct mdp_ipi_deinit_msg *)data;
9861890ccaSMoudy Ho 	struct mdp_vpu_dev *vpu =
9961890ccaSMoudy Ho 		(struct mdp_vpu_dev *)(unsigned long)msg->drv_data;
10061890ccaSMoudy Ho 
10161890ccaSMoudy Ho 	vpu->status = msg->status;
10261890ccaSMoudy Ho 	complete(&vpu->ipi_acked);
10361890ccaSMoudy Ho }
10461890ccaSMoudy Ho 
mdp_vpu_ipi_handle_frame_ack(void * data,unsigned int len,void * priv)10561890ccaSMoudy Ho static void mdp_vpu_ipi_handle_frame_ack(void *data, unsigned int len,
10661890ccaSMoudy Ho 					 void *priv)
10761890ccaSMoudy Ho {
10861890ccaSMoudy Ho 	struct img_sw_addr *addr = (struct img_sw_addr *)data;
10961890ccaSMoudy Ho 	struct img_ipi_frameparam *param =
11061890ccaSMoudy Ho 		(struct img_ipi_frameparam *)(unsigned long)addr->va;
111b4e52199SMoudy Ho 	struct mdp_vpu_dev *vpu =
112b4e52199SMoudy Ho 		(struct mdp_vpu_dev *)(unsigned long)param->drv_data;
11361890ccaSMoudy Ho 
11461890ccaSMoudy Ho 	if (param->state) {
115b4e52199SMoudy Ho 		struct mdp_dev *mdp = vpu_to_mdp(vpu);
11661890ccaSMoudy Ho 
11761890ccaSMoudy Ho 		dev_err(&mdp->pdev->dev, "VPU MDP failure:%d\n", param->state);
11861890ccaSMoudy Ho 	}
119b4e52199SMoudy Ho 	vpu->status = param->state;
120b4e52199SMoudy Ho 	complete(&vpu->ipi_acked);
12161890ccaSMoudy Ho }
12261890ccaSMoudy Ho 
mdp_vpu_register(struct mdp_dev * mdp)12361890ccaSMoudy Ho int mdp_vpu_register(struct mdp_dev *mdp)
12461890ccaSMoudy Ho {
12561890ccaSMoudy Ho 	int err;
12661890ccaSMoudy Ho 	struct mtk_scp *scp = mdp->scp;
12761890ccaSMoudy Ho 	struct device *dev = &mdp->pdev->dev;
12861890ccaSMoudy Ho 
12961890ccaSMoudy Ho 	err = scp_ipi_register(scp, SCP_IPI_MDP_INIT,
13061890ccaSMoudy Ho 			       mdp_vpu_ipi_handle_init_ack, NULL);
13161890ccaSMoudy Ho 	if (err) {
13261890ccaSMoudy Ho 		dev_err(dev, "scp_ipi_register failed %d\n", err);
13361890ccaSMoudy Ho 		goto err_ipi_init;
13461890ccaSMoudy Ho 	}
13561890ccaSMoudy Ho 	err = scp_ipi_register(scp, SCP_IPI_MDP_DEINIT,
13661890ccaSMoudy Ho 			       mdp_vpu_ipi_handle_deinit_ack, NULL);
13761890ccaSMoudy Ho 	if (err) {
13861890ccaSMoudy Ho 		dev_err(dev, "scp_ipi_register failed %d\n", err);
13961890ccaSMoudy Ho 		goto err_ipi_deinit;
14061890ccaSMoudy Ho 	}
14161890ccaSMoudy Ho 	err = scp_ipi_register(scp, SCP_IPI_MDP_FRAME,
14261890ccaSMoudy Ho 			       mdp_vpu_ipi_handle_frame_ack, NULL);
14361890ccaSMoudy Ho 	if (err) {
14461890ccaSMoudy Ho 		dev_err(dev, "scp_ipi_register failed %d\n", err);
14561890ccaSMoudy Ho 		goto err_ipi_frame;
14661890ccaSMoudy Ho 	}
14761890ccaSMoudy Ho 	return 0;
14861890ccaSMoudy Ho 
14961890ccaSMoudy Ho err_ipi_frame:
15061890ccaSMoudy Ho 	scp_ipi_unregister(scp, SCP_IPI_MDP_DEINIT);
15161890ccaSMoudy Ho err_ipi_deinit:
15261890ccaSMoudy Ho 	scp_ipi_unregister(scp, SCP_IPI_MDP_INIT);
15361890ccaSMoudy Ho err_ipi_init:
15461890ccaSMoudy Ho 
15561890ccaSMoudy Ho 	return err;
15661890ccaSMoudy Ho }
15761890ccaSMoudy Ho 
mdp_vpu_unregister(struct mdp_dev * mdp)15861890ccaSMoudy Ho void mdp_vpu_unregister(struct mdp_dev *mdp)
15961890ccaSMoudy Ho {
16061890ccaSMoudy Ho 	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_INIT);
16161890ccaSMoudy Ho 	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_DEINIT);
16261890ccaSMoudy Ho 	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_FRAME);
16361890ccaSMoudy Ho }
16461890ccaSMoudy Ho 
mdp_vpu_sendmsg(struct mdp_vpu_dev * vpu,enum scp_ipi_id id,void * buf,unsigned int len)16561890ccaSMoudy Ho static int mdp_vpu_sendmsg(struct mdp_vpu_dev *vpu, enum scp_ipi_id id,
16661890ccaSMoudy Ho 			   void *buf, unsigned int len)
16761890ccaSMoudy Ho {
16861890ccaSMoudy Ho 	struct mdp_dev *mdp = vpu_to_mdp(vpu);
16961890ccaSMoudy Ho 	unsigned int t = MDP_VPU_MESSAGE_TIMEOUT;
17061890ccaSMoudy Ho 	int ret;
17161890ccaSMoudy Ho 
17261890ccaSMoudy Ho 	if (!vpu->scp) {
17361890ccaSMoudy Ho 		dev_dbg(&mdp->pdev->dev, "vpu scp is NULL");
17461890ccaSMoudy Ho 		return -EINVAL;
17561890ccaSMoudy Ho 	}
17661890ccaSMoudy Ho 	ret = scp_ipi_send(vpu->scp, id, buf, len, 2000);
17761890ccaSMoudy Ho 
17861890ccaSMoudy Ho 	if (ret) {
17961890ccaSMoudy Ho 		dev_err(&mdp->pdev->dev, "scp_ipi_send failed %d\n", ret);
18061890ccaSMoudy Ho 		return -EPERM;
18161890ccaSMoudy Ho 	}
18261890ccaSMoudy Ho 	ret = wait_for_completion_timeout(&vpu->ipi_acked,
18361890ccaSMoudy Ho 					  msecs_to_jiffies(t));
18461890ccaSMoudy Ho 	if (!ret)
18561890ccaSMoudy Ho 		ret = -ETIME;
18661890ccaSMoudy Ho 	else if (vpu->status)
18761890ccaSMoudy Ho 		ret = -EINVAL;
18861890ccaSMoudy Ho 	else
18961890ccaSMoudy Ho 		ret = 0;
19061890ccaSMoudy Ho 	return ret;
19161890ccaSMoudy Ho }
19261890ccaSMoudy Ho 
mdp_vpu_dev_init(struct mdp_vpu_dev * vpu,struct mtk_scp * scp,struct mutex * lock)19361890ccaSMoudy Ho int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
19461890ccaSMoudy Ho 		     struct mutex *lock)
19561890ccaSMoudy Ho {
19661890ccaSMoudy Ho 	struct mdp_ipi_init_msg msg = {
19761890ccaSMoudy Ho 		.drv_data = (unsigned long)vpu,
19861890ccaSMoudy Ho 	};
19961890ccaSMoudy Ho 	struct mdp_dev *mdp = vpu_to_mdp(vpu);
20061890ccaSMoudy Ho 	int err;
2019288eae4SMoudy Ho 	u8 pp_num = mdp->mdp_data->pp_used;
20261890ccaSMoudy Ho 
20361890ccaSMoudy Ho 	init_completion(&vpu->ipi_acked);
20461890ccaSMoudy Ho 	vpu->scp = scp;
20561890ccaSMoudy Ho 	vpu->lock = lock;
20661890ccaSMoudy Ho 	vpu->work_size = 0;
20761890ccaSMoudy Ho 	err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
20861890ccaSMoudy Ho 	if (err)
20961890ccaSMoudy Ho 		goto err_work_size;
21061890ccaSMoudy Ho 	/* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */
21161890ccaSMoudy Ho 
212b4e52199SMoudy Ho 	mutex_lock(vpu->lock);
213b4e52199SMoudy Ho 	vpu->work_size = ALIGN(vpu->work_size, 64);
214b4e52199SMoudy Ho 	vpu->param_size = ALIGN(sizeof(struct img_ipi_frameparam), 64);
2159288eae4SMoudy Ho 	vpu->config_size = ALIGN(sizeof(struct img_config) * pp_num, 64);
216dec7920eSDan Carpenter 	err = mdp_vpu_shared_mem_alloc(vpu);
217b4e52199SMoudy Ho 	mutex_unlock(vpu->lock);
218dec7920eSDan Carpenter 	if (err) {
21961890ccaSMoudy Ho 		dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
22061890ccaSMoudy Ho 		goto err_mem_alloc;
22161890ccaSMoudy Ho 	}
22261890ccaSMoudy Ho 
22361890ccaSMoudy Ho 	dev_dbg(&mdp->pdev->dev,
224b4e52199SMoudy Ho 		"VPU param:%pK pa:%pad sz:%zx, work:%pK pa:%pad sz:%zx, config:%pK pa:%pad sz:%zx",
225b4e52199SMoudy Ho 		vpu->param, &vpu->param_addr, vpu->param_size,
22661890ccaSMoudy Ho 		vpu->work, &vpu->work_addr, vpu->work_size,
227b4e52199SMoudy Ho 		vpu->config, &vpu->config_addr, vpu->config_size);
228b4e52199SMoudy Ho 
22961890ccaSMoudy Ho 	msg.work_addr = vpu->work_addr;
23061890ccaSMoudy Ho 	msg.work_size = vpu->work_size;
23161890ccaSMoudy Ho 	err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
23261890ccaSMoudy Ho 	if (err)
23361890ccaSMoudy Ho 		goto err_work_size;
23461890ccaSMoudy Ho 
23561890ccaSMoudy Ho 	return 0;
23661890ccaSMoudy Ho 
23761890ccaSMoudy Ho err_work_size:
23861890ccaSMoudy Ho 	switch (vpu->status) {
23961890ccaSMoudy Ho 	case -MDP_IPI_EBUSY:
24061890ccaSMoudy Ho 		err = -EBUSY;
24161890ccaSMoudy Ho 		break;
24261890ccaSMoudy Ho 	case -MDP_IPI_ENOMEM:
24361890ccaSMoudy Ho 		err = -ENOSPC;	/* -ENOMEM */
24461890ccaSMoudy Ho 		break;
24561890ccaSMoudy Ho 	}
24661890ccaSMoudy Ho 	return err;
24761890ccaSMoudy Ho err_mem_alloc:
24861890ccaSMoudy Ho 	return err;
24961890ccaSMoudy Ho }
25061890ccaSMoudy Ho 
mdp_vpu_dev_deinit(struct mdp_vpu_dev * vpu)25161890ccaSMoudy Ho int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu)
25261890ccaSMoudy Ho {
25361890ccaSMoudy Ho 	struct mdp_ipi_deinit_msg msg = {
25461890ccaSMoudy Ho 		.drv_data = (unsigned long)vpu,
25561890ccaSMoudy Ho 		.work_addr = vpu->work_addr,
25661890ccaSMoudy Ho 	};
25761890ccaSMoudy Ho 
25861890ccaSMoudy Ho 	return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_DEINIT, &msg, sizeof(msg));
25961890ccaSMoudy Ho }
26061890ccaSMoudy Ho 
mdp_vpu_process(struct mdp_vpu_dev * vpu,struct img_ipi_frameparam * param)261b4e52199SMoudy Ho int mdp_vpu_process(struct mdp_vpu_dev *vpu, struct img_ipi_frameparam *param)
26261890ccaSMoudy Ho {
26361890ccaSMoudy Ho 	struct mdp_dev *mdp = vpu_to_mdp(vpu);
26461890ccaSMoudy Ho 	struct img_sw_addr addr;
26561890ccaSMoudy Ho 
266b4e52199SMoudy Ho 	mutex_lock(vpu->lock);
26761890ccaSMoudy Ho 	if (mdp_vpu_shared_mem_alloc(vpu)) {
26861890ccaSMoudy Ho 		dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
269b4e52199SMoudy Ho 		mutex_unlock(vpu->lock);
27061890ccaSMoudy Ho 		return -ENOMEM;
27161890ccaSMoudy Ho 	}
27261890ccaSMoudy Ho 
273b4e52199SMoudy Ho 	memset(vpu->param, 0, vpu->param_size);
274b4e52199SMoudy Ho 	memset(vpu->work, 0, vpu->work_size);
275b4e52199SMoudy Ho 	memset(vpu->config, 0, vpu->config_size);
276b4e52199SMoudy Ho 
277b4e52199SMoudy Ho 	param->self_data.va = (unsigned long)vpu->work;
278b4e52199SMoudy Ho 	param->self_data.pa = vpu->work_addr;
279b4e52199SMoudy Ho 	param->config_data.va = (unsigned long)vpu->config;
280b4e52199SMoudy Ho 	param->config_data.pa = vpu->config_addr;
281b4e52199SMoudy Ho 	param->drv_data = (unsigned long)vpu;
282b4e52199SMoudy Ho 	memcpy(vpu->param, param, sizeof(*param));
283b4e52199SMoudy Ho 
284b4e52199SMoudy Ho 	addr.pa = vpu->param_addr;
285b4e52199SMoudy Ho 	addr.va = (unsigned long)vpu->param;
286b4e52199SMoudy Ho 	mutex_unlock(vpu->lock);
287b4e52199SMoudy Ho 	return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_FRAME, &addr, sizeof(addr));
28861890ccaSMoudy Ho }
289