[PATCH 2/2] drm/ast: Fix framebuffer color swapping on ppc64 systems

Thomas Zimmermann tzimmermann at suse.de
Fri Nov 21 19:13:02 AEDT 2025


Hi

Am 17.10.25 um 20:18 schrieb Timothy Pearson:
> On certain big endian systems, such as the POWER9 operating in big endian
> mode, PCI MMIO BAR accesses are transparently endian-swapped by hardware.
> On the AST2xx0 series devices, this results in the little endian framebuffer
> appearing to the host as a big endian device, resulting in unwanted color
> swapping.
>
> Furthermore, per ASpeed technical support, the big endian mode on these devices
> is not supported and, per Raptor's internal testing, does not function at a
> hardware level.
>
> Detect transparent PCI swapping via CONFIG_PCI_ARCH_ENDIAN_AUTOSWAP, and
> expose the framebuffer as a big endian device with software swapping.
>
> Tested on a POWER9 Blackbird system with Debian sid/ppc64.
>
> Signed-off-by: Timothy Pearson <tpearson at raptorengineering.com>
> ---
>   drivers/gpu/drm/ast/ast_mode.c | 33 +++++++++++++++++++++++++++++++--
>   1 file changed, 31 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
> index 30b011ed0a05..07f04668ef92 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -105,9 +105,11 @@ static void ast_crtc_fill_gamma(struct ast_device *ast,
>   		drm_crtc_fill_palette_8(crtc, ast_set_gamma_lut);
>   		break;
>   	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_HOST_RGB565:
>   		/* also uses 8-bit gamma ramp on low-color modes */
>   		fallthrough;
>   	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_HOST_XRGB8888:
>   		drm_crtc_fill_gamma_888(crtc, ast_set_gamma_lut);
>   		break;
>   	default:
> @@ -129,9 +131,11 @@ static void ast_crtc_load_gamma(struct ast_device *ast,
>   		drm_crtc_load_palette_8(crtc, lut, ast_set_gamma_lut);
>   		break;
>   	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_HOST_RGB565:
>   		/* also uses 8-bit gamma ramp on low-color modes */
>   		fallthrough;
>   	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_HOST_XRGB8888:
>   		drm_crtc_load_gamma_888(crtc, lut, ast_set_gamma_lut);
>   		break;
>   	default:
> @@ -502,8 +506,13 @@ void __iomem *ast_plane_vaddr(struct ast_plane *ast_plane)
>    */
>   
>   static const uint32_t ast_primary_plane_formats[] = {
> +#if defined(__BIG_ENDIAN) && defined(CONFIG_PCI_ARCH_ENDIAN_AUTOSWAP)
> +	DRM_FORMAT_HOST_XRGB8888,
> +	DRM_FORMAT_HOST_RGB565,
> +#else
>   	DRM_FORMAT_XRGB8888,
>   	DRM_FORMAT_RGB565,
> +#endif
>   	DRM_FORMAT_C8,
>   };
>   
> @@ -541,12 +550,24 @@ 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) && defined(CONFIG_PCI_ARCH_ENDIAN_AUTOSWAP)
> +	switch (fb->format->format) {
> +		case DRM_FORMAT_HOST_XRGB8888:
> +		case DRM_FORMAT_HOST_RGB565:
> +			drm_fb_swab(&dst, fb->pitches, src, fb, clip, false, fmtcnv_state);

DRM formats are always little endian. I'm not sure if most user space 
even supports anything else.  Can we just drop the whole _FORMAT_HOST_ 
formats and do a swap here if we're on BE PPC64?

Best regards
Thomas

> +			break;
> +		default:
> +			drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);
> +	}
> +#else
>   	drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);
> +#endif
>   }
>   
>   static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
> @@ -574,7 +595,7 @@ static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
>   
>   	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);
>   	}
>   
>   	/*
> @@ -766,10 +787,13 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
>   		ast_state->std_table = &vbios_stdtable[VGAModeIndex];
>   		break;
>   	case DRM_FORMAT_RGB565:
> +	case DRM_FORMAT_HOST_RGB565:
>   		ast_state->std_table = &vbios_stdtable[HiCModeIndex];
>   		break;
>   	case DRM_FORMAT_RGB888:
> +	case DRM_FORMAT_BGR888:
>   	case DRM_FORMAT_XRGB8888:
> +	case DRM_FORMAT_HOST_XRGB8888:
>   		ast_state->std_table = &vbios_stdtable[TrueCModeIndex];
>   		break;
>   	default:
> @@ -978,7 +1002,11 @@ static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs =
>   static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev,
>   						       const struct drm_display_mode *mode)
>   {
> +#if defined(__BIG_ENDIAN) && defined(CONFIG_PCI_ARCH_ENDIAN_AUTOSWAP)
> +	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_HOST_XRGB8888);
> +#else
>   	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB8888);
> +#endif
>   	struct ast_device *ast = to_ast_device(dev);
>   	unsigned long max_fb_size = ast_fb_vram_size(ast);
>   	u64 pitch;
> @@ -1021,6 +1049,7 @@ int ast_mode_config_init(struct ast_device *ast)
>   	dev->mode_config.min_width = 0;
>   	dev->mode_config.min_height = 0;
>   	dev->mode_config.preferred_depth = 24;
> +	dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
>   
>   	if (ast->support_fullhd) {
>   		dev->mode_config.max_width = 1920;

-- 
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich, (HRB 36809, AG Nürnberg)




More information about the Linuxppc-dev mailing list