Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License as |
| 8 | * published by the Free Software Foundation; version 2 of |
| 9 | * the License. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | #include <console/console.h> |
| 18 | #include <cpu/intel/turbo.h> |
| 19 | #include <cpu/x86/msr.h> |
| 20 | #include <arch/cpu.h> |
| 21 | |
Martin Roth | ffdee28 | 2017-06-24 13:43:40 -0600 | [diff] [blame] | 22 | #if IS_ENABLED(CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED) |
Aaron Durbin | ba6b07e | 2014-01-14 17:28:33 -0600 | [diff] [blame] | 23 | static inline int get_global_turbo_state(void) |
| 24 | { |
| 25 | return TURBO_UNKNOWN; |
| 26 | } |
| 27 | |
| 28 | static inline void set_global_turbo_state(int state) |
| 29 | { |
| 30 | } |
| 31 | #else |
| 32 | static int g_turbo_state = TURBO_UNKNOWN; |
| 33 | |
| 34 | static inline int get_global_turbo_state(void) |
| 35 | { |
| 36 | return g_turbo_state; |
| 37 | } |
| 38 | |
| 39 | static inline void set_global_turbo_state(int state) |
| 40 | { |
| 41 | g_turbo_state = state; |
| 42 | } |
| 43 | #endif |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 44 | |
Elyes HAOUAS | 6c9737b | 2018-07-08 12:30:02 +0200 | [diff] [blame] | 45 | static const char *const turbo_state_desc[] = { |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 46 | [TURBO_UNKNOWN] = "unknown", |
| 47 | [TURBO_UNAVAILABLE] = "unavailable", |
| 48 | [TURBO_DISABLED] = "available but hidden", |
| 49 | [TURBO_ENABLED] = "available and visible" |
| 50 | }; |
| 51 | |
| 52 | /* |
| 53 | * Determine the current state of Turbo and cache it for later. |
| 54 | * Turbo is a package level config so it does not need to be |
| 55 | * enabled on every core. |
| 56 | */ |
| 57 | int get_turbo_state(void) |
| 58 | { |
| 59 | struct cpuid_result cpuid_regs; |
| 60 | int turbo_en, turbo_cap; |
| 61 | msr_t msr; |
Aaron Durbin | ba6b07e | 2014-01-14 17:28:33 -0600 | [diff] [blame] | 62 | int turbo_state = get_global_turbo_state(); |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 63 | |
| 64 | /* Return cached state if available */ |
| 65 | if (turbo_state != TURBO_UNKNOWN) |
| 66 | return turbo_state; |
| 67 | |
| 68 | cpuid_regs = cpuid(CPUID_LEAF_PM); |
| 69 | turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE); |
| 70 | |
Elyes HAOUAS | 419bfbc | 2018-10-01 08:47:51 +0200 | [diff] [blame] | 71 | msr = rdmsr(IA32_MISC_ENABLE); |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 72 | turbo_en = !(msr.hi & H_MISC_DISABLE_TURBO); |
| 73 | |
| 74 | if (!turbo_cap && turbo_en) { |
| 75 | /* Unavailable */ |
| 76 | turbo_state = TURBO_UNAVAILABLE; |
| 77 | } else if (!turbo_cap && !turbo_en) { |
| 78 | /* Available but disabled */ |
| 79 | turbo_state = TURBO_DISABLED; |
| 80 | } else if (turbo_cap && turbo_en) { |
| 81 | /* Available */ |
| 82 | turbo_state = TURBO_ENABLED; |
| 83 | } |
| 84 | |
Aaron Durbin | ba6b07e | 2014-01-14 17:28:33 -0600 | [diff] [blame] | 85 | set_global_turbo_state(turbo_state); |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 86 | printk(BIOS_INFO, "Turbo is %s\n", turbo_state_desc[turbo_state]); |
| 87 | return turbo_state; |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | * Try to enable Turbo mode. |
| 92 | */ |
| 93 | void enable_turbo(void) |
| 94 | { |
| 95 | msr_t msr; |
| 96 | |
| 97 | /* Only possible if turbo is available but hidden */ |
| 98 | if (get_turbo_state() == TURBO_DISABLED) { |
| 99 | /* Clear Turbo Disable bit in Misc Enables */ |
Elyes HAOUAS | 419bfbc | 2018-10-01 08:47:51 +0200 | [diff] [blame] | 100 | msr = rdmsr(IA32_MISC_ENABLE); |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 101 | msr.hi &= ~H_MISC_DISABLE_TURBO; |
Elyes HAOUAS | 419bfbc | 2018-10-01 08:47:51 +0200 | [diff] [blame] | 102 | wrmsr(IA32_MISC_ENABLE, msr); |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 103 | |
| 104 | /* Update cached turbo state */ |
Aaron Durbin | ba6b07e | 2014-01-14 17:28:33 -0600 | [diff] [blame] | 105 | set_global_turbo_state(TURBO_ENABLED); |
Stefan Reinauer | ea37a21 | 2012-04-02 13:35:09 -0700 | [diff] [blame] | 106 | printk(BIOS_INFO, "Turbo has been enabled\n"); |
| 107 | } |
| 108 | } |
Subrata Banik | 7bde848 | 2017-05-02 19:35:42 +0530 | [diff] [blame] | 109 | |
| 110 | /* |
| 111 | * Try to disable Turbo mode. |
| 112 | */ |
| 113 | void disable_turbo(void) |
| 114 | { |
| 115 | msr_t msr; |
| 116 | |
| 117 | /* Set Turbo Disable bit in Misc Enables */ |
Elyes HAOUAS | 419bfbc | 2018-10-01 08:47:51 +0200 | [diff] [blame] | 118 | msr = rdmsr(IA32_MISC_ENABLE); |
Subrata Banik | 7bde848 | 2017-05-02 19:35:42 +0530 | [diff] [blame] | 119 | msr.hi |= H_MISC_DISABLE_TURBO; |
Elyes HAOUAS | 419bfbc | 2018-10-01 08:47:51 +0200 | [diff] [blame] | 120 | wrmsr(IA32_MISC_ENABLE, msr); |
Subrata Banik | 7bde848 | 2017-05-02 19:35:42 +0530 | [diff] [blame] | 121 | |
| 122 | /* Update cached turbo state */ |
| 123 | set_global_turbo_state(TURBO_UNAVAILABLE); |
| 124 | printk(BIOS_INFO, "Turbo has been disabled\n"); |
| 125 | } |