[PATCH v2 0/4] 30bpp framebuffer support

Apple M1 machines come up with a framebuffer that in 30bpp mode. This series adds basic support for this mode.
What I call 30bpp mode here is really a 32bpp mode with pixels where each color channel is 10 bits deep. To distinguish this mode from the "regular" 32bpp mode (where each channel is 8 bits deep) we need to keep track of the pixel format. In order to avoid having to update each and every video driver, I've introduced an "unknown" format that is the default, where the code continues to infer the pixel format from the bpp value.
Changelog:
v2: - Encode pixel format in favour of adding VIDEO_30BPP - Recognize more format strings in simplefb driver - Fix EFI block image transfer for 30bpp mode
Mark Kettenis (4): video: Add 30bpp support efi_loader: GOP: Add 30bpp support video: simplefb: Add 30bpp support efi_loader: GOP: Fix 30bpp block transfer support
drivers/video/simplefb.c | 12 +++++- drivers/video/vidconsole-uclass.c | 11 ++++-- include/video.h | 9 +++++ lib/efi_loader/efi_gop.c | 61 +++++++++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 7 deletions(-)

Add support for 30bpp mode where pixels are picked in 32-bit integers but use 10 bits instead of 8 bits for each component.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- drivers/video/vidconsole-uclass.c | 11 ++++++++--- include/video.h | 9 +++++++++ 2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 8132efa55a..f42db40d4c 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -155,9 +155,14 @@ u32 vid_console_color(struct video_priv *priv, unsigned int idx) break; case VIDEO_BPP32: if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { - return (colors[idx].r << 16) | - (colors[idx].g << 8) | - (colors[idx].b << 0); + if (priv->format == VIDEO_X2R10G10B10) + return (colors[idx].r << 22) | + (colors[idx].g << 12) | + (colors[idx].b << 2); + else + return (colors[idx].r << 16) | + (colors[idx].g << 8) | + (colors[idx].b << 0); } break; default: diff --git a/include/video.h b/include/video.h index 827733305e..f14fb15f84 100644 --- a/include/video.h +++ b/include/video.h @@ -64,6 +64,13 @@ enum video_log2_bpp {
#define VNBITS(bpix) (1 << (bpix))
+enum video_format { + VIDEO_UNKNOWN, + VIDEO_X8B8G8R8, + VIDEO_X8R8G8B8, + VIDEO_X2R10G10B10, +}; + /** * struct video_priv - Device information used by the video uclass * @@ -71,6 +78,7 @@ enum video_log2_bpp { * @ysize: Number of pixels rows (e.g.. 768) * @rot: Display rotation (0=none, 1=90 degrees clockwise, etc.) * @bpix: Encoded bits per pixel (enum video_log2_bpp) + * @format: Pixel format (enum video_format) * @vidconsole_drv_name: Driver to use for the text console, NULL to * select automatically * @font_size: Font size in pixels (0 to use a default value) @@ -95,6 +103,7 @@ struct video_priv { ushort ysize; ushort rot; enum video_log2_bpp bpix; + enum video_format format; const char *vidconsole_drv_name; int font_size;

Provide correct framebuffer information for 30bpp modes.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- lib/efi_loader/efi_gop.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..5033a2c9e3 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -432,7 +432,7 @@ efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer, efi_status_t efi_gop_register(void) { struct efi_gop_obj *gopobj; - u32 bpix, col, row; + u32 bpix, format, col, row; u64 fb_base, fb_size; void *fb; efi_status_t ret; @@ -449,6 +449,7 @@ efi_status_t efi_gop_register(void)
priv = dev_get_uclass_priv(vdev); bpix = priv->bpix; + format = priv->format; col = video_get_xsize(vdev); row = video_get_ysize(vdev); fb_base = (uintptr_t)priv->fb; @@ -458,6 +459,7 @@ efi_status_t efi_gop_register(void) int line_len;
bpix = panel_info.vl_bpix; + format = VIDEO_UNKNOWN; col = panel_info.vl_col; row = panel_info.vl_row; fb_base = gd->fb_base; @@ -517,7 +519,15 @@ efi_status_t efi_gop_register(void) if (bpix == LCD_COLOR32) #endif { - gopobj->info.pixel_format = EFI_GOT_BGRA8; + if (format == VIDEO_X2R10G10B10) { + gopobj->info.pixel_format = EFI_GOT_BITMASK; + gopobj->info.pixel_bitmask[0] = 0x3ff00000; /* red */ + gopobj->info.pixel_bitmask[1] = 0x000ffc00; /* green */ + gopobj->info.pixel_bitmask[2] = 0x000003ff; /* blue */ + gopobj->info.pixel_bitmask[3] = 0xc0000000; /* reserved */ + } else { + gopobj->info.pixel_format = EFI_GOT_BGRA8; + } } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */

Recognize the canonical format strings for framebuffers in 30bpp mode and 32/24bpp mode.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- drivers/video/simplefb.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index fd58426cf5..2b0d8835e3 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -50,8 +50,18 @@ static int simple_video_probe(struct udevice *dev)
if (strcmp(format, "r5g6b5") == 0) { uc_priv->bpix = VIDEO_BPP16; - } else if (strcmp(format, "a8b8g8r8") == 0) { + } else if (strcmp(format, "a8b8g8r8") == 0 || + strcmp(format, "x8b8g8r8") == 0) { uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X8B8G8R8; + } else if (strcmp(format, "a8r8g8b8") == 0 || + strcmp(format, "x8r8g8b8") == 0) { + uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X8R8G8B8; + } else if (strcmp(format, "a2r10g10b10") == 0 || + strcmp(format, "x2r10g10b10") == 0) { + uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X2R10G10B10; } else { printf("%s: invalid format: %s\n", __func__, format); return -EINVAL;

Convert pixel values when necessary like we do for 16bpp framebuffers.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- lib/efi_loader/efi_gop.c | 47 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 5033a2c9e3..7683a34a96 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -64,6 +64,27 @@ out: return EFI_EXIT(ret); }
+static __always_inline struct efi_gop_pixel efi_vid30_to_blt_col(u32 vid) +{ + struct efi_gop_pixel blt = { + .reserved = 0, + }; + + blt.blue = (vid & 0x3ff) >> 2; + vid >>= 10; + blt.green = (vid & 0x3ff) >> 2; + vid >>= 10; + blt.red = (vid & 0x3ff) >> 2; + return blt; +} + +static __always_inline u32 efi_blt_col_to_vid30(struct efi_gop_pixel *blt) +{ + return (u32)(blt->red << 2) << 20 | + (u32)(blt->green << 2) << 10 | + (u32)(blt->blue << 2); +} + static __always_inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid) { struct efi_gop_pixel blt = { @@ -191,6 +212,9 @@ static __always_inline efi_status_t gop_blt_int(struct efi_gop *this, if (vid_bpp == 32) pix = *(struct efi_gop_pixel *)&fb32[ slineoff + j + sx]; + else if (vid_bpp == 30) + pix = efi_vid30_to_blt_col(fb32[ + slineoff + j + sx]); else pix = efi_vid16_to_blt_col(fb16[ slineoff + j + sx]); @@ -207,6 +231,9 @@ static __always_inline efi_status_t gop_blt_int(struct efi_gop *this, case EFI_BLT_VIDEO_TO_VIDEO: if (vid_bpp == 32) fb32[dlineoff + j + dx] = *(u32 *)&pix; + else if (vid_bpp == 30) + fb32[dlineoff + j + dx] = + efi_blt_col_to_vid30(&pix); else fb16[dlineoff + j + dx] = efi_blt_col_to_vid16(&pix); @@ -231,7 +258,10 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this) #else case LCD_COLOR32: #endif - vid_bpp = 32; + if (gopobj->info.pixel_format == EFI_GOT_BGRA8) + vid_bpp = 32; + else + vid_bpp = 30; break; #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16: @@ -277,6 +307,17 @@ static efi_status_t gop_blt_buf_to_vid16(struct efi_gop *this, dy, width, height, delta, 16); }
+static efi_status_t gop_blt_buf_to_vid30(struct efi_gop *this, + struct efi_gop_pixel *buffer, + u32 foo, efi_uintn_t sx, + efi_uintn_t sy, efi_uintn_t dx, + efi_uintn_t dy, efi_uintn_t width, + efi_uintn_t height, efi_uintn_t delta) +{ + return gop_blt_int(this, buffer, EFI_BLT_BUFFER_TO_VIDEO, sx, sy, dx, + dy, width, height, delta, 30); +} + static efi_status_t gop_blt_buf_to_vid32(struct efi_gop *this, struct efi_gop_pixel *buffer, u32 foo, efi_uintn_t sx, @@ -394,6 +435,10 @@ efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer, ret = gop_blt_buf_to_vid32(this, buffer, operation, sx, sy, dx, dy, width, height, delta); + else if (vid_bpp == 30) + ret = gop_blt_buf_to_vid30(this, buffer, operation, sx, + sy, dx, dy, width, height, + delta); else ret = gop_blt_buf_to_vid16(this, buffer, operation, sx, sy, dx, dy, width, height,

On 9/25/21 10:47 PM, Mark Kettenis wrote:
Convert pixel values when necessary like we do for 16bpp framebuffers.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
lib/efi_loader/efi_gop.c | 47 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 5033a2c9e3..7683a34a96 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -64,6 +64,27 @@ out: return EFI_EXIT(ret); }
+static __always_inline struct efi_gop_pixel efi_vid30_to_blt_col(u32 vid) +{
- struct efi_gop_pixel blt = {
.reserved = 0,
- };
- blt.blue = (vid & 0x3ff) >> 2;
- vid >>= 10;
- blt.green = (vid & 0x3ff) >> 2;
- vid >>= 10;
- blt.red = (vid & 0x3ff) >> 2;
- return blt;
+}
+static __always_inline u32 efi_blt_col_to_vid30(struct efi_gop_pixel *blt) +{
- return (u32)(blt->red << 2) << 20 |
(u32)(blt->green << 2) << 10 |
(u32)(blt->blue << 2);
+}
- static __always_inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid) { struct efi_gop_pixel blt = {
@@ -191,6 +212,9 @@ static __always_inline efi_status_t gop_blt_int(struct efi_gop *this, if (vid_bpp == 32) pix = *(struct efi_gop_pixel *)&fb32[ slineoff + j + sx];
else if (vid_bpp == 30)
pix = efi_vid30_to_blt_col(fb32[
slineoff + j + sx]); else pix = efi_vid16_to_blt_col(fb16[ slineoff + j + sx]);
@@ -207,6 +231,9 @@ static __always_inline efi_status_t gop_blt_int(struct efi_gop *this, case EFI_BLT_VIDEO_TO_VIDEO: if (vid_bpp == 32) fb32[dlineoff + j + dx] = *(u32 *)&pix;
else if (vid_bpp == 30)
fb32[dlineoff + j + dx] =
efi_blt_col_to_vid30(&pix); else fb16[dlineoff + j + dx] = efi_blt_col_to_vid16(&pix);
@@ -231,7 +258,10 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this) #else case LCD_COLOR32: #endif
vid_bpp = 32;
if (gopobj->info.pixel_format == EFI_GOT_BGRA8)
vid_bpp = 32;
else
break; #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16:vid_bpp = 30;
@@ -277,6 +307,17 @@ static efi_status_t gop_blt_buf_to_vid16(struct efi_gop *this, dy, width, height, delta, 16); }
+static efi_status_t gop_blt_buf_to_vid30(struct efi_gop *this,
struct efi_gop_pixel *buffer,
u32 foo, efi_uintn_t sx,
efi_uintn_t sy, efi_uintn_t dx,
efi_uintn_t dy, efi_uintn_t width,
efi_uintn_t height, efi_uintn_t delta)
+{
- return gop_blt_int(this, buffer, EFI_BLT_BUFFER_TO_VIDEO, sx, sy, dx,
dy, width, height, delta, 30);
+}
- static efi_status_t gop_blt_buf_to_vid32(struct efi_gop *this, struct efi_gop_pixel *buffer, u32 foo, efi_uintn_t sx,
@@ -394,6 +435,10 @@ efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer, ret = gop_blt_buf_to_vid32(this, buffer, operation, sx, sy, dx, dy, width, height, delta);
else if (vid_bpp == 30)
ret = gop_blt_buf_to_vid30(this, buffer, operation, sx,
sy, dx, dy, width, height,
else ret = gop_blt_buf_to_vid16(this, buffer, operation, sx, sy, dx, dy, width, height,delta);

On Sat, 25 Sep 2021 22:47:35 +0200 Mark Kettenis kettenis@openbsd.org wrote: ...
v2: - Encode pixel format in favour of adding VIDEO_30BPP - Recognize more format strings in simplefb driver - Fix EFI block image transfer for 30bpp mode
Mark Kettenis (4): video: Add 30bpp support efi_loader: GOP: Add 30bpp support video: simplefb: Add 30bpp support efi_loader: GOP: Fix 30bpp block transfer support
drivers/video/simplefb.c | 12 +++++- drivers/video/vidconsole-uclass.c | 11 ++++-- include/video.h | 9 +++++ lib/efi_loader/efi_gop.c | 61 +++++++++++++++++++++++++++++-- 4 files changed, 86 insertions(+), 7 deletions(-)
applied to u-boot-video/master, thanks!
-- Anatolij
participants (3)
-
Anatolij Gustschin
-
Heinrich Schuchardt
-
Mark Kettenis