OSDN Git Service

drm/tegra: Support semi-planar formats on Tegra114+
authorThierry Reding <treding@nvidia.com>
Wed, 12 Jan 2022 08:36:29 +0000 (09:36 +0100)
committerThierry Reding <treding@nvidia.com>
Tue, 1 Mar 2022 10:13:09 +0000 (11:13 +0100)
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>
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 9435c86..9442d7e 100644 (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,
index 3f91a10..67c4c5b 100644 (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
 
index fc9813e..b8d3174 100644 (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);
+               }
+
+               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);
index 321cb1f..5136a37 100644 (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;
 }
index dfb2071..e33a581 100644 (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);