/* * 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 }