1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2022 MediaTek Inc.
4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
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>
16 #include "mtk-mdp3-core.h"
17 #include "mtk-mdp3-cfg.h"
18 #include "mtk-mdp3-m2m.h"
20 static const struct of_device_id mdp_of_ids[] = {
21 { .compatible = "mediatek,mt8183-mdp3-rdma",
22 .data = &mt8183_mdp_driver_data,
26 MODULE_DEVICE_TABLE(of, mdp_of_ids);
28 static struct platform_device *__get_pdev_by_id(struct platform_device *pdev,
31 struct device_node *node;
32 struct platform_device *mdp_pdev = NULL;
33 const struct mtk_mdp_driver_data *mdp_data;
39 if (id < MDP_INFRA_MMSYS || id >= MDP_INFRA_MAX) {
40 dev_err(&pdev->dev, "Illegal infra id %d\n", id);
44 mdp_data = of_device_get_match_data(&pdev->dev);
46 dev_err(&pdev->dev, "have no driver data to find node\n");
49 compat = mdp_data->mdp_probe_infra[id].compatible;
51 node = of_find_compatible_node(NULL, NULL, compat);
53 dev_err(&pdev->dev, "find node from id %d failed\n", id);
57 mdp_pdev = of_find_device_by_node(node);
59 if (WARN_ON(!mdp_pdev)) {
60 dev_err(&pdev->dev, "find pdev from id %d failed\n", id);
67 struct platform_device *mdp_get_plat_device(struct platform_device *pdev)
69 struct device *dev = &pdev->dev;
70 struct device_node *mdp_node;
71 struct platform_device *mdp_pdev;
73 mdp_node = of_parse_phandle(dev->of_node, MDP_PHANDLE_NAME, 0);
75 dev_err(dev, "can't get node %s\n", MDP_PHANDLE_NAME);
79 mdp_pdev = of_find_device_by_node(mdp_node);
80 of_node_put(mdp_node);
84 EXPORT_SYMBOL_GPL(mdp_get_plat_device);
86 int mdp_vpu_get_locked(struct mdp_dev *mdp)
90 if (mdp->vpu_count++ == 0) {
91 ret = rproc_boot(mdp->rproc_handle);
93 dev_err(&mdp->pdev->dev,
94 "vpu_load_firmware failed %d\n", ret);
97 ret = mdp_vpu_register(mdp);
99 dev_err(&mdp->pdev->dev,
100 "mdp_vpu register failed %d\n", ret);
103 ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock);
105 dev_err(&mdp->pdev->dev,
106 "mdp_vpu device init failed %d\n", ret);
113 mdp_vpu_unregister(mdp);
120 void mdp_vpu_put_locked(struct mdp_dev *mdp)
122 if (--mdp->vpu_count == 0) {
123 mdp_vpu_dev_deinit(&mdp->vpu);
124 mdp_vpu_unregister(mdp);
128 void mdp_video_device_release(struct video_device *vdev)
130 struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev);
135 destroy_workqueue(mdp->job_wq);
136 destroy_workqueue(mdp->clock_wq);
138 pm_runtime_disable(&mdp->pdev->dev);
140 vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev);
142 mdp_comp_destroy(mdp);
143 for (i = 0; i < MDP_PIPE_MAX; i++)
144 mtk_mutex_put(mdp->mdp_mutex[i]);
146 mdp_vpu_shared_mem_free(&mdp->vpu);
147 v4l2_m2m_release(mdp->m2m_dev);
151 static int mdp_probe(struct platform_device *pdev)
153 struct device *dev = &pdev->dev;
155 struct platform_device *mm_pdev;
156 int ret, i, mutex_id;
158 mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);
165 mdp->mdp_data = of_device_get_match_data(&pdev->dev);
167 mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS);
170 goto err_destroy_device;
172 mdp->mdp_mmsys = &mm_pdev->dev;
174 mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX);
175 if (WARN_ON(!mm_pdev)) {
177 goto err_destroy_device;
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]))
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]);
190 ret = mdp_comp_config(mdp);
192 dev_err(dev, "Failed to config mdp components\n");
196 mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
198 dev_err(dev, "Unable to create job workqueue\n");
200 goto err_deinit_comp;
203 mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE,
205 if (!mdp->clock_wq) {
206 dev_err(dev, "Unable to create clock workqueue\n");
208 goto err_destroy_job_wq;
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");
215 goto err_destroy_clock_wq;
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);
221 mutex_init(&mdp->vpu_lock);
222 mutex_init(&mdp->m2m_lock);
224 mdp->cmdq_clt = cmdq_mbox_create(dev, 0);
225 if (IS_ERR(mdp->cmdq_clt)) {
226 ret = PTR_ERR(mdp->cmdq_clt);
230 init_waitqueue_head(&mdp->callback_wq);
231 ida_init(&mdp->mdp_ida);
232 platform_set_drvdata(pdev, mdp);
234 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
236 ret = v4l2_device_register(dev, &mdp->v4l2_dev);
238 dev_err(dev, "Failed to register v4l2 device\n");
240 goto err_mbox_destroy;
243 ret = mdp_m2m_device_register(mdp);
245 v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n");
246 goto err_unregister_device;
249 dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id);
252 err_unregister_device:
253 v4l2_device_unregister(&mdp->v4l2_dev);
255 cmdq_mbox_destroy(mdp->cmdq_clt);
258 err_destroy_clock_wq:
259 destroy_workqueue(mdp->clock_wq);
261 destroy_workqueue(mdp->job_wq);
263 mdp_comp_destroy(mdp);
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]);
271 dev_dbg(dev, "Errno %d\n", ret);
275 static void mdp_remove(struct platform_device *pdev)
277 struct mdp_dev *mdp = platform_get_drvdata(pdev);
279 v4l2_device_unregister(&mdp->v4l2_dev);
281 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
284 static int __maybe_unused mdp_suspend(struct device *dev)
286 struct mdp_dev *mdp = dev_get_drvdata(dev);
289 atomic_set(&mdp->suspended, 1);
291 if (atomic_read(&mdp->job_count)) {
292 ret = wait_event_timeout(mdp->callback_wq,
293 !atomic_read(&mdp->job_count),
297 "%s:flushed cmdq task incomplete, count=%d\n",
298 __func__, atomic_read(&mdp->job_count));
306 static int __maybe_unused mdp_resume(struct device *dev)
308 struct mdp_dev *mdp = dev_get_drvdata(dev);
310 atomic_set(&mdp->suspended, 0);
315 static const struct dev_pm_ops mdp_pm_ops = {
316 SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume)
319 static struct platform_driver mdp_driver = {
321 .remove_new = mdp_remove,
323 .name = MDP_MODULE_NAME,
325 .of_match_table = mdp_of_ids,
329 module_platform_driver(mdp_driver);
331 MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>");
332 MODULE_DESCRIPTION("MediaTek image processor 3 driver");
333 MODULE_LICENSE("GPL");