drivers/intel/fsp2_0: Introduce coreboot native logo rendering

This commit implements coreboot native logo rendering when
`USE_COREBOOT_FOR_BMP_RENDERING` Kconfig is enabled.

When enabled, this option allows coreboot to perform the boot logo
rendering directly after the FSP initializes the display. A new API
`soc_load_logo_by_coreboot` is introduced for this purpose.

This approach offers greater flexibility for platform-specific logo
customizations (e.g., alignment) that might be impractical to
implement within the FSP.

Note that enabling this option might introduce a slight delay (~10-30ms)
in displaying BMP images compared to FSP-based rendering.

BUG=b:409718202
TEST=Built and booted google/fatcat. Verified boot splash was rendered
by coreboot as `USE_COREBOOT_FOR_BMP_RENDERING` was set to `y`.

Change-Id: I9454d0941458e29a5533a92170831f360765b413
Signed-off-by: Subrata Banik <subratabanik@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/87541
Reviewed-by: Jérémy Compostella <jeremy.compostella@intel.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
This commit is contained in:
Subrata Banik 2025-05-05 19:36:42 +05:30
commit e446c1f917
4 changed files with 218 additions and 0 deletions

View file

@ -35,6 +35,7 @@ ramstage-$(CONFIG_FSP_NVS_DATA_POST_SILICON_INIT) += save_mrc_data.c
ramstage-$(CONFIG_MMA) += mma_core.c
ramstage-$(CONFIG_ENABLE_FSP_ERROR_INFO) += fsp_error_info_hob.c
ramstage-$(CONFIG_BMP_LOGO) += fsp_gop_blt.c
ramstage-$(CONFIG_USE_COREBOOT_FOR_BMP_RENDERING) += cb_logo.c
ifneq ($(CONFIG_NO_FSP_TEMP_RAM_EXIT),y)
postcar-$(CONFIG_FSP_CAR) += temp_ram_exit.c

View file

