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