Skip to content

Commit e16efff

Browse files
committed
drm/tegra: hub: Fix YUV support
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>
1 parent 671cc35 commit e16efff

5 files changed

Lines changed: 78 additions & 9 deletions

File tree

drivers/gpu/drm/tegra/dc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
348348
* For YUV planar modes, the number of bytes per pixel takes into
349349
* account only the luma component and therefore is 1.
350350
*/
351-
yuv = tegra_plane_format_is_yuv(window->format, &planar);
351+
yuv = tegra_plane_format_is_yuv(window->format, &planar, NULL);
352352
if (!yuv)
353353
bpp = window->bits_per_pixel / 8;
354354
else

drivers/gpu/drm/tegra/dc.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
696696

697697
#define DC_WINBUF_START_ADDR_HI 0x80d
698698

699+
#define DC_WINBUF_START_ADDR_HI_U 0x80f
700+
#define DC_WINBUF_START_ADDR_HI_V 0x811
701+
699702
#define DC_WINBUF_CDE_CONTROL 0x82f
700703
#define ENABLE_SURFACE (1 << 0)
701704

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

726+
#define DC_WIN_PLANAR_STORAGE_UV 0x70a
727+
#define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0)
728+
#define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16)
729+
723730
#define DC_WIN_SET_PARAMS 0x70d
724731
#define CLAMP_BEFORE_BLEND (1 << 15)
725732
#define DEGAMMA_NONE (0 << 13)

drivers/gpu/drm/tegra/hub.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,9 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
454454
unsigned int zpos = new_state->normalized_zpos;
455455
struct drm_framebuffer *fb = new_state->fb;
456456
struct tegra_plane *p = to_tegra_plane(plane);
457-
dma_addr_t base;
457+
dma_addr_t base, addr_flag = 0;
458+
unsigned int bpc;
459+
bool yuv, planar;
458460
u32 value;
459461
int err;
460462

@@ -473,6 +475,8 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
473475
return;
474476
}
475477

478+
yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planar, &bpc);
479+
476480
tegra_dc_assign_shared_plane(dc, p);
477481

478482
tegra_plane_writel(p, VCOUNTER, DC_WIN_CORE_ACT_CONTROL);
@@ -501,18 +505,19 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
501505
/* disable compression */
502506
tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);
503507

504-
base = tegra_plane_state->iova[0] + fb->offsets[0];
505-
506508
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
507509
/*
508510
* Physical address bit 39 in Tegra194 is used as a switch for special
509511
* logic that swizzles the memory using either the legacy Tegra or the
510512
* dGPU sector layout.
511513
*/
512514
if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU)
513-
base |= BIT_ULL(39);
515+
addr_flag = BIT_ULL(39);
514516
#endif
515517

518+
base = tegra_plane_state->iova[0] + fb->offsets[0];
519+
base |= addr_flag;
520+
516521
tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH);
517522
tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS);
518523

@@ -535,7 +540,44 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
535540
value = PITCH(fb->pitches[0]);
536541
tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE);
537542

538-
value = CLAMP_BEFORE_BLEND | DEGAMMA_SRGB | INPUT_RANGE_FULL;
543+
if (yuv && planar) {
544+
base = tegra_plane_state->iova[1] + fb->offsets[1];
545+
base |= addr_flag;
546+
547+
tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_U);
548+
tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_U);
549+
550+
base = tegra_plane_state->iova[2] + fb->offsets[2];
551+
base |= addr_flag;
552+
553+
tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_V);
554+
tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_V);
555+
556+
value = PITCH_U(fb->pitches[2]) | PITCH_V(fb->pitches[2]);
557+
tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE_UV);
558+
} else {
559+
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_U);
560+
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_U);
561+
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_V);
562+
tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_V);
563+
tegra_plane_writel(p, 0, DC_WIN_PLANAR_STORAGE_UV);
564+
}
565+
566+
value = CLAMP_BEFORE_BLEND | INPUT_RANGE_FULL;
567+
568+
if (yuv) {
569+
if (bpc < 12)
570+
value |= DEGAMMA_YUV8_10;
571+
else
572+
value |= DEGAMMA_YUV12;
573+
574+
/* XXX parameterize */
575+
value |= COLOR_SPACE_YUV_2020;
576+
} else {
577+
if (!tegra_plane_format_is_indexed(tegra_plane_state->format))
578+
value |= DEGAMMA_SRGB;
579+
}
580+
539581
tegra_plane_writel(p, value, DC_WIN_SET_PARAMS);
540582

541583
value = OFFSET_X(new_state->src_y >> 16) |

drivers/gpu/drm/tegra/plane.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,14 +375,30 @@ int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
375375
return 0;
376376
}
377377

378-
bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
378+
bool tegra_plane_format_is_indexed(unsigned int format)
379+
{
380+
switch (format) {
381+
case WIN_COLOR_DEPTH_P1:
382+
case WIN_COLOR_DEPTH_P2:
383+
case WIN_COLOR_DEPTH_P4:
384+
case WIN_COLOR_DEPTH_P8:
385+
return true;
386+
}
387+
388+
return false;
389+
}
390+
391+
bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc)
379392
{
380393
switch (format) {
381394
case WIN_COLOR_DEPTH_YCbCr422:
382395
case WIN_COLOR_DEPTH_YUV422:
383396
if (planar)
384397
*planar = false;
385398

399+
if (bpc)
400+
*bpc = 8;
401+
386402
return true;
387403

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

415+
if (bpc)
416+
*bpc = 8;
417+
399418
return true;
400419
}
401420

@@ -421,7 +440,7 @@ static bool __drm_format_has_alpha(u32 format)
421440
static int tegra_plane_format_get_alpha(unsigned int opaque,
422441
unsigned int *alpha)
423442
{
424-
if (tegra_plane_format_is_yuv(opaque, NULL)) {
443+
if (tegra_plane_format_is_yuv(opaque, NULL, NULL)) {
425444
*alpha = opaque;
426445
return 0;
427446
}

drivers/gpu/drm/tegra/plane.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ int tegra_plane_state_add(struct tegra_plane *plane,
7474
struct drm_plane_state *state);
7575

7676
int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
77-
bool tegra_plane_format_is_yuv(unsigned int format, bool *planar);
77+
bool tegra_plane_format_is_indexed(unsigned int format);
78+
bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc);
7879
int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
7980
struct tegra_plane_state *state);
8081

0 commit comments

Comments
 (0)