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/clk.h> 8#include <linux/module.h> 9#include <linux/of_platform.h> 10#include <linux/platform_device.h> 11#include <linux/pm_runtime.h> 12#include <linux/remoteproc.h> 13#include <linux/remoteproc/mtk_scp.h> 14#include <media/videobuf2-dma-contig.h> 15 16#include "mtk-mdp3-core.h" 17#include "mtk-mdp3-cfg.h" 18#include "mtk-mdp3-m2m.h" 19 20static const struct of_device_id mdp_of_ids[] = { 21 { .compatible = "mediatek,mt8183-mdp3-rdma", 22 .data = &mt8183_mdp_driver_data, 23 }, 24 { .compatible = "mediatek,mt8195-mdp3-rdma", 25 .data = &mt8195_mdp_driver_data, 26 }, 27 { .compatible = "mediatek,mt8195-mdp3-wrot", 28 .data = &mt8195_mdp_driver_data, 29 }, 30 {}, 31}; 32MODULE_DEVICE_TABLE(of, mdp_of_ids); 33 34static struct platform_device *__get_pdev_by_id(struct platform_device *pdev, 35 struct platform_device *from, 36 enum mdp_infra_id id) 37{ 38 struct device_node *node, *f = NULL; 39 struct platform_device *mdp_pdev = NULL; 40 const struct mtk_mdp_driver_data *mdp_data; 41 const char *compat; 42 43 if (!pdev) 44 return NULL; 45 46 if (id < MDP_INFRA_MMSYS || id >= MDP_INFRA_MAX) { 47 dev_err(&pdev->dev, "Illegal infra id %d\n", id); 48 return NULL; 49 } 50 51 mdp_data = of_device_get_match_data(&pdev->dev); 52 if (!mdp_data) { 53 dev_err(&pdev->dev, "have no driver data to find node\n"); 54 return NULL; 55 } 56 57 compat = mdp_data->mdp_probe_infra[id].compatible; 58 if (strlen(compat) == 0) 59 return NULL; 60 61 if (from) 62 f = from->dev.of_node; 63 node = of_find_compatible_node(f, NULL, compat); 64 if (WARN_ON(!node)) { 65 dev_err(&pdev->dev, "find node from id %d failed\n", id); 66 return NULL; 67 } 68 69 mdp_pdev = of_find_device_by_node(node); 70 of_node_put(node); 71 if (WARN_ON(!mdp_pdev)) { 72 dev_err(&pdev->dev, "find pdev from id %d failed\n", id); 73 return NULL; 74 } 75 76 return mdp_pdev; 77} 78 79struct platform_device *mdp_get_plat_device(struct platform_device *pdev) 80{ 81 struct device *dev = &pdev->dev; 82 struct device_node *mdp_node; 83 struct platform_device *mdp_pdev; 84 85 mdp_node = of_parse_phandle(dev->of_node, MDP_PHANDLE_NAME, 0); 86 if (!mdp_node) { 87 dev_err(dev, "can't get node %s\n", MDP_PHANDLE_NAME); 88 return NULL; 89 } 90 91 mdp_pdev = of_find_device_by_node(mdp_node); 92 of_node_put(mdp_node); 93 94 return mdp_pdev; 95} 96EXPORT_SYMBOL_GPL(mdp_get_plat_device); 97 98int mdp_vpu_get_locked(struct mdp_dev *mdp) 99{ 100 int ret = 0; 101 102 if (mdp->vpu_count++ == 0) { 103 ret = rproc_boot(mdp->rproc_handle); 104 if (ret) { 105 dev_err(&mdp->pdev->dev, 106 "vpu_load_firmware failed %d\n", ret); 107 goto err_load_vpu; 108 } 109 ret = mdp_vpu_register(mdp); 110 if (ret) { 111 dev_err(&mdp->pdev->dev, 112 "mdp_vpu register failed %d\n", ret); 113 goto err_reg_vpu; 114 } 115 ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock); 116 if (ret) { 117 dev_err(&mdp->pdev->dev, 118 "mdp_vpu device init failed %d\n", ret); 119 goto err_init_vpu; 120 } 121 } 122 return 0; 123 124err_init_vpu: 125 mdp_vpu_unregister(mdp); 126err_reg_vpu: 127err_load_vpu: 128 mdp->vpu_count--; 129 return ret; 130} 131 132void mdp_vpu_put_locked(struct mdp_dev *mdp) 133{ 134 if (--mdp->vpu_count == 0) { 135 mdp_vpu_dev_deinit(&mdp->vpu); 136 mdp_vpu_unregister(mdp); 137 } 138} 139 140void mdp_video_device_release(struct video_device *vdev) 141{ 142 struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev); 143 int i; 144 145 for (i = 0; i < mdp->mdp_data->pp_used; i++) 146 if (mdp->cmdq_clt[i]) 147 cmdq_mbox_destroy(mdp->cmdq_clt[i]); 148 149 scp_put(mdp->scp); 150 151 destroy_workqueue(mdp->job_wq); 152 destroy_workqueue(mdp->clock_wq); 153 154 pm_runtime_disable(&mdp->pdev->dev); 155 156 vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev); 157 158 mdp_comp_destroy(mdp); 159 for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) { 160 enum mdp_mm_subsys_id idx; 161 struct mtk_mutex *m; 162 u32 m_id; 163 164 idx = mdp->mdp_data->pipe_info[i].sub_id; 165 m_id = mdp->mdp_data->pipe_info[i].mutex_id; 166 m = mdp->mm_subsys[idx].mdp_mutex[m_id]; 167 if (!IS_ERR_OR_NULL(m)) 168 mtk_mutex_put(m); 169 } 170 171 mdp_vpu_shared_mem_free(&mdp->vpu); 172 v4l2_m2m_release(mdp->m2m_dev); 173 kfree(mdp); 174} 175 176static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id) 177{ 178 struct platform_device *mm_pdev = NULL; 179 struct device **dev; 180 int i; 181 182 if (!mdp) 183 return -EINVAL; 184 185 for (i = 0; i < MDP_MM_SUBSYS_MAX; i++) { 186 const char *compat; 187 enum mdp_infra_id sub_id = id + i; 188 189 switch (id) { 190 case MDP_INFRA_MMSYS: 191 dev = &mdp->mm_subsys[i].mmsys; 192 break; 193 case MDP_INFRA_MUTEX: 194 dev = &mdp->mm_subsys[i].mutex; 195 break; 196 default: 197 dev_err(&mdp->pdev->dev, "Unknown infra id %d", id); 198 return -EINVAL; 199 } 200 201 /* 202 * Not every chip has multiple multimedia subsystems, so 203 * the config may be null. 204 */ 205 compat = mdp->mdp_data->mdp_probe_infra[sub_id].compatible; 206 if (strlen(compat) == 0) 207 continue; 208 209 mm_pdev = __get_pdev_by_id(mdp->pdev, mm_pdev, sub_id); 210 if (WARN_ON(!mm_pdev)) 211 return -ENODEV; 212 213 *dev = &mm_pdev->dev; 214 } 215 216 return 0; 217} 218 219static int mdp_probe(struct platform_device *pdev) 220{ 221 struct device *dev = &pdev->dev; 222 struct mdp_dev *mdp; 223 struct platform_device *mm_pdev; 224 struct resource *res; 225 int ret, i, mutex_id; 226 227 mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); 228 if (!mdp) { 229 ret = -ENOMEM; 230 goto err_return; 231 } 232 233 mdp->pdev = pdev; 234 mdp->mdp_data = of_device_get_match_data(&pdev->dev); 235 236 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 237 if (res->start != mdp->mdp_data->mdp_con_res) { 238 platform_set_drvdata(pdev, mdp); 239 goto success_return; 240 } 241 242 ret = mdp_mm_subsys_deploy(mdp, MDP_INFRA_MMSYS); 243 if (ret) 244 goto err_destroy_device; 245 246 ret = mdp_mm_subsys_deploy(mdp, MDP_INFRA_MUTEX); 247 if (ret) 248 goto err_destroy_device; 249 250 for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) { 251 enum mdp_mm_subsys_id idx; 252 struct mtk_mutex **m; 253 254 idx = mdp->mdp_data->pipe_info[i].sub_id; 255 mutex_id = mdp->mdp_data->pipe_info[i].mutex_id; 256 m = &mdp->mm_subsys[idx].mdp_mutex[mutex_id]; 257 258 if (!IS_ERR_OR_NULL(*m)) 259 continue; 260 261 *m = mtk_mutex_get(mdp->mm_subsys[idx].mutex); 262 if (IS_ERR(*m)) { 263 ret = PTR_ERR(*m); 264 goto err_free_mutex; 265 } 266 } 267 268 ret = mdp_comp_config(mdp); 269 if (ret) { 270 dev_err(dev, "Failed to config mdp components\n"); 271 goto err_free_mutex; 272 } 273 274 mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0); 275 if (!mdp->job_wq) { 276 dev_err(dev, "Unable to create job workqueue\n"); 277 ret = -ENOMEM; 278 goto err_deinit_comp; 279 } 280 281 mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE, 282 0); 283 if (!mdp->clock_wq) { 284 dev_err(dev, "Unable to create clock workqueue\n"); 285 ret = -ENOMEM; 286 goto err_destroy_job_wq; 287 } 288 289 mdp->scp = scp_get(pdev); 290 if (!mdp->scp) { 291 mm_pdev = __get_pdev_by_id(pdev, NULL, MDP_INFRA_SCP); 292 if (WARN_ON(!mm_pdev)) { 293 dev_err(&pdev->dev, "Could not get scp device\n"); 294 ret = -ENODEV; 295 goto err_destroy_clock_wq; 296 } 297 mdp->scp = platform_get_drvdata(mm_pdev); 298 } 299 300 mdp->rproc_handle = scp_get_rproc(mdp->scp); 301 dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle); 302 303 mutex_init(&mdp->vpu_lock); 304 mutex_init(&mdp->m2m_lock); 305 306 for (i = 0; i < mdp->mdp_data->pp_used; i++) { 307 mdp->cmdq_clt[i] = cmdq_mbox_create(dev, i); 308 if (IS_ERR(mdp->cmdq_clt[i])) { 309 ret = PTR_ERR(mdp->cmdq_clt[i]); 310 goto err_mbox_destroy; 311 } 312 } 313 314 init_waitqueue_head(&mdp->callback_wq); 315 ida_init(&mdp->mdp_ida); 316 platform_set_drvdata(pdev, mdp); 317 318 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); 319 320 ret = v4l2_device_register(dev, &mdp->v4l2_dev); 321 if (ret) { 322 dev_err(dev, "Failed to register v4l2 device\n"); 323 ret = -EINVAL; 324 goto err_mbox_destroy; 325 } 326 327 ret = mdp_m2m_device_register(mdp); 328 if (ret) { 329 v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n"); 330 goto err_unregister_device; 331 } 332 333success_return: 334 dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id); 335 return 0; 336 337err_unregister_device: 338 v4l2_device_unregister(&mdp->v4l2_dev); 339err_mbox_destroy: 340 while (--i >= 0) 341 cmdq_mbox_destroy(mdp->cmdq_clt[i]); 342 scp_put(mdp->scp); 343err_destroy_clock_wq: 344 destroy_workqueue(mdp->clock_wq); 345err_destroy_job_wq: 346 destroy_workqueue(mdp->job_wq); 347err_deinit_comp: 348 mdp_comp_destroy(mdp); 349err_free_mutex: 350 for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) { 351 enum mdp_mm_subsys_id idx; 352 struct mtk_mutex *m; 353 354 idx = mdp->mdp_data->pipe_info[i].sub_id; 355 mutex_id = mdp->mdp_data->pipe_info[i].mutex_id; 356 m = mdp->mm_subsys[idx].mdp_mutex[mutex_id]; 357 if (!IS_ERR_OR_NULL(m)) 358 mtk_mutex_put(m); 359 } 360err_destroy_device: 361 kfree(mdp); 362err_return: 363 dev_dbg(dev, "Errno %d\n", ret); 364 return ret; 365} 366 367static void mdp_remove(struct platform_device *pdev) 368{ 369 struct mdp_dev *mdp = platform_get_drvdata(pdev); 370 371 v4l2_device_unregister(&mdp->v4l2_dev); 372 373 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); 374} 375 376static int __maybe_unused mdp_suspend(struct device *dev) 377{ 378 struct mdp_dev *mdp = dev_get_drvdata(dev); 379 int ret; 380 381 atomic_set(&mdp->suspended, 1); 382 383 if (atomic_read(&mdp->job_count)) { 384 ret = wait_event_timeout(mdp->callback_wq, 385 !atomic_read(&mdp->job_count), 386 2 * HZ); 387 if (ret == 0) { 388 dev_err(dev, 389 "%s:flushed cmdq task incomplete, count=%d\n", 390 __func__, atomic_read(&mdp->job_count)); 391 return -EBUSY; 392 } 393 } 394 395 return 0; 396} 397 398static int __maybe_unused mdp_resume(struct device *dev) 399{ 400 struct mdp_dev *mdp = dev_get_drvdata(dev); 401 402 atomic_set(&mdp->suspended, 0); 403 404 return 0; 405} 406 407static const struct dev_pm_ops mdp_pm_ops = { 408 SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume) 409}; 410 411static struct platform_driver mdp_driver = { 412 .probe = mdp_probe, 413 .remove_new = mdp_remove, 414 .driver = { 415 .name = MDP_MODULE_NAME, 416 .pm = &mdp_pm_ops, 417 .of_match_table = mdp_of_ids, 418 }, 419}; 420 421module_platform_driver(mdp_driver); 422 423MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>"); 424MODULE_DESCRIPTION("MediaTek image processor 3 driver"); 425MODULE_LICENSE("GPL"); 426