brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · da3a892 Raw
289 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/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 500U13 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	else189		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:%pK pa:%pad sz:%zx, work:%pK pa:%pad sz:%zx, config:%pK 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}289