From e446c1f9171445229c070ea152975f342a396d75 Mon Sep 17 00:00:00 2001 From: Subrata Banik Date: Mon, 5 May 2025 19:36:42 +0530 Subject: [PATCH] drivers/intel/fsp2_0: Introduce coreboot native logo rendering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/87541 Reviewed-by: Jérémy Compostella Tested-by: build bot (Jenkins) Reviewed-by: Nick Vaccaro --- src/drivers/intel/fsp2_0/Makefile.mk | 1 + src/drivers/intel/fsp2_0/cb_logo.c | 175 +++++++++++++++++++++ src/drivers/intel/fsp2_0/include/fsp/api.h | 22 +++ src/drivers/intel/fsp2_0/silicon_init.c | 20 +++ 4 files changed, 218 insertions(+) create mode 100644 src/drivers/intel/fsp2_0/cb_logo.c diff --git a/src/drivers/intel/fsp2_0/Makefile.mk b/src/drivers/intel/fsp2_0/Makefile.mk index 18a62e3b57..16905ca373 100644 --- a/src/drivers/intel/fsp2_0/Makefile.mk +++ b/src/drivers/intel/fsp2_0/Makefile.mk @@ -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 diff --git a/src/drivers/intel/fsp2_0/cb_logo.c b/src/drivers/intel/fsp2_0/cb_logo.c new file mode 100644 index 0000000000..cc62a1c553 --- /dev/null +++ b/src/drivers/intel/fsp2_0/cb_logo.c @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#define __SIMPLE_DEVICE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/src/drivers/intel/fsp2_0/include/fsp/api.h b/src/drivers/intel/fsp2_0/include/fsp/api.h index 8c9dc8c529..9ff32be6fc 100644 --- a/src/drivers/intel/fsp2_0/include/fsp/api.h +++ b/src/drivers/intel/fsp2_0/include/fsp/api.h @@ -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); diff --git a/src/drivers/intel/fsp2_0/silicon_init.c b/src/drivers/intel/fsp2_0/silicon_init.c index cd4b5cb682..76636dd7a8 100644 --- a/src/drivers/intel/fsp2_0/silicon_init.c +++ b/src/drivers/intel/fsp2_0/silicon_init.c @@ -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();