From f5fbbe95798dba8f1536892598afbf33b5c07b5f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 12 Nov 2014 22:42:19 -0700 Subject: 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 --- arch/x86/cpu/ivybridge/cpu.c | 130 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) (limited to 'arch/x86/cpu') 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 #include #include +#include +#include +#include #include #include #include +#include #include 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, ®8); + 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; } -- cgit v1.1