From 50c26c301c5176cc8b431044390e10ec862b9b77 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ren=C3=A9=20Rebe?= Date: Fri, 12 Dec 2025 21:05:04 +0100 Subject: [PATCH] drm/ast: Swap framebuffer writes on big-endian machines MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Swap the pixel data when writing to framebuffer memory on big-endian machines. Fixes incorrect output. Aspeed graphics does not appear to support big-endian framebuffers after AST2400, although the feature has been documented. There's a lengthy discussion at [1]. v5: - avoid restricted cast from __be16 (kernel test robot) Signed-off-by: René Rebe Link: https://lore.kernel.org/dri-devel/20251202.170626.2134482663677806825.rene@exactco.de/ # [1] Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patch.msgid.link/20251212.210504.1355099120650239629.rene@exactco.de --- drivers/gpu/drm/ast/ast_cursor.c | 11 ++++++++--- drivers/gpu/drm/ast/ast_mode.c | 11 +++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c index 30b62d3f01513..3fa8e75db9c05 100644 --- a/drivers/gpu/drm/ast/ast_cursor.c +++ b/drivers/gpu/drm/ast/ast_cursor.c @@ -93,12 +93,17 @@ static void ast_set_cursor_image(struct ast_device *ast, const u8 *src, unsigned int width, unsigned int height) { u8 __iomem *dst = ast_plane_vaddr(&ast->cursor_plane.base); - u32 csum; - - csum = ast_cursor_calculate_checksum(src, width, height); + u32 csum = ast_cursor_calculate_checksum(src, width, height); /* write pixel data */ +#if defined(__BIG_ENDIAN) + unsigned int i; + + for (i = 0; i < AST_HWC_SIZE; i += 2) + writew(swab16(*(const __u16 *)&src[i]), &dst[i]); +#else memcpy_toio(dst, src, AST_HWC_SIZE); +#endif /* write checksum + signature */ dst += AST_HWC_SIZE; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index cd08990a10f93..57c6fbc3232b0 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -526,12 +526,18 @@ static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src, struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, + struct drm_format_conv_state *fmtcnv_state) { struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(ast_plane_vaddr(ast_plane)); iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); + +#if defined(__BIG_ENDIAN) + drm_fb_swab(&dst, fb->pitches, src, fb, clip, !src[0].is_iomem, fmtcnv_state); +#else drm_fb_memcpy(&dst, fb->pitches, src, fb, clip); +#endif } static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, @@ -561,7 +567,8 @@ static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) { drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); drm_atomic_for_each_plane_damage(&iter, &damage) { - ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage); + ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage, + &shadow_plane_state->fmtcnv_state); } drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); -- 2.47.3