uboot/arch/x86/cpu/ivybridge/model_206ax.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * From Coreboot file of same name
   4 *
   5 * Copyright (C) 2007-2009 coresystems GmbH
   6 * Copyright (C) 2011 The Chromium Authors
   7 */
   8
   9#include <common.h>
  10#include <cpu.h>
  11#include <dm.h>
  12#include <fdtdec.h>
  13#include <malloc.h>
  14#include <asm/cpu.h>
  15#include <asm/cpu_common.h>
  16#include <asm/cpu_x86.h>
  17#include <asm/msr.h>
  18#include <asm/msr-index.h>
  19#include <asm/mtrr.h>
  20#include <asm/processor.h>
  21#include <asm/speedstep.h>
  22#include <asm/turbo.h>
  23#include <asm/arch/model_206ax.h>
  24
  25DECLARE_GLOBAL_DATA_PTR;
  26
  27static void enable_vmx(void)
  28{
  29        struct cpuid_result regs;
  30#ifdef CONFIG_ENABLE_VMX
  31        int enable = true;
  32#else
  33        int enable = false;
  34#endif
  35        msr_t msr;
  36
  37        regs = cpuid(1);
  38        /* Check that the VMX is supported before reading or writing the MSR. */
  39        if (!((regs.ecx & CPUID_VMX) || (regs.ecx & CPUID_SMX)))
  40                return;
  41
  42        msr = msr_read(MSR_IA32_FEATURE_CONTROL);
  43
  44        if (msr.lo & (1 << 0)) {
  45                debug("VMX is locked, so %s will do nothing\n", __func__);
  46                /* VMX locked. If we set it again we get an illegal
  47                 * instruction
  48                 */
  49                return;
  50        }
  51
  52        /* The IA32_FEATURE_CONTROL MSR may initialize with random values.
  53         * It must be cleared regardless of VMX config setting.
  54         */
  55        msr.hi = 0;
  56        msr.lo = 0;
  57
  58        debug("%s VMX\n", enable ? "Enabling" : "Disabling");
  59
  60        /*
  61         * Even though the Intel manual says you must set the lock bit in
  62         * addition to the VMX bit in order for VMX to work, it is incorrect.
  63         * Thus we leave it unlocked for the OS to manage things itself.
  64         * This is good for a few reasons:
  65         * - No need to reflash the bios just to toggle the lock bit.
  66         * - The VMX bits really really should match each other across cores,
  67         *   so hard locking it on one while another has the opposite setting
  68         *   can easily lead to crashes as code using VMX migrates between
  69         *   them.
  70         * - Vendors that want to "upsell" from a bios that disables+locks to
  71         *   one that doesn't is sleazy.
  72         * By leaving this to the OS (e.g. Linux), people can do exactly what
  73         * they want on the fly, and do it correctly (e.g. across multiple
  74         * cores).
  75         */
  76        if (enable) {
  77                msr.lo |= (1 << 2);
  78                if (regs.ecx & CPUID_SMX)
  79                        msr.lo |= (1 << 1);
  80        }
  81
  82        msr_write(MSR_IA32_FEATURE_CONTROL, msr);
  83}
  84
  85/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
  86static const u8 power_limit_time_sec_to_msr[] = {
  87        [0]   = 0x00,
  88        [1]   = 0x0a,
  89        [2]   = 0x0b,
  90        [3]   = 0x4b,
  91        [4]   = 0x0c,
  92        [5]   = 0x2c,
  93        [6]   = 0x4c,
  94        [7]   = 0x6c,
  95        [8]   = 0x0d,
  96        [10]  = 0x2d,
  97        [12]  = 0x4d,
  98        [14]  = 0x6d,
  99        [16]  = 0x0e,
 100        [20]  = 0x2e,
 101        [24]  = 0x4e,
 102        [28]  = 0x6e,
 103        [32]  = 0x0f,
 104        [40]  = 0x2f,
 105        [48]  = 0x4f,
 106        [56]  = 0x6f,
 107        [64]  = 0x10,
 108        [80]  = 0x30,
 109        [96]  = 0x50,
 110        [112] = 0x70,
 111        [128] = 0x11,
 112};
 113
 114/* Convert POWER_LIMIT_1_TIME MSR value to seconds */
 115static const u8 power_limit_time_msr_to_sec[] = {
 116        [0x00] = 0,
 117        [0x0a] = 1,
 118        [0x0b] = 2,
 119        [0x4b] = 3,
 120        [0x0c] = 4,
 121        [0x2c] = 5,
 122        [0x4c] = 6,
 123        [0x6c] = 7,
 124        [0x0d] = 8,
 125        [0x2d] = 10,
 126        [0x4d] = 12,
 127        [0x6d] = 14,
 128        [0x0e] = 16,
 129        [0x2e] = 20,
 130        [0x4e] = 24,
 131        [0x6e] = 28,
 132        [0x0f] = 32,
 133        [0x2f] = 40,
 134        [0x4f] = 48,
 135        [0x6f] = 56,
 136        [0x10] = 64,
 137        [0x30] = 80,
 138        [0x50] = 96,
 139        [0x70] = 112,
 140        [0x11] = 128,
 141};
 142
 143bool cpu_ivybridge_config_tdp_levels(void)
 144{
 145        struct cpuid_result result;
 146
 147        /* Minimum CPU revision */
 148        result = cpuid(1);
 149        if (result.eax < IVB_CONFIG_TDP_MIN_CPUID)
 150                return false;
 151
 152        return cpu_config_tdp_levels();
 153}
 154
 155/*
 156 * Configure processor power limits if possible
 157 * This must be done AFTER set of BIOS_RESET_CPL
 158 */
 159void set_power_limits(u8 power_limit_1_time)
 160{
 161        msr_t msr = msr_read(MSR_PLATFORM_INFO);
 162        msr_t limit;
 163        unsigned power_unit;
 164        unsigned tdp, min_power, max_power, max_time;
 165        u8 power_limit_1_val;
 166
 167        if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr))
 168                return;
 169
 170        if (!(msr.lo & PLATFORM_INFO_SET_TDP))
 171                return;
 172
 173        /* Get units */
 174        msr = msr_read(MSR_PKG_POWER_SKU_UNIT);
 175        power_unit = 2 << ((msr.lo & 0xf) - 1);
 176
 177        /* Get power defaults for this SKU */
 178        msr = msr_read(MSR_PKG_POWER_SKU);
 179        tdp = msr.lo & 0x7fff;
 180        min_power = (msr.lo >> 16) & 0x7fff;
 181        max_power = msr.hi & 0x7fff;
 182        max_time = (msr.hi >> 16) & 0x7f;
 183
 184        debug("CPU TDP: %u Watts\n", tdp / power_unit);
 185
 186        if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time)
 187                power_limit_1_time = power_limit_time_msr_to_sec[max_time];
 188
 189        if (min_power > 0 && tdp < min_power)
 190                tdp = min_power;
 191
 192        if (max_power > 0 && tdp > max_power)
 193                tdp = max_power;
 194
 195        power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time];
 196
 197        /* Set long term power limit to TDP */
 198        limit.lo = 0;
 199        limit.lo |= tdp & PKG_POWER_LIMIT_MASK;
 200        limit.lo |= PKG_POWER_LIMIT_EN;
 201        limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) <<
 202                PKG_POWER_LIMIT_TIME_SHIFT;
 203
 204        /* Set short term power limit to 1.25 * TDP */
 205        limit.hi = 0;
 206        limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK;
 207        limit.hi |= PKG_POWER_LIMIT_EN;
 208        /* Power limit 2 time is only programmable on SNB EP/EX */
 209
 210        msr_write(MSR_PKG_POWER_LIMIT, limit);
 211
 212        /* Use nominal TDP values for CPUs with configurable TDP */
 213        if (cpu_ivybridge_config_tdp_levels()) {
 214                msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
 215                limit.hi = 0;
 216                limit.lo = msr.lo & 0xff;
 217                msr_write(MSR_TURBO_ACTIVATION_RATIO, limit);
 218        }
 219}
 220
 221static void configure_c_states(void)
 222{
 223        struct cpuid_result result;
 224        msr_t msr;
 225
 226        msr = msr_read(MSR_PMG_CST_CONFIG_CTL);
 227        msr.lo |= (1 << 28);    /* C1 Auto Undemotion Enable */
 228        msr.lo |= (1 << 27);    /* C3 Auto Undemotion Enable */
 229        msr.lo |= (1 << 26);    /* C1 Auto Demotion Enable */
 230        msr.lo |= (1 << 25);    /* C3 Auto Demotion Enable */
 231        msr.lo &= ~(1 << 10);   /* Disable IO MWAIT redirection */
 232        msr.lo |= 7;            /* No package C-state limit */
 233        msr_write(MSR_PMG_CST_CONFIG_CTL, msr);
 234
 235        msr = msr_read(MSR_PMG_IO_CAPTURE_ADR);
 236        msr.lo &= ~0x7ffff;
 237        msr.lo |= (PMB0_BASE + 4);      /* LVL_2 base address */
 238        msr.lo |= (2 << 16);            /* CST Range: C7 is max C-state */
 239        msr_write(MSR_PMG_IO_CAPTURE_ADR, msr);
 240
 241        msr = msr_read(MSR_MISC_PWR_MGMT);
 242        msr.lo &= ~(1 << 0);    /* Enable P-state HW_ALL coordination */
 243        msr_write(MSR_MISC_PWR_MGMT, msr);
 244
 245        msr = msr_read(MSR_POWER_CTL);
 246        msr.lo |= (1 << 18);    /* Enable Energy Perf Bias MSR 0x1b0 */
 247        msr.lo |= (1 << 1);     /* C1E Enable */
 248        msr.lo |= (1 << 0);     /* Bi-directional PROCHOT# */
 249        msr_write(MSR_POWER_CTL, msr);
 250
 251        /* C3 Interrupt Response Time Limit */
 252        msr.hi = 0;
 253        msr.lo = IRTL_VALID | IRTL_1024_NS | 0x50;
 254        msr_write(MSR_PKGC3_IRTL, msr);
 255
 256        /* C6 Interrupt Response Time Limit */
 257        msr.hi = 0;
 258        msr.lo = IRTL_VALID | IRTL_1024_NS | 0x68;
 259        msr_write(MSR_PKGC6_IRTL, msr);
 260
 261        /* C7 Interrupt Response Time Limit */
 262        msr.hi = 0;
 263        msr.lo = IRTL_VALID | IRTL_1024_NS | 0x6D;
 264        msr_write(MSR_PKGC7_IRTL, msr);
 265
 266        /* Primary Plane Current Limit */
 267        msr = msr_read(MSR_PP0_CURRENT_CONFIG);
 268        msr.lo &= ~0x1fff;
 269        msr.lo |= PP0_CURRENT_LIMIT;
 270        msr_write(MSR_PP0_CURRENT_CONFIG, msr);
 271
 272        /* Secondary Plane Current Limit */
 273        msr = msr_read(MSR_PP1_CURRENT_CONFIG);
 274        msr.lo &= ~0x1fff;
 275        result = cpuid(1);
 276        if (result.eax >= 0x30600)
 277                msr.lo |= PP1_CURRENT_LIMIT_IVB;
 278        else
 279                msr.lo |= PP1_CURRENT_LIMIT_SNB;
 280        msr_write(MSR_PP1_CURRENT_CONFIG, msr);
 281}
 282
 283static void configure_misc(void)
 284{
 285        msr_t msr;
 286
 287        msr = msr_read(IA32_MISC_ENABLE);
 288        msr.lo |= (1 << 0);       /* Fast String enable */
 289        msr.lo |= (1 << 3);       /* TM1/TM2/EMTTM enable */
 290        msr.lo |= (1 << 16);      /* Enhanced SpeedStep Enable */
 291        msr_write(IA32_MISC_ENABLE, msr);
 292
 293        /* Disable Thermal interrupts */
 294        msr.lo = 0;
 295        msr.hi = 0;
 296        msr_write(IA32_THERM_INTERRUPT, msr);
 297
 298        /* Enable package critical interrupt only */
 299        msr.lo = 1 << 4;
 300        msr.hi = 0;
 301        msr_write(IA32_PACKAGE_THERM_INTERRUPT, msr);
 302}
 303
 304static void enable_lapic_tpr(void)
 305{
 306        msr_t msr;
 307
 308        msr = msr_read(MSR_PIC_MSG_CONTROL);
 309        msr.lo &= ~(1 << 10);   /* Enable APIC TPR updates */
 310        msr_write(MSR_PIC_MSG_CONTROL, msr);
 311}
 312
 313static void configure_dca_cap(void)
 314{
 315        struct cpuid_result cpuid_regs;
 316        msr_t msr;
 317
 318        /* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */
 319        cpuid_regs = cpuid(1);
 320        if (cpuid_regs.ecx & (1 << 18)) {
 321                msr = msr_read(IA32_PLATFORM_DCA_CAP);
 322                msr.lo |= 1;
 323                msr_write(IA32_PLATFORM_DCA_CAP, msr);
 324        }
 325}
 326
 327static void set_max_ratio(void)
 328{
 329        msr_t msr;
 330        uint ratio;
 331
 332        /* Check for configurable TDP option */
 333        if (cpu_ivybridge_config_tdp_levels()) {
 334                /* Set to nominal TDP ratio */
 335                msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
 336                ratio = msr.lo & 0xff;
 337        } else {
 338                /* Platform Info bits 15:8 give max ratio */
 339                msr = msr_read(MSR_PLATFORM_INFO);
 340                ratio = (msr.lo & 0xff00) >> 8;
 341        }
 342        cpu_set_perf_control(ratio);
 343}
 344
 345static void set_energy_perf_bias(u8 policy)
 346{
 347        msr_t msr;
 348
 349        /* Energy Policy is bits 3:0 */
 350        msr = msr_read(IA32_ENERGY_PERFORMANCE_BIAS);
 351        msr.lo &= ~0xf;
 352        msr.lo |= policy & 0xf;
 353        msr_write(IA32_ENERGY_PERFORMANCE_BIAS, msr);
 354
 355        debug("model_x06ax: energy policy set to %u\n", policy);
 356}
 357
 358static void configure_mca(void)
 359{
 360        msr_t msr;
 361        int i;
 362
 363        msr.lo = 0;
 364        msr.hi = 0;
 365        /* This should only be done on a cold boot */
 366        for (i = 0; i < 7; i++)
 367                msr_write(IA32_MC0_STATUS + (i * 4), msr);
 368}
 369
 370static int model_206ax_init(struct udevice *dev)
 371{
 372        int ret;
 373
 374        /* Clear out pending MCEs */
 375        configure_mca();
 376
 377        /* Enable the local cpu apics */
 378        enable_lapic_tpr();
 379
 380        /* Enable virtualization if enabled in CMOS */
 381        enable_vmx();
 382
 383        /* Configure C States */
 384        configure_c_states();
 385
 386        /* Configure Enhanced SpeedStep and Thermal Sensors */
 387        configure_misc();
 388
 389        /* Thermal throttle activation offset */
 390        ret = cpu_configure_thermal_target(dev);
 391        if (ret) {
 392                debug("Cannot set thermal target\n");
 393                if (ret != -ENOENT)
 394                        return ret;
 395        }
 396
 397        /* Enable Direct Cache Access */
 398        configure_dca_cap();
 399
 400        /* Set energy policy */
 401        set_energy_perf_bias(ENERGY_POLICY_NORMAL);
 402
 403        /* Set Max Ratio */
 404        set_max_ratio();
 405
 406        /* Enable Turbo */
 407        turbo_enable();
 408
 409        return 0;
 410}
 411
 412static int model_206ax_get_info(struct udevice *dev, struct cpu_info *info)
 413{
 414        return cpu_intel_get_info(info, INTEL_BCLK_MHZ);
 415
 416        return 0;
 417}
 418
 419static int model_206ax_get_count(struct udevice *dev)
 420{
 421        return 4;
 422}
 423
 424static int cpu_x86_model_206ax_probe(struct udevice *dev)
 425{
 426        if (dev->seq == 0)
 427                model_206ax_init(dev);
 428
 429        return 0;
 430}
 431
 432static const struct cpu_ops cpu_x86_model_206ax_ops = {
 433        .get_desc       = cpu_x86_get_desc,
 434        .get_info       = model_206ax_get_info,
 435        .get_count      = model_206ax_get_count,
 436        .get_vendor     = cpu_x86_get_vendor,
 437};
 438
 439static const struct udevice_id cpu_x86_model_206ax_ids[] = {
 440        { .compatible = "intel,core-gen3" },
 441        { }
 442};
 443
 444U_BOOT_DRIVER(cpu_x86_model_206ax_drv) = {
 445        .name           = "cpu_x86_model_206ax",
 446        .id             = UCLASS_CPU,
 447        .of_match       = cpu_x86_model_206ax_ids,
 448        .bind           = cpu_x86_bind,
 449        .probe          = cpu_x86_model_206ax_probe,
 450        .ops            = &cpu_x86_model_206ax_ops,
 451        .flags          = DM_FLAG_PRE_RELOC,
 452};
 453