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. */ 26 int mtk_mdp_dbg_level; 27 EXPORT_SYMBOL(mtk_mdp_dbg_level); 28 29 module_param(mtk_mdp_dbg_level, int, 0644); 30 31 static const struct of_device_id mtk_mdp_comp_dt_ids[] = { 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 48 static const struct of_device_id mtk_mdp_of_ids[] = { 49 { .compatible = "mediatek,mt8173-mdp", }, 50 { }, 51 }; 52 MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids); 53 54 static 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 63 static 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 72 static 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 86 static 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 93 void 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 99 void mtk_mdp_unregister_component(struct mtk_mdp_dev *mdp, 100 struct mtk_mdp_comp *comp) 101 { 102 list_del(&comp->node); 103 } 104 105 static 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 ret = vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp, 198 VPU_RST_MDP); 199 if (ret) { 200 dev_err(&pdev->dev, "Failed to register reset handler\n"); 201 goto err_m2m_register; 202 } 203 204 platform_set_drvdata(pdev, mdp); 205 206 ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); 207 if (ret) { 208 dev_err(&pdev->dev, "Failed to set vb2 dma mag seg size\n"); 209 goto err_m2m_register; 210 } 211 212 pm_runtime_enable(dev); 213 dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id); 214 215 return 0; 216 217 err_m2m_register: 218 v4l2_device_unregister(&mdp->v4l2_dev); 219 220 err_dev_register: 221 destroy_workqueue(mdp->wdt_wq); 222 223 err_alloc_wdt_wq: 224 destroy_workqueue(mdp->job_wq); 225 226 err_alloc_job_wq: 227 228 err_comp: 229 list_for_each_entry_safe(comp, comp_temp, &mdp->comp_list, node) { 230 mtk_mdp_unregister_component(mdp, comp); 231 mtk_mdp_comp_deinit(dev, comp); 232 } 233 234 dev_dbg(dev, "err %d\n", ret); 235 return ret; 236 } 237 238 static int mtk_mdp_remove(struct platform_device *pdev) 239 { 240 struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev); 241 struct mtk_mdp_comp *comp, *comp_temp; 242 243 pm_runtime_disable(&pdev->dev); 244 vb2_dma_contig_clear_max_seg_size(&pdev->dev); 245 mtk_mdp_unregister_m2m_device(mdp); 246 v4l2_device_unregister(&mdp->v4l2_dev); 247 248 destroy_workqueue(mdp->wdt_wq); 249 250 destroy_workqueue(mdp->job_wq); 251 252 list_for_each_entry_safe(comp, comp_temp, &mdp->comp_list, node) { 253 mtk_mdp_unregister_component(mdp, comp); 254 mtk_mdp_comp_deinit(&pdev->dev, comp); 255 } 256 257 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); 258 return 0; 259 } 260 261 static int __maybe_unused mtk_mdp_pm_suspend(struct device *dev) 262 { 263 struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); 264 265 mtk_mdp_clock_off(mdp); 266 267 return 0; 268 } 269 270 static int __maybe_unused mtk_mdp_pm_resume(struct device *dev) 271 { 272 struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); 273 274 mtk_mdp_clock_on(mdp); 275 276 return 0; 277 } 278 279 static int __maybe_unused mtk_mdp_suspend(struct device *dev) 280 { 281 if (pm_runtime_suspended(dev)) 282 return 0; 283 284 return mtk_mdp_pm_suspend(dev); 285 } 286 287 static int __maybe_unused mtk_mdp_resume(struct device *dev) 288 { 289 if (pm_runtime_suspended(dev)) 290 return 0; 291 292 return mtk_mdp_pm_resume(dev); 293 } 294 295 static const struct dev_pm_ops mtk_mdp_pm_ops = { 296 SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume) 297 SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL) 298 }; 299 300 static struct platform_driver mtk_mdp_driver = { 301 .probe = mtk_mdp_probe, 302 .remove = mtk_mdp_remove, 303 .driver = { 304 .name = MTK_MDP_MODULE_NAME, 305 .pm = &mtk_mdp_pm_ops, 306 .of_match_table = mtk_mdp_of_ids, 307 } 308 }; 309 310 module_platform_driver(mtk_mdp_driver); 311 312 MODULE_AUTHOR("Houlong Wei <houlong.wei@mediatek.com>"); 313 MODULE_DESCRIPTION("Mediatek image processor driver"); 314 MODULE_LICENSE("GPL v2"); 315