Commit b7fa0cde authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm/tegra/for-5.5-rc1-fixes' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/tegra: Fixes for v5.5-rc1

This is a set of small fixes, mostly for regressions introduced with the
DMA API and DisplayPort support in the main pull request for v5.5-rc1.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Thierry Reding <thierry.reding@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191204124316.3534855-1-thierry.reding@gmail.com
parents 4673402e d66dfcf8
...@@ -837,16 +837,15 @@ static int tegra_cursor_atomic_check(struct drm_plane *plane, ...@@ -837,16 +837,15 @@ static int tegra_cursor_atomic_check(struct drm_plane *plane,
static void tegra_cursor_atomic_update(struct drm_plane *plane, static void tegra_cursor_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state) struct drm_plane_state *old_state)
{ {
struct tegra_bo *bo = tegra_fb_get_plane(plane->state->fb, 0); struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
struct tegra_dc *dc = to_tegra_dc(plane->state->crtc); struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
struct drm_plane_state *state = plane->state;
u32 value = CURSOR_CLIP_DISPLAY; u32 value = CURSOR_CLIP_DISPLAY;
/* rien ne va plus */ /* rien ne va plus */
if (!plane->state->crtc || !plane->state->fb) if (!plane->state->crtc || !plane->state->fb)
return; return;
switch (state->crtc_w) { switch (plane->state->crtc_w) {
case 32: case 32:
value |= CURSOR_SIZE_32x32; value |= CURSOR_SIZE_32x32;
break; break;
...@@ -864,16 +863,16 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, ...@@ -864,16 +863,16 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
break; break;
default: default:
WARN(1, "cursor size %ux%u not supported\n", state->crtc_w, WARN(1, "cursor size %ux%u not supported\n",
state->crtc_h); plane->state->crtc_w, plane->state->crtc_h);
return; return;
} }
value |= (bo->iova >> 10) & 0x3fffff; value |= (state->iova[0] >> 10) & 0x3fffff;
tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR); tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
value = (bo->iova >> 32) & 0x3; value = (state->iova[0] >> 32) & 0x3;
tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI); tegra_dc_writel(dc, value, DC_DISP_CURSOR_START_ADDR_HI);
#endif #endif
...@@ -892,7 +891,8 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane, ...@@ -892,7 +891,8 @@ static void tegra_cursor_atomic_update(struct drm_plane *plane,
tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL); tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
/* position the cursor */ /* position the cursor */
value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff); value = (plane->state->crtc_y & 0x3fff) << 16 |
(plane->state->crtc_x & 0x3fff);
tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION); tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
} }
...@@ -2017,7 +2017,7 @@ static int tegra_dc_init(struct host1x_client *client) ...@@ -2017,7 +2017,7 @@ static int tegra_dc_init(struct host1x_client *client)
dev_warn(dc->dev, "failed to allocate syncpoint\n"); dev_warn(dc->dev, "failed to allocate syncpoint\n");
err = host1x_client_iommu_attach(client); err = host1x_client_iommu_attach(client);
if (err < 0) { if (err < 0 && err != -ENODEV) {
dev_err(client->dev, "failed to attach to domain: %d\n", err); dev_err(client->dev, "failed to attach to domain: %d\n", err);
return err; return err;
} }
......
...@@ -920,10 +920,8 @@ int host1x_client_iommu_attach(struct host1x_client *client) ...@@ -920,10 +920,8 @@ int host1x_client_iommu_attach(struct host1x_client *client)
if (tegra->domain) { if (tegra->domain) {
group = iommu_group_get(client->dev); group = iommu_group_get(client->dev);
if (!group) { if (!group)
dev_err(client->dev, "failed to get IOMMU group\n");
return -ENODEV; return -ENODEV;
}
if (domain != tegra->domain) { if (domain != tegra->domain) {
err = iommu_attach_group(tegra->domain, group); err = iommu_attach_group(tegra->domain, group);
...@@ -1243,6 +1241,9 @@ static int host1x_drm_remove(struct host1x_device *dev) ...@@ -1243,6 +1241,9 @@ static int host1x_drm_remove(struct host1x_device *dev)
drm_atomic_helper_shutdown(drm); drm_atomic_helper_shutdown(drm);
drm_mode_config_cleanup(drm); drm_mode_config_cleanup(drm);
if (tegra->hub)
tegra_display_hub_cleanup(tegra->hub);
err = host1x_device_exit(dev); err = host1x_device_exit(dev);
if (err < 0) if (err < 0)
dev_err(&dev->dev, "host1x device cleanup failed: %d\n", err); dev_err(&dev->dev, "host1x device cleanup failed: %d\n", err);
......
...@@ -27,6 +27,29 @@ static void tegra_bo_put(struct host1x_bo *bo) ...@@ -27,6 +27,29 @@ static void tegra_bo_put(struct host1x_bo *bo)
drm_gem_object_put_unlocked(&obj->gem); drm_gem_object_put_unlocked(&obj->gem);
} }
/* XXX move this into lib/scatterlist.c? */
static int sg_alloc_table_from_sg(struct sg_table *sgt, struct scatterlist *sg,
unsigned int nents, gfp_t gfp_mask)
{
struct scatterlist *dst;
unsigned int i;
int err;
err = sg_alloc_table(sgt, nents, gfp_mask);
if (err < 0)
return err;
dst = sgt->sgl;
for (i = 0; i < nents; i++) {
sg_set_page(dst, sg_page(sg), sg->length, 0);
dst = sg_next(dst);
sg = sg_next(sg);
}
return 0;
}
static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo, static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo,
dma_addr_t *phys) dma_addr_t *phys)
{ {
...@@ -52,11 +75,31 @@ static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo, ...@@ -52,11 +75,31 @@ static struct sg_table *tegra_bo_pin(struct device *dev, struct host1x_bo *bo,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (obj->pages) { if (obj->pages) {
/*
* If the buffer object was allocated from the explicit IOMMU
* API code paths, construct an SG table from the pages.
*/
err = sg_alloc_table_from_pages(sgt, obj->pages, obj->num_pages, err = sg_alloc_table_from_pages(sgt, obj->pages, obj->num_pages,
0, obj->gem.size, GFP_KERNEL); 0, obj->gem.size, GFP_KERNEL);
if (err < 0) if (err < 0)
goto free; goto free;
} else if (obj->sgt) {
/*
* If the buffer object already has an SG table but no pages
* were allocated for it, it means the buffer was imported and
* the SG table needs to be copied to avoid overwriting any
* other potential users of the original SG table.
*/
err = sg_alloc_table_from_sg(sgt, obj->sgt->sgl, obj->sgt->nents,
GFP_KERNEL);
if (err < 0)
goto free;
} else { } else {
/*
* If the buffer object had no pages allocated and if it was
* not imported, it had to be allocated with the DMA API, so
* the DMA API helper can be used.
*/
err = dma_get_sgtable(dev, sgt, obj->vaddr, obj->iova, err = dma_get_sgtable(dev, sgt, obj->vaddr, obj->iova,
obj->gem.size); obj->gem.size);
if (err < 0) if (err < 0)
...@@ -397,13 +440,6 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm, ...@@ -397,13 +440,6 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
err = tegra_bo_iommu_map(tegra, bo); err = tegra_bo_iommu_map(tegra, bo);
if (err < 0) if (err < 0)
goto detach; goto detach;
} else {
if (bo->sgt->nents > 1) {
err = -EINVAL;
goto detach;
}
bo->iova = sg_dma_address(bo->sgt->sgl);
} }
bo->gem.import_attach = attach; bo->gem.import_attach = attach;
......
...@@ -605,11 +605,8 @@ static struct tegra_display_hub_state * ...@@ -605,11 +605,8 @@ static struct tegra_display_hub_state *
tegra_display_hub_get_state(struct tegra_display_hub *hub, tegra_display_hub_get_state(struct tegra_display_hub *hub,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
struct drm_device *drm = dev_get_drvdata(hub->client.parent);
struct drm_private_state *priv; struct drm_private_state *priv;
WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex));
priv = drm_atomic_get_private_obj_state(state, &hub->base); priv = drm_atomic_get_private_obj_state(state, &hub->base);
if (IS_ERR(priv)) if (IS_ERR(priv))
return ERR_CAST(priv); return ERR_CAST(priv);
......
...@@ -129,6 +129,17 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) ...@@ -129,6 +129,17 @@ static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
goto unpin; goto unpin;
} }
/*
* The display controller needs contiguous memory, so
* fail if the buffer is discontiguous and we fail to
* map its SG table to a single contiguous chunk of
* I/O virtual memory.
*/
if (err > 1) {
err = -EINVAL;
goto unpin;
}
state->iova[i] = sg_dma_address(sgt->sgl); state->iova[i] = sg_dma_address(sgt->sgl);
state->sgt[i] = sgt; state->sgt[i] = sgt;
} else { } else {
......
...@@ -3912,8 +3912,7 @@ static int tegra_sor_remove(struct platform_device *pdev) ...@@ -3912,8 +3912,7 @@ static int tegra_sor_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM static int tegra_sor_runtime_suspend(struct device *dev)
static int tegra_sor_suspend(struct device *dev)
{ {
struct tegra_sor *sor = dev_get_drvdata(dev); struct tegra_sor *sor = dev_get_drvdata(dev);
int err; int err;
...@@ -3935,7 +3934,7 @@ static int tegra_sor_suspend(struct device *dev) ...@@ -3935,7 +3934,7 @@ static int tegra_sor_suspend(struct device *dev)
return 0; return 0;
} }
static int tegra_sor_resume(struct device *dev) static int tegra_sor_runtime_resume(struct device *dev)
{ {
struct tegra_sor *sor = dev_get_drvdata(dev); struct tegra_sor *sor = dev_get_drvdata(dev);
int err; int err;
...@@ -3967,10 +3966,39 @@ static int tegra_sor_resume(struct device *dev) ...@@ -3967,10 +3966,39 @@ static int tegra_sor_resume(struct device *dev)
return 0; return 0;
} }
#endif
static int tegra_sor_suspend(struct device *dev)
{
struct tegra_sor *sor = dev_get_drvdata(dev);
int err;
if (sor->hdmi_supply) {
err = regulator_disable(sor->hdmi_supply);
if (err < 0)
return err;
}
return 0;
}
static int tegra_sor_resume(struct device *dev)
{
struct tegra_sor *sor = dev_get_drvdata(dev);
int err;
if (sor->hdmi_supply) {
err = regulator_enable(sor->hdmi_supply);
if (err < 0)
return err;
}
return 0;
}
static const struct dev_pm_ops tegra_sor_pm_ops = { static const struct dev_pm_ops tegra_sor_pm_ops = {
SET_RUNTIME_PM_OPS(tegra_sor_suspend, tegra_sor_resume, NULL) SET_RUNTIME_PM_OPS(tegra_sor_runtime_suspend, tegra_sor_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(tegra_sor_suspend, tegra_sor_resume)
}; };
struct platform_driver tegra_sor_driver = { struct platform_driver tegra_sor_driver = {
......
...@@ -167,7 +167,7 @@ static int vic_init(struct host1x_client *client) ...@@ -167,7 +167,7 @@ static int vic_init(struct host1x_client *client)
int err; int err;
err = host1x_client_iommu_attach(client); err = host1x_client_iommu_attach(client);
if (err < 0) { if (err < 0 && err != -ENODEV) {
dev_err(vic->dev, "failed to attach to domain: %d\n", err); dev_err(vic->dev, "failed to attach to domain: %d\n", err);
return err; return err;
} }
...@@ -386,13 +386,14 @@ static const struct vic_config vic_t194_config = { ...@@ -386,13 +386,14 @@ static const struct vic_config vic_t194_config = {
.supports_sid = true, .supports_sid = true,
}; };
static const struct of_device_id vic_match[] = { static const struct of_device_id tegra_vic_of_match[] = {
{ .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config }, { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
{ .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config }, { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
{ .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config }, { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
{ .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config }, { .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, tegra_vic_of_match);
static int vic_probe(struct platform_device *pdev) static int vic_probe(struct platform_device *pdev)
{ {
...@@ -516,7 +517,7 @@ static const struct dev_pm_ops vic_pm_ops = { ...@@ -516,7 +517,7 @@ static const struct dev_pm_ops vic_pm_ops = {
struct platform_driver tegra_vic_driver = { struct platform_driver tegra_vic_driver = {
.driver = { .driver = {
.name = "tegra-vic", .name = "tegra-vic",
.of_match_table = vic_match, .of_match_table = tegra_vic_of_match,
.pm = &vic_pm_ops .pm = &vic_pm_ops
}, },
.probe = vic_probe, .probe = vic_probe,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment