Skip to content

Commit

Permalink
drm/tegra: hub: Fix YUV support
Browse files Browse the repository at this point in the history
The driver currently exposes several YUV formats but fails to properly
program all the registers needed to display such formats. Add the right
programming sequences so that overlay windows can be used to accelerate
color format conversions in multimedia playback use-cases.

Signed-off-by: Thierry Reding <treding@nvidia.com>
  • Loading branch information
Thierry Reding committed May 31, 2021
1 parent 671cc35 commit e16efff
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 9 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/tegra/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
* 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);
yuv = tegra_plane_format_is_yuv(window->format, &planar, NULL);
if (!yuv)
bpp = window->bits_per_pixel / 8;
else
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpu/drm/tegra/dc.h
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,9 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);

#define DC_WINBUF_START_ADDR_HI 0x80d

#define DC_WINBUF_START_ADDR_HI_U 0x80f
#define DC_WINBUF_START_ADDR_HI_V 0x811

#define DC_WINBUF_CDE_CONTROL 0x82f
#define ENABLE_SURFACE (1 << 0)

Expand All @@ -720,6 +723,10 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_WIN_PLANAR_STORAGE 0x709
#define PITCH(x) (((x) >> 6) & 0x1fff)

#define DC_WIN_PLANAR_STORAGE_UV 0x70a
#define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0)
#define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16)

#define DC_WIN_SET_PARAMS 0x70d
#define CLAMP_BEFORE_BLEND (1 << 15)
#define DEGAMMA_NONE (0 << 13)
Expand Down
52 changes: 47 additions & 5 deletions drivers/gpu/drm/tegra/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,9 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
unsigned int zpos = new_state->normalized_zpos;
struct drm_framebuffer *fb = new_state->fb;
struct tegra_plane *p = to_tegra_plane(plane);
dma_addr_t base;
dma_addr_t base, addr_flag = 0;
unsigned int bpc;
bool yuv, planar;
u32 value;
int err;

Expand All @@ -473,6 +475,8 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
return;
}

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

tegra_dc_assign_shared_plane(dc, p);

tegra_plane_writel(p, VCOUNTER, DC_WIN_CORE_ACT_CONTROL);
Expand Down Expand Up @@ -501,18 +505,19 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
/* disable compression */
tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);

base = tegra_plane_state->iova[0] + fb->offsets[0];

#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
/*
* Physical address bit 39 in Tegra194 is used as a switch for special
* logic that swizzles the memory using either the legacy Tegra or the
* dGPU sector layout.
*/
if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU)
base |= BIT_ULL(39);
addr_flag = BIT_ULL(39);
#endif

base = tegra_plane_state->iova[0] + fb->offsets[0];
base |= addr_flag;

tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH);
tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);

Expand All @@ -535,7 +540,44 @@ 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);

value = CLAMP_BEFORE_BLEND | DEGAMMA_SRGB | INPUT_RANGE_FULL;
if (yuv && planar) {
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;

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[2]) | 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);
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_U);
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_V);
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_V);
tegra_plane_writel(p, 0, DC_WIN_PLANAR_STORAGE_UV);
}

value = CLAMP_BEFORE_BLEND | INPUT_RANGE_FULL;

if (yuv) {
if (bpc < 12)
value |= DEGAMMA_YUV8_10;
else
value |= DEGAMMA_YUV12;

/* XXX parameterize */
value |= COLOR_SPACE_YUV_2020;
} else {
if (!tegra_plane_format_is_indexed(tegra_plane_state->format))
value |= DEGAMMA_SRGB;
}

tegra_plane_writel(p, value, DC_WIN_SET_PARAMS);

value = OFFSET_X(new_state->src_y >> 16) |
Expand Down
23 changes: 21 additions & 2 deletions drivers/gpu/drm/tegra/plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,14 +375,30 @@ int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
return 0;
}

bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
bool tegra_plane_format_is_indexed(unsigned int format)
{
switch (format) {
case WIN_COLOR_DEPTH_P1:
case WIN_COLOR_DEPTH_P2:
case WIN_COLOR_DEPTH_P4:
case WIN_COLOR_DEPTH_P8:
return true;
}

return false;
}

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

if (bpc)
*bpc = 8;

return true;

case WIN_COLOR_DEPTH_YCbCr420P:
Expand All @@ -396,6 +412,9 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
if (planar)
*planar = true;

if (bpc)
*bpc = 8;

return true;
}

Expand All @@ -421,7 +440,7 @@ static bool __drm_format_has_alpha(u32 format)
static int tegra_plane_format_get_alpha(unsigned int opaque,
unsigned int *alpha)
{
if (tegra_plane_format_is_yuv(opaque, NULL)) {
if (tegra_plane_format_is_yuv(opaque, NULL, NULL)) {
*alpha = opaque;
return 0;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/tegra/plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ int tegra_plane_state_add(struct tegra_plane *plane,
struct drm_plane_state *state);

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

Expand Down

0 comments on commit e16efff

Please sign in to comment.