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 #include "mtk-mdp3-core.h" 16 #include "mtk-mdp3-m2m.h" 17 18 static const struct mdp_platform_config mt8183_plat_cfg = { 19 .rdma_support_10bit = true, 20 .rdma_rsz1_sram_sharing = true, 21 .rdma_upsample_repeat_only = true, 22 .rsz_disable_dcm_small_sample = false, 23 .wrot_filter_constraint = false, 24 }; 25 26 static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = { 27 [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8183-mmsys" }, 28 [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8183-disp-mutex" }, 29 [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" } 30 }; 31 32 static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = { 33 [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, 34 [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0, 35 [MDP_COMP_RSZ1] = MUTEX_MOD_IDX_MDP_RSZ1, 36 [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0, 37 [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0, 38 [MDP_COMP_WDMA] = MUTEX_MOD_IDX_MDP_WDMA, 39 [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0, 40 [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0, 41 }; 42 43 static const struct mtk_mdp_driver_data mt8183_mdp_driver_data = { 44 .mdp_probe_infra = mt8183_mdp_probe_infra, 45 .mdp_cfg = &mt8183_plat_cfg, 46 .mdp_mutex_table_idx = mt8183_mutex_idx, 47 }; 48 49 static const struct of_device_id mdp_of_ids[] = { 50 { .compatible = "mediatek,mt8183-mdp3-rdma", 51 .data = &mt8183_mdp_driver_data, 52 }, 53 {}, 54 }; 55 MODULE_DEVICE_TABLE(of, mdp_of_ids); 56 57 static struct platform_device *__get_pdev_by_id(struct platform_device *pdev, 58 enum mdp_infra_id id) 59 { 60 struct device_node *node; 61 struct platform_device *mdp_pdev = NULL; 62 const struct mtk_mdp_driver_data *mdp_data; 63 const char *compat; 64 65 if (!pdev) 66 return NULL; 67 68 if (id < MDP_INFRA_MMSYS || id >= MDP_INFRA_MAX) { 69 dev_err(&pdev->dev, "Illegal infra id %d\n", id); 70 return NULL; 71 } 72 73 mdp_data = of_device_get_match_data(&pdev->dev); 74 if (!mdp_data) { 75 dev_err(&pdev->dev, "have no driver data to find node\n"); 76 return NULL; 77 } 78 compat = mdp_data->mdp_probe_infra[id].compatible; 79 80 node = of_find_compatible_node(NULL, NULL, compat); 81 if (WARN_ON(!node)) { 82 dev_err(&pdev->dev, "find node from id %d failed\n", id); 83 return NULL; 84 } 85 86 mdp_pdev = of_find_device_by_node(node); 87 of_node_put(node); 88 if (WARN_ON(!mdp_pdev)) { 89 dev_err(&pdev->dev, "find pdev from id %d failed\n", id); 90 return NULL; 91 } 92 93 return mdp_pdev; 94 } 95 96 struct platform_device *mdp_get_plat_device(struct platform_device *pdev) 97 { 98 struct device *dev = &pdev->dev; 99 struct device_node *mdp_node; 100 struct platform_device *mdp_pdev; 101 102 mdp_node = of_parse_phandle(dev->of_node, MDP_PHANDLE_NAME, 0); 103 if (!mdp_node) { 104 dev_err(dev, "can't get node %s\n", MDP_PHANDLE_NAME); 105 return NULL; 106 } 107 108 mdp_pdev = of_find_device_by_node(mdp_node); 109 of_node_put(mdp_node); 110 111 return mdp_pdev; 112 } 113 EXPORT_SYMBOL_GPL(mdp_get_plat_device); 114 115 int mdp_vpu_get_locked(struct mdp_dev *mdp) 116 { 117 int ret = 0; 118 119 if (mdp->vpu_count++ == 0) { 120 ret = rproc_boot(mdp->rproc_handle); 121 if (ret) { 122 dev_err(&mdp->pdev->dev, 123 "vpu_load_firmware failed %d\n", ret); 124 goto err_load_vpu; 125 } 126 ret = mdp_vpu_register(mdp); 127 if (ret) { 128 dev_err(&mdp->pdev->dev, 129 "mdp_vpu register failed %d\n", ret); 130 goto err_reg_vpu; 131 } 132 ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock); 133 if (ret) { 134 dev_err(&mdp->pdev->dev, 135 "mdp_vpu device init failed %d\n", ret); 136 goto err_init_vpu; 137 } 138 } 139 return 0; 140 141 err_init_vpu: 142 mdp_vpu_unregister(mdp); 143 err_reg_vpu: 144 err_load_vpu: 145 mdp->vpu_count--; 146 return ret; 147 } 148 149 void mdp_vpu_put_locked(struct mdp_dev *mdp) 150 { 151 if (--mdp->vpu_count == 0) { 152 mdp_vpu_dev_deinit(&mdp->vpu); 153 mdp_vpu_unregister(mdp); 154 } 155 } 156 157 void mdp_video_device_release(struct video_device *vdev) 158 { 159 struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev); 160 int i; 161 162 scp_put(mdp->scp); 163 164 destroy_workqueue(mdp->job_wq); 165 destroy_workqueue(mdp->clock_wq); 166 167 pm_runtime_disable(&mdp->pdev->dev); 168 169 vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev); 170 171 mdp_comp_destroy(mdp); 172 for (i = 0; i < MDP_PIPE_MAX; i++) 173 mtk_mutex_put(mdp->mdp_mutex[i]); 174 175 mdp_vpu_shared_mem_free(&mdp->vpu); 176 v4l2_m2m_release(mdp->m2m_dev); 177 kfree(mdp); 178 } 179 180 static int mdp_probe(struct platform_device *pdev) 181 { 182 struct device *dev = &pdev->dev; 183 struct mdp_dev *mdp; 184 struct platform_device *mm_pdev; 185 int ret, i; 186 187 mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); 188 if (!mdp) { 189 ret = -ENOMEM; 190 goto err_return; 191 } 192 193 mdp->pdev = pdev; 194 mdp->mdp_data = of_device_get_match_data(&pdev->dev); 195 196 mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS); 197 if (!mm_pdev) { 198 ret = -ENODEV; 199 goto err_destroy_device; 200 } 201 mdp->mdp_mmsys = &mm_pdev->dev; 202 203 mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX); 204 if (WARN_ON(!mm_pdev)) { 205 ret = -ENODEV; 206 goto err_destroy_device; 207 } 208 for (i = 0; i < MDP_PIPE_MAX; i++) { 209 mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev); 210 if (!mdp->mdp_mutex[i]) { 211 ret = -ENODEV; 212 goto err_free_mutex; 213 } 214 } 215 216 ret = mdp_comp_config(mdp); 217 if (ret) { 218 dev_err(dev, "Failed to config mdp components\n"); 219 goto err_free_mutex; 220 } 221 222 mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0); 223 if (!mdp->job_wq) { 224 dev_err(dev, "Unable to create job workqueue\n"); 225 ret = -ENOMEM; 226 goto err_deinit_comp; 227 } 228 229 mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE, 230 0); 231 if (!mdp->clock_wq) { 232 dev_err(dev, "Unable to create clock workqueue\n"); 233 ret = -ENOMEM; 234 goto err_destroy_job_wq; 235 } 236 237 mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP); 238 if (WARN_ON(!mm_pdev)) { 239 dev_err(&pdev->dev, "Could not get scp device\n"); 240 ret = -ENODEV; 241 goto err_destroy_clock_wq; 242 } 243 mdp->scp = platform_get_drvdata(mm_pdev); 244 mdp->rproc_handle = scp_get_rproc(mdp->scp); 245 dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle); 246 247 mutex_init(&mdp->vpu_lock); 248 mutex_init(&mdp->m2m_lock); 249 250 mdp->cmdq_clt = cmdq_mbox_create(dev, 0); 251 if (IS_ERR(mdp->cmdq_clt)) { 252 ret = PTR_ERR(mdp->cmdq_clt); 253 goto err_put_scp; 254 } 255 256 init_waitqueue_head(&mdp->callback_wq); 257 ida_init(&mdp->mdp_ida); 258 platform_set_drvdata(pdev, mdp); 259 260 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); 261 262 ret = v4l2_device_register(dev, &mdp->v4l2_dev); 263 if (ret) { 264 dev_err(dev, "Failed to register v4l2 device\n"); 265 ret = -EINVAL; 266 goto err_mbox_destroy; 267 } 268 269 ret = mdp_m2m_device_register(mdp); 270 if (ret) { 271 v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n"); 272 goto err_unregister_device; 273 } 274 275 dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id); 276 return 0; 277 278 err_unregister_device: 279 v4l2_device_unregister(&mdp->v4l2_dev); 280 err_mbox_destroy: 281 cmdq_mbox_destroy(mdp->cmdq_clt); 282 err_put_scp: 283 scp_put(mdp->scp); 284 err_destroy_clock_wq: 285 destroy_workqueue(mdp->clock_wq); 286 err_destroy_job_wq: 287 destroy_workqueue(mdp->job_wq); 288 err_deinit_comp: 289 mdp_comp_destroy(mdp); 290 err_free_mutex: 291 for (i = 0; i < MDP_PIPE_MAX; i++) 292 mtk_mutex_put(mdp->mdp_mutex[i]); 293 err_destroy_device: 294 kfree(mdp); 295 err_return: 296 dev_dbg(dev, "Errno %d\n", ret); 297 return ret; 298 } 299 300 static int mdp_remove(struct platform_device *pdev) 301 { 302 struct mdp_dev *mdp = platform_get_drvdata(pdev); 303 304 v4l2_device_unregister(&mdp->v4l2_dev); 305 306 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); 307 return 0; 308 } 309 310 static int __maybe_unused mdp_suspend(struct device *dev) 311 { 312 struct mdp_dev *mdp = dev_get_drvdata(dev); 313 int ret; 314 315 atomic_set(&mdp->suspended, 1); 316 317 if (atomic_read(&mdp->job_count)) { 318 ret = wait_event_timeout(mdp->callback_wq, 319 !atomic_read(&mdp->job_count), 320 2 * HZ); 321 if (ret == 0) { 322 dev_err(dev, 323 "%s:flushed cmdq task incomplete, count=%d\n", 324 __func__, atomic_read(&mdp->job_count)); 325 return -EBUSY; 326 } 327 } 328 329 return 0; 330 } 331 332 static int __maybe_unused mdp_resume(struct device *dev) 333 { 334 struct mdp_dev *mdp = dev_get_drvdata(dev); 335 336 atomic_set(&mdp->suspended, 0); 337 338 return 0; 339 } 340 341 static const struct dev_pm_ops mdp_pm_ops = { 342 SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume) 343 }; 344 345 static struct platform_driver mdp_driver = { 346 .probe = mdp_probe, 347 .remove = mdp_remove, 348 .driver = { 349 .name = MDP_MODULE_NAME, 350 .pm = &mdp_pm_ops, 351 .of_match_table = of_match_ptr(mdp_of_ids), 352 }, 353 }; 354 355 module_platform_driver(mdp_driver); 356 357 MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>"); 358 MODULE_DESCRIPTION("MediaTek image processor 3 driver"); 359 MODULE_LICENSE("GPL"); 360