Skip to content

Commit

Permalink
drm/tegra: Support semi-planar formats on Tegra114+
Browse files Browse the repository at this point in the history
The NV12, NV21, NV16, NV61, NV24 and NV42 formats are supported by
Tegra114 and later display hardware. Add the necessary programming to
allow them to be used.

Note that this does not work for Tegra186 and later yet because those
generations have a different display architecture that doesn't support
the same formats.

Signed-off-by: Thierry Reding <treding@nvidia.com>
  • Loading branch information
thierryreding committed Feb 25, 2022
1 parent f3e0a17 commit c25eae9
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 23 deletions.
30 changes: 24 additions & 6 deletions drivers/gpu/drm/tegra/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,18 +345,19 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
{
unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
struct tegra_dc *dc = plane->dc;
bool yuv, planar;
unsigned int planes;
u32 value;
bool yuv;

/*
* For YUV planar modes, the number of bytes per pixel takes into
* account only the luma component and therefore is 1.
*/
yuv = tegra_plane_format_is_yuv(window->format, &planar, NULL);
yuv = tegra_plane_format_is_yuv(window->format, &planes, NULL);
if (!yuv)
bpp = window->bits_per_pixel / 8;
else
bpp = planar ? 1 : 2;
bpp = (planes > 1) ? 1 : 2;

tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH);
tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP);
Expand Down Expand Up @@ -385,7 +386,7 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
* For DDA computations the number of bytes per pixel for YUV planar
* modes needs to take into account all Y, U and V components.
*/
if (yuv && planar)
if (yuv && planes > 1)
bpp = 2;

h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
Expand All @@ -405,9 +406,12 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,

tegra_plane_writel(plane, window->base[0], DC_WINBUF_START_ADDR);

if (yuv && planar) {
if (yuv && planes > 1) {
tegra_plane_writel(plane, window->base[1], DC_WINBUF_START_ADDR_U);
tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);

if (planes > 2)
tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);

value = window->stride[1] << 16 | window->stride[0];
tegra_plane_writel(plane, value, DC_WIN_LINE_STRIDE);
} else {
Expand Down Expand Up @@ -1193,6 +1197,13 @@ static const u32 tegra114_overlay_formats[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
/* semi-planar formats */
DRM_FORMAT_NV12,
DRM_FORMAT_NV21,
DRM_FORMAT_NV16,
DRM_FORMAT_NV61,
DRM_FORMAT_NV24,
DRM_FORMAT_NV42,
};

static const u32 tegra124_overlay_formats[] = {
Expand Down Expand Up @@ -1223,6 +1234,13 @@ static const u32 tegra124_overlay_formats[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
/* semi-planar formats */
DRM_FORMAT_NV12,
DRM_FORMAT_NV21,
DRM_FORMAT_NV16,
DRM_FORMAT_NV61,
DRM_FORMAT_NV24,
DRM_FORMAT_NV42,
};

static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/tegra/dc.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,12 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define WIN_COLOR_DEPTH_A8B8G8R8 36
#define WIN_COLOR_DEPTH_B8G8R8X8 37
#define WIN_COLOR_DEPTH_R8G8B8X8 38
#define WIN_COLOR_DEPTH_YCrCb420SP 42
#define WIN_COLOR_DEPTH_YCbCr420SP 43
#define WIN_COLOR_DEPTH_YCrCb422SP 44
#define WIN_COLOR_DEPTH_YCbCr422SP 45
#define WIN_COLOR_DEPTH_YCrCb444SP 48
#define WIN_COLOR_DEPTH_YCbCr444SP 49
#define WIN_COLOR_DEPTH_X8B8G8R8 65
#define WIN_COLOR_DEPTH_X8R8G8B8 66

Expand Down
24 changes: 15 additions & 9 deletions drivers/gpu/drm/tegra/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,8 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
struct tegra_plane *p = to_tegra_plane(plane);
u32 value, min_width, bypass = 0;
dma_addr_t base, addr_flag = 0;
unsigned int bpc;
bool yuv, planar;
unsigned int bpc, planes;
bool yuv;
int err;

/* rien ne va plus */
Expand All @@ -559,7 +559,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
return;
}

yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planar, &bpc);
yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planes, &bpc);

tegra_dc_assign_shared_plane(dc, p);

Expand Down Expand Up @@ -660,20 +660,26 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
value = PITCH(fb->pitches[0]);
tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE);

if (yuv && planar) {
if (yuv && planes > 1) {
base = tegra_plane_state->iova[1] + fb->offsets[1];
base |= addr_flag;

tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_U);
tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_U);

base = tegra_plane_state->iova[2] + fb->offsets[2];
base |= addr_flag;
if (planes > 2) {
base = tegra_plane_state->iova[2] + fb->offsets[2];
base |= addr_flag;

tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_V);
tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_V);
}

value = PITCH_U(fb->pitches[1]);

tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_V);
tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_V);
if (planes > 2)
value |= PITCH_V(fb->pitches[2]);

value = PITCH_U(fb->pitches[1]) | PITCH_V(fb->pitches[2]);
tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE_UV);
} else {
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_U);
Expand Down
52 changes: 45 additions & 7 deletions drivers/gpu/drm/tegra/plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,30 @@ int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
*format = WIN_COLOR_DEPTH_YCbCr422P;
break;

case DRM_FORMAT_NV12:
*format = WIN_COLOR_DEPTH_YCbCr420SP;
break;

case DRM_FORMAT_NV21:
*format = WIN_COLOR_DEPTH_YCrCb420SP;
break;

case DRM_FORMAT_NV16:
*format = WIN_COLOR_DEPTH_YCbCr422SP;
break;

case DRM_FORMAT_NV61:
*format = WIN_COLOR_DEPTH_YCrCb422SP;
break;

case DRM_FORMAT_NV24:
*format = WIN_COLOR_DEPTH_YCbCr444SP;
break;

case DRM_FORMAT_NV42:
*format = WIN_COLOR_DEPTH_YCrCb444SP;
break;

default:
return -EINVAL;
}
Expand All @@ -441,13 +465,13 @@ bool tegra_plane_format_is_indexed(unsigned int format)
return false;
}

bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc)
bool tegra_plane_format_is_yuv(unsigned int format, unsigned int *planes, unsigned int *bpc)
{
switch (format) {
case WIN_COLOR_DEPTH_YCbCr422:
case WIN_COLOR_DEPTH_YUV422:
if (planar)
*planar = false;
if (planes)
*planes = 1;

if (bpc)
*bpc = 8;
Expand All @@ -462,17 +486,31 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *
case WIN_COLOR_DEPTH_YUV422R:
case WIN_COLOR_DEPTH_YCbCr422RA:
case WIN_COLOR_DEPTH_YUV422RA:
if (planar)
*planar = true;
if (planes)
*planes = 3;

if (bpc)
*bpc = 8;

return true;

case WIN_COLOR_DEPTH_YCrCb420SP:
case WIN_COLOR_DEPTH_YCbCr420SP:
case WIN_COLOR_DEPTH_YCrCb422SP:
case WIN_COLOR_DEPTH_YCbCr422SP:
case WIN_COLOR_DEPTH_YCrCb444SP:
case WIN_COLOR_DEPTH_YCbCr444SP:
if (planes)
*planes = 2;

if (bpc)
*bpc = 8;

return true;
}

if (planar)
*planar = false;
if (planes)
*planes = 1;

return false;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/tegra/plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ int tegra_plane_state_add(struct tegra_plane *plane,

int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
bool tegra_plane_format_is_indexed(unsigned int format);
bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc);
bool tegra_plane_format_is_yuv(unsigned int format, unsigned int *planes, unsigned int *bpc);
int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
struct tegra_plane_state *state);
int tegra_plane_interconnect_init(struct tegra_plane *plane);
Expand Down

0 comments on commit c25eae9

Please sign in to comment.