Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/40798 )
Change subject: [WIP]framebuffer_info: Add new method to specify an exact pixel format ......................................................................
[WIP]framebuffer_info: Add new method to specify an exact pixel format
Add an enum for framebuffer pixel formats. This allows to get rid of the imprecise BPP argument used for now.
Add a test pattern generator to easily test the framebuffer format.
Tested on qemu cirrus and bochs VGA.
Change-Id: Ice6f3fa73d5d40e5e35073b85c53a76e35cc93ad Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/device/Kconfig M src/drivers/emulation/qemu/bochs.c M src/drivers/emulation/qemu/cirrus.c M src/drivers/intel/fsp1_1/fsp_gop.c M src/include/framebuffer_info.h M src/lib/framebuffer_info.c M src/mainboard/google/daisy/mainboard.c M src/mainboard/google/peach_pit/mainboard.c M src/soc/nvidia/tegra124/display.c 9 files changed, 162 insertions(+), 7 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/98/40798/1
diff --git a/src/device/Kconfig b/src/device/Kconfig index 951062c..7e3a60c 100644 --- a/src/device/Kconfig +++ b/src/device/Kconfig @@ -467,6 +467,16 @@ image in the 'General' section or add it manually to CBFS, using, for example, cbfstool.
+config FRAMEBUFFER_PATTERN + prompt "Show test pattern on screen" + bool + depends on LINEAR_FRAMEBUFFER + help + This option shows a red, green, blue, white test pattern on the screen + from the left to the right. + + Can be used for framebuffer debugging. + config LINEAR_FRAMEBUFFER_MAX_WIDTH int "Maximum width in pixels" depends on LINEAR_FRAMEBUFFER && MAINBOARD_USE_LIBGFXINIT diff --git a/src/drivers/emulation/qemu/bochs.c b/src/drivers/emulation/qemu/bochs.c index ad50a0b..bacc6c0 100644 --- a/src/drivers/emulation/qemu/bochs.c +++ b/src/drivers/emulation/qemu/bochs.c @@ -102,7 +102,7 @@ outb(0x20, 0x3c0); /* disable blanking */
/* Advertise new mode */ - fb_add_framebuffer_info(addr, width, height, 32, 1); + fb_add_framebuffer_info_pf(addr, width, height, PF_32BPP_XRGB8, 1); }
static void bochs_init_text_mode(struct device *dev) diff --git a/src/drivers/emulation/qemu/cirrus.c b/src/drivers/emulation/qemu/cirrus.c index bb24e77..d920c89 100644 --- a/src/drivers/emulation/qemu/cirrus.c +++ b/src/drivers/emulation/qemu/cirrus.c @@ -311,7 +311,7 @@ vga_sr_write (CIRRUS_SR_EXTENDED_MODE, sr_ext); write_hidden_dac (hidden_dac);
- fb_add_framebuffer_info(addr, width, height, 32, 8); + fb_add_framebuffer_info_pf(addr, width, height, PF_32BPP_XRGB8, 8); }
static void cirrus_init_text_mode(struct device *dev) diff --git a/src/drivers/intel/fsp1_1/fsp_gop.c b/src/drivers/intel/fsp1_1/fsp_gop.c index 6b0d647..593e2d0 100644 --- a/src/drivers/intel/fsp1_1/fsp_gop.c +++ b/src/drivers/intel/fsp1_1/fsp_gop.c @@ -22,10 +22,10 @@ printk(BIOS_DEBUG, "FSP_DEBUG: Graphics Data HOB present\n"); vbt_gop = GET_GUID_HOB_DATA(vbt_hob);
- fb_add_framebuffer_info(vbt_gop->FrameBufferBase, + fb_add_framebuffer_info_pf(vbt_gop->FrameBufferBase, vbt_gop->GraphicsMode.HorizontalResolution, vbt_gop->GraphicsMode.VerticalResolution, - 32, + PF_32BPP_BGRX8, 64); }
diff --git a/src/include/framebuffer_info.h b/src/include/framebuffer_info.h index b4bdad6..8c34d56 100644 --- a/src/include/framebuffer_info.h +++ b/src/include/framebuffer_info.h @@ -24,6 +24,22 @@ uint32_t y_resolution, uint8_t bits_per_pixel, uint32_t row_alignment);
+enum fb_pixelformat { + PF_UNKNOWN = 0, + PF_16BPP_B5G6R5, + PF_24BPP_RGB8, + PF_24BPP_BGR8, + PF_32BPP_XRGB8, + PF_32BPP_XBGR8, + PF_32BPP_BGRX8, + PF_32BPP_RGBX8, +}; + +struct fb_info *fb_add_framebuffer_info_pf(uintptr_t fb_addr, uint32_t x_resolution, + uint32_t y_resolution, enum fb_pixelformat pf, + uint32_t row_alignment); + + void fb_set_orientation(struct fb_info *info, enum lb_fb_orientation orientation);
diff --git a/src/lib/framebuffer_info.c b/src/lib/framebuffer_info.c index b8a7bae..18a2e0b 100644 --- a/src/lib/framebuffer_info.c +++ b/src/lib/framebuffer_info.c @@ -51,6 +51,71 @@ return ret; }
+static void fb_set_pixel(struct lb_framebuffer *fb, uint32_t x, uint32_t y, + uint8_t r, uint8_t g, uint8_t b) +{ + uint8_t *fb_ptr = (uint8_t *)(uintptr_t)fb->physical_address; + fb_ptr += fb->bytes_per_line * y; + fb_ptr += (fb->bits_per_pixel/8) * x; + uint32_t *tmp; + + if (fb->bits_per_pixel > 32) + return; + + if (fb->red_mask_size < sizeof(r) * 8) + r >>= sizeof(r) * 8 - fb->red_mask_size; + + if (fb->green_mask_size < sizeof(g) * 8) + g >>= sizeof(g) * 8 - fb->green_mask_size; + + if (fb->blue_mask_size < sizeof(b) * 8) + b >>= sizeof(b) * 8 - fb->blue_mask_size; + + tmp = (uint32_t *)fb_ptr; + for (uint8_t i = 0; i < sizeof(*tmp) * 8; i++) { + if (i >= fb->red_mask_pos && i < (fb->red_mask_pos + fb->red_mask_size)) { + if (r & 1) + *tmp |= 1 << i; + else + *tmp &= ~(1 << i); + r >>= 1; + } + if (i >= fb->green_mask_pos && i < (fb->green_mask_pos + fb->green_mask_size)) { + if (g & 1) + *tmp |= 1 << i; + else + *tmp &= ~(1 << i); + g >>= 1; + } + if (i >= fb->blue_mask_pos && i < (fb->blue_mask_pos + fb->blue_mask_size)) { + if (b & 1) + *tmp |= 1 << i; + else + *tmp &= ~(1 << i); + b >>= 1; + } + } +} + +/* Generate a red, green, blue, white test pattern from the left to the right */ +static void set_test_pattern(struct lb_framebuffer *fb) +{ + for (int y = fb->y_resolution / 4; y < fb->y_resolution / 4 * 3; y++) { + for (int x = 0; x < fb->x_resolution; x++) { + if (x < fb->x_resolution / 4) + fb_set_pixel(fb, x, y, 0xff, 0, 0); + else if ((x >= fb->x_resolution / 4) && + (x < fb->x_resolution / 2)) + fb_set_pixel(fb, x, y, 0, 0xff, 0); + else if ((x >= fb->x_resolution / 2) && + (x < fb->x_resolution / 4 * 3)) + fb_set_pixel(fb, x, y, 0, 0, 0xff); + else + fb_set_pixel(fb, x, y, 0xff, 0xff, 0xff); + } + } +} + /* * Fills a provided framebuffer info struct and adds it to the internal list if it's * valid. Returns NULL on error. @@ -131,6 +196,9 @@ { struct fb_info *info = NULL;
+ printk(BIOS_WARNING, "%s: The use of this function is deprecated." + "Please provide a meaningful pixel format.\n", __func__); + switch (bits_per_pixel) { case 32: case 24: /* FIXME: 24 BPP might be RGB8 or XRGB8 */ @@ -154,6 +222,65 @@ return info; }
+struct fb_info *fb_add_framebuffer_info_pf(uintptr_t fb_addr, uint32_t x_resolution, + uint32_t y_resolution, enum fb_pixelformat pf, + uint32_t row_alignment) +{ + struct fb_info *info = NULL; + + switch (pf) { + case PF_32BPP_XBGR8: + /* packed into 4-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 32, row_alignment, 24, 8, 0, + 8, 8, 8, 16, 8); + break; + case PF_32BPP_XRGB8: + /* packed into 4-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 32, row_alignment, 24, 8, 16, + 8, 8, 8, 0, 8); + break; + case PF_32BPP_BGRX8: + /* packed into 4-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 32, row_alignment, 0, 8, 8, + 8, 16, 8, 24, 8); + break; + case PF_32BPP_RGBX8: + /* packed into 4-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 32, row_alignment, 0, 8, 24, + 8, 16, 8, 0, 8); + break; + case PF_24BPP_RGB8: + /* packed into 3-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 24, row_alignment, 0, 0, 16, + 8, 8, 8, 0, 8); + break; + case PF_24BPP_BGR8: + /* packed into 3-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 24, row_alignment, 0, 0, 0, + 8, 8, 8, 16, 8); + break; + case PF_16BPP_B5G6R5: + /* packed into 2-byte words */ + info = fb_add_framebuffer_info_ex(fb_addr, x_resolution, y_resolution, + 16, row_alignment, 0, 0, 11, + 5, 5, 6, 0, 5); + break; + default: + printk(BIOS_ERR, "%s: unsupported pixel format %d\n", __func__, pf); + } + if (!info) { + printk(BIOS_ERR, "%s: failed to add framebuffer info\n", __func__); + } + return info; + +} + void fb_set_orientation(struct fb_info *info, enum lb_fb_orientation orientation) { if (!info) @@ -191,6 +318,8 @@ unsigned int depth = framebuffer->bits_per_pixel; //FIXME: Temporary cache the bootsplash outside of this loop set_bootsplash(fb_ptr, width, height, depth); + } else if (CONFIG(FRAMEBUFFER_PATTERN)) { + set_test_pattern(framebuffer); } }
diff --git a/src/mainboard/google/daisy/mainboard.c b/src/mainboard/google/daisy/mainboard.c index 7a51c7e..8f5f734 100644 --- a/src/mainboard/google/daisy/mainboard.c +++ b/src/mainboard/google/daisy/mainboard.c @@ -255,7 +255,7 @@
sdmmc_vdd();
- fb_add_framebuffer_info((uintptr_t)fb_addr, 1366, 768, 16, 0); + fb_add_framebuffer_info_pf((uintptr_t)fb_addr, 1366, 768, PF_16BPP_B5G6R5, 0);
lcd_vdd();
diff --git a/src/mainboard/google/peach_pit/mainboard.c b/src/mainboard/google/peach_pit/mainboard.c index 1d60e3b..b5dd35f 100644 --- a/src/mainboard/google/peach_pit/mainboard.c +++ b/src/mainboard/google/peach_pit/mainboard.c @@ -394,7 +394,7 @@
sdmmc_vdd();
- fb_add_framebuffer_info((uintptr_t)fb_addr, 1366, 768, 16, 0); + fb_add_framebuffer_info_pf((uintptr_t)fb_addr, 1366, 768, PF_16BPP_B5G6R5, 0);
/* * The reset value for FIMD SYSMMU register MMU_CTRL:0x14640000 diff --git a/src/soc/nvidia/tegra124/display.c b/src/soc/nvidia/tegra124/display.c index c64d19d..dd3a1ce 100644 --- a/src/soc/nvidia/tegra124/display.c +++ b/src/soc/nvidia/tegra124/display.c @@ -314,7 +314,7 @@ /* tell depthcharge ... */
- fb_add_framebuffer_info((uintptr_t)(framebuffer_base_mb*MiB), + fb_add_framebuffer_info_pf((uintptr_t)(framebuffer_base_mb*MiB), config->xres, config->yres, config->framebuffer_bits_per_pixel,