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 <leroy.p.leahy@intel.com>
Reviewed-on: http://review.coreboot.org/10050
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/src/soc/intel/common/romstage.c b/src/soc/intel/common/romstage.c
new file mode 100644
index 0000000..adebf51
--- /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 <stddef.h>
+#include <stdint.h>
+#include <arch/cpu.h>
+#include <arch/io.h>
+#include <arch/cbfs.h>
+#include <arch/stages.h>
+#include <arch/early_variables.h>
+#include <console/console.h>
+#include <cbmem.h>
+#include <cpu/x86/mtrr.h>
+#include <ec/google/chromeec/ec.h>
+#include <ec/google/chromeec/ec_commands.h>
+#include <elog.h>
+#include <memory_info.h>
+#include <reset.h>
+#include <romstage_handoff.h>
+#include <soc/intel/common/mrc_cache.h>
+#include <soc/intel/common/util.h>
+#include <soc/pei_wrapper.h>
+#include <soc/pm.h>
+#include <soc/romstage.h>
+#include <soc/spi.h>
+#include <stage_cache.h>
+#include <timestamp.h>
+#include <tpm.h>
+#include <vendorcode/google/chromeos/chromeos.h>
+
+/* 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(&params);
+	mainboard_pre_console_init(&params);
+
+	/* 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(&params);
+
+	/* Call into mainboard. */
+	mainboard_romstage_entry(&params);
+	soc_after_ram_init(&params);
+	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
+}