]> Git Repo - linux.git/commitdiff
drm/tegra: hub: Fix YUV support
authorThierry Reding <[email protected]>
Thu, 27 May 2021 18:15:46 +0000 (20:15 +0200)
committerThierry Reding <[email protected]>
Mon, 31 May 2021 12:30:11 +0000 (14:30 +0200)
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 <[email protected]>
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/hub.c
drivers/gpu/drm/tegra/plane.c
drivers/gpu/drm/tegra/plane.h

index f9120dc2468288acb4e0feefd990a97dbf7c5172..c5ea88a686d15fff83f0a1ca2a065037c7c89992 100644 (file)
@@ -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
index 29f19c3c614937bd3bc5963388fad122abf8b245..455c3fdef8dc996af522143ee6d3aa2af757f09e 100644 (file)
@@ -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)
 
@@ -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)
index bfae8a02f55b82dfc4968c7d03b507994e49b1c1..94e1ccfb6235a464f5232b024b475a9726e9f8f7 100644 (file)
@@ -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;
 
@@ -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);
@@ -501,8 +505,6 @@ 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
@@ -510,9 +512,12 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
         * 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);
 
@@ -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) |
index 2e11b4b1f7025608a70561a2f5564cf802633296..2e65b4075ce6cf80b5542e5ca6c753535565996d 100644 (file)
@@ -375,7 +375,20 @@ 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:
@@ -383,6 +396,9 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
                if (planar)
                        *planar = false;
 
+               if (bpc)
+                       *bpc = 8;
+
                return true;
 
        case WIN_COLOR_DEPTH_YCbCr420P:
@@ -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;
        }
 
@@ -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;
        }
index c691dd79b27b153e45b71fa6e663b5275cf73bfd..1785c1559c0ce15f1d56299e9ddde444f002a589 100644 (file)
@@ -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);
 
This page took 0.062054 seconds and 4 git commands to generate.