brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · 81a0d3b Raw
551 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NVIDIA Tegra Video decoder driver4 *5 * Copyright (C) 2016-2017 Dmitry Osipenko <digetx@gmail.com>6 *7 */8 9#include <linux/clk.h>10#include <linux/dma-buf.h>11#include <linux/genalloc.h>12#include <linux/interrupt.h>13#include <linux/list.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/platform_device.h>17#include <linux/pm_runtime.h>18#include <linux/reset.h>19#include <linux/slab.h>20#include <linux/uaccess.h>21 22#include <soc/tegra/common.h>23#include <soc/tegra/pmc.h>24 25#include "vde.h"26 27#define CREATE_TRACE_POINTS28#include "trace.h"29 30void tegra_vde_writel(struct tegra_vde *vde, u32 value,31		      void __iomem *base, u32 offset)32{33	trace_vde_writel(vde, base, offset, value);34 35	writel_relaxed(value, base + offset);36}37 38u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset)39{40	u32 value = readl_relaxed(base + offset);41 42	trace_vde_readl(vde, base, offset, value);43 44	return value;45}46 47void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask,48			void __iomem *base, u32 offset)49{50	u32 value = tegra_vde_readl(vde, base, offset);51 52	tegra_vde_writel(vde, value | mask, base, offset);53}54 55int tegra_vde_alloc_bo(struct tegra_vde *vde,56		       struct tegra_vde_bo **ret_bo,57		       enum dma_data_direction dma_dir,58		       size_t size)59{60	struct device *dev = vde->dev;61	struct tegra_vde_bo *bo;62	int err;63 64	bo = kzalloc(sizeof(*bo), GFP_KERNEL);65	if (!bo)66		return -ENOMEM;67 68	bo->vde = vde;69	bo->size = size;70	bo->dma_dir = dma_dir;71	bo->dma_attrs = DMA_ATTR_WRITE_COMBINE |72			DMA_ATTR_NO_KERNEL_MAPPING;73 74	if (!vde->domain)75		bo->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;76 77	bo->dma_cookie = dma_alloc_attrs(dev, bo->size, &bo->dma_handle,78					 GFP_KERNEL, bo->dma_attrs);79	if (!bo->dma_cookie) {80		dev_err(dev, "Failed to allocate DMA buffer of size: %zu\n",81			bo->size);82		err = -ENOMEM;83		goto free_bo;84	}85 86	err = dma_get_sgtable_attrs(dev, &bo->sgt, bo->dma_cookie,87				    bo->dma_handle, bo->size, bo->dma_attrs);88	if (err) {89		dev_err(dev, "Failed to get DMA buffer SG table: %d\n", err);90		goto free_attrs;91	}92 93	err = dma_map_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs);94	if (err) {95		dev_err(dev, "Failed to map DMA buffer SG table: %d\n", err);96		goto free_table;97	}98 99	if (vde->domain) {100		err = tegra_vde_iommu_map(vde, &bo->sgt, &bo->iova, bo->size);101		if (err) {102			dev_err(dev, "Failed to map DMA buffer IOVA: %d\n", err);103			goto unmap_sgtable;104		}105 106		bo->dma_addr = iova_dma_addr(&vde->iova, bo->iova);107	} else {108		bo->dma_addr = sg_dma_address(bo->sgt.sgl);109	}110 111	*ret_bo = bo;112 113	return 0;114 115unmap_sgtable:116	dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs);117free_table:118	sg_free_table(&bo->sgt);119free_attrs:120	dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle,121		       bo->dma_attrs);122free_bo:123	kfree(bo);124 125	return err;126}127 128void tegra_vde_free_bo(struct tegra_vde_bo *bo)129{130	struct tegra_vde *vde = bo->vde;131	struct device *dev = vde->dev;132 133	if (vde->domain)134		tegra_vde_iommu_unmap(vde, bo->iova);135 136	dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs);137 138	sg_free_table(&bo->sgt);139 140	dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle,141		       bo->dma_attrs);142	kfree(bo);143}144 145static irqreturn_t tegra_vde_isr(int irq, void *data)146{147	struct tegra_vde *vde = data;148 149	if (completion_done(&vde->decode_completion))150		return IRQ_NONE;151 152	tegra_vde_set_bits(vde, 0, vde->frameid, 0x208);153	complete(&vde->decode_completion);154 155	return IRQ_HANDLED;156}157 158static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev)159{160	struct tegra_vde *vde = dev_get_drvdata(dev);161	int err;162 163	if (!dev->pm_domain) {164		err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC);165		if (err) {166			dev_err(dev, "Failed to power down HW: %d\n", err);167			return err;168		}169	}170 171	clk_disable_unprepare(vde->clk);172	reset_control_release(vde->rst);173	reset_control_release(vde->rst_mc);174 175	return 0;176}177 178static __maybe_unused int tegra_vde_runtime_resume(struct device *dev)179{180	struct tegra_vde *vde = dev_get_drvdata(dev);181	int err;182 183	err = reset_control_acquire(vde->rst_mc);184	if (err) {185		dev_err(dev, "Failed to acquire mc reset: %d\n", err);186		return err;187	}188 189	err = reset_control_acquire(vde->rst);190	if (err) {191		dev_err(dev, "Failed to acquire reset: %d\n", err);192		goto release_mc_reset;193	}194 195	if (!dev->pm_domain) {196		err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC,197							vde->clk, vde->rst);198		if (err) {199			dev_err(dev, "Failed to power up HW : %d\n", err);200			goto release_reset;201		}202	} else {203		/*204		 * tegra_powergate_sequence_power_up() leaves clocks enabled,205		 * while GENPD not.206		 */207		err = clk_prepare_enable(vde->clk);208		if (err) {209			dev_err(dev, "Failed to enable clock: %d\n", err);210			goto release_reset;211		}212	}213 214	return 0;215 216release_reset:217	reset_control_release(vde->rst);218release_mc_reset:219	reset_control_release(vde->rst_mc);220 221	return err;222}223 224static int tegra_vde_probe(struct platform_device *pdev)225{226	struct device *dev = &pdev->dev;227	struct tegra_vde *vde;228	int irq, err;229 230	vde = devm_kzalloc(dev, sizeof(*vde), GFP_KERNEL);231	if (!vde)232		return -ENOMEM;233 234	platform_set_drvdata(pdev, vde);235 236	vde->soc = of_device_get_match_data(&pdev->dev);237	vde->dev = dev;238 239	vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe");240	if (IS_ERR(vde->sxe))241		return PTR_ERR(vde->sxe);242 243	vde->bsev = devm_platform_ioremap_resource_byname(pdev, "bsev");244	if (IS_ERR(vde->bsev))245		return PTR_ERR(vde->bsev);246 247	vde->mbe = devm_platform_ioremap_resource_byname(pdev, "mbe");248	if (IS_ERR(vde->mbe))249		return PTR_ERR(vde->mbe);250 251	vde->ppe = devm_platform_ioremap_resource_byname(pdev, "ppe");252	if (IS_ERR(vde->ppe))253		return PTR_ERR(vde->ppe);254 255	vde->mce = devm_platform_ioremap_resource_byname(pdev, "mce");256	if (IS_ERR(vde->mce))257		return PTR_ERR(vde->mce);258 259	vde->tfe = devm_platform_ioremap_resource_byname(pdev, "tfe");260	if (IS_ERR(vde->tfe))261		return PTR_ERR(vde->tfe);262 263	vde->ppb = devm_platform_ioremap_resource_byname(pdev, "ppb");264	if (IS_ERR(vde->ppb))265		return PTR_ERR(vde->ppb);266 267	vde->vdma = devm_platform_ioremap_resource_byname(pdev, "vdma");268	if (IS_ERR(vde->vdma))269		return PTR_ERR(vde->vdma);270 271	vde->frameid = devm_platform_ioremap_resource_byname(pdev, "frameid");272	if (IS_ERR(vde->frameid))273		return PTR_ERR(vde->frameid);274 275	vde->clk = devm_clk_get(dev, NULL);276	if (IS_ERR(vde->clk)) {277		err = PTR_ERR(vde->clk);278		dev_err(dev, "Could not get VDE clk %d\n", err);279		return err;280	}281 282	vde->rst = devm_reset_control_get_exclusive_released(dev, NULL);283	if (IS_ERR(vde->rst)) {284		err = PTR_ERR(vde->rst);285		dev_err(dev, "Could not get VDE reset %d\n", err);286		return err;287	}288 289	vde->rst_mc = devm_reset_control_get_optional_exclusive_released(dev, "mc");290	if (IS_ERR(vde->rst_mc)) {291		err = PTR_ERR(vde->rst_mc);292		dev_err(dev, "Could not get MC reset %d\n", err);293		return err;294	}295 296	irq = platform_get_irq_byname(pdev, "sync-token");297	if (irq < 0)298		return irq;299 300	err = devm_request_irq(dev, irq, tegra_vde_isr, 0,301			       dev_name(dev), vde);302	if (err) {303		dev_err(dev, "Could not request IRQ %d\n", err);304		return err;305	}306 307	err = devm_tegra_core_dev_init_opp_table_common(dev);308	if (err) {309		dev_err(dev, "Could initialize OPP table %d\n", err);310		return err;311	}312 313	vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0);314	if (!vde->iram_pool) {315		dev_err(dev, "Could not get IRAM pool\n");316		return -EPROBE_DEFER;317	}318 319	vde->iram = gen_pool_dma_alloc(vde->iram_pool,320				       gen_pool_size(vde->iram_pool),321				       &vde->iram_lists_addr);322	if (!vde->iram) {323		dev_err(dev, "Could not reserve IRAM\n");324		return -ENOMEM;325	}326 327	INIT_LIST_HEAD(&vde->map_list);328	mutex_init(&vde->map_lock);329	mutex_init(&vde->lock);330	init_completion(&vde->decode_completion);331 332	err = tegra_vde_iommu_init(vde);333	if (err) {334		dev_err(dev, "Failed to initialize IOMMU: %d\n", err);335		goto err_gen_free;336	}337 338	pm_runtime_enable(dev);339	pm_runtime_use_autosuspend(dev);340	pm_runtime_set_autosuspend_delay(dev, 300);341 342	/*343	 * VDE partition may be left ON after bootloader, hence let's344	 * power-cycle it in order to put hardware into a predictable lower345	 * power state.346	 */347	err = pm_runtime_resume_and_get(dev);348	if (err)349		goto err_pm_runtime;350 351	pm_runtime_put(dev);352 353	err = tegra_vde_alloc_bo(vde, &vde->secure_bo, DMA_FROM_DEVICE, 4096);354	if (err) {355		dev_err(dev, "Failed to allocate secure BO: %d\n", err);356		goto err_pm_runtime;357	}358 359	err = tegra_vde_v4l2_init(vde);360	if (err) {361		dev_err(dev, "Failed to initialize V4L2: %d\n", err);362		goto err_free_secure_bo;363	}364 365	return 0;366 367err_free_secure_bo:368	tegra_vde_free_bo(vde->secure_bo);369err_pm_runtime:370	pm_runtime_dont_use_autosuspend(dev);371	pm_runtime_disable(dev);372 373	tegra_vde_iommu_deinit(vde);374 375err_gen_free:376	gen_pool_free(vde->iram_pool, (unsigned long)vde->iram,377		      gen_pool_size(vde->iram_pool));378 379	return err;380}381 382static void tegra_vde_remove(struct platform_device *pdev)383{384	struct tegra_vde *vde = platform_get_drvdata(pdev);385	struct device *dev = &pdev->dev;386 387	tegra_vde_v4l2_deinit(vde);388	tegra_vde_free_bo(vde->secure_bo);389 390	/*391	 * As it increments RPM usage_count even on errors, we don't need to392	 * check the returned code here.393	 */394	pm_runtime_get_sync(dev);395 396	pm_runtime_dont_use_autosuspend(dev);397	pm_runtime_disable(dev);398 399	/*400	 * Balance RPM state, the VDE power domain is left ON and hardware401	 * is clock-gated. It's safe to reboot machine now.402	 */403	pm_runtime_put_noidle(dev);404	clk_disable_unprepare(vde->clk);405 406	tegra_vde_dmabuf_cache_unmap_all(vde);407	tegra_vde_iommu_deinit(vde);408 409	gen_pool_free(vde->iram_pool, (unsigned long)vde->iram,410		      gen_pool_size(vde->iram_pool));411}412 413static void tegra_vde_shutdown(struct platform_device *pdev)414{415	/*416	 * On some devices bootloader isn't ready to a power-gated VDE on417	 * a warm-reboot, machine will hang in that case.418	 */419	pm_runtime_get_sync(&pdev->dev);420}421 422static __maybe_unused int tegra_vde_pm_suspend(struct device *dev)423{424	struct tegra_vde *vde = dev_get_drvdata(dev);425	int err;426 427	mutex_lock(&vde->lock);428 429	err = pm_runtime_force_suspend(dev);430	if (err < 0)431		return err;432 433	return 0;434}435 436static __maybe_unused int tegra_vde_pm_resume(struct device *dev)437{438	struct tegra_vde *vde = dev_get_drvdata(dev);439	int err;440 441	err = pm_runtime_force_resume(dev);442	if (err < 0)443		return err;444 445	mutex_unlock(&vde->lock);446 447	return 0;448}449 450static const struct dev_pm_ops tegra_vde_pm_ops = {451	SET_RUNTIME_PM_OPS(tegra_vde_runtime_suspend,452			   tegra_vde_runtime_resume,453			   NULL)454	SET_SYSTEM_SLEEP_PM_OPS(tegra_vde_pm_suspend,455				tegra_vde_pm_resume)456};457 458static const u32 tegra124_decoded_fmts[] = {459	/* TBD: T124 supports only a non-standard Tegra tiled format */460};461 462static const struct tegra_coded_fmt_desc tegra124_coded_fmts[] = {463	{464		.fourcc = V4L2_PIX_FMT_H264_SLICE,465		.frmsize = {466			.min_width = 16,467			.max_width = 1920,468			.step_width = 16,469			.min_height = 16,470			.max_height = 2032,471			.step_height = 16,472		},473		.num_decoded_fmts = ARRAY_SIZE(tegra124_decoded_fmts),474		.decoded_fmts = tegra124_decoded_fmts,475		.decode_run = tegra_vde_h264_decode_run,476		.decode_wait = tegra_vde_h264_decode_wait,477	},478};479 480static const u32 tegra20_decoded_fmts[] = {481	V4L2_PIX_FMT_YUV420M,482	V4L2_PIX_FMT_YVU420M,483};484 485static const struct tegra_coded_fmt_desc tegra20_coded_fmts[] = {486	{487		.fourcc = V4L2_PIX_FMT_H264_SLICE,488		.frmsize = {489			.min_width = 16,490			.max_width = 1920,491			.step_width = 16,492			.min_height = 16,493			.max_height = 2032,494			.step_height = 16,495		},496		.num_decoded_fmts = ARRAY_SIZE(tegra20_decoded_fmts),497		.decoded_fmts = tegra20_decoded_fmts,498		.decode_run = tegra_vde_h264_decode_run,499		.decode_wait = tegra_vde_h264_decode_wait,500	},501};502 503static const struct tegra_vde_soc tegra124_vde_soc = {504	.supports_ref_pic_marking = true,505	.coded_fmts = tegra124_coded_fmts,506	.num_coded_fmts = ARRAY_SIZE(tegra124_coded_fmts),507};508 509static const struct tegra_vde_soc tegra114_vde_soc = {510	.supports_ref_pic_marking = true,511	.coded_fmts = tegra20_coded_fmts,512	.num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts),513};514 515static const struct tegra_vde_soc tegra30_vde_soc = {516	.supports_ref_pic_marking = false,517	.coded_fmts = tegra20_coded_fmts,518	.num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts),519};520 521static const struct tegra_vde_soc tegra20_vde_soc = {522	.supports_ref_pic_marking = false,523	.coded_fmts = tegra20_coded_fmts,524	.num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts),525};526 527static const struct of_device_id tegra_vde_of_match[] = {528	{ .compatible = "nvidia,tegra124-vde", .data = &tegra124_vde_soc },529	{ .compatible = "nvidia,tegra114-vde", .data = &tegra114_vde_soc },530	{ .compatible = "nvidia,tegra30-vde", .data = &tegra30_vde_soc },531	{ .compatible = "nvidia,tegra20-vde", .data = &tegra20_vde_soc },532	{ },533};534MODULE_DEVICE_TABLE(of, tegra_vde_of_match);535 536static struct platform_driver tegra_vde_driver = {537	.probe		= tegra_vde_probe,538	.remove_new	= tegra_vde_remove,539	.shutdown	= tegra_vde_shutdown,540	.driver		= {541		.name		= "tegra-vde",542		.of_match_table = tegra_vde_of_match,543		.pm		= &tegra_vde_pm_ops,544	},545};546module_platform_driver(tegra_vde_driver);547 548MODULE_DESCRIPTION("NVIDIA Tegra Video Decoder driver");549MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");550MODULE_LICENSE("GPL");551