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