From 0946ec37aa4660ecf16d66cb1174a68df0afc4f0 Mon Sep 17 00:00:00 2001 From: Lee Leahy Date: Mon, 20 Apr 2015 15:24:54 -0700 Subject: Intel Common SOC: Add romstage support Provide a common romstage implementation for the Intel SOCs. BRANCH=none BUG=None TEST=Build for Braswell Change-Id: I80f5f8f0f36e9023117b07d4af5c806fff8157b6 Signed-off-by: Lee Leahy Reviewed-on: http://review.coreboot.org/10050 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/soc/intel/common/romstage.c | 447 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 src/soc/intel/common/romstage.c (limited to 'src/soc/intel/common/romstage.c') diff --git a/src/soc/intel/common/romstage.c b/src/soc/intel/common/romstage.c new file mode 100644 index 0000000000..adebf5175e --- /dev/null +++ b/src/soc/intel/common/romstage.c @@ -0,0 +1,447 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Entry from cache-as-ram.inc. */ +asmlinkage void *romstage_main(unsigned int bist, + uint32_t tsc_low, uint32_t tsc_high, + void *chipset_context) +{ + void *top_of_stack; + struct pei_data pei_data; + struct romstage_params params = { + .bist = bist, + .pei_data = &pei_data, + .chipset_context = chipset_context, + }; + + post_code(0x30); + + /* Save timestamp data */ + timestamp_init((((uint64_t)tsc_high) << 32) | (uint64_t)tsc_low); + timestamp_add_now(TS_START_ROMSTAGE); + + memset(&pei_data, 0, sizeof(pei_data)); + + /* Call into pre-console init code. */ + soc_pre_console_init(¶ms); + mainboard_pre_console_init(¶ms); + + /* Start console drivers */ + console_init(); + + /* Display parameters */ + printk(BIOS_SPEW, "bist: 0x%08x\n", bist); + printk(BIOS_SPEW, "tsc_low: 0x%08x\n", tsc_low); + printk(BIOS_SPEW, "tsc_hi: 0x%08x\n", tsc_high); + printk(BIOS_SPEW, "CONFIG_MMCONF_BASE_ADDRESS: 0x%08x\n", + CONFIG_MMCONF_BASE_ADDRESS); + printk(BIOS_INFO, "Using: %s\n", + IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1) ? "FSP 1.1" : + (IS_ENABLED(CONFIG_HAVE_MRC) ? "MRC" : + "No Memory Support")); + + /* Display FSP banner */ + if (IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1)) { + printk(BIOS_DEBUG, "FSP TempRamInit successful\n"); + print_fsp_info(params.chipset_context); + } + + /* Get power state */ + params.power_state = fill_power_state(); + + /* Print useful platform information */ + report_platform_info(); + + /* Set CPU frequency to maximum */ + set_max_freq(); + + /* Perform SOC specific initialization. */ + soc_romstage_init(¶ms); + + /* Call into mainboard. */ + mainboard_romstage_entry(¶ms); + soc_after_ram_init(¶ms); + post_code(0x38); + + top_of_stack = setup_stack_and_mtrrs(); + + if (IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1)) { + printk(BIOS_DEBUG, "Calling FspTempRamExit API\n"); + timestamp_add_now(TS_FSP_TEMP_RAM_EXIT_START); + } + return top_of_stack; +} + +/* Entry from the mainboard. */ +void romstage_common(struct romstage_params *params) +{ + const struct mrc_saved_data *cache; + struct romstage_handoff *handoff; + struct pei_data *pei_data; + + post_code(0x32); + + timestamp_add_now(TS_BEFORE_INITRAM); + + pei_data = params->pei_data; + pei_data->boot_mode = params->power_state->prev_sleep_state; + +#if IS_ENABLED(CONFIG_ELOG_BOOT_COUNT) + if (params->power_state->prev_sleep_state != SLEEP_STATE_S3) + boot_count_increment(); +#endif + + /* Perform remaining SOC initialization */ + soc_pre_ram_init(params); + post_code(0x33); + + /* Check recovery and MRC cache */ + params->pei_data->saved_data_size = 0; + params->pei_data->saved_data = NULL; + if (!params->pei_data->disable_saved_data) { + if (recovery_mode_enabled()) { + /* Recovery mode does not use MRC cache */ + printk(BIOS_DEBUG, + "Recovery mode: not using MRC cache.\n"); + } else if (!mrc_cache_get_current(&cache)) { + /* MRC cache found */ + params->pei_data->saved_data_size = cache->size; + params->pei_data->saved_data = &cache->data[0]; + } else if (params->pei_data->boot_mode == SLEEP_STATE_S3) { + /* Waking from S3 and no cache. */ + printk(BIOS_DEBUG, + "No MRC cache found in S3 resume path.\n"); + post_code(POST_RESUME_FAILURE); + hard_reset(); + } else { + printk(BIOS_DEBUG, "No MRC cache found.\n"); + mainboard_check_ec_image(params); + } + } + + /* Initialize RAM */ + raminit(params); + timestamp_add_now(TS_AFTER_INITRAM); + + /* Save MRC output */ + printk(BIOS_DEBUG, "MRC data at %p %d bytes\n", pei_data->data_to_save, + pei_data->data_to_save_size); + if (params->pei_data->boot_mode != SLEEP_STATE_S3) { + if (params->pei_data->data_to_save_size != 0 && + params->pei_data->data_to_save != NULL) { + mrc_cache_stash_data(params->pei_data->data_to_save, + params->pei_data->data_to_save_size); + } + } + + /* Save DIMM information */ + mainboard_save_dimm_info(params); + + /* Create romstage handof information */ + handoff = romstage_handoff_find_or_add(); + if (handoff != NULL) + handoff->s3_resume = (params->power_state->prev_sleep_state == + SLEEP_STATE_S3); + else { + printk(BIOS_DEBUG, "Romstage handoff structure not added!\n"); + hard_reset(); + } + + if (IS_ENABLED(CONFIG_LPC_TPM)) + init_tpm(params->power_state->prev_sleep_state == SLEEP_STATE_S3); +} + +asmlinkage void romstage_after_car(void *chipset_context) +{ + if (IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1)) { + timestamp_add_now(TS_FSP_TEMP_RAM_EXIT_END); + printk(BIOS_DEBUG, "FspTempRamExit returned successfully\n"); + soc_after_temp_ram_exit(); + soc_display_mtrrs(); + } + + timestamp_add_now(TS_END_ROMSTAGE); + + /* Load the ramstage. */ + copy_and_run(); + die("ERROR - Failed to load ramstage!"); +} + +/* Initialize the power state */ +__attribute__((weak)) struct chipset_power_state *fill_power_state(void) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); + return NULL; +} + +__attribute__((weak)) void mainboard_check_ec_image( + struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC) + struct pei_data *pei_data; + + pei_data = params->pei_data; + if (params->pei_data->boot_mode == SLEEP_STATE_S0) { + /* Ensure EC is running RO firmware. */ + google_chromeec_check_ec_image(EC_IMAGE_RO); + } +#endif +} + +/* Board initialization before the console is enabled */ +__attribute__((weak)) void mainboard_pre_console_init( + struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* Board initialization before and after RAM is enabled */ +__attribute__((weak)) void mainboard_romstage_entry( + struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); + + post_code(0x31); + + /* Initliaze memory */ + romstage_common(params); +} + +/* Save the DIMM information for SMBIOS table 17 */ +#if IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1) +__attribute__((weak)) void mainboard_save_dimm_info( + struct romstage_params *params) +{ + int channel; + CHANNEL_INFO *channel_info; + int dimm; + DIMM_INFO *dimm_info; + int dimm_max; + void *hob_list_ptr; + EFI_HOB_GUID_TYPE *hob_ptr; + int index; + struct memory_info *mem_info; + FSP_SMBIOS_MEMORY_INFO *memory_info_hob; + const EFI_GUID memory_info_hob_guid = FSP_SMBIOS_MEMORY_INFO_GUID; + + /* Locate the memory info HOB, presence validated by raminit */ + hob_list_ptr = fsp_get_hob_list(); + hob_ptr = get_next_guid_hob(&memory_info_hob_guid, hob_list_ptr); + memory_info_hob = (FSP_SMBIOS_MEMORY_INFO *)(hob_ptr + 1); + + /* Display the data in the FSP_SMBIOS_MEMORY_INFO HOB */ + if (IS_ENABLED(CONFIG_DISPLAY_HOBS)) { + printk(BIOS_DEBUG, "FSP_SMBIOS_MEMORY_INFO HOB\n"); + printk(BIOS_DEBUG, " 0x%02x: Revision\n", + memory_info_hob->Revision); + printk(BIOS_DEBUG, " 0x%02x: MemoryType\n", + memory_info_hob->MemoryType); + printk(BIOS_DEBUG, " 0x%04x: MemoryFrequencyInMHz\n", + memory_info_hob->MemoryFrequencyInMHz); + printk(BIOS_DEBUG, " 0x%02x: ErrorCorrectionType\n", + memory_info_hob->ErrorCorrectionType); + printk(BIOS_DEBUG, " 0x%02x: ChannelCount\n", + memory_info_hob->ChannelCount); + for (channel = 0; channel < memory_info_hob->ChannelCount; + channel++) { + channel_info = &memory_info_hob->ChannelInfo[channel]; + printk(BIOS_DEBUG, " Channel %d\n", channel); + printk(BIOS_DEBUG, " 0x%02x: ChannelId\n", + channel_info->ChannelId); + printk(BIOS_DEBUG, " 0x%02x: DimmCount\n", + channel_info->DimmCount); + for (dimm = 0; dimm < channel_info->DimmCount; + dimm++) { + dimm_info = &channel_info->DimmInfo[dimm]; + printk(BIOS_DEBUG, " DIMM %d\n", dimm); + printk(BIOS_DEBUG, " 0x%02x: DimmId\n", + dimm_info->DimmId); + printk(BIOS_DEBUG, " 0x%02x: SizeInMb\n", + dimm_info->SizeInMb); + } + } + } + + /* + * Allocate CBMEM area for DIMM information used to populate SMBIOS + * table 17 + */ + mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); + printk(BIOS_DEBUG, "CBMEM entry for DIMM info: 0x%p\n", mem_info); + if (mem_info == NULL) + return; + memset(mem_info, 0, sizeof(*mem_info)); + + /* Describe the first N DIMMs in the system */ + index = 0; + dimm_max = ARRAY_SIZE(mem_info->dimm); + for (channel = 0; channel < memory_info_hob->ChannelCount; channel++) { + if (index >= dimm_max) + break; + channel_info = &memory_info_hob->ChannelInfo[channel]; + for (dimm = 0; dimm < channel_info->DimmCount; dimm++) { + if (index >= dimm_max) + break; + dimm_info = &channel_info->DimmInfo[dimm]; + + /* Populate the DIMM information */ + if (dimm_info->SizeInMb) { + mem_info->dimm[index].dimm_size = + dimm_info->SizeInMb; + mem_info->dimm[index].ddr_type = + memory_info_hob->MemoryType; + mem_info->dimm[index].ddr_frequency = + memory_info_hob->MemoryFrequencyInMHz; + mem_info->dimm[index].channel_num = + channel_info->ChannelId; + mem_info->dimm[index].dimm_num = + dimm_info->DimmId; + index++; + } + } + } + mem_info->dimm_cnt = index; + printk(BIOS_DEBUG, "%d DIMMs found\n", mem_info->dimm_cnt); +} +#else /* CONFIG_PLATFORM_USES_FSP1_1 */ +__attribute__((weak)) void mainboard_save_dimm_info( + struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} +#endif /* CONFIG_PLATFORM_USES_FSP1_1 */ + +/* Get the memory configuration data */ +__attribute__((weak)) int mrc_cache_get_current( + const struct mrc_saved_data **cache) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); + return -1; +} + +/* Save the memory configuration data */ +__attribute__((weak)) int mrc_cache_stash_data(void *data, size_t size) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); + return -1; +} + +/* Transition RAM from off or self-refresh to active */ +__attribute__((weak)) void raminit(struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); + post_code(0x34); + die("ERROR - No RAM initialization specified!\n"); +} + +void ramstage_cache_invalid(void) +{ + if (IS_ENABLED(CONFIG_RESET_ON_INVALID_RAMSTAGE_CACHE)) + /* Perform cold reset on invalid ramstage cache. */ + hard_reset(); +} + +/* Display the memory configuration */ +__attribute__((weak)) void report_memory_config(void) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* Display the platform configuration */ +__attribute__((weak)) void report_platform_info(void) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* Choose top of stack and setup MTRRs */ +__attribute__((weak)) void *setup_stack_and_mtrrs(void) +{ + printk(BIOS_ERR, "WEAK: %s/%s called\n", __FILE__, __func__); + die("ERROR - Must specify top of stack!\n"); + return NULL; +} + +/* Speed up the CPU to the maximum frequency */ +__attribute__((weak)) void set_max_freq(void) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* SOC initialization after RAM is enabled */ +__attribute__((weak)) void soc_after_ram_init(struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* SOC initialization after temporary RAM is disabled */ +__attribute__((weak)) void soc_after_temp_ram_exit(void) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* SOC initialization before the console is enabled */ +__attribute__((weak)) void soc_pre_console_init(struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* SOC initialization before RAM is enabled */ +__attribute__((weak)) void soc_pre_ram_init(struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +} + +/* SOC initialization after console is enabled */ +__attribute__((weak)) void soc_romstage_init(struct romstage_params *params) +{ + printk(BIOS_DEBUG, "WEAK: %s/%s called\n", __FILE__, __func__); +#if IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC) + /* Ensure the EC is in the right mode for recovery */ + google_chromeec_early_init(); +#endif +} -- cgit v1.2.3