Skip to content

Commit

Permalink
drm/tegra: Support DMA API for display controllers
Browse files Browse the repository at this point in the history
If a display controller is not attached to an explicit IOMMU domain,
which usually means that it's connected to an IOMMU domain controlled by
the DMA API, make sure to map the framebuffer to the display controller
address space. This allows us to transparently handle setups where the
display controller is attached to an IOMMU or setups where it isn't. It
also allows the driver to work with a DMA API that is backed by an
IOMMU.

Signed-off-by: Thierry Reding <treding@nvidia.com>
  • Loading branch information
Thierry Reding committed Oct 29, 2019
1 parent d972d62 commit 2e8d874
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 6 deletions.
8 changes: 5 additions & 3 deletions drivers/gpu/drm/tegra/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,9 +715,7 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
window.swap = state->swap;

for (i = 0; i < fb->format->num_planes; i++) {
struct tegra_bo *bo = tegra_fb_get_plane(fb, i);

window.base[i] = bo->iova + fb->offsets[i];
window.base[i] = state->iova[i] + fb->offsets[i];

/*
* Tegra uses a shared stride for UV planes. Framebuffers are
Expand All @@ -732,6 +730,8 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
}

static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
.prepare_fb = tegra_plane_prepare_fb,
.cleanup_fb = tegra_plane_cleanup_fb,
.atomic_check = tegra_plane_atomic_check,
.atomic_disable = tegra_plane_atomic_disable,
.atomic_update = tegra_plane_atomic_update,
Expand Down Expand Up @@ -914,6 +914,8 @@ static void tegra_cursor_atomic_disable(struct drm_plane *plane,
}

static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
.prepare_fb = tegra_plane_prepare_fb,
.cleanup_fb = tegra_plane_cleanup_fb,
.atomic_check = tegra_cursor_atomic_check,
.atomic_update = tegra_cursor_atomic_update,
.atomic_disable = tegra_cursor_atomic_disable,
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/tegra/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,6 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
unsigned int zpos = plane->state->normalized_zpos;
struct drm_framebuffer *fb = plane->state->fb;
struct tegra_plane *p = to_tegra_plane(plane);
struct tegra_bo *bo;
dma_addr_t base;
u32 value;

Expand Down Expand Up @@ -456,8 +455,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
/* disable compression */
tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);

bo = tegra_fb_get_plane(fb, 0);
base = bo->iova;
base = state->iova[0] + fb->offsets[0];

tegra_plane_writel(p, state->format, DC_WIN_COLOR_DEPTH);
tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);
Expand Down Expand Up @@ -521,6 +519,8 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
}

static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = {
.prepare_fb = tegra_plane_prepare_fb,
.cleanup_fb = tegra_plane_cleanup_fb,
.atomic_check = tegra_shared_plane_atomic_check,
.atomic_update = tegra_shared_plane_atomic_update,
.atomic_disable = tegra_shared_plane_atomic_disable,
Expand Down
104 changes: 104 additions & 0 deletions drivers/gpu/drm/tegra/plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_plane_helper.h>

#include "dc.h"
Expand All @@ -23,6 +24,7 @@ static void tegra_plane_reset(struct drm_plane *plane)
{
struct tegra_plane *p = to_tegra_plane(plane);
struct tegra_plane_state *state;
unsigned int i;

if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
Expand All @@ -36,6 +38,9 @@ static void tegra_plane_reset(struct drm_plane *plane)
plane->state->plane = plane;
plane->state->zpos = p->index;
plane->state->normalized_zpos = p->index;

for (i = 0; i < 3; i++)
state->iova[i] = DMA_MAPPING_ERROR;
}
}

Expand All @@ -60,6 +65,11 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
for (i = 0; i < 2; i++)
copy->blending[i] = state->blending[i];

for (i = 0; i < 3; i++) {
copy->iova[i] = DMA_MAPPING_ERROR;
copy->sgt[i] = NULL;
}

return &copy->base;
}

Expand Down Expand Up @@ -95,6 +105,100 @@ const struct drm_plane_funcs tegra_plane_funcs = {
.format_mod_supported = tegra_plane_format_mod_supported,
};

static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
{
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);

if (!dc->client.group) {
struct sg_table *sgt;

sgt = host1x_bo_pin(dc->dev, &bo->base, NULL);
if (IS_ERR(sgt)) {
err = PTR_ERR(sgt);
goto unpin;
}

err = dma_map_sg(dc->dev, sgt->sgl, sgt->nents,
DMA_TO_DEVICE);
if (err == 0) {
err = -ENOMEM;
goto unpin;
}

state->iova[i] = sg_dma_address(sgt->sgl);
state->sgt[i] = sgt;
} else {
state->iova[i] = bo->iova;
}
}

return 0;

unpin:
dev_err(dc->dev, "failed to map plane %u: %d\n", i, err);

while (i--) {
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);

state->iova[i] = DMA_MAPPING_ERROR;
state->sgt[i] = NULL;
}

return err;
}

static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state)
{
unsigned int i;

for (i = 0; i < state->base.fb->format->num_planes; i++) {
struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, 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);
}
}

state->iova[i] = DMA_MAPPING_ERROR;
state->sgt[i] = NULL;
}
}

int tegra_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct tegra_dc *dc = to_tegra_dc(state->crtc);

if (!state->fb)
return 0;

drm_gem_fb_prepare_fb(plane, state);

return tegra_dc_pin(dc, to_tegra_plane_state(state));
}

void tegra_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *state)
{
struct tegra_dc *dc = to_tegra_dc(state->crtc);

if (dc)
tegra_dc_unpin(dc, to_tegra_plane_state(state));
}

int tegra_plane_state_add(struct tegra_plane *plane,
struct drm_plane_state *state)
{
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/tegra/plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ struct tegra_plane_legacy_blending_state {
struct tegra_plane_state {
struct drm_plane_state base;

struct sg_table *sgt[3];
dma_addr_t iova[3];

struct tegra_bo_tiling tiling;
u32 format;
u32 swap;
Expand All @@ -61,6 +64,11 @@ to_tegra_plane_state(struct drm_plane_state *state)

extern const struct drm_plane_funcs tegra_plane_funcs;

int tegra_plane_prepare_fb(struct drm_plane *plane,
struct drm_plane_state *state);
void tegra_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *state);

int tegra_plane_state_add(struct tegra_plane *plane,
struct drm_plane_state *state);

Expand Down

0 comments on commit 2e8d874

Please sign in to comment.