diff options
Diffstat (limited to 'arch/x86/cpu')
-rw-r--r-- | arch/x86/cpu/Makefile | 15 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/Makefile | 23 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/cpu.c | 676 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/cpu_from_spl.c | 63 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/cpu_full.c | 694 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/northbridge.c | 100 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/pch.c | 37 | ||||
-rw-r--r-- | arch/x86/cpu/broadwell/sdram.c | 136 | ||||
-rw-r--r-- | arch/x86/cpu/i386/cpu.c | 113 | ||||
-rw-r--r-- | arch/x86/cpu/intel_common/Makefile | 17 | ||||
-rw-r--r-- | arch/x86/cpu/intel_common/car.S | 2 | ||||
-rw-r--r-- | arch/x86/cpu/intel_common/cpu_from_spl.c | 27 | ||||
-rw-r--r-- | arch/x86/cpu/ivybridge/bd82x6x.c | 15 | ||||
-rw-r--r-- | arch/x86/cpu/mp_init.c | 10 | ||||
-rw-r--r-- | arch/x86/cpu/start.S | 13 | ||||
-rw-r--r-- | arch/x86/cpu/start64.S | 2 | ||||
-rw-r--r-- | arch/x86/cpu/start_from_spl.S | 71 | ||||
-rw-r--r-- | arch/x86/cpu/start_from_tpl.S | 49 | ||||
-rw-r--r-- | arch/x86/cpu/u-boot-spl.lds | 2 | ||||
-rw-r--r-- | arch/x86/cpu/x86_64/cpu.c | 5 |
20 files changed, 1223 insertions, 847 deletions
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 54668aab24..85fd5e616e 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -9,9 +9,22 @@ ifeq ($(CONFIG_$(SPL_)X86_64),y) extra-y = start64.o else +ifeq ($(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),y) extra-y = start.o +else +ifndef CONFIG_SPL +extra-y = start.o +else +ifdef CONFIG_SPL_BUILD +extra-y = start_from_tpl.o +else +extra-y = start_from_spl.o endif -extra-$(CONFIG_$(SPL_)X86_16BIT_INIT) += resetvec.o start16.o +endif +endif +endif + +extra-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += resetvec.o start16.o obj-y += cpu.o cpu_x86.o diff --git a/arch/x86/cpu/broadwell/Makefile b/arch/x86/cpu/broadwell/Makefile index d3785aabdf..52d56c65be 100644 --- a/arch/x86/cpu/broadwell/Makefile +++ b/arch/x86/cpu/broadwell/Makefile @@ -3,7 +3,24 @@ # Copyright (c) 2016 Google, Inc obj-y += adsp.o -obj-y += cpu.o +obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += cpu.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += cpu_full.o + +ifdef CONFIG_SPL +ifndef CONFIG_SPL_BUILD +obj-y += cpu_from_spl.o +obj-y += cpu_full.o +obj-y += refcode.o +endif +ifndef CONFIG_SPL_BUILD +# obj-y += cpu_from_spl.o +endif +endif + +ifeq ($(CONFIG_$(SPL_TPL_)X86_32BIT_INIT),) +#obj-y += cpu_from_spl.o +endif + obj-y += iobp.o obj-y += lpc.o obj-y += me.o @@ -11,6 +28,6 @@ obj-y += northbridge.o obj-y += pch.o obj-y += pinctrl_broadwell.o obj-y += power_state.o -obj-y += refcode.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += refcode.o obj-y += sata.o -obj-y += sdram.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += sdram.o diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 232fa40eb5..bb7c361408 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -12,75 +12,15 @@ #include <asm/cpu_x86.h> #include <asm/cpu_common.h> #include <asm/intel_regs.h> +#include <asm/lpc_common.h> #include <asm/msr.h> +#include <asm/pci.h> #include <asm/post.h> #include <asm/turbo.h> #include <asm/arch/cpu.h> #include <asm/arch/pch.h> #include <asm/arch/rcb.h> -struct cpu_broadwell_priv { - bool ht_disabled; -}; - -/* 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 arch_cpu_init_dm(void) { struct udevice *dev; @@ -156,613 +96,13 @@ int print_cpuinfo(void) return 0; } -/* - * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate - * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly - * when a core is woken up - */ -static int pcode_ready(void) -{ - int wait_count; - const int delay_step = 10; - - wait_count = 0; - do { - if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & - MAILBOX_RUN_BUSY)) - return 0; - wait_count += delay_step; - udelay(delay_step); - } while (wait_count < 1000); - - return -ETIMEDOUT; -} - -static u32 pcode_mailbox_read(u32 command) -{ - int ret; - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on wait ready\n"); - return ret; - } - - /* Send command and start transaction */ - writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on completion\n"); - return ret; - } - - /* Read mailbox */ - return readl(MCHBAR_REG(BIOS_MAILBOX_DATA)); -} - -static int pcode_mailbox_write(u32 command, u32 data) -{ - int ret; - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on wait ready\n"); - return ret; - } - - writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA)); - - /* Send command and start transaction */ - writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on completion\n"); - return ret; - } - - return 0; -} - -/* @dev is the CPU device */ -static void initialize_vr_config(struct udevice *dev) -{ - int ramp, min_vid; - msr_t msr; - - debug("Initializing VR config\n"); - - /* Configure VR_CURRENT_CONFIG */ - msr = msr_read(MSR_VR_CURRENT_CONFIG); - /* - * Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid - * on ULT systems - */ - msr.hi &= 0xc0000000; - msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */ - msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */ - msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */ - msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */ - /* Leave the max instantaneous current limit (12:0) to default */ - msr_write(MSR_VR_CURRENT_CONFIG, msr); - - /* Configure VR_MISC_CONFIG MSR */ - msr = msr_read(MSR_VR_MISC_CONFIG); - /* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */ - msr.hi &= ~(0x3ff << (40 - 32)); - msr.hi |= (0x200 << (40 - 32)); /* 1.0 */ - /* Set IOUT_OFFSET to 0 */ - msr.hi &= ~0xff; - /* Set entry ramp rate to slow */ - msr.hi &= ~(1 << (51 - 32)); - /* Enable decay mode on C-state entry */ - msr.hi |= (1 << (52 - 32)); - /* Set the slow ramp rate */ - msr.hi &= ~(0x3 << (53 - 32)); - /* Configure the C-state exit ramp rate */ - ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "intel,slow-ramp", -1); - if (ramp != -1) { - /* Configured slow ramp rate */ - msr.hi |= ((ramp & 0x3) << (53 - 32)); - /* Set exit ramp rate to slow */ - msr.hi &= ~(1 << (50 - 32)); - } else { - /* Fast ramp rate / 4 */ - msr.hi |= (0x01 << (53 - 32)); - /* Set exit ramp rate to fast */ - msr.hi |= (1 << (50 - 32)); - } - /* Set MIN_VID (31:24) to allow CPU to have full control */ - msr.lo &= ~0xff000000; - min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "intel,min-vid", 0); - msr.lo |= (min_vid & 0xff) << 24; - msr_write(MSR_VR_MISC_CONFIG, msr); - - /* Configure VR_MISC_CONFIG2 MSR */ - msr = msr_read(MSR_VR_MISC_CONFIG2); - msr.lo &= ~0xffff; - /* - * Allow CPU to control minimum voltage completely (15:8) and - * set the fast ramp voltage in 10mV steps - */ - if (cpu_get_family_model() == BROADWELL_FAMILY_ULT) - msr.lo |= 0x006a; /* 1.56V */ - else - msr.lo |= 0x006f; /* 1.60V */ - msr_write(MSR_VR_MISC_CONFIG2, msr); - - /* Set C9/C10 VCC Min */ - pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f); -} - -static int calibrate_24mhz_bclk(void) -{ - int err_code; - int ret; - - ret = pcode_ready(); - if (ret) - return ret; - - /* A non-zero value initiates the PCODE calibration */ - writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA)); - writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL, - MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) - return ret; - - err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff; - - debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code); - - /* Read the calibrated value */ - writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION, - MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) - return ret; - - debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n", - readl(MCHBAR_REG(BIOS_MAILBOX_DATA))); - - return 0; -} - -static void configure_pch_power_sharing(void) -{ - u32 pch_power, pch_power_ext, pmsync, pmsync2; - int i; - - /* Read PCH Power levels from PCODE */ - pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER); - pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT); - - debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power, - pch_power_ext); - - pmsync = readl(RCB_REG(PMSYNC_CONFIG)); - pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2)); - - /* - * Program PMSYNC_TPR_CONFIG PCH power limit values - * pmsync[0:4] = mailbox[0:5] - * pmsync[8:12] = mailbox[6:11] - * pmsync[16:20] = mailbox[12:17] - */ - for (i = 0; i < 3; i++) { - u32 level = pch_power & 0x3f; - pch_power >>= 6; - pmsync &= ~(0x1f << (i * 8)); - pmsync |= (level & 0x1f) << (i * 8); - } - writel(pmsync, RCB_REG(PMSYNC_CONFIG)); - - /* - * Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values - * pmsync2[0:4] = mailbox[23:18] - * pmsync2[8:12] = mailbox_ext[6:11] - * pmsync2[16:20] = mailbox_ext[12:17] - * pmsync2[24:28] = mailbox_ext[18:22] - */ - pmsync2 &= ~0x1f; - pmsync2 |= pch_power & 0x1f; - - for (i = 1; i < 4; i++) { - u32 level = pch_power_ext & 0x3f; - pch_power_ext >>= 6; - pmsync2 &= ~(0x1f << (i * 8)); - pmsync2 |= (level & 0x1f) << (i * 8); - } - writel(pmsync2, RCB_REG(PMSYNC_CONFIG2)); -} - -static int bsp_init_before_ap_bringup(struct udevice *dev) -{ - int ret; - - initialize_vr_config(dev); - ret = calibrate_24mhz_bclk(); - if (ret) - return ret; - configure_pch_power_sharing(); - - return 0; -} - -int cpu_config_tdp_levels(void) -{ - msr_t platform_info; - - /* Bits 34:33 indicate how many levels supported */ - platform_info = msr_read(MSR_PLATFORM_INFO); - return (platform_info.hi >> 1) & 3; -} - -static void set_max_ratio(void) -{ - msr_t msr, perf_ctl; - - perf_ctl.hi = 0; - - /* Check for configurable TDP option */ - if (turbo_get_state() == TURBO_ENABLED) { - msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT); - perf_ctl.lo = (msr.lo & 0xff) << 8; - } else if (cpu_config_tdp_levels()) { - /* Set to nominal TDP ratio */ - msr = msr_read(MSR_CONFIG_TDP_NOMINAL); - perf_ctl.lo = (msr.lo & 0xff) << 8; - } else { - /* Platform Info bits 15:8 give max ratio */ - msr = msr_read(MSR_PLATFORM_INFO); - perf_ctl.lo = msr.lo & 0xff00; - } - msr_write(IA32_PERF_CTL, perf_ctl); - - debug("cpu: frequency set to %d\n", - ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); -} - -int broadwell_init(struct udevice *dev) -{ - struct cpu_broadwell_priv *priv = dev_get_priv(dev); - int num_threads; - int num_cores; - msr_t msr; - int ret; - - msr = msr_read(CORE_THREAD_COUNT_MSR); - num_threads = (msr.lo >> 0) & 0xffff; - num_cores = (msr.lo >> 16) & 0xffff; - debug("CPU has %u cores, %u threads enabled\n", num_cores, - num_threads); - - priv->ht_disabled = num_threads == num_cores; - - ret = bsp_init_before_ap_bringup(dev); - if (ret) - return ret; - - set_max_ratio(); - - return ret; -} - -static void configure_mca(void) -{ - msr_t msr; - const unsigned int mcg_cap_msr = 0x179; - int i; - int num_banks; - - msr = msr_read(mcg_cap_msr); - num_banks = msr.lo & 0xff; - msr.lo = 0; - msr.hi = 0; - /* - * TODO(adurbin): This should only be done on a cold boot. Also, some - * of these banks are core vs package scope. For now every CPU clears - * every bank - */ - for (i = 0; i < num_banks; i++) - msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); -} - -static void enable_lapic_tpr(void) -{ - msr_t msr; - - msr = msr_read(MSR_PIC_MSG_CONTROL); - msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */ - msr_write(MSR_PIC_MSG_CONTROL, msr); -} - - -static void configure_c_states(void) -{ - msr_t msr; - - msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL); - msr.lo |= (1 << 31); /* Timed MWAIT Enable */ - msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */ - msr.lo |= (1 << 29); /* Package c-state Demotion Enable */ - msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */ - msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */ - msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */ - msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */ - msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */ - /* The deepest package c-state defaults to factory-configured value */ - msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr); - - msr = msr_read(MSR_MISC_PWR_MGMT); - msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */ - msr_write(MSR_MISC_PWR_MGMT, msr); - - msr = msr_read(MSR_POWER_CTL); - msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */ - msr.lo |= (1 << 1); /* C1E Enable */ - msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */ - msr_write(MSR_POWER_CTL, msr); - - /* C-state Interrupt Response Latency Control 0 - package C3 latency */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr); - - /* C-state Interrupt Response Latency Control 1 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr); - - /* C-state Interrupt Response Latency Control 2 - package C6/C7 short */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr); - - /* C-state Interrupt Response Latency Control 3 - package C8 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr); - - /* C-state Interrupt Response Latency Control 4 - package C9 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr); - - /* C-state Interrupt Response Latency Control 5 - package C10 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr); -} - -static void configure_misc(void) -{ - msr_t msr; - - msr = msr_read(MSR_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 */ - msr_write(MSR_IA32_MISC_ENABLE, msr); - - /* Disable thermal interrupts */ - msr.lo = 0; - msr.hi = 0; - msr_write(MSR_IA32_THERM_INTERRUPT, msr); - - /* Enable package critical interrupt only */ - msr.lo = 1 << 4; - msr.hi = 0; - msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr); -} - -static void configure_thermal_target(struct udevice *dev) -{ - int tcc_offset; - msr_t msr; - - tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "intel,tcc-offset", 0); - - /* Set TCC activaiton offset if supported */ - msr = msr_read(MSR_PLATFORM_INFO); - if ((msr.lo & (1 << 30)) && tcc_offset) { - msr = msr_read(MSR_TEMPERATURE_TARGET); - msr.lo &= ~(0xf << 24); /* Bits 27:24 */ - msr.lo |= (tcc_offset & 0xf) << 24; - msr_write(MSR_TEMPERATURE_TARGET, 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 = msr_read(MSR_IA32_PLATFORM_DCA_CAP); - msr.lo |= 1; - msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr); - } -} - -static void set_energy_perf_bias(u8 policy) -{ - msr_t msr; - int ecx; - - /* Determine if energy efficient policy is supported */ - ecx = cpuid_ecx(0x6); - if (!(ecx & (1 << 3))) - return; - - /* Energy Policy is bits 3:0 */ - msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS); - msr.lo &= ~0xf; - msr.lo |= policy & 0xf; - msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr); - - debug("cpu: energy policy set to %u\n", policy); -} - -/* All CPUs including BSP will run the following function */ -static void cpu_core_init(struct udevice *dev) -{ - /* Clear out pending MCEs */ - configure_mca(); - - /* Enable the local cpu apics */ - enable_lapic_tpr(); - - /* Configure C States */ - configure_c_states(); - - /* Configure Enhanced SpeedStep and Thermal Sensors */ - configure_misc(); - - /* Thermal throttle activation offset */ - configure_thermal_target(dev); - - /* Enable Direct Cache Access */ - configure_dca_cap(); - - /* Set energy policy */ - set_energy_perf_bias(ENERGY_POLICY_NORMAL); - - /* Enable Turbo */ - turbo_enable(); -} - -/* - * Configure processor power limits if possible - * This must be done AFTER set of BIOS_RESET_CPL - */ -void cpu_set_power_limits(int power_limit_1_time) -{ - msr_t msr; - msr_t limit; - unsigned power_unit; - unsigned tdp, min_power, max_power, max_time; - u8 power_limit_1_val; - - msr = msr_read(MSR_PLATFORM_INFO); - if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) - power_limit_1_time = 28; - - if (!(msr.lo & PLATFORM_INFO_SET_TDP)) - return; - - /* Get units */ - msr = msr_read(MSR_PKG_POWER_SKU_UNIT); - power_unit = 2 << ((msr.lo & 0xf) - 1); - - /* Get power defaults for this SKU */ - msr = msr_read(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; - - 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 server SKU */ - - msr_write(MSR_PKG_POWER_LIMIT, limit); - - /* Set power limit values in MCHBAR as well */ - writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO)); - writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI)); - - /* Set DDR RAPL power limit by copying from MMIO to MSR */ - msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO)); - msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI)); - msr_write(MSR_DDR_RAPL_LIMIT, msr); - - /* Use nominal TDP values for CPUs with configurable TDP */ - if (cpu_config_tdp_levels()) { - msr = msr_read(MSR_CONFIG_TDP_NOMINAL); - limit.hi = 0; - limit.lo = msr.lo & 0xff; - msr_write(MSR_TURBO_ACTIVATION_RATIO, limit); - } -} - -static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) -{ - msr_t msr; - - msr = msr_read(IA32_PERF_CTL); - info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000; - info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | - 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; - - return 0; -} - -static int broadwell_get_count(struct udevice *dev) +void board_debug_uart_init(void) { - return 4; -} + struct udevice *bus = NULL; -static int cpu_x86_broadwell_probe(struct udevice *dev) -{ - if (dev->seq == 0) { - cpu_core_init(dev); - return broadwell_init(dev); - } + /* com1 / com2 decode range */ + pci_x86_write_config(bus, PCH_DEV_LPC, LPC_IO_DEC, 1 << 4, PCI_SIZE_16); - return 0; + pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN, + PCI_SIZE_16); } - -static const struct cpu_ops cpu_x86_broadwell_ops = { - .get_desc = cpu_x86_get_desc, - .get_info = broadwell_get_info, - .get_count = broadwell_get_count, - .get_vendor = cpu_x86_get_vendor, -}; - -static const struct udevice_id cpu_x86_broadwell_ids[] = { - { .compatible = "intel,core-i3-gen5" }, - { } -}; - -U_BOOT_DRIVER(cpu_x86_broadwell_drv) = { - .name = "cpu_x86_broadwell", - .id = UCLASS_CPU, - .of_match = cpu_x86_broadwell_ids, - .bind = cpu_x86_bind, - .probe = cpu_x86_broadwell_probe, - .ops = &cpu_x86_broadwell_ops, - .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv), - .flags = DM_FLAG_PRE_RELOC, -}; diff --git a/arch/x86/cpu/broadwell/cpu_from_spl.c b/arch/x86/cpu/broadwell/cpu_from_spl.c new file mode 100644 index 0000000000..c3d4a8d547 --- /dev/null +++ b/arch/x86/cpu/broadwell/cpu_from_spl.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <bloblist.h> +#include <debug_uart.h> +#include <handoff.h> +#include <asm/mtrr.h> + +int misc_init_r(void) +{ + return 0; +} + +int dram_init(void) +{ + struct spl_handoff *ho; + + ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho)); + if (!ho) + return log_msg_ret("Missing SPL hand-off info", -ENOENT); + handoff_load_dram_size(ho); +#ifdef CONFIG_TPL + /* TODO(sjg@chromium.org): MTRR cannot be adjusted without a hang */ + mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30); +#else + mtrr_add_request(MTRR_TYPE_WRBACK, 0, gd->ram_size); + mtrr_commit(true); +#endif + + return 0; +} + +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return 0; +} + +void board_debug_uart_init(void) +{ +} + +int dram_init_banksize(void) +{ +#ifdef CONFIG_NR_DRAM_BANKS + struct spl_handoff *ho; + + ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho)); + if (!ho) + return log_msg_ret("Missing SPL hand-off info", -ENOENT); + handoff_load_dram_banks(ho); +#endif + + return 0; +} diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c new file mode 100644 index 0000000000..c1db184549 --- /dev/null +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016 Google, Inc + * + * Based on code from coreboot src/soc/intel/broadwell/cpu.c + */ + +#include <common.h> +#include <dm.h> +#include <cpu.h> +#include <asm/cpu.h> +#include <asm/cpu_x86.h> +#include <asm/cpu_common.h> +#include <asm/intel_regs.h> +#include <asm/msr.h> +#include <asm/post.h> +#include <asm/turbo.h> +#include <asm/arch/cpu.h> +#include <asm/arch/pch.h> +#include <asm/arch/rcb.h> + +struct cpu_broadwell_priv { + bool ht_disabled; +}; + +/* 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, +}; + +/* + * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate + * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly + * when a core is woken up + */ +static int pcode_ready(void) +{ + int wait_count; + const int delay_step = 10; + + wait_count = 0; + do { + if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & + MAILBOX_RUN_BUSY)) + return 0; + wait_count += delay_step; + udelay(delay_step); + } while (wait_count < 1000); + + return -ETIMEDOUT; +} + +static u32 pcode_mailbox_read(u32 command) +{ + int ret; + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on wait ready\n"); + return ret; + } + + /* Send command and start transaction */ + writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on completion\n"); + return ret; + } + + /* Read mailbox */ + return readl(MCHBAR_REG(BIOS_MAILBOX_DATA)); +} + +static int pcode_mailbox_write(u32 command, u32 data) +{ + int ret; + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on wait ready\n"); + return ret; + } + + writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA)); + + /* Send command and start transaction */ + writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on completion\n"); + return ret; + } + + return 0; +} + +/* @dev is the CPU device */ +static void initialize_vr_config(struct udevice *dev) +{ + int ramp, min_vid; + msr_t msr; + + debug("Initializing VR config\n"); + + /* Configure VR_CURRENT_CONFIG */ + msr = msr_read(MSR_VR_CURRENT_CONFIG); + /* + * Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid + * on ULT systems + */ + msr.hi &= 0xc0000000; + msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */ + msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */ + msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */ + msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */ + /* Leave the max instantaneous current limit (12:0) to default */ + msr_write(MSR_VR_CURRENT_CONFIG, msr); + + /* Configure VR_MISC_CONFIG MSR */ + msr = msr_read(MSR_VR_MISC_CONFIG); + /* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */ + msr.hi &= ~(0x3ff << (40 - 32)); + msr.hi |= (0x200 << (40 - 32)); /* 1.0 */ + /* Set IOUT_OFFSET to 0 */ + msr.hi &= ~0xff; + /* Set entry ramp rate to slow */ + msr.hi &= ~(1 << (51 - 32)); + /* Enable decay mode on C-state entry */ + msr.hi |= (1 << (52 - 32)); + /* Set the slow ramp rate */ + msr.hi &= ~(0x3 << (53 - 32)); + /* Configure the C-state exit ramp rate */ + ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,slow-ramp", -1); + if (ramp != -1) { + /* Configured slow ramp rate */ + msr.hi |= ((ramp & 0x3) << (53 - 32)); + /* Set exit ramp rate to slow */ + msr.hi &= ~(1 << (50 - 32)); + } else { + /* Fast ramp rate / 4 */ + msr.hi |= (0x01 << (53 - 32)); + /* Set exit ramp rate to fast */ + msr.hi |= (1 << (50 - 32)); + } + /* Set MIN_VID (31:24) to allow CPU to have full control */ + msr.lo &= ~0xff000000; + min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,min-vid", 0); + msr.lo |= (min_vid & 0xff) << 24; + msr_write(MSR_VR_MISC_CONFIG, msr); + + /* Configure VR_MISC_CONFIG2 MSR */ + msr = msr_read(MSR_VR_MISC_CONFIG2); + msr.lo &= ~0xffff; + /* + * Allow CPU to control minimum voltage completely (15:8) and + * set the fast ramp voltage in 10mV steps + */ + if (cpu_get_family_model() == BROADWELL_FAMILY_ULT) + msr.lo |= 0x006a; /* 1.56V */ + else + msr.lo |= 0x006f; /* 1.60V */ + msr_write(MSR_VR_MISC_CONFIG2, msr); + + /* Set C9/C10 VCC Min */ + pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f); +} + +static int calibrate_24mhz_bclk(void) +{ + int err_code; + int ret; + + ret = pcode_ready(); + if (ret) + return ret; + + /* A non-zero value initiates the PCODE calibration */ + writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA)); + writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL, + MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) + return ret; + + err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff; + + debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code); + + /* Read the calibrated value */ + writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION, + MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) + return ret; + + debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n", + readl(MCHBAR_REG(BIOS_MAILBOX_DATA))); + + return 0; +} + +static void configure_pch_power_sharing(void) +{ + u32 pch_power, pch_power_ext, pmsync, pmsync2; + int i; + + /* Read PCH Power levels from PCODE */ + pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER); + pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT); + + debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power, + pch_power_ext); + + pmsync = readl(RCB_REG(PMSYNC_CONFIG)); + pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2)); + + /* + * Program PMSYNC_TPR_CONFIG PCH power limit values + * pmsync[0:4] = mailbox[0:5] + * pmsync[8:12] = mailbox[6:11] + * pmsync[16:20] = mailbox[12:17] + */ + for (i = 0; i < 3; i++) { + u32 level = pch_power & 0x3f; + + pch_power >>= 6; + pmsync &= ~(0x1f << (i * 8)); + pmsync |= (level & 0x1f) << (i * 8); + } + writel(pmsync, RCB_REG(PMSYNC_CONFIG)); + + /* + * Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values + * pmsync2[0:4] = mailbox[23:18] + * pmsync2[8:12] = mailbox_ext[6:11] + * pmsync2[16:20] = mailbox_ext[12:17] + * pmsync2[24:28] = mailbox_ext[18:22] + */ + pmsync2 &= ~0x1f; + pmsync2 |= pch_power & 0x1f; + + for (i = 1; i < 4; i++) { + u32 level = pch_power_ext & 0x3f; + + pch_power_ext >>= 6; + pmsync2 &= ~(0x1f << (i * 8)); + pmsync2 |= (level & 0x1f) << (i * 8); + } + writel(pmsync2, RCB_REG(PMSYNC_CONFIG2)); +} + +static int bsp_init_before_ap_bringup(struct udevice *dev) +{ + int ret; + + initialize_vr_config(dev); + ret = calibrate_24mhz_bclk(); + if (ret) + return ret; + configure_pch_power_sharing(); + + return 0; +} + +static int cpu_config_tdp_levels(void) +{ + msr_t platform_info; + + /* Bits 34:33 indicate how many levels supported */ + platform_info = msr_read(MSR_PLATFORM_INFO); + return (platform_info.hi >> 1) & 3; +} + +static void set_max_ratio(void) +{ + msr_t msr, perf_ctl; + + perf_ctl.hi = 0; + + /* Check for configurable TDP option */ + if (turbo_get_state() == TURBO_ENABLED) { + msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else if (cpu_config_tdp_levels()) { + /* Set to nominal TDP ratio */ + msr = msr_read(MSR_CONFIG_TDP_NOMINAL); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else { + /* Platform Info bits 15:8 give max ratio */ + msr = msr_read(MSR_PLATFORM_INFO); + perf_ctl.lo = msr.lo & 0xff00; + } + msr_write(IA32_PERF_CTL, perf_ctl); + + debug("cpu: frequency set to %d\n", + ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); +} + +int broadwell_init(struct udevice *dev) +{ + struct cpu_broadwell_priv *priv = dev_get_priv(dev); + int num_threads; + int num_cores; + msr_t msr; + int ret; + + msr = msr_read(CORE_THREAD_COUNT_MSR); + num_threads = (msr.lo >> 0) & 0xffff; + num_cores = (msr.lo >> 16) & 0xffff; + debug("CPU has %u cores, %u threads enabled\n", num_cores, + num_threads); + + priv->ht_disabled = num_threads == num_cores; + + ret = bsp_init_before_ap_bringup(dev); + if (ret) + return ret; + + set_max_ratio(); + + return ret; +} + +static void configure_mca(void) +{ + msr_t msr; + const unsigned int mcg_cap_msr = 0x179; + int i; + int num_banks; + + msr = msr_read(mcg_cap_msr); + num_banks = msr.lo & 0xff; + msr.lo = 0; + msr.hi = 0; + /* + * TODO(adurbin): This should only be done on a cold boot. Also, some + * of these banks are core vs package scope. For now every CPU clears + * every bank + */ + for (i = 0; i < num_banks; i++) + msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); +} + +static void enable_lapic_tpr(void) +{ + msr_t msr; + + msr = msr_read(MSR_PIC_MSG_CONTROL); + msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */ + msr_write(MSR_PIC_MSG_CONTROL, msr); +} + +static void configure_c_states(void) +{ + msr_t msr; + + msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL); + msr.lo |= (1 << 31); /* Timed MWAIT Enable */ + msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */ + msr.lo |= (1 << 29); /* Package c-state Demotion Enable */ + msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */ + msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */ + msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */ + msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */ + msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */ + /* The deepest package c-state defaults to factory-configured value */ + msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr); + + msr = msr_read(MSR_MISC_PWR_MGMT); + msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */ + msr_write(MSR_MISC_PWR_MGMT, msr); + + msr = msr_read(MSR_POWER_CTL); + msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */ + msr.lo |= (1 << 1); /* C1E Enable */ + msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */ + msr_write(MSR_POWER_CTL, msr); + + /* C-state Interrupt Response Latency Control 0 - package C3 latency */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr); + + /* C-state Interrupt Response Latency Control 1 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr); + + /* C-state Interrupt Response Latency Control 2 - package C6/C7 short */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr); + + /* C-state Interrupt Response Latency Control 3 - package C8 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr); + + /* C-state Interrupt Response Latency Control 4 - package C9 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr); + + /* C-state Interrupt Response Latency Control 5 - package C10 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr); +} + +static void configure_misc(void) +{ + msr_t msr; + + msr = msr_read(MSR_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 */ + msr_write(MSR_IA32_MISC_ENABLE, msr); + + /* Disable thermal interrupts */ + msr.lo = 0; + msr.hi = 0; + msr_write(MSR_IA32_THERM_INTERRUPT, msr); + + /* Enable package critical interrupt only */ + msr.lo = 1 << 4; + msr.hi = 0; + msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr); +} + +static void configure_thermal_target(struct udevice *dev) +{ + int tcc_offset; + msr_t msr; + + tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,tcc-offset", 0); + + /* Set TCC activaiton offset if supported */ + msr = msr_read(MSR_PLATFORM_INFO); + if ((msr.lo & (1 << 30)) && tcc_offset) { + msr = msr_read(MSR_TEMPERATURE_TARGET); + msr.lo &= ~(0xf << 24); /* Bits 27:24 */ + msr.lo |= (tcc_offset & 0xf) << 24; + msr_write(MSR_TEMPERATURE_TARGET, 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 = msr_read(MSR_IA32_PLATFORM_DCA_CAP); + msr.lo |= 1; + msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr); + } +} + +static void set_energy_perf_bias(u8 policy) +{ + msr_t msr; + int ecx; + + /* Determine if energy efficient policy is supported */ + ecx = cpuid_ecx(0x6); + if (!(ecx & (1 << 3))) + return; + + /* Energy Policy is bits 3:0 */ + msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS); + msr.lo &= ~0xf; + msr.lo |= policy & 0xf; + msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr); + + debug("cpu: energy policy set to %u\n", policy); +} + +/* All CPUs including BSP will run the following function */ +static void cpu_core_init(struct udevice *dev) +{ + /* Clear out pending MCEs */ + configure_mca(); + + /* Enable the local cpu apics */ + enable_lapic_tpr(); + + /* Configure C States */ + configure_c_states(); + + /* Configure Enhanced SpeedStep and Thermal Sensors */ + configure_misc(); + + /* Thermal throttle activation offset */ + configure_thermal_target(dev); + + /* Enable Direct Cache Access */ + configure_dca_cap(); + + /* Set energy policy */ + set_energy_perf_bias(ENERGY_POLICY_NORMAL); + + /* Enable Turbo */ + turbo_enable(); +} + +/* + * Configure processor power limits if possible + * This must be done AFTER set of BIOS_RESET_CPL + */ +void cpu_set_power_limits(int power_limit_1_time) +{ + msr_t msr; + msr_t limit; + uint power_unit; + uint tdp, min_power, max_power, max_time; + u8 power_limit_1_val; + + msr = msr_read(MSR_PLATFORM_INFO); + if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) + power_limit_1_time = 28; + + if (!(msr.lo & PLATFORM_INFO_SET_TDP)) + return; + + /* Get units */ + msr = msr_read(MSR_PKG_POWER_SKU_UNIT); + power_unit = 2 << ((msr.lo & 0xf) - 1); + + /* Get power defaults for this SKU */ + msr = msr_read(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; + + 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 server SKU */ + + msr_write(MSR_PKG_POWER_LIMIT, limit); + + /* Set power limit values in MCHBAR as well */ + writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO)); + writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI)); + + /* Set DDR RAPL power limit by copying from MMIO to MSR */ + msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO)); + msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI)); + msr_write(MSR_DDR_RAPL_LIMIT, msr); + + /* Use nominal TDP values for CPUs with configurable TDP */ + if (cpu_config_tdp_levels()) { + msr = msr_read(MSR_CONFIG_TDP_NOMINAL); + limit.hi = 0; + limit.lo = msr.lo & 0xff; + msr_write(MSR_TURBO_ACTIVATION_RATIO, limit); + } +} + +static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) +{ + msr_t msr; + + msr = msr_read(IA32_PERF_CTL); + info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000; + info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | + 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; + + return 0; +} + +static int broadwell_get_count(struct udevice *dev) +{ + return 4; +} + +static int cpu_x86_broadwell_probe(struct udevice *dev) +{ + if (dev->seq == 0) { + cpu_core_init(dev); + return broadwell_init(dev); + } + + return 0; +} + +static const struct cpu_ops cpu_x86_broadwell_ops = { + .get_desc = cpu_x86_get_desc, + .get_info = broadwell_get_info, + .get_count = broadwell_get_count, + .get_vendor = cpu_x86_get_vendor, +}; + +static const struct udevice_id cpu_x86_broadwell_ids[] = { + { .compatible = "intel,core-i3-gen5" }, + { } +}; + +U_BOOT_DRIVER(cpu_x86_broadwell_drv) = { + .name = "cpu_x86_broadwell", + .id = UCLASS_CPU, + .of_match = cpu_x86_broadwell_ids, + .bind = cpu_x86_bind, + .probe = cpu_x86_broadwell_probe, + .ops = &cpu_x86_broadwell_ops, + .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/arch/x86/cpu/broadwell/northbridge.c b/arch/x86/cpu/broadwell/northbridge.c index 3055880bb7..4bcab78556 100644 --- a/arch/x86/cpu/broadwell/northbridge.c +++ b/arch/x86/cpu/broadwell/northbridge.c @@ -6,8 +6,108 @@ #include <common.h> #include <dm.h> #include <asm/io.h> +#include <asm/mrc_common.h> #include <asm/arch/iomap.h> #include <asm/arch/pch.h> +#include <asm/arch/pei_data.h> + +__weak asmlinkage void sdram_console_tx_byte(unsigned char byte) +{ +#ifdef DEBUG + putc(byte); +#endif +} + +void broadwell_fill_pei_data(struct pei_data *pei_data) +{ + pei_data->pei_version = PEI_VERSION; + pei_data->board_type = BOARD_TYPE_ULT; + pei_data->pciexbar = MCFG_BASE_ADDRESS; + pei_data->smbusbar = SMBUS_BASE_ADDRESS; + pei_data->ehcibar = EARLY_EHCI_BAR; + pei_data->xhcibar = EARLY_XHCI_BAR; + pei_data->gttbar = EARLY_GTT_BAR; + pei_data->pmbase = ACPI_BASE_ADDRESS; + pei_data->gpiobase = GPIO_BASE_ADDRESS; + pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE; + pei_data->temp_mmio_base = EARLY_TEMP_MMIO; + pei_data->tx_byte = sdram_console_tx_byte; + pei_data->ddr_refresh_2x = 1; +} + +static void pei_data_usb2_port(struct pei_data *pei_data, int port, uint length, + uint enable, uint oc_pin, uint location) +{ + pei_data->usb2_ports[port].length = length; + pei_data->usb2_ports[port].enable = enable; + pei_data->usb2_ports[port].oc_pin = oc_pin; + pei_data->usb2_ports[port].location = location; +} + +static void pei_data_usb3_port(struct pei_data *pei_data, int port, uint enable, + uint oc_pin, uint fixed_eq) +{ + pei_data->usb3_ports[port].enable = enable; + pei_data->usb3_ports[port].oc_pin = oc_pin; + pei_data->usb3_ports[port].fixed_eq = fixed_eq; +} + +void mainboard_fill_pei_data(struct pei_data *pei_data) +{ + /* DQ byte map for Samus board */ + const u8 dq_map[2][6][2] = { + { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, + { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } }, + { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, + { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } } }; + /* DQS CPU<>DRAM map for Samus board */ + const u8 dqs_map[2][8] = { + { 2, 0, 1, 3, 6, 4, 7, 5 }, + { 2, 1, 0, 3, 6, 5, 4, 7 } }; + + pei_data->ec_present = 1; + + /* One installed DIMM per channel */ + pei_data->dimm_channel0_disabled = 2; + pei_data->dimm_channel1_disabled = 2; + + memcpy(pei_data->dq_map, dq_map, sizeof(dq_map)); + memcpy(pei_data->dqs_map, dqs_map, sizeof(dqs_map)); + + /* P0: HOST PORT */ + pei_data_usb2_port(pei_data, 0, 0x0080, 1, 0, + USB_PORT_BACK_PANEL); + /* P1: HOST PORT */ + pei_data_usb2_port(pei_data, 1, 0x0080, 1, 1, + USB_PORT_BACK_PANEL); + /* P2: RAIDEN */ + pei_data_usb2_port(pei_data, 2, 0x0080, 1, USB_OC_PIN_SKIP, + USB_PORT_BACK_PANEL); + /* P3: SD CARD */ + pei_data_usb2_port(pei_data, 3, 0x0040, 1, USB_OC_PIN_SKIP, + USB_PORT_INTERNAL); + /* P4: RAIDEN */ + pei_data_usb2_port(pei_data, 4, 0x0080, 1, USB_OC_PIN_SKIP, + USB_PORT_BACK_PANEL); + /* P5: WWAN (Disabled) */ + pei_data_usb2_port(pei_data, 5, 0x0000, 0, USB_OC_PIN_SKIP, + USB_PORT_SKIP); + /* P6: CAMERA */ + pei_data_usb2_port(pei_data, 6, 0x0040, 1, USB_OC_PIN_SKIP, + USB_PORT_INTERNAL); + /* P7: BT */ + pei_data_usb2_port(pei_data, 7, 0x0040, 1, USB_OC_PIN_SKIP, + USB_PORT_INTERNAL); + + /* P1: HOST PORT */ + pei_data_usb3_port(pei_data, 0, 1, 0, 0); + /* P2: HOST PORT */ + pei_data_usb3_port(pei_data, 1, 1, 1, 0); + /* P3: RAIDEN */ + pei_data_usb3_port(pei_data, 2, 1, USB_OC_PIN_SKIP, 0); + /* P4: RAIDEN */ + pei_data_usb3_port(pei_data, 3, 1, USB_OC_PIN_SKIP, 0); +} static int broadwell_northbridge_early_init(struct udevice *dev) { diff --git a/arch/x86/cpu/broadwell/pch.c b/arch/x86/cpu/broadwell/pch.c index 73d3d3b515..a48945adf1 100644 --- a/arch/x86/cpu/broadwell/pch.c +++ b/arch/x86/cpu/broadwell/pch.c @@ -599,10 +599,16 @@ static int broadwell_pch_init(struct udevice *dev) static int broadwell_pch_probe(struct udevice *dev) { - if (!(gd->flags & GD_FLG_RELOC)) - return broadwell_pch_early_init(dev); - else + if (CONFIG_IS_ENABLED(X86_32BIT_INIT)) { + if (!(gd->flags & GD_FLG_RELOC)) + return broadwell_pch_early_init(dev); + else + return broadwell_pch_init(dev); + } else if (IS_ENABLED(CONFIG_SPL) && !IS_ENABLED(CONFIG_SPL_BUILD)) { return broadwell_pch_init(dev); + } else { + return 0; + } } static int broadwell_pch_get_spi_base(struct udevice *dev, ulong *sbasep) @@ -630,10 +636,35 @@ static int broadwell_get_gpio_base(struct udevice *dev, u32 *gbasep) return 0; } +static int broadwell_ioctl(struct udevice *dev, enum pch_req_t req, void *data, + int size) +{ + switch (req) { + case PCH_REQ_PMBASE_INFO: { + struct pch_pmbase_info *pm = data; + int ret; + + /* Find the base address of the powermanagement registers */ + ret = dm_pci_read_config16(dev, 0x40, &pm->base); + if (ret) + return ret; + pm->base &= 0xfffe; + pm->gpio0_en_ofs = GPE0_EN(0); + pm->pm1_sts_ofs = PM1_STS; + pm->pm1_cnt_ofs = PM1_CNT; + + return 0; + } + default: + return -ENOSYS; + } +} + static const struct pch_ops broadwell_pch_ops = { .get_spi_base = broadwell_pch_get_spi_base, .set_spi_protect = broadwell_set_spi_protect, .get_gpio_base = broadwell_get_gpio_base, + .ioctl = broadwell_ioctl, }; static const struct udevice_id broadwell_pch_ids[] = { diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index 03a35bcf73..b31d78c092 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -34,99 +34,6 @@ int dram_init_banksize(void) return 0; } -void broadwell_fill_pei_data(struct pei_data *pei_data) -{ - pei_data->pei_version = PEI_VERSION; - pei_data->board_type = BOARD_TYPE_ULT; - pei_data->pciexbar = MCFG_BASE_ADDRESS; - pei_data->smbusbar = SMBUS_BASE_ADDRESS; - pei_data->ehcibar = EARLY_EHCI_BAR; - pei_data->xhcibar = EARLY_XHCI_BAR; - pei_data->gttbar = EARLY_GTT_BAR; - pei_data->pmbase = ACPI_BASE_ADDRESS; - pei_data->gpiobase = GPIO_BASE_ADDRESS; - pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE; - pei_data->temp_mmio_base = EARLY_TEMP_MMIO; - pei_data->tx_byte = sdram_console_tx_byte; - pei_data->ddr_refresh_2x = 1; -} - -static inline void pei_data_usb2_port(struct pei_data *pei_data, int port, - uint16_t length, uint8_t enable, - uint8_t oc_pin, uint8_t location) -{ - pei_data->usb2_ports[port].length = length; - pei_data->usb2_ports[port].enable = enable; - pei_data->usb2_ports[port].oc_pin = oc_pin; - pei_data->usb2_ports[port].location = location; -} - -static inline void pei_data_usb3_port(struct pei_data *pei_data, int port, - uint8_t enable, uint8_t oc_pin, - uint8_t fixed_eq) -{ - pei_data->usb3_ports[port].enable = enable; - pei_data->usb3_ports[port].oc_pin = oc_pin; - pei_data->usb3_ports[port].fixed_eq = fixed_eq; -} - -void mainboard_fill_pei_data(struct pei_data *pei_data) -{ - /* DQ byte map for Samus board */ - const u8 dq_map[2][6][2] = { - { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, - { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } }, - { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, - { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } } }; - /* DQS CPU<>DRAM map for Samus board */ - const u8 dqs_map[2][8] = { - { 2, 0, 1, 3, 6, 4, 7, 5 }, - { 2, 1, 0, 3, 6, 5, 4, 7 } }; - - pei_data->ec_present = 1; - - /* One installed DIMM per channel */ - pei_data->dimm_channel0_disabled = 2; - pei_data->dimm_channel1_disabled = 2; - - memcpy(pei_data->dq_map, dq_map, sizeof(dq_map)); - memcpy(pei_data->dqs_map, dqs_map, sizeof(dqs_map)); - - /* P0: HOST PORT */ - pei_data_usb2_port(pei_data, 0, 0x0080, 1, 0, - USB_PORT_BACK_PANEL); - /* P1: HOST PORT */ - pei_data_usb2_port(pei_data, 1, 0x0080, 1, 1, - USB_PORT_BACK_PANEL); - /* P2: RAIDEN */ - pei_data_usb2_port(pei_data, 2, 0x0080, 1, USB_OC_PIN_SKIP, - USB_PORT_BACK_PANEL); - /* P3: SD CARD */ - pei_data_usb2_port(pei_data, 3, 0x0040, 1, USB_OC_PIN_SKIP, - USB_PORT_INTERNAL); - /* P4: RAIDEN */ - pei_data_usb2_port(pei_data, 4, 0x0080, 1, USB_OC_PIN_SKIP, - USB_PORT_BACK_PANEL); - /* P5: WWAN (Disabled) */ - pei_data_usb2_port(pei_data, 5, 0x0000, 0, USB_OC_PIN_SKIP, - USB_PORT_SKIP); - /* P6: CAMERA */ - pei_data_usb2_port(pei_data, 6, 0x0040, 1, USB_OC_PIN_SKIP, - USB_PORT_INTERNAL); - /* P7: BT */ - pei_data_usb2_port(pei_data, 7, 0x0040, 1, USB_OC_PIN_SKIP, - USB_PORT_INTERNAL); - - /* P1: HOST PORT */ - pei_data_usb3_port(pei_data, 0, 1, 0, 0); - /* P2: HOST PORT */ - pei_data_usb3_port(pei_data, 1, 1, 1, 0); - /* P3: RAIDEN */ - pei_data_usb3_port(pei_data, 2, 1, USB_OC_PIN_SKIP, 0); - /* P4: RAIDEN */ - pei_data_usb3_port(pei_data, 3, 1, USB_OC_PIN_SKIP, 0); -} - static unsigned long get_top_of_ram(struct udevice *dev) { /* @@ -204,16 +111,18 @@ int dram_init(void) /* Print ME state before MRC */ ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev); - if (ret) + if (ret) { + debug("Cannot get ME (err=%d)\n", ret); return ret; + } intel_me_status(me_dev); /* Save ME HSIO version */ - ret = uclass_first_device(UCLASS_PCH, &pch_dev); - if (ret) + ret = uclass_first_device_err(UCLASS_PCH, &pch_dev); + if (ret) { + debug("Cannot get PCH (err=%d)\n", ret); return ret; - if (!pch_dev) - return -ENODEV; + } power_state_get(pch_dev, &ps); intel_me_hsio_version(me_dev, &ps.hsio_version, &ps.hsio_checksum); @@ -221,15 +130,17 @@ int dram_init(void) broadwell_fill_pei_data(pei_data); mainboard_fill_pei_data(pei_data); - ret = uclass_first_device(UCLASS_NORTHBRIDGE, &dev); - if (ret) + ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); + if (ret) { + debug("Cannot get Northbridge (err=%d)\n", ret); return ret; - if (!dev) - return -ENODEV; + } size = 256; ret = mrc_locate_spd(dev, size, &spd_data); - if (ret) + if (ret) { + debug("Cannot locate SPD (err=%d)\n", ret); return ret; + } memcpy(pei_data->spd_data[0][0], spd_data, size); memcpy(pei_data->spd_data[1][0], spd_data, size); @@ -239,13 +150,17 @@ int dram_init(void) debug("PEI version %#x\n", pei_data->pei_version); ret = mrc_common_init(dev, pei_data, true); - if (ret) + if (ret) { + debug("mrc_common_init() failed(err=%d)\n", ret); return ret; + } debug("Memory init done\n"); ret = sdram_find(dev); - if (ret) + if (ret) { + debug("sdram_find() failed (err=%d)\n", ret); return ret; + } gd->ram_size = gd->arch.meminfo.total_32bit_memory; debug("RAM size %llx\n", (unsigned long long)gd->ram_size); @@ -279,17 +194,6 @@ int misc_init_r(void) return 0; } -void board_debug_uart_init(void) -{ - struct udevice *bus = NULL; - - /* com1 / com2 decode range */ - pci_x86_write_config(bus, PCH_DEV_LPC, LPC_IO_DEC, 1 << 4, PCI_SIZE_16); - - pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN, - PCI_SIZE_16); -} - static const struct udevice_id broadwell_syscon_ids[] = { { .compatible = "intel,me", .data = X86_SYSCON_ME }, { } diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 3bde44ebf5..90b546e741 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -309,21 +309,22 @@ u32 cpu_get_stepping(void) return gd->arch.x86_mask; } -int x86_cpu_init_f(void) +/* initialise FPU, reset EM, set MP and NE */ +static void setup_cpu_features(void) { const u32 em_rst = ~X86_CR0_EM; const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE; - if (ll_boot_init()) { - /* initialize FPU, reset EM, set MP and NE */ - asm ("fninit\n" \ - "movl %%cr0, %%eax\n" \ - "andl %0, %%eax\n" \ - "orl %1, %%eax\n" \ - "movl %%eax, %%cr0\n" \ - : : "i" (em_rst), "i" (mp_ne_set) : "eax"); - } + asm ("fninit\n" \ + "movl %%cr0, %%eax\n" \ + "andl %0, %%eax\n" \ + "orl %1, %%eax\n" \ + "movl %%eax, %%cr0\n" \ + : : "i" (em_rst), "i" (mp_ne_set) : "eax"); +} +static void setup_identity(void) +{ /* identify CPU via cpuid and store the decoded info into gd->arch */ if (has_cpuid()) { struct cpu_device_id cpu; @@ -339,46 +340,70 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } - /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ +} + +/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ +static void setup_pci_ram_top(void) +{ gd->pci_ram_top = 0x80000000U; +} + +static void setup_mtrr(void) +{ + u64 mtrr_cap; /* Configure fixed range MTRRs for some legacy regions */ - if (gd->arch.has_mtrr) { - u64 mtrr_cap; - - mtrr_cap = native_read_msr(MTRR_CAP_MSR); - if (mtrr_cap & MTRR_CAP_FIX) { - /* Mark the VGA RAM area as uncacheable */ - native_write_msr(MTRR_FIX_16K_A0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE), - MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE)); - - /* - * Mark the PCI ROM area as cacheable to improve ROM - * execution performance. - */ - native_write_msr(MTRR_FIX_4K_C0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_C8000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_D0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_D8000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - - /* Enable the fixed range MTRRs */ - msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); - } + if (!gd->arch.has_mtrr) + return; + + mtrr_cap = native_read_msr(MTRR_CAP_MSR); + if (mtrr_cap & MTRR_CAP_FIX) { + /* Mark the VGA RAM area as uncacheable */ + native_write_msr(MTRR_FIX_16K_A0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE), + MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE)); + + /* + * Mark the PCI ROM area as cacheable to improve ROM + * execution performance. + */ + native_write_msr(MTRR_FIX_4K_C0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_C8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_D0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_D8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + + /* Enable the fixed range MTRRs */ + msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); } +} + +int x86_cpu_init_f(void) +{ + if (ll_boot_init()) + setup_cpu_features(); + setup_identity(); + setup_mtrr(); + setup_pci_ram_top(); -#ifdef CONFIG_I8254_TIMER /* Set up the i8254 timer if required */ - i8254_init(); -#endif + if (IS_ENABLED(CONFIG_I8254_TIMER)) + i8254_init(); + + return 0; +} + +int x86_cpu_reinit_f(void) +{ + setup_identity(); + setup_pci_ram_top(); return 0; } diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index bf798c287f..07f27c29ec 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -3,14 +3,23 @@ # Copyright (c) 2016 Google, Inc ifdef CONFIG_HAVE_MRC -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += car.o -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += me_status.o -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += report_platform.o -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += mrc.o +obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += car.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += me_status.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o endif obj-y += cpu.o obj-y += lpc.o ifndef CONFIG_TARGET_EFI_APP +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o +ifndef CONFIG_$(SPL_)X86_64 obj-y += microcode.o endif +endif obj-y += pch.o + +ifdef CONFIG_SPL +ifndef CONFIG_SPL_BUILD +obj-y += cpu_from_spl.o +endif +endif diff --git a/arch/x86/cpu/intel_common/car.S b/arch/x86/cpu/intel_common/car.S index 52a77bb2d1..00308dbdef 100644 --- a/arch/x86/cpu/intel_common/car.S +++ b/arch/x86/cpu/intel_common/car.S @@ -235,7 +235,7 @@ mtrr_table_end: .align 4 _dt_ucode_base_size: - /* These next two fields are filled in by ifdtool */ + /* These next two fields are filled in by binman */ .globl ucode_base ucode_base: /* Declared in microcode.h */ .long 0 /* microcode base */ diff --git a/arch/x86/cpu/intel_common/cpu_from_spl.c b/arch/x86/cpu/intel_common/cpu_from_spl.c new file mode 100644 index 0000000000..a6233c75ce --- /dev/null +++ b/arch/x86/cpu/intel_common/cpu_from_spl.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016 Google, Inc + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/cpu_common.h> +#include <asm/intel_regs.h> +#include <asm/lapic.h> +#include <asm/lpc_common.h> +#include <asm/msr.h> +#include <asm/mtrr.h> +#include <asm/post.h> +#include <asm/microcode.h> + +DECLARE_GLOBAL_DATA_PTR; + +int arch_cpu_init(void) +{ + int ret; + + ret = x86_cpu_reinit_f(); + + return ret; +} diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index ed9bce6416..1cb6cecda9 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -229,6 +229,21 @@ static int bd82x6x_ioctl(struct udevice *dev, enum pch_req_t req, void *data, return -ENOENT; return val & RCBA_AUDIO_CONFIG_MASK; + case PCH_REQ_PMBASE_INFO: { + struct pch_pmbase_info *pm = data; + int ret; + + /* Find the base address of the powermanagement registers */ + ret = dm_pci_read_config16(dev, 0x40, &pm->base); + if (ret) + return ret; + pm->base &= 0xfffe; + pm->gpio0_en_ofs = GPE0_EN; + pm->pm1_sts_ofs = PM1_STS; + pm->pm1_cnt_ofs = PM1_CNT; + + return 0; + } default: return -ENOSYS; } diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index ea64c2ee57..fefbf8f728 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -322,7 +322,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) if (sipi_vector > max_vector_loc) { printf("SIPI vector too large! 0x%08x\n", sipi_vector); - return -1; + return -ENOSPC; } debug("Attempting to start %d APs\n", ap_count); @@ -364,7 +364,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) if (wait_for_aps(num_aps, ap_count, 10000, 50)) { debug("Not all APs checked in: %d/%d\n", atomic_read(num_aps), ap_count); - return -1; + return -EIO; } return 0; @@ -387,7 +387,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) if (wait_for_aps(&rec->cpus_entered, num_aps, timeout_us, step_us)) { debug("MP record %d timeout\n", i); - ret = -1; + ret = -ETIMEDOUT; } } @@ -508,7 +508,7 @@ int mp_init(struct mp_params *p) if (p == NULL || p->flight_plan == NULL || p->num_records < 1) { printf("Invalid MP parameters\n"); - return -1; + return -EINVAL; } num_cpus = cpu_get_count(cpu); @@ -531,7 +531,7 @@ int mp_init(struct mp_params *p) /* Load the SIPI vector */ ret = load_sipi_vector(&ap_count, num_cpus); if (ap_count == NULL) - return -1; + return -ENOENT; /* * Make sure SIPI data hits RAM so the APs that come up will see diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 30fa7def46..4a82add76b 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -190,6 +190,19 @@ board_init_f_r_trampoline: /* Re-enter U-Boot by calling board_init_f_r() */ call board_init_f_r +#ifdef CONFIG_TPL +.globl jump_to_spl +.type jump_to_spl, @function +jump_to_spl: + /* Reset stack to the top of CAR space */ + movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp +#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE + subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp +#endif + + jmp *%eax +#endif + die: hlt jmp die diff --git a/arch/x86/cpu/start64.S b/arch/x86/cpu/start64.S index a78a3316b6..7be834788b 100644 --- a/arch/x86/cpu/start64.S +++ b/arch/x86/cpu/start64.S @@ -2,7 +2,7 @@ /* * 64-bit x86 Startup Code * - * (C) Copyright 216 Google, Inc + * Copyright 2019 Google, Inc * Written by Simon Glass <sjg@chromium.org> */ diff --git a/arch/x86/cpu/start_from_spl.S b/arch/x86/cpu/start_from_spl.S new file mode 100644 index 0000000000..4d4e5d0758 --- /dev/null +++ b/arch/x86/cpu/start_from_spl.S @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 32-bit x86 Startup Code when running from SPL + * + * Copyright 2018 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <config.h> + +.section .text.start +.code32 +.globl _start +.type _start, @function +_start: + /* Set up memory using the existing stack */ + movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %eax +#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE + subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %eax +#endif + /* + * We don't subject CONFIG_DCACHE_RAM_MRC_VAR_SIZE since memory is + * already set up. This has the happy side-effect of putting gd in a + * new place separate from SPL, so the memset() in + * board_init_f_init_reserve() does not cause any problems (otherwise + * it would zero out the gd and crash) + */ + call board_init_f_alloc_reserve + mov %eax, %esp + + call board_init_f_init_reserve + + xorl %eax, %eax + call board_init_f + call board_init_f_r + + /* Should not return here */ + jmp . + +.globl board_init_f_r_trampoline +.type board_init_f_r_trampoline, @function +board_init_f_r_trampoline: + /* + * SPL has been executed and SDRAM has been initialised, U-Boot code + * has been copied into RAM, BSS has been cleared and relocation + * adjustments have been made. It is now time to jump into the in-RAM + * copy of U-Boot + * + * %eax = Address of top of new stack + */ + + /* Stack grows down from top of SDRAM */ + movl %eax, %esp + + /* Re-enter U-Boot by calling board_init_f_r() */ + call board_init_f_r + +die: + hlt + jmp die + hlt + + .align 4 +_dt_ucode_base_size: + /* These next two fields are filled in by binman */ +.globl ucode_base +ucode_base: /* Declared in microcode.h */ + .long 0 /* microcode base */ +.globl ucode_size +ucode_size: /* Declared in microcode.h */ + .long 0 /* microcode size */ diff --git a/arch/x86/cpu/start_from_tpl.S b/arch/x86/cpu/start_from_tpl.S new file mode 100644 index 0000000000..44b5363a68 --- /dev/null +++ b/arch/x86/cpu/start_from_tpl.S @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 32-bit x86 Startup Code when running from TPL + * + * Copyright 2018 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <config.h> + +.section .text.start +.code32 +.globl _start +.type _start, @function +_start: + /* Set up memory using the existing stack */ + mov %esp, %eax + call board_init_f_alloc_reserve + mov %eax, %esp + + call board_init_f_init_reserve + + xorl %eax, %eax + call board_init_f + call board_init_f_r + + /* Should not return here */ + jmp . + +.globl board_init_f_r_trampoline +.type board_init_f_r_trampoline, @function +board_init_f_r_trampoline: + /* + * TPL has been executed: SDRAM has been initialised, BSS has been + * cleared. + * + * %eax = Address of top of new stack + */ + + /* Stack grows down from top of SDRAM */ + movl %eax, %esp + + /* Re-enter SPL by calling board_init_f_r() */ + call board_init_f_r + +die: + hlt + jmp die + hlt diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index 4e656dc4e5..f20c0b810d 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -54,7 +54,7 @@ SECTIONS /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } -#ifdef CONFIG_SPL_X86_16BIT_INIT +#if defined(CONFIG_SPL_X86_16BIT_INIT) || defined(CONFIG_TPL_X86_16BIT_INIT) /* * The following expressions place the 16-bit Real-Mode code and * Reset Vector at the end of the Flash ROM diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 6c063e8200..42abb23a9e 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -61,3 +61,8 @@ int print_cpuinfo(void) { return 0; } + +int x86_cpu_reinit_f(void) +{ + return 0; +} |