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/mailbox_controller.h> 862306a36Sopenharmony_ci#include <linux/platform_device.h> 962306a36Sopenharmony_ci#include "mtk-mdp3-cmdq.h" 1062306a36Sopenharmony_ci#include "mtk-mdp3-comp.h" 1162306a36Sopenharmony_ci#include "mtk-mdp3-core.h" 1262306a36Sopenharmony_ci#include "mtk-mdp3-m2m.h" 1362306a36Sopenharmony_ci#include "mtk-img-ipi.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct mdp_path { 1862306a36Sopenharmony_ci struct mdp_dev *mdp_dev; 1962306a36Sopenharmony_ci struct mdp_comp_ctx comps[MDP_PATH_MAX_COMPS]; 2062306a36Sopenharmony_ci u32 num_comps; 2162306a36Sopenharmony_ci const struct img_config *config; 2262306a36Sopenharmony_ci const struct img_ipi_frameparam *param; 2362306a36Sopenharmony_ci const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS]; 2462306a36Sopenharmony_ci struct v4l2_rect bounds[IMG_MAX_HW_OUTPUTS]; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define has_op(ctx, op) \ 2862306a36Sopenharmony_ci ((ctx)->comp->ops && (ctx)->comp->ops->op) 2962306a36Sopenharmony_ci #define call_op(ctx, op, ...) \ 3062306a36Sopenharmony_ci (has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci u32 num = 0; 3562306a36Sopenharmony_ci bool dis_output = false; 3662306a36Sopenharmony_ci bool dis_tile = false; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) { 3962306a36Sopenharmony_ci num = CFG_COMP(MT8183, param, num_subfrms); 4062306a36Sopenharmony_ci dis_output = CFG_COMP(MT8183, param, frame.output_disable); 4162306a36Sopenharmony_ci dis_tile = CFG_COMP(MT8183, param, frame.output_disable); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return (count < num) ? (dis_output || dis_tile) : true; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int mdp_path_subfrm_require(const struct mdp_path *path, 4862306a36Sopenharmony_ci struct mdp_cmdq_cmd *cmd, 4962306a36Sopenharmony_ci s32 *mutex_id, u32 count) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; 5262306a36Sopenharmony_ci const struct mdp_comp_ctx *ctx; 5362306a36Sopenharmony_ci const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data; 5462306a36Sopenharmony_ci struct device *dev = &path->mdp_dev->pdev->dev; 5562306a36Sopenharmony_ci struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; 5662306a36Sopenharmony_ci int id, index; 5762306a36Sopenharmony_ci u32 num_comp = 0; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 6062306a36Sopenharmony_ci num_comp = CFG_GET(MT8183, path->config, num_components); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Decide which mutex to use based on the current pipeline */ 6362306a36Sopenharmony_ci switch (path->comps[0].comp->public_id) { 6462306a36Sopenharmony_ci case MDP_COMP_RDMA0: 6562306a36Sopenharmony_ci index = MDP_PIPE_RDMA0; 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci case MDP_COMP_ISP_IMGI: 6862306a36Sopenharmony_ci index = MDP_PIPE_IMGI; 6962306a36Sopenharmony_ci break; 7062306a36Sopenharmony_ci case MDP_COMP_WPEI: 7162306a36Sopenharmony_ci index = MDP_PIPE_WPEI; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci case MDP_COMP_WPEI2: 7462306a36Sopenharmony_ci index = MDP_PIPE_WPEI2; 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci default: 7762306a36Sopenharmony_ci dev_err(dev, "Unknown pipeline and no mutex is assigned"); 7862306a36Sopenharmony_ci return -EINVAL; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci *mutex_id = data->pipe_info[index].mutex_id; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Set mutex mod */ 8362306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 8462306a36Sopenharmony_ci ctx = &path->comps[index]; 8562306a36Sopenharmony_ci if (is_output_disabled(p_id, ctx->param, count)) 8662306a36Sopenharmony_ci continue; 8762306a36Sopenharmony_ci id = ctx->comp->public_id; 8862306a36Sopenharmony_ci mtk_mutex_write_mod(mutex[*mutex_id], 8962306a36Sopenharmony_ci data->mdp_mutex_table_idx[id], false); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mtk_mutex_write_sof(mutex[*mutex_id], 9362306a36Sopenharmony_ci MUTEX_SOF_IDX_SINGLE_MODE); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int mdp_path_subfrm_run(const struct mdp_path *path, 9962306a36Sopenharmony_ci struct mdp_cmdq_cmd *cmd, 10062306a36Sopenharmony_ci s32 *mutex_id, u32 count) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; 10362306a36Sopenharmony_ci const struct mdp_comp_ctx *ctx; 10462306a36Sopenharmony_ci struct device *dev = &path->mdp_dev->pdev->dev; 10562306a36Sopenharmony_ci struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; 10662306a36Sopenharmony_ci int index; 10762306a36Sopenharmony_ci u32 num_comp = 0; 10862306a36Sopenharmony_ci s32 event; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (-1 == *mutex_id) { 11162306a36Sopenharmony_ci dev_err(dev, "Incorrect mutex id"); 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 11662306a36Sopenharmony_ci num_comp = CFG_GET(MT8183, path->config, num_components); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Wait WROT SRAM shared to DISP RDMA */ 11962306a36Sopenharmony_ci /* Clear SOF event for each engine */ 12062306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 12162306a36Sopenharmony_ci ctx = &path->comps[index]; 12262306a36Sopenharmony_ci if (is_output_disabled(p_id, ctx->param, count)) 12362306a36Sopenharmony_ci continue; 12462306a36Sopenharmony_ci event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF]; 12562306a36Sopenharmony_ci if (event != MDP_GCE_NO_EVENT) 12662306a36Sopenharmony_ci MM_REG_CLEAR(cmd, event); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Enable the mutex */ 13062306a36Sopenharmony_ci mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Wait SOF events and clear mutex modules (optional) */ 13362306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 13462306a36Sopenharmony_ci ctx = &path->comps[index]; 13562306a36Sopenharmony_ci if (is_output_disabled(p_id, ctx->param, count)) 13662306a36Sopenharmony_ci continue; 13762306a36Sopenharmony_ci event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF]; 13862306a36Sopenharmony_ci if (event != MDP_GCE_NO_EVENT) 13962306a36Sopenharmony_ci MM_REG_WAIT(cmd, event); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci const int p_id = mdp->mdp_data->mdp_plat_id; 14862306a36Sopenharmony_ci void *param = NULL; 14962306a36Sopenharmony_ci int index, ret; 15062306a36Sopenharmony_ci u32 num_comp = 0; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 15362306a36Sopenharmony_ci num_comp = CFG_GET(MT8183, path->config, num_components); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (num_comp < 1) 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 15962306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 16062306a36Sopenharmony_ci param = (void *)CFG_ADDR(MT8183, path->config, components[index]); 16162306a36Sopenharmony_ci ret = mdp_comp_ctx_config(mdp, &path->comps[index], 16262306a36Sopenharmony_ci param, path->param); 16362306a36Sopenharmony_ci if (ret) 16462306a36Sopenharmony_ci return ret; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, 17162306a36Sopenharmony_ci struct mdp_path *path, u32 count) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; 17462306a36Sopenharmony_ci const struct img_mmsys_ctrl *ctrl = NULL; 17562306a36Sopenharmony_ci const struct img_mux *set; 17662306a36Sopenharmony_ci struct mdp_comp_ctx *ctx; 17762306a36Sopenharmony_ci s32 mutex_id; 17862306a36Sopenharmony_ci int index, ret; 17962306a36Sopenharmony_ci u32 num_comp = 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 18262306a36Sopenharmony_ci num_comp = CFG_GET(MT8183, path->config, num_components); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 18562306a36Sopenharmony_ci ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* Acquire components */ 18862306a36Sopenharmony_ci ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count); 18962306a36Sopenharmony_ci if (ret) 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci /* Enable mux settings */ 19262306a36Sopenharmony_ci for (index = 0; index < ctrl->num_sets; index++) { 19362306a36Sopenharmony_ci set = &ctrl->sets[index]; 19462306a36Sopenharmony_ci cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg, 19562306a36Sopenharmony_ci set->value, 0xFFFFFFFF); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci /* Config sub-frame information */ 19862306a36Sopenharmony_ci for (index = (num_comp - 1); index >= 0; index--) { 19962306a36Sopenharmony_ci ctx = &path->comps[index]; 20062306a36Sopenharmony_ci if (is_output_disabled(p_id, ctx->param, count)) 20162306a36Sopenharmony_ci continue; 20262306a36Sopenharmony_ci ret = call_op(ctx, config_subfrm, cmd, count); 20362306a36Sopenharmony_ci if (ret) 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci /* Run components */ 20762306a36Sopenharmony_ci ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count); 20862306a36Sopenharmony_ci if (ret) 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci /* Wait components done */ 21162306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 21262306a36Sopenharmony_ci ctx = &path->comps[index]; 21362306a36Sopenharmony_ci if (is_output_disabled(p_id, ctx->param, count)) 21462306a36Sopenharmony_ci continue; 21562306a36Sopenharmony_ci ret = call_op(ctx, wait_comp_event, cmd); 21662306a36Sopenharmony_ci if (ret) 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci /* Advance to the next sub-frame */ 22062306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 22162306a36Sopenharmony_ci ctx = &path->comps[index]; 22262306a36Sopenharmony_ci ret = call_op(ctx, advance_subfrm, cmd, count); 22362306a36Sopenharmony_ci if (ret) 22462306a36Sopenharmony_ci return ret; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci /* Disable mux settings */ 22762306a36Sopenharmony_ci for (index = 0; index < ctrl->num_sets; index++) { 22862306a36Sopenharmony_ci set = &ctrl->sets[index]; 22962306a36Sopenharmony_ci cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg, 23062306a36Sopenharmony_ci 0, 0xFFFFFFFF); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, 23762306a36Sopenharmony_ci struct mdp_path *path) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci const int p_id = mdp->mdp_data->mdp_plat_id; 24062306a36Sopenharmony_ci struct mdp_comp_ctx *ctx; 24162306a36Sopenharmony_ci int index, count, ret; 24262306a36Sopenharmony_ci u32 num_comp = 0; 24362306a36Sopenharmony_ci u32 num_sub = 0; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 24662306a36Sopenharmony_ci num_comp = CFG_GET(MT8183, path->config, num_components); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 24962306a36Sopenharmony_ci num_sub = CFG_GET(MT8183, path->config, num_subfrms); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Config path frame */ 25262306a36Sopenharmony_ci /* Reset components */ 25362306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 25462306a36Sopenharmony_ci ctx = &path->comps[index]; 25562306a36Sopenharmony_ci ret = call_op(ctx, init_comp, cmd); 25662306a36Sopenharmony_ci if (ret) 25762306a36Sopenharmony_ci return ret; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci /* Config frame mode */ 26062306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 26162306a36Sopenharmony_ci const struct v4l2_rect *compose; 26262306a36Sopenharmony_ci u32 out = 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ctx = &path->comps[index]; 26562306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) 26662306a36Sopenharmony_ci out = CFG_COMP(MT8183, ctx->param, outputs[0]); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci compose = path->composes[out]; 26962306a36Sopenharmony_ci ret = call_op(ctx, config_frame, cmd, compose); 27062306a36Sopenharmony_ci if (ret) 27162306a36Sopenharmony_ci return ret; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Config path sub-frames */ 27562306a36Sopenharmony_ci for (count = 0; count < num_sub; count++) { 27662306a36Sopenharmony_ci ret = mdp_path_config_subfrm(cmd, path, count); 27762306a36Sopenharmony_ci if (ret) 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci /* Post processing information */ 28162306a36Sopenharmony_ci for (index = 0; index < num_comp; index++) { 28262306a36Sopenharmony_ci ctx = &path->comps[index]; 28362306a36Sopenharmony_ci ret = call_op(ctx, post_process, cmd); 28462306a36Sopenharmony_ci if (ret) 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, 29162306a36Sopenharmony_ci size_t size) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct device *dev; 29462306a36Sopenharmony_ci dma_addr_t dma_addr; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci pkt->va_base = kzalloc(size, GFP_KERNEL); 29762306a36Sopenharmony_ci if (!pkt->va_base) 29862306a36Sopenharmony_ci return -ENOMEM; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci pkt->buf_size = size; 30162306a36Sopenharmony_ci pkt->cl = (void *)client; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci dev = client->chan->mbox->dev; 30462306a36Sopenharmony_ci dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, 30562306a36Sopenharmony_ci DMA_TO_DEVICE); 30662306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) { 30762306a36Sopenharmony_ci dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); 30862306a36Sopenharmony_ci kfree(pkt->va_base); 30962306a36Sopenharmony_ci return -ENOMEM; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci pkt->pa_base = dma_addr; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct cmdq_client *client = (struct cmdq_client *)pkt->cl; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, 32262306a36Sopenharmony_ci DMA_TO_DEVICE); 32362306a36Sopenharmony_ci kfree(pkt->va_base); 32462306a36Sopenharmony_ci pkt->va_base = NULL; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void mdp_auto_release_work(struct work_struct *work) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct mdp_cmdq_cmd *cmd; 33062306a36Sopenharmony_ci struct mdp_dev *mdp; 33162306a36Sopenharmony_ci int id; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work); 33462306a36Sopenharmony_ci mdp = cmd->mdp; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 33762306a36Sopenharmony_ci mtk_mutex_unprepare(mdp->mdp_mutex[id]); 33862306a36Sopenharmony_ci mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, 33962306a36Sopenharmony_ci cmd->num_comps); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci atomic_dec(&mdp->job_count); 34262306a36Sopenharmony_ci wake_up(&mdp->callback_wq); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci mdp_cmdq_pkt_destroy(&cmd->pkt); 34562306a36Sopenharmony_ci kfree(cmd->comps); 34662306a36Sopenharmony_ci cmd->comps = NULL; 34762306a36Sopenharmony_ci kfree(cmd); 34862306a36Sopenharmony_ci cmd = NULL; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct mdp_cmdq_cmd *cmd; 35462306a36Sopenharmony_ci struct cmdq_cb_data *data; 35562306a36Sopenharmony_ci struct mdp_dev *mdp; 35662306a36Sopenharmony_ci struct device *dev; 35762306a36Sopenharmony_ci int id; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (!mssg) { 36062306a36Sopenharmony_ci pr_info("%s:no callback data\n", __func__); 36162306a36Sopenharmony_ci return; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci data = (struct cmdq_cb_data *)mssg; 36562306a36Sopenharmony_ci cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt); 36662306a36Sopenharmony_ci mdp = cmd->mdp; 36762306a36Sopenharmony_ci dev = &mdp->pdev->dev; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (cmd->mdp_ctx) 37062306a36Sopenharmony_ci mdp_m2m_job_finish(cmd->mdp_ctx); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (cmd->user_cmdq_cb) { 37362306a36Sopenharmony_ci struct cmdq_cb_data user_cb_data; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci user_cb_data.sta = data->sta; 37662306a36Sopenharmony_ci user_cb_data.pkt = data->pkt; 37762306a36Sopenharmony_ci cmd->user_cmdq_cb(user_cb_data); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work); 38162306a36Sopenharmony_ci if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) { 38262306a36Sopenharmony_ci dev_err(dev, "%s:queue_work fail!\n", __func__); 38362306a36Sopenharmony_ci id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 38462306a36Sopenharmony_ci mtk_mutex_unprepare(mdp->mdp_mutex[id]); 38562306a36Sopenharmony_ci mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, 38662306a36Sopenharmony_ci cmd->num_comps); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci atomic_dec(&mdp->job_count); 38962306a36Sopenharmony_ci wake_up(&mdp->callback_wq); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci mdp_cmdq_pkt_destroy(&cmd->pkt); 39262306a36Sopenharmony_ci kfree(cmd->comps); 39362306a36Sopenharmony_ci cmd->comps = NULL; 39462306a36Sopenharmony_ci kfree(cmd); 39562306a36Sopenharmony_ci cmd = NULL; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciint mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct mdp_path *path = NULL; 40262306a36Sopenharmony_ci struct mdp_cmdq_cmd *cmd = NULL; 40362306a36Sopenharmony_ci struct mdp_comp *comps = NULL; 40462306a36Sopenharmony_ci struct device *dev = &mdp->pdev->dev; 40562306a36Sopenharmony_ci const int p_id = mdp->mdp_data->mdp_plat_id; 40662306a36Sopenharmony_ci int i, ret; 40762306a36Sopenharmony_ci u32 num_comp = 0; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci atomic_inc(&mdp->job_count); 41062306a36Sopenharmony_ci if (atomic_read(&mdp->suspended)) { 41162306a36Sopenharmony_ci atomic_dec(&mdp->job_count); 41262306a36Sopenharmony_ci return -ECANCELED; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 41662306a36Sopenharmony_ci if (!cmd) { 41762306a36Sopenharmony_ci ret = -ENOMEM; 41862306a36Sopenharmony_ci goto err_cancel_job; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K); 42262306a36Sopenharmony_ci if (ret) 42362306a36Sopenharmony_ci goto err_free_cmd; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (CFG_CHECK(MT8183, p_id)) { 42662306a36Sopenharmony_ci num_comp = CFG_GET(MT8183, param->config, num_components); 42762306a36Sopenharmony_ci } else { 42862306a36Sopenharmony_ci ret = -EINVAL; 42962306a36Sopenharmony_ci goto err_destroy_pkt; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL); 43262306a36Sopenharmony_ci if (!comps) { 43362306a36Sopenharmony_ci ret = -ENOMEM; 43462306a36Sopenharmony_ci goto err_destroy_pkt; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci path = kzalloc(sizeof(*path), GFP_KERNEL); 43862306a36Sopenharmony_ci if (!path) { 43962306a36Sopenharmony_ci ret = -ENOMEM; 44062306a36Sopenharmony_ci goto err_free_comps; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 44462306a36Sopenharmony_ci ret = mtk_mutex_prepare(mdp->mdp_mutex[i]); 44562306a36Sopenharmony_ci if (ret) { 44662306a36Sopenharmony_ci dev_err(dev, "Fail to enable mutex clk\n"); 44762306a36Sopenharmony_ci goto err_free_path; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci path->mdp_dev = mdp; 45162306a36Sopenharmony_ci path->config = param->config; 45262306a36Sopenharmony_ci path->param = param->param; 45362306a36Sopenharmony_ci for (i = 0; i < param->param->num_outputs; i++) { 45462306a36Sopenharmony_ci path->bounds[i].left = 0; 45562306a36Sopenharmony_ci path->bounds[i].top = 0; 45662306a36Sopenharmony_ci path->bounds[i].width = 45762306a36Sopenharmony_ci param->param->outputs[i].buffer.format.width; 45862306a36Sopenharmony_ci path->bounds[i].height = 45962306a36Sopenharmony_ci param->param->outputs[i].buffer.format.height; 46062306a36Sopenharmony_ci path->composes[i] = param->composes[i] ? 46162306a36Sopenharmony_ci param->composes[i] : &path->bounds[i]; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci ret = mdp_path_ctx_init(mdp, path); 46462306a36Sopenharmony_ci if (ret) { 46562306a36Sopenharmony_ci dev_err(dev, "mdp_path_ctx_init error\n"); 46662306a36Sopenharmony_ci goto err_free_path; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ret = mdp_path_config(mdp, cmd, path); 47062306a36Sopenharmony_ci if (ret) { 47162306a36Sopenharmony_ci dev_err(dev, "mdp_path_config error\n"); 47262306a36Sopenharmony_ci goto err_free_path; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci cmdq_pkt_finalize(&cmd->pkt); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci for (i = 0; i < num_comp; i++) 47762306a36Sopenharmony_ci memcpy(&comps[i], path->comps[i].comp, 47862306a36Sopenharmony_ci sizeof(struct mdp_comp)); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback; 48162306a36Sopenharmony_ci cmd->mdp = mdp; 48262306a36Sopenharmony_ci cmd->user_cmdq_cb = param->cmdq_cb; 48362306a36Sopenharmony_ci cmd->user_cb_data = param->cb_data; 48462306a36Sopenharmony_ci cmd->comps = comps; 48562306a36Sopenharmony_ci cmd->num_comps = num_comp; 48662306a36Sopenharmony_ci cmd->mdp_ctx = param->mdp_ctx; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps); 48962306a36Sopenharmony_ci if (ret) 49062306a36Sopenharmony_ci goto err_free_path; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev, 49362306a36Sopenharmony_ci cmd->pkt.pa_base, cmd->pkt.cmd_buf_size, 49462306a36Sopenharmony_ci DMA_TO_DEVICE); 49562306a36Sopenharmony_ci ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt); 49662306a36Sopenharmony_ci if (ret < 0) { 49762306a36Sopenharmony_ci dev_err(dev, "mbox send message fail %d!\n", ret); 49862306a36Sopenharmony_ci goto err_clock_off; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci mbox_client_txdone(mdp->cmdq_clt->chan, 0); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci kfree(path); 50362306a36Sopenharmony_ci return 0; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cierr_clock_off: 50662306a36Sopenharmony_ci mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, 50762306a36Sopenharmony_ci cmd->num_comps); 50862306a36Sopenharmony_cierr_free_path: 50962306a36Sopenharmony_ci i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 51062306a36Sopenharmony_ci mtk_mutex_unprepare(mdp->mdp_mutex[i]); 51162306a36Sopenharmony_ci kfree(path); 51262306a36Sopenharmony_cierr_free_comps: 51362306a36Sopenharmony_ci kfree(comps); 51462306a36Sopenharmony_cierr_destroy_pkt: 51562306a36Sopenharmony_ci mdp_cmdq_pkt_destroy(&cmd->pkt); 51662306a36Sopenharmony_cierr_free_cmd: 51762306a36Sopenharmony_ci kfree(cmd); 51862306a36Sopenharmony_cierr_cancel_job: 51962306a36Sopenharmony_ci atomic_dec(&mdp->job_count); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mdp_cmdq_send); 524