File Index
Files and directories
Sign in
FILE

mtk-mdp3-vpu.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2022 MediaTek Inc.
  4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
  5 */
  6
  7#include <linux/remoteproc.h>
  8#include <linux/remoteproc/mtk_scp.h>
  9#include "mtk-mdp3-vpu.h"
 10#include "mtk-mdp3-core.h"
 11
 12#define MDP_VPU_MESSAGE_TIMEOUT 500U
 13
 14static inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu)
 15{
 16	return container_of(vpu, struct mdp_dev, vpu);
 17}
 18
 19static int mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev *vpu)
 20{
 21	struct device *dev;
 22
 23	if (IS_ERR_OR_NULL(vpu))
 24		goto err_return;
 25
 26	dev = scp_get_device(vpu->scp);
 27
 28	if (!vpu->param) {
 29		vpu->param = dma_alloc_wc(dev, vpu->param_size,
 30					  &vpu->param_addr, GFP_KERNEL);
 31		if (!vpu->param)
 32			goto err_return;
 33	}
 34
 35	if (!vpu->work) {
 36		vpu->work = dma_alloc_wc(dev, vpu->work_size,
 37					 &vpu->work_addr, GFP_KERNEL);
 38		if (!vpu->work)
 39			goto err_free_param;
 40	}
 41
 42	if (!vpu->config) {
 43		vpu->config = dma_alloc_wc(dev, vpu->config_size,
 44					   &vpu->config_addr, GFP_KERNEL);
 45		if (!vpu->config)
 46			goto err_free_work;
 47	}
 48
 49	return 0;
 50
 51err_free_work:
 52	dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr);
 53	vpu->work = NULL;
 54err_free_param:
 55	dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr);
 56	vpu->param = NULL;
 57err_return:
 58	return -ENOMEM;
 59}
 60
 61void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu)
 62{
 63	struct device *dev;
 64
 65	if (IS_ERR_OR_NULL(vpu))
 66		return;
 67
 68	dev = scp_get_device(vpu->scp);
 69
 70	if (vpu->param && vpu->param_addr)
 71		dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr);
 72
 73	if (vpu->work && vpu->work_addr)
 74		dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr);
 75
 76	if (vpu->config && vpu->config_addr)
 77		dma_free_wc(dev, vpu->config_size, vpu->config, vpu->config_addr);
 78}
 79
 80static void mdp_vpu_ipi_handle_init_ack(void *data, unsigned int len,
 81					void *priv)
 82{
 83	struct mdp_ipi_init_msg *msg = (struct mdp_ipi_init_msg *)data;
 84	struct mdp_vpu_dev *vpu =
 85		(struct mdp_vpu_dev *)(unsigned long)msg->drv_data;
 86
 87	if (!vpu->work_size)
 88		vpu->work_size = msg->work_size;
 89
 90	vpu->status = msg->status;
 91	complete(&vpu->ipi_acked);
 92}
 93
 94static void mdp_vpu_ipi_handle_deinit_ack(void *data, unsigned int len,
 95					  void *priv)
 96{
 97	struct mdp_ipi_deinit_msg *msg = (struct mdp_ipi_deinit_msg *)data;
 98	struct mdp_vpu_dev *vpu =
 99		(struct mdp_vpu_dev *)(unsigned long)msg->drv_data;
100
101	vpu->status = msg->status;
102	complete(&vpu->ipi_acked);
103}
104
105static void mdp_vpu_ipi_handle_frame_ack(void *data, unsigned int len,
106					 void *priv)
107{
108	struct img_sw_addr *addr = (struct img_sw_addr *)data;
109	struct img_ipi_frameparam *param =
110		(struct img_ipi_frameparam *)(unsigned long)addr->va;
111	struct mdp_vpu_dev *vpu =
112		(struct mdp_vpu_dev *)(unsigned long)param->drv_data;
113
114	if (param->state) {
115		struct mdp_dev *mdp = vpu_to_mdp(vpu);
116
117		dev_err(&mdp->pdev->dev, "VPU MDP failure:%d\n", param->state);
118	}
119	vpu->status = param->state;
120	complete(&vpu->ipi_acked);
121}
122
123int mdp_vpu_register(struct mdp_dev *mdp)
124{
125	int err;
126	struct mtk_scp *scp = mdp->scp;
127	struct device *dev = &mdp->pdev->dev;
128
129	err = scp_ipi_register(scp, SCP_IPI_MDP_INIT,
130			       mdp_vpu_ipi_handle_init_ack, NULL);
131	if (err) {
132		dev_err(dev, "scp_ipi_register failed %d\n", err);
133		goto err_ipi_init;
134	}
135	err = scp_ipi_register(scp, SCP_IPI_MDP_DEINIT,
136			       mdp_vpu_ipi_handle_deinit_ack, NULL);
137	if (err) {
138		dev_err(dev, "scp_ipi_register failed %d\n", err);
139		goto err_ipi_deinit;
140	}
141	err = scp_ipi_register(scp, SCP_IPI_MDP_FRAME,
142			       mdp_vpu_ipi_handle_frame_ack, NULL);
143	if (err) {
144		dev_err(dev, "scp_ipi_register failed %d\n", err);
145		goto err_ipi_frame;
146	}
147	return 0;
148
149err_ipi_frame:
150	scp_ipi_unregister(scp, SCP_IPI_MDP_DEINIT);
151err_ipi_deinit:
152	scp_ipi_unregister(scp, SCP_IPI_MDP_INIT);
153err_ipi_init:
154
155	return err;
156}
157
158void mdp_vpu_unregister(struct mdp_dev *mdp)
159{
160	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_INIT);
161	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_DEINIT);
162	scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_FRAME);
163}
164
165static int mdp_vpu_sendmsg(struct mdp_vpu_dev *vpu, enum scp_ipi_id id,
166			   void *buf, unsigned int len)
167{
168	struct mdp_dev *mdp = vpu_to_mdp(vpu);
169	unsigned int t = MDP_VPU_MESSAGE_TIMEOUT;
170	int ret;
171
172	if (!vpu->scp) {
173		dev_dbg(&mdp->pdev->dev, "vpu scp is NULL");
174		return -EINVAL;
175	}
176	ret = scp_ipi_send(vpu->scp, id, buf, len, 2000);
177
178	if (ret) {
179		dev_err(&mdp->pdev->dev, "scp_ipi_send failed %d\n", ret);
180		return -EPERM;
181	}
182	ret = wait_for_completion_timeout(&vpu->ipi_acked,
183					  msecs_to_jiffies(t));
184	if (!ret)
185		ret = -ETIME;
186	else if (vpu->status)
187		ret = -EINVAL;
188	else
189		ret = 0;
190	return ret;
191}
192
193int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp,
194		     struct mutex *lock)
195{
196	struct mdp_ipi_init_msg msg = {
197		.drv_data = (unsigned long)vpu,
198	};
199	struct mdp_dev *mdp = vpu_to_mdp(vpu);
200	int err;
201	u8 pp_num = mdp->mdp_data->pp_used;
202
203	init_completion(&vpu->ipi_acked);
204	vpu->scp = scp;
205	vpu->lock = lock;
206	vpu->work_size = 0;
207	err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
208	if (err)
209		goto err_work_size;
210	/* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */
211
212	mutex_lock(vpu->lock);
213	vpu->work_size = ALIGN(vpu->work_size, 64);
214	vpu->param_size = ALIGN(sizeof(struct img_ipi_frameparam), 64);
215	vpu->config_size = ALIGN(sizeof(struct img_config) * pp_num, 64);
216	err = mdp_vpu_shared_mem_alloc(vpu);
217	mutex_unlock(vpu->lock);
218	if (err) {
219		dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
220		goto err_mem_alloc;
221	}
222
223	dev_dbg(&mdp->pdev->dev,
224		"VPU param:%p pa:%pad sz:%zx, work:%p pa:%pad sz:%zx, config:%p pa:%pad sz:%zx",
225		vpu->param, &vpu->param_addr, vpu->param_size,
226		vpu->work, &vpu->work_addr, vpu->work_size,
227		vpu->config, &vpu->config_addr, vpu->config_size);
228
229	msg.work_addr = vpu->work_addr;
230	msg.work_size = vpu->work_size;
231	err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg));
232	if (err)
233		goto err_work_size;
234
235	return 0;
236
237err_work_size:
238	switch (vpu->status) {
239	case -MDP_IPI_EBUSY:
240		err = -EBUSY;
241		break;
242	case -MDP_IPI_ENOMEM:
243		err = -ENOSPC;	/* -ENOMEM */
244		break;
245	}
246	return err;
247err_mem_alloc:
248	return err;
249}
250
251int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu)
252{
253	struct mdp_ipi_deinit_msg msg = {
254		.drv_data = (unsigned long)vpu,
255		.work_addr = vpu->work_addr,
256	};
257
258	return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_DEINIT, &msg, sizeof(msg));
259}
260
261int mdp_vpu_process(struct mdp_vpu_dev *vpu, struct img_ipi_frameparam *param)
262{
263	struct mdp_dev *mdp = vpu_to_mdp(vpu);
264	struct img_sw_addr addr;
265
266	mutex_lock(vpu->lock);
267	if (mdp_vpu_shared_mem_alloc(vpu)) {
268		dev_err(&mdp->pdev->dev, "VPU memory alloc fail!");
269		mutex_unlock(vpu->lock);
270		return -ENOMEM;
271	}
272
273	memset(vpu->param, 0, vpu->param_size);
274	memset(vpu->work, 0, vpu->work_size);
275	memset(vpu->config, 0, vpu->config_size);
276
277	param->self_data.va = (unsigned long)vpu->work;
278	param->self_data.pa = vpu->work_addr;
279	param->config_data.va = (unsigned long)vpu->config;
280	param->config_data.pa = vpu->config_addr;
281	param->drv_data = (unsigned long)vpu;
282	memcpy(vpu->param, param, sizeof(*param));
283
284	addr.pa = vpu->param_addr;
285	addr.va = (unsigned long)vpu->param;
286	mutex_unlock(vpu->lock);
287	return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_FRAME, &addr, sizeof(addr));
288}
~/ Read-only file preview.