FILE
mtk_mdp_core.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2015-2016 MediaTek Inc. 4 * Author: Houlong Wei <houlong.wei@mediatek.com> 5 * Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> 6 */ 7 8#include <linux/clk.h> 9#include <linux/device.h> 10#include <linux/errno.h> 11#include <linux/interrupt.h> 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/of_address.h> 16#include <linux/of_platform.h> 17#include <linux/platform_device.h> 18#include <linux/pm_runtime.h> 19#include <linux/workqueue.h> 20 21#include "mtk_mdp_core.h" 22#include "mtk_mdp_m2m.h" 23#include "mtk_vpu.h" 24 25/* MDP debug log level (0-3). 3 shows all the logs. */ 26int mtk_mdp_dbg_level; 27EXPORT_SYMBOL(mtk_mdp_dbg_level); 28 29module_param(mtk_mdp_dbg_level, int, 0644); 30 31static const struct of_device_id mtk_mdp_comp_dt_ids[] __maybe_unused = { 32 { 33 .compatible = "mediatek,mt8173-mdp-rdma", 34 .data = (void *)MTK_MDP_RDMA 35 }, { 36 .compatible = "mediatek,mt8173-mdp-rsz", 37 .data = (void *)MTK_MDP_RSZ 38 }, { 39 .compatible = "mediatek,mt8173-mdp-wdma", 40 .data = (void *)MTK_MDP_WDMA 41 }, { 42 .compatible = "mediatek,mt8173-mdp-wrot", 43 .data = (void *)MTK_MDP_WROT 44 }, 45 { }, 46}; 47 48static const struct of_device_id mtk_mdp_of_ids[] = { 49 { .compatible = "mediatek,mt8173-mdp", }, 50 { }, 51}; 52MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids); 53 54static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp) 55{ 56 struct device *dev = &mdp->pdev->dev; 57 struct mtk_mdp_comp *comp_node; 58 59 list_for_each_entry(comp_node, &mdp->comp_list, node) 60 mtk_mdp_comp_clock_on(dev, comp_node); 61} 62 63static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp) 64{ 65 struct device *dev = &mdp->pdev->dev; 66 struct mtk_mdp_comp *comp_node; 67 68 list_for_each_entry(comp_node, &mdp->comp_list, node) 69 mtk_mdp_comp_clock_off(dev, comp_node); 70} 71 72static void mtk_mdp_wdt_worker(struct work_struct *work) 73{ 74 struct mtk_mdp_dev *mdp = 75 container_of(work, struct mtk_mdp_dev, wdt_work); 76 struct mtk_mdp_ctx *ctx; 77 78 mtk_mdp_err("Watchdog timeout"); 79 80 list_for_each_entry(ctx, &mdp->ctx_list, list) { 81 mtk_mdp_dbg(0, "[%d] Change as state error", ctx->id); 82 mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_CTX_ERROR); 83 } 84} 85 86static void mtk_mdp_reset_handler(void *priv) 87{ 88 struct mtk_mdp_dev *mdp = priv; 89 90 queue_work(mdp->wdt_wq, &mdp->wdt_work); 91} 92 93void mtk_mdp_register_component(struct mtk_mdp_dev *mdp, 94 struct mtk_mdp_comp *comp) 95{ 96 list_add(&comp->node, &mdp->comp_list); 97} 98 99void mtk_mdp_unregister_component(struct mtk_mdp_dev *mdp, 100 struct mtk_mdp_comp *comp) 101{ 102 list_del(&comp->node); 103} 104 105static int mtk_mdp_probe(struct platform_device *pdev) 106{ 107 struct mtk_mdp_dev *mdp; 108 struct device *dev = &pdev->dev; 109 struct device_node *node, *parent; 110 struct mtk_mdp_comp *comp, *comp_temp; 111 int ret = 0; 112 113 mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL); 114 if (!mdp) 115 return -ENOMEM; 116 117 mdp->id = pdev->id; 118 mdp->pdev = pdev; 119 INIT_LIST_HEAD(&mdp->comp_list); 120 INIT_LIST_HEAD(&mdp->ctx_list); 121 122 mutex_init(&mdp->lock); 123 mutex_init(&mdp->vpulock); 124 125 /* Old dts had the components as child nodes */ 126 node = of_get_next_child(dev->of_node, NULL); 127 if (node) { 128 of_node_put(node); 129 parent = dev->of_node; 130 dev_warn(dev, "device tree is out of date\n"); 131 } else { 132 parent = dev->of_node->parent; 133 } 134 135 /* Iterate over sibling MDP function blocks */ 136 for_each_child_of_node(parent, node) { 137 const struct of_device_id *of_id; 138 enum mtk_mdp_comp_type comp_type; 139 140 of_id = of_match_node(mtk_mdp_comp_dt_ids, node); 141 if (!of_id) 142 continue; 143 144 if (!of_device_is_available(node)) { 145 dev_err(dev, "Skipping disabled component %pOF\n", 146 node); 147 continue; 148 } 149 150 comp_type = (uintptr_t)of_id->data; 151 152 comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); 153 if (!comp) { 154 ret = -ENOMEM; 155 of_node_put(node); 156 goto err_comp; 157 } 158 159 ret = mtk_mdp_comp_init(dev, node, comp, comp_type); 160 if (ret) { 161 of_node_put(node); 162 goto err_comp; 163 } 164 165 mtk_mdp_register_component(mdp, comp); 166 } 167 168 mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME); 169 if (!mdp->job_wq) { 170 dev_err(&pdev->dev, "unable to alloc job workqueue\n"); 171 ret = -ENOMEM; 172 goto err_alloc_job_wq; 173 } 174 175 mdp->wdt_wq = create_singlethread_workqueue("mdp_wdt_wq"); 176 if (!mdp->wdt_wq) { 177 dev_err(&pdev->dev, "unable to alloc wdt workqueue\n"); 178 ret = -ENOMEM; 179 goto err_alloc_wdt_wq; 180 } 181 INIT_WORK(&mdp->wdt_work, mtk_mdp_wdt_worker); 182 183 ret = v4l2_device_register(dev, &mdp->v4l2_dev); 184 if (ret) { 185 dev_err(&pdev->dev, "Failed to register v4l2 device\n"); 186 ret = -EINVAL; 187 goto err_dev_register; 188 } 189 190 ret = mtk_mdp_register_m2m_device(mdp); 191 if (ret) { 192 v4l2_err(&mdp->v4l2_dev, "Failed to init mem2mem device\n"); 193 goto err_m2m_register; 194 } 195 196 mdp->vpu_dev = vpu_get_plat_device(pdev); 197 if (!mdp->vpu_dev) { 198 dev_err(&pdev->dev, "Failed to get vpu device\n"); 199 ret = -ENODEV; 200 goto err_vpu_get_dev; 201 } 202 203 ret = vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp, 204 VPU_RST_MDP); 205 if (ret) { 206 dev_err(&pdev->dev, "Failed to register reset handler\n"); 207 goto err_reg_handler; 208 } 209 210 platform_set_drvdata(pdev, mdp); 211 212 ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); 213 if (ret) { 214 dev_err(&pdev->dev, "Failed to set vb2 dma mag seg size\n"); 215 goto err_reg_handler; 216 } 217 218 pm_runtime_enable(dev); 219 dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id); 220 221 return 0; 222 223err_reg_handler: 224 platform_device_put(mdp->vpu_dev); 225 226err_vpu_get_dev: 227 mtk_mdp_unregister_m2m_device(mdp); 228 229err_m2m_register: 230 v4l2_device_unregister(&mdp->v4l2_dev); 231 232err_dev_register: 233 destroy_workqueue(mdp->wdt_wq); 234 235err_alloc_wdt_wq: 236 destroy_workqueue(mdp->job_wq); 237 238err_alloc_job_wq: 239 240err_comp: 241 list_for_each_entry_safe(comp, comp_temp, &mdp->comp_list, node) { 242 mtk_mdp_unregister_component(mdp, comp); 243 mtk_mdp_comp_deinit(dev, comp); 244 } 245 246 dev_dbg(dev, "err %d\n", ret); 247 return ret; 248} 249 250static void mtk_mdp_remove(struct platform_device *pdev) 251{ 252 struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev); 253 struct mtk_mdp_comp *comp, *comp_temp; 254 255 pm_runtime_disable(&pdev->dev); 256 vb2_dma_contig_clear_max_seg_size(&pdev->dev); 257 platform_device_put(mdp->vpu_dev); 258 mtk_mdp_unregister_m2m_device(mdp); 259 v4l2_device_unregister(&mdp->v4l2_dev); 260 261 destroy_workqueue(mdp->wdt_wq); 262 263 destroy_workqueue(mdp->job_wq); 264 265 list_for_each_entry_safe(comp, comp_temp, &mdp->comp_list, node) { 266 mtk_mdp_unregister_component(mdp, comp); 267 mtk_mdp_comp_deinit(&pdev->dev, comp); 268 } 269 270 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); 271} 272 273static int __maybe_unused mtk_mdp_pm_suspend(struct device *dev) 274{ 275 struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); 276 277 mtk_mdp_clock_off(mdp); 278 279 return 0; 280} 281 282static int __maybe_unused mtk_mdp_pm_resume(struct device *dev) 283{ 284 struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); 285 286 mtk_mdp_clock_on(mdp); 287 288 return 0; 289} 290 291static int __maybe_unused mtk_mdp_suspend(struct device *dev) 292{ 293 if (pm_runtime_suspended(dev)) 294 return 0; 295 296 return mtk_mdp_pm_suspend(dev); 297} 298 299static int __maybe_unused mtk_mdp_resume(struct device *dev) 300{ 301 if (pm_runtime_suspended(dev)) 302 return 0; 303 304 return mtk_mdp_pm_resume(dev); 305} 306 307static const struct dev_pm_ops mtk_mdp_pm_ops = { 308 SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume) 309 SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL) 310}; 311 312static struct platform_driver mtk_mdp_driver = { 313 .probe = mtk_mdp_probe, 314 .remove = mtk_mdp_remove, 315 .driver = { 316 .name = MTK_MDP_MODULE_NAME, 317 .pm = &mtk_mdp_pm_ops, 318 .of_match_table = mtk_mdp_of_ids, 319 } 320}; 321 322module_platform_driver(mtk_mdp_driver); 323 324MODULE_AUTHOR("Houlong Wei <houlong.wei@mediatek.com>"); 325MODULE_DESCRIPTION("Mediatek image processor driver"); 326MODULE_LICENSE("GPL v2");
~/
Read-only file preview.