@ -0,0 +1,175 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#define __SIMPLE_DEVICE__
#include <bootmode.h>
#include <console/console.h>
#include <cpu/x86/mtrr.h>
#include <device/pci_ops.h>
#include <fsp/api.h>
#include <fsp/fsp_gop_blt.h>
#include <fsp/graphics.h>
#include <fsp/util.h>
#include <intelblocks/graphics.h>
#include <soc/iomap.h>
#include <soc/soc_chip.h>
#include <stdlib.h>
#include <string.h>
struct logo_coordinates {
uint32_t x;
uint32_t y;
};
/*
* Programs the Local Memory BAR (LMEMBAR) for the IGD.
*
* This function disables PCI command bits related to I/O, memory, and bus mastering
* for the IGD, programs the LMEMBAR with the provided base address, and then
* re-enables the PCI command bits.
*/
static void program_igd_lmembar(uint32_t base)
{
const uint16_t disable_mask = ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
const uint16_t enable_mask = (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
/* Disable response in IO, MMIO space and Bus Master. */
pci_and_config16(SA_DEV_IGD, PCI_COMMAND, disable_mask);
/* Program IGD Base Address Register 2 aka LMEMBAR */
pci_write_config32(SA_DEV_IGD, PCI_BASE_ADDRESS_2, base);
/* Enable response in IO, MMIO space and Bus Master. */
pci_or_config16(SA_DEV_IGD, PCI_COMMAND, enable_mask);
}
/*
* Calculates the destination coordinates for the logo based on alignment settings.
*
* horizontal_resolution: The horizontal resolution of the display panel.
* vertical_resolution: The vertical resolution of the display panel.
* logo_width: The width of the logo bitmap.
* logo_height: The height of the logo bitmap.
* valignment: The vertical alignment setting.
*
* Returning `struct logo_coordinates` that contains the calculated x and y coordinates
* for rendering the logo.
*/
static struct logo_coordinates calculate_logo_coordinates(
uint32_t horizontal_resolution, uint32_t vertical_resolution,
uint32_t logo_width, uint32_t logo_height, enum fw_splash_vertical_alignment valignment)
{
struct logo_coordinates coords;
/* Always horizontally centered */
coords.x = (horizontal_resolution - logo_width) / 2;
switch (valignment) {
case FW_SPLASH_VALIGNMENT_MIDDLE:
coords.y = vertical_resolution / 2;
break;
case FW_SPLASH_VALIGNMENT_TOP:
coords.y = 0;
break;
case FW_SPLASH_VALIGNMENT_BOTTOM:
coords.y = vertical_resolution - logo_height;
break;
default: /* FW_SPLASH_VALIGNMENT_CENTER (default) */
coords.y = (vertical_resolution - logo_height) / 2;
break;
}
return coords;
}
/*
* Copies the logo to the framebuffer.
*
* framebuffer_base: The base address of the framebuffer.
* bytes_per_scanline: The number of bytes per scanline in the framebuffer.
* logo_buffer_addr: The address of the logo data in BLT format.
* logo_width: The width of the logo bitmap.
* logo_height: The height of the logo bitmap.
* dest_x: The destination x-coordinate in the framebuffer for rendering the logo.
* dest_y: The destination y-coordinate in the framebuffer for rendering the logo.
*/
static void copy_logo_to_framebuffer(
uintptr_t framebuffer_base, uint32_t bytes_per_scanline,
efi_uintn_t logo_buffer_addr, uint32_t logo_width, uint32_t logo_height,
efi_uintn_t dest_x, efi_uintn_t dest_y)
{
size_t pixel_size = sizeof(efi_graphics_output_blt_pixel);
size_t logo_line_bytes = logo_width * pixel_size;
efi_uintn_t framebuffer_offset = framebuffer_base + dest_y * bytes_per_scanline
+ dest_x * pixel_size;
uint8_t *dst_row_address = (uint8_t *)framebuffer_offset;
uint8_t *src_row_address = (uint8_t *)(uintptr_t)logo_buffer_addr;
for (uint32_t i = 0; i < logo_height; i++) {
memcpy(dst_row_address, src_row_address, logo_line_bytes);
dst_row_address += bytes_per_scanline;
src_row_address += logo_line_bytes;
}
}
void soc_load_logo_by_coreboot(void)
{
size_t size;
const struct hob_graphics_info *ginfo;
struct soc_intel_common_config *config = chip_get_common_soc_structure();
efi_uintn_t logo, blt_size;
efi_uintn_t blt_buffer_addr;
uint32_t logo_size, logo_height, logo_width;
int temp_mtrr_index = -1;
/* Find the graphics information HOB */
ginfo = fsp_find_extension_hob_by_guid(fsp_graphics_info_guid, &size);
if (!ginfo || ginfo->framebuffer_base == 0) {
printk(BIOS_ERR, "Graphics information HOB not found or invalid framebuffer base.\n");
return;
}
/* Program the IGD LMEMBAR */
program_igd_lmembar(GMADR_BASE);
/* Set up a temporary Write Combine (WC) MTRR for the GMADR range */
temp_mtrr_index = acquire_and_configure_mtrr(GMADR_BASE, GMADR_SIZE, MTRR_TYPE_WRCOMB);
if (temp_mtrr_index < 0) {
printk(BIOS_ERR, "Failed to configure WC MTRR for GMADR.\n");
return;
}
uintptr_t framebuffer_bar = ginfo->framebuffer_base;
uint32_t horizontal_resolution = ginfo->horizontal_resolution;
uint32_t vertical_resolution = ginfo->vertical_resolution;
uint32_t bytes_per_scanline = ginfo->pixels_per_scanline *
sizeof(efi_graphics_output_blt_pixel);
/*
* Adjusts panel orientation for external display when the lid is closed.
*
* When the lid is closed, indicating the onboard display is inactive,
* below logic 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 (CONFIG(VBOOT_LID_SWITCH) ? !get_lid_switch() : !CONFIG(RUN_FSP_GOP))
config->panel_orientation = LB_FB_ORIENTATION_NORMAL;
/* Convert BMP logo to GOP BLT format */
fsp_convert_bmp_to_gop_blt(&logo, &logo_size, &blt_buffer_addr, &blt_size,
&logo_height, &logo_width, config->panel_orientation);
/* Override logo alignment if the default screen orientation is not normal */
if (config->panel_orientation != LB_FB_ORIENTATION_NORMAL)
config->logo_valignment = FW_SPLASH_VALIGNMENT_CENTER;
/* Calculate logo destination coordinates */
struct logo_coordinates logo_coords = calculate_logo_coordinates(horizontal_resolution,
vertical_resolution, logo_width, logo_height, config->logo_valignment);
/* Copy the logo to the framebuffer */
copy_logo_to_framebuffer(framebuffer_bar, bytes_per_scanline, blt_buffer_addr, logo_width,
logo_height, logo_coords.x, logo_coords.y);
/* Clear temporary Write Combine (WC) MTRR */
clear_var_mtrr(temp_mtrr_index);
}

View file

@ -90,6 +90,28 @@ void setup_mma(FSP_M_CONFIG *memory_cfg);
* the FSP's capability for rendering bitmap (BMP) images.
*/
void soc_load_logo_by_fsp(FSPS_UPD *supd);
/*
* API that allows coreboot to perform native logo rendering after FSP display initialization.
*
* This implementation handles rendering the boot logo directly within coreboot.
* It depends on the FSP to initialize the display panel.
* Once the FSP completes display initialization and transfers control, coreboot
* renders the logo.
*
* Note: This native approach may introduce a ~10-30ms delay in displaying
* BMP images compared to rendering via FSP (when `USE_COREBOOT_FOR_BMP_RENDERING`
* Kconfig is not enable).
*
* coreboot native logo rendering provides greater flexibility for platform-specific
* logo customizations (e.g., alignment) that are not feasible or practical to implement
* within the FSP (silicon firmware) depending upon the OEM device need.
*/
#if CONFIG(USE_COREBOOT_FOR_BMP_RENDERING)
void soc_load_logo_by_coreboot(void);
#else
static inline void soc_load_logo_by_coreboot(void) { /* nop */ }
#endif
/* Update the SOC specific memory config param for mma. */
void soc_update_memory_params_for_mma(FSP_M_CONFIG *memory_cfg,
struct mma_config_param *mma_cfg);

View file

@ -157,6 +157,17 @@ static void do_silicon_init(struct fsp_header *hdr)
fsp_debug_after_silicon_init(status);
fsps_return_value_handler(FSP_SILICON_INIT_API, status);
/*
* Only applies for SoC platforms prior to FSP 2.2 specification:
* If a BMP logo is enabled (`BMP_LOGO`) and the platform is
* configured to skip the FSP for rendering logo bitmap
* (`USE_COREBOOT_FOR_BMP_RENDERING`), then call the coreboot
* native function to handle BMP logo loading and display.
*/
if (!CONFIG(PLATFORM_USES_FSP2_2) && CONFIG(BMP_LOGO) &&
CONFIG(USE_COREBOOT_FOR_BMP_RENDERING))
soc_load_logo_by_coreboot();
/* Reinitialize CPUs if FSP-S has done MP Init */
if (CONFIG(USE_INTEL_FSP_MP_INIT) && !fsp_is_multi_phase_init_enabled())
do_mpinit_after_fsp();
@ -205,6 +216,15 @@ static void do_silicon_init(struct fsp_header *hdr)
timestamp_add_now(TS_FSP_MULTI_PHASE_SI_INIT_END);
post_code(POSTCODE_FSP_MULTI_PHASE_SI_INIT_EXIT);
/*
* If a BMP logo is enabled (`BMP_LOGO`) and the platform is
* configured to skip the FSP for rendering logo bitmap
* (`USE_COREBOOT_FOR_BMP_RENDERING`), then call the coreboot
* native function to handle BMP logo loading and display.
*/
if (CONFIG(BMP_LOGO) && CONFIG(USE_COREBOOT_FOR_BMP_RENDERING))
soc_load_logo_by_coreboot();
/* Reinitialize CPUs if FSP-S has done MP Init */
if (CONFIG(USE_INTEL_FSP_MP_INIT))
do_mpinit_after_fsp();