summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2014-11-13 05:42:19 (GMT)
committerSimon Glass <sjg@chromium.org>2014-11-21 06:34:13 (GMT)
commitf5fbbe95798dba8f1536892598afbf33b5c07b5f (patch)
treece333098bc5a1049a82093450deb9fe55df3ed44 /arch
parenteddbad224b9e0e6834f946f587923f27e54abb69 (diff)
downloadu-boot-f5fbbe95798dba8f1536892598afbf33b5c07b5f.tar.xz
x86: ivybridge: Perform initial CPU setup
Set up the flex ratio (controls speed versus heat output) and a few other very early things. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/cpu/ivybridge/cpu.c130
-rw-r--r--arch/x86/include/asm/arch-ivybridge/model_206ax.h82
-rw-r--r--arch/x86/include/asm/arch-ivybridge/pch.h60
-rw-r--r--arch/x86/include/asm/processor.h2
4 files changed, 274 insertions, 0 deletions
diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c
index 5d7640b..ab708dd 100644
--- a/arch/x86/cpu/ivybridge/cpu.c
+++ b/arch/x86/cpu/ivybridge/cpu.c
@@ -14,13 +14,123 @@
#include <errno.h>
#include <fdtdec.h>
#include <asm/cpu.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/mtrr.h>
#include <asm/pci.h>
#include <asm/post.h>
#include <asm/processor.h>
+#include <asm/arch/model_206ax.h>
#include <asm/arch/pch.h>
DECLARE_GLOBAL_DATA_PTR;
+static void enable_port80_on_lpc(struct pci_controller *hose, pci_dev_t dev)
+{
+ /* Enable port 80 POST on LPC */
+ pci_hose_write_config_dword(hose, dev, PCH_RCBA_BASE, DEFAULT_RCBA | 1);
+ clrbits_le32(RCB_REG(GCS), 4);
+}
+
+/*
+ * Enable Prefetching and Caching.
+ */
+static void enable_spi_prefetch(struct pci_controller *hose, pci_dev_t dev)
+{
+ u8 reg8;
+
+ pci_hose_read_config_byte(hose, dev, 0xdc, &reg8);
+ reg8 &= ~(3 << 2);
+ reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
+ pci_hose_write_config_byte(hose, dev, 0xdc, reg8);
+}
+
+static void set_var_mtrr(
+ unsigned reg, unsigned base, unsigned size, unsigned type)
+
+{
+ /* Bit Bit 32-35 of MTRRphysMask should be set to 1 */
+ /* FIXME: It only support 4G less range */
+ wrmsr(MTRRphysBase_MSR(reg), base | type, 0);
+ wrmsr(MTRRphysMask_MSR(reg), ~(size - 1) | MTRRphysMaskValid,
+ (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1);
+}
+
+static void enable_rom_caching(void)
+{
+ disable_caches();
+ set_var_mtrr(1, 0xffc00000, 4 << 20, MTRR_TYPE_WRPROT);
+ enable_caches();
+
+ /* Enable Variable MTRRs */
+ wrmsr(MTRRdefType_MSR, 0x800, 0);
+}
+
+static int set_flex_ratio_to_tdp_nominal(void)
+{
+ msr_t flex_ratio, msr;
+ u8 nominal_ratio;
+
+ /* Minimum CPU revision for configurable TDP support */
+ if (cpuid_eax(1) < IVB_CONFIG_TDP_MIN_CPUID)
+ return -EINVAL;
+
+ /* Check for Flex Ratio support */
+ flex_ratio = msr_read(MSR_FLEX_RATIO);
+ if (!(flex_ratio.lo & FLEX_RATIO_EN))
+ return -EINVAL;
+
+ /* Check for >0 configurable TDPs */
+ msr = msr_read(MSR_PLATFORM_INFO);
+ if (((msr.hi >> 1) & 3) == 0)
+ return -EINVAL;
+
+ /* Use nominal TDP ratio for flex ratio */
+ msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
+ nominal_ratio = msr.lo & 0xff;
+
+ /* See if flex ratio is already set to nominal TDP ratio */
+ if (((flex_ratio.lo >> 8) & 0xff) == nominal_ratio)
+ return 0;
+
+ /* Set flex ratio to nominal TDP ratio */
+ flex_ratio.lo &= ~0xff00;
+ flex_ratio.lo |= nominal_ratio << 8;
+ flex_ratio.lo |= FLEX_RATIO_LOCK;
+ msr_write(MSR_FLEX_RATIO, flex_ratio);
+
+ /* Set flex ratio in soft reset data register bits 11:6 */
+ clrsetbits_le32(RCB_REG(SOFT_RESET_DATA), 0x3f << 6,
+ (nominal_ratio & 0x3f) << 6);
+
+ /* Set soft reset control to use register value */
+ setbits_le32(RCB_REG(SOFT_RESET_CTRL), 1);
+
+ /* Issue warm reset, will be "CPU only" due to soft reset data */
+ outb(0x0, PORT_RESET);
+ outb(0x6, PORT_RESET);
+ cpu_hlt();
+
+ /* Not reached */
+ return -EINVAL;
+}
+
+static void set_spi_speed(void)
+{
+ u32 fdod;
+
+ /* Observe SPI Descriptor Component Section 0 */
+ writel(0x1000, RCB_REG(SPI_DESC_COMP0));
+
+ /* Extract the1 Write/Erase SPI Frequency from descriptor */
+ fdod = readl(RCB_REG(SPI_FREQ_WR_ERA));
+ fdod >>= 24;
+ fdod &= 7;
+
+ /* Set Software Sequence frequency to match */
+ clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod);
+}
+
int arch_cpu_init(void)
{
const void *blob = gd->fdt_blob;
@@ -46,6 +156,26 @@ int arch_cpu_init(void)
if (ret)
return ret;
+ enable_spi_prefetch(hose, PCH_LPC_DEV);
+
+ /* This is already done in start.S, but let's do it in C */
+ enable_port80_on_lpc(hose, PCH_LPC_DEV);
+
+ /* already done in car.S */
+ if (false)
+ enable_rom_caching();
+
+ set_spi_speed();
+
+ /*
+ * We should do as little as possible before the serial console is
+ * up. Perhaps this should move to later. Our next lot of init
+ * happens in print_cpuinfo() when we have a console
+ */
+ ret = set_flex_ratio_to_tdp_nominal();
+ if (ret)
+ return ret;
+
return 0;
}
diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h
new file mode 100644
index 0000000..8281d7a
--- /dev/null
+++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h
@@ -0,0 +1,82 @@
+/*
+ * From Coreboot file of the same name
+ *
+ * Copyright (C) 2011 The ChromiumOS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _ASM_ARCH_MODEL_206AX_H
+#define _ASM_ARCH_MODEL_206AX_H
+
+/* SandyBridge/IvyBridge bus clock is fixed at 100MHz */
+#define SANDYBRIDGE_BCLK 100
+
+#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 PLATFORM_INFO_SET_TDP (1 << 29)
+
+#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 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 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
+
+#endif
diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h
index 26ddeab..c572f76 100644
--- a/arch/x86/include/asm/arch-ivybridge/pch.h
+++ b/arch/x86/include/asm/arch-ivybridge/pch.h
@@ -35,6 +35,66 @@
#define LPC_GEN4_DEC 0x90 /* LPC IF Generic Decode Range 4 */
#define LPC_GENX_DEC(x) (0x84 + 4 * (x))
+#define DEFAULT_RCBA 0xfed1c000
+
+/* Root Complex Register Block */
+#define RCB_REG(reg) (DEFAULT_RCBA + (reg))
+
+#define PCH_RCBA_BASE 0xf0
+
+#define VCH 0x0000 /* 32bit */
+#define VCAP1 0x0004 /* 32bit */
+#define VCAP2 0x0008 /* 32bit */
+#define PVC 0x000c /* 16bit */
+#define PVS 0x000e /* 16bit */
+
+#define V0CAP 0x0010 /* 32bit */
+#define V0CTL 0x0014 /* 32bit */
+#define V0STS 0x001a /* 16bit */
+
+#define V1CAP 0x001c /* 32bit */
+#define V1CTL 0x0020 /* 32bit */
+#define V1STS 0x0026 /* 16bit */
+
+#define RCTCL 0x0100 /* 32bit */
+#define ESD 0x0104 /* 32bit */
+#define ULD 0x0110 /* 32bit */
+#define ULBA 0x0118 /* 64bit */
+
+#define RP1D 0x0120 /* 32bit */
+#define RP1BA 0x0128 /* 64bit */
+#define RP2D 0x0130 /* 32bit */
+#define RP2BA 0x0138 /* 64bit */
+#define RP3D 0x0140 /* 32bit */
+#define RP3BA 0x0148 /* 64bit */
+#define RP4D 0x0150 /* 32bit */
+#define RP4BA 0x0158 /* 64bit */
+#define HDD 0x0160 /* 32bit */
+#define HDBA 0x0168 /* 64bit */
+#define RP5D 0x0170 /* 32bit */
+#define RP5BA 0x0178 /* 64bit */
+#define RP6D 0x0180 /* 32bit */
+#define RP6BA 0x0188 /* 64bit */
+
+#define RPC 0x0400 /* 32bit */
+#define RPFN 0x0404 /* 32bit */
+
+#define SPI_FREQ_SWSEQ 0x3893
+#define SPI_DESC_COMP0 0x38b0
+#define SPI_FREQ_WR_ERA 0x38b4
+#define SOFT_RESET_CTRL 0x38f4
+#define SOFT_RESET_DATA 0x38f8
+
+#define RC 0x3400 /* 32bit */
+#define HPTC 0x3404 /* 32bit */
+#define GCS 0x3410 /* 32bit */
+#define BUC 0x3414 /* 32bit */
+#define PCH_DISABLE_GBE (1 << 5)
+#define FD 0x3418 /* 32bit */
+#define DISPBDF 0x3424 /* 16bit */
+#define FD2 0x3428 /* 32bit */
+#define CG 0x341c /* 32bit */
+
/**
* lpc_early_init() - set up LPC serial ports and other early things
*
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index b2854a9..b9317cb 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -32,6 +32,8 @@ enum {
#ifndef __ASSEMBLY__
+#define PORT_RESET 0xcf9
+
static inline __attribute__((always_inline)) void cpu_hlt(void)
{
asm("hlt");