Marc Jones (marc.jones(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4016
-gerrit
commit bcffdf7b163a57ae5b0918f2cc3a69ce7d6bcef6
Author: Marc Jones <marc.jones(a)se-eng.com>
Date: Tue Oct 29 17:46:54 2013 -0600
Add FSP version on the Intel 206ax CPU core
Add support for 206ax using the Intel FSP.
The FSP is different enough to warrant it's own source files.
Change-Id: I5105631af34e9c3a804ace908c4205f073abb9b4
Signed-off-by: Marc Jones <marc.jones(a)se-eng.com>
---
src/cpu/Kconfig | 39 +-
src/cpu/Makefile.inc | 8 +-
src/cpu/intel/Kconfig | 1 +
src/cpu/intel/Makefile.inc | 2 +
src/cpu/intel/fsp_model_206ax/Kconfig | 93 +++++
src/cpu/intel/fsp_model_206ax/Makefile.inc | 12 +
src/cpu/intel/fsp_model_206ax/acpi.c | 364 +++++++++++++++++++
src/cpu/intel/fsp_model_206ax/acpi/cpu.asl | 102 ++++++
src/cpu/intel/fsp_model_206ax/bootblock.c | 64 ++++
src/cpu/intel/fsp_model_206ax/cache_as_ram.inc | 294 +++++++++++++++
src/cpu/intel/fsp_model_206ax/chip.h | 37 ++
src/cpu/intel/fsp_model_206ax/finalize.c | 72 ++++
src/cpu/intel/fsp_model_206ax/microcode_blob.c | 24 ++
src/cpu/intel/fsp_model_206ax/microcode_blob.h | 33 ++
src/cpu/intel/fsp_model_206ax/model_206ax.h | 113 ++++++
src/cpu/intel/fsp_model_206ax/model_206ax_init.c | 433 +++++++++++++++++++++++
16 files changed, 1688 insertions(+), 3 deletions(-)
diff --git a/src/cpu/Kconfig b/src/cpu/Kconfig
index e48fe87..46b6f1c 100644
--- a/src/cpu/Kconfig
+++ b/src/cpu/Kconfig
@@ -77,10 +77,32 @@ config CPU_MICROCODE_IN_CBFS
bool
default n
+# The following options (BOARD_MICROCODE_CBFS_*) make it possible for the
+# microcode configuration to be selected in the board-level Kconfig. If
+# you want your platform's microcode to be generated during the build,
+# add "select BOARD_MICROCODE_CBFS_GENERATE" to your mainboard's Kconfig.
+# If you want to use an external microcode file, add "select
+# BOARD_MICROCODE_CBFS_EXTERNAL" instead. If neither of these statements
+# exists in your mainboard's configuration file (or if you include a
+# "select BOARD_MICROCODE_CBFS_NONE" statement), then the ROM image will
+# be built without any microcode.
+config BOARD_MICROCODE_CBFS_NONE
+ bool
+ default y
+
+config BOARD_MICROCODE_CBFS_GENERATE
+ bool
+ default n
+
+config BOARD_MICROCODE_CBFS_EXTERNAL
+ bool
+ default n
+
choice
prompt "Include CPU microcode in CBFS" if ARCH_X86
- default CPU_MICROCODE_CBFS_GENERATE if CPU_MICROCODE_IN_CBFS
- default CPU_MICROCODE_CBFS_NONE if !CPU_MICROCODE_IN_CBFS
+ default CPU_MICROCODE_CBFS_GENERATE if CPU_MICROCODE_IN_CBFS && BOARD_MICROCODE_CBFS_GENERATE
+ default CPU_MICROCODE_CBFS_EXTERNAL if CPU_MICROCODE_IN_CBFS && BOARD_MICROCODE_CBFS_EXTERNAL
+ default CPU_MICROCODE_CBFS_NONE
config CPU_MICROCODE_CBFS_GENERATE
bool "Generate from tree"
@@ -158,3 +180,16 @@ config CPU_MICROCODE_FILE
default "cpu_microcode.bin"
help
The path and filename of the file containing the CPU microcode.
+
+config CPU_MICROCODE_CBFS_LOC
+ hex "Microcode address in CBFS"
+ depends on CPU_MICROCODE_IN_CBFS
+ default 0
+
+config CPU_MICROCODE_CBFS_LEN
+ hex "Microcode length in CBFS"
+ depends on CPU_MICROCODE_IN_CBFS
+ default 0xC000
+ help
+ The microcode needs a specific length to get correctly
+ detected and loaded by all CPUs.
diff --git a/src/cpu/Makefile.inc b/src/cpu/Makefile.inc
index a860f67..34ae53e 100644
--- a/src/cpu/Makefile.inc
+++ b/src/cpu/Makefile.inc
@@ -28,6 +28,12 @@ cpu_ucode_cbfs_file = $(obj)/cpu_microcode_blob.bin
cbfs_include_ucode = y
endif
+ifneq ($(CONFIG_CPU_MICROCODE_CBFS_LOC), 0)
+cpu_ucode_cbfs_offset = "-b $(CONFIG_CPU_MICROCODE_CBFS_LOC)"
+else
+cpu_ucode_cbfs_offset = "-b"
+endif
+
# In case we have more than one "source" (cough) files containing microcode, we
# link them together in one large blob, so that we get all the microcode updates
# in one file. This makes it easier for objcopy in the final step.
@@ -46,7 +52,7 @@ $(obj)/cpu_microcode_blob.bin: $(obj)/cpu_microcode_blob.o
ifeq ($(cbfs_include_ucode),y)
# Add CPU microcode to specified rom image $(1)
add-cpu-microcode-to-cbfs = \
- $(CBFSTOOL) $(1) locate -f $(cpu_ucode_cbfs_file) -n $(cpu_ucode_cbfs_name) -a 16 | xargs $(CBFSTOOL) $(1) add -n $(cpu_ucode_cbfs_name) -f $(cpu_ucode_cbfs_file) -t 0x53 -b
+ $(CBFSTOOL) $(1) locate -f $(cpu_ucode_cbfs_file) -n $(cpu_ucode_cbfs_name) -a 16 | xargs $(CBFSTOOL) $(1) add -n $(cpu_ucode_cbfs_name) -f $(cpu_ucode_cbfs_file) -t 0x53 $(cpu_ucode_cbfs_offset)
else
add-cpu-microcode-to-cbfs = true
endif
diff --git a/src/cpu/intel/Kconfig b/src/cpu/intel/Kconfig
index 2bafa49..6f4f561 100644
--- a/src/cpu/intel/Kconfig
+++ b/src/cpu/intel/Kconfig
@@ -10,6 +10,7 @@ source src/cpu/intel/model_6fx/Kconfig
source src/cpu/intel/model_1067x/Kconfig
source src/cpu/intel/model_106cx/Kconfig
source src/cpu/intel/model_206ax/Kconfig
+source src/cpu/intel/fsp_model_206ax/Kconfig
source src/cpu/intel/model_2065x/Kconfig
source src/cpu/intel/model_f0x/Kconfig
source src/cpu/intel/model_f1x/Kconfig
diff --git a/src/cpu/intel/Makefile.inc b/src/cpu/intel/Makefile.inc
index 54624fb..964369d 100644
--- a/src/cpu/intel/Makefile.inc
+++ b/src/cpu/intel/Makefile.inc
@@ -19,6 +19,8 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += model_2065x
subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += model_206ax
subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += model_206ax
subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell
+subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_SANDYBRIDGE) += fsp_model_206ax
+subdirs-$(CONFIG_NORTHBRIDGE_INTEL_FSP_IVYBRIDGE) += fsp_model_206ax
subdirs-$(CONFIG_CPU_INTEL_SLOT_2) += slot_2
subdirs-$(CONFIG_CPU_INTEL_SLOT_1) += slot_1
subdirs-$(CONFIG_CPU_INTEL_SOCKET_LGA771) += socket_LGA771
diff --git a/src/cpu/intel/fsp_model_206ax/Kconfig b/src/cpu/intel/fsp_model_206ax/Kconfig
new file mode 100644
index 0000000..406f8a5
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/Kconfig
@@ -0,0 +1,93 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2013 Sage Electronic Engineering, LLC.
+##
+## 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
+##
+
+
+config CPU_INTEL_FSP_MODEL_206AX
+ bool
+
+config CPU_INTEL_FSP_MODEL_306AX
+ bool
+
+if CPU_INTEL_FSP_MODEL_206AX || CPU_INTEL_FSP_MODEL_306AX
+
+config CPU_SPECIFIC_OPTIONS
+ def_bool y
+ select SMP
+ select SSE2
+ select UDELAY_LAPIC
+ select SMM_TSEG
+ select CPU_MICROCODE_IN_CBFS if HAVE_FSP_BIN
+ select BOARD_MICROCODE_CBFS_GENERATE
+ select TSC_SYNC_MFENCE
+
+config BOOTBLOCK_CPU_INIT
+ string
+ default "cpu/intel/fsp_model_206ax/bootblock.c"
+
+config SERIAL_CPU_INIT
+ bool
+ default n
+
+config SMM_TSEG_SIZE
+ hex
+ default 0x800000
+
+config ENABLE_VMX
+ bool "Enable VMX for virtualization"
+ default n
+
+config CPU_MICROCODE_CBFS_LOC
+ hex
+ depends on CPU_MICROCODE_IN_CBFS
+ default 0xfff70000
+
+config CPU_MICROCODE_CBFS_LEN
+ hex
+ depends on CPU_MICROCODE_IN_CBFS
+ default 0xC000 if CPU_INTEL_FSP_MODEL_306AX
+ default 0x2800 if CPU_INTEL_FSP_MODEL_206AX
+
+config MICROCODE_INCLUDE_PATH
+ string "Location of the intel microcode patches"
+ default "../intel/cpu/ivybridge/microcode" if CPU_INTEL_FSP_MODEL_306AX
+ default "../intel/cpu/sandybridge/microcode" if CPU_INTEL_FSP_MODEL_206AX
+
+config FSP_IMAGE_ID_DWORD0
+ hex
+ default 0x2D325453 if CPU_INTEL_FSP_MODEL_306AX && SOUTHBRIDGE_INTEL_FSP_I89XX
+ default 0x2D324343 if CPU_INTEL_FSP_MODEL_306AX && SOUTHBRIDGE_INTEL_FSP_BD82X6X
+ help
+ The FSP Image ID is different for each platform's FSP and can be used to
+ verify that the right FSP binary is loaded.
+ For the ivybridge/89xx FSP, the Image Id will be "ST2-FSP\0",
+ for ivybridge/bd82x6x FSPs, the Image Id will be "CC2-FSP\0",
+ This dword holds the first 4 bytes of the string, as
+ a hex value.
+
+config FSP_IMAGE_ID_DWORD1
+ hex
+ default 0x00505346
+ help
+ For the ivybridge/I89xx FSP, the Image Id will be "ST2-FSP\0",
+ for ivybridge/bd82x6x FSPs, the Image Id will be "CC2-FSP\0",
+ This dword holds the second 4 bytes of the string, as
+ a hex value. Since the strings use the same second dword,
+ no additional logic is needed.
+
+endif
diff --git a/src/cpu/intel/fsp_model_206ax/Makefile.inc b/src/cpu/intel/fsp_model_206ax/Makefile.inc
new file mode 100644
index 0000000..1ea9c2a
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/Makefile.inc
@@ -0,0 +1,12 @@
+ramstage-y += model_206ax_init.c
+subdirs-y += ../../x86/name
+
+ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c
+
+smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c
+
+cpu_microcode-$(CONFIG_CPU_MICROCODE_CBFS_GENERATE) += microcode_blob.c
+
+cpu_incs += $(src)/cpu/intel/fsp_model_206ax/cache_as_ram.inc
+
+CC := $(CC) -I$(CONFIG_MICROCODE_INCLUDE_PATH)
diff --git a/src/cpu/intel/fsp_model_206ax/acpi.c b/src/cpu/intel/fsp_model_206ax/acpi.c
new file mode 100644
index 0000000..47e651f
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/acpi.c
@@ -0,0 +1,364 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 coresystems GmbH
+ * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * 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 <types.h>
+#include <console/console.h>
+#include <arch/acpi.h>
+#include <arch/acpigen.h>
+#include <arch/cpu.h>
+#include <cpu/x86/msr.h>
+#include <cpu/intel/speedstep.h>
+#include <cpu/intel/turbo.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include "model_206ax.h"
+#include "chip.h"
+
+static int get_cores_per_package(void)
+{
+ struct cpuinfo_x86 c;
+ struct cpuid_result result;
+ int cores = 1;
+
+ get_fms(&c, cpuid_eax(1));
+ if (c.x86 != 6)
+ return 1;
+
+ result = cpuid_ext(0xb, 1);
+ cores = result.ebx & 0xff;
+
+ return cores;
+}
+
+static int generate_cstate_entries(acpi_cstate_t *cstates,
+ int c1, int c2, int c3)
+{
+ int length, cstate_count = 0;
+
+ /* Count number of active C-states */
+ if (c1 > 0)
+ ++cstate_count;
+ if (c2 > 0)
+ ++cstate_count;
+ if (c3 > 0)
+ ++cstate_count;
+ if (!cstate_count)
+ return 0;
+
+ length = acpigen_write_package(cstate_count + 1);
+ length += acpigen_write_byte(cstate_count);
+
+ /* Add an entry if the level is enabled */
+ if (c1 > 0) {
+ cstates[c1].ctype = 1;
+ length += acpigen_write_CST_package_entry(&cstates[c1]);
+ }
+ if (c2 > 0) {
+ cstates[c2].ctype = 2;
+ length += acpigen_write_CST_package_entry(&cstates[c2]);
+ }
+ if (c3 > 0) {
+ cstates[c3].ctype = 3;
+ length += acpigen_write_CST_package_entry(&cstates[c3]);
+ }
+
+ acpigen_patch_len(length - 1);
+ return length;
+}
+
+static int generate_C_state_entries(void)
+{
+ struct cpu_info *info;
+ struct cpu_driver *cpu;
+ int len, lenif;
+ device_t lapic;
+ struct cpu_intel_fsp_model_206ax_config *conf = NULL;
+
+ /* Find the SpeedStep CPU in the device tree using magic APIC ID */
+ lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
+ if (!lapic)
+ return 0;
+ conf = lapic->chip_info;
+ if (!conf)
+ return 0;
+
+ /* Find CPU map of supported C-states */
+ info = cpu_info();
+ if (!info)
+ return 0;
+ cpu = find_cpu_driver(info->cpu);
+ if (!cpu || !cpu->cstates)
+ return 0;
+
+ len = acpigen_emit_byte(0x14); /* MethodOp */
+ len += acpigen_write_len_f(); /* PkgLength */
+ len += acpigen_emit_namestring("_CST");
+ len += acpigen_emit_byte(0x00); /* No Arguments */
+
+ /* If running on AC power */
+ len += acpigen_emit_byte(0xa0); /* IfOp */
+ lenif = acpigen_write_len_f(); /* PkgLength */
+ lenif += acpigen_emit_namestring("PWRS");
+ lenif += acpigen_emit_byte(0xa4); /* ReturnOp */
+ lenif += generate_cstate_entries(cpu->cstates, conf->c1_acpower,
+ conf->c2_acpower, conf->c3_acpower);
+ acpigen_patch_len(lenif - 1);
+ len += lenif;
+
+ /* Else on battery power */
+ len += acpigen_emit_byte(0xa4); /* ReturnOp */
+ len += generate_cstate_entries(cpu->cstates, conf->c1_battery,
+ conf->c2_battery, conf->c3_battery);
+ acpigen_patch_len(len - 1);
+ return len;
+}
+
+static acpi_tstate_t tss_table_fine[] = {
+ { 100, 1000, 0, 0x00, 0 },
+ { 94, 940, 0, 0x1f, 0 },
+ { 88, 880, 0, 0x1e, 0 },
+ { 82, 820, 0, 0x1d, 0 },
+ { 75, 760, 0, 0x1c, 0 },
+ { 69, 700, 0, 0x1b, 0 },
+ { 63, 640, 0, 0x1a, 0 },
+ { 57, 580, 0, 0x19, 0 },
+ { 50, 520, 0, 0x18, 0 },
+ { 44, 460, 0, 0x17, 0 },
+ { 38, 400, 0, 0x16, 0 },
+ { 32, 340, 0, 0x15, 0 },
+ { 25, 280, 0, 0x14, 0 },
+ { 19, 220, 0, 0x13, 0 },
+ { 13, 160, 0, 0x12, 0 },
+};
+
+static acpi_tstate_t tss_table_coarse[] = {
+ { 100, 1000, 0, 0x00, 0 },
+ { 88, 875, 0, 0x1f, 0 },
+ { 75, 750, 0, 0x1e, 0 },
+ { 63, 625, 0, 0x1d, 0 },
+ { 50, 500, 0, 0x1c, 0 },
+ { 38, 375, 0, 0x1b, 0 },
+ { 25, 250, 0, 0x1a, 0 },
+ { 13, 125, 0, 0x19, 0 },
+};
+
+static int generate_T_state_entries(int core, int cores_per_package)
+{
+ int len;
+
+ /* Indicate SW_ALL coordination for T-states */
+ len = acpigen_write_TSD_package(core, cores_per_package, SW_ALL);
+
+ /* Indicate FFixedHW so OS will use MSR */
+ len += acpigen_write_empty_PTC();
+
+ /* Set a T-state limit that can be modified in NVS */
+ len += acpigen_write_TPC("\\TLVL");
+
+ /*
+ * CPUID.(EAX=6):EAX[5] indicates support
+ * for extended throttle levels.
+ */
+ if (cpuid_eax(6) & (1 << 5))
+ len += acpigen_write_TSS_package(
+ ARRAY_SIZE(tss_table_fine), tss_table_fine);
+ else
+ len += acpigen_write_TSS_package(
+ ARRAY_SIZE(tss_table_coarse), tss_table_coarse);
+
+ return len;
+}
+
+static int calculate_power(int tdp, int p1_ratio, int ratio)
+{
+ u32 m;
+ u32 power;
+
+ /*
+ * M = ((1.1 - ((p1_ratio - ratio) * 0.00625)) / 1.1) ^ 2
+ *
+ * Power = (ratio / p1_ratio) * m * tdp
+ */
+
+ m = (110000 - ((p1_ratio - ratio) * 625)) / 11;
+ m = (m * m) / 1000;
+
+ power = ((ratio * 100000 / p1_ratio) / 100);
+ power *= (m / 100) * (tdp / 1000);
+ power /= 1000;
+
+ return (int)power;
+}
+
+static int generate_P_state_entries(int core, int cores_per_package)
+{
+ int len, len_pss;
+ int ratio_min, ratio_max, ratio_turbo, ratio_step;
+ int coord_type, power_max, power_unit, num_entries;
+ int ratio, power, clock, clock_max;
+ msr_t msr;
+
+ /* Determine P-state coordination type from MISC_PWR_MGMT[0] */
+ msr = rdmsr(MSR_MISC_PWR_MGMT);
+ if (msr.lo & MISC_PWR_MGMT_EIST_HW_DIS)
+ coord_type = SW_ANY;
+ else
+ coord_type = HW_ALL;
+
+ /* Get bus ratio limits and calculate clock speeds */
+ msr = rdmsr(MSR_PLATFORM_INFO);
+ ratio_min = (msr.hi >> (40-32)) & 0xff; /* Max Efficiency Ratio */
+
+ /* Determine if this CPU has configurable TDP */
+ if (cpu_config_tdp_levels()) {
+ /* Set max ratio to nominal TDP ratio */
+ msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
+ ratio_max = msr.lo & 0xff;
+ } else {
+ /* Max Non-Turbo Ratio */
+ ratio_max = (msr.lo >> 8) & 0xff;
+ }
+ clock_max = ratio_max * SANDYBRIDGE_BCLK;
+
+ /* Calculate CPU TDP in mW */
+ msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
+ power_unit = 2 << ((msr.lo & 0xf) - 1);
+ msr = rdmsr(MSR_PKG_POWER_SKU);
+ power_max = ((msr.lo & 0x7fff) / power_unit) * 1000;
+
+ /* Write _PCT indicating use of FFixedHW */
+ len = acpigen_write_empty_PCT();
+
+ /* Write _PPC with no limit on supported P-state */
+ len += acpigen_write_PPC_NVS();
+
+ /* Write PSD indicating configured coordination type */
+ len += acpigen_write_PSD_package(core, cores_per_package, coord_type);
+
+ /* Add P-state entries in _PSS table */
+ len += acpigen_write_name("_PSS");
+
+ /* Determine ratio points */
+ ratio_step = PSS_RATIO_STEP;
+ num_entries = (ratio_max - ratio_min) / ratio_step;
+ while (num_entries > PSS_MAX_ENTRIES-1) {
+ ratio_step <<= 1;
+ num_entries >>= 1;
+ }
+
+ /* P[T] is Turbo state if enabled */
+ if (get_turbo_state() == TURBO_ENABLED) {
+ /* _PSS package count including Turbo */
+ len_pss = acpigen_write_package(num_entries + 2);
+
+ msr = rdmsr(MSR_TURBO_RATIO_LIMIT);
+ ratio_turbo = msr.lo & 0xff;
+
+ /* Add entry for Turbo ratio */
+ len_pss += acpigen_write_PSS_package(
+ clock_max + 1, /*MHz*/
+ power_max, /*mW*/
+ PSS_LATENCY_TRANSITION, /*lat1*/
+ PSS_LATENCY_BUSMASTER, /*lat2*/
+ ratio_turbo << 8, /*control*/
+ ratio_turbo << 8); /*status*/
+ } else {
+ /* _PSS package count without Turbo */
+ len_pss = acpigen_write_package(num_entries + 1);
+ }
+
+ /* First regular entry is max non-turbo ratio */
+ len_pss += acpigen_write_PSS_package(
+ clock_max, /*MHz*/
+ power_max, /*mW*/
+ PSS_LATENCY_TRANSITION, /*lat1*/
+ PSS_LATENCY_BUSMASTER, /*lat2*/
+ ratio_max << 8, /*control*/
+ ratio_max << 8); /*status*/
+
+ /* Generate the remaining entries */
+ for (ratio = ratio_min + ((num_entries - 1) * ratio_step);
+ ratio >= ratio_min; ratio -= ratio_step) {
+
+ /* Calculate power at this ratio */
+ power = calculate_power(power_max, ratio_max, ratio);
+ clock = ratio * SANDYBRIDGE_BCLK;
+
+ len_pss += acpigen_write_PSS_package(
+ clock, /*MHz*/
+ power, /*mW*/
+ PSS_LATENCY_TRANSITION, /*lat1*/
+ PSS_LATENCY_BUSMASTER, /*lat2*/
+ ratio << 8, /*control*/
+ ratio << 8); /*status*/
+ }
+
+ /* Fix package length */
+ len_pss--;
+ acpigen_patch_len(len_pss);
+
+ return len + len_pss;
+}
+
+void generate_cpu_entries(void)
+{
+ int len_pr;
+ int coreID, cpuID, pcontrol_blk = PMB0_BASE, plen = 6;
+ int totalcores = dev_count_cpu();
+ int cores_per_package = get_cores_per_package();
+ int numcpus = totalcores/cores_per_package;
+
+ printk(BIOS_DEBUG, "Found %d CPU(s) with %d core(s) each.\n",
+ numcpus, cores_per_package);
+
+ for (cpuID=1; cpuID <=numcpus; cpuID++) {
+ for (coreID=1; coreID<=cores_per_package; coreID++) {
+ if (coreID>1) {
+ pcontrol_blk = 0;
+ plen = 0;
+ }
+
+ /* Generate processor \_PR.CPUx */
+ len_pr = acpigen_write_processor(
+ (cpuID-1)*cores_per_package+coreID-1,
+ pcontrol_blk, plen);
+
+ /* Generate P-state tables */
+ len_pr += generate_P_state_entries(
+ cpuID-1, cores_per_package);
+
+ /* Generate C-state tables */
+ len_pr += generate_C_state_entries();
+
+ /* Generate T-state tables */
+ len_pr += generate_T_state_entries(
+ cpuID-1, cores_per_package);
+
+ len_pr--;
+ acpigen_patch_len(len_pr);
+ }
+ }
+}
+
+struct chip_operations cpu_intel_model_206ax_ops = {
+ CHIP_NAME("Intel SandyBridge/IvyBridge CPU")
+};
diff --git a/src/cpu/intel/fsp_model_206ax/acpi/cpu.asl b/src/cpu/intel/fsp_model_206ax/acpi/cpu.asl
new file mode 100644
index 0000000..558a9d3
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/acpi/cpu.asl
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
+ *
+ * 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
+ */
+
+/* These devices are created at runtime */
+External (\_PR.CPU0, DeviceObj)
+External (\_PR.CPU1, DeviceObj)
+External (\_PR.CPU2, DeviceObj)
+External (\_PR.CPU3, DeviceObj)
+External (\_PR.CPU4, DeviceObj)
+External (\_PR.CPU5, DeviceObj)
+External (\_PR.CPU6, DeviceObj)
+External (\_PR.CPU7, DeviceObj)
+
+/* Notify OS to re-read CPU tables, assuming ^2 CPU count */
+Method (PNOT)
+{
+ If (LGreaterEqual (\PCNT, 2)) {
+ Notify (\_PR.CPU0, 0x81) // _CST
+ Notify (\_PR.CPU1, 0x81) // _CST
+ }
+ If (LGreaterEqual (\PCNT, 4)) {
+ Notify (\_PR.CPU2, 0x81) // _CST
+ Notify (\_PR.CPU3, 0x81) // _CST
+ }
+ If (LGreaterEqual (\PCNT, 8)) {
+ Notify (\_PR.CPU4, 0x81) // _CST
+ Notify (\_PR.CPU5, 0x81) // _CST
+ Notify (\_PR.CPU6, 0x81) // _CST
+ Notify (\_PR.CPU7, 0x81) // _CST
+ }
+}
+
+/* Notify OS to re-read CPU _PPC limit, assuming ^2 CPU count */
+Method (PPCN)
+{
+ If (LGreaterEqual (\PCNT, 2)) {
+ Notify (\_PR.CPU0, 0x80) // _PPC
+ Notify (\_PR.CPU1, 0x80) // _PPC
+ }
+ If (LGreaterEqual (\PCNT, 4)) {
+ Notify (\_PR.CPU2, 0x80) // _PPC
+ Notify (\_PR.CPU3, 0x80) // _PPC
+ }
+ If (LGreaterEqual (\PCNT, 8)) {
+ Notify (\_PR.CPU4, 0x80) // _PPC
+ Notify (\_PR.CPU5, 0x80) // _PPC
+ Notify (\_PR.CPU6, 0x80) // _PPC
+ Notify (\_PR.CPU7, 0x80) // _PPC
+ }
+}
+
+/* Notify OS to re-read Throttle Limit tables, assuming ^2 CPU count */
+Method (TNOT)
+{
+ If (LGreaterEqual (\PCNT, 2)) {
+ Notify (\_PR.CPU0, 0x82) // _TPC
+ Notify (\_PR.CPU1, 0x82) // _TPC
+ }
+ If (LGreaterEqual (\PCNT, 4)) {
+ Notify (\_PR.CPU2, 0x82) // _TPC
+ Notify (\_PR.CPU3, 0x82) // _TPC
+ }
+ If (LGreaterEqual (\PCNT, 8)) {
+ Notify (\_PR.CPU4, 0x82) // _TPC
+ Notify (\_PR.CPU5, 0x82) // _TPC
+ Notify (\_PR.CPU6, 0x82) // _TPC
+ Notify (\_PR.CPU7, 0x82) // _TPC
+ }
+}
+
+/* Return a package containing enabled processor entries */
+Method (PPKG)
+{
+ If (LGreaterEqual (\PCNT, 8)) {
+ Return (Package() {\_PR.CPU0, \_PR.CPU1, \_PR.CPU2, \_PR.CPU3,
+ \_PR.CPU4, \_PR.CPU5, \_PR.CPU6, \_PR.CPU7})
+ } ElseIf (LGreaterEqual (\PCNT, 4)) {
+ Return (Package() {\_PR.CPU0, \_PR.CPU1, \_PR.CPU2, \_PR.CPU3})
+ } ElseIf (LGreaterEqual (\PCNT, 2)) {
+ Return (Package() {\_PR.CPU0, \_PR.CPU1})
+ } Else {
+ Return (Package() {\_PR.CPU0})
+ }
+}
diff --git a/src/cpu/intel/fsp_model_206ax/bootblock.c b/src/cpu/intel/fsp_model_206ax/bootblock.c
new file mode 100644
index 0000000..338b8c9
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/bootblock.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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 <stdint.h>
+#include <arch/cpu.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/mtrr.h>
+#include <arch/io.h>
+
+#include "model_206ax.h"
+
+
+static void set_var_mtrr(
+ unsigned reg, unsigned base, unsigned size, unsigned type)
+
+{
+ /* Bit Bit 32-35 of MTRRphysMask should be set to 1 */
+ /* FIXME: It only support 4G less range */
+ msr_t basem, maskm;
+ basem.lo = base | type;
+ basem.hi = 0;
+ wrmsr(MTRRphysBase_MSR(reg), basem);
+ maskm.lo = ~(size - 1) | MTRRphysMaskValid;
+ maskm.hi = (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1;
+ wrmsr(MTRRphysMask_MSR(reg), maskm);
+}
+
+static void enable_rom_caching(void)
+{
+ msr_t msr;
+
+ disable_cache();
+ set_var_mtrr(1, 0xffc00000, 4*1024*1024, MTRR_TYPE_WRPROT);
+ enable_cache();
+
+ /* Enable Variable MTRRs */
+ msr.hi = 0x00000000;
+ msr.lo = 0x00000800;
+ wrmsr(MTRRdefType_MSR, msr);
+}
+
+
+
+static void bootblock_cpu_init(void)
+{
+ enable_rom_caching();
+}
diff --git a/src/cpu/intel/fsp_model_206ax/cache_as_ram.inc b/src/cpu/intel/fsp_model_206ax/cache_as_ram.inc
new file mode 100644
index 0000000..a4f0d0b
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/cache_as_ram.inc
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2000,2007 Ronald G. Minnich <rminnich(a)gmail.com>
+ * Copyright (C) 2007-2008 coresystems GmbH
+ * Copyright (C) 2013 Sage Electronic Engineering, LLC.
+ *
+ * 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 <cpu/x86/stack.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/post_code.h>
+#include <cbmem.h>
+
+#define CACHE_AS_RAM_SIZE CONFIG_DCACHE_RAM_SIZE
+#define CACHE_AS_RAM_BASE CONFIG_DCACHE_RAM_BASE
+
+#define CPU_PHYSMASK_HI (1 << (CONFIG_CPU_ADDR_BITS - 32) - 1)
+#define LHLT_DELAY 0x50000 /* delay between post codes on FSP failure */
+#define NoEvictMod_MSR 0x2e0
+
+cache_as_ram:
+ post_code(0x20)
+
+#if CONFIG_HAVE_FSP_BIN
+ /* Send INIT IPI to all excluding ourself. */
+ movl $0x000C4500, %eax
+ movl $0xFEE00300, %esi
+ movl %eax, (%esi)
+
+ /* All CPUs need to be in Wait for SIPI state */
+wait_for_sipi:
+ movl (%esi), %eax
+ bt $12, %eax
+ jc wait_for_sipi
+
+ post_code(0x21)
+ /* Zero out all fixed range and variable range MTRRs. */
+ movl $mtrr_table, %esi
+ movl $((mtrr_table_end - mtrr_table) / 2), %edi
+ xorl %eax, %eax
+ xorl %edx, %edx
+clear_mtrrs:
+ movw (%esi), %bx
+ movzx %bx, %ecx
+ wrmsr
+ add $2, %esi
+ dec %edi
+ jnz clear_mtrrs
+
+ /* Init floating point */
+ emms
+ fninit
+
+ /*
+ * Find the FSP binary in cbfs.
+ * Make a fake stack that has the return value back to this code.
+ */
+ lea fake_fsp_stack, %esp
+ jmp find_fsp
+find_fsp_ret:
+ /* Save the FSP location */
+ mov %eax, %ebp
+ cmp $CONFIG_FSP_LOC, %eax
+ jb halt1
+
+ post_code(0x22)
+
+ /* Calculate entry into FSP */
+ mov 0x30(%ebp), %eax /* Load TempRamInitEntry */
+ add 0x1c(%ebp), %eax /* add in the offset for the FSP base address */
+
+ /*
+ * Pass early init variables on a fake stack (no memory yet)
+ * as well as the return location
+ */
+ lea CAR_init_stack, %esp
+
+ /* call FSP binary to setup temporary stack */
+ jmp *%eax
+
+CAR_init_done:
+ addl $4, %esp
+ cmp $0, %eax
+ jne halt2
+
+ /* Save FSP_INFO_HEADER location in ebx */
+ mov %ebp, %ebx
+
+ /*
+ * setup bootloader stack
+ * ecx: stack base
+ * edx: stack top
+ */
+ lea -4(%edx), %esp
+ movl %esp, %ebp
+
+before_romstage:
+ post_code(0x23)
+
+ /* Call romstage.c main function. */
+ pushl %ebx
+ call main
+
+romstage_main_return:
+ post_code(0x2f)
+
+/* Disable cache. */
+ movl %cr0, %eax
+ orl $CR0_CacheDisable, %eax
+ movl %eax, %cr0
+
+ post_code(0x31)
+
+ /* Disable MTRR. */
+ movl $MTRRdefType_MSR, %ecx
+ rdmsr
+ andl $(~MTRRdefTypeEn), %eax
+ wrmsr
+
+ post_code(0x32)
+
+ /* Zero out all fixed range and variable range MTRRs. */
+ movl $mtrr_table, %esi
+ movl $((mtrr_table_end - mtrr_table) / 2), %edi
+ xorl %eax, %eax
+ xorl %edx, %edx
+_clear_mtrrs_:
+ movw (%esi), %bx
+ movzx %bx, %ecx
+ wrmsr
+ add $2, %esi
+ dec %edi
+ jnz _clear_mtrrs_
+
+ post_code(0x33)
+
+ /* Enable cache. */
+ movl %cr0, %eax
+ andl $~(CR0_CacheDisable | CR0_NoWriteThrough), %eax
+ movl %eax, %cr0
+
+ post_code(0x36)
+
+ /* Disable cache. */
+ movl %cr0, %eax
+ orl $CR0_CacheDisable, %eax
+ movl %eax, %cr0
+
+ post_code(0x38)
+
+ /* Enable Write Back and Speculative Reads for the first MB
+ * and coreboot_ram.
+ */
+ movl $MTRRphysBase_MSR(0), %ecx
+ movl $(0x00000000 | MTRR_TYPE_WRBACK), %eax
+ xorl %edx, %edx
+ wrmsr
+ movl $MTRRphysMask_MSR(0), %ecx
+ movl $(~(CONFIG_RAMTOP - 1) | MTRRphysMaskValid), %eax
+ movl $CPU_PHYSMASK_HI, %edx // 36bit address space
+ wrmsr
+
+#if CONFIG_CACHE_ROM_SIZE
+ /* Enable Caching and speculative Reads for the
+ * complete ROM now that we actually have RAM.
+ */
+ movl $MTRRphysBase_MSR(1), %ecx
+ movl $(CACHE_ROM_BASE | MTRR_TYPE_WRPROT), %eax
+ xorl %edx, %edx
+ wrmsr
+ movl $MTRRphysMask_MSR(1), %ecx
+ movl $(~(CONFIG_CACHE_ROM_SIZE - 1) | MTRRphysMaskValid), %eax
+ movl $CPU_PHYSMASK_HI, %edx
+ wrmsr
+#endif
+
+ post_code(0x39)
+
+ /* And enable cache again after setting MTRRs. */
+ movl %cr0, %eax
+ andl $~(CR0_CacheDisable | CR0_NoWriteThrough), %eax
+ movl %eax, %cr0
+
+ post_code(0x3a)
+
+ /* Enable MTRR. */
+ movl $MTRRdefType_MSR, %ecx
+ rdmsr
+ orl $MTRRdefTypeEn, %eax
+ wrmsr
+
+ post_code(0x3d)
+
+ /* Clear boot_complete flag. */
+ xorl %ebp, %ebp
+__main:
+ post_code(POST_PREPARE_RAMSTAGE)
+ cld /* Clear direction flag. */
+
+ movl %ebp, %esi
+
+ movl $ROMSTAGE_STACK, %esp
+ movl %esp, %ebp
+ pushl %esi
+ call copy_and_run
+
+halt1:
+ /*
+ * Failures for postcode 0xBA - failed in find_fsp()
+ *
+ * Values are:
+ * 0x01 - FV signature, "_FVH" not present
+ * 0x02 - FFS GUID not present
+ * 0x03 - FSP INFO Header not found
+ * 0x04 - ImageBase does not equal CONFIG_FSP_LOC - Is the FSP rebased to
+ * a different location, or does it need to be?
+ * 0x05 - FSP INFO Header signature "FSPH" not found
+ * 0x06 - FSP Image ID is not the expected ID.
+ * For ivybridge_bd82x6x, the ID is expected to be 'CC2-FSP\0'
+ * For ivybridge_i89xx, the ID is expected to be 'ST2-FSP\0'
+ *
+ */
+ movb $0xBA, %ah
+ jmp .Lhlt
+
+halt2:
+ /*
+ * Failures for postcode 0xBB - failed in the FSP:
+ *
+ * 0x00 - FSP_SUCCESS: Temp RAM was initialized successfully.
+ * 0x02 - FSP_INVALID_PARAMETER: Input parameters are invalid.
+ * 0x0E - FSP_NOT_FOUND: No valid microcode was found in the microcode region.
+ * 0x03 - FSP_UNSUPPORTED: The FSP calling conditions were not met.
+ * 0x07 - FSP_DEVICE_ERROR: Temp RAM initialization failed
+ * 0x14 - FSP_ALREADY_STARTED: Temp RAM initialization has been invoked
+ */
+ movb $0xBB, %ah
+
+.Lhlt:
+ xchg %al, %ah
+#if CONFIG_IO_POST
+ outb %al, $CONFIG_IO_POST_PORT
+#else
+ post_code(POST_DEAD_CODE)
+#endif
+ movl $LHLT_DELAY, %ecx
+.Lhlt_Delay:
+ outb %al, $0xED
+ loop .Lhlt_Delay
+ jmp .Lhlt
+
+ .align 4
+fake_fsp_stack:
+ .long find_fsp_ret
+
+CAR_init_params:
+ .long CONFIG_CPU_MICROCODE_CBFS_LOC
+ .long CONFIG_CPU_MICROCODE_CBFS_LEN /* Microcode Length */
+ .long 0xFFFFFFFF - CONFIG_ROM_SIZE + 1 /* Firmware Location */
+ .long CONFIG_ROM_SIZE /* Total Firmware Length */
+
+CAR_init_stack:
+ .long CAR_init_done
+ .long CAR_init_params
+
+mtrr_table:
+ /* Fixed MTRRs */
+ .word 0x250, 0x258, 0x259
+ .word 0x268, 0x269, 0x26A
+ .word 0x26B, 0x26C, 0x26D
+ .word 0x26E, 0x26F
+ /* Variable MTRRs */
+ .word 0x200, 0x201, 0x202, 0x203
+ .word 0x204, 0x205, 0x206, 0x207
+ .word 0x208, 0x209, 0x20A, 0x20B
+ .word 0x20C, 0x20D, 0x20E, 0x20F
+/* .word 0x210, 0x211, 0x212, 0x213 */
+mtrr_table_end:
+
+#endif /* CONFIG_HAVE_FSP_BIN */
\ No newline at end of file
diff --git a/src/cpu/intel/fsp_model_206ax/chip.h b/src/cpu/intel/fsp_model_206ax/chip.h
new file mode 100644
index 0000000..afa5774
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/chip.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * 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
+ */
+
+/* Magic value used to locate this chip in the device tree */
+#define SPEEDSTEP_APIC_MAGIC 0xACAC
+
+struct cpu_intel_fsp_model_206ax_config {
+ u8 disable_acpi; /* Do not generate CPU ACPI tables */
+
+ u8 pstate_coord_type; /* Processor Coordination Type */
+
+ int c1_battery; /* ACPI C1 on Battery Power */
+ int c2_battery; /* ACPI C2 on Battery Power */
+ int c3_battery; /* ACPI C3 on Battery Power */
+
+ int c1_acpower; /* ACPI C1 on AC Power */
+ int c2_acpower; /* ACPI C2 on AC Power */
+ int c3_acpower; /* ACPI C3 on AC Power */
+
+ int tcc_offset; /* TCC Activation Offset */
+};
diff --git a/src/cpu/intel/fsp_model_206ax/finalize.c b/src/cpu/intel/fsp_model_206ax/finalize.c
new file mode 100644
index 0000000..4ed5d1e
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/finalize.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/msr.h>
+#include "model_206ax.h"
+
+static void msr_set_bit(unsigned reg, unsigned bit)
+{
+ msr_t msr = rdmsr(reg);
+
+ if (bit < 32) {
+ if (msr.lo & (1 << bit))
+ return;
+ msr.lo |= 1 << bit;
+ } else {
+ if (msr.hi & (1 << (bit - 32)))
+ return;
+ msr.hi |= 1 << (bit - 32);
+ }
+
+ wrmsr(reg, msr);
+}
+
+void intel_model_206ax_finalize_smm(void)
+{
+ msr_set_bit(MSR_PMG_CST_CONFIG_CONTROL, 15);
+
+ /* Lock AES-NI only if supported */
+ if (cpuid_ecx(1) & (1 << 25))
+ msr_set_bit(MSR_FEATURE_CONFIG, 0);
+
+#ifdef LOCK_POWER_CONTROL_REGISTERS
+ /*
+ * Lock the power control registers.
+ *
+ * These registers can be left unlocked if modifying power
+ * limits from the OS is desirable. Modifying power limits
+ * from the OS can be especially useful for experimentation
+ * during early phases of system bringup while the thermal
+ * power envelope is being proven.
+ */
+
+ msr_set_bit(MSR_PP0_CURRENT_CONFIG, 31);
+ msr_set_bit(MSR_PP1_CURRENT_CONFIG, 31);
+ msr_set_bit(MSR_PKG_POWER_LIMIT, 63);
+ msr_set_bit(MSR_PP0_POWER_LIMIT, 31);
+ msr_set_bit(MSR_PP1_POWER_LIMIT, 31);
+#endif
+
+ msr_set_bit(MSR_MISC_PWR_MGMT, 22);
+ msr_set_bit(MSR_LT_LOCK_MEMORY, 0);
+}
diff --git a/src/cpu/intel/fsp_model_206ax/microcode_blob.c b/src/cpu/intel/fsp_model_206ax/microcode_blob.c
new file mode 100644
index 0000000..8bd790a
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/microcode_blob.c
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.
+ *
+ * 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
+ */
+
+unsigned microcode[] = {
+#if IS_ENABLED(CONFIG_CPU_MICROCODE_IN_CBFS)
+#include "microcode_blob.h"
+#endif
+};
diff --git a/src/cpu/intel/fsp_model_206ax/microcode_blob.h b/src/cpu/intel/fsp_model_206ax/microcode_blob.h
new file mode 100644
index 0000000..e56bef1
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/microcode_blob.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Google Inc.
+ * Copyright (C) 2013 Sage Electronic Engineering, LLC.
+ *
+ * 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
+ */
+
+#if IS_ENABLED(CONFIG_CPU_INTEL_FSP_MODEL_206AX)
+ /* Size is 0x2800 - Update in Kconfigs when any included file changes*/
+ #include <microcode-m12206a7_00000029.h>
+#endif
+
+#if IS_ENABLED(CONFIG_CPU_INTEL_FSP_MODEL_306AX)
+ /* Size is 0xC000 - Update in Kconfigs when any included file changes*/
+ #include <microcode-m12306a2_00000008.h>
+ #include <microcode-m12306a4_00000007.h>
+ #include <microcode-m12306a5_00000007.h>
+ #include <microcode-m12306a8_00000010.h>
+ #include <microcode-m12306a9_00000019.h>
+#endif
diff --git a/src/cpu/intel/fsp_model_206ax/model_206ax.h b/src/cpu/intel/fsp_model_206ax/model_206ax.h
new file mode 100644
index 0000000..a7ca04a
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/model_206ax.h
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
+ *
+ * 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
+ */
+
+#ifndef _CPU_INTEL_MODEL_206AX_H
+#define _CPU_INTEL_MODEL_206AX_H
+
+/* SandyBridge/IvyBridge bus clock is fixed at 100MHz */
+#define SANDYBRIDGE_BCLK 100
+
+#define IA32_FEATURE_CONTROL 0x3a
+#define CPUID_VMX (1 << 5)
+#define CPUID_SMX (1 << 6)
+#define MSR_FEATURE_CONFIG 0x13c
+#define MSR_FLEX_RATIO 0x194
+#define FLEX_RATIO_LOCK (1 << 20)
+#define FLEX_RATIO_EN (1 << 16)
+#define IA32_PLATFORM_DCA_CAP 0x1f8
+#define IA32_MISC_ENABLE 0x1a0
+#define MSR_TEMPERATURE_TARGET 0x1a2
+#define IA32_PERF_CTL 0x199
+#define IA32_THERM_INTERRUPT 0x19b
+#define IA32_ENERGY_PERFORMANCE_BIAS 0x1b0
+#define ENERGY_POLICY_PERFORMANCE 0
+#define ENERGY_POLICY_NORMAL 6
+#define ENERGY_POLICY_POWERSAVE 15
+#define IA32_PACKAGE_THERM_INTERRUPT 0x1b2
+#define MSR_LT_LOCK_MEMORY 0x2e7
+#define IA32_MC0_STATUS 0x401
+
+#define MSR_PIC_MSG_CONTROL 0x2e
+#define MSR_PLATFORM_INFO 0xce
+#define PLATFORM_INFO_SET_TDP (1 << 29)
+#define MSR_PMG_CST_CONFIG_CONTROL 0xe2
+#define MSR_PMG_IO_CAPTURE_BASE 0xe4
+
+#define MSR_MISC_PWR_MGMT 0x1aa
+#define MISC_PWR_MGMT_EIST_HW_DIS (1 << 0)
+#define MSR_TURBO_RATIO_LIMIT 0x1ad
+#define MSR_POWER_CTL 0x1fc
+
+#define MSR_PKGC3_IRTL 0x60a
+#define MSR_PKGC6_IRTL 0x60b
+#define MSR_PKGC7_IRTL 0x60c
+#define IRTL_VALID (1 << 15)
+#define IRTL_1_NS (0 << 10)
+#define IRTL_32_NS (1 << 10)
+#define IRTL_1024_NS (2 << 10)
+#define IRTL_32768_NS (3 << 10)
+#define IRTL_1048576_NS (4 << 10)
+#define IRTL_33554432_NS (5 << 10)
+#define IRTL_RESPONSE_MASK (0x3ff)
+
+/* long duration in low dword, short duration in high dword */
+#define MSR_PKG_POWER_LIMIT 0x610
+#define PKG_POWER_LIMIT_MASK 0x7fff
+#define PKG_POWER_LIMIT_EN (1 << 15)
+#define PKG_POWER_LIMIT_CLAMP (1 << 16)
+#define PKG_POWER_LIMIT_TIME_SHIFT 17
+#define PKG_POWER_LIMIT_TIME_MASK 0x7f
+
+#define MSR_PP0_CURRENT_CONFIG 0x601
+#define PP0_CURRENT_LIMIT (112 << 3) /* 112 A */
+#define MSR_PP1_CURRENT_CONFIG 0x602
+#define PP1_CURRENT_LIMIT_SNB (35 << 3) /* 35 A */
+#define PP1_CURRENT_LIMIT_IVB (50 << 3) /* 50 A */
+#define MSR_PKG_POWER_SKU_UNIT 0x606
+#define MSR_PKG_POWER_SKU 0x614
+#define MSR_PP0_POWER_LIMIT 0x638
+#define MSR_PP1_POWER_LIMIT 0x640
+
+#define IVB_CONFIG_TDP_MIN_CPUID 0x306a2
+#define MSR_CONFIG_TDP_NOMINAL 0x648
+#define MSR_CONFIG_TDP_LEVEL1 0x649
+#define MSR_CONFIG_TDP_LEVEL2 0x64a
+#define MSR_CONFIG_TDP_CONTROL 0x64b
+#define MSR_TURBO_ACTIVATION_RATIO 0x64c
+
+/* P-state configuration */
+#define PSS_MAX_ENTRIES 8
+#define PSS_RATIO_STEP 2
+#define PSS_LATENCY_TRANSITION 10
+#define PSS_LATENCY_BUSMASTER 10
+
+#ifndef __ROMCC__
+#ifdef __SMM__
+/* Lock MSRs */
+void intel_model_206ax_finalize_smm(void);
+#else
+/* Configure power limits for turbo mode */
+void set_power_limits(u8 power_limit_1_time);
+int cpu_config_tdp_levels(void);
+#endif
+#endif
+
+#endif
diff --git a/src/cpu/intel/fsp_model_206ax/model_206ax_init.c b/src/cpu/intel/fsp_model_206ax/model_206ax_init.c
new file mode 100644
index 0000000..6eb4787
--- /dev/null
+++ b/src/cpu/intel/fsp_model_206ax/model_206ax_init.c
@@ -0,0 +1,433 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2007-2009 coresystems GmbH
+ * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
+ *
+ * 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 <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <arch/acpi.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/intel/speedstep.h>
+#include <cpu/intel/turbo.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/name.h>
+#include <pc80/mc146818rtc.h>
+#include <usbdebug.h>
+#include "model_206ax.h"
+#include "chip.h"
+
+static void enable_vmx(void)
+{
+ struct cpuid_result regs;
+ msr_t msr;
+ int enable = CONFIG_ENABLE_VMX;
+
+ regs = cpuid(1);
+ /* Check that the VMX is supported before reading or writing the MSR. */
+ if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX)))
+ return;
+
+ msr = rdmsr(IA32_FEATURE_CONTROL);
+
+ if (msr.lo & (1 << 0)) {
+ printk(BIOS_ERR, "VMX is locked, so %s will do nothing\n", __func__);
+ /* VMX locked. If we set it again we get an illegal
+ * instruction
+ */
+ return;
+ }
+
+ /* The IA32_FEATURE_CONTROL MSR may initialize with random values.
+ * It must be cleared regardless of VMX config setting.
+ */
+ msr.hi = msr.lo = 0;
+
+ printk(BIOS_DEBUG, "%s VMX\n", enable ? "Enabling" : "Disabling");
+
+ if (enable) {
+ msr.lo |= (1 << 2);
+ if (regs.ecx & CPUID_SMX)
+ msr.lo |= (1 << 1);
+ }
+
+ wrmsr(IA32_FEATURE_CONTROL, msr);
+}
+
+/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
+static const u8 power_limit_time_sec_to_msr[] = {
+ [0] = 0x00,
+ [1] = 0x0a,
+ [2] = 0x0b,
+ [3] = 0x4b,
+ [4] = 0x0c,
+ [5] = 0x2c,
+ [6] = 0x4c,
+ [7] = 0x6c,
+ [8] = 0x0d,
+ [10] = 0x2d,
+ [12] = 0x4d,
+ [14] = 0x6d,
+ [16] = 0x0e,
+ [20] = 0x2e,
+ [24] = 0x4e,
+ [28] = 0x6e,
+ [32] = 0x0f,
+ [40] = 0x2f,
+ [48] = 0x4f,
+ [56] = 0x6f,
+ [64] = 0x10,
+ [80] = 0x30,
+ [96] = 0x50,
+ [112] = 0x70,
+ [128] = 0x11,
+};
+
+/* Convert POWER_LIMIT_1_TIME MSR value to seconds */
+static const u8 power_limit_time_msr_to_sec[] = {
+ [0x00] = 0,
+ [0x0a] = 1,
+ [0x0b] = 2,
+ [0x4b] = 3,
+ [0x0c] = 4,
+ [0x2c] = 5,
+ [0x4c] = 6,
+ [0x6c] = 7,
+ [0x0d] = 8,
+ [0x2d] = 10,
+ [0x4d] = 12,
+ [0x6d] = 14,
+ [0x0e] = 16,
+ [0x2e] = 20,
+ [0x4e] = 24,
+ [0x6e] = 28,
+ [0x0f] = 32,
+ [0x2f] = 40,
+ [0x4f] = 48,
+ [0x6f] = 56,
+ [0x10] = 64,
+ [0x30] = 80,
+ [0x50] = 96,
+ [0x70] = 112,
+ [0x11] = 128,
+};
+
+int cpu_config_tdp_levels(void)
+{
+ msr_t platform_info;
+
+ /* Minimum CPU revision */
+ if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
+ return 0;
+
+ /* Bits 34:33 indicate how many levels supported */
+ platform_info = rdmsr(MSR_PLATFORM_INFO);
+ return (platform_info.hi >> 1) & 3;
+}
+
+/*
+ * Configure processor power limits if possible
+ * This must be done AFTER set of BIOS_RESET_CPL
+ */
+void set_power_limits(u8 power_limit_1_time)
+{
+ msr_t msr = rdmsr(MSR_PLATFORM_INFO);
+ msr_t limit;
+ unsigned power_unit;
+ unsigned tdp, min_power, max_power, max_time;
+ u8 power_limit_1_val;
+
+ if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr))
+ return;
+
+ if (!(msr.lo & PLATFORM_INFO_SET_TDP))
+ return;
+
+ /* Get units */
+ msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
+ power_unit = 2 << ((msr.lo & 0xf) - 1);
+
+ /* Get power defaults for this SKU */
+ msr = rdmsr(MSR_PKG_POWER_SKU);
+ tdp = msr.lo & 0x7fff;
+ min_power = (msr.lo >> 16) & 0x7fff;
+ max_power = msr.hi & 0x7fff;
+ max_time = (msr.hi >> 16) & 0x7f;
+
+ printk(BIOS_DEBUG, "CPU TDP: %u Watts\n", tdp / power_unit);
+
+ if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time)
+ power_limit_1_time = power_limit_time_msr_to_sec[max_time];
+
+ if (min_power > 0 && tdp < min_power)
+ tdp = min_power;
+
+ if (max_power > 0 && tdp > max_power)
+ tdp = max_power;
+
+ power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time];
+
+ /* Set long term power limit to TDP */
+ limit.lo = 0;
+ limit.lo |= tdp & PKG_POWER_LIMIT_MASK;
+ limit.lo |= PKG_POWER_LIMIT_EN;
+ limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) <<
+ PKG_POWER_LIMIT_TIME_SHIFT;
+
+ /* Set short term power limit to 1.25 * TDP */
+ limit.hi = 0;
+ limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK;
+ limit.hi |= PKG_POWER_LIMIT_EN;
+ /* Power limit 2 time is only programmable on SNB EP/EX */
+
+ wrmsr(MSR_PKG_POWER_LIMIT, limit);
+
+ /* Use nominal TDP values for CPUs with configurable TDP */
+ if (cpu_config_tdp_levels()) {
+ msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
+ limit.hi = 0;
+ limit.lo = msr.lo & 0xff;
+ wrmsr(MSR_TURBO_ACTIVATION_RATIO, limit);
+ }
+}
+
+static void configure_misc(void)
+{
+ msr_t msr;
+
+ msr = rdmsr(IA32_MISC_ENABLE);
+ msr.lo |= (1 << 0); /* Fast String enable */
+ msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */
+ msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */
+ wrmsr(IA32_MISC_ENABLE, msr);
+
+ /* Disable Thermal interrupts */
+ msr.lo = 0;
+ msr.hi = 0;
+ wrmsr(IA32_THERM_INTERRUPT, msr);
+
+ /* Enable package critical interrupt only */
+ msr.lo = 1 << 4;
+ msr.hi = 0;
+ wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
+}
+
+static void enable_lapic_tpr(void)
+{
+ msr_t msr;
+
+ msr = rdmsr(MSR_PIC_MSG_CONTROL);
+ msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
+ wrmsr(MSR_PIC_MSG_CONTROL, msr);
+}
+
+static void configure_dca_cap(void)
+{
+ struct cpuid_result cpuid_regs;
+ msr_t msr;
+
+ /* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */
+ cpuid_regs = cpuid(1);
+ if (cpuid_regs.ecx & (1 << 18)) {
+ msr = rdmsr(IA32_PLATFORM_DCA_CAP);
+ msr.lo |= 1;
+ wrmsr(IA32_PLATFORM_DCA_CAP, msr);
+ }
+}
+
+static void set_max_ratio(void)
+{
+ msr_t msr, perf_ctl;
+
+ perf_ctl.hi = 0;
+
+ /* Check for configurable TDP option */
+ if (cpu_config_tdp_levels()) {
+ /* Set to nominal TDP ratio */
+ msr = rdmsr(MSR_CONFIG_TDP_NOMINAL);
+ perf_ctl.lo = (msr.lo & 0xff) << 8;
+ } else {
+ /* Platform Info bits 15:8 give max ratio */
+ msr = rdmsr(MSR_PLATFORM_INFO);
+ perf_ctl.lo = msr.lo & 0xff00;
+ }
+ wrmsr(IA32_PERF_CTL, perf_ctl);
+
+ printk(BIOS_DEBUG, "model_x06ax: frequency set to %d\n",
+ ((perf_ctl.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK);
+}
+
+static void configure_mca(void)
+{
+ msr_t msr;
+ int i;
+
+ msr.lo = msr.hi = 0;
+ /* This should only be done on a cold boot */
+ for (i = 0; i < 7; i++)
+ wrmsr(IA32_MC0_STATUS + (i * 4), msr);
+}
+
+#if CONFIG_USBDEBUG
+static unsigned ehci_debug_addr;
+#endif
+
+/*
+ * Initialize any extra cores/threads in this package.
+ */
+static void intel_cores_init(device_t cpu)
+{
+ struct cpuid_result result;
+ unsigned threads_per_package, threads_per_core, i;
+
+ /* Logical processors (threads) per core */
+ result = cpuid_ext(0xb, 0);
+ threads_per_core = result.ebx & 0xffff;
+
+ /* Logical processors (threads) per package */
+ result = cpuid_ext(0xb, 1);
+ threads_per_package = result.ebx & 0xffff;
+
+ /* Only initialize extra cores from BSP */
+ if (cpu->path.apic.apic_id)
+ return;
+
+ printk(BIOS_DEBUG, "CPU: %u has %u cores, %u threads per core\n",
+ cpu->path.apic.apic_id, threads_per_package/threads_per_core,
+ threads_per_core);
+
+ for (i = 1; i < threads_per_package; ++i) {
+ struct device_path cpu_path;
+ device_t new;
+
+ /* Build the cpu device path */
+ cpu_path.type = DEVICE_PATH_APIC;
+ cpu_path.apic.apic_id =
+ cpu->path.apic.apic_id + i;
+
+ /* Update APIC ID if no hyperthreading */
+ if (threads_per_core == 1)
+ cpu_path.apic.apic_id <<= 1;
+
+ /* Allocate the new cpu device structure */
+ new = alloc_dev(cpu->bus, &cpu_path);
+ if (!new)
+ continue;
+
+ printk(BIOS_DEBUG, "CPU: %u has core %u\n",
+ cpu->path.apic.apic_id,
+ new->path.apic.apic_id);
+
+#if CONFIG_SMP && CONFIG_MAX_CPUS > 1
+ /* Start the new cpu */
+ if (!start_cpu(new)) {
+ /* Record the error in cpu? */
+ printk(BIOS_ERR, "CPU %u would not start!\n",
+ new->path.apic.apic_id);
+ }
+#endif
+ }
+}
+
+static void model_206ax_init(device_t cpu)
+{
+ char processor_name[49];
+ struct cpuid_result cpuid_regs;
+
+ /* Turn on caching if we haven't already */
+ x86_enable_cache();
+
+ /* Clear out pending MCEs */
+ configure_mca();
+
+ /* Print processor name */
+ fill_processor_name(processor_name);
+ printk(BIOS_INFO, "CPU: %s.\n", processor_name);
+
+#if CONFIG_USBDEBUG
+ // Is this caution really needed?
+ if(!ehci_debug_addr)
+ ehci_debug_addr = get_ehci_debug();
+ set_ehci_debug(0);
+#endif
+
+ /* Setup MTRRs based on physical address size */
+ cpuid_regs = cpuid(0x80000008);
+ x86_setup_fixed_mtrrs();
+ x86_setup_var_mtrrs(cpuid_regs.eax & 0xff, 2);
+ x86_mtrr_check();
+
+ /* Setup Page Attribute Tables (PAT) */
+ // TODO set up PAT
+
+#if CONFIG_USBDEBUG
+ set_ehci_debug(ehci_debug_addr);
+#endif
+
+ /* Enable the local cpu apics */
+ enable_lapic_tpr();
+ setup_lapic();
+
+ /* Enable virtualization if enabled in CMOS */
+ enable_vmx();
+
+ /* Configure Enhanced SpeedStep and Thermal Sensors */
+ configure_misc();
+
+ /* Enable Direct Cache Access */
+ configure_dca_cap();
+
+ /* Set Max Ratio */
+ set_max_ratio();
+
+ /* Enable Turbo */
+ enable_turbo();
+
+ /* Start up extra cores */
+ intel_cores_init(cpu);
+}
+
+static struct device_operations cpu_dev_ops = {
+ .init = model_206ax_init,
+};
+
+static struct cpu_device_id cpu_table[] = {
+ { X86_VENDOR_INTEL, 0x206a0 }, /* Intel Sandybridge */
+ { X86_VENDOR_INTEL, 0x206a6 }, /* Intel Sandybridge D1 */
+ { X86_VENDOR_INTEL, 0x206a7 }, /* Intel Sandybridge D2/J1 */
+ { X86_VENDOR_INTEL, 0x306a0 }, /* Intel IvyBridge */
+ { X86_VENDOR_INTEL, 0x306a2 }, /* Intel IvyBridge */
+ { X86_VENDOR_INTEL, 0x306a4 }, /* Intel IvyBridge */
+ { X86_VENDOR_INTEL, 0x306a5 }, /* Intel IvyBridge */
+ { X86_VENDOR_INTEL, 0x306a6 }, /* Intel IvyBridge */
+ { X86_VENDOR_INTEL, 0x306a8 }, /* Intel IvyBridge */
+ { X86_VENDOR_INTEL, 0x306a9 }, /* Intel IvyBridge */
+ { 0, 0 },
+};
+
+static const struct cpu_driver driver __cpu_driver = {
+ .ops = &cpu_dev_ops,
+ .id_table = cpu_table,
+};
+
Marc Jones (marc.jones(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4020
-gerrit
commit 42623a28ceac0a5624b08c86254bc1c8d52bb2ae
Author: Marc Jones <marc.jones(a)se-eng.com>
Date: Tue Oct 29 22:23:11 2013 -0600
Save memory space for FSP above CBMEM
The FSP uses the top of memory for itself. Move CBMEM down
below the FSP memory. This memory can be used by the OS or
payload after coreboot is finished.
Change-Id: I9d3c33397c118095d96fd42531f28e722ec0f491
Signed-off-by: Marc Jones <marc.jones(a)se-eng.com>
---
src/arch/x86/boot/cbmem.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/arch/x86/boot/cbmem.c b/src/arch/x86/boot/cbmem.c
index bdc695c..fbb513f 100644
--- a/src/arch/x86/boot/cbmem.c
+++ b/src/arch/x86/boot/cbmem.c
@@ -24,7 +24,12 @@ void get_cbmem_table(uint64_t *base, uint64_t *size)
uint64_t top_of_ram = get_top_of_ram();
if (top_of_ram >= HIGH_MEMORY_SIZE) {
+#if CONFIG_HAVE_FSP_BIN
+ /* The FSP uses space for HOB and other stuff. Don't overwrite it */
+ *base = top_of_ram - HIGH_MEMORY_SIZE - 0x200000; /* 2MB for FSP HOB */
+#else
*base = top_of_ram - HIGH_MEMORY_SIZE;
+#endif
*size = HIGH_MEMORY_SIZE;
} else {
*base = 0;
@@ -45,7 +50,12 @@ void __attribute__((weak)) backup_top_of_ram(uint64_t ramtop)
void set_top_of_ram(uint64_t ramtop)
{
backup_top_of_ram(ramtop);
+#if CONFIG_HAVE_FSP_BIN
+ /* The FSP uses space for HOB and other stuff. Don't overwrite it */
+ cbmem_late_set_table(ramtop - HIGH_MEMORY_SIZE - 0x200000, HIGH_MEMORY_SIZE); /* 2MB for FSP HOB */
+#else
cbmem_late_set_table(ramtop - HIGH_MEMORY_SIZE, HIGH_MEMORY_SIZE);
+#endif
}
unsigned long __attribute__((weak)) get_top_of_ram(void)
Denis Carikli (GNUtoo(a)no-log.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3991
-gerrit
commit 32b567f6e3e584fc47b494d13f4dde23bce2dbe7
Author: Denis 'GNUtoo' Carikli <GNUtoo(a)no-log.org>
Date: Sun Oct 20 23:37:35 2013 +0200
lenovo/x60: Require only one failed boot to switch to fallback in X86_BOOTBLOCK_NORMAL mode.
src/arch/x86/Kconfig defines MAX_REBOOT_CNT as 3.
If that value is not overrided, then the Lenovo X60 coreboot image gets it too.
At the end of a successfull boot, with CONFIG_KEEP_BOOT_COUNT,
the Lenovo X60 increments its reboot_bits cmos option by one.
In case of a failed boot, the user probably doesn't know that coreboot will
only switch to fallback after 3 failed boots, and will act as if the laptop
will not boot anymore with its current coreboot image.
Change-Id: I746df11c933dfe62e01e1591479ca96a84907dc0
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo(a)no-log.org>
---
src/mainboard/lenovo/x60/Kconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/mainboard/lenovo/x60/Kconfig b/src/mainboard/lenovo/x60/Kconfig
index 72aeef8..90d472c 100644
--- a/src/mainboard/lenovo/x60/Kconfig
+++ b/src/mainboard/lenovo/x60/Kconfig
@@ -54,6 +54,10 @@ config MAX_CPUS
int
default 2
+config MAX_REBOOT_CNT
+ int
+ default 1
+
config MAINBOARD_SMBIOS_MANUFACTURER
string
default "LENOVO"
Denis Carikli (GNUtoo(a)no-log.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3990
-gerrit
commit a258325ee3703fd17749fab9e8237b313c79ac10
Author: Denis 'GNUtoo' Carikli <GNUtoo(a)no-log.org>
Date: Mon Oct 21 01:56:47 2013 +0200
Add a KEEP_BOOT_COUNT Kconfig option.
The use case of that option is to inform coreboot (trough the nvram) at the
next boot, that the computer could not fully boot to boot to an usable state.
In that case, the boot count is incremented by one.
Previously there was no way to tell coreboot that the computer really booted
successfully, because it was assumed that if set_boot_successful was called
in ramstage, then the computer would have booted successfully.
However many things can go wrong after that point, for instance the payload
could fail to boot, or the operating system's kernel could fail to boot too,
due to the wrong configurations passed to it by coreboot and the payload.
Change-Id: I01af053455eb6bd2f7a4f9d37e8c234ba8d55250
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo(a)no-log.org>
---
src/arch/x86/Kconfig | 8 ++++++++
src/lib/fallback_boot.c | 10 ++++++++++
2 files changed, 18 insertions(+)
diff --git a/src/arch/x86/Kconfig b/src/arch/x86/Kconfig
index 0a21fcc..b4e8eb0 100644
--- a/src/arch/x86/Kconfig
+++ b/src/arch/x86/Kconfig
@@ -72,6 +72,14 @@ config X86_BOOTBLOCK_NORMAL
endchoice
+config KEEP_BOOT_COUNT
+ bool "Keep boot count"
+ default n
+ depends on PC80_SYSTEM && X86_BOOTBLOCK_NORMAL
+ help
+ If enabled, the boot count is not reset anymore in the ramstage.
+ This delegates that task to the software running after the ramstage.
+
config BOOTBLOCK_SOURCE
string
default "bootblock_simple.c" if X86_BOOTBLOCK_SIMPLE
diff --git a/src/lib/fallback_boot.c b/src/lib/fallback_boot.c
index 0c49d5c..994dd0a 100644
--- a/src/lib/fallback_boot.c
+++ b/src/lib/fallback_boot.c
@@ -1,6 +1,8 @@
#include <console/console.h>
#include <fallback.h>
+#include <string.h>
#include <watchdog.h>
+#include <arch/acpi.h>
#include <arch/io.h>
void boot_successful(void)
@@ -10,8 +12,16 @@ void boot_successful(void)
vbe_textmode_console();
#endif
+
+#if CONFIG_KEEP_BOOT_COUNT
+ /* we don't want to resume with the wrong prefix next time */
+ if (acpi_slp_type == 3 &&
+ strncmp(CONFIG_CBFS_PREFIX, "fallback", sizeof("fallback")))
+ set_boot_successful();
+#else
/* Remember this was a successful boot */
set_boot_successful();
+#endif
/* turn off the boot watchdog */
watchdog_off();
Paul Menzel (paulepanter(a)users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4012
-gerrit
commit bca72ea7949633361e4f32ad6b47e1a82d9c97c2
Author: Marc Jones <marc.jones(a)se-eng.com>
Date: Tue Oct 29 17:32:00 2013 -0600
Add new finalize functions for devices and chips
Many chipset devices require additional configuration after
device init. It is not uncommmon for a device early in the devicetree
list to need to change a setting after a device later in the tree does
PCI init. A final function call has been added to device ops to handle
this case. It is called prior to coreboot table setup.
Another problem that is often seen is that the chipset or mainboard
need to do some final cleanup just before loading the OS. The chip
finalize has been added for this case. It is call after all coreboot
tables are setup and the payload is ready to be called.
Similar functionality could be implemented with the hardwaremain
states, but those don't fit well in the device tree function pointer
structure and should be used sparingly.
Change-Id: Ib37cce104ae41ec225a8502942d85e54d99ea75f
Signed-off-by: Marc Jones <marc.jones(a)se-eng.com>
---
src/device/device.c | 76 +++++++++++++++++++++++++++++++++++++++++++++
src/include/device/device.h | 5 +++
src/lib/hardwaremain.c | 3 ++
3 files changed, 84 insertions(+)
diff --git a/src/device/device.c b/src/device/device.c
index 3837928..91cb4fa 100644
--- a/src/device/device.c
+++ b/src/device/device.c
@@ -72,6 +72,26 @@ void dev_initialize_chips(void)
}
}
+/**
+ * Finalize all chips of statically known devices.
+ *
+ * This is the last call before calling the payload. This is a good place
+ * to lock registers or other final cleanup.
+ */
+void dev_finalize_chips(void)
+{
+ struct device *dev;
+
+ for (dev = all_devices; dev; dev = dev->next) {
+ /* Initialize chip if we haven't yet. */
+ if (dev->chip_ops && dev->chip_ops->final &&
+ !dev->chip_ops->finalized) {
+ dev->chip_ops->final(dev->chip_info);
+ dev->chip_ops->finalized = 1;
+ }
+ }
+}
+
DECLARE_SPIN_LOCK(dev_lock)
#if CONFIG_GFXUMA
@@ -1167,3 +1187,59 @@ void dev_initialize(void)
printk(BIOS_INFO, "Devices initialized\n");
show_all_devs(BIOS_SPEW, "After init.");
}
+
+/**
+ * Finalize a specific device.
+ *
+ * The parent should be finalized first to avoid having an ordering problem.
+ * This is done by calling the parent's final() method before its childrens'
+ * final() methods.
+ *
+ * @param dev The device to be initialized.
+ */
+static void final_dev(struct device *dev)
+{
+ if (!dev->enabled)
+ return;
+
+ if (dev->ops && dev->ops->final) {
+ printk(BIOS_DEBUG, "%s final\n", dev_path(dev));
+ dev->ops->final(dev);
+ }
+}
+
+static void final_link(struct bus *link)
+{
+ struct device *dev;
+ struct bus *c_link;
+
+ for (dev = link->children; dev; dev = dev->sibling)
+ final_dev(dev);
+
+ for (dev = link->children; dev; dev = dev->sibling) {
+ for (c_link = dev->link_list; c_link; c_link = c_link->next)
+ final_link(c_link);
+ }
+}
+/**
+ * Finalize all devices in the global device tree.
+ *
+ * Starting at the root device, call the device's final() method to do
+ * device-specific cleanup, then call each child's final() method.
+ */
+void dev_finalize(void)
+{
+ struct bus *link;
+
+ printk(BIOS_INFO, "Finalize devices...\n");
+
+ /* First call the mainboard finalize. */
+ final_dev(&dev_root);
+
+ /* Now finalize everything. */
+ for (link = dev_root.link_list; link; link = link->next)
+ final_link(link);
+
+ printk(BIOS_INFO, "Devices finalized\n");
+ show_all_devs(BIOS_SPEW, "After finalize.");
+}
diff --git a/src/include/device/device.h b/src/include/device/device.h
index c0e6e0f..fec0497 100644
--- a/src/include/device/device.h
+++ b/src/include/device/device.h
@@ -22,7 +22,9 @@ struct pnp_mode_ops;
struct chip_operations {
void (*enable_dev)(struct device *dev);
void (*init)(void *chip_info);
+ void (*final)(void *chip_info);
unsigned int initialized : 1;
+ unsigned int finalized : 1;
const char *name;
};
@@ -35,6 +37,7 @@ struct device_operations {
void (*set_resources)(device_t dev);
void (*enable_resources)(device_t dev);
void (*init)(device_t dev);
+ void (*final)(device_t dev);
unsigned int (*scan_bus)(device_t bus, unsigned int max);
void (*enable)(device_t dev);
void (*disable)(device_t dev);
@@ -140,6 +143,8 @@ void dev_configure(void);
void dev_enable(void);
void dev_initialize(void);
void dev_optimize(void);
+void dev_finalize(void);
+void dev_finalize_chips(void);
/* Generic device helper functions */
int reset_bus(struct bus *bus);
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index a5993c4..501591f 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -175,6 +175,7 @@ static boot_state_t bs_dev_init(void *arg)
static boot_state_t bs_post_device(void *arg)
{
+ dev_finalize();
timestamp_add_now(TS_DEVICE_DONE);
timestamp_reinit();
@@ -217,6 +218,8 @@ static boot_state_t bs_write_tables(void *arg)
*/
write_tables();
+ dev_finalize_chips();
+
return BS_PAYLOAD_LOAD;
}
Marc Jones (marc.jones(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4020
-gerrit
commit 20e6b3a867f401e18d891ad9893e36dbe85babe3
Author: Marc Jones <marc.jones(a)se-eng.com>
Date: Tue Oct 29 22:23:11 2013 -0600
Save memory space for FSP above CBMEM
The FSP uses the top of memory for itself. Move CBMEM down
below the FSP memory. This memory can be used by the OS or
payload after coreboot is finished.
Change-Id: I9d3c33397c118095d96fd42531f28e722ec0f491
Signed-off-by: Marc Jones <marc.jones(a)se-eng.com>
---
src/arch/x86/boot/cbmem.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/arch/x86/boot/cbmem.c b/src/arch/x86/boot/cbmem.c
index bdc695c..fbb513f 100644
--- a/src/arch/x86/boot/cbmem.c
+++ b/src/arch/x86/boot/cbmem.c
@@ -24,7 +24,12 @@ void get_cbmem_table(uint64_t *base, uint64_t *size)
uint64_t top_of_ram = get_top_of_ram();
if (top_of_ram >= HIGH_MEMORY_SIZE) {
+#if CONFIG_HAVE_FSP_BIN
+ /* The FSP uses space for HOB and other stuff. Don't overwrite it */
+ *base = top_of_ram - HIGH_MEMORY_SIZE - 0x200000; /* 2MB for FSP HOB */
+#else
*base = top_of_ram - HIGH_MEMORY_SIZE;
+#endif
*size = HIGH_MEMORY_SIZE;
} else {
*base = 0;
@@ -45,7 +50,12 @@ void __attribute__((weak)) backup_top_of_ram(uint64_t ramtop)
void set_top_of_ram(uint64_t ramtop)
{
backup_top_of_ram(ramtop);
+#if CONFIG_HAVE_FSP_BIN
+ /* The FSP uses space for HOB and other stuff. Don't overwrite it */
+ cbmem_late_set_table(ramtop - HIGH_MEMORY_SIZE - 0x200000, HIGH_MEMORY_SIZE); /* 2MB for FSP HOB */
+#else
cbmem_late_set_table(ramtop - HIGH_MEMORY_SIZE, HIGH_MEMORY_SIZE);
+#endif
}
unsigned long __attribute__((weak)) get_top_of_ram(void)