From e64a5c4d49dfba5307279bee2de9681bea5f9e26 Mon Sep 17 00:00:00 2001 From: Subrata Banik Date: Fri, 14 Mar 2025 01:34:50 +0530 Subject: [PATCH] drivers/intel/fsp2_0: Enable panel-orientation aware bitmap rotation Implement logo bitmap rotation within fsp_convert_bmp_to_gop_blt() to support devices with portrait-oriented displays. The rotation is driven by the panel framebuffer orientation, allowing the logo to be displayed correctly regardless of physical panel orientation. This resolves issues where the logo was displayed incorrectly on portrait-oriented displays. Additionally, discard the display orientation change if the LID is closed aka built-in display is not active. This will ensure that display orientation is proper when extended display is attached w/o any display rotation. BUG=b:396580135 TEST=Verified BMP logo display in landscape mode on a portrait panel with rotation enabled. Also verified portrait logo display in landscape mode with rotation enabled. Change-Id: I110bd67331f01e523c227e1a4bdb0484f0157a60 Signed-off-by: Subrata Banik Reviewed-on: https://review.coreboot.org/c/coreboot/+/86850 Reviewed-by: Karthik Ramasubramanian Tested-by: build bot (Jenkins) --- src/drivers/intel/fsp2_0/fsp_gop_blt.c | 230 ++++++++++++++++-- .../intel/fsp2_0/include/fsp/fsp_gop_blt.h | 4 +- src/soc/intel/alderlake/fsp_params.c | 18 +- src/soc/intel/meteorlake/fsp_params.c | 18 +- src/soc/intel/pantherlake/fsp_params.c | 17 +- 5 files changed, 262 insertions(+), 25 deletions(-) diff --git a/src/drivers/intel/fsp2_0/fsp_gop_blt.c b/src/drivers/intel/fsp2_0/fsp_gop_blt.c index bbeece4e97..087fb02df0 100644 --- a/src/drivers/intel/fsp2_0/fsp_gop_blt.c +++ b/src/drivers/intel/fsp2_0/fsp_gop_blt.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#include #include #include #include @@ -131,9 +132,184 @@ static uint32_t get_color_map_num(efi_bmp_image_header *header) return col_map_number; } -/* Fill BMP image into BLT buffer format */ +/* + * Visual Representation of the Flipping: + * + * Original BMP Image: + * + * 0 -----------------------------------------PixelWidth-1 + * | | + * | | + * | | + * PixelHeight-1------------------------------| + * + * Blitting Region: + * + * (x, y) ----------------------------------- (x + blt_width, y) + * | | + * | | + * (x, y + blt_height) -------------------- --(x + blt_width, y + blt_height) + * + * Flipped Coordinates: + * + * flipped_x: Represents the horizontal coordinate from the `right` edge of the BMP, + * accounting for the blit width. + * + * flipped_y: Represents the vertical coordinate from the `bottom` edge of the BMP, + * accounting for the blit height. + * + * Example (Orientation: LB_FB_ORIENTATION_BOTTOM_UP): + * + * If blt_width is small, flipped_x will be near PixelWidth. + * If blt_height is small, flipped_y will be near PixelHeight. + * + * The blit then starts at (flipped_x, blt_height), effectively flipping the + * horizontal position and using the original blit height. + * + * This allows for blitting from the bottom-left corner of the display panel. + */ +static bool calculate_adj_height_width(const efi_bmp_image_header *header, size_t *adjusted_x, + size_t *adjusted_y, enum lb_fb_orientation orientation, int blt_width, int blt_height) +{ + if (!header || !adjusted_x || !adjusted_y) + return false; + + size_t flipped_x = header->PixelWidth - blt_width - 1; + size_t flipped_y = header->PixelHeight - blt_height - 1; + + switch (orientation) { + case LB_FB_ORIENTATION_LEFT_UP: + *adjusted_x = flipped_y; + *adjusted_y = flipped_x; + break; + + case LB_FB_ORIENTATION_BOTTOM_UP: + *adjusted_x = flipped_x; + *adjusted_y = blt_height; + break; + + case LB_FB_ORIENTATION_RIGHT_UP: + *adjusted_x = blt_height; + *adjusted_y = blt_width; + break; + + case LB_FB_ORIENTATION_NORMAL: + default: + *adjusted_x = blt_width; + *adjusted_y = flipped_y; + break; + } + + return true; +} + +/* + * Visual Representation of gop_width and calculate linear offset into the GOP buffer: + * + * GOP Display Buffer: + * + * +------------------------------------------------+ + * | 0 | + * | |--> gop_width pixels in this row | + * +------------------------------------------------+ + * | gop_width | + * | | + * | gop_width | + * | ... | + * +------------------------------------------------+ + * | gop_width | + * +------------------------------------------------+ + * + * gop_width: Represents the width of a row in the GOP buffer. + * - It is determined by the `orientation` of the image. + * - For `LEFT_UP` and `RIGHT_UP`, the GOP width is the BMP image's `PixelHeight`. + * - For `BOTTOM_UP` and `NORMAL`, the GOP width is the BMP image's `PixelWidth`. + * + * gop_x, gop_y: Coordinates within the GOP buffer where the blit will start. + * - These are calculated by `calculate_adj_height_width` based on the `orientation`, + * `blt_width`, and `blt_height`. + * + * Pointer to the calculated pixel in the GOP blit buffer, or NULL on error. + * - Calculate `gop_blt_offset`as `gop_y * gop_width + gop_x` to determine the offset + * to access the correct pixel within `gop_blt_buffer`. + * - `gop_y * gop_width` calculates the offset of the row. + * - `gop_x` calculates the offset within that row. + */ +static efi_graphics_output_blt_pixel *get_gop_blt_pixel( + efi_graphics_output_blt_pixel *gop_blt_buffer, const efi_bmp_image_header *header, + int blt_width, int blt_height, enum lb_fb_orientation orientation) +{ + size_t gop_x; + size_t gop_y; + size_t gop_width; + + if (!header || !gop_blt_buffer) + return NULL; + + switch (orientation) { + case LB_FB_ORIENTATION_LEFT_UP: + case LB_FB_ORIENTATION_RIGHT_UP: + gop_width = header->PixelHeight; + break; + + case LB_FB_ORIENTATION_BOTTOM_UP: + case LB_FB_ORIENTATION_NORMAL: + default: + gop_width = header->PixelWidth; + break; + } + + if (!calculate_adj_height_width(header, &gop_x, &gop_y, orientation, + blt_width, blt_height)) + return NULL; + + /* + * Calculated pixel in the Graphics Output Protocol (GOP) blit buffer. + * This offset represents the starting position where the blitted region will be placed + * in the framebuffer. + */ + return &gop_blt_buffer[gop_y * gop_width + gop_x]; +} + +/* + * Fill BMP image into BLT buffer format with optional orientation + * + * +------------------------------------------------------------------+ + * | BMP Image (header: efi_bmp_image_header) | + * | (PixelWidth, PixelHeight) | + * +------------------------------------------------------------------+ + * | + * | (blt_width, blt_height) : Region to blit + * V + * +------------------------------------------------------------------+ + * | calculate_adj_height_width(header, adjusted_x, adjusted_y, | + * | orientation, blt_width, blt_height)| + * +------------------------------------------------------------------+ + * | + * | Calculates adjusted coordinates based on orientation: + * | - flipped_x = header->PixelWidth - blt_width - 1 + * | - flipped_y = header->PixelHeight - blt_height - 1 + * | - Depending on 'orientation', adjusted_x and adjusted_y are set. + * V + * +-------------------------------------------------------------------+ + * | get_gop_blt_pixel(gop_blt_buffer, header, blt_width, blt_height, | + * | orientation) | + * +-------------------------------------------------------------------+ + * | + * | 1. Determines gop_width based on orientation: + * | - LEFT_UP/RIGHT_UP: gop_width = header->PixelHeight, + * | - BOTTOM_UP/NORMAL: gop_width = header->PixelWidth, + * | 2. Calls calculate_adj_height_width to get gop_x and gop_y. + * | 3. GOP BLT offset: calculates linear offset into the GOP buffer + * | - gop_blt_offset = gop_y * gop_width + gop_x + * | 4. GOP BLT offset is used to access the correct regions in: + * V + * +------------------------------------------------------------------+ + * | GOP Blit Buffer (Framebuffer) | + * +------------------------------------------------------------------+ + */ static void *fill_blt_buffer(efi_bmp_image_header *header, - uintptr_t logo_ptr, size_t blt_buffer_size) + uintptr_t logo_ptr, size_t blt_buffer_size, enum lb_fb_orientation orientation) { efi_graphics_output_blt_pixel *gop_blt_buffer; efi_graphics_output_blt_pixel *gop_blt_ptr; @@ -157,25 +333,32 @@ static void *fill_blt_buffer(efi_bmp_image_header *header, bmp_color_map = (efi_bmp_color_map *)(logo_ptr + sizeof(efi_bmp_image_header)); for (size_t height = 0; height < header->PixelHeight; height++) { - gop_blt = &gop_blt_buffer[(header->PixelHeight - height - 1) * - header->PixelWidth]; - for (size_t width = 0; width < header->PixelWidth; width++, bmp_image++, - gop_blt++) { + for (size_t width = 0; width < header->PixelWidth; width++, bmp_image++) { size_t index = 0; + + gop_blt = get_gop_blt_pixel(gop_blt_buffer, header, width, height, + orientation); + if (!gop_blt) { + free(gop_blt_ptr); + return NULL; + } + switch (header->BitPerPixel) { /* Translate 1-bit (2 colors) BMP to 24-bit color */ case 1: for (index = 0; index < 8 && width < header->PixelWidth; index++) { - gop_blt->Red = bmp_color_map[((*bmp_image) >> (7 - index)) - & 0x1].Red; - gop_blt->Green = bmp_color_map[((*bmp_image) >> (7 - index)) - & 0x1].Green; - gop_blt->Blue = bmp_color_map[((*bmp_image) >> (7 - index)) - & 0x1].Blue; - gop_blt++; + uint8_t bit = ((*bmp_image) >> (7 - index)) & 0x1; + gop_blt->Red = bmp_color_map[bit].Red; + gop_blt->Green = bmp_color_map[bit].Green; + gop_blt->Blue = bmp_color_map[bit].Blue; width++; + gop_blt = get_gop_blt_pixel(gop_blt_buffer, header, width, height, + orientation); + if (!gop_blt) { + free(gop_blt_ptr); + return NULL; + } } - gop_blt--; width--; break; @@ -186,8 +369,13 @@ static void *fill_blt_buffer(efi_bmp_image_header *header, gop_blt->Green = bmp_color_map[index].Green; gop_blt->Blue = bmp_color_map[index].Blue; if (width < (header->PixelWidth - 1)) { - gop_blt++; width++; + gop_blt = get_gop_blt_pixel(gop_blt_buffer, header, width, height, + orientation); + if (!gop_blt) { + free(gop_blt_ptr); + return NULL; + } index = (*bmp_image) & 0x0f; gop_blt->Red = bmp_color_map[index].Red; gop_blt->Green = bmp_color_map[index].Green; @@ -237,8 +425,8 @@ static void *fill_blt_buffer(efi_bmp_image_header *header, /* Convert a *.BMP graphics image to a GOP blt buffer */ void fsp_convert_bmp_to_gop_blt(efi_uintn_t *logo, uint32_t *logo_size, - efi_uintn_t *blt_ptr, efi_uintn_t *blt_size, - uint32_t *pixel_height, uint32_t *pixel_width) + efi_uintn_t *blt_ptr, efi_uintn_t *blt_size, uint32_t *pixel_height, uint32_t *pixel_width, + enum lb_fb_orientation orientation) { uintptr_t logo_ptr; size_t logo_ptr_size, blt_buffer_size; @@ -265,10 +453,12 @@ void fsp_convert_bmp_to_gop_blt(efi_uintn_t *logo, uint32_t *logo_size, if (!get_color_map_num(bmp_header)) return; + bool is_standard_orientation = (orientation == LB_FB_ORIENTATION_NORMAL || + orientation == LB_FB_ORIENTATION_BOTTOM_UP); *logo = logo_ptr; *logo_size = logo_ptr_size; *blt_size = blt_buffer_size; - *pixel_height = bmp_header->PixelHeight; - *pixel_width = bmp_header->PixelWidth; - *blt_ptr = (uintptr_t)fill_blt_buffer(bmp_header, logo_ptr, blt_buffer_size); + *pixel_height = is_standard_orientation ? bmp_header->PixelHeight : bmp_header->PixelWidth; + *pixel_width = is_standard_orientation ? bmp_header->PixelWidth : bmp_header->PixelHeight; + *blt_ptr = (uintptr_t)fill_blt_buffer(bmp_header, logo_ptr, blt_buffer_size, orientation); } diff --git a/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h b/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h index ff1548328e..4e1f68952e 100644 --- a/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h +++ b/src/drivers/intel/fsp2_0/include/fsp/fsp_gop_blt.h @@ -8,7 +8,7 @@ /* Convert a *.BMP graphics image to a GOP blt buffer */ void fsp_convert_bmp_to_gop_blt(efi_uintn_t *logo, uint32_t *logo_size, - efi_uintn_t *blt_ptr, efi_uintn_t *blt_size, - uint32_t *pixel_height, uint32_t *pixel_width); + efi_uintn_t *blt_ptr, efi_uintn_t *blt_size, uint32_t *pixel_height, uint32_t *pixel_width, + enum lb_fb_orientation orientation); #endif /* FSP_GOP_BLT_H */ diff --git a/src/soc/intel/alderlake/fsp_params.c b/src/soc/intel/alderlake/fsp_params.c index 39582b5ec6..28c9169529 100644 --- a/src/soc/intel/alderlake/fsp_params.c +++ b/src/soc/intel/alderlake/fsp_params.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include @@ -1376,10 +1377,25 @@ __weak void mainboard_silicon_init_params(FSP_S_CONFIG *s_cfg) /* Handle FSP logo params */ void soc_load_logo(FSPS_UPD *supd) { + struct soc_intel_common_config *config = chip_get_common_soc_structure(); + FSP_S_CONFIG *s_cfg = &supd->FspsConfig; + + /* + * Adjusts panel orientation for external display when the lid is closed. + * + * When the lid is closed (LidStatus == 0), indicating the onboard display is inactive, + * this function forces the panel orientation to normal. This ensures proper display + * on an external monitor, as rotated orientations are typically not suitable in + * such state. + */ + if (s_cfg->LidStatus == 0) + config->panel_orientation = LB_FB_ORIENTATION_NORMAL; + fsp_convert_bmp_to_gop_blt(&supd->FspsConfig.LogoPtr, &supd->FspsConfig.LogoSize, &supd->FspsConfig.BltBufferAddress, &supd->FspsConfig.BltBufferSize, &supd->FspsConfig.LogoPixelHeight, - &supd->FspsConfig.LogoPixelWidth); + &supd->FspsConfig.LogoPixelWidth, + config->panel_orientation); } diff --git a/src/soc/intel/meteorlake/fsp_params.c b/src/soc/intel/meteorlake/fsp_params.c index f3fec481b4..ad85702dbe 100644 --- a/src/soc/intel/meteorlake/fsp_params.c +++ b/src/soc/intel/meteorlake/fsp_params.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include +#include #include #include #include @@ -869,10 +870,25 @@ __weak void mainboard_silicon_init_params(FSP_S_CONFIG *s_cfg) /* Handle FSP logo params */ void soc_load_logo(FSPS_UPD *supd) { + struct soc_intel_common_config *config = chip_get_common_soc_structure(); + FSP_S_CONFIG *s_cfg = &supd->FspsConfig; + + /* + * Adjusts panel orientation for external display when the lid is closed. + * + * When the lid is closed (LidStatus == 0), indicating the onboard display is inactive, + * this function forces the panel orientation to normal. This ensures proper display + * on an external monitor, as rotated orientations are typically not suitable in + * such state. + */ + if (s_cfg->LidStatus == 0) + config->panel_orientation = LB_FB_ORIENTATION_NORMAL; + fsp_convert_bmp_to_gop_blt(&supd->FspsConfig.LogoPtr, &supd->FspsConfig.LogoSize, &supd->FspsConfig.BltBufferAddress, &supd->FspsConfig.BltBufferSize, &supd->FspsConfig.LogoPixelHeight, - &supd->FspsConfig.LogoPixelWidth); + &supd->FspsConfig.LogoPixelWidth, + config->panel_orientation); } diff --git a/src/soc/intel/pantherlake/fsp_params.c b/src/soc/intel/pantherlake/fsp_params.c index fefd3e0890..7544894b75 100644 --- a/src/soc/intel/pantherlake/fsp_params.c +++ b/src/soc/intel/pantherlake/fsp_params.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include #include @@ -785,10 +786,24 @@ void soc_load_logo(FSPS_UPD *supd) { efi_uintn_t logo, blt_size; uint32_t logo_size; + struct soc_intel_common_config *config = chip_get_common_soc_structure(); + FSP_S_CONFIG *s_cfg = &supd->FspsConfig; + + /* + * Adjusts panel orientation for external display when the lid is closed. + * + * When the lid is closed (LidStatus == 0), indicating the onboard display is inactive, + * this function forces the panel orientation to normal. This ensures proper display + * on an external monitor, as rotated orientations are typically not suitable in + * such state. + */ + if (s_cfg->LidStatus == 0) + config->panel_orientation = LB_FB_ORIENTATION_NORMAL; fsp_convert_bmp_to_gop_blt(&logo, &logo_size, &supd->FspsConfig.BltBufferAddress, &blt_size, &supd->FspsConfig.LogoPixelHeight, - &supd->FspsConfig.LogoPixelWidth); + &supd->FspsConfig.LogoPixelWidth, + config->panel_orientation); }