diff --git a/src/cpu/Kconfig b/src/cpu/Kconfig index e48fe877e0..46b6f1c765 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 a860f67752..34ae53ecef 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 2bafa498c3..6f4f561bf2 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 54624fb8c7..964369ddd3 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 0000000000..406f8a5c95 --- /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 0000000000..1ea9c2aa49 --- /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 0000000000..47e651f2ee --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 0000000000..558a9d3663 --- /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 0000000000..e57217132d --- /dev/null +++ b/src/cpu/intel/fsp_model_206ax/bootblock.c @@ -0,0 +1,31 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "model_206ax.h" + +static void bootblock_cpu_init(void) +{ +} 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 0000000000..a8d7cc54cb --- /dev/null +++ b/src/cpu/intel/fsp_model_206ax/cache_as_ram.inc @@ -0,0 +1,292 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2000,2007 Ronald G. Minnich + * 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 +#include +#include +#include +#include + +#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) + + /* 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: + 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 0000000000..afa5774fa4 --- /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 0000000000..4ed5d1e5f8 --- /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 +#include +#include +#include +#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 0000000000..8bd790ade4 --- /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 0000000000..e56bef17a6 --- /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 +#endif + +#if IS_ENABLED(CONFIG_CPU_INTEL_FSP_MODEL_306AX) + /* Size is 0xC000 - Update in Kconfigs when any included file changes*/ + #include + #include + #include + #include + #include +#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 0000000000..a7ca04a690 --- /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 0000000000..6eb4787353 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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, +}; +