From 83311886151f80ef24d30f850baece07d08863cb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 25 Sep 2019 08:00:11 -0600 Subject: x86: Rename existing FSP code to fsp1 Since there is now a new version of the FSP and it is incompatible with the existing version, move the code into an fsp1 directory. This will allow us to put FSP v2 code into an fsp2 directory. Add a Kconfig which defines which version is in use. Some of the code in this new fsp1/ directory is generic across both FSPv1 and FSPv2. Future patches will address this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng --- arch/x86/lib/Makefile | 3 +- arch/x86/lib/fsp/Makefile | 9 - arch/x86/lib/fsp/fsp_car.S | 111 ------------ arch/x86/lib/fsp/fsp_common.c | 165 ------------------ arch/x86/lib/fsp/fsp_dram.c | 108 ------------ arch/x86/lib/fsp/fsp_graphics.c | 127 -------------- arch/x86/lib/fsp/fsp_support.c | 366 --------------------------------------- arch/x86/lib/fsp1/Makefile | 9 + arch/x86/lib/fsp1/fsp_car.S | 111 ++++++++++++ arch/x86/lib/fsp1/fsp_common.c | 165 ++++++++++++++++++ arch/x86/lib/fsp1/fsp_dram.c | 108 ++++++++++++ arch/x86/lib/fsp1/fsp_graphics.c | 127 ++++++++++++++ arch/x86/lib/fsp1/fsp_support.c | 366 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 888 insertions(+), 887 deletions(-) delete mode 100644 arch/x86/lib/fsp/Makefile delete mode 100644 arch/x86/lib/fsp/fsp_car.S delete mode 100644 arch/x86/lib/fsp/fsp_common.c delete mode 100644 arch/x86/lib/fsp/fsp_dram.c delete mode 100644 arch/x86/lib/fsp/fsp_graphics.c delete mode 100644 arch/x86/lib/fsp/fsp_support.c create mode 100644 arch/x86/lib/fsp1/Makefile create mode 100644 arch/x86/lib/fsp1/fsp_car.S create mode 100644 arch/x86/lib/fsp1/fsp_common.c create mode 100644 arch/x86/lib/fsp1/fsp_dram.c create mode 100644 arch/x86/lib/fsp1/fsp_graphics.c create mode 100644 arch/x86/lib/fsp1/fsp_support.c (limited to 'arch/x86/lib') diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 906be5eab9..a8c7448ee4 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -43,7 +43,8 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CMD_ZBOOT) += zimage.o endif obj-$(CONFIG_USE_HOB) += hob.o -obj-$(CONFIG_HAVE_FSP) += fsp/ +obj-$(CONFIG_FSP_VERSION1) += fsp1/ +obj-$(CONFIG_FSP_VERSION2) += fsp2/ ifdef CONFIG_SPL_BUILD ifdef CONFIG_TPL_BUILD diff --git a/arch/x86/lib/fsp/Makefile b/arch/x86/lib/fsp/Makefile deleted file mode 100644 index 870de71bd7..0000000000 --- a/arch/x86/lib/fsp/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright (C) 2015 Google, Inc - -obj-y += fsp_car.o -obj-y += fsp_common.o -obj-y += fsp_dram.o -obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o -obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S deleted file mode 100644 index 8c54cea3db..0000000000 --- a/arch/x86/lib/fsp/fsp_car.S +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014, Bin Meng - */ - -#include -#include - -.globl car_init -car_init: - /* - * Note: ebp holds the BIST value (built-in self test) so far, but ebp - * will be destroyed through the FSP call, thus we have to test the - * BIST value here before we call into FSP. - */ - test %ebp, %ebp - jz car_init_start - post_code(POST_BIST_FAILURE) - jmp die - -car_init_start: - post_code(POST_CAR_START) - lea find_fsp_header_romstack, %esp - jmp find_fsp_header - -find_fsp_header_ret: - /* EAX points to FSP_INFO_HEADER */ - mov %eax, %ebp - - /* sanity test */ - cmp $CONFIG_FSP_ADDR, %eax - jb die - - /* calculate TempRamInitEntry address */ - mov 0x30(%ebp), %eax - add 0x1c(%ebp), %eax - - /* call FSP TempRamInitEntry to setup temporary stack */ - lea temp_ram_init_romstack, %esp - jmp *%eax - -temp_ram_init_ret: - addl $4, %esp - cmp $0, %eax - jnz car_init_fail - - post_code(POST_CAR_CPU_CACHE) - - /* - * The FSP TempRamInit initializes the ecx and edx registers to - * point to a temporary but writable memory range (Cache-As-RAM). - * ecx: the start of this temporary memory range, - * edx: the end of this range. - */ - - /* stack grows down from top of CAR */ - movl %edx, %esp - subl $4, %esp - - xor %esi, %esi - jmp car_init_done - -.global fsp_init_done -fsp_init_done: - /* - * We come here from fsp_continue() with eax pointing to the HOB list. - * Save eax to esi temporarily. - */ - movl %eax, %esi - -car_init_done: - /* - * Re-initialize the ebp (BIST) to zero, as we already reach here - * which means we passed BIST testing before. - */ - xorl %ebp, %ebp - jmp car_init_ret - -car_init_fail: - post_code(POST_CAR_FAILURE) - -die: - hlt - jmp die - hlt - - /* - * The function call before CAR initialization is tricky. It cannot - * be called using the 'call' instruction but only the 'jmp' with - * the help of a handcrafted stack in the ROM. The stack needs to - * contain the function return address as well as the parameters. - */ - .balign 4 -find_fsp_header_romstack: - .long find_fsp_header_ret - - .balign 4 -temp_ram_init_romstack: - .long temp_ram_init_ret - .long temp_ram_init_params -temp_ram_init_params: -_dt_ucode_base_size: - /* These next two fields are filled in by binman */ -.globl ucode_base -ucode_base: /* Declared in microcode.h */ - .long 0 /* microcode base */ -.globl ucode_size -ucode_size: /* Declared in microcode.h */ - .long 0 /* microcode size */ - .long CONFIG_SYS_MONITOR_BASE /* code region base */ - .long CONFIG_SYS_MONITOR_LEN /* code region size */ diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c deleted file mode 100644 index ed0827c6e9..0000000000 --- a/arch/x86/lib/fsp/fsp_common.c +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2014, Bin Meng - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -int checkcpu(void) -{ - return 0; -} - -int print_cpuinfo(void) -{ - post_code(POST_CPU_INFO); - return default_print_cpuinfo(); -} - -int fsp_init_phase_pci(void) -{ - u32 status; - - /* call into FspNotify */ - debug("Calling into FSP (notify phase INIT_PHASE_PCI): "); - status = fsp_notify(NULL, INIT_PHASE_PCI); - if (status) - debug("fail, error code %x\n", status); - else - debug("OK\n"); - - return status ? -EPERM : 0; -} - -void board_final_cleanup(void) -{ - u32 status; - - /* call into FspNotify */ - debug("Calling into FSP (notify phase INIT_PHASE_BOOT): "); - status = fsp_notify(NULL, INIT_PHASE_BOOT); - if (status) - debug("fail, error code %x\n", status); - else - debug("OK\n"); - - return; -} - -static __maybe_unused void *fsp_prepare_mrc_cache(void) -{ - struct mrc_data_container *cache; - struct mrc_region entry; - int ret; - - ret = mrccache_get_region(NULL, &entry); - if (ret) - return NULL; - - cache = mrccache_find_current(&entry); - if (!cache) - return NULL; - - debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, - cache->data, cache->data_size, cache->checksum); - - return cache->data; -} - -#ifdef CONFIG_HAVE_ACPI_RESUME -int fsp_save_s3_stack(void) -{ - struct udevice *dev; - int ret; - - if (gd->arch.prev_sleep_state == ACPI_S3) - return 0; - - ret = uclass_get_device(UCLASS_RTC, 0, &dev); - if (ret) { - debug("Cannot find RTC: err=%d\n", ret); - return -ENODEV; - } - - /* Save the stack address to CMOS */ - ret = rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp); - if (ret) { - debug("Save stack address to CMOS: err=%d\n", ret); - return -EIO; - } - - return 0; -} -#endif - -int arch_fsp_init(void) -{ - void *nvs; - int stack = CONFIG_FSP_TEMP_RAM_ADDR; - int boot_mode = BOOT_FULL_CONFIG; -#ifdef CONFIG_HAVE_ACPI_RESUME - int prev_sleep_state = chipset_prev_sleep_state(); - gd->arch.prev_sleep_state = prev_sleep_state; -#endif - - if (!gd->arch.hob_list) { -#ifdef CONFIG_ENABLE_MRC_CACHE - nvs = fsp_prepare_mrc_cache(); -#else - nvs = NULL; -#endif - -#ifdef CONFIG_HAVE_ACPI_RESUME - if (prev_sleep_state == ACPI_S3) { - if (nvs == NULL) { - /* If waking from S3 and no cache then */ - debug("No MRC cache found in S3 resume path\n"); - post_code(POST_RESUME_FAILURE); - /* Clear Sleep Type */ - chipset_clear_sleep_state(); - /* Reboot */ - debug("Rebooting..\n"); - outb(SYS_RST | RST_CPU, IO_PORT_RESET); - /* Should not reach here.. */ - panic("Reboot System"); - } - - /* - * DM is not available yet at this point, hence call - * CMOS access library which does not depend on DM. - */ - stack = cmos_read32(CMOS_FSP_STACK_ADDR); - boot_mode = BOOT_ON_S3_RESUME; - } -#endif - /* - * The first time we enter here, call fsp_init(). - * Note the execution does not return to this function, - * instead it jumps to fsp_continue(). - */ - fsp_init(stack, boot_mode, nvs); - } else { - /* - * The second time we enter here, adjust the size of malloc() - * pool before relocation. Given gd->malloc_base was adjusted - * after the call to board_init_f_init_reserve() in arch/x86/ - * cpu/start.S, we should fix up gd->malloc_limit here. - */ - gd->malloc_limit += CONFIG_FSP_SYS_MALLOC_F_LEN; - } - - return 0; -} diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c deleted file mode 100644 index 3a23b70410..0000000000 --- a/arch/x86/lib/fsp/fsp_dram.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2014, Bin Meng - */ - -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -int dram_init(void) -{ - phys_size_t ram_size = 0; - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - - hdr = gd->arch.hob_list; - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_SYS_MEM || - res_desc->type == RES_MEM_RESERVED) { - ram_size += res_desc->len; - } - } - hdr = get_next_hob(hdr); - } - - gd->ram_size = ram_size; - post_code(POST_DRAM); - -#ifdef CONFIG_ENABLE_MRC_CACHE - gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, - &gd->arch.mrc_output_len); -#endif - - return 0; -} - -int dram_init_banksize(void) -{ - gd->bd->bi_dram[0].start = 0; - gd->bd->bi_dram[0].size = gd->ram_size; - - return 0; -} - -/* - * This function looks for the highest region of memory lower than 4GB which - * has enough space for U-Boot where U-Boot is aligned on a page boundary. - * It overrides the default implementation found elsewhere which simply - * picks the end of ram, wherever that may be. The location of the stack, - * the relocation address, and how far U-Boot is moved by relocation are - * set in the global data structure. - */ -ulong board_get_usable_ram_top(ulong total_size) -{ - return fsp_get_usable_lowmem_top(gd->arch.hob_list); -} - -unsigned int install_e820_map(unsigned int max_entries, - struct e820_entry *entries) -{ - unsigned int num_entries = 0; - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - - hdr = gd->arch.hob_list; - - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - entries[num_entries].addr = res_desc->phys_start; - entries[num_entries].size = res_desc->len; - - if (res_desc->type == RES_SYS_MEM) - entries[num_entries].type = E820_RAM; - else if (res_desc->type == RES_MEM_RESERVED) - entries[num_entries].type = E820_RESERVED; - - num_entries++; - } - hdr = get_next_hob(hdr); - } - - /* Mark PCIe ECAM address range as reserved */ - entries[num_entries].addr = CONFIG_PCIE_ECAM_BASE; - entries[num_entries].size = CONFIG_PCIE_ECAM_SIZE; - entries[num_entries].type = E820_RESERVED; - num_entries++; - -#ifdef CONFIG_HAVE_ACPI_RESUME - /* - * Everything between U-Boot's stack and ram top needs to be - * reserved in order for ACPI S3 resume to work. - */ - entries[num_entries].addr = gd->start_addr_sp - CONFIG_STACK_SIZE; - entries[num_entries].size = gd->ram_top - gd->start_addr_sp + \ - CONFIG_STACK_SIZE; - entries[num_entries].type = E820_RESERVED; - num_entries++; -#endif - - return num_entries; -} diff --git a/arch/x86/lib/fsp/fsp_graphics.c b/arch/x86/lib/fsp/fsp_graphics.c deleted file mode 100644 index 91d2d08557..0000000000 --- a/arch/x86/lib/fsp/fsp_graphics.c +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2017, Bin Meng - */ - -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -struct pixel { - u8 pos; - u8 size; -}; - -static const struct fsp_framebuffer { - struct pixel red; - struct pixel green; - struct pixel blue; - struct pixel rsvd; -} fsp_framebuffer_format_map[] = { - [pixel_rgbx_8bpc] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} }, - [pixel_bgrx_8bpc] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} }, -}; - -static int save_vesa_mode(struct vesa_mode_info *vesa) -{ - const struct hob_graphics_info *ginfo; - const struct fsp_framebuffer *fbinfo; - - ginfo = fsp_get_graphics_info(gd->arch.hob_list, NULL); - - /* - * If there is no graphics info structure, bail out and keep - * running on the serial console. - * - * Note: on some platforms (eg: Braswell), the FSP will not produce - * the graphics info HOB unless you plug some cables to the display - * interface (eg: HDMI) on the board. - */ - if (!ginfo) { - debug("FSP graphics hand-off block not found\n"); - return -ENXIO; - } - - vesa->x_resolution = ginfo->width; - vesa->y_resolution = ginfo->height; - vesa->bits_per_pixel = 32; - vesa->bytes_per_scanline = ginfo->pixels_per_scanline * 4; - vesa->phys_base_ptr = ginfo->fb_base; - - if (ginfo->pixel_format >= pixel_bitmask) { - debug("FSP set unknown framebuffer format: %d\n", - ginfo->pixel_format); - return -EINVAL; - } - fbinfo = &fsp_framebuffer_format_map[ginfo->pixel_format]; - vesa->red_mask_size = fbinfo->red.size; - vesa->red_mask_pos = fbinfo->red.pos; - vesa->green_mask_size = fbinfo->green.size; - vesa->green_mask_pos = fbinfo->green.pos; - vesa->blue_mask_size = fbinfo->blue.size; - vesa->blue_mask_pos = fbinfo->blue.pos; - vesa->reserved_mask_size = fbinfo->rsvd.size; - vesa->reserved_mask_pos = fbinfo->rsvd.pos; - - return 0; -} - -static int fsp_video_probe(struct udevice *dev) -{ - struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); - struct video_priv *uc_priv = dev_get_uclass_priv(dev); - struct vesa_mode_info *vesa = &mode_info.vesa; - int ret; - - printf("Video: "); - - /* Initialize vesa_mode_info structure */ - ret = save_vesa_mode(vesa); - if (ret) - goto err; - - /* - * The framebuffer base address in the FSP graphics info HOB reflects - * the value assigned by the FSP. After PCI enumeration the framebuffer - * base address may be relocated. Let's get the updated one from device. - * - * For IGD, it seems to be always on BAR2. - */ - vesa->phys_base_ptr = dm_pci_read_bar32(dev, 2); - - ret = vbe_setup_video_priv(vesa, uc_priv, plat); - if (ret) - goto err; - - printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, - vesa->bits_per_pixel); - - return 0; - -err: - printf("No video mode configured in FSP!\n"); - return ret; -} - -static const struct udevice_id fsp_video_ids[] = { - { .compatible = "fsp-fb" }, - { } -}; - -U_BOOT_DRIVER(fsp_video) = { - .name = "fsp_video", - .id = UCLASS_VIDEO, - .of_match = fsp_video_ids, - .probe = fsp_video_probe, -}; - -static struct pci_device_id fsp_video_supported[] = { - { PCI_DEVICE_CLASS(PCI_CLASS_DISPLAY_VGA << 8, 0xffff00) }, - { }, -}; - -U_BOOT_PCI_DEVICE(fsp_video, fsp_video_supported); diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c deleted file mode 100644 index 0eaa9b232b..0000000000 --- a/arch/x86/lib/fsp/fsp_support.c +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-License-Identifier: Intel -/* - * Copyright (C) 2013, Intel Corporation - * Copyright (C) 2014, Bin Meng - */ - -#include -#include -#include - -struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void) -{ - /* - * This function may be called before the a stack is established, - * so special care must be taken. First, it cannot declare any local - * variable using stack. Only register variable can be used here. - * Secondly, some compiler version will add prolog or epilog code - * for the C function. If so the function call may not work before - * stack is ready. - * - * GCC 4.8.1 has been verified to be working for the following codes. - */ - volatile register u8 *fsp asm("eax"); - - /* Initalize the FSP base */ - fsp = (u8 *)CONFIG_FSP_ADDR; - - /* Check the FV signature, _FVH */ - if (((struct fv_header *)fsp)->sign == EFI_FVH_SIGNATURE) { - /* Go to the end of the FV header and align the address */ - fsp += ((struct fv_header *)fsp)->ext_hdr_off; - fsp += ((struct fv_ext_header *)fsp)->ext_hdr_size; - fsp = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8); - } else { - fsp = 0; - } - - /* Check the FFS GUID */ - if (fsp && - ((struct ffs_file_header *)fsp)->name.b[0] == FSP_GUID_BYTE0 && - ((struct ffs_file_header *)fsp)->name.b[1] == FSP_GUID_BYTE1 && - ((struct ffs_file_header *)fsp)->name.b[2] == FSP_GUID_BYTE2 && - ((struct ffs_file_header *)fsp)->name.b[3] == FSP_GUID_BYTE3 && - ((struct ffs_file_header *)fsp)->name.b[4] == FSP_GUID_BYTE4 && - ((struct ffs_file_header *)fsp)->name.b[5] == FSP_GUID_BYTE5 && - ((struct ffs_file_header *)fsp)->name.b[6] == FSP_GUID_BYTE6 && - ((struct ffs_file_header *)fsp)->name.b[7] == FSP_GUID_BYTE7 && - ((struct ffs_file_header *)fsp)->name.b[8] == FSP_GUID_BYTE8 && - ((struct ffs_file_header *)fsp)->name.b[9] == FSP_GUID_BYTE9 && - ((struct ffs_file_header *)fsp)->name.b[10] == FSP_GUID_BYTE10 && - ((struct ffs_file_header *)fsp)->name.b[11] == FSP_GUID_BYTE11 && - ((struct ffs_file_header *)fsp)->name.b[12] == FSP_GUID_BYTE12 && - ((struct ffs_file_header *)fsp)->name.b[13] == FSP_GUID_BYTE13 && - ((struct ffs_file_header *)fsp)->name.b[14] == FSP_GUID_BYTE14 && - ((struct ffs_file_header *)fsp)->name.b[15] == FSP_GUID_BYTE15) { - /* Add the FFS header size to find the raw section header */ - fsp += sizeof(struct ffs_file_header); - } else { - fsp = 0; - } - - if (fsp && - ((struct raw_section *)fsp)->type == EFI_SECTION_RAW) { - /* Add the raw section header size to find the FSP header */ - fsp += sizeof(struct raw_section); - } else { - fsp = 0; - } - - return (struct fsp_header *)fsp; -} - -void fsp_continue(u32 status, void *hob_list) -{ - post_code(POST_MRC); - - assert(status == 0); - - /* The boot loader main function entry */ - fsp_init_done(hob_list); -} - -void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) -{ - struct fsp_config_data config_data; - fsp_init_f init; - struct fsp_init_params params; - struct fspinit_rtbuf rt_buf; - struct fsp_header *fsp_hdr; - struct fsp_init_params *params_ptr; -#ifdef CONFIG_FSP_USE_UPD - struct vpd_region *fsp_vpd; - struct upd_region *fsp_upd; -#endif - - fsp_hdr = find_fsp_header(); - if (fsp_hdr == NULL) { - /* No valid FSP info header was found */ - panic("Invalid FSP header"); - } - - config_data.common.fsp_hdr = fsp_hdr; - config_data.common.stack_top = stack_top; - config_data.common.boot_mode = boot_mode; - -#ifdef CONFIG_FSP_USE_UPD - /* Get VPD region start */ - fsp_vpd = (struct vpd_region *)(fsp_hdr->img_base + - fsp_hdr->cfg_region_off); - - /* Verify the VPD data region is valid */ - assert(fsp_vpd->sign == VPD_IMAGE_ID); - - fsp_upd = &config_data.fsp_upd; - - /* Copy default data from Flash */ - memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset), - sizeof(struct upd_region)); - - /* Verify the UPD data region is valid */ - assert(fsp_upd->terminator == UPD_TERMINATOR); -#endif - - memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf)); - - /* Override any configuration if required */ - update_fsp_configs(&config_data, &rt_buf); - - memset(¶ms, 0, sizeof(struct fsp_init_params)); - params.nvs_buf = nvs_buf; - params.rt_buf = (struct fspinit_rtbuf *)&rt_buf; - params.continuation = (fsp_continuation_f)asm_continuation; - - init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init); - params_ptr = ¶ms; - - post_code(POST_PRE_MRC); - - /* Load GDT for FSP */ - setup_fsp_gdt(); - - /* - * Use ASM code to ensure the register value in EAX & EDX - * will be passed into fsp_continue - */ - asm volatile ( - "pushl %0;" - "call *%%eax;" - ".global asm_continuation;" - "asm_continuation:;" - "movl 4(%%esp), %%eax;" /* status */ - "movl 8(%%esp), %%edx;" /* hob_list */ - "jmp fsp_continue;" - : : "m"(params_ptr), "a"(init) - ); - - /* - * Should never get here. - * Control will continue from fsp_continue. - * This line below is to prevent the compiler from optimizing - * structure intialization. - * - * DO NOT REMOVE! - */ - init(¶ms); -} - -u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase) -{ - fsp_notify_f notify; - struct fsp_notify_params params; - struct fsp_notify_params *params_ptr; - u32 status; - - if (!fsp_hdr) - fsp_hdr = (struct fsp_header *)find_fsp_header(); - - if (fsp_hdr == NULL) { - /* No valid FSP info header */ - panic("Invalid FSP header"); - } - - notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify); - params.phase = phase; - params_ptr = ¶ms; - - /* - * Use ASM code to ensure correct parameter is on the stack for - * FspNotify as U-Boot is using different ABI from FSP - */ - asm volatile ( - "pushl %1;" /* push notify phase */ - "call *%%eax;" /* call FspNotify */ - "addl $4, %%esp;" /* clean up the stack */ - : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr) - ); - - return status; -} - -u32 fsp_get_usable_lowmem_top(const void *hob_list) -{ - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - phys_addr_t phys_start; - u32 top; -#ifdef CONFIG_FSP_BROKEN_HOB - struct hob_mem_alloc *res_mem; - phys_addr_t mem_base = 0; -#endif - - /* Get the HOB list for processing */ - hdr = hob_list; - - /* * Collect memory ranges */ - top = FSP_LOWMEM_BASE; - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_SYS_MEM) { - phys_start = res_desc->phys_start; - /* Need memory above 1MB to be collected here */ - if (phys_start >= FSP_LOWMEM_BASE && - phys_start < (phys_addr_t)FSP_HIGHMEM_BASE) - top += (u32)(res_desc->len); - } - } - -#ifdef CONFIG_FSP_BROKEN_HOB - /* - * Find out the lowest memory base address allocated by FSP - * for the boot service data - */ - if (hdr->type == HOB_TYPE_MEM_ALLOC) { - res_mem = (struct hob_mem_alloc *)hdr; - if (!mem_base) - mem_base = res_mem->mem_base; - if (res_mem->mem_base < mem_base) - mem_base = res_mem->mem_base; - } -#endif - - hdr = get_next_hob(hdr); - } - -#ifdef CONFIG_FSP_BROKEN_HOB - /* - * Check whether the memory top address is below the FSP HOB list. - * If not, use the lowest memory base address allocated by FSP as - * the memory top address. This is to prevent U-Boot relocation - * overwrites the important boot service data which is used by FSP, - * otherwise the subsequent call to fsp_notify() will fail. - */ - if (top > (u32)hob_list) { - debug("Adjust memory top address due to a buggy FSP\n"); - top = (u32)mem_base; - } -#endif - - return top; -} - -u64 fsp_get_usable_highmem_top(const void *hob_list) -{ - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - phys_addr_t phys_start; - u64 top; - - /* Get the HOB list for processing */ - hdr = hob_list; - - /* Collect memory ranges */ - top = FSP_HIGHMEM_BASE; - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_SYS_MEM) { - phys_start = res_desc->phys_start; - /* Need memory above 4GB to be collected here */ - if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE) - top += (u32)(res_desc->len); - } - } - hdr = get_next_hob(hdr); - } - - return top; -} - -u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len, - const efi_guid_t *guid) -{ - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - - /* Get the HOB list for processing */ - hdr = hob_list; - - /* Collect memory ranges */ - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_MEM_RESERVED) { - if (!guidcmp(&res_desc->owner, guid)) { - if (len) - *len = (u32)(res_desc->len); - - return (u64)(res_desc->phys_start); - } - } - } - hdr = get_next_hob(hdr); - } - - return 0; -} - -u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID; - u64 length; - u32 base; - - base = (u32)fsp_get_reserved_mem_from_guid(hob_list, - &length, &guid); - if ((len != 0) && (base != 0)) - *len = (u32)length; - - return base; -} - -u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID; - u64 length; - u32 base; - - base = (u32)fsp_get_reserved_mem_from_guid(hob_list, - &length, &guid); - if ((len != 0) && (base != 0)) - *len = (u32)length; - - return base; -} - -void *fsp_get_nvs_data(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; - - return hob_get_guid_hob_data(hob_list, len, &guid); -} - -void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID; - - return hob_get_guid_hob_data(hob_list, len, &guid); -} - -void *fsp_get_graphics_info(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_GRAPHICS_INFO_HOB_GUID; - - return hob_get_guid_hob_data(hob_list, len, &guid); -} diff --git a/arch/x86/lib/fsp1/Makefile b/arch/x86/lib/fsp1/Makefile new file mode 100644 index 0000000000..870de71bd7 --- /dev/null +++ b/arch/x86/lib/fsp1/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2015 Google, Inc + +obj-y += fsp_car.o +obj-y += fsp_common.o +obj-y += fsp_dram.o +obj-$(CONFIG_VIDEO_FSP) += fsp_graphics.o +obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp1/fsp_car.S b/arch/x86/lib/fsp1/fsp_car.S new file mode 100644 index 0000000000..8c54cea3db --- /dev/null +++ b/arch/x86/lib/fsp1/fsp_car.S @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2014, Bin Meng + */ + +#include +#include + +.globl car_init +car_init: + /* + * Note: ebp holds the BIST value (built-in self test) so far, but ebp + * will be destroyed through the FSP call, thus we have to test the + * BIST value here before we call into FSP. + */ + test %ebp, %ebp + jz car_init_start + post_code(POST_BIST_FAILURE) + jmp die + +car_init_start: + post_code(POST_CAR_START) + lea find_fsp_header_romstack, %esp + jmp find_fsp_header + +find_fsp_header_ret: + /* EAX points to FSP_INFO_HEADER */ + mov %eax, %ebp + + /* sanity test */ + cmp $CONFIG_FSP_ADDR, %eax + jb die + + /* calculate TempRamInitEntry address */ + mov 0x30(%ebp), %eax + add 0x1c(%ebp), %eax + + /* call FSP TempRamInitEntry to setup temporary stack */ + lea temp_ram_init_romstack, %esp + jmp *%eax + +temp_ram_init_ret: + addl $4, %esp + cmp $0, %eax + jnz car_init_fail + + post_code(POST_CAR_CPU_CACHE) + + /* + * The FSP TempRamInit initializes the ecx and edx registers to + * point to a temporary but writable memory range (Cache-As-RAM). + * ecx: the start of this temporary memory range, + * edx: the end of this range. + */ + + /* stack grows down from top of CAR */ + movl %edx, %esp + subl $4, %esp + + xor %esi, %esi + jmp car_init_done + +.global fsp_init_done +fsp_init_done: + /* + * We come here from fsp_continue() with eax pointing to the HOB list. + * Save eax to esi temporarily. + */ + movl %eax, %esi + +car_init_done: + /* + * Re-initialize the ebp (BIST) to zero, as we already reach here + * which means we passed BIST testing before. + */ + xorl %ebp, %ebp + jmp car_init_ret + +car_init_fail: + post_code(POST_CAR_FAILURE) + +die: + hlt + jmp die + hlt + + /* + * The function call before CAR initialization is tricky. It cannot + * be called using the 'call' instruction but only the 'jmp' with + * the help of a handcrafted stack in the ROM. The stack needs to + * contain the function return address as well as the parameters. + */ + .balign 4 +find_fsp_header_romstack: + .long find_fsp_header_ret + + .balign 4 +temp_ram_init_romstack: + .long temp_ram_init_ret + .long temp_ram_init_params +temp_ram_init_params: +_dt_ucode_base_size: + /* These next two fields are filled in by binman */ +.globl ucode_base +ucode_base: /* Declared in microcode.h */ + .long 0 /* microcode base */ +.globl ucode_size +ucode_size: /* Declared in microcode.h */ + .long 0 /* microcode size */ + .long CONFIG_SYS_MONITOR_BASE /* code region base */ + .long CONFIG_SYS_MONITOR_LEN /* code region size */ diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c new file mode 100644 index 0000000000..591eef7b81 --- /dev/null +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014, Bin Meng + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + post_code(POST_CPU_INFO); + return default_print_cpuinfo(); +} + +int fsp_init_phase_pci(void) +{ + u32 status; + + /* call into FspNotify */ + debug("Calling into FSP (notify phase INIT_PHASE_PCI): "); + status = fsp_notify(NULL, INIT_PHASE_PCI); + if (status) + debug("fail, error code %x\n", status); + else + debug("OK\n"); + + return status ? -EPERM : 0; +} + +void board_final_cleanup(void) +{ + u32 status; + + /* call into FspNotify */ + debug("Calling into FSP (notify phase INIT_PHASE_BOOT): "); + status = fsp_notify(NULL, INIT_PHASE_BOOT); + if (status) + debug("fail, error code %x\n", status); + else + debug("OK\n"); + + return; +} + +static __maybe_unused void *fsp_prepare_mrc_cache(void) +{ + struct mrc_data_container *cache; + struct mrc_region entry; + int ret; + + ret = mrccache_get_region(NULL, &entry); + if (ret) + return NULL; + + cache = mrccache_find_current(&entry); + if (!cache) + return NULL; + + debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, + cache->data, cache->data_size, cache->checksum); + + return cache->data; +} + +#ifdef CONFIG_HAVE_ACPI_RESUME +int fsp_save_s3_stack(void) +{ + struct udevice *dev; + int ret; + + if (gd->arch.prev_sleep_state == ACPI_S3) + return 0; + + ret = uclass_get_device(UCLASS_RTC, 0, &dev); + if (ret) { + debug("Cannot find RTC: err=%d\n", ret); + return -ENODEV; + } + + /* Save the stack address to CMOS */ + ret = rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp); + if (ret) { + debug("Save stack address to CMOS: err=%d\n", ret); + return -EIO; + } + + return 0; +} +#endif + +int arch_fsp_init(void) +{ + void *nvs; + int stack = CONFIG_FSP_TEMP_RAM_ADDR; + int boot_mode = BOOT_FULL_CONFIG; +#ifdef CONFIG_HAVE_ACPI_RESUME + int prev_sleep_state = chipset_prev_sleep_state(); + gd->arch.prev_sleep_state = prev_sleep_state; +#endif + + if (!gd->arch.hob_list) { +#ifdef CONFIG_ENABLE_MRC_CACHE + nvs = fsp_prepare_mrc_cache(); +#else + nvs = NULL; +#endif + +#ifdef CONFIG_HAVE_ACPI_RESUME + if (prev_sleep_state == ACPI_S3) { + if (nvs == NULL) { + /* If waking from S3 and no cache then */ + debug("No MRC cache found in S3 resume path\n"); + post_code(POST_RESUME_FAILURE); + /* Clear Sleep Type */ + chipset_clear_sleep_state(); + /* Reboot */ + debug("Rebooting..\n"); + outb(SYS_RST | RST_CPU, IO_PORT_RESET); + /* Should not reach here.. */ + panic("Reboot System"); + } + + /* + * DM is not available yet at this point, hence call + * CMOS access library which does not depend on DM. + */ + stack = cmos_read32(CMOS_FSP_STACK_ADDR); + boot_mode = BOOT_ON_S3_RESUME; + } +#endif + /* + * The first time we enter here, call fsp_init(). + * Note the execution does not return to this function, + * instead it jumps to fsp_continue(). + */ + fsp_init(stack, boot_mode, nvs); + } else { + /* + * The second time we enter here, adjust the size of malloc() + * pool before relocation. Given gd->malloc_base was adjusted + * after the call to board_init_f_init_reserve() in arch/x86/ + * cpu/start.S, we should fix up gd->malloc_limit here. + */ + gd->malloc_limit += CONFIG_FSP_SYS_MALLOC_F_LEN; + } + + return 0; +} diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c new file mode 100644 index 0000000000..3bf65b495c --- /dev/null +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014, Bin Meng + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int dram_init(void) +{ + phys_size_t ram_size = 0; + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + + hdr = gd->arch.hob_list; + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_SYS_MEM || + res_desc->type == RES_MEM_RESERVED) { + ram_size += res_desc->len; + } + } + hdr = get_next_hob(hdr); + } + + gd->ram_size = ram_size; + post_code(POST_DRAM); + +#ifdef CONFIG_ENABLE_MRC_CACHE + gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, + &gd->arch.mrc_output_len); +#endif + + return 0; +} + +int dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = 0; + gd->bd->bi_dram[0].size = gd->ram_size; + + return 0; +} + +/* + * This function looks for the highest region of memory lower than 4GB which + * has enough space for U-Boot where U-Boot is aligned on a page boundary. + * It overrides the default implementation found elsewhere which simply + * picks the end of ram, wherever that may be. The location of the stack, + * the relocation address, and how far U-Boot is moved by relocation are + * set in the global data structure. + */ +ulong board_get_usable_ram_top(ulong total_size) +{ + return fsp_get_usable_lowmem_top(gd->arch.hob_list); +} + +unsigned int install_e820_map(unsigned int max_entries, + struct e820_entry *entries) +{ + unsigned int num_entries = 0; + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + + hdr = gd->arch.hob_list; + + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + entries[num_entries].addr = res_desc->phys_start; + entries[num_entries].size = res_desc->len; + + if (res_desc->type == RES_SYS_MEM) + entries[num_entries].type = E820_RAM; + else if (res_desc->type == RES_MEM_RESERVED) + entries[num_entries].type = E820_RESERVED; + + num_entries++; + } + hdr = get_next_hob(hdr); + } + + /* Mark PCIe ECAM address range as reserved */ + entries[num_entries].addr = CONFIG_PCIE_ECAM_BASE; + entries[num_entries].size = CONFIG_PCIE_ECAM_SIZE; + entries[num_entries].type = E820_RESERVED; + num_entries++; + +#ifdef CONFIG_HAVE_ACPI_RESUME + /* + * Everything between U-Boot's stack and ram top needs to be + * reserved in order for ACPI S3 resume to work. + */ + entries[num_entries].addr = gd->start_addr_sp - CONFIG_STACK_SIZE; + entries[num_entries].size = gd->ram_top - gd->start_addr_sp + \ + CONFIG_STACK_SIZE; + entries[num_entries].type = E820_RESERVED; + num_entries++; +#endif + + return num_entries; +} diff --git a/arch/x86/lib/fsp1/fsp_graphics.c b/arch/x86/lib/fsp1/fsp_graphics.c new file mode 100644 index 0000000000..52e71334f9 --- /dev/null +++ b/arch/x86/lib/fsp1/fsp_graphics.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017, Bin Meng + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct pixel { + u8 pos; + u8 size; +}; + +static const struct fsp_framebuffer { + struct pixel red; + struct pixel green; + struct pixel blue; + struct pixel rsvd; +} fsp_framebuffer_format_map[] = { + [pixel_rgbx_8bpc] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} }, + [pixel_bgrx_8bpc] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} }, +}; + +static int save_vesa_mode(struct vesa_mode_info *vesa) +{ + const struct hob_graphics_info *ginfo; + const struct fsp_framebuffer *fbinfo; + + ginfo = fsp_get_graphics_info(gd->arch.hob_list, NULL); + + /* + * If there is no graphics info structure, bail out and keep + * running on the serial console. + * + * Note: on some platforms (eg: Braswell), the FSP will not produce + * the graphics info HOB unless you plug some cables to the display + * interface (eg: HDMI) on the board. + */ + if (!ginfo) { + debug("FSP graphics hand-off block not found\n"); + return -ENXIO; + } + + vesa->x_resolution = ginfo->width; + vesa->y_resolution = ginfo->height; + vesa->bits_per_pixel = 32; + vesa->bytes_per_scanline = ginfo->pixels_per_scanline * 4; + vesa->phys_base_ptr = ginfo->fb_base; + + if (ginfo->pixel_format >= pixel_bitmask) { + debug("FSP set unknown framebuffer format: %d\n", + ginfo->pixel_format); + return -EINVAL; + } + fbinfo = &fsp_framebuffer_format_map[ginfo->pixel_format]; + vesa->red_mask_size = fbinfo->red.size; + vesa->red_mask_pos = fbinfo->red.pos; + vesa->green_mask_size = fbinfo->green.size; + vesa->green_mask_pos = fbinfo->green.pos; + vesa->blue_mask_size = fbinfo->blue.size; + vesa->blue_mask_pos = fbinfo->blue.pos; + vesa->reserved_mask_size = fbinfo->rsvd.size; + vesa->reserved_mask_pos = fbinfo->rsvd.pos; + + return 0; +} + +static int fsp_video_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct vesa_mode_info *vesa = &mode_info.vesa; + int ret; + + printf("Video: "); + + /* Initialize vesa_mode_info structure */ + ret = save_vesa_mode(vesa); + if (ret) + goto err; + + /* + * The framebuffer base address in the FSP graphics info HOB reflects + * the value assigned by the FSP. After PCI enumeration the framebuffer + * base address may be relocated. Let's get the updated one from device. + * + * For IGD, it seems to be always on BAR2. + */ + vesa->phys_base_ptr = dm_pci_read_bar32(dev, 2); + + ret = vbe_setup_video_priv(vesa, uc_priv, plat); + if (ret) + goto err; + + printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, + vesa->bits_per_pixel); + + return 0; + +err: + printf("No video mode configured in FSP!\n"); + return ret; +} + +static const struct udevice_id fsp_video_ids[] = { + { .compatible = "fsp-fb" }, + { } +}; + +U_BOOT_DRIVER(fsp_video) = { + .name = "fsp_video", + .id = UCLASS_VIDEO, + .of_match = fsp_video_ids, + .probe = fsp_video_probe, +}; + +static struct pci_device_id fsp_video_supported[] = { + { PCI_DEVICE_CLASS(PCI_CLASS_DISPLAY_VGA << 8, 0xffff00) }, + { }, +}; + +U_BOOT_PCI_DEVICE(fsp_video, fsp_video_supported); diff --git a/arch/x86/lib/fsp1/fsp_support.c b/arch/x86/lib/fsp1/fsp_support.c new file mode 100644 index 0000000000..019a42f53f --- /dev/null +++ b/arch/x86/lib/fsp1/fsp_support.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2014, Bin Meng + */ + +#include +#include +#include + +struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void) +{ + /* + * This function may be called before the a stack is established, + * so special care must be taken. First, it cannot declare any local + * variable using stack. Only register variable can be used here. + * Secondly, some compiler version will add prolog or epilog code + * for the C function. If so the function call may not work before + * stack is ready. + * + * GCC 4.8.1 has been verified to be working for the following codes. + */ + volatile register u8 *fsp asm("eax"); + + /* Initalize the FSP base */ + fsp = (u8 *)CONFIG_FSP_ADDR; + + /* Check the FV signature, _FVH */ + if (((struct fv_header *)fsp)->sign == EFI_FVH_SIGNATURE) { + /* Go to the end of the FV header and align the address */ + fsp += ((struct fv_header *)fsp)->ext_hdr_off; + fsp += ((struct fv_ext_header *)fsp)->ext_hdr_size; + fsp = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8); + } else { + fsp = 0; + } + + /* Check the FFS GUID */ + if (fsp && + ((struct ffs_file_header *)fsp)->name.b[0] == FSP_GUID_BYTE0 && + ((struct ffs_file_header *)fsp)->name.b[1] == FSP_GUID_BYTE1 && + ((struct ffs_file_header *)fsp)->name.b[2] == FSP_GUID_BYTE2 && + ((struct ffs_file_header *)fsp)->name.b[3] == FSP_GUID_BYTE3 && + ((struct ffs_file_header *)fsp)->name.b[4] == FSP_GUID_BYTE4 && + ((struct ffs_file_header *)fsp)->name.b[5] == FSP_GUID_BYTE5 && + ((struct ffs_file_header *)fsp)->name.b[6] == FSP_GUID_BYTE6 && + ((struct ffs_file_header *)fsp)->name.b[7] == FSP_GUID_BYTE7 && + ((struct ffs_file_header *)fsp)->name.b[8] == FSP_GUID_BYTE8 && + ((struct ffs_file_header *)fsp)->name.b[9] == FSP_GUID_BYTE9 && + ((struct ffs_file_header *)fsp)->name.b[10] == FSP_GUID_BYTE10 && + ((struct ffs_file_header *)fsp)->name.b[11] == FSP_GUID_BYTE11 && + ((struct ffs_file_header *)fsp)->name.b[12] == FSP_GUID_BYTE12 && + ((struct ffs_file_header *)fsp)->name.b[13] == FSP_GUID_BYTE13 && + ((struct ffs_file_header *)fsp)->name.b[14] == FSP_GUID_BYTE14 && + ((struct ffs_file_header *)fsp)->name.b[15] == FSP_GUID_BYTE15) { + /* Add the FFS header size to find the raw section header */ + fsp += sizeof(struct ffs_file_header); + } else { + fsp = 0; + } + + if (fsp && + ((struct raw_section *)fsp)->type == EFI_SECTION_RAW) { + /* Add the raw section header size to find the FSP header */ + fsp += sizeof(struct raw_section); + } else { + fsp = 0; + } + + return (struct fsp_header *)fsp; +} + +void fsp_continue(u32 status, void *hob_list) +{ + post_code(POST_MRC); + + assert(status == 0); + + /* The boot loader main function entry */ + fsp_init_done(hob_list); +} + +void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) +{ + struct fsp_config_data config_data; + fsp_init_f init; + struct fsp_init_params params; + struct fspinit_rtbuf rt_buf; + struct fsp_header *fsp_hdr; + struct fsp_init_params *params_ptr; +#ifdef CONFIG_FSP_USE_UPD + struct vpd_region *fsp_vpd; + struct upd_region *fsp_upd; +#endif + + fsp_hdr = find_fsp_header(); + if (fsp_hdr == NULL) { + /* No valid FSP info header was found */ + panic("Invalid FSP header"); + } + + config_data.common.fsp_hdr = fsp_hdr; + config_data.common.stack_top = stack_top; + config_data.common.boot_mode = boot_mode; + +#ifdef CONFIG_FSP_USE_UPD + /* Get VPD region start */ + fsp_vpd = (struct vpd_region *)(fsp_hdr->img_base + + fsp_hdr->cfg_region_off); + + /* Verify the VPD data region is valid */ + assert(fsp_vpd->sign == VPD_IMAGE_ID); + + fsp_upd = &config_data.fsp_upd; + + /* Copy default data from Flash */ + memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset), + sizeof(struct upd_region)); + + /* Verify the UPD data region is valid */ + assert(fsp_upd->terminator == UPD_TERMINATOR); +#endif + + memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf)); + + /* Override any configuration if required */ + update_fsp_configs(&config_data, &rt_buf); + + memset(¶ms, 0, sizeof(struct fsp_init_params)); + params.nvs_buf = nvs_buf; + params.rt_buf = (struct fspinit_rtbuf *)&rt_buf; + params.continuation = (fsp_continuation_f)asm_continuation; + + init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init); + params_ptr = ¶ms; + + post_code(POST_PRE_MRC); + + /* Load GDT for FSP */ + setup_fsp_gdt(); + + /* + * Use ASM code to ensure the register value in EAX & EDX + * will be passed into fsp_continue + */ + asm volatile ( + "pushl %0;" + "call *%%eax;" + ".global asm_continuation;" + "asm_continuation:;" + "movl 4(%%esp), %%eax;" /* status */ + "movl 8(%%esp), %%edx;" /* hob_list */ + "jmp fsp_continue;" + : : "m"(params_ptr), "a"(init) + ); + + /* + * Should never get here. + * Control will continue from fsp_continue. + * This line below is to prevent the compiler from optimizing + * structure intialization. + * + * DO NOT REMOVE! + */ + init(¶ms); +} + +u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase) +{ + fsp_notify_f notify; + struct fsp_notify_params params; + struct fsp_notify_params *params_ptr; + u32 status; + + if (!fsp_hdr) + fsp_hdr = (struct fsp_header *)find_fsp_header(); + + if (fsp_hdr == NULL) { + /* No valid FSP info header */ + panic("Invalid FSP header"); + } + + notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify); + params.phase = phase; + params_ptr = ¶ms; + + /* + * Use ASM code to ensure correct parameter is on the stack for + * FspNotify as U-Boot is using different ABI from FSP + */ + asm volatile ( + "pushl %1;" /* push notify phase */ + "call *%%eax;" /* call FspNotify */ + "addl $4, %%esp;" /* clean up the stack */ + : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr) + ); + + return status; +} + +u32 fsp_get_usable_lowmem_top(const void *hob_list) +{ + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + phys_addr_t phys_start; + u32 top; +#ifdef CONFIG_FSP_BROKEN_HOB + struct hob_mem_alloc *res_mem; + phys_addr_t mem_base = 0; +#endif + + /* Get the HOB list for processing */ + hdr = hob_list; + + /* * Collect memory ranges */ + top = FSP_LOWMEM_BASE; + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_SYS_MEM) { + phys_start = res_desc->phys_start; + /* Need memory above 1MB to be collected here */ + if (phys_start >= FSP_LOWMEM_BASE && + phys_start < (phys_addr_t)FSP_HIGHMEM_BASE) + top += (u32)(res_desc->len); + } + } + +#ifdef CONFIG_FSP_BROKEN_HOB + /* + * Find out the lowest memory base address allocated by FSP + * for the boot service data + */ + if (hdr->type == HOB_TYPE_MEM_ALLOC) { + res_mem = (struct hob_mem_alloc *)hdr; + if (!mem_base) + mem_base = res_mem->mem_base; + if (res_mem->mem_base < mem_base) + mem_base = res_mem->mem_base; + } +#endif + + hdr = get_next_hob(hdr); + } + +#ifdef CONFIG_FSP_BROKEN_HOB + /* + * Check whether the memory top address is below the FSP HOB list. + * If not, use the lowest memory base address allocated by FSP as + * the memory top address. This is to prevent U-Boot relocation + * overwrites the important boot service data which is used by FSP, + * otherwise the subsequent call to fsp_notify() will fail. + */ + if (top > (u32)hob_list) { + debug("Adjust memory top address due to a buggy FSP\n"); + top = (u32)mem_base; + } +#endif + + return top; +} + +u64 fsp_get_usable_highmem_top(const void *hob_list) +{ + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + phys_addr_t phys_start; + u64 top; + + /* Get the HOB list for processing */ + hdr = hob_list; + + /* Collect memory ranges */ + top = FSP_HIGHMEM_BASE; + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_SYS_MEM) { + phys_start = res_desc->phys_start; + /* Need memory above 4GB to be collected here */ + if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE) + top += (u32)(res_desc->len); + } + } + hdr = get_next_hob(hdr); + } + + return top; +} + +u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len, + const efi_guid_t *guid) +{ + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + + /* Get the HOB list for processing */ + hdr = hob_list; + + /* Collect memory ranges */ + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_MEM_RESERVED) { + if (!guidcmp(&res_desc->owner, guid)) { + if (len) + *len = (u32)(res_desc->len); + + return (u64)(res_desc->phys_start); + } + } + } + hdr = get_next_hob(hdr); + } + + return 0; +} + +u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID; + u64 length; + u32 base; + + base = (u32)fsp_get_reserved_mem_from_guid(hob_list, + &length, &guid); + if ((len != 0) && (base != 0)) + *len = (u32)length; + + return base; +} + +u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID; + u64 length; + u32 base; + + base = (u32)fsp_get_reserved_mem_from_guid(hob_list, + &length, &guid); + if ((len != 0) && (base != 0)) + *len = (u32)length; + + return base; +} + +void *fsp_get_nvs_data(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} + +void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} + +void *fsp_get_graphics_info(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_GRAPHICS_INFO_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} -- cgit