drm/tegra: Support semi-planar formats on Tegra114+

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>
This commit is contained in:
Thierry Reding 2022-01-12 09:36:29 +01:00
parent 28aa30b08d
commit a649b133c3
5 changed files with 91 additions and 23 deletions

View file

@ -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);
@ -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);
@ -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 {
@ -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[] = {
@ -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,

View file

@ -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

View file

@ -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 */
@ -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);
@ -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);
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]);
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);

View file

@ -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;
}
@ -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;
@ -462,8 +486,22 @@ 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;
@ -471,8 +509,8 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *
return true;
}
if (planar)
*planar = false;
if (planes)
*planes = 1;
return false;
}

View file

@ -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);