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/mailbox_controller.h> 8 #include <linux/platform_device.h> 9 #include "mtk-mdp3-cmdq.h" 10 #include "mtk-mdp3-comp.h" 11 #include "mtk-mdp3-core.h" 12 #include "mtk-mdp3-m2m.h" 13 #include "mtk-img-ipi.h" 14 15 #define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS 16 17 struct mdp_path { 18 struct mdp_dev *mdp_dev; 19 struct mdp_comp_ctx comps[MDP_PATH_MAX_COMPS]; 20 u32 num_comps; 21 const struct img_config *config; 22 const struct img_ipi_frameparam *param; 23 const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS]; 24 struct v4l2_rect bounds[IMG_MAX_HW_OUTPUTS]; 25 }; 26 27 #define has_op(ctx, op) \ 28 ((ctx)->comp->ops && (ctx)->comp->ops->op) 29 #define call_op(ctx, op, ...) \ 30 (has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0) 31 32 static bool is_output_disabled(int p_id, const struct img_compparam *param, u32 count) 33 { 34 u32 num = 0; 35 bool dis_output = false; 36 bool dis_tile = false; 37 38 if (CFG_CHECK(MT8183, p_id)) { 39 num = CFG_COMP(MT8183, param, num_subfrms); 40 dis_output = CFG_COMP(MT8183, param, frame.output_disable); 41 dis_tile = CFG_COMP(MT8183, param, frame.output_disable); 42 } 43 44 return (count < num) ? (dis_output || dis_tile) : true; 45 } 46 47 static int mdp_path_subfrm_require(const struct mdp_path *path, 48 struct mdp_cmdq_cmd *cmd, 49 s32 *mutex_id, u32 count) 50 { 51 const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; 52 const struct mdp_comp_ctx *ctx; 53 const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data; 54 struct device *dev = &path->mdp_dev->pdev->dev; 55 struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; 56 int id, index; 57 u32 num_comp = 0; 58 59 if (CFG_CHECK(MT8183, p_id)) 60 num_comp = CFG_GET(MT8183, path->config, num_components); 61 62 /* Decide which mutex to use based on the current pipeline */ 63 switch (path->comps[0].comp->public_id) { 64 case MDP_COMP_RDMA0: 65 index = MDP_PIPE_RDMA0; 66 break; 67 case MDP_COMP_ISP_IMGI: 68 index = MDP_PIPE_IMGI; 69 break; 70 case MDP_COMP_WPEI: 71 index = MDP_PIPE_WPEI; 72 break; 73 case MDP_COMP_WPEI2: 74 index = MDP_PIPE_WPEI2; 75 break; 76 default: 77 dev_err(dev, "Unknown pipeline and no mutex is assigned"); 78 return -EINVAL; 79 } 80 *mutex_id = data->pipe_info[index].mutex_id; 81 82 /* Set mutex mod */ 83 for (index = 0; index < num_comp; index++) { 84 ctx = &path->comps[index]; 85 if (is_output_disabled(p_id, ctx->param, count)) 86 continue; 87 id = ctx->comp->public_id; 88 mtk_mutex_write_mod(mutex[*mutex_id], 89 data->mdp_mutex_table_idx[id], false); 90 } 91 92 mtk_mutex_write_sof(mutex[*mutex_id], 93 MUTEX_SOF_IDX_SINGLE_MODE); 94 95 return 0; 96 } 97 98 static int mdp_path_subfrm_run(const struct mdp_path *path, 99 struct mdp_cmdq_cmd *cmd, 100 s32 *mutex_id, u32 count) 101 { 102 const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; 103 const struct mdp_comp_ctx *ctx; 104 struct device *dev = &path->mdp_dev->pdev->dev; 105 struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; 106 int index; 107 u32 num_comp = 0; 108 s32 event; 109 110 if (-1 == *mutex_id) { 111 dev_err(dev, "Incorrect mutex id"); 112 return -EINVAL; 113 } 114 115 if (CFG_CHECK(MT8183, p_id)) 116 num_comp = CFG_GET(MT8183, path->config, num_components); 117 118 /* Wait WROT SRAM shared to DISP RDMA */ 119 /* Clear SOF event for each engine */ 120 for (index = 0; index < num_comp; index++) { 121 ctx = &path->comps[index]; 122 if (is_output_disabled(p_id, ctx->param, count)) 123 continue; 124 event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF]; 125 if (event != MDP_GCE_NO_EVENT) 126 MM_REG_CLEAR(cmd, event); 127 } 128 129 /* Enable the mutex */ 130 mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt); 131 132 /* Wait SOF events and clear mutex modules (optional) */ 133 for (index = 0; index < num_comp; index++) { 134 ctx = &path->comps[index]; 135 if (is_output_disabled(p_id, ctx->param, count)) 136 continue; 137 event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF]; 138 if (event != MDP_GCE_NO_EVENT) 139 MM_REG_WAIT(cmd, event); 140 } 141 142 return 0; 143 } 144 145 static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path) 146 { 147 const int p_id = mdp->mdp_data->mdp_plat_id; 148 void *param = NULL; 149 int index, ret; 150 u32 num_comp = 0; 151 152 if (CFG_CHECK(MT8183, p_id)) 153 num_comp = CFG_GET(MT8183, path->config, num_components); 154 155 if (num_comp < 1) 156 return -EINVAL; 157 158 for (index = 0; index < num_comp; index++) { 159 if (CFG_CHECK(MT8183, p_id)) 160 param = (void *)CFG_ADDR(MT8183, path->config, components[index]); 161 ret = mdp_comp_ctx_config(mdp, &path->comps[index], 162 param, path->param); 163 if (ret) 164 return ret; 165 } 166 167 return 0; 168 } 169 170 static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, 171 struct mdp_path *path, u32 count) 172 { 173 const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; 174 const struct img_mmsys_ctrl *ctrl = NULL; 175 const struct img_mux *set; 176 struct mdp_comp_ctx *ctx; 177 s32 mutex_id; 178 int index, ret; 179 u32 num_comp = 0; 180 181 if (CFG_CHECK(MT8183, p_id)) 182 num_comp = CFG_GET(MT8183, path->config, num_components); 183 184 if (CFG_CHECK(MT8183, p_id)) 185 ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]); 186 187 /* Acquire components */ 188 ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count); 189 if (ret) 190 return ret; 191 /* Enable mux settings */ 192 for (index = 0; index < ctrl->num_sets; index++) { 193 set = &ctrl->sets[index]; 194 cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg, 195 set->value, 0xFFFFFFFF); 196 } 197 /* Config sub-frame information */ 198 for (index = (num_comp - 1); index >= 0; index--) { 199 ctx = &path->comps[index]; 200 if (is_output_disabled(p_id, ctx->param, count)) 201 continue; 202 ret = call_op(ctx, config_subfrm, cmd, count); 203 if (ret) 204 return ret; 205 } 206 /* Run components */ 207 ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count); 208 if (ret) 209 return ret; 210 /* Wait components done */ 211 for (index = 0; index < num_comp; index++) { 212 ctx = &path->comps[index]; 213 if (is_output_disabled(p_id, ctx->param, count)) 214 continue; 215 ret = call_op(ctx, wait_comp_event, cmd); 216 if (ret) 217 return ret; 218 } 219 /* Advance to the next sub-frame */ 220 for (index = 0; index < num_comp; index++) { 221 ctx = &path->comps[index]; 222 ret = call_op(ctx, advance_subfrm, cmd, count); 223 if (ret) 224 return ret; 225 } 226 /* Disable mux settings */ 227 for (index = 0; index < ctrl->num_sets; index++) { 228 set = &ctrl->sets[index]; 229 cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg, 230 0, 0xFFFFFFFF); 231 } 232 233 return 0; 234 } 235 236 static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, 237 struct mdp_path *path) 238 { 239 const int p_id = mdp->mdp_data->mdp_plat_id; 240 struct mdp_comp_ctx *ctx; 241 int index, count, ret; 242 u32 num_comp = 0; 243 u32 num_sub = 0; 244 245 if (CFG_CHECK(MT8183, p_id)) 246 num_comp = CFG_GET(MT8183, path->config, num_components); 247 248 if (CFG_CHECK(MT8183, p_id)) 249 num_sub = CFG_GET(MT8183, path->config, num_subfrms); 250 251 /* Config path frame */ 252 /* Reset components */ 253 for (index = 0; index < num_comp; index++) { 254 ctx = &path->comps[index]; 255 ret = call_op(ctx, init_comp, cmd); 256 if (ret) 257 return ret; 258 } 259 /* Config frame mode */ 260 for (index = 0; index < num_comp; index++) { 261 const struct v4l2_rect *compose; 262 u32 out = 0; 263 264 if (CFG_CHECK(MT8183, p_id)) 265 out = CFG_COMP(MT8183, ctx->param, outputs[0]); 266 267 compose = path->composes[out]; 268 ctx = &path->comps[index]; 269 ret = call_op(ctx, config_frame, cmd, compose); 270 if (ret) 271 return ret; 272 } 273 274 /* Config path sub-frames */ 275 for (count = 0; count < num_sub; count++) { 276 ret = mdp_path_config_subfrm(cmd, path, count); 277 if (ret) 278 return ret; 279 } 280 /* Post processing information */ 281 for (index = 0; index < num_comp; index++) { 282 ctx = &path->comps[index]; 283 ret = call_op(ctx, post_process, cmd); 284 if (ret) 285 return ret; 286 } 287 return 0; 288 } 289 290 static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, 291 size_t size) 292 { 293 struct device *dev; 294 dma_addr_t dma_addr; 295 296 pkt->va_base = kzalloc(size, GFP_KERNEL); 297 if (!pkt->va_base) 298 return -ENOMEM; 299 300 pkt->buf_size = size; 301 pkt->cl = (void *)client; 302 303 dev = client->chan->mbox->dev; 304 dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, 305 DMA_TO_DEVICE); 306 if (dma_mapping_error(dev, dma_addr)) { 307 dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); 308 kfree(pkt->va_base); 309 return -ENOMEM; 310 } 311 312 pkt->pa_base = dma_addr; 313 314 return 0; 315 } 316 317 static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt) 318 { 319 struct cmdq_client *client = (struct cmdq_client *)pkt->cl; 320 321 dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, 322 DMA_TO_DEVICE); 323 kfree(pkt->va_base); 324 pkt->va_base = NULL; 325 } 326 327 static void mdp_auto_release_work(struct work_struct *work) 328 { 329 struct mdp_cmdq_cmd *cmd; 330 struct mdp_dev *mdp; 331 int id; 332 333 cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work); 334 mdp = cmd->mdp; 335 336 id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 337 mtk_mutex_unprepare(mdp->mdp_mutex[id]); 338 mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, 339 cmd->num_comps); 340 341 atomic_dec(&mdp->job_count); 342 wake_up(&mdp->callback_wq); 343 344 mdp_cmdq_pkt_destroy(&cmd->pkt); 345 kfree(cmd->comps); 346 cmd->comps = NULL; 347 kfree(cmd); 348 cmd = NULL; 349 } 350 351 static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg) 352 { 353 struct mdp_cmdq_cmd *cmd; 354 struct cmdq_cb_data *data; 355 struct mdp_dev *mdp; 356 struct device *dev; 357 int id; 358 359 if (!mssg) { 360 pr_info("%s:no callback data\n", __func__); 361 return; 362 } 363 364 data = (struct cmdq_cb_data *)mssg; 365 cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt); 366 mdp = cmd->mdp; 367 dev = &mdp->pdev->dev; 368 369 if (cmd->mdp_ctx) 370 mdp_m2m_job_finish(cmd->mdp_ctx); 371 372 if (cmd->user_cmdq_cb) { 373 struct cmdq_cb_data user_cb_data; 374 375 user_cb_data.sta = data->sta; 376 user_cb_data.pkt = data->pkt; 377 cmd->user_cmdq_cb(user_cb_data); 378 } 379 380 INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work); 381 if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) { 382 dev_err(dev, "%s:queue_work fail!\n", __func__); 383 id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 384 mtk_mutex_unprepare(mdp->mdp_mutex[id]); 385 mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, 386 cmd->num_comps); 387 388 atomic_dec(&mdp->job_count); 389 wake_up(&mdp->callback_wq); 390 391 mdp_cmdq_pkt_destroy(&cmd->pkt); 392 kfree(cmd->comps); 393 cmd->comps = NULL; 394 kfree(cmd); 395 cmd = NULL; 396 } 397 } 398 399 int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) 400 { 401 struct mdp_path *path = NULL; 402 struct mdp_cmdq_cmd *cmd = NULL; 403 struct mdp_comp *comps = NULL; 404 struct device *dev = &mdp->pdev->dev; 405 const int p_id = mdp->mdp_data->mdp_plat_id; 406 int i, ret; 407 u32 num_comp = 0; 408 409 atomic_inc(&mdp->job_count); 410 if (atomic_read(&mdp->suspended)) { 411 atomic_dec(&mdp->job_count); 412 return -ECANCELED; 413 } 414 415 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 416 if (!cmd) { 417 ret = -ENOMEM; 418 goto err_cancel_job; 419 } 420 421 ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K); 422 if (ret) 423 goto err_free_cmd; 424 425 if (CFG_CHECK(MT8183, p_id)) { 426 num_comp = CFG_GET(MT8183, param->config, num_components); 427 } else { 428 ret = -EINVAL; 429 goto err_destroy_pkt; 430 } 431 comps = kcalloc(num_comp, sizeof(*comps), GFP_KERNEL); 432 if (!comps) { 433 ret = -ENOMEM; 434 goto err_destroy_pkt; 435 } 436 437 path = kzalloc(sizeof(*path), GFP_KERNEL); 438 if (!path) { 439 ret = -ENOMEM; 440 goto err_free_comps; 441 } 442 443 i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 444 ret = mtk_mutex_prepare(mdp->mdp_mutex[i]); 445 if (ret) { 446 dev_err(dev, "Fail to enable mutex clk\n"); 447 goto err_free_path; 448 } 449 450 path->mdp_dev = mdp; 451 path->config = param->config; 452 path->param = param->param; 453 for (i = 0; i < param->param->num_outputs; i++) { 454 path->bounds[i].left = 0; 455 path->bounds[i].top = 0; 456 path->bounds[i].width = 457 param->param->outputs[i].buffer.format.width; 458 path->bounds[i].height = 459 param->param->outputs[i].buffer.format.height; 460 path->composes[i] = param->composes[i] ? 461 param->composes[i] : &path->bounds[i]; 462 } 463 ret = mdp_path_ctx_init(mdp, path); 464 if (ret) { 465 dev_err(dev, "mdp_path_ctx_init error\n"); 466 goto err_free_path; 467 } 468 469 ret = mdp_path_config(mdp, cmd, path); 470 if (ret) { 471 dev_err(dev, "mdp_path_config error\n"); 472 goto err_free_path; 473 } 474 cmdq_pkt_finalize(&cmd->pkt); 475 476 for (i = 0; i < num_comp; i++) 477 memcpy(&comps[i], path->comps[i].comp, 478 sizeof(struct mdp_comp)); 479 480 mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback; 481 cmd->mdp = mdp; 482 cmd->user_cmdq_cb = param->cmdq_cb; 483 cmd->user_cb_data = param->cb_data; 484 cmd->comps = comps; 485 cmd->num_comps = num_comp; 486 cmd->mdp_ctx = param->mdp_ctx; 487 488 ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps); 489 if (ret) 490 goto err_free_path; 491 492 dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev, 493 cmd->pkt.pa_base, cmd->pkt.cmd_buf_size, 494 DMA_TO_DEVICE); 495 ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt); 496 if (ret < 0) { 497 dev_err(dev, "mbox send message fail %d!\n", ret); 498 goto err_clock_off; 499 } 500 mbox_client_txdone(mdp->cmdq_clt->chan, 0); 501 502 kfree(path); 503 return 0; 504 505 err_clock_off: 506 mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, 507 cmd->num_comps); 508 err_free_path: 509 i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; 510 mtk_mutex_unprepare(mdp->mdp_mutex[i]); 511 kfree(path); 512 err_free_comps: 513 kfree(comps); 514 err_destroy_pkt: 515 mdp_cmdq_pkt_destroy(&cmd->pkt); 516 err_free_cmd: 517 kfree(cmd); 518 err_cancel_job: 519 atomic_dec(&mdp->job_count); 520 521 return ret; 522 } 523 EXPORT_SYMBOL_GPL(mdp_cmdq_send); 524