Set up MSRs required for Apollo Lake. This enables Linux to use the timers correctly. Also write the fixed MSRs for this platform.
Signed-off-by: Simon Glass <s...@chromium.org> Reviewed-by: Bin Meng <bmeng...@gmail.com> --- (no changes since v2) Changes in v2: - Rename update_fixed_mtrss() to update_fixed_mtrrs() - Add comments to enable_pm_timer_emulation() and cpu_mca_configure() arch/x86/cpu/apollolake/cpu.c | 84 ++++++++++++++++++++++ arch/x86/cpu/apollolake/cpu_common.c | 25 +++++++ arch/x86/cpu/apollolake/cpu_spl.c | 20 ------ arch/x86/cpu/intel_common/cpu.c | 19 +++++ arch/x86/include/asm/arch-apollolake/cpu.h | 14 ++++ arch/x86/include/asm/cpu_common.h | 9 +++ arch/x86/include/asm/msr-index.h | 20 +++++- 7 files changed, 170 insertions(+), 21 deletions(-) diff --git a/arch/x86/cpu/apollolake/cpu.c b/arch/x86/cpu/apollolake/cpu.c index a4c9c96cfdc..d37f91d1ce1 100644 --- a/arch/x86/cpu/apollolake/cpu.c +++ b/arch/x86/cpu/apollolake/cpu.c @@ -13,6 +13,9 @@ #include <asm/cpu_x86.h> #include <asm/intel_acpi.h> #include <asm/msr.h> +#include <asm/mtrr.h> +#include <asm/arch/cpu.h> +#include <asm/arch/iomap.h> #include <dm/acpi.h> #define CSTATE_RES(address_space, width, offset, address) \ @@ -86,6 +89,86 @@ static int acpi_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) return 0; } +static void update_fixed_mtrrs(void) +{ + native_write_msr(MTRR_FIX_64K_00000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_16K_80000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_E0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_E8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_F0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_F8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); +} + +static void setup_core_msrs(void) +{ + wrmsrl(MSR_PMG_CST_CONFIG_CONTROL, + PKG_C_STATE_LIMIT_C2_MASK | CORE_C_STATE_LIMIT_C10_MASK | + IO_MWAIT_REDIRECT_MASK | CST_CFG_LOCK_MASK); + /* Power Management I/O base address for I/O trapping to C-states */ + wrmsrl(MSR_PMG_IO_CAPTURE_ADR, ACPI_PMIO_CST_REG | + (PMG_IO_BASE_CST_RNG_BLK_SIZE << 16)); + /* Disable C1E */ + msr_clrsetbits_64(MSR_POWER_CTL, 0x2, 0); + /* Disable support for MONITOR and MWAIT instructions */ + msr_clrsetbits_64(MSR_IA32_MISC_ENABLE, MISC_ENABLE_MWAIT, 0); + /* + * Enable and Lock the Advanced Encryption Standard (AES-NI) + * feature register + */ + msr_clrsetbits_64(MSR_FEATURE_CONFIG, FEATURE_CONFIG_RESERVED_MASK, + FEATURE_CONFIG_LOCK); + + update_fixed_mtrrs(); +} + +static int soc_core_init(void) +{ + struct udevice *pmc; + int ret; + + /* Clear out pending MCEs */ + cpu_mca_configure(); + + /* Set core MSRs */ + setup_core_msrs(); + /* + * Enable ACPI PM timer emulation, which also lets microcode know + * location of ACPI_BASE_ADDRESS. This also enables other features + * implemented in microcode. + */ + ret = uclass_first_device_err(UCLASS_ACPI_PMC, &pmc); + if (ret) + return log_msg_ret("PMC", ret); + enable_pm_timer_emulation(pmc); + + return 0; +} + +static int cpu_apl_probe(struct udevice *dev) +{ + if (gd->flags & GD_FLG_RELOC) { + int ret; + + ret = soc_core_init(); + if (ret) + return log_ret(ret); + } + + return 0; +} + struct acpi_ops apl_cpu_acpi_ops = { .fill_ssdt = acpi_cpu_fill_ssdt, }; @@ -107,6 +190,7 @@ U_BOOT_DRIVER(intel_apl_cpu) = { .id = UCLASS_CPU, .of_match = cpu_x86_apl_ids, .bind = cpu_x86_bind, + .probe = cpu_apl_probe, .ops = &cpu_x86_apl_ops, ACPI_OPS_PTR(&apl_cpu_acpi_ops) .flags = DM_FLAG_PRE_RELOC, diff --git a/arch/x86/cpu/apollolake/cpu_common.c b/arch/x86/cpu/apollolake/cpu_common.c index ba6bda37bc5..63f6999b024 100644 --- a/arch/x86/cpu/apollolake/cpu_common.c +++ b/arch/x86/cpu/apollolake/cpu_common.c @@ -4,8 +4,13 @@ */ #include <common.h> +#include <dm.h> +#include <log.h> #include <asm/cpu_common.h> #include <asm/msr.h> +#include <asm/arch/cpu.h> +#include <asm/arch/iomap.h> +#include <power/acpi_pmc.h> void cpu_flush_l1d_to_l2(void) { @@ -15,3 +20,23 @@ void cpu_flush_l1d_to_l2(void) msr.lo |= FLUSH_DL1_L2; msr_write(MSR_POWER_MISC, msr); } + +void enable_pm_timer_emulation(const struct udevice *pmc) +{ + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(pmc); + msr_t msr; + + /* + * The derived frequency is calculated as follows: + * (CTC_FREQ * msr[63:32]) >> 32 = target frequency. + * + * Back-solve the multiplier so the 3.579545MHz ACPI timer frequency is + * used. + */ + msr.hi = (3579545ULL << 32) / CTC_FREQ; + + /* Set PM1 timer IO port and enable */ + msr.lo = EMULATE_PM_TMR_EN | (upriv->acpi_base + R_ACPI_PM1_TMR); + debug("PM timer %x %x\n", msr.hi, msr.lo); + msr_write(MSR_EMULATE_PM_TIMER, msr); +} diff --git a/arch/x86/cpu/apollolake/cpu_spl.c b/arch/x86/cpu/apollolake/cpu_spl.c index 9f32f2e27e1..fafe4dbc0a0 100644 --- a/arch/x86/cpu/apollolake/cpu_spl.c +++ b/arch/x86/cpu/apollolake/cpu_spl.c @@ -114,26 +114,6 @@ static int fast_spi_cache_bios_region(void) return 0; } -static void enable_pm_timer_emulation(struct udevice *pmc) -{ - struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(pmc); - msr_t msr; - - /* - * The derived frequency is calculated as follows: - * (CTC_FREQ * msr[63:32]) >> 32 = target frequency. - * - * Back-solve the multiplier so the 3.579545MHz ACPI timer frequency is - * used. - */ - msr.hi = (3579545ULL << 32) / CTC_FREQ; - - /* Set PM1 timer IO port and enable */ - msr.lo = EMULATE_PM_TMR_EN | (upriv->acpi_base + R_ACPI_PM1_TMR); - debug("PM timer %x %x\n", msr.hi, msr.lo); - msr_write(MSR_EMULATE_PM_TIMER, msr); -} - static void google_chromeec_ioport_range(uint *out_basep, uint *out_sizep) { uint base; diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 39aa0f63c65..a51bf86f7ab 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -306,3 +306,22 @@ int cpu_get_cores_per_package(void) return cores; } + +void cpu_mca_configure(void) +{ + msr_t msr; + int i; + int num_banks; + + msr = msr_read(MSR_IA32_MCG_CAP); + num_banks = msr.lo & 0xff; + msr.lo = 0; + msr.hi = 0; + for (i = 0; i < num_banks; i++) { + /* Clear the machine check status */ + msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); + /* Initialise machine checks */ + msr_write(MSR_IA32_MC0_CTL + i * 4, + (msr_t) {.lo = 0xffffffff, .hi = 0xffffffff}); + } +} diff --git a/arch/x86/include/asm/arch-apollolake/cpu.h b/arch/x86/include/asm/arch-apollolake/cpu.h index 5e906c5e7d7..67d48c61098 100644 --- a/arch/x86/include/asm/arch-apollolake/cpu.h +++ b/arch/x86/include/asm/arch-apollolake/cpu.h @@ -15,6 +15,20 @@ #ifndef __ASSEMBLY__ /* Flush L1D to L2 */ void cpu_flush_l1d_to_l2(void); + +/** + * Enable emulation of the PM timer + * + * Some legacy OSes cannot tolerate the ACPI timer stoping during idle states, + * and this results in higher power consumption. ACPI timer emulation allows + * disabling of the ACPI Timer (PM1_TMR) to have no impact on the system, with + * the exception that TMR_STS will not be set on an overflow condition. All + * aligned 32-bit reads from the ACPI Timer port are valid and will behave as if + * the ACPI timer remains enabled. + * + * @pmc: PMC device + */ +void enable_pm_timer_emulation(const struct udevice *pmc); #endif #endif /* _ASM_ARCH_CPU_H */ diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 48f56c2aad9..2a5779a8e1a 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -184,4 +184,13 @@ int cpu_get_max_turbo_ratio(void); */ int cpu_get_cores_per_package(void); +/** + * cpu_mca_configure() - Set up machine-check exceptions ready for use + * + * These allow the SoC to report errors while running. See here for details: + * + * https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/machine-check-exceptions-debug-paper.pdf + */ +void cpu_mca_configure(void); + #endif diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 94e6b18e21c..c49b4225ac2 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -68,7 +68,18 @@ #define MSR_BSEL_CR_OVERCLOCK_CONTROL 0x000000cd #define MSR_PLATFORM_INFO 0x000000ce #define MSR_PMG_CST_CONFIG_CONTROL 0x000000e2 -#define SINGLE_PCTL (1 << 11) +/* Set MSR_PMG_CST_CONFIG_CONTROL[3:0] for Package C-State limit */ +#define PKG_C_STATE_LIMIT_C2_MASK BIT(1) +/* Set MSR_PMG_CST_CONFIG_CONTROL[7:4] for Core C-State limit*/ +#define CORE_C_STATE_LIMIT_C10_MASK 0x70 +/* Set MSR_PMG_CST_CONFIG_CONTROL[10] to IO redirect to MWAIT */ +#define IO_MWAIT_REDIRECT_MASK BIT(10) +/* Set MSR_PMG_CST_CONFIG_CONTROL[15] to lock CST_CFG [0-15] bits */ +#define CST_CFG_LOCK_MASK BIT(15) +#define SINGLE_PCTL BIT(11) + +/* ACPI PMIO Offset to C-state register */ +#define ACPI_PMIO_CST_REG (ACPI_BASE_ADDRESS + 0x14) #define MSR_MTRRcap 0x000000fe #define MSR_IA32_BBL_CR_CTL 0x00000119 @@ -83,6 +94,10 @@ #define EMULATE_PM_TMR_EN (1 << 16) #define EMULATE_DELAY_VALUE 0x13 +#define MSR_FEATURE_CONFIG 0x13c +#define FEATURE_CONFIG_RESERVED_MASK 0x3ULL +#define FEATURE_CONFIG_LOCK (1 << 0) + #define MSR_IA32_SYSENTER_CS 0x00000174 #define MSR_IA32_SYSENTER_ESP 0x00000175 #define MSR_IA32_SYSENTER_EIP 0x00000176 @@ -453,6 +468,9 @@ #define MSR_AMD_PERF_CTL 0xc0010062 #define MSR_PMG_CST_CONFIG_CTL 0x000000e2 +/* CST Range (R/W) IO port block size */ +#define PMG_IO_BASE_CST_RNG_BLK_SIZE 0x5 + #define MSR_PMG_IO_CAPTURE_ADR 0x000000e4 #define MSR_IA32_MPERF 0x000000e7 #define MSR_IA32_APERF 0x000000e8 -- 2.29.1.341.ge80a0c044ae-goog