brintos

brintos / linux-shallow public Read only

0
0
Text · 9.6 KiB · 37e7b98 Raw
429 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 20static const struct of_device_id mdp_of_ids[] = {21	{ .compatible = "mediatek,mt8183-mdp3-rdma",22	  .data = &mt8183_mdp_driver_data,23	},24	{ .compatible = "mediatek,mt8188-mdp3-rdma",25	  .data = &mt8188_mdp_driver_data,26	},27	{ .compatible = "mediatek,mt8195-mdp3-rdma",28	  .data = &mt8195_mdp_driver_data,29	},30	{ .compatible = "mediatek,mt8195-mdp3-wrot",31	  .data = &mt8195_mdp_driver_data,32	},33	{},34};35MODULE_DEVICE_TABLE(of, mdp_of_ids);36 37static struct platform_device *__get_pdev_by_id(struct platform_device *pdev,38						struct platform_device *from,39						enum mdp_infra_id id)40{41	struct device_node *node, *f = NULL;42	struct platform_device *mdp_pdev = NULL;43	const struct mtk_mdp_driver_data *mdp_data;44	const char *compat;45 46	if (!pdev)47		return NULL;48 49	if (id < MDP_INFRA_MMSYS || id >= MDP_INFRA_MAX) {50		dev_err(&pdev->dev, "Illegal infra id %d\n", id);51		return NULL;52	}53 54	mdp_data = of_device_get_match_data(&pdev->dev);55	if (!mdp_data) {56		dev_err(&pdev->dev, "have no driver data to find node\n");57		return NULL;58	}59 60	compat = mdp_data->mdp_probe_infra[id].compatible;61	if (strlen(compat) == 0)62		return NULL;63 64	if (from)65		f = from->dev.of_node;66	node = of_find_compatible_node(f, NULL, compat);67	if (WARN_ON(!node)) {68		dev_err(&pdev->dev, "find node from id %d failed\n", id);69		return NULL;70	}71 72	mdp_pdev = of_find_device_by_node(node);73	of_node_put(node);74	if (WARN_ON(!mdp_pdev)) {75		dev_err(&pdev->dev, "find pdev from id %d failed\n", id);76		return NULL;77	}78 79	return mdp_pdev;80}81 82struct platform_device *mdp_get_plat_device(struct platform_device *pdev)83{84	struct device *dev = &pdev->dev;85	struct device_node *mdp_node;86	struct platform_device *mdp_pdev;87 88	mdp_node = of_parse_phandle(dev->of_node, MDP_PHANDLE_NAME, 0);89	if (!mdp_node) {90		dev_err(dev, "can't get node %s\n", MDP_PHANDLE_NAME);91		return NULL;92	}93 94	mdp_pdev = of_find_device_by_node(mdp_node);95	of_node_put(mdp_node);96 97	return mdp_pdev;98}99EXPORT_SYMBOL_GPL(mdp_get_plat_device);100 101int mdp_vpu_get_locked(struct mdp_dev *mdp)102{103	int ret = 0;104 105	if (mdp->vpu_count++ == 0) {106		ret = rproc_boot(mdp->rproc_handle);107		if (ret) {108			dev_err(&mdp->pdev->dev,109				"vpu_load_firmware failed %d\n", ret);110			goto err_load_vpu;111		}112		ret = mdp_vpu_register(mdp);113		if (ret) {114			dev_err(&mdp->pdev->dev,115				"mdp_vpu register failed %d\n", ret);116			goto err_reg_vpu;117		}118		ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock);119		if (ret) {120			dev_err(&mdp->pdev->dev,121				"mdp_vpu device init failed %d\n", ret);122			goto err_init_vpu;123		}124	}125	return 0;126 127err_init_vpu:128	mdp_vpu_unregister(mdp);129err_reg_vpu:130err_load_vpu:131	mdp->vpu_count--;132	return ret;133}134 135void mdp_vpu_put_locked(struct mdp_dev *mdp)136{137	if (--mdp->vpu_count == 0) {138		mdp_vpu_dev_deinit(&mdp->vpu);139		mdp_vpu_unregister(mdp);140	}141}142 143void mdp_video_device_release(struct video_device *vdev)144{145	struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev);146	int i;147 148	for (i = 0; i < mdp->mdp_data->pp_used; i++)149		if (mdp->cmdq_clt[i])150			cmdq_mbox_destroy(mdp->cmdq_clt[i]);151 152	scp_put(mdp->scp);153 154	destroy_workqueue(mdp->job_wq);155	destroy_workqueue(mdp->clock_wq);156 157	pm_runtime_disable(&mdp->pdev->dev);158 159	vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev);160 161	mdp_comp_destroy(mdp);162	for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) {163		enum mdp_mm_subsys_id idx;164		struct mtk_mutex *m;165		u32 m_id;166 167		idx = mdp->mdp_data->pipe_info[i].sub_id;168		m_id = mdp->mdp_data->pipe_info[i].mutex_id;169		m = mdp->mm_subsys[idx].mdp_mutex[m_id];170		if (!IS_ERR_OR_NULL(m))171			mtk_mutex_put(m);172	}173 174	mdp_vpu_shared_mem_free(&mdp->vpu);175	v4l2_m2m_release(mdp->m2m_dev);176	kfree(mdp);177}178 179static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id)180{181	struct platform_device *mm_pdev = NULL;182	struct device **dev;183	int i;184 185	if (!mdp)186		return -EINVAL;187 188	for (i = 0; i < MDP_MM_SUBSYS_MAX; i++) {189		const char *compat;190		enum mdp_infra_id sub_id = id + i;191 192		switch (id) {193		case MDP_INFRA_MMSYS:194			dev = &mdp->mm_subsys[i].mmsys;195			break;196		case MDP_INFRA_MUTEX:197			dev = &mdp->mm_subsys[i].mutex;198			break;199		default:200			dev_err(&mdp->pdev->dev, "Unknown infra id %d", id);201			return -EINVAL;202		}203 204		/*205		 * Not every chip has multiple multimedia subsystems, so206		 * the config may be null.207		 */208		compat = mdp->mdp_data->mdp_probe_infra[sub_id].compatible;209		if (strlen(compat) == 0)210			continue;211 212		mm_pdev = __get_pdev_by_id(mdp->pdev, mm_pdev, sub_id);213		if (WARN_ON(!mm_pdev))214			return -ENODEV;215 216		*dev = &mm_pdev->dev;217	}218 219	return 0;220}221 222static int mdp_probe(struct platform_device *pdev)223{224	struct device *dev = &pdev->dev;225	struct mdp_dev *mdp;226	struct platform_device *mm_pdev;227	struct resource *res;228	int ret, i, mutex_id;229 230	mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);231	if (!mdp) {232		ret = -ENOMEM;233		goto err_return;234	}235 236	mdp->pdev = pdev;237	mdp->mdp_data = of_device_get_match_data(&pdev->dev);238 239	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);240	if (res->start != mdp->mdp_data->mdp_con_res) {241		platform_set_drvdata(pdev, mdp);242		goto success_return;243	}244 245	ret = mdp_mm_subsys_deploy(mdp, MDP_INFRA_MMSYS);246	if (ret)247		goto err_destroy_device;248 249	ret = mdp_mm_subsys_deploy(mdp, MDP_INFRA_MUTEX);250	if (ret)251		goto err_destroy_device;252 253	for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) {254		enum mdp_mm_subsys_id idx;255		struct mtk_mutex **m;256 257		idx = mdp->mdp_data->pipe_info[i].sub_id;258		mutex_id = mdp->mdp_data->pipe_info[i].mutex_id;259		m = &mdp->mm_subsys[idx].mdp_mutex[mutex_id];260 261		if (!IS_ERR_OR_NULL(*m))262			continue;263 264		*m = mtk_mutex_get(mdp->mm_subsys[idx].mutex);265		if (IS_ERR(*m)) {266			ret = PTR_ERR(*m);267			goto err_free_mutex;268		}269	}270 271	ret = mdp_comp_config(mdp);272	if (ret) {273		dev_err(dev, "Failed to config mdp components\n");274		goto err_free_mutex;275	}276 277	mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);278	if (!mdp->job_wq) {279		dev_err(dev, "Unable to create job workqueue\n");280		ret = -ENOMEM;281		goto err_deinit_comp;282	}283 284	mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE,285					0);286	if (!mdp->clock_wq) {287		dev_err(dev, "Unable to create clock workqueue\n");288		ret = -ENOMEM;289		goto err_destroy_job_wq;290	}291 292	mdp->scp = scp_get(pdev);293	if (!mdp->scp) {294		mm_pdev = __get_pdev_by_id(pdev, NULL, MDP_INFRA_SCP);295		if (WARN_ON(!mm_pdev)) {296			dev_err(&pdev->dev, "Could not get scp device\n");297			ret = -ENODEV;298			goto err_destroy_clock_wq;299		}300		mdp->scp = platform_get_drvdata(mm_pdev);301	}302 303	mdp->rproc_handle = scp_get_rproc(mdp->scp);304	dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle);305 306	mutex_init(&mdp->vpu_lock);307	mutex_init(&mdp->m2m_lock);308 309	for (i = 0; i < mdp->mdp_data->pp_used; i++) {310		mdp->cmdq_clt[i] = cmdq_mbox_create(dev, i);311		if (IS_ERR(mdp->cmdq_clt[i])) {312			ret = PTR_ERR(mdp->cmdq_clt[i]);313			goto err_mbox_destroy;314		}315	}316 317	init_waitqueue_head(&mdp->callback_wq);318	ida_init(&mdp->mdp_ida);319	platform_set_drvdata(pdev, mdp);320 321	vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));322 323	ret = v4l2_device_register(dev, &mdp->v4l2_dev);324	if (ret) {325		dev_err(dev, "Failed to register v4l2 device\n");326		ret = -EINVAL;327		goto err_mbox_destroy;328	}329 330	ret = mdp_m2m_device_register(mdp);331	if (ret) {332		v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n");333		goto err_unregister_device;334	}335 336success_return:337	dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id);338	return 0;339 340err_unregister_device:341	v4l2_device_unregister(&mdp->v4l2_dev);342err_mbox_destroy:343	while (--i >= 0)344		cmdq_mbox_destroy(mdp->cmdq_clt[i]);345	scp_put(mdp->scp);346err_destroy_clock_wq:347	destroy_workqueue(mdp->clock_wq);348err_destroy_job_wq:349	destroy_workqueue(mdp->job_wq);350err_deinit_comp:351	mdp_comp_destroy(mdp);352err_free_mutex:353	for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) {354		enum mdp_mm_subsys_id idx;355		struct mtk_mutex *m;356 357		idx = mdp->mdp_data->pipe_info[i].sub_id;358		mutex_id = mdp->mdp_data->pipe_info[i].mutex_id;359		m = mdp->mm_subsys[idx].mdp_mutex[mutex_id];360		if (!IS_ERR_OR_NULL(m))361			mtk_mutex_put(m);362	}363err_destroy_device:364	kfree(mdp);365err_return:366	dev_dbg(dev, "Errno %d\n", ret);367	return ret;368}369 370static void mdp_remove(struct platform_device *pdev)371{372	struct mdp_dev *mdp = platform_get_drvdata(pdev);373 374	v4l2_device_unregister(&mdp->v4l2_dev);375 376	dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);377}378 379static int __maybe_unused mdp_suspend(struct device *dev)380{381	struct mdp_dev *mdp = dev_get_drvdata(dev);382	int ret;383 384	atomic_set(&mdp->suspended, 1);385 386	if (refcount_read(&mdp->job_count)) {387		ret = wait_event_timeout(mdp->callback_wq,388					 !refcount_read(&mdp->job_count),389					 2 * HZ);390		if (ret == 0) {391			dev_err(dev,392				"%s:flushed cmdq task incomplete, count=%d\n",393				__func__, refcount_read(&mdp->job_count));394			return -EBUSY;395		}396	}397 398	return 0;399}400 401static int __maybe_unused mdp_resume(struct device *dev)402{403	struct mdp_dev *mdp = dev_get_drvdata(dev);404 405	atomic_set(&mdp->suspended, 0);406 407	return 0;408}409 410static const struct dev_pm_ops mdp_pm_ops = {411	SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume)412};413 414static struct platform_driver mdp_driver = {415	.probe		= mdp_probe,416	.remove_new	= mdp_remove,417	.driver = {418		.name	= MDP_MODULE_NAME,419		.pm	= &mdp_pm_ops,420		.of_match_table = mdp_of_ids,421	},422};423 424module_platform_driver(mdp_driver);425 426MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>");427MODULE_DESCRIPTION("MediaTek image processor 3 driver");428MODULE_LICENSE("GPL");429