media: staging: tegra-vde: Support reference picture marking

Tegra114 and Tegra124 support reference picture marking, which will
cause BSEV to write picture marking data to SDRAM. Make sure there is
a valid destination address for that data to avoid error messages from
the memory controller.

[digetx@gmail.com: added BO support and moved secure BO allocation to kernel]
Tested-by: Anton Bambura <jenneron@protonmail.com> # T114 ASUS TF701T
Signed-off-by: Thierry Reding <treding@nvidia.com>
Co-developed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Thierry Reding 2021-11-14 23:47:30 +01:00 committed by Mauro Carvalho Chehab
parent 41479adb5e
commit aee3c14363
2 changed files with 141 additions and 1 deletions

View file

@ -84,6 +84,96 @@ static int tegra_vde_wait_mbe(struct tegra_vde *vde)
(tmp >= 0x10), 1, 100);
}
static int tegra_vde_alloc_bo(struct tegra_vde *vde,
struct tegra_vde_bo **ret_bo,
enum dma_data_direction dma_dir,
size_t size)
{
struct device *dev = vde->miscdev.parent;
struct tegra_vde_bo *bo;
int err;
bo = kzalloc(sizeof(*bo), GFP_KERNEL);
if (!bo)
return -ENOMEM;
bo->vde = vde;
bo->size = size;
bo->dma_dir = dma_dir;
bo->dma_attrs = DMA_ATTR_WRITE_COMBINE |
DMA_ATTR_NO_KERNEL_MAPPING;
if (!vde->domain)
bo->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS;
bo->dma_cookie = dma_alloc_attrs(dev, bo->size, &bo->dma_handle,
GFP_KERNEL, bo->dma_attrs);
if (!bo->dma_cookie) {
dev_err(dev, "Failed to allocate DMA buffer of size: %zu\n",
bo->size);
err = -ENOMEM;
goto free_bo;
}
err = dma_get_sgtable_attrs(dev, &bo->sgt, bo->dma_cookie,
bo->dma_handle, bo->size, bo->dma_attrs);
if (err) {
dev_err(dev, "Failed to get DMA buffer SG table: %d\n", err);
goto free_attrs;
}
err = dma_map_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs);
if (err) {
dev_err(dev, "Failed to map DMA buffer SG table: %d\n", err);
goto free_table;
}
if (vde->domain) {
err = tegra_vde_iommu_map(vde, &bo->sgt, &bo->iova, bo->size);
if (err) {
dev_err(dev, "Failed to map DMA buffer IOVA: %d\n", err);
goto unmap_sgtable;
}
bo->dma_addr = iova_dma_addr(&vde->iova, bo->iova);
} else {
bo->dma_addr = sg_dma_address(bo->sgt.sgl);
}
*ret_bo = bo;
return 0;
unmap_sgtable:
dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs);
free_table:
sg_free_table(&bo->sgt);
free_attrs:
dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle,
bo->dma_attrs);
free_bo:
kfree(bo);
return err;
}
static void tegra_vde_free_bo(struct tegra_vde_bo *bo)
{
struct tegra_vde *vde = bo->vde;
struct device *dev = vde->miscdev.parent;
if (vde->domain)
tegra_vde_iommu_unmap(vde, bo->iova);
dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs);
sg_free_table(&bo->sgt);
dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle,
bo->dma_attrs);
kfree(bo);
}
static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde,
unsigned int refs_nb,
bool setup_refs)
@ -424,6 +514,9 @@ static int tegra_vde_setup_hw_context(struct tegra_vde *vde,
tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C);
if (vde->soc->supports_ref_pic_marking)
tegra_vde_writel(vde, vde->secure_bo->dma_addr, vde->sxe, 0x7c);
value = 0x10000005;
value |= ctx->pic_width_in_mbs << 11;
value |= ctx->pic_height_in_mbs << 3;
@ -958,6 +1051,8 @@ static int tegra_vde_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, vde);
vde->soc = of_device_get_match_data(&pdev->dev);
vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe");
if (IS_ERR(vde->sxe))
return PTR_ERR(vde->sxe);
@ -1077,6 +1172,12 @@ static int tegra_vde_probe(struct platform_device *pdev)
pm_runtime_put(dev);
err = tegra_vde_alloc_bo(vde, &vde->secure_bo, DMA_FROM_DEVICE, 4096);
if (err) {
dev_err(dev, "Failed to allocate secure BO: %d\n", err);
goto err_pm_runtime;
}
return 0;
err_pm_runtime:
@ -1100,6 +1201,8 @@ static int tegra_vde_remove(struct platform_device *pdev)
struct tegra_vde *vde = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
tegra_vde_free_bo(vde->secure_bo);
/*
* As it increments RPM usage_count even on errors, we don't need to
* check the returned code here.
@ -1173,8 +1276,27 @@ static const struct dev_pm_ops tegra_vde_pm_ops = {
tegra_vde_pm_resume)
};
static const struct tegra_vde_soc tegra124_vde_soc = {
.supports_ref_pic_marking = true,
};
static const struct tegra_vde_soc tegra114_vde_soc = {
.supports_ref_pic_marking = true,
};
static const struct tegra_vde_soc tegra30_vde_soc = {
.supports_ref_pic_marking = false,
};
static const struct tegra_vde_soc tegra20_vde_soc = {
.supports_ref_pic_marking = false,
};
static const struct of_device_id tegra_vde_of_match[] = {
{ .compatible = "nvidia,tegra20-vde", },
{ .compatible = "nvidia,tegra124-vde", .data = &tegra124_vde_soc },
{ .compatible = "nvidia,tegra114-vde", .data = &tegra114_vde_soc },
{ .compatible = "nvidia,tegra30-vde", .data = &tegra30_vde_soc },
{ .compatible = "nvidia,tegra20-vde", .data = &tegra20_vde_soc },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_vde_of_match);

View file

@ -24,6 +24,22 @@ struct iommu_domain;
struct reset_control;
struct dma_buf_attachment;
struct tegra_vde_soc {
bool supports_ref_pic_marking;
};
struct tegra_vde_bo {
struct iova *iova;
struct sg_table sgt;
struct tegra_vde *vde;
enum dma_data_direction dma_dir;
unsigned long dma_attrs;
dma_addr_t dma_handle;
dma_addr_t dma_addr;
void *dma_cookie;
size_t size;
};
struct tegra_vde {
void __iomem *sxe;
void __iomem *bsev;
@ -48,6 +64,8 @@ struct tegra_vde {
struct iova_domain iova;
struct iova *iova_resv_static_addresses;
struct iova *iova_resv_last_page;
const struct tegra_vde_soc *soc;
struct tegra_vde_bo *secure_bo;
dma_addr_t iram_lists_addr;
u32 *iram;
};