media: staging: tegra-vde: Support reference picture marking
authorThierry Reding <treding@nvidia.com>
Sun, 14 Nov 2021 22:47:30 +0000 (23:47 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Tue, 30 Nov 2021 11:09:00 +0000 (12:09 +0100)
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>
drivers/staging/media/tegra-vde/vde.c
drivers/staging/media/tegra-vde/vde.h

index ed4c125..9c06998 100644 (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);
index 5561291..bbd42b8 100644 (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;
 };