coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
power_limit.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <console/console.h>
4 #include <cpu/x86/msr.h>
5 #include <intelblocks/cpulib.h>
7 #include <soc/msr.h>
8 #include <soc/systemagent.h>
9 
10 /* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
11 static const u8 power_limit_time_sec_to_msr[] = {
12  [0] = 0x00,
13  [1] = 0x0a,
14  [2] = 0x0b,
15  [3] = 0x4b,
16  [4] = 0x0c,
17  [5] = 0x2c,
18  [6] = 0x4c,
19  [7] = 0x6c,
20  [8] = 0x0d,
21  [10] = 0x2d,
22  [12] = 0x4d,
23  [14] = 0x6d,
24  [16] = 0x0e,
25  [20] = 0x2e,
26  [24] = 0x4e,
27  [28] = 0x6e,
28  [32] = 0x0f,
29  [40] = 0x2f,
30  [48] = 0x4f,
31  [56] = 0x6f,
32  [64] = 0x10,
33  [80] = 0x30,
34  [96] = 0x50,
35  [112] = 0x70,
36  [128] = 0x11,
37 };
38 
39 /* Convert POWER_LIMIT_1_TIME MSR value to seconds */
40 static const u8 power_limit_time_msr_to_sec[] = {
41  [0x00] = 0,
42  [0x0a] = 1,
43  [0x0b] = 2,
44  [0x4b] = 3,
45  [0x0c] = 4,
46  [0x2c] = 5,
47  [0x4c] = 6,
48  [0x6c] = 7,
49  [0x0d] = 8,
50  [0x2d] = 10,
51  [0x4d] = 12,
52  [0x6d] = 14,
53  [0x0e] = 16,
54  [0x2e] = 20,
55  [0x4e] = 24,
56  [0x6e] = 28,
57  [0x0f] = 32,
58  [0x2f] = 40,
59  [0x4f] = 48,
60  [0x6f] = 56,
61  [0x10] = 64,
62  [0x30] = 80,
63  [0x50] = 96,
64  [0x70] = 112,
65  [0x11] = 128,
66 };
67 
68 /*
69  * Configure processor power limits if possible
70  * This must be done AFTER set of BIOS_RESET_CPL
71  */
72 void set_power_limits(u8 power_limit_1_time,
73  struct soc_power_limits_config *conf)
74 {
76  msr_t limit;
77  unsigned int power_unit;
78  unsigned int tdp, min_power, max_power, max_time, tdp_pl2, tdp_pl1;
79  u8 power_limit_1_val;
80 
81  if (power_limit_1_time >= ARRAY_SIZE(power_limit_time_sec_to_msr))
82  power_limit_1_time =
84 
85  if (!(msr.lo & PLATFORM_INFO_SET_TDP))
86  return;
87 
88  /* Get units */
90  power_unit = 1 << (msr.lo & 0xf);
91 
92  /* Get power defaults for this SKU */
93  msr = rdmsr(MSR_PKG_POWER_SKU);
94  tdp = msr.lo & 0x7fff;
95  min_power = (msr.lo >> 16) & 0x7fff;
96  max_power = msr.hi & 0x7fff;
97  max_time = (msr.hi >> 16) & 0x7f;
98 
99  printk(BIOS_INFO, "CPU TDP = %u Watts\n", tdp / power_unit);
100 
101  if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time)
102  power_limit_1_time = power_limit_time_msr_to_sec[max_time];
103 
104  if (min_power > 0 && tdp < min_power)
105  tdp = min_power;
106 
107  if (max_power > 0 && tdp > max_power)
108  tdp = max_power;
109 
110  power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time];
111 
112  /* Set long term power limit to TDP */
113  limit.lo = 0;
114  tdp_pl1 = ((conf->tdp_pl1_override == 0) ?
115  tdp : (conf->tdp_pl1_override * power_unit));
116  printk(BIOS_INFO, "CPU PL1 = %u Watts\n", tdp_pl1 / power_unit);
117  limit.lo |= (tdp_pl1 & PKG_POWER_LIMIT_MASK);
118 
119  /* Set PL1 Pkg Power clamp bit */
120  limit.lo |= PKG_POWER_LIMIT_CLAMP;
121 
122  limit.lo |= PKG_POWER_LIMIT_EN;
123  limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) <<
125 
126  /* Set short term power limit to 1.25 * TDP if no config given */
127  limit.hi = 0;
128  tdp_pl2 = (conf->tdp_pl2_override == 0) ?
129  (tdp * 125) / 100 : (conf->tdp_pl2_override * power_unit);
130  printk(BIOS_INFO, "CPU PL2 = %u Watts\n", tdp_pl2 / power_unit);
131  limit.hi |= (tdp_pl2) & PKG_POWER_LIMIT_MASK;
132  limit.hi |= PKG_POWER_LIMIT_CLAMP;
133  limit.hi |= PKG_POWER_LIMIT_EN;
134 
135  /* Power limit 2 time is only programmable on server SKU */
136  wrmsr(MSR_PKG_POWER_LIMIT, limit);
137 
138  /* Set PL2 power limit values in MCHBAR and disable PL1 */
141 
142  /* Set PsysPl2 */
143  if (conf->tdp_psyspl2) {
145  limit.hi = 0;
146  printk(BIOS_INFO, "CPU PsysPL2 = %u Watts\n",
147  conf->tdp_psyspl2);
148  limit.hi |= (conf->tdp_psyspl2 * power_unit) &
150  limit.hi |= PKG_POWER_LIMIT_CLAMP;
151  limit.hi |= PKG_POWER_LIMIT_EN;
153  }
154 
155  /* Set PsysPl3 */
156  if (conf->tdp_psyspl3) {
157  limit = rdmsr(MSR_PL3_CONTROL);
158  limit.lo = 0;
159  printk(BIOS_INFO, "CPU PsysPL3 = %u Watts\n",
160  conf->tdp_psyspl3);
161  limit.lo |= (conf->tdp_psyspl3 * power_unit) &
163  /* Enable PsysPl3 */
164  limit.lo |= PKG_POWER_LIMIT_EN;
165  /* set PsysPl3 time window */
166  limit.lo |= (conf->tdp_psyspl3_time &
169  /* set PsysPl3 duty cycle */
170  limit.lo |= (conf->tdp_psyspl3_dutycycle &
173  wrmsr(MSR_PL3_CONTROL, limit);
174  }
175 
176  /* Set Pl4 */
177  if (conf->tdp_pl4) {
178  limit = rdmsr(MSR_VR_CURRENT_CONFIG);
179  limit.lo = 0;
180  printk(BIOS_INFO, "CPU PL4 = %u Watts\n", conf->tdp_pl4);
181  limit.lo |= (conf->tdp_pl4 * power_unit) &
184  }
185 
186  /* Set DDR RAPL power limit by copying from MMIO to MSR */
190 
191  /* Use nominal TDP values for CPUs with configurable TDP */
192  if (cpu_config_tdp_levels()) {
193  limit.hi = 0;
194  limit.lo = cpu_get_tdp_nominal_ratio();
196  }
197 }
198 
200 {
201  unsigned int power_unit, cpu_tdp;
202 
203  /* Get units */
205  power_unit = 1 << (msr.lo & 0xf);
206 
207  /* Get power defaults for this SKU */
208  msr = rdmsr(MSR_PKG_POWER_SKU);
209  cpu_tdp = msr.lo & 0x7fff;
210 
211  return cpu_tdp / power_unit;
212 }
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define MCHBAR32(x)
Definition: systemagent.h:23
#define printk(level,...)
Definition: stdlib.h:16
#define MSR_PKG_POWER_SKU
Definition: haswell.h:89
#define PKG_POWER_LIMIT_CLAMP
Definition: haswell.h:82
#define MSR_DDR_RAPL_LIMIT
Definition: haswell.h:90
#define MSR_TURBO_ACTIVATION_RATIO
Definition: haswell.h:99
#define MSR_PKG_POWER_LIMIT
Definition: haswell.h:79
#define PKG_POWER_LIMIT_TIME_SHIFT
Definition: haswell.h:83
#define PKG_POWER_LIMIT_TIME_MASK
Definition: haswell.h:84
#define PKG_POWER_LIMIT_MASK
Definition: haswell.h:80
#define PLATFORM_INFO_SET_TDP
Definition: haswell.h:39
#define MSR_VR_CURRENT_CONFIG
Definition: haswell.h:86
#define MSR_PKG_POWER_SKU_UNIT
Definition: haswell.h:88
int cpu_config_tdp_levels(void)
Definition: haswell_init.c:300
#define PKG_POWER_LIMIT_EN
Definition: haswell.h:81
u8 cpu_get_tdp_nominal_ratio(void)
Definition: cpulib.c:55
#define MSR_PLATFORM_INFO
Definition: fsb.c:16
#define MCH_DDR_POWER_LIMIT_HI
Definition: mchbar.h:34
#define MCH_PKG_POWER_LIMIT_LO
Definition: mchbar.h:30
#define MCH_DDR_POWER_LIMIT_LO
Definition: mchbar.h:33
#define MCH_PKG_POWER_LIMIT_HI
Definition: mchbar.h:31
static __always_inline msr_t rdmsr(unsigned int index)
Definition: msr.h:146
static __always_inline void wrmsr(unsigned int index, msr_t msr)
Definition: msr.h:157
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
static const u8 power_limit_time_sec_to_msr[]
Definition: power_limit.c:11
u8 get_cpu_tdp(void)
Definition: power_limit.c:199
void set_power_limits(u8 power_limit_1_time, struct soc_power_limits_config *conf)
Definition: power_limit.c:72
static const u8 power_limit_time_msr_to_sec[]
Definition: power_limit.c:40
enum soc_intel_alderlake_cpu_tdps cpu_tdp
Definition: chip.h:49
#define MSR_PL3_CONTROL
Definition: msr.h:11
#define MSR_PLATFORM_POWER_LIMIT
Definition: msr.h:13
#define PKG_POWER_LIMIT_DUTYCYCLE_SHIFT
Definition: msr.h:94
#define PKG_POWER_LIMIT_DUTYCYCLE_MASK
Definition: msr.h:95
uint8_t u8
Definition: stdint.h:45
unsigned int hi
Definition: msr.h:112
unsigned int lo
Definition: msr.h:111
uint32_t tdp_psyspl3_dutycycle
Definition: power_limit.h:32