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/remoteproc.h> 862306a36Sopenharmony_ci#include <linux/remoteproc/mtk_scp.h> 962306a36Sopenharmony_ci#include "mtk-mdp3-vpu.h" 1062306a36Sopenharmony_ci#include "mtk-mdp3-core.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define MDP_VPU_MESSAGE_TIMEOUT 500U 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci return container_of(vpu, struct mdp_dev, vpu); 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev *vpu) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct device *dev; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(vpu)) 2462306a36Sopenharmony_ci goto err_return; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci dev = scp_get_device(vpu->scp); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (!vpu->param) { 2962306a36Sopenharmony_ci vpu->param = dma_alloc_wc(dev, vpu->param_size, 3062306a36Sopenharmony_ci &vpu->param_addr, GFP_KERNEL); 3162306a36Sopenharmony_ci if (!vpu->param) 3262306a36Sopenharmony_ci goto err_return; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (!vpu->work) { 3662306a36Sopenharmony_ci vpu->work = dma_alloc_wc(dev, vpu->work_size, 3762306a36Sopenharmony_ci &vpu->work_addr, GFP_KERNEL); 3862306a36Sopenharmony_ci if (!vpu->work) 3962306a36Sopenharmony_ci goto err_free_param; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!vpu->config) { 4362306a36Sopenharmony_ci vpu->config = dma_alloc_wc(dev, vpu->config_size, 4462306a36Sopenharmony_ci &vpu->config_addr, GFP_KERNEL); 4562306a36Sopenharmony_ci if (!vpu->config) 4662306a36Sopenharmony_ci goto err_free_work; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cierr_free_work: 5262306a36Sopenharmony_ci dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr); 5362306a36Sopenharmony_ci vpu->work = NULL; 5462306a36Sopenharmony_cierr_free_param: 5562306a36Sopenharmony_ci dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr); 5662306a36Sopenharmony_ci vpu->param = NULL; 5762306a36Sopenharmony_cierr_return: 5862306a36Sopenharmony_ci return -ENOMEM; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_civoid mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct device *dev; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (IS_ERR_OR_NULL(vpu)) 6662306a36Sopenharmony_ci return; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci dev = scp_get_device(vpu->scp); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (vpu->param && vpu->param_addr) 7162306a36Sopenharmony_ci dma_free_wc(dev, vpu->param_size, vpu->param, vpu->param_addr); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (vpu->work && vpu->work_addr) 7462306a36Sopenharmony_ci dma_free_wc(dev, vpu->work_size, vpu->work, vpu->work_addr); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (vpu->config && vpu->config_addr) 7762306a36Sopenharmony_ci dma_free_wc(dev, vpu->config_size, vpu->config, vpu->config_addr); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void mdp_vpu_ipi_handle_init_ack(void *data, unsigned int len, 8162306a36Sopenharmony_ci void *priv) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct mdp_ipi_init_msg *msg = (struct mdp_ipi_init_msg *)data; 8462306a36Sopenharmony_ci struct mdp_vpu_dev *vpu = 8562306a36Sopenharmony_ci (struct mdp_vpu_dev *)(unsigned long)msg->drv_data; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!vpu->work_size) 8862306a36Sopenharmony_ci vpu->work_size = msg->work_size; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci vpu->status = msg->status; 9162306a36Sopenharmony_ci complete(&vpu->ipi_acked); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic void mdp_vpu_ipi_handle_deinit_ack(void *data, unsigned int len, 9562306a36Sopenharmony_ci void *priv) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct mdp_ipi_deinit_msg *msg = (struct mdp_ipi_deinit_msg *)data; 9862306a36Sopenharmony_ci struct mdp_vpu_dev *vpu = 9962306a36Sopenharmony_ci (struct mdp_vpu_dev *)(unsigned long)msg->drv_data; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci vpu->status = msg->status; 10262306a36Sopenharmony_ci complete(&vpu->ipi_acked); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void mdp_vpu_ipi_handle_frame_ack(void *data, unsigned int len, 10662306a36Sopenharmony_ci void *priv) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct img_sw_addr *addr = (struct img_sw_addr *)data; 10962306a36Sopenharmony_ci struct img_ipi_frameparam *param = 11062306a36Sopenharmony_ci (struct img_ipi_frameparam *)(unsigned long)addr->va; 11162306a36Sopenharmony_ci struct mdp_vpu_dev *vpu = 11262306a36Sopenharmony_ci (struct mdp_vpu_dev *)(unsigned long)param->drv_data; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (param->state) { 11562306a36Sopenharmony_ci struct mdp_dev *mdp = vpu_to_mdp(vpu); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci dev_err(&mdp->pdev->dev, "VPU MDP failure:%d\n", param->state); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci vpu->status = param->state; 12062306a36Sopenharmony_ci complete(&vpu->ipi_acked); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ciint mdp_vpu_register(struct mdp_dev *mdp) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci int err; 12662306a36Sopenharmony_ci struct mtk_scp *scp = mdp->scp; 12762306a36Sopenharmony_ci struct device *dev = &mdp->pdev->dev; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci err = scp_ipi_register(scp, SCP_IPI_MDP_INIT, 13062306a36Sopenharmony_ci mdp_vpu_ipi_handle_init_ack, NULL); 13162306a36Sopenharmony_ci if (err) { 13262306a36Sopenharmony_ci dev_err(dev, "scp_ipi_register failed %d\n", err); 13362306a36Sopenharmony_ci goto err_ipi_init; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci err = scp_ipi_register(scp, SCP_IPI_MDP_DEINIT, 13662306a36Sopenharmony_ci mdp_vpu_ipi_handle_deinit_ack, NULL); 13762306a36Sopenharmony_ci if (err) { 13862306a36Sopenharmony_ci dev_err(dev, "scp_ipi_register failed %d\n", err); 13962306a36Sopenharmony_ci goto err_ipi_deinit; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci err = scp_ipi_register(scp, SCP_IPI_MDP_FRAME, 14262306a36Sopenharmony_ci mdp_vpu_ipi_handle_frame_ack, NULL); 14362306a36Sopenharmony_ci if (err) { 14462306a36Sopenharmony_ci dev_err(dev, "scp_ipi_register failed %d\n", err); 14562306a36Sopenharmony_ci goto err_ipi_frame; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cierr_ipi_frame: 15062306a36Sopenharmony_ci scp_ipi_unregister(scp, SCP_IPI_MDP_DEINIT); 15162306a36Sopenharmony_cierr_ipi_deinit: 15262306a36Sopenharmony_ci scp_ipi_unregister(scp, SCP_IPI_MDP_INIT); 15362306a36Sopenharmony_cierr_ipi_init: 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return err; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_civoid mdp_vpu_unregister(struct mdp_dev *mdp) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_INIT); 16162306a36Sopenharmony_ci scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_DEINIT); 16262306a36Sopenharmony_ci scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_FRAME); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int mdp_vpu_sendmsg(struct mdp_vpu_dev *vpu, enum scp_ipi_id id, 16662306a36Sopenharmony_ci void *buf, unsigned int len) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct mdp_dev *mdp = vpu_to_mdp(vpu); 16962306a36Sopenharmony_ci unsigned int t = MDP_VPU_MESSAGE_TIMEOUT; 17062306a36Sopenharmony_ci int ret; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!vpu->scp) { 17362306a36Sopenharmony_ci dev_dbg(&mdp->pdev->dev, "vpu scp is NULL"); 17462306a36Sopenharmony_ci return -EINVAL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci ret = scp_ipi_send(vpu->scp, id, buf, len, 2000); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (ret) { 17962306a36Sopenharmony_ci dev_err(&mdp->pdev->dev, "scp_ipi_send failed %d\n", ret); 18062306a36Sopenharmony_ci return -EPERM; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci ret = wait_for_completion_timeout(&vpu->ipi_acked, 18362306a36Sopenharmony_ci msecs_to_jiffies(t)); 18462306a36Sopenharmony_ci if (!ret) 18562306a36Sopenharmony_ci ret = -ETIME; 18662306a36Sopenharmony_ci else if (vpu->status) 18762306a36Sopenharmony_ci ret = -EINVAL; 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci ret = 0; 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ciint mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, 19462306a36Sopenharmony_ci struct mutex *lock) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct mdp_ipi_init_msg msg = { 19762306a36Sopenharmony_ci .drv_data = (unsigned long)vpu, 19862306a36Sopenharmony_ci }; 19962306a36Sopenharmony_ci struct mdp_dev *mdp = vpu_to_mdp(vpu); 20062306a36Sopenharmony_ci int err; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci init_completion(&vpu->ipi_acked); 20362306a36Sopenharmony_ci vpu->scp = scp; 20462306a36Sopenharmony_ci vpu->lock = lock; 20562306a36Sopenharmony_ci vpu->work_size = 0; 20662306a36Sopenharmony_ci err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg)); 20762306a36Sopenharmony_ci if (err) 20862306a36Sopenharmony_ci goto err_work_size; 20962306a36Sopenharmony_ci /* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci mutex_lock(vpu->lock); 21262306a36Sopenharmony_ci vpu->work_size = ALIGN(vpu->work_size, 64); 21362306a36Sopenharmony_ci vpu->param_size = ALIGN(sizeof(struct img_ipi_frameparam), 64); 21462306a36Sopenharmony_ci vpu->config_size = ALIGN(sizeof(struct img_config), 64); 21562306a36Sopenharmony_ci err = mdp_vpu_shared_mem_alloc(vpu); 21662306a36Sopenharmony_ci mutex_unlock(vpu->lock); 21762306a36Sopenharmony_ci if (err) { 21862306a36Sopenharmony_ci dev_err(&mdp->pdev->dev, "VPU memory alloc fail!"); 21962306a36Sopenharmony_ci goto err_mem_alloc; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci dev_dbg(&mdp->pdev->dev, 22362306a36Sopenharmony_ci "VPU param:%pK pa:%pad sz:%zx, work:%pK pa:%pad sz:%zx, config:%pK pa:%pad sz:%zx", 22462306a36Sopenharmony_ci vpu->param, &vpu->param_addr, vpu->param_size, 22562306a36Sopenharmony_ci vpu->work, &vpu->work_addr, vpu->work_size, 22662306a36Sopenharmony_ci vpu->config, &vpu->config_addr, vpu->config_size); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci msg.work_addr = vpu->work_addr; 22962306a36Sopenharmony_ci msg.work_size = vpu->work_size; 23062306a36Sopenharmony_ci err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg)); 23162306a36Sopenharmony_ci if (err) 23262306a36Sopenharmony_ci goto err_work_size; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cierr_work_size: 23762306a36Sopenharmony_ci switch (vpu->status) { 23862306a36Sopenharmony_ci case -MDP_IPI_EBUSY: 23962306a36Sopenharmony_ci err = -EBUSY; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case -MDP_IPI_ENOMEM: 24262306a36Sopenharmony_ci err = -ENOSPC; /* -ENOMEM */ 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci return err; 24662306a36Sopenharmony_cierr_mem_alloc: 24762306a36Sopenharmony_ci return err; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciint mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct mdp_ipi_deinit_msg msg = { 25362306a36Sopenharmony_ci .drv_data = (unsigned long)vpu, 25462306a36Sopenharmony_ci .work_addr = vpu->work_addr, 25562306a36Sopenharmony_ci }; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_DEINIT, &msg, sizeof(msg)); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciint mdp_vpu_process(struct mdp_vpu_dev *vpu, struct img_ipi_frameparam *param) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct mdp_dev *mdp = vpu_to_mdp(vpu); 26362306a36Sopenharmony_ci struct img_sw_addr addr; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci mutex_lock(vpu->lock); 26662306a36Sopenharmony_ci if (mdp_vpu_shared_mem_alloc(vpu)) { 26762306a36Sopenharmony_ci dev_err(&mdp->pdev->dev, "VPU memory alloc fail!"); 26862306a36Sopenharmony_ci mutex_unlock(vpu->lock); 26962306a36Sopenharmony_ci return -ENOMEM; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci memset(vpu->param, 0, vpu->param_size); 27362306a36Sopenharmony_ci memset(vpu->work, 0, vpu->work_size); 27462306a36Sopenharmony_ci memset(vpu->config, 0, vpu->config_size); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci param->self_data.va = (unsigned long)vpu->work; 27762306a36Sopenharmony_ci param->self_data.pa = vpu->work_addr; 27862306a36Sopenharmony_ci param->config_data.va = (unsigned long)vpu->config; 27962306a36Sopenharmony_ci param->config_data.pa = vpu->config_addr; 28062306a36Sopenharmony_ci param->drv_data = (unsigned long)vpu; 28162306a36Sopenharmony_ci memcpy(vpu->param, param, sizeof(*param)); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci addr.pa = vpu->param_addr; 28462306a36Sopenharmony_ci addr.va = (unsigned long)vpu->param; 28562306a36Sopenharmony_ci mutex_unlock(vpu->lock); 28662306a36Sopenharmony_ci return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_FRAME, &addr, sizeof(addr)); 28762306a36Sopenharmony_ci} 288