Merge tag 'drm/tegra/for-5.6-rc1-fixes' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Fixes for v5.6-rc1 These are a couple of quick fixes for regressions that were found during the first two weeks of the merge window. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thierry Reding <thierry.reding@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200206172753.2185390-1-thierry.reding@gmail.com
This commit is contained in:
@@ -1037,23 +1037,9 @@ void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt,
|
||||
free_pages((unsigned long)virt, get_order(size));
|
||||
}
|
||||
|
||||
static int host1x_drm_probe(struct host1x_device *dev)
|
||||
static bool host1x_drm_wants_iommu(struct host1x_device *dev)
|
||||
{
|
||||
struct drm_driver *driver = &tegra_drm_driver;
|
||||
struct iommu_domain *domain;
|
||||
struct tegra_drm *tegra;
|
||||
struct drm_device *drm;
|
||||
int err;
|
||||
|
||||
drm = drm_dev_alloc(driver, &dev->dev);
|
||||
if (IS_ERR(drm))
|
||||
return PTR_ERR(drm);
|
||||
|
||||
tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
|
||||
if (!tegra) {
|
||||
err = -ENOMEM;
|
||||
goto put;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the Tegra DRM clients are backed by an IOMMU, push buffers are
|
||||
@@ -1082,9 +1068,38 @@ static int host1x_drm_probe(struct host1x_device *dev)
|
||||
* up the device tree appropriately. This is considered an problem
|
||||
* of integration, so care must be taken for the DT to be consistent.
|
||||
*/
|
||||
domain = iommu_get_domain_for_dev(drm->dev->parent);
|
||||
domain = iommu_get_domain_for_dev(dev->dev.parent);
|
||||
|
||||
if (domain && iommu_present(&platform_bus_type)) {
|
||||
/*
|
||||
* Tegra20 and Tegra30 don't support addressing memory beyond the
|
||||
* 32-bit boundary, so the regular GATHER opcodes will always be
|
||||
* sufficient and whether or not the host1x is attached to an IOMMU
|
||||
* doesn't matter.
|
||||
*/
|
||||
if (!domain && dma_get_mask(dev->dev.parent) <= DMA_BIT_MASK(32))
|
||||
return true;
|
||||
|
||||
return domain != NULL;
|
||||
}
|
||||
|
||||
static int host1x_drm_probe(struct host1x_device *dev)
|
||||
{
|
||||
struct drm_driver *driver = &tegra_drm_driver;
|
||||
struct tegra_drm *tegra;
|
||||
struct drm_device *drm;
|
||||
int err;
|
||||
|
||||
drm = drm_dev_alloc(driver, &dev->dev);
|
||||
if (IS_ERR(drm))
|
||||
return PTR_ERR(drm);
|
||||
|
||||
tegra = kzalloc(sizeof(*tegra), GFP_KERNEL);
|
||||
if (!tegra) {
|
||||
err = -ENOMEM;
|
||||
goto put;
|
||||
}
|
||||
|
||||
if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) {
|
||||
tegra->domain = iommu_domain_alloc(&platform_bus_type);
|
||||
if (!tegra->domain) {
|
||||
err = -ENOMEM;
|
||||
|
@@ -60,8 +60,16 @@ static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo,
|
||||
/*
|
||||
* If we've manually mapped the buffer object through the IOMMU, make
|
||||
* sure to return the IOVA address of our mapping.
|
||||
*
|
||||
* Similarly, for buffers that have been allocated by the DMA API the
|
||||
* physical address can be used for devices that are not attached to
|
||||
* an IOMMU. For these devices, callers must pass a valid pointer via
|
||||
* the @phys argument.
|
||||
*
|
||||
* Imported buffers were also already mapped at import time, so the
|
||||
* existing mapping can be reused.
|
||||
*/
|
||||
if (phys && obj->mm) {
|
||||
if (phys) {
|
||||
*phys = obj->iova;
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@
|
||||
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
@@ -107,21 +109,27 @@ const struct drm_plane_funcs tegra_plane_funcs = {
|
||||
|
||||
static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
|
||||
{
|
||||
struct iommu_domain *domain = iommu_get_domain_for_dev(dc->dev);
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < state->base.fb->format->num_planes; i++) {
|
||||
struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
|
||||
dma_addr_t phys_addr, *phys;
|
||||
struct sg_table *sgt;
|
||||
|
||||
if (!dc->client.group) {
|
||||
struct sg_table *sgt;
|
||||
if (!domain || dc->client.group)
|
||||
phys = &phys_addr;
|
||||
else
|
||||
phys = NULL;
|
||||
|
||||
sgt = host1x_bo_pin(dc->dev, &bo->base, NULL);
|
||||
if (IS_ERR(sgt)) {
|
||||
err = PTR_ERR(sgt);
|
||||
goto unpin;
|
||||
}
|
||||
sgt = host1x_bo_pin(dc->dev, &bo->base, phys);
|
||||
if (IS_ERR(sgt)) {
|
||||
err = PTR_ERR(sgt);
|
||||
goto unpin;
|
||||
}
|
||||
|
||||
if (sgt) {
|
||||
err = dma_map_sg(dc->dev, sgt->sgl, sgt->nents,
|
||||
DMA_TO_DEVICE);
|
||||
if (err == 0) {
|
||||
@@ -143,7 +151,7 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
|
||||
state->iova[i] = sg_dma_address(sgt->sgl);
|
||||
state->sgt[i] = sgt;
|
||||
} else {
|
||||
state->iova[i] = bo->iova;
|
||||
state->iova[i] = phys_addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,9 +164,11 @@ unpin:
|
||||
struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
|
||||
struct sg_table *sgt = state->sgt[i];
|
||||
|
||||
dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE);
|
||||
host1x_bo_unpin(dc->dev, &bo->base, sgt);
|
||||
if (sgt)
|
||||
dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
host1x_bo_unpin(dc->dev, &bo->base, sgt);
|
||||
state->iova[i] = DMA_MAPPING_ERROR;
|
||||
state->sgt[i] = NULL;
|
||||
}
|
||||
@@ -172,17 +182,13 @@ static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state)
|
||||
|
||||
for (i = 0; i < state->base.fb->format->num_planes; i++) {
|
||||
struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
|
||||
struct sg_table *sgt = state->sgt[i];
|
||||
|
||||
if (!dc->client.group) {
|
||||
struct sg_table *sgt = state->sgt[i];
|
||||
|
||||
if (sgt) {
|
||||
dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents,
|
||||
DMA_TO_DEVICE);
|
||||
host1x_bo_unpin(dc->dev, &bo->base, sgt);
|
||||
}
|
||||
}
|
||||
if (sgt)
|
||||
dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
host1x_bo_unpin(dc->dev, &bo->base, sgt);
|
||||
state->iova[i] = DMA_MAPPING_ERROR;
|
||||
state->sgt[i] = NULL;
|
||||
}
|
||||
|
@@ -3915,36 +3915,6 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, sor);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
/*
|
||||
* On Tegra210 and earlier, provide our own implementation for the
|
||||
* pad output clock.
|
||||
*/
|
||||
if (!sor->clk_pad) {
|
||||
char *name;
|
||||
|
||||
err = host1x_client_resume(&sor->client);
|
||||
if (err < 0) {
|
||||
dev_err(sor->dev, "failed to resume: %d\n", err);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "sor%u_pad_clkout", sor->index);
|
||||
if (!name) {
|
||||
err = -ENOMEM;
|
||||
goto remove;
|
||||
}
|
||||
|
||||
sor->clk_pad = tegra_clk_sor_pad_register(sor, name);
|
||||
host1x_client_suspend(&sor->client);
|
||||
}
|
||||
|
||||
if (IS_ERR(sor->clk_pad)) {
|
||||
err = PTR_ERR(sor->clk_pad);
|
||||
dev_err(&pdev->dev, "failed to register SOR pad clock: %d\n",
|
||||
err);
|
||||
goto remove;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&sor->client.list);
|
||||
sor->client.ops = &sor_client_ops;
|
||||
sor->client.dev = &pdev->dev;
|
||||
@@ -3953,11 +3923,46 @@ static int tegra_sor_probe(struct platform_device *pdev)
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
|
||||
err);
|
||||
goto remove;
|
||||
goto rpm_disable;
|
||||
}
|
||||
|
||||
/*
|
||||
* On Tegra210 and earlier, provide our own implementation for the
|
||||
* pad output clock.
|
||||
*/
|
||||
if (!sor->clk_pad) {
|
||||
char *name;
|
||||
|
||||
name = devm_kasprintf(sor->dev, GFP_KERNEL, "sor%u_pad_clkout",
|
||||
sor->index);
|
||||
if (!name) {
|
||||
err = -ENOMEM;
|
||||
goto unregister;
|
||||
}
|
||||
|
||||
err = host1x_client_resume(&sor->client);
|
||||
if (err < 0) {
|
||||
dev_err(sor->dev, "failed to resume: %d\n", err);
|
||||
goto unregister;
|
||||
}
|
||||
|
||||
sor->clk_pad = tegra_clk_sor_pad_register(sor, name);
|
||||
host1x_client_suspend(&sor->client);
|
||||
}
|
||||
|
||||
if (IS_ERR(sor->clk_pad)) {
|
||||
err = PTR_ERR(sor->clk_pad);
|
||||
dev_err(sor->dev, "failed to register SOR pad clock: %d\n",
|
||||
err);
|
||||
goto unregister;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unregister:
|
||||
host1x_client_unregister(&sor->client);
|
||||
rpm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
remove:
|
||||
if (sor->ops && sor->ops->remove)
|
||||
sor->ops->remove(sor);
|
||||
@@ -3971,8 +3976,6 @@ static int tegra_sor_remove(struct platform_device *pdev)
|
||||
struct tegra_sor *sor = platform_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
err = host1x_client_unregister(&sor->client);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
|
||||
@@ -3980,6 +3983,8 @@ static int tegra_sor_remove(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
if (sor->ops && sor->ops->remove) {
|
||||
err = sor->ops->remove(sor);
|
||||
if (err < 0)
|
||||
|
Viittaa uudesa ongelmassa
Block a user