Add the Intel FSP 206ax CPU core support

Add support for 206ax using the Intel FSP.
The FSP is different enough to warrant its own source files
for now. It has different CAR code, micorcode, and FSP inclusion.
It may be possible to combine this code with the mrc based
solution used by the chromebooks in the future.

Change-Id: I5105631af34e9c3a804ace908c4205f073abb9b4
Signed-off-by: Marc Jones <marc.jones@se-eng.com>
Reviewed-on: http://review.coreboot.org/4016
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Marc Jones 2013-10-29 17:46:54 -06:00
parent 54b8e7a0bb
commit bdafcfa555
16 changed files with 1653 additions and 3 deletions

View File

@ -77,10 +77,32 @@ config CPU_MICROCODE_IN_CBFS
bool bool
default n 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 choice
prompt "Include CPU microcode in CBFS" if ARCH_X86 prompt "Include CPU microcode in CBFS" if ARCH_X86
default CPU_MICROCODE_CBFS_GENERATE if CPU_MICROCODE_IN_CBFS default CPU_MICROCODE_CBFS_GENERATE if CPU_MICROCODE_IN_CBFS && BOARD_MICROCODE_CBFS_GENERATE
default CPU_MICROCODE_CBFS_NONE if !CPU_MICROCODE_IN_CBFS default CPU_MICROCODE_CBFS_EXTERNAL if CPU_MICROCODE_IN_CBFS && BOARD_MICROCODE_CBFS_EXTERNAL
default CPU_MICROCODE_CBFS_NONE
config CPU_MICROCODE_CBFS_GENERATE config CPU_MICROCODE_CBFS_GENERATE
bool "Generate from tree" bool "Generate from tree"
@ -158,3 +180,16 @@ config CPU_MICROCODE_FILE
default "cpu_microcode.bin" default "cpu_microcode.bin"
help help
The path and filename of the file containing the CPU microcode. 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.

View File

@ -28,6 +28,12 @@ cpu_ucode_cbfs_file = $(obj)/cpu_microcode_blob.bin
cbfs_include_ucode = y cbfs_include_ucode = y
endif 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 # 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 # 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. # 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) ifeq ($(cbfs_include_ucode),y)
# Add CPU microcode to specified rom image $(1) # Add CPU microcode to specified rom image $(1)
add-cpu-microcode-to-cbfs = \ 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 else
add-cpu-microcode-to-cbfs = true add-cpu-microcode-to-cbfs = true
endif endif

View File

@ -10,6 +10,7 @@ source src/cpu/intel/model_6fx/Kconfig
source src/cpu/intel/model_1067x/Kconfig source src/cpu/intel/model_1067x/Kconfig
source src/cpu/intel/model_106cx/Kconfig source src/cpu/intel/model_106cx/Kconfig
source src/cpu/intel/model_206ax/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_2065x/Kconfig
source src/cpu/intel/model_f0x/Kconfig source src/cpu/intel/model_f0x/Kconfig
source src/cpu/intel/model_f1x/Kconfig source src/cpu/intel/model_f1x/Kconfig

View File

@ -19,6 +19,8 @@ subdirs-$(CONFIG_NORTHBRIDGE_INTEL_NEHALEM) += model_2065x
subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_SANDYBRIDGE) += model_206ax
subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += model_206ax subdirs-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += model_206ax
subdirs-$(CONFIG_NORTHBRIDGE_INTEL_HASWELL) += haswell 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_2) += slot_2
subdirs-$(CONFIG_CPU_INTEL_SLOT_1) += slot_1 subdirs-$(CONFIG_CPU_INTEL_SLOT_1) += slot_1
subdirs-$(CONFIG_CPU_INTEL_SOCKET_LGA771) += socket_LGA771 subdirs-$(CONFIG_CPU_INTEL_SOCKET_LGA771) += socket_LGA771

View File

@ -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

View File

@ -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)

View File

@ -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")
};

View File

@ -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})
}
}

View File

@ -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 <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 bootblock_cpu_init(void)
{
}

View File

@ -0,0 +1,292 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2000,2007 Ronald G. Minnich <rminnich@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)
/* 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:

View File

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

View File

@ -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);
}

View File

@ -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
};

View File

@ -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

View File

@ -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

View File

@ -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,
};