diff mbox series

[v9,2/9] drm/format-helper: Add drm_fb_blit_from_r1 and drm_fb_fill

Message ID 20240307091936.576689-3-jfalempe@redhat.com (mailing list archive)
State New, archived
Headers show
Series drm/panic: Add a drm panic handler | expand

Commit Message

Jocelyn Falempe March 7, 2024, 9:14 a.m. UTC
This is needed for drm_panic, to draw the font, and fill
the background color, in multiple color format.

v5:
 * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
 * Also add drm_fb_fill() to fill area with background color.
v6:
 * fix __le32 conversion warning found by the kernel test bot

Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
---
 drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
 include/drm/drm_format_helper.h     |   9 +
 2 files changed, 360 insertions(+), 81 deletions(-)

Comments

Thomas Zimmermann March 7, 2024, 2:08 p.m. UTC | #1
Hi

Am 07.03.24 um 10:14 schrieb Jocelyn Falempe:
> This is needed for drm_panic, to draw the font, and fill
> the background color, in multiple color format.

As you know, I'm not happy about this patch and the the changes do not 
reflect my easier review. These format helpers are supposed to serve all 
of DRM and not just the panic handler. I know that the current code 
isn't perfect, but the R1 support is a step backwards IMHO.

I suggest to the drawing routines entirely within the panic-handler code 
and maybe try to sort out things later. IIRC that's how it was in 
earlier revisions of the patchset.

Best regards
Thomas

>
> v5:
>   * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
>   * Also add drm_fb_fill() to fill area with background color.
> v6:
>   * fix __le32 conversion warning found by the kernel test bot
>
> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
> ---
>   drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
>   include/drm/drm_format_helper.h     |   9 +
>   2 files changed, 360 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
> index b1be458ed4dd..2d9646cefc4f 100644
> --- a/drivers/gpu/drm/drm_format_helper.c
> +++ b/drivers/gpu/drm/drm_format_helper.c
> @@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct drm_format_conv_state *state)
>   }
>   EXPORT_SYMBOL(drm_format_conv_state_release);
>   
> +static __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
> +{
> +	u16 val16;
> +	u32 pix;
> +
> +	pix = le32_to_cpu(val32);
> +	val16 = ((pix & 0x00F80000) >> 8) |
> +		((pix & 0x0000FC00) >> 5) |
> +		((pix & 0x000000F8) >> 3);
> +	return cpu_to_le16(val16);
> +}
> +
> +static __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
> +{
> +	u16 val16;
> +	u32 pix;
> +
> +	pix = le32_to_cpu(val32);
> +	val16 = ((pix & 0x00f80000) >> 8) |
> +		((pix & 0x0000f800) >> 5) |
> +		((pix & 0x000000f8) >> 2) |
> +		BIT(0); /* set alpha bit */
> +	return cpu_to_le16(val16);
> +}
> +
> +static __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
> +{
> +	u16 val16;
> +	u32 pix;
> +
> +	pix = le32_to_cpu(val32);
> +	val16 = ((pix & 0x00f80000) >> 9) |
> +		((pix & 0x0000f800) >> 6) |
> +		((pix & 0x000000f8) >> 3);
> +	return cpu_to_le16(val16);
> +}
> +
> +static __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
> +{
> +	u16 val16;
> +	u32 pix;
> +
> +	pix = le32_to_cpu(val32);
> +	val16 = BIT(15) | /* set alpha bit */
> +		((pix & 0x00f80000) >> 9) |
> +		((pix & 0x0000f800) >> 6) |
> +		((pix & 0x000000f8) >> 3);
> +	return cpu_to_le16(val16);
> +}
> +
> +static __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
> +{
> +	u32 val32;
> +
> +	val32 = le32_to_cpu(pix);
> +	val32 |= GENMASK(31, 24); /* fill alpha bits */
> +	return cpu_to_le32(val32);
> +}
> +
> +static __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
> +{
> +	u32 val32;
> +
> +	val32 = le32_to_cpu(pix);
> +	val32 = ((val32 & 0x00ff0000) >> 16) <<  0 |
> +		((val32 & 0x0000ff00) >>  8) <<  8 |
> +		((val32 & 0x000000ff) >>  0) << 16 |
> +		((val32 & 0xff000000) >> 24) << 24;
> +	return cpu_to_le32(val32);
> +}
> +
> +static __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
> +{
> +	u32 val32;
> +
> +	val32 = le32_to_cpu(pix);
> +	val32 = ((val32 & 0x00ff0000) >> 16) <<  0 |
> +		((val32 & 0x0000ff00) >>  8) <<  8 |
> +		((val32 & 0x000000ff) >>  0) << 16 |
> +		GENMASK(31, 24); /* fill alpha bits */
> +	return cpu_to_le32(val32);
> +}
> +
> +static __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
> +{
> +	u32 val32;
> +
> +	val32 = le32_to_cpu(pix);
> +	val32 = ((val32 & 0x000000FF) << 2) |
> +		((val32 & 0x0000FF00) << 4) |
> +		((val32 & 0x00FF0000) << 6);
> +	return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
> +}
> +
> +static __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
> +{
> +	u32 val32;
> +
> +	val32 = le32_to_cpu(pix);
> +	val32 = ((val32 & 0x000000FF) << 2) |
> +		((val32 & 0x0000FF00) << 4) |
> +		((val32 & 0x00FF0000) << 6);
> +	val32 = GENMASK(31, 30) | /* set alpha bits */
> +	      val32 | ((val32 >> 8) & 0x00300c03);
> +	return cpu_to_le32(val32);
> +}
> +
> +/**
> + * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format
> + * @color: input color, in xrgb8888 format
> + * @format: output format
> + *
> + * Returns:
> + * Color in the format specified, casted to u32.
> + * Or 0 if the format is unknown.
> + */
> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
> +{
> +	__le32 pix = cpu_to_le32(color);
> +
> +	switch (format) {
> +	case DRM_FORMAT_RGB565:
> +		return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
> +	case DRM_FORMAT_RGBA5551:
> +		return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
> +	case DRM_FORMAT_XRGB1555:
> +		return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
> +	case DRM_FORMAT_ARGB1555:
> +		return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
> +	case DRM_FORMAT_RGB888:
> +	case DRM_FORMAT_XRGB8888:
> +		return le32_to_cpu(pix);
> +	case DRM_FORMAT_ARGB8888:
> +		return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
> +	case DRM_FORMAT_XBGR8888:
> +		return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
> +	case DRM_FORMAT_XRGB2101010:
> +		return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
> +	case DRM_FORMAT_ARGB2101010:
> +		return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
> +	default:
> +		WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
> +		return 0;
> +	}
> +}
> +EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
> +
>   static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
>   {
>   	return clip->y1 * pitch + clip->x1 * cpp;
> @@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
>   }
>   EXPORT_SYMBOL(drm_fb_swab);
>   
> +static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int dpitch,
> +			       const u8 *sbuf8, unsigned int spitch,
> +			       unsigned int height, unsigned int width,
> +			       __le16 fg16, __le16 bg16)
> +{
> +	unsigned int l, x;
> +	__le16 val16;
> +
> +	for (l = 0; l < height; l++) {
> +		for (x = 0; x < width; x++) {
> +			val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16;
> +			iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, le16_to_cpu(val16));
> +		}
> +	}
> +}
> +
> +static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int dpitch,
> +			       const u8 *sbuf8, unsigned int spitch,
> +			       unsigned int height, unsigned int width,
> +			       __le32 fg32, __le32 bg32)
> +{
> +	unsigned int l, x;
> +	__le32 color;
> +	u32 val32;
> +
> +	for (l = 0; l < height; l++) {
> +		for (x = 0; x < width; x++) {
> +			u32 off = l * dpitch + x * 3;
> +
> +			color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
> +			val32 = le32_to_cpu(color);
> +
> +			/* write blue-green-red to output in little endianness */
> +			iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
> +			iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
> +			iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
> +		}
> +	}
> +}
> +
> +static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int dpitch,
> +			       const u8 *sbuf8, unsigned int spitch,
> +			       unsigned int height, unsigned int width,
> +			       __le32 fg32, __le32 bg32)
> +{
> +	unsigned int l, x;
> +	__le32 val32;
> +
> +	for (l = 0; l < height; l++) {
> +		for (x = 0; x < width; x++) {
> +			val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
> +			iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, le32_to_cpu(val32));
> +		}
> +	}
> +}
> +
> +/**
> + * drm_fb_blit_from_r1 - convert a monochrome image to a linear framebuffer
> + * @dmap: destination iosys_map
> + * @dpitch: destination pitch in bytes
> + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
> + * @spitch: source pitch in bytes
> + * @height: height of the image to copy, in pixels
> + * @width: width of the image to copy, in pixels
> + * @fg_color: foreground color, in destination format
> + * @bg_color: background color, in destination format
> + * @pixel_width: pixel width in bytes.
> + *
> + * This can be used to draw font which are monochrome images, to a framebuffer
> + * in other supported format.
> + */
> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
> +			 const u8 *sbuf8, unsigned int spitch,
> +			 unsigned int height, unsigned int width,
> +			 u32 fg_color, u32 bg_color,
> +			 unsigned int pixel_width)
> +{
> +	switch (pixel_width) {
> +	case 2:
> +		drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
> +				   height, width,
> +				   cpu_to_le16(fg_color),
> +				   cpu_to_le16(bg_color));
> +	break;
> +	case 3:
> +		drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
> +				   height, width,
> +				   cpu_to_le32(fg_color),
> +				   cpu_to_le32(bg_color));
> +	break;
> +	case 4:
> +		drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
> +				   height, width,
> +				   cpu_to_le32(fg_color),
> +				   cpu_to_le32(bg_color));
> +	break;
> +	default:
> +		WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
> +	}
> +}
> +EXPORT_SYMBOL(drm_fb_blit_from_r1);
> +
> +static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
> +			 unsigned int height, unsigned int width,
> +			 u8 color)
> +{
> +	unsigned int l, x;
> +
> +	for (l = 0; l < height; l++)
> +		for (x = 0; x < width; x++)
> +			iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
> +}
> +
> +static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
> +			  unsigned int height, unsigned int width,
> +			  u16 color)
> +{
> +	unsigned int l, x;
> +
> +	for (l = 0; l < height; l++)
> +		for (x = 0; x < width; x++)
> +			iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, color);
> +}
> +
> +static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
> +			  unsigned int height, unsigned int width,
> +			  u32 color)
> +{
> +	unsigned int l, x;
> +
> +	for (l = 0; l < height; l++) {
> +		for (x = 0; x < width; x++) {
> +			unsigned int off = l * dpitch + x * 3;
> +
> +			/* write blue-green-red to output in little endianness */
> +			iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
> +			iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
> +			iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
> +		}
> +	}
> +}
> +
> +static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
> +			  unsigned int height, unsigned int width,
> +			  u32 color)
> +{
> +	unsigned int l, x;
> +
> +	for (l = 0; l < height; l++)
> +		for (x = 0; x < width; x++)
> +			iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, color);
> +}
> +
> +/**
> + * drm_fb_fill - Fill a rectangle with a color
> + * @dmap: destination iosys_map, pointing to the top left corner of the rectangle
> + * @dpitch: destination pitch in bytes
> + * @height: height of the rectangle, in pixels
> + * @width: width of the rectangle, in pixels
> + * @color: color to fill the rectangle.
> + * @pixel_width: pixel width in bytes
> + *
> + * Fill a rectangle with a color, in a linear framebuffer.
> + */
> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
> +			 unsigned int height, unsigned int width,
> +			 u32 color, unsigned int pixel_width)
> +{
> +	switch (pixel_width) {
> +	case 1:
> +		drm_fb_fill8(dmap, dpitch, height, width, color);
> +	break;
> +	case 2:
> +		drm_fb_fill16(dmap, dpitch, height, width, color);
> +	break;
> +	case 3:
> +		drm_fb_fill24(dmap, dpitch, height, width, color);
> +	break;
> +	case 4:
> +		drm_fb_fill32(dmap, dpitch, height, width, color);
> +	break;
> +	default:
> +		WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
> +	}
> +}
> +EXPORT_SYMBOL(drm_fb_fill);
> +
>   static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
>   {
>   	u8 *dbuf8 = dbuf;
> @@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
>   	__le16 *dbuf16 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u16 val16;
> -	u32 pix;
>   
>   	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		val16 = ((pix & 0x00F80000) >> 8) |
> -			((pix & 0x0000FC00) >> 5) |
> -			((pix & 0x000000F8) >> 3);
> -		dbuf16[x] = cpu_to_le16(val16);
> +		dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
>   	}
>   }
>   
> @@ -498,16 +826,9 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
>   	__le16 *dbuf16 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u16 val16;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		val16 = ((pix & 0x00f80000) >> 9) |
> -			((pix & 0x0000f800) >> 6) |
> -			((pix & 0x000000f8) >> 3);
> -		dbuf16[x] = cpu_to_le16(val16);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
>   }
>   
>   /**
> @@ -550,17 +871,9 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
>   	__le16 *dbuf16 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u16 val16;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		val16 = BIT(15) | /* set alpha bit */
> -			((pix & 0x00f80000) >> 9) |
> -			((pix & 0x0000f800) >> 6) |
> -			((pix & 0x000000f8) >> 3);
> -		dbuf16[x] = cpu_to_le16(val16);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
>   }
>   
>   /**
> @@ -603,17 +916,9 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
>   	__le16 *dbuf16 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u16 val16;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		val16 = ((pix & 0x00f80000) >> 8) |
> -			((pix & 0x0000f800) >> 5) |
> -			((pix & 0x000000f8) >> 2) |
> -			BIT(0); /* set alpha bit */
> -		dbuf16[x] = cpu_to_le16(val16);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
>   }
>   
>   /**
> @@ -707,13 +1012,9 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
>   	__le32 *dbuf32 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		pix |= GENMASK(31, 24); /* fill alpha bits */
> -		dbuf32[x] = cpu_to_le32(pix);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
>   }
>   
>   /**
> @@ -756,16 +1057,9 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
>   	__le32 *dbuf32 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		pix = ((pix & 0x00ff0000) >> 16) <<  0 |
> -		      ((pix & 0x0000ff00) >>  8) <<  8 |
> -		      ((pix & 0x000000ff) >>  0) << 16 |
> -		      GENMASK(31, 24); /* fill alpha bits */
> -		*dbuf32++ = cpu_to_le32(pix);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		*dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
>   }
>   
>   static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
> @@ -787,16 +1081,9 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
>   	__le32 *dbuf32 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		pix = ((pix & 0x00ff0000) >> 16) <<  0 |
> -		      ((pix & 0x0000ff00) >>  8) <<  8 |
> -		      ((pix & 0x000000ff) >>  0) << 16 |
> -		      ((pix & 0xff000000) >> 24) << 24;
> -		*dbuf32++ = cpu_to_le32(pix);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		*dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
>   }
>   
>   static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
> @@ -818,17 +1105,9 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
>   	__le32 *dbuf32 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u32 val32;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		val32 = ((pix & 0x000000FF) << 2) |
> -			((pix & 0x0000FF00) << 4) |
> -			((pix & 0x00FF0000) << 6);
> -		pix = val32 | ((val32 >> 8) & 0x00300C03);
> -		*dbuf32++ = cpu_to_le32(pix);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		*dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
>   }
>   
>   /**
> @@ -872,18 +1151,9 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
>   	__le32 *dbuf32 = dbuf;
>   	const __le32 *sbuf32 = sbuf;
>   	unsigned int x;
> -	u32 val32;
> -	u32 pix;
>   
> -	for (x = 0; x < pixels; x++) {
> -		pix = le32_to_cpu(sbuf32[x]);
> -		val32 = ((pix & 0x000000ff) << 2) |
> -			((pix & 0x0000ff00) << 4) |
> -			((pix & 0x00ff0000) << 6);
> -		pix = GENMASK(31, 30) | /* set alpha bits */
> -		      val32 | ((val32 >> 8) & 0x00300c03);
> -		*dbuf32++ = cpu_to_le32(pix);
> -	}
> +	for (x = 0; x < pixels; x++)
> +		*dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
>   }
>   
>   /**
> diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
> index f13b34e0b752..f416f0bef52d 100644
> --- a/include/drm/drm_format_helper.h
> +++ b/include/drm/drm_format_helper.h
> @@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
>   				    size_t new_size, gfp_t flags);
>   void drm_format_conv_state_release(struct drm_format_conv_state *state);
>   
> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
>   unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
>   				const struct drm_rect *clip);
>   
> @@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
>   		 const struct iosys_map *src, const struct drm_framebuffer *fb,
>   		 const struct drm_rect *clip, bool cached,
>   		 struct drm_format_conv_state *state);
> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
> +			 const u8 *sbuf8, unsigned int spitch,
> +			 unsigned int height, unsigned int width,
> +			 u32 fg_color, u32 bg_color,
> +			 unsigned int pixel_width);
> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
> +		 unsigned int height, unsigned int width,
> +		 u32 color, unsigned int pixel_width);
>   void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
>   			       const struct iosys_map *src, const struct drm_framebuffer *fb,
>   			       const struct drm_rect *clip, struct drm_format_conv_state *state);
Thomas Zimmermann March 7, 2024, 3:41 p.m. UTC | #2
Am 07.03.24 um 15:08 schrieb Thomas Zimmermann:
> Hi
>
> Am 07.03.24 um 10:14 schrieb Jocelyn Falempe:
>> This is needed for drm_panic, to draw the font, and fill
>> the background color, in multiple color format.
>
> As you know, I'm not happy about this patch and the the changes do not 
> reflect my easier

s/easier/earlier

> review. These format helpers are supposed to serve all of DRM and not 
> just the panic handler. I know that the current code isn't perfect, 
> but the R1 support is a step backwards IMHO.
>
> I suggest to the drawing routines entirely within the panic-handler 
> code and maybe try to sort out things later. IIRC that's how it was in 
> earlier revisions of the patchset.
>
> Best regards
> Thomas
>
>>
>> v5:
>>   * Change the drawing API, use drm_fb_blit_from_r1() to draw the font.
>>   * Also add drm_fb_fill() to fill area with background color.
>> v6:
>>   * fix __le32 conversion warning found by the kernel test bot
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
>> ---
>>   drivers/gpu/drm/drm_format_helper.c | 432 ++++++++++++++++++++++------
>>   include/drm/drm_format_helper.h     |   9 +
>>   2 files changed, 360 insertions(+), 81 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_format_helper.c 
>> b/drivers/gpu/drm/drm_format_helper.c
>> index b1be458ed4dd..2d9646cefc4f 100644
>> --- a/drivers/gpu/drm/drm_format_helper.c
>> +++ b/drivers/gpu/drm/drm_format_helper.c
>> @@ -111,6 +111,153 @@ void drm_format_conv_state_release(struct 
>> drm_format_conv_state *state)
>>   }
>>   EXPORT_SYMBOL(drm_format_conv_state_release);
>>   +static __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
>> +{
>> +    u16 val16;
>> +    u32 pix;
>> +
>> +    pix = le32_to_cpu(val32);
>> +    val16 = ((pix & 0x00F80000) >> 8) |
>> +        ((pix & 0x0000FC00) >> 5) |
>> +        ((pix & 0x000000F8) >> 3);
>> +    return cpu_to_le16(val16);
>> +}
>> +
>> +static __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
>> +{
>> +    u16 val16;
>> +    u32 pix;
>> +
>> +    pix = le32_to_cpu(val32);
>> +    val16 = ((pix & 0x00f80000) >> 8) |
>> +        ((pix & 0x0000f800) >> 5) |
>> +        ((pix & 0x000000f8) >> 2) |
>> +        BIT(0); /* set alpha bit */
>> +    return cpu_to_le16(val16);
>> +}
>> +
>> +static __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
>> +{
>> +    u16 val16;
>> +    u32 pix;
>> +
>> +    pix = le32_to_cpu(val32);
>> +    val16 = ((pix & 0x00f80000) >> 9) |
>> +        ((pix & 0x0000f800) >> 6) |
>> +        ((pix & 0x000000f8) >> 3);
>> +    return cpu_to_le16(val16);
>> +}
>> +
>> +static __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
>> +{
>> +    u16 val16;
>> +    u32 pix;
>> +
>> +    pix = le32_to_cpu(val32);
>> +    val16 = BIT(15) | /* set alpha bit */
>> +        ((pix & 0x00f80000) >> 9) |
>> +        ((pix & 0x0000f800) >> 6) |
>> +        ((pix & 0x000000f8) >> 3);
>> +    return cpu_to_le16(val16);
>> +}
>> +
>> +static __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
>> +{
>> +    u32 val32;
>> +
>> +    val32 = le32_to_cpu(pix);
>> +    val32 |= GENMASK(31, 24); /* fill alpha bits */
>> +    return cpu_to_le32(val32);
>> +}
>> +
>> +static __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
>> +{
>> +    u32 val32;
>> +
>> +    val32 = le32_to_cpu(pix);
>> +    val32 = ((val32 & 0x00ff0000) >> 16) <<  0 |
>> +        ((val32 & 0x0000ff00) >>  8) <<  8 |
>> +        ((val32 & 0x000000ff) >>  0) << 16 |
>> +        ((val32 & 0xff000000) >> 24) << 24;
>> +    return cpu_to_le32(val32);
>> +}
>> +
>> +static __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
>> +{
>> +    u32 val32;
>> +
>> +    val32 = le32_to_cpu(pix);
>> +    val32 = ((val32 & 0x00ff0000) >> 16) <<  0 |
>> +        ((val32 & 0x0000ff00) >>  8) <<  8 |
>> +        ((val32 & 0x000000ff) >>  0) << 16 |
>> +        GENMASK(31, 24); /* fill alpha bits */
>> +    return cpu_to_le32(val32);
>> +}
>> +
>> +static __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
>> +{
>> +    u32 val32;
>> +
>> +    val32 = le32_to_cpu(pix);
>> +    val32 = ((val32 & 0x000000FF) << 2) |
>> +        ((val32 & 0x0000FF00) << 4) |
>> +        ((val32 & 0x00FF0000) << 6);
>> +    return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
>> +}
>> +
>> +static __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
>> +{
>> +    u32 val32;
>> +
>> +    val32 = le32_to_cpu(pix);
>> +    val32 = ((val32 & 0x000000FF) << 2) |
>> +        ((val32 & 0x0000FF00) << 4) |
>> +        ((val32 & 0x00FF0000) << 6);
>> +    val32 = GENMASK(31, 30) | /* set alpha bits */
>> +          val32 | ((val32 >> 8) & 0x00300c03);
>> +    return cpu_to_le32(val32);
>> +}
>> +
>> +/**
>> + * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to 
>> the desired format
>> + * @color: input color, in xrgb8888 format
>> + * @format: output format
>> + *
>> + * Returns:
>> + * Color in the format specified, casted to u32.
>> + * Or 0 if the format is unknown.
>> + */
>> +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
>> +{
>> +    __le32 pix = cpu_to_le32(color);
>> +
>> +    switch (format) {
>> +    case DRM_FORMAT_RGB565:
>> +        return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
>> +    case DRM_FORMAT_RGBA5551:
>> +        return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
>> +    case DRM_FORMAT_XRGB1555:
>> +        return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
>> +    case DRM_FORMAT_ARGB1555:
>> +        return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
>> +    case DRM_FORMAT_RGB888:
>> +    case DRM_FORMAT_XRGB8888:
>> +        return le32_to_cpu(pix);
>> +    case DRM_FORMAT_ARGB8888:
>> +        return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
>> +    case DRM_FORMAT_XBGR8888:
>> +        return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
>> +    case DRM_FORMAT_XRGB2101010:
>> +        return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
>> +    case DRM_FORMAT_ARGB2101010:
>> +        return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
>> +    default:
>> +        WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
>> +        return 0;
>> +    }
>> +}
>> +EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
>> +
>>   static unsigned int clip_offset(const struct drm_rect *clip, 
>> unsigned int pitch, unsigned int cpp)
>>   {
>>       return clip->y1 * pitch + clip->x1 * cpp;
>> @@ -366,6 +513,193 @@ void drm_fb_swab(struct iosys_map *dst, const 
>> unsigned int *dst_pitch,
>>   }
>>   EXPORT_SYMBOL(drm_fb_swab);
>>   +static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned 
>> int dpitch,
>> +                   const u8 *sbuf8, unsigned int spitch,
>> +                   unsigned int height, unsigned int width,
>> +                   __le16 fg16, __le16 bg16)
>> +{
>> +    unsigned int l, x;
>> +    __le16 val16;
>> +
>> +    for (l = 0; l < height; l++) {
>> +        for (x = 0; x < width; x++) {
>> +            val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 
>> 8))) ? fg16 : bg16;
>> +            iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, 
>> le16_to_cpu(val16));
>> +        }
>> +    }
>> +}
>> +
>> +static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int 
>> dpitch,
>> +                   const u8 *sbuf8, unsigned int spitch,
>> +                   unsigned int height, unsigned int width,
>> +                   __le32 fg32, __le32 bg32)
>> +{
>> +    unsigned int l, x;
>> +    __le32 color;
>> +    u32 val32;
>> +
>> +    for (l = 0; l < height; l++) {
>> +        for (x = 0; x < width; x++) {
>> +            u32 off = l * dpitch + x * 3;
>> +
>> +            color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 
>> 8))) ? fg32 : bg32;
>> +            val32 = le32_to_cpu(color);
>> +
>> +            /* write blue-green-red to output in little endianness */
>> +            iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
>> +            iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
>> +            iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 
>> 16);
>> +        }
>> +    }
>> +}
>> +
>> +static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int 
>> dpitch,
>> +                   const u8 *sbuf8, unsigned int spitch,
>> +                   unsigned int height, unsigned int width,
>> +                   __le32 fg32, __le32 bg32)
>> +{
>> +    unsigned int l, x;
>> +    __le32 val32;
>> +
>> +    for (l = 0; l < height; l++) {
>> +        for (x = 0; x < width; x++) {
>> +            val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 
>> 8))) ? fg32 : bg32;
>> +            iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, 
>> le32_to_cpu(val32));
>> +        }
>> +    }
>> +}
>> +
>> +/**
>> + * drm_fb_blit_from_r1 - convert a monochrome image to a linear 
>> framebuffer
>> + * @dmap: destination iosys_map
>> + * @dpitch: destination pitch in bytes
>> + * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
>> + * @spitch: source pitch in bytes
>> + * @height: height of the image to copy, in pixels
>> + * @width: width of the image to copy, in pixels
>> + * @fg_color: foreground color, in destination format
>> + * @bg_color: background color, in destination format
>> + * @pixel_width: pixel width in bytes.
>> + *
>> + * This can be used to draw font which are monochrome images, to a 
>> framebuffer
>> + * in other supported format.
>> + */
>> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
>> +             const u8 *sbuf8, unsigned int spitch,
>> +             unsigned int height, unsigned int width,
>> +             u32 fg_color, u32 bg_color,
>> +             unsigned int pixel_width)
>> +{
>> +    switch (pixel_width) {
>> +    case 2:
>> +        drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
>> +                   height, width,
>> +                   cpu_to_le16(fg_color),
>> +                   cpu_to_le16(bg_color));
>> +    break;
>> +    case 3:
>> +        drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
>> +                   height, width,
>> +                   cpu_to_le32(fg_color),
>> +                   cpu_to_le32(bg_color));
>> +    break;
>> +    case 4:
>> +        drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
>> +                   height, width,
>> +                   cpu_to_le32(fg_color),
>> +                   cpu_to_le32(bg_color));
>> +    break;
>> +    default:
>> +        WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
>> +    }
>> +}
>> +EXPORT_SYMBOL(drm_fb_blit_from_r1);
>> +
>> +static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
>> +             unsigned int height, unsigned int width,
>> +             u8 color)
>> +{
>> +    unsigned int l, x;
>> +
>> +    for (l = 0; l < height; l++)
>> +        for (x = 0; x < width; x++)
>> +            iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
>> +}
>> +
>> +static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
>> +              unsigned int height, unsigned int width,
>> +              u16 color)
>> +{
>> +    unsigned int l, x;
>> +
>> +    for (l = 0; l < height; l++)
>> +        for (x = 0; x < width; x++)
>> +            iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, 
>> color);
>> +}
>> +
>> +static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
>> +              unsigned int height, unsigned int width,
>> +              u32 color)
>> +{
>> +    unsigned int l, x;
>> +
>> +    for (l = 0; l < height; l++) {
>> +        for (x = 0; x < width; x++) {
>> +            unsigned int off = l * dpitch + x * 3;
>> +
>> +            /* write blue-green-red to output in little endianness */
>> +            iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
>> +            iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
>> +            iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 
>> 16);
>> +        }
>> +    }
>> +}
>> +
>> +static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
>> +              unsigned int height, unsigned int width,
>> +              u32 color)
>> +{
>> +    unsigned int l, x;
>> +
>> +    for (l = 0; l < height; l++)
>> +        for (x = 0; x < width; x++)
>> +            iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, 
>> color);
>> +}
>> +
>> +/**
>> + * drm_fb_fill - Fill a rectangle with a color
>> + * @dmap: destination iosys_map, pointing to the top left corner of 
>> the rectangle
>> + * @dpitch: destination pitch in bytes
>> + * @height: height of the rectangle, in pixels
>> + * @width: width of the rectangle, in pixels
>> + * @color: color to fill the rectangle.
>> + * @pixel_width: pixel width in bytes
>> + *
>> + * Fill a rectangle with a color, in a linear framebuffer.
>> + */
>> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
>> +             unsigned int height, unsigned int width,
>> +             u32 color, unsigned int pixel_width)
>> +{
>> +    switch (pixel_width) {
>> +    case 1:
>> +        drm_fb_fill8(dmap, dpitch, height, width, color);
>> +    break;
>> +    case 2:
>> +        drm_fb_fill16(dmap, dpitch, height, width, color);
>> +    break;
>> +    case 3:
>> +        drm_fb_fill24(dmap, dpitch, height, width, color);
>> +    break;
>> +    case 4:
>> +        drm_fb_fill32(dmap, dpitch, height, width, color);
>> +    break;
>> +    default:
>> +        WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
>> +    }
>> +}
>> +EXPORT_SYMBOL(drm_fb_fill);
>> +
>>   static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void 
>> *sbuf, unsigned int pixels)
>>   {
>>       u8 *dbuf8 = dbuf;
>> @@ -420,15 +754,9 @@ static void drm_fb_xrgb8888_to_rgb565_line(void 
>> *dbuf, const void *sbuf, unsigne
>>       __le16 *dbuf16 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u16 val16;
>> -    u32 pix;
>>         for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        val16 = ((pix & 0x00F80000) >> 8) |
>> -            ((pix & 0x0000FC00) >> 5) |
>> -            ((pix & 0x000000F8) >> 3);
>> -        dbuf16[x] = cpu_to_le16(val16);
>> +        dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
>>       }
>>   }
>>   @@ -498,16 +826,9 @@ static void 
>> drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
>>       __le16 *dbuf16 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u16 val16;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        val16 = ((pix & 0x00f80000) >> 9) |
>> -            ((pix & 0x0000f800) >> 6) |
>> -            ((pix & 0x000000f8) >> 3);
>> -        dbuf16[x] = cpu_to_le16(val16);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
>>   }
>>     /**
>> @@ -550,17 +871,9 @@ static void 
>> drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
>>       __le16 *dbuf16 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u16 val16;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        val16 = BIT(15) | /* set alpha bit */
>> -            ((pix & 0x00f80000) >> 9) |
>> -            ((pix & 0x0000f800) >> 6) |
>> -            ((pix & 0x000000f8) >> 3);
>> -        dbuf16[x] = cpu_to_le16(val16);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
>>   }
>>     /**
>> @@ -603,17 +916,9 @@ static void 
>> drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
>>       __le16 *dbuf16 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u16 val16;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        val16 = ((pix & 0x00f80000) >> 8) |
>> -            ((pix & 0x0000f800) >> 5) |
>> -            ((pix & 0x000000f8) >> 2) |
>> -            BIT(0); /* set alpha bit */
>> -        dbuf16[x] = cpu_to_le16(val16);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
>>   }
>>     /**
>> @@ -707,13 +1012,9 @@ static void 
>> drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
>>       __le32 *dbuf32 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        pix |= GENMASK(31, 24); /* fill alpha bits */
>> -        dbuf32[x] = cpu_to_le32(pix);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
>>   }
>>     /**
>> @@ -756,16 +1057,9 @@ static void 
>> drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
>>       __le32 *dbuf32 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        pix = ((pix & 0x00ff0000) >> 16) <<  0 |
>> -              ((pix & 0x0000ff00) >>  8) <<  8 |
>> -              ((pix & 0x000000ff) >>  0) << 16 |
>> -              GENMASK(31, 24); /* fill alpha bits */
>> -        *dbuf32++ = cpu_to_le32(pix);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        *dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
>>   }
>>     static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, 
>> const unsigned int *dst_pitch,
>> @@ -787,16 +1081,9 @@ static void 
>> drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
>>       __le32 *dbuf32 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        pix = ((pix & 0x00ff0000) >> 16) <<  0 |
>> -              ((pix & 0x0000ff00) >>  8) <<  8 |
>> -              ((pix & 0x000000ff) >>  0) << 16 |
>> -              ((pix & 0xff000000) >> 24) << 24;
>> -        *dbuf32++ = cpu_to_le32(pix);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        *dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
>>   }
>>     static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, 
>> const unsigned int *dst_pitch,
>> @@ -818,17 +1105,9 @@ static void 
>> drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
>>       __le32 *dbuf32 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u32 val32;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        val32 = ((pix & 0x000000FF) << 2) |
>> -            ((pix & 0x0000FF00) << 4) |
>> -            ((pix & 0x00FF0000) << 6);
>> -        pix = val32 | ((val32 >> 8) & 0x00300C03);
>> -        *dbuf32++ = cpu_to_le32(pix);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        *dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
>>   }
>>     /**
>> @@ -872,18 +1151,9 @@ static void 
>> drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
>>       __le32 *dbuf32 = dbuf;
>>       const __le32 *sbuf32 = sbuf;
>>       unsigned int x;
>> -    u32 val32;
>> -    u32 pix;
>>   -    for (x = 0; x < pixels; x++) {
>> -        pix = le32_to_cpu(sbuf32[x]);
>> -        val32 = ((pix & 0x000000ff) << 2) |
>> -            ((pix & 0x0000ff00) << 4) |
>> -            ((pix & 0x00ff0000) << 6);
>> -        pix = GENMASK(31, 30) | /* set alpha bits */
>> -              val32 | ((val32 >> 8) & 0x00300c03);
>> -        *dbuf32++ = cpu_to_le32(pix);
>> -    }
>> +    for (x = 0; x < pixels; x++)
>> +        *dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
>>   }
>>     /**
>> diff --git a/include/drm/drm_format_helper.h 
>> b/include/drm/drm_format_helper.h
>> index f13b34e0b752..f416f0bef52d 100644
>> --- a/include/drm/drm_format_helper.h
>> +++ b/include/drm/drm_format_helper.h
>> @@ -66,6 +66,7 @@ void *drm_format_conv_state_reserve(struct 
>> drm_format_conv_state *state,
>>                       size_t new_size, gfp_t flags);
>>   void drm_format_conv_state_release(struct drm_format_conv_state 
>> *state);
>>   +u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
>>   unsigned int drm_fb_clip_offset(unsigned int pitch, const struct 
>> drm_format_info *format,
>>                   const struct drm_rect *clip);
>>   @@ -76,6 +77,14 @@ void drm_fb_swab(struct iosys_map *dst, const 
>> unsigned int *dst_pitch,
>>            const struct iosys_map *src, const struct drm_framebuffer 
>> *fb,
>>            const struct drm_rect *clip, bool cached,
>>            struct drm_format_conv_state *state);
>> +void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
>> +             const u8 *sbuf8, unsigned int spitch,
>> +             unsigned int height, unsigned int width,
>> +             u32 fg_color, u32 bg_color,
>> +             unsigned int pixel_width);
>> +void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
>> +         unsigned int height, unsigned int width,
>> +         u32 color, unsigned int pixel_width);
>>   void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const 
>> unsigned int *dst_pitch,
>>                      const struct iosys_map *src, const struct 
>> drm_framebuffer *fb,
>>                      const struct drm_rect *clip, struct 
>> drm_format_conv_state *state);
>
Jocelyn Falempe March 7, 2024, 5:12 p.m. UTC | #3
Hi,

On 07/03/2024 16:41, Thomas Zimmermann wrote:
> 
> 
> Am 07.03.24 um 15:08 schrieb Thomas Zimmermann:
>> Hi
>>
>> Am 07.03.24 um 10:14 schrieb Jocelyn Falempe:
>>> This is needed for drm_panic, to draw the font, and fill
>>> the background color, in multiple color format.
>>
>> As you know, I'm not happy about this patch and the the changes do not 
>> reflect my easier
> 
> s/easier/earlier
> 
>> review. These format helpers are supposed to serve all of DRM and not 
>> just the panic handler. I know that the current code isn't perfect, 
>> but the R1 support is a step backwards IMHO.
>>
>> I suggest to the drawing routines entirely within the panic-handler 
>> code and maybe try to sort out things later. IIRC that's how it was in 
>> earlier revisions of the patchset.

Sorry I didn't change this patch in v8 and v9, I was focusing on locking 
and the overall design.
I agree to move this back to drm_panic.c, so we can merge a first 
version of drm_panic. And when a generic format converter will be ready, 
I will do the patch to use it.

Best regards,
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c
index b1be458ed4dd..2d9646cefc4f 100644
--- a/drivers/gpu/drm/drm_format_helper.c
+++ b/drivers/gpu/drm/drm_format_helper.c
@@ -111,6 +111,153 @@  void drm_format_conv_state_release(struct drm_format_conv_state *state)
 }
 EXPORT_SYMBOL(drm_format_conv_state_release);
 
+static __le16 drm_format_xrgb8888_to_rgb565(__le32 val32)
+{
+	u16 val16;
+	u32 pix;
+
+	pix = le32_to_cpu(val32);
+	val16 = ((pix & 0x00F80000) >> 8) |
+		((pix & 0x0000FC00) >> 5) |
+		((pix & 0x000000F8) >> 3);
+	return cpu_to_le16(val16);
+}
+
+static __le16 drm_format_xrgb8888_to_rgba5551(__le32 val32)
+{
+	u16 val16;
+	u32 pix;
+
+	pix = le32_to_cpu(val32);
+	val16 = ((pix & 0x00f80000) >> 8) |
+		((pix & 0x0000f800) >> 5) |
+		((pix & 0x000000f8) >> 2) |
+		BIT(0); /* set alpha bit */
+	return cpu_to_le16(val16);
+}
+
+static __le16 drm_format_xrgb8888_to_xrgb1555(__le32 val32)
+{
+	u16 val16;
+	u32 pix;
+
+	pix = le32_to_cpu(val32);
+	val16 = ((pix & 0x00f80000) >> 9) |
+		((pix & 0x0000f800) >> 6) |
+		((pix & 0x000000f8) >> 3);
+	return cpu_to_le16(val16);
+}
+
+static __le16 drm_format_xrgb8888_to_argb1555(__le32 val32)
+{
+	u16 val16;
+	u32 pix;
+
+	pix = le32_to_cpu(val32);
+	val16 = BIT(15) | /* set alpha bit */
+		((pix & 0x00f80000) >> 9) |
+		((pix & 0x0000f800) >> 6) |
+		((pix & 0x000000f8) >> 3);
+	return cpu_to_le16(val16);
+}
+
+static __le32 drm_format_xrgb8888_to_argb8888(__le32 pix)
+{
+	u32 val32;
+
+	val32 = le32_to_cpu(pix);
+	val32 |= GENMASK(31, 24); /* fill alpha bits */
+	return cpu_to_le32(val32);
+}
+
+static __le32 drm_format_xrgb8888_to_xbgr8888(__le32 pix)
+{
+	u32 val32;
+
+	val32 = le32_to_cpu(pix);
+	val32 = ((val32 & 0x00ff0000) >> 16) <<  0 |
+		((val32 & 0x0000ff00) >>  8) <<  8 |
+		((val32 & 0x000000ff) >>  0) << 16 |
+		((val32 & 0xff000000) >> 24) << 24;
+	return cpu_to_le32(val32);
+}
+
+static __le32 drm_format_xrgb8888_to_abgr8888(__le32 pix)
+{
+	u32 val32;
+
+	val32 = le32_to_cpu(pix);
+	val32 = ((val32 & 0x00ff0000) >> 16) <<  0 |
+		((val32 & 0x0000ff00) >>  8) <<  8 |
+		((val32 & 0x000000ff) >>  0) << 16 |
+		GENMASK(31, 24); /* fill alpha bits */
+	return cpu_to_le32(val32);
+}
+
+static __le32 drm_format_xrgb8888_to_xrgb2101010(__le32 pix)
+{
+	u32 val32;
+
+	val32 = le32_to_cpu(pix);
+	val32 = ((val32 & 0x000000FF) << 2) |
+		((val32 & 0x0000FF00) << 4) |
+		((val32 & 0x00FF0000) << 6);
+	return cpu_to_le32(val32 | ((val32 >> 8) & 0x00300C03));
+}
+
+static __le32 drm_format_xrgb8888_to_argb2101010(__le32 pix)
+{
+	u32 val32;
+
+	val32 = le32_to_cpu(pix);
+	val32 = ((val32 & 0x000000FF) << 2) |
+		((val32 & 0x0000FF00) << 4) |
+		((val32 & 0x00FF0000) << 6);
+	val32 = GENMASK(31, 30) | /* set alpha bits */
+	      val32 | ((val32 >> 8) & 0x00300c03);
+	return cpu_to_le32(val32);
+}
+
+/**
+ * drm_fb_convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format
+ * @color: input color, in xrgb8888 format
+ * @format: output format
+ *
+ * Returns:
+ * Color in the format specified, casted to u32.
+ * Or 0 if the format is unknown.
+ */
+u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format)
+{
+	__le32 pix = cpu_to_le32(color);
+
+	switch (format) {
+	case DRM_FORMAT_RGB565:
+		return le16_to_cpu(drm_format_xrgb8888_to_rgb565(pix));
+	case DRM_FORMAT_RGBA5551:
+		return le16_to_cpu(drm_format_xrgb8888_to_rgba5551(pix));
+	case DRM_FORMAT_XRGB1555:
+		return le16_to_cpu(drm_format_xrgb8888_to_xrgb1555(pix));
+	case DRM_FORMAT_ARGB1555:
+		return le16_to_cpu(drm_format_xrgb8888_to_argb1555(pix));
+	case DRM_FORMAT_RGB888:
+	case DRM_FORMAT_XRGB8888:
+		return le32_to_cpu(pix);
+	case DRM_FORMAT_ARGB8888:
+		return le32_to_cpu(drm_format_xrgb8888_to_argb8888(pix));
+	case DRM_FORMAT_XBGR8888:
+		return le32_to_cpu(drm_format_xrgb8888_to_xbgr8888(pix));
+	case DRM_FORMAT_XRGB2101010:
+		return le32_to_cpu(drm_format_xrgb8888_to_xrgb2101010(pix));
+	case DRM_FORMAT_ARGB2101010:
+		return le32_to_cpu(drm_format_xrgb8888_to_argb2101010(pix));
+	default:
+		WARN_ONCE(1, "Can't convert to %p4cc\n", &format);
+		return 0;
+	}
+}
+EXPORT_SYMBOL(drm_fb_convert_from_xrgb8888);
+
 static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp)
 {
 	return clip->y1 * pitch + clip->x1 * cpp;
@@ -366,6 +513,193 @@  void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
 }
 EXPORT_SYMBOL(drm_fb_swab);
 
+static void drm_fb_r1_to_16bit(struct iosys_map *dmap, unsigned int dpitch,
+			       const u8 *sbuf8, unsigned int spitch,
+			       unsigned int height, unsigned int width,
+			       __le16 fg16, __le16 bg16)
+{
+	unsigned int l, x;
+	__le16 val16;
+
+	for (l = 0; l < height; l++) {
+		for (x = 0; x < width; x++) {
+			val16 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg16 : bg16;
+			iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, le16_to_cpu(val16));
+		}
+	}
+}
+
+static void drm_fb_r1_to_24bit(struct iosys_map *dmap, unsigned int dpitch,
+			       const u8 *sbuf8, unsigned int spitch,
+			       unsigned int height, unsigned int width,
+			       __le32 fg32, __le32 bg32)
+{
+	unsigned int l, x;
+	__le32 color;
+	u32 val32;
+
+	for (l = 0; l < height; l++) {
+		for (x = 0; x < width; x++) {
+			u32 off = l * dpitch + x * 3;
+
+			color = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
+			val32 = le32_to_cpu(color);
+
+			/* write blue-green-red to output in little endianness */
+			iosys_map_wr(dmap, off, u8, (val32 & 0x000000FF) >> 0);
+			iosys_map_wr(dmap, off + 1, u8, (val32 & 0x0000FF00) >> 8);
+			iosys_map_wr(dmap, off + 2, u8, (val32 & 0x00FF0000) >> 16);
+		}
+	}
+}
+
+static void drm_fb_r1_to_32bit(struct iosys_map *dmap, unsigned int dpitch,
+			       const u8 *sbuf8, unsigned int spitch,
+			       unsigned int height, unsigned int width,
+			       __le32 fg32, __le32 bg32)
+{
+	unsigned int l, x;
+	__le32 val32;
+
+	for (l = 0; l < height; l++) {
+		for (x = 0; x < width; x++) {
+			val32 = (sbuf8[(l * spitch) + x / 8] & (0x80 >> (x % 8))) ? fg32 : bg32;
+			iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, le32_to_cpu(val32));
+		}
+	}
+}
+
+/**
+ * drm_fb_blit_from_r1 - convert a monochrome image to a linear framebuffer
+ * @dmap: destination iosys_map
+ * @dpitch: destination pitch in bytes
+ * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
+ * @spitch: source pitch in bytes
+ * @height: height of the image to copy, in pixels
+ * @width: width of the image to copy, in pixels
+ * @fg_color: foreground color, in destination format
+ * @bg_color: background color, in destination format
+ * @pixel_width: pixel width in bytes.
+ *
+ * This can be used to draw font which are monochrome images, to a framebuffer
+ * in other supported format.
+ */
+void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
+			 const u8 *sbuf8, unsigned int spitch,
+			 unsigned int height, unsigned int width,
+			 u32 fg_color, u32 bg_color,
+			 unsigned int pixel_width)
+{
+	switch (pixel_width) {
+	case 2:
+		drm_fb_r1_to_16bit(dmap, dpitch, sbuf8, spitch,
+				   height, width,
+				   cpu_to_le16(fg_color),
+				   cpu_to_le16(bg_color));
+	break;
+	case 3:
+		drm_fb_r1_to_24bit(dmap, dpitch, sbuf8, spitch,
+				   height, width,
+				   cpu_to_le32(fg_color),
+				   cpu_to_le32(bg_color));
+	break;
+	case 4:
+		drm_fb_r1_to_32bit(dmap, dpitch, sbuf8, spitch,
+				   height, width,
+				   cpu_to_le32(fg_color),
+				   cpu_to_le32(bg_color));
+	break;
+	default:
+		WARN_ONCE(1, "Can't blit with pixel width %d\n", pixel_width);
+	}
+}
+EXPORT_SYMBOL(drm_fb_blit_from_r1);
+
+static void drm_fb_fill8(struct iosys_map *dmap, unsigned int dpitch,
+			 unsigned int height, unsigned int width,
+			 u8 color)
+{
+	unsigned int l, x;
+
+	for (l = 0; l < height; l++)
+		for (x = 0; x < width; x++)
+			iosys_map_wr(dmap, l * dpitch + x * sizeof(u8), u8, color);
+}
+
+static void drm_fb_fill16(struct iosys_map *dmap, unsigned int dpitch,
+			  unsigned int height, unsigned int width,
+			  u16 color)
+{
+	unsigned int l, x;
+
+	for (l = 0; l < height; l++)
+		for (x = 0; x < width; x++)
+			iosys_map_wr(dmap, l * dpitch + x * sizeof(u16), u16, color);
+}
+
+static void drm_fb_fill24(struct iosys_map *dmap, unsigned int dpitch,
+			  unsigned int height, unsigned int width,
+			  u32 color)
+{
+	unsigned int l, x;
+
+	for (l = 0; l < height; l++) {
+		for (x = 0; x < width; x++) {
+			unsigned int off = l * dpitch + x * 3;
+
+			/* write blue-green-red to output in little endianness */
+			iosys_map_wr(dmap, off, u8, (color & 0x000000FF) >> 0);
+			iosys_map_wr(dmap, off + 1, u8, (color & 0x0000FF00) >> 8);
+			iosys_map_wr(dmap, off + 2, u8, (color & 0x00FF0000) >> 16);
+		}
+	}
+}
+
+static void drm_fb_fill32(struct iosys_map *dmap, unsigned int dpitch,
+			  unsigned int height, unsigned int width,
+			  u32 color)
+{
+	unsigned int l, x;
+
+	for (l = 0; l < height; l++)
+		for (x = 0; x < width; x++)
+			iosys_map_wr(dmap, l * dpitch + x * sizeof(u32), u32, color);
+}
+
+/**
+ * drm_fb_fill - Fill a rectangle with a color
+ * @dmap: destination iosys_map, pointing to the top left corner of the rectangle
+ * @dpitch: destination pitch in bytes
+ * @height: height of the rectangle, in pixels
+ * @width: width of the rectangle, in pixels
+ * @color: color to fill the rectangle.
+ * @pixel_width: pixel width in bytes
+ *
+ * Fill a rectangle with a color, in a linear framebuffer.
+ */
+void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
+			 unsigned int height, unsigned int width,
+			 u32 color, unsigned int pixel_width)
+{
+	switch (pixel_width) {
+	case 1:
+		drm_fb_fill8(dmap, dpitch, height, width, color);
+	break;
+	case 2:
+		drm_fb_fill16(dmap, dpitch, height, width, color);
+	break;
+	case 3:
+		drm_fb_fill24(dmap, dpitch, height, width, color);
+	break;
+	case 4:
+		drm_fb_fill32(dmap, dpitch, height, width, color);
+	break;
+	default:
+		WARN_ONCE(1, "Can't fill with pixel width %d\n", pixel_width);
+	}
+}
+EXPORT_SYMBOL(drm_fb_fill);
+
 static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigned int pixels)
 {
 	u8 *dbuf8 = dbuf;
@@ -420,15 +754,9 @@  static void drm_fb_xrgb8888_to_rgb565_line(void *dbuf, const void *sbuf, unsigne
 	__le16 *dbuf16 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u16 val16;
-	u32 pix;
 
 	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		val16 = ((pix & 0x00F80000) >> 8) |
-			((pix & 0x0000FC00) >> 5) |
-			((pix & 0x000000F8) >> 3);
-		dbuf16[x] = cpu_to_le16(val16);
+		dbuf16[x] = drm_format_xrgb8888_to_rgb565(sbuf32[x]);
 	}
 }
 
@@ -498,16 +826,9 @@  static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig
 	__le16 *dbuf16 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u16 val16;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		val16 = ((pix & 0x00f80000) >> 9) |
-			((pix & 0x0000f800) >> 6) |
-			((pix & 0x000000f8) >> 3);
-		dbuf16[x] = cpu_to_le16(val16);
-	}
+	for (x = 0; x < pixels; x++)
+		dbuf16[x] = drm_format_xrgb8888_to_xrgb1555(sbuf32[x]);
 }
 
 /**
@@ -550,17 +871,9 @@  static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig
 	__le16 *dbuf16 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u16 val16;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		val16 = BIT(15) | /* set alpha bit */
-			((pix & 0x00f80000) >> 9) |
-			((pix & 0x0000f800) >> 6) |
-			((pix & 0x000000f8) >> 3);
-		dbuf16[x] = cpu_to_le16(val16);
-	}
+	for (x = 0; x < pixels; x++)
+		dbuf16[x] = drm_format_xrgb8888_to_argb1555(sbuf32[x]);
 }
 
 /**
@@ -603,17 +916,9 @@  static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig
 	__le16 *dbuf16 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u16 val16;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		val16 = ((pix & 0x00f80000) >> 8) |
-			((pix & 0x0000f800) >> 5) |
-			((pix & 0x000000f8) >> 2) |
-			BIT(0); /* set alpha bit */
-		dbuf16[x] = cpu_to_le16(val16);
-	}
+	for (x = 0; x < pixels; x++)
+		dbuf16[x] = drm_format_xrgb8888_to_rgba5551(sbuf32[x]);
 }
 
 /**
@@ -707,13 +1012,9 @@  static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig
 	__le32 *dbuf32 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		pix |= GENMASK(31, 24); /* fill alpha bits */
-		dbuf32[x] = cpu_to_le32(pix);
-	}
+	for (x = 0; x < pixels; x++)
+		dbuf32[x] = drm_format_xrgb8888_to_argb8888(sbuf32[x]);
 }
 
 /**
@@ -756,16 +1057,9 @@  static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig
 	__le32 *dbuf32 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		pix = ((pix & 0x00ff0000) >> 16) <<  0 |
-		      ((pix & 0x0000ff00) >>  8) <<  8 |
-		      ((pix & 0x000000ff) >>  0) << 16 |
-		      GENMASK(31, 24); /* fill alpha bits */
-		*dbuf32++ = cpu_to_le32(pix);
-	}
+	for (x = 0; x < pixels; x++)
+		*dbuf32++ = drm_format_xrgb8888_to_abgr8888(sbuf32[x]);
 }
 
 static void drm_fb_xrgb8888_to_abgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
@@ -787,16 +1081,9 @@  static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig
 	__le32 *dbuf32 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		pix = ((pix & 0x00ff0000) >> 16) <<  0 |
-		      ((pix & 0x0000ff00) >>  8) <<  8 |
-		      ((pix & 0x000000ff) >>  0) << 16 |
-		      ((pix & 0xff000000) >> 24) << 24;
-		*dbuf32++ = cpu_to_le32(pix);
-	}
+	for (x = 0; x < pixels; x++)
+		*dbuf32++ = drm_format_xrgb8888_to_xbgr8888(sbuf32[x]);
 }
 
 static void drm_fb_xrgb8888_to_xbgr8888(struct iosys_map *dst, const unsigned int *dst_pitch,
@@ -818,17 +1105,9 @@  static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un
 	__le32 *dbuf32 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u32 val32;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		val32 = ((pix & 0x000000FF) << 2) |
-			((pix & 0x0000FF00) << 4) |
-			((pix & 0x00FF0000) << 6);
-		pix = val32 | ((val32 >> 8) & 0x00300C03);
-		*dbuf32++ = cpu_to_le32(pix);
-	}
+	for (x = 0; x < pixels; x++)
+		*dbuf32++ = drm_format_xrgb8888_to_xrgb2101010(sbuf32[x]);
 }
 
 /**
@@ -872,18 +1151,9 @@  static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un
 	__le32 *dbuf32 = dbuf;
 	const __le32 *sbuf32 = sbuf;
 	unsigned int x;
-	u32 val32;
-	u32 pix;
 
-	for (x = 0; x < pixels; x++) {
-		pix = le32_to_cpu(sbuf32[x]);
-		val32 = ((pix & 0x000000ff) << 2) |
-			((pix & 0x0000ff00) << 4) |
-			((pix & 0x00ff0000) << 6);
-		pix = GENMASK(31, 30) | /* set alpha bits */
-		      val32 | ((val32 >> 8) & 0x00300c03);
-		*dbuf32++ = cpu_to_le32(pix);
-	}
+	for (x = 0; x < pixels; x++)
+		*dbuf32++ = drm_format_xrgb8888_to_argb2101010(sbuf32[x]);
 }
 
 /**
diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h
index f13b34e0b752..f416f0bef52d 100644
--- a/include/drm/drm_format_helper.h
+++ b/include/drm/drm_format_helper.h
@@ -66,6 +66,7 @@  void *drm_format_conv_state_reserve(struct drm_format_conv_state *state,
 				    size_t new_size, gfp_t flags);
 void drm_format_conv_state_release(struct drm_format_conv_state *state);
 
+u32 drm_fb_convert_from_xrgb8888(u32 color, u32 format);
 unsigned int drm_fb_clip_offset(unsigned int pitch, const struct drm_format_info *format,
 				const struct drm_rect *clip);
 
@@ -76,6 +77,14 @@  void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch,
 		 const struct iosys_map *src, const struct drm_framebuffer *fb,
 		 const struct drm_rect *clip, bool cached,
 		 struct drm_format_conv_state *state);
+void drm_fb_blit_from_r1(struct iosys_map *dmap, unsigned int dpitch,
+			 const u8 *sbuf8, unsigned int spitch,
+			 unsigned int height, unsigned int width,
+			 u32 fg_color, u32 bg_color,
+			 unsigned int pixel_width);
+void drm_fb_fill(struct iosys_map *dmap, unsigned int dpitch,
+		 unsigned int height, unsigned int width,
+		 u32 color, unsigned int pixel_width);
 void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch,
 			       const struct iosys_map *src, const struct drm_framebuffer *fb,
 			       const struct drm_rect *clip, struct drm_format_conv_state *state);