From 2777ad050a50091f189df9e1a71b3e6412568890 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 10 Dec 2025 09:52:23 +0100 Subject: [PATCH] drm/ast: Swap framebuffer writes on big-endian machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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 little-endian framebuffers after AST2400, although the feature has been documented. There's a lengthy discussion at [1]. Signed-off-by: Thomas Zimmermann Co-developed-by: René Rebe Link: https://lore.kernel.org/dri-devel/20251202.170626.2134482663677806825.rene@exactco.de/ # [1] --- drivers/gpu/drm/ast/ast_cursor.c | 27 +++++++++++++++++++++------ drivers/gpu/drm/ast/ast_mode.c | 11 +++++++++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c index 30b62d3f0151..02e019eb97c5 100644 --- a/drivers/gpu/drm/ast/ast_cursor.c +++ b/drivers/gpu/drm/ast/ast_cursor.c @@ -90,23 +90,37 @@ static u32 ast_cursor_calculate_checksum(const void *src, unsigned int width, un } static void ast_set_cursor_image(struct ast_device *ast, const u8 *src, - unsigned int width, unsigned int height) + unsigned int width, unsigned int height, + struct drm_format_conv_state *fmtcnv_state) { 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 */ - memcpy_toio(dst, src, AST_HWC_SIZE); +#if defined(__BIG_ENDIAN) + unsigned int i; + + for (i = 0; i < AST_HWC_SIZE; i += 2) + writew(swab16(*(const __be16 *)&src[i]), &dst[i]); + dst += AST_HWC_SIZE; /* write checksum + signature */ + writel(swab32(csum), dst); + writel(swab32(width), dst + AST_HWC_SIGNATURE_SizeX); + writel(swab32(height), dst + AST_HWC_SIGNATURE_SizeY); + writel(swab32(0), dst + AST_HWC_SIGNATURE_HOTSPOTX); + writel(swab32(0), dst + AST_HWC_SIGNATURE_HOTSPOTY); +#else + memcpy_toio(dst, src, AST_HWC_SIZE); dst += AST_HWC_SIZE; + + /* write checksum + signature */ writel(csum, dst); writel(width, dst + AST_HWC_SIGNATURE_SizeX); writel(height, dst + AST_HWC_SIGNATURE_SizeY); writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX); writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY); +#endif } static void ast_set_cursor_base(struct ast_device *ast, u64 address) @@ -267,7 +281,8 @@ static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, &damage); if (argb4444) - ast_set_cursor_image(ast, argb4444, fb->width, fb->height); + ast_set_cursor_image(ast, argb4444, fb->width, fb->height, + &shadow_plane_state->fmtcnv_state); ast_set_cursor_base(ast, dst_off); } diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index cd08990a10f9..57c6fbc3232b 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.52.0