From: Mikko Perttunen <mperttunen@nvidia.com>
To: Thierry Reding <thierry.reding@kernel.org>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Jonathan Hunter <jonathanh@nvidia.com>,
webgeek1234@gmail.com
Cc: dri-devel@lists.freedesktop.org, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org, Aaron Kling <webgeek1234@gmail.com>
Subject: Re: [PATCH 1/2] drm/tegra: Support swapping chroma planes
Date: Fri, 09 Oct 2026 17:59:32 +0900 [thread overview]
Message-ID: <qEporZZOT_abKwO4JObFpQ@nvidia.com> (raw)
In-Reply-To: <20261008-tegra-drm-yvu420-v1-1-dc1c443c00f3@gmail.com>
On Friday, October 9, 2026 5:57 AM Aaron Kling via B4 Relay wrote:
> From: Aaron Kling <webgeek1234@gmail.com>
>
> The Tegra display controller supports some yuv types, but not their
> chroma swapped variants. For example, yuv420 is supported but yvu420 is
> not. This can be efficiently worked around by just passing the hardware
> said chroma planes backwards. Add a flag to the plane state struct and
> handling to both tegradc and nvdisplay paths.
>
> Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
> ---
> drivers/gpu/drm/tegra/dc.c | 17 ++++++++++++-----
> drivers/gpu/drm/tegra/hub.c | 14 +++++++++-----
> drivers/gpu/drm/tegra/plane.c | 4 +++-
> drivers/gpu/drm/tegra/plane.h | 3 ++-
> 4 files changed, 26 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index b0bfa946e6979..76d3841a17b8b 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -444,7 +444,8 @@ tegra_plane_use_vertical_filtering(struct tegra_plane *plane,
> }
>
> static void tegra_dc_setup_window(struct tegra_plane *plane,
> - const struct tegra_dc_window *window)
> + const struct tegra_dc_window *window,
> + struct tegra_plane_state *tegra_plane_state)
> {
> unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
> struct tegra_dc *dc = plane->dc;
> @@ -510,10 +511,13 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
> tegra_plane_writel(plane, window->base[0], DC_WINBUF_START_ADDR);
>
> if (yuv && planes > 1) {
> - tegra_plane_writel(plane, window->base[1], DC_WINBUF_START_ADDR_U);
> + uint8_t u = tegra_plane_state->swap_uv ? 2 : 1;
> + uint8_t v = tegra_plane_state->swap_uv ? 1 : 2;
> +
> + tegra_plane_writel(plane, window->base[u], DC_WINBUF_START_ADDR_U);
>
> if (planes > 2)
> - tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);
> + tegra_plane_writel(plane, window->base[v], DC_WINBUF_START_ADDR_V);
>
> value = window->stride[1] << 16 | window->stride[0];
> tegra_plane_writel(plane, value, DC_WIN_LINE_STRIDE);
> @@ -740,7 +744,8 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
>
> err = tegra_plane_format(new_plane_state->fb->format->format,
> &plane_state->format,
> - &plane_state->swap);
> + &plane_state->swap,
> + &plane_state->swap_uv);
> if (err < 0)
> return err;
>
> @@ -871,8 +876,10 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
> if (i < 2)
> window.stride[i] = fb->pitches[i];
> }
> + if (tegra_plane_state->swap_uv)
> + window.stride[1] = fb->pitches[2];
Based on the comment above, U and V have the same stride, so this
isn't required.
>
> - tegra_dc_setup_window(p, &window);
> + tegra_dc_setup_window(p, &window, tegra_plane_state);
Instead of passing the plane state, I'd just add a
swap(window.base[1], window.base[2]);
here.
Otherwise looks good to me! I also tested on AGX Xavier.
Mikko
> }
>
> static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
> diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c
> index 448f49f3a7d7e..6427155ac4fdf 100644
> --- a/drivers/gpu/drm/tegra/hub.c
> +++ b/drivers/gpu/drm/tegra/hub.c
> @@ -440,7 +440,8 @@ static int tegra_shared_plane_atomic_check(struct drm_plane *plane,
>
> err = tegra_plane_format(new_plane_state->fb->format->format,
> &plane_state->format,
> - &plane_state->swap);
> + &plane_state->swap,
> + &plane_state->swap_uv);
> if (err < 0)
> return err;
>
> @@ -664,24 +665,27 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
> tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE);
>
> if (yuv && planes > 1) {
> - base = tegra_plane_state->iova[1] + fb->offsets[1];
> + uint8_t u = tegra_plane_state->swap_uv ? 2 : 1;
> + uint8_t v = tegra_plane_state->swap_uv ? 1 : 2;
> +
> + base = tegra_plane_state->iova[u] + fb->offsets[u];
> 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);
>
> if (planes > 2) {
> - base = tegra_plane_state->iova[2] + fb->offsets[2];
> + base = tegra_plane_state->iova[v] + fb->offsets[v];
> 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]);
> + value = PITCH_U(fb->pitches[u]);
>
> if (planes > 2)
> - value |= PITCH_V(fb->pitches[2]);
> + value |= PITCH_V(fb->pitches[v]);
>
> tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE_UV);
> } else {
> diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c
> index 2148b0c59815c..f4feec62ac023 100644
> --- a/drivers/gpu/drm/tegra/plane.c
> +++ b/drivers/gpu/drm/tegra/plane.c
> @@ -319,11 +319,13 @@ int tegra_plane_state_add(struct tegra_plane *plane,
> return 0;
> }
>
> -int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
> +int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap, bool *swap_uv)
> {
> /* assume no swapping of fetched data */
> if (swap)
> *swap = BYTE_SWAP_NOSWAP;
> + if (swap_uv)
> + *swap_uv = false;
>
> switch (fourcc) {
> case DRM_FORMAT_ARGB4444:
> diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h
> index e33a581e6490e..dba5f1b254e98 100644
> --- a/drivers/gpu/drm/tegra/plane.h
> +++ b/drivers/gpu/drm/tegra/plane.h
> @@ -49,6 +49,7 @@ struct tegra_plane_state {
> struct tegra_bo_tiling tiling;
> u32 format;
> u32 swap;
> + bool swap_uv;
>
> bool reflect_x;
> bool reflect_y;
> @@ -88,7 +89,7 @@ void tegra_plane_cleanup_fb(struct drm_plane *plane,
> int tegra_plane_state_add(struct tegra_plane *plane,
> struct drm_plane_state *state);
>
> -int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
> +int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap, bool *swap_uv);
> bool tegra_plane_format_is_indexed(unsigned int format);
> 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,
>
> --
> 2.54.0
>
>
>
next prev parent reply other threads:[~2026-10-09 9:00 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 20:57 [PATCH 0/2] drm/tegra: Support YVU420 Aaron Kling via B4 Relay
2026-10-08 20:57 ` [PATCH 1/2] drm/tegra: Support swapping chroma planes Aaron Kling via B4 Relay
2026-10-09 8:59 ` Mikko Perttunen [this message]
2026-10-09 9:03 ` Mikko Perttunen
2026-10-08 20:57 ` [PATCH 2/2] drm/tegra: Support YVU420 Aaron Kling via B4 Relay
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=qEporZZOT_abKwO4JObFpQ@nvidia.com \
--to=mperttunen@nvidia.com \
--cc=airlied@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=jonathanh@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=thierry.reding@kernel.org \
--cc=webgeek1234@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®