[PATCH 0/3] 30bpp framebuffer support

Apple M1 machines come up with a framebuffer that in 30bpp mode. This series adds basic support for this mode.
Mark Kettenis (3): video: Add 30bpp support efi_loader: GOP: Add 30bpp support video: simplefb: Add 30bpp support
drivers/video/console_normal.c | 2 ++ drivers/video/console_rotate.c | 6 ++++++ drivers/video/console_truetype.c | 3 +++ drivers/video/simplefb.c | 3 +++ drivers/video/vidconsole-uclass.c | 7 +++++++ drivers/video/video-uclass.c | 1 + include/video.h | 1 + lib/efi_loader/efi_gop.c | 10 ++++++++++ 8 files changed, 33 insertions(+)

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/console_normal.c | 2 ++ drivers/video/console_rotate.c | 6 ++++++ drivers/video/console_truetype.c | 3 +++ drivers/video/vidconsole-uclass.c | 7 +++++++ drivers/video/video-uclass.c | 1 + include/video.h | 1 + 6 files changed, 20 insertions(+)
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 04f022491e..e0b89cbb93 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -41,6 +41,7 @@ static int console_normal_set_row(struct udevice *dev, uint row, int clr) end = dst; break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; @@ -126,6 +127,7 @@ static int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, } break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c index 36c8d0609d..bf81b80a39 100644 --- a/drivers/video/console_rotate.c +++ b/drivers/video/console_rotate.c @@ -40,6 +40,7 @@ static int console_set_row_1(struct udevice *dev, uint row, int clr) *dst++ = clr; break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; @@ -128,6 +129,7 @@ static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch) } break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; @@ -183,6 +185,7 @@ static int console_set_row_2(struct udevice *dev, uint row, int clr) end = dst; break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; @@ -266,6 +269,7 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch) } break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; @@ -318,6 +322,7 @@ static int console_set_row_3(struct udevice *dev, uint row, int clr) *dst++ = clr; break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; @@ -402,6 +407,7 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch) } break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line; diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 98427f4c61..0195d996de 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -153,6 +153,7 @@ static int console_truetype_set_row(struct udevice *dev, uint row, int clr) } #endif #ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP30: case VIDEO_BPP32: { u32 *dst = line;
@@ -299,6 +300,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, } #endif #ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP30: case VIDEO_BPP32: { u32 *dst = (u32 *)line + xoff; int i; @@ -381,6 +383,7 @@ static int console_truetype_erase(struct udevice *dev, int xstart, int ystart, } #endif #ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP30: case VIDEO_BPP32: { uint32_t *dst = line;
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 8132efa55a..cc274b45fe 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -153,6 +153,13 @@ u32 vid_console_color(struct video_priv *priv, unsigned int idx) ((colors[idx].b >> 3) << 0); } break; + case VIDEO_BPP30: + if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { + return (colors[idx].r << 22) | + (colors[idx].g << 12) | + (colors[idx].b << 2); + } + break; case VIDEO_BPP32: if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { return (colors[idx].r << 16) | diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 9f8cf6ef2a..28bf701f41 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -129,6 +129,7 @@ int video_clear(struct udevice *dev) *ppix++ = priv->colour_bg; break; } + case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { u32 *ppix = priv->fb; diff --git a/include/video.h b/include/video.h index 827733305e..04c636b317 100644 --- a/include/video.h +++ b/include/video.h @@ -53,6 +53,7 @@ enum video_log2_bpp { VIDEO_BPP4, VIDEO_BPP8, VIDEO_BPP16, + VIDEO_BPP30, VIDEO_BPP32, };

On Thu, 16 Sept 2021 at 07:01, Mark Kettenis kettenis@openbsd.org wrote:
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/console_normal.c | 2 ++ drivers/video/console_rotate.c | 6 ++++++ drivers/video/console_truetype.c | 3 +++ drivers/video/vidconsole-uclass.c | 7 +++++++ drivers/video/video-uclass.c | 1 + include/video.h | 1 + 6 files changed, 20 insertions(+)
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 04f022491e..e0b89cbb93 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -41,6 +41,7 @@ static int console_normal_set_row(struct udevice *dev, uint row, int clr) end = dst; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -126,6 +127,7 @@ static int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c index 36c8d0609d..bf81b80a39 100644 --- a/drivers/video/console_rotate.c +++ b/drivers/video/console_rotate.c @@ -40,6 +40,7 @@ static int console_set_row_1(struct udevice *dev, uint row, int clr) *dst++ = clr; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -128,6 +129,7 @@ static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch) } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -183,6 +185,7 @@ static int console_set_row_2(struct udevice *dev, uint row, int clr) end = dst; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -266,6 +269,7 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch) } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -318,6 +322,7 @@ static int console_set_row_3(struct udevice *dev, uint row, int clr) *dst++ = clr; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -402,6 +407,7 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch) } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 98427f4c61..0195d996de 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -153,6 +153,7 @@ static int console_truetype_set_row(struct udevice *dev, uint row, int clr) } #endif #ifdef CONFIG_VIDEO_BPP32
case VIDEO_BPP30: case VIDEO_BPP32: { u32 *dst = line;
@@ -299,6 +300,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, } #endif #ifdef CONFIG_VIDEO_BPP32
case VIDEO_BPP30: case VIDEO_BPP32: { u32 *dst = (u32 *)line + xoff; int i;
@@ -381,6 +383,7 @@ static int console_truetype_erase(struct udevice *dev, int xstart, int ystart, } #endif #ifdef CONFIG_VIDEO_BPP32
case VIDEO_BPP30: case VIDEO_BPP32: { uint32_t *dst = line;
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 8132efa55a..cc274b45fe 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -153,6 +153,13 @@ u32 vid_console_color(struct video_priv *priv, unsigned int idx) ((colors[idx].b >> 3) << 0); } break;
case VIDEO_BPP30:
if (CONFIG_IS_ENABLED(VIDEO_BPP32)) {
return (colors[idx].r << 22) |
(colors[idx].g << 12) |
(colors[idx].b << 2);
}
break; case VIDEO_BPP32: if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { return (colors[idx].r << 16) |
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 9f8cf6ef2a..28bf701f41 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -129,6 +129,7 @@ int video_clear(struct udevice *dev) *ppix++ = priv->colour_bg; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { u32 *ppix = priv->fb;
diff --git a/include/video.h b/include/video.h index 827733305e..04c636b317 100644 --- a/include/video.h +++ b/include/video. @@ -53,6 +53,7 @@ enum video_log2_bpp { VIDEO_BPP4, VIDEO_BPP8, VIDEO_BPP16,
VIDEO_BPP30, VIDEO_BPP32,
};
This breaks the enuam here. See the comment above:
/* * Bits per pixel selector. Each value n is such that the bits-per-pixel is * 2 ^ n */
Quite a few things rely on this, so there will need to be some changes. See for example VBNBYTE() immediately below.
Also don't you need a CONFIG_VIDEO_BPP30 ?
Tested on: Macbook Air M1 Tested-by: Simon Glass sjg@chromium.org
Fails on sandbox (display turns blue)
Regards, Simon

From: Simon Glass sjg@chromium.org Date: Sat, 25 Sep 2021 07:40:54 -0600
On Thu, 16 Sept 2021 at 07:01, Mark Kettenis kettenis@openbsd.org wrote:
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/console_normal.c | 2 ++ drivers/video/console_rotate.c | 6 ++++++ drivers/video/console_truetype.c | 3 +++ drivers/video/vidconsole-uclass.c | 7 +++++++ drivers/video/video-uclass.c | 1 + include/video.h | 1 + 6 files changed, 20 insertions(+)
diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 04f022491e..e0b89cbb93 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -41,6 +41,7 @@ static int console_normal_set_row(struct udevice *dev, uint row, int clr) end = dst; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -126,6 +127,7 @@ static int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c index 36c8d0609d..bf81b80a39 100644 --- a/drivers/video/console_rotate.c +++ b/drivers/video/console_rotate.c @@ -40,6 +40,7 @@ static int console_set_row_1(struct udevice *dev, uint row, int clr) *dst++ = clr; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -128,6 +129,7 @@ static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch) } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -183,6 +185,7 @@ static int console_set_row_2(struct udevice *dev, uint row, int clr) end = dst; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -266,6 +269,7 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch) } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -318,6 +322,7 @@ static int console_set_row_3(struct udevice *dev, uint row, int clr) *dst++ = clr; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
@@ -402,6 +407,7 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch) } break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { uint32_t *dst = line;
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 98427f4c61..0195d996de 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -153,6 +153,7 @@ static int console_truetype_set_row(struct udevice *dev, uint row, int clr) } #endif #ifdef CONFIG_VIDEO_BPP32
case VIDEO_BPP30: case VIDEO_BPP32: { u32 *dst = line;
@@ -299,6 +300,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, } #endif #ifdef CONFIG_VIDEO_BPP32
case VIDEO_BPP30: case VIDEO_BPP32: { u32 *dst = (u32 *)line + xoff; int i;
@@ -381,6 +383,7 @@ static int console_truetype_erase(struct udevice *dev, int xstart, int ystart, } #endif #ifdef CONFIG_VIDEO_BPP32
case VIDEO_BPP30: case VIDEO_BPP32: { uint32_t *dst = line;
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 8132efa55a..cc274b45fe 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -153,6 +153,13 @@ u32 vid_console_color(struct video_priv *priv, unsigned int idx) ((colors[idx].b >> 3) << 0); } break;
case VIDEO_BPP30:
if (CONFIG_IS_ENABLED(VIDEO_BPP32)) {
return (colors[idx].r << 22) |
(colors[idx].g << 12) |
(colors[idx].b << 2);
}
break; case VIDEO_BPP32: if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { return (colors[idx].r << 16) |
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 9f8cf6ef2a..28bf701f41 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -129,6 +129,7 @@ int video_clear(struct udevice *dev) *ppix++ = priv->colour_bg; break; }
case VIDEO_BPP30: case VIDEO_BPP32: if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { u32 *ppix = priv->fb;
diff --git a/include/video.h b/include/video.h index 827733305e..04c636b317 100644 --- a/include/video.h +++ b/include/video. @@ -53,6 +53,7 @@ enum video_log2_bpp { VIDEO_BPP4, VIDEO_BPP8, VIDEO_BPP16,
VIDEO_BPP30, VIDEO_BPP32,
};
This breaks the enuam here. See the comment above:
/*
- Bits per pixel selector. Each value n is such that the bits-per-pixel is
- 2 ^ n
*/
Quite a few things rely on this, so there will need to be some changes. See for example VBNBYTE() immediately below.
Bleah. I suppose I need a separate field in struct video_priv to keep track of the pixel format then.
Also don't you need a CONFIG_VIDEO_BPP30 ?
The idea was that the code additions were minimal enough for that not to make sense. But I'll need re-evaluate this after I figure out a better way to distinguish between 8-bit and 10-bit color depth.

Provide correct framebuffer information for 30bpp modes.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- lib/efi_loader/efi_gop.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..42bf49b184 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -227,6 +227,7 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
switch (gopobj->bpix) { #ifdef CONFIG_DM_VIDEO + case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32: @@ -468,6 +469,7 @@ efi_status_t efi_gop_register(void) switch (bpix) { #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16: + case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32: @@ -518,6 +520,14 @@ efi_status_t efi_gop_register(void) #endif { gopobj->info.pixel_format = EFI_GOT_BGRA8; +#ifdef CONFIG_DM_VIDEO + } else if (bpix == VIDEO_BPP30) { + 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 */ +#endif } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */

On 9/16/21 3:01 PM, Mark Kettenis wrote:
Provide correct framebuffer information for 30bpp modes.
This is not enough to get a correct GOP implementation for the 30bpp mode.
Have a look at efi_gop_pixel efi_vid16_to_blt_col() and efi_blt_col_to_vid16() and where they are used.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
lib/efi_loader/efi_gop.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..42bf49b184 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -227,6 +227,7 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
switch (gopobj->bpix) { #ifdef CONFIG_DM_VIDEO
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -468,6 +469,7 @@ efi_status_t efi_gop_register(void) switch (bpix) { #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16:
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -518,6 +520,14 @@ efi_status_t efi_gop_register(void) #endif { gopobj->info.pixel_format = EFI_GOT_BGRA8; +#ifdef CONFIG_DM_VIDEO
This symbol is not 30bpp specific. Is there a Kconfig variable that we can use to hide 30bpp support where it is not needed?
Which modes does the M1 support?
Best regards
Heinrich
- } else if (bpix == VIDEO_BPP30) {
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 */
+#endif } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */

From: Heinrich Schuchardt xypron.glpk@gmx.de Date: Fri, 17 Sep 2021 04:56:31 +0200
Hi Heinrich,
On 9/16/21 3:01 PM, Mark Kettenis wrote:
Provide correct framebuffer information for 30bpp modes.
This is not enough to get a correct GOP implementation for the 30bpp mode.
Have a look at efi_gop_pixel efi_vid16_to_blt_col() and efi_blt_col_to_vid16() and where they are used.
Ah right. This does indeed not support EFI_GRAPHICS_OUTPUT_PROTOCOL.Blt() correctly. I shouldn't be too hard to translate between XRGB2101010 and XRGB8888. Any ideas how I could test that code?
Signed-off-by: Mark Kettenis kettenis@openbsd.org
lib/efi_loader/efi_gop.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..42bf49b184 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -227,6 +227,7 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
switch (gopobj->bpix) { #ifdef CONFIG_DM_VIDEO
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -468,6 +469,7 @@ efi_status_t efi_gop_register(void) switch (bpix) { #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16:
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -518,6 +520,14 @@ efi_status_t efi_gop_register(void) #endif { gopobj->info.pixel_format = EFI_GOT_BGRA8; +#ifdef CONFIG_DM_VIDEO
This symbol is not 30bpp specific. Is there a Kconfig variable that we can use to hide 30bpp support where it is not needed?
I quite deliberately didn't add a separate config option for 30bpp as there is very little code that is added to the already existing 32bpp code. In a sense 30bpp is just a different submode of the 32bpp support with just a different color map, so I thought it made sense to group it under CONFIG_VIDEO_32BPP. I did initially consider adding a separate config option for it, but it quickly turns into an #ifdef maze that makes it hard to understand the code.
The CONFIG_DM_VIDEO check is just there to make sure the 30bpp is only offered in the DM model. Based on recent discussions I expect the !CONFIG_DM_VIDEO case to disappear in the near feature so adding 30bpp support for the non-DM case doesn't make sense.
The EFI GOP code currently doesn't check the CONFIG_VIDEO_BPP16 and CONFIG_VIDEO_BPP32 defines to see which of these modes are enabled within U-Boot, so we don't "hide" 16bpp support on platforms that just support 32bpp either.
Which modes does the M1 support?
We're not sure. It does support at least 8-bit (32bpp) and 10-bit (30bpp) color depth modes. But the firmware tends to come up with 10-bit color depth whenever it can and I'm not planning to add support for changing the framebuffer mode on the M1, since the interface to do that is "interesting" [1].
[1] See Alyssa Rozenzweig's talk at XDC 2021, https://www.youtube.com/watch?v=uTZISTjqy9Q
- } else if (bpix == VIDEO_BPP30) {
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 */
+#endif } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */

On 9/17/21 11:23 AM, Mark Kettenis wrote:
From: Heinrich Schuchardt xypron.glpk@gmx.de Date: Fri, 17 Sep 2021 04:56:31 +0200
Hi Heinrich,
On 9/16/21 3:01 PM, Mark Kettenis wrote:
Provide correct framebuffer information for 30bpp modes.
This is not enough to get a correct GOP implementation for the 30bpp mode.
Have a look at efi_gop_pixel efi_vid16_to_blt_col() and efi_blt_col_to_vid16() and where they are used.
Ah right. This does indeed not support EFI_GRAPHICS_OUTPUT_PROTOCOL.Blt() correctly. I shouldn't be too hard to translate between XRGB2101010 and XRGB8888. Any ideas how I could test that code?
setenv efi_selftest block image transfer bootefi selftest
should show an animated submarine with yellow portholes similar to
https://gist.github.com/xypron/7e1f73408465da71e3ef946250e76776#file-sub-png
Best regards
Heinrich
Signed-off-by: Mark Kettenis kettenis@openbsd.org
lib/efi_loader/efi_gop.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..42bf49b184 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -227,6 +227,7 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
switch (gopobj->bpix) {
#ifdef CONFIG_DM_VIDEO
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -468,6 +469,7 @@ efi_status_t efi_gop_register(void) switch (bpix) { #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16:
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -518,6 +520,14 @@ efi_status_t efi_gop_register(void) #endif { gopobj->info.pixel_format = EFI_GOT_BGRA8; +#ifdef CONFIG_DM_VIDEO
This symbol is not 30bpp specific. Is there a Kconfig variable that we can use to hide 30bpp support where it is not needed?
I quite deliberately didn't add a separate config option for 30bpp as there is very little code that is added to the already existing 32bpp code. In a sense 30bpp is just a different submode of the 32bpp support with just a different color map, so I thought it made sense to group it under CONFIG_VIDEO_32BPP. I did initially consider adding a separate config option for it, but it quickly turns into an #ifdef maze that makes it hard to understand the code.
The CONFIG_DM_VIDEO check is just there to make sure the 30bpp is only offered in the DM model. Based on recent discussions I expect the !CONFIG_DM_VIDEO case to disappear in the near feature so adding 30bpp support for the non-DM case doesn't make sense.
The EFI GOP code currently doesn't check the CONFIG_VIDEO_BPP16 and CONFIG_VIDEO_BPP32 defines to see which of these modes are enabled within U-Boot, so we don't "hide" 16bpp support on platforms that just support 32bpp either.
Which modes does the M1 support?
We're not sure. It does support at least 8-bit (32bpp) and 10-bit (30bpp) color depth modes. But the firmware tends to come up with 10-bit color depth whenever it can and I'm not planning to add support for changing the framebuffer mode on the M1, since the interface to do that is "interesting" [1].
[1] See Alyssa Rozenzweig's talk at XDC 2021, https://www.youtube.com/watch?v=uTZISTjqy9Q
- } else if (bpix == VIDEO_BPP30) {
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 */
+#endif } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */

From: Heinrich Schuchardt xypron.glpk@gmx.de Date: Fri, 17 Sep 2021 13:29:06 +0200
On 9/17/21 11:23 AM, Mark Kettenis wrote:
From: Heinrich Schuchardt xypron.glpk@gmx.de Date: Fri, 17 Sep 2021 04:56:31 +0200
Hi Heinrich,
On 9/16/21 3:01 PM, Mark Kettenis wrote:
Provide correct framebuffer information for 30bpp modes.
This is not enough to get a correct GOP implementation for the 30bpp mode.
Have a look at efi_gop_pixel efi_vid16_to_blt_col() and efi_blt_col_to_vid16() and where they are used.
Ah right. This does indeed not support EFI_GRAPHICS_OUTPUT_PROTOCOL.Blt() correctly. I shouldn't be too hard to translate between XRGB2101010 and XRGB8888. Any ideas how I could test that code?
setenv efi_selftest block image transfer bootefi selftest
should show an animated submarine with yellow portholes similar to
https://gist.github.com/xypron/7e1f73408465da71e3ef946250e76776#file-sub-png
Best regards
Cool thanks. Looks like my implementation works! I'll wait a bit for feedback on the other diffs in this series before sending a v2 with that.
Cheers,
Mark
Signed-off-by: Mark Kettenis kettenis@openbsd.org
lib/efi_loader/efi_gop.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..42bf49b184 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -227,6 +227,7 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
switch (gopobj->bpix) {
#ifdef CONFIG_DM_VIDEO
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -468,6 +469,7 @@ efi_status_t efi_gop_register(void) switch (bpix) { #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16:
- case VIDEO_BPP30: case VIDEO_BPP32: #else case LCD_COLOR32:
@@ -518,6 +520,14 @@ efi_status_t efi_gop_register(void) #endif { gopobj->info.pixel_format = EFI_GOT_BGRA8; +#ifdef CONFIG_DM_VIDEO
This symbol is not 30bpp specific. Is there a Kconfig variable that we can use to hide 30bpp support where it is not needed?
I quite deliberately didn't add a separate config option for 30bpp as there is very little code that is added to the already existing 32bpp code. In a sense 30bpp is just a different submode of the 32bpp support with just a different color map, so I thought it made sense to group it under CONFIG_VIDEO_32BPP. I did initially consider adding a separate config option for it, but it quickly turns into an #ifdef maze that makes it hard to understand the code.
The CONFIG_DM_VIDEO check is just there to make sure the 30bpp is only offered in the DM model. Based on recent discussions I expect the !CONFIG_DM_VIDEO case to disappear in the near feature so adding 30bpp support for the non-DM case doesn't make sense.
The EFI GOP code currently doesn't check the CONFIG_VIDEO_BPP16 and CONFIG_VIDEO_BPP32 defines to see which of these modes are enabled within U-Boot, so we don't "hide" 16bpp support on platforms that just support 32bpp either.
Which modes does the M1 support?
We're not sure. It does support at least 8-bit (32bpp) and 10-bit (30bpp) color depth modes. But the firmware tends to come up with 10-bit color depth whenever it can and I'm not planning to add support for changing the framebuffer mode on the M1, since the interface to do that is "interesting" [1].
[1] See Alyssa Rozenzweig's talk at XDC 2021, https://www.youtube.com/watch?v=uTZISTjqy9Q
- } else if (bpix == VIDEO_BPP30) {
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 */
+#endif } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */

Hi Mark,
On Thu, 16 Sept 2021 at 07:02, Mark Kettenis kettenis@openbsd.org wrote:
Provide correct framebuffer information for 30bpp modes.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
lib/efi_loader/efi_gop.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 1206b2d7a2..42bf49b184 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -227,6 +227,7 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
switch (gopobj->bpix) {
#ifdef CONFIG_DM_VIDEO
case VIDEO_BPP30: case VIDEO_BPP32:
#else case LCD_COLOR32: @@ -468,6 +469,7 @@ efi_status_t efi_gop_register(void) switch (bpix) { #ifdef CONFIG_DM_VIDEO case VIDEO_BPP16:
case VIDEO_BPP30: case VIDEO_BPP32:
#else case LCD_COLOR32: @@ -518,6 +520,14 @@ efi_status_t efi_gop_register(void) #endif { gopobj->info.pixel_format = EFI_GOT_BGRA8; +#ifdef CONFIG_DM_VIDEO
Can avoid #ifdefs please? Does this work?
if (IS_ENABLED(CONFIG_DM_VIDEO) && IS_ENABLED(CONFIG_VIDEO_BPP30) && bpix == VIDEO_BPP30)
Heinrich might know if we can just require DM_VIDEO.
} else if (bpix == VIDEO_BPP30) {
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 */
+#endif } else { gopobj->info.pixel_format = EFI_GOT_BITMASK; gopobj->info.pixel_bitmask[0] = 0xf800; /* red */ -- 2.33.0
Tested on: Macbook Air M1 Tested-by: Simon Glass sjg@chromium.org
Regards, Simon

Recognize the canonical format strings for framebuffers in 30bpp mode.
Signed-off-by: Mark Kettenis kettenis@openbsd.org --- drivers/video/simplefb.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index fd58426cf5..7e1cc4560f 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -52,6 +52,9 @@ static int simple_video_probe(struct udevice *dev) uc_priv->bpix = VIDEO_BPP16; } else if (strcmp(format, "a8b8g8r8") == 0) { uc_priv->bpix = VIDEO_BPP32; + } else if (strcmp(format, "a2r10g10b10") == 0 || + strcmp(format, "x2r10g10b10") == 0) { + uc_priv->bpix = VIDEO_BPP30; } else { printf("%s: invalid format: %s\n", __func__, format); return -EINVAL;

On Thu, 16 Sept 2021 at 07:02, Mark Kettenis kettenis@openbsd.org wrote:
Recognize the canonical format strings for framebuffers in 30bpp mode.
Signed-off-by: Mark Kettenis kettenis@openbsd.org
drivers/video/simplefb.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index fd58426cf5..7e1cc4560f 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -52,6 +52,9 @@ static int simple_video_probe(struct udevice *dev) uc_priv->bpix = VIDEO_BPP16; } else if (strcmp(format, "a8b8g8r8") == 0) { uc_priv->bpix = VIDEO_BPP32;
} else if (strcmp(format, "a2r10g10b10") == 0 ||
strcmp(format, "x2r10g10b10") == 0) {
uc_priv->bpix = VIDEO_BPP30; } else { printf("%s: invalid format: %s\n", __func__, format); return -EINVAL;
-- 2.33.0
Reviewed-by: Simon Glass sjg@chromium.org Tested on: Macbook Air M1 Tested-by: Simon Glass sjg@chromium.org
participants (4)
-
Heinrich Schuchardt
-
Mark Kettenis
-
Mark Kettenis
-
Simon Glass