1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #include <console/console.h>
4 #include <cpu/x86/msr.h>
5 #include <device/pci_ops.h>
6 #include <drivers/intel/dptf/chip.h>
7 #include <intelblocks/cpulib.h>
8 #include <intelblocks/power_limit.h>
9 #include <soc/msr.h>
10 #include <soc/pci_devs.h>
11 #include <soc/soc_chip.h>
12 #include <soc/systemagent.h>
13
14 /* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
15 static const u8 power_limit_time_sec_to_msr[] = {
16 [0] = 0x00,
17 [1] = 0x0a,
18 [2] = 0x0b,
19 [3] = 0x4b,
20 [4] = 0x0c,
21 [5] = 0x2c,
22 [6] = 0x4c,
23 [7] = 0x6c,
24 [8] = 0x0d,
25 [10] = 0x2d,
26 [12] = 0x4d,
27 [14] = 0x6d,
28 [16] = 0x0e,
29 [20] = 0x2e,
30 [24] = 0x4e,
31 [28] = 0x6e,
32 [32] = 0x0f,
33 [40] = 0x2f,
34 [48] = 0x4f,
35 [56] = 0x6f,
36 [64] = 0x10,
37 [80] = 0x30,
38 [96] = 0x50,
39 [112] = 0x70,
40 [128] = 0x11,
41 };
42
43 /* Convert POWER_LIMIT_1_TIME MSR value to seconds */
44 static const u8 power_limit_time_msr_to_sec[] = {
45 [0x00] = 0,
46 [0x0a] = 1,
47 [0x0b] = 2,
48 [0x4b] = 3,
49 [0x0c] = 4,
50 [0x2c] = 5,
51 [0x4c] = 6,
52 [0x6c] = 7,
53 [0x0d] = 8,
54 [0x2d] = 10,
55 [0x4d] = 12,
56 [0x6d] = 14,
57 [0x0e] = 16,
58 [0x2e] = 20,
59 [0x4e] = 24,
60 [0x6e] = 28,
61 [0x0f] = 32,
62 [0x2f] = 40,
63 [0x4f] = 48,
64 [0x6f] = 56,
65 [0x10] = 64,
66 [0x30] = 80,
67 [0x50] = 96,
68 [0x70] = 112,
69 [0x11] = 128,
70 };
71
72 /*
73 * Configure processor power limits if possible
74 * This must be done AFTER set of BIOS_RESET_CPL
75 */
set_power_limits(u8 power_limit_1_time,struct soc_power_limits_config * conf)76 void set_power_limits(u8 power_limit_1_time,
77 struct soc_power_limits_config *conf)
78 {
79 msr_t msr;
80 msr_t limit;
81 unsigned int power_unit;
82 unsigned int tdp, min_power, max_power, max_time, tdp_pl2, tdp_pl1;
83 u8 power_limit_1_val;
84 uint32_t value;
85
86 if (CONFIG(SOC_INTEL_DISABLE_POWER_LIMITS)) {
87 printk(BIOS_INFO, "Disabling RAPL\n");
88 if (CONFIG(SOC_INTEL_RAPL_DISABLE_VIA_MCHBAR)) {
89 value = MCHBAR32(MCH_PKG_POWER_LIMIT_LO);
90 MCHBAR32(MCH_PKG_POWER_LIMIT_LO) = value & ~(PKG_POWER_LIMIT_EN);
91 value = MCHBAR32(MCH_PKG_POWER_LIMIT_HI);
92 MCHBAR32(MCH_PKG_POWER_LIMIT_HI) = value & ~(PKG_POWER_LIMIT_EN);
93 } else {
94 msr = rdmsr(MSR_PKG_POWER_LIMIT);
95 msr.lo &= ~PKG_POWER_LIMIT_EN;
96 msr.hi &= ~PKG_POWER_LIMIT_EN;
97 wrmsr(MSR_PKG_POWER_LIMIT, msr);
98 }
99 return;
100 }
101
102 if (power_limit_1_time >= ARRAY_SIZE(power_limit_time_sec_to_msr))
103 power_limit_1_time = ARRAY_SIZE(power_limit_time_sec_to_msr) - 1;
104
105 msr = rdmsr(MSR_PLATFORM_INFO);
106 if (!(msr.lo & PLATFORM_INFO_SET_TDP))
107 return;
108
109 /* Get units */
110 msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
111 power_unit = 1 << (msr.lo & 0xf);
112
113 /* Get power defaults for this SKU */
114 msr = rdmsr(MSR_PKG_POWER_SKU);
115 tdp = msr.lo & 0x7fff;
116 min_power = (msr.lo >> 16) & 0x7fff;
117 max_power = msr.hi & 0x7fff;
118 max_time = (msr.hi >> 16) & 0x7f;
119
120 printk(BIOS_INFO, "CPU TDP = %u Watts\n", tdp / power_unit);
121
122 if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time)
123 power_limit_1_time = power_limit_time_msr_to_sec[max_time];
124
125 if (min_power > 0 && tdp < min_power)
126 tdp = min_power;
127
128 if (max_power > 0 && tdp > max_power)
129 tdp = max_power;
130
131 power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time];
132
133 /* Set long term power limit to TDP */
134 limit.lo = 0;
135 tdp_pl1 = ((conf->tdp_pl1_override == 0) ?
136 tdp : (conf->tdp_pl1_override * power_unit));
137 printk(BIOS_INFO, "CPU PL1 = %u Watts\n", tdp_pl1 / power_unit);
138 limit.lo |= (tdp_pl1 & PKG_POWER_LIMIT_MASK);
139
140 /* Set PL1 Pkg Power clamp bit */
141 limit.lo |= PKG_POWER_LIMIT_CLAMP;
142
143 limit.lo |= PKG_POWER_LIMIT_EN;
144 limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) <<
145 PKG_POWER_LIMIT_TIME_SHIFT;
146
147 /* Set short term power limit to 1.25 * TDP if no config given */
148 limit.hi = 0;
149 tdp_pl2 = (conf->tdp_pl2_override == 0) ?
150 (tdp * 125) / 100 : (conf->tdp_pl2_override * power_unit);
151 printk(BIOS_INFO, "CPU PL2 = %u Watts\n", tdp_pl2 / power_unit);
152 limit.hi |= (tdp_pl2) & PKG_POWER_LIMIT_MASK;
153 limit.hi |= PKG_POWER_LIMIT_CLAMP;
154 limit.hi |= PKG_POWER_LIMIT_EN;
155
156 /* Power limit 2 time is only programmable on server SKU */
157 wrmsr(MSR_PKG_POWER_LIMIT, limit);
158
159 /* Set PL2 power limit values in MCHBAR and disable PL1 */
160 MCHBAR32(MCH_PKG_POWER_LIMIT_LO) = limit.lo & (~(PKG_POWER_LIMIT_EN));
161 MCHBAR32(MCH_PKG_POWER_LIMIT_HI) = limit.hi;
162
163 /* Set PsysPl2 */
164 if (conf->tdp_psyspl2) {
165 limit = rdmsr(MSR_PLATFORM_POWER_LIMIT);
166 limit.hi = 0;
167 printk(BIOS_INFO, "CPU PsysPL2 = %u Watts\n",
168 conf->tdp_psyspl2);
169 limit.hi |= (conf->tdp_psyspl2 * power_unit) &
170 PKG_POWER_LIMIT_MASK;
171 limit.hi |= PKG_POWER_LIMIT_CLAMP;
172 limit.hi |= PKG_POWER_LIMIT_EN;
173 wrmsr(MSR_PLATFORM_POWER_LIMIT, limit);
174 }
175
176 /* Set PsysPl3 */
177 if (conf->tdp_psyspl3) {
178 limit = rdmsr(MSR_PL3_CONTROL);
179 limit.lo = 0;
180 printk(BIOS_INFO, "CPU PsysPL3 = %u Watts\n",
181 conf->tdp_psyspl3);
182 limit.lo |= (conf->tdp_psyspl3 * power_unit) &
183 PKG_POWER_LIMIT_MASK;
184 /* Enable PsysPl3 */
185 limit.lo |= PKG_POWER_LIMIT_EN;
186 /* set PsysPl3 time window */
187 limit.lo |= (conf->tdp_psyspl3_time &
188 PKG_POWER_LIMIT_TIME_MASK) <<
189 PKG_POWER_LIMIT_TIME_SHIFT;
190 /* set PsysPl3 duty cycle */
191 limit.lo |= (conf->tdp_psyspl3_dutycycle &
192 PKG_POWER_LIMIT_DUTYCYCLE_MASK) <<
193 PKG_POWER_LIMIT_DUTYCYCLE_SHIFT;
194 wrmsr(MSR_PL3_CONTROL, limit);
195 }
196
197 /* Set Pl4 */
198 if (conf->tdp_pl4) {
199 limit = rdmsr(MSR_VR_CURRENT_CONFIG);
200 limit.lo = 0;
201 printk(BIOS_INFO, "CPU PL4 = %u Watts\n", conf->tdp_pl4);
202 limit.lo |= (conf->tdp_pl4 * power_unit) &
203 PKG_POWER_LIMIT_MASK;
204 wrmsr(MSR_VR_CURRENT_CONFIG, limit);
205 }
206
207 /* Set DDR RAPL power limit by copying from MMIO to MSR */
208 msr.lo = MCHBAR32(MCH_DDR_POWER_LIMIT_LO);
209 msr.hi = MCHBAR32(MCH_DDR_POWER_LIMIT_HI);
210 wrmsr(MSR_DDR_RAPL_LIMIT, msr);
211
212 /* Use nominal TDP values for CPUs with configurable TDP */
213 if (cpu_config_tdp_levels()) {
214 limit.hi = 0;
215 limit.lo = cpu_get_tdp_nominal_ratio();
216 wrmsr(MSR_TURBO_ACTIVATION_RATIO, limit);
217 }
218 }
219
get_cpu_tdp(void)220 u8 get_cpu_tdp(void)
221 {
222 unsigned int power_unit, cpu_tdp;
223
224 /* Get units */
225 msr_t msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
226 power_unit = 1 << (msr.lo & 0xf);
227
228 /* Get power defaults for this SKU */
229 msr = rdmsr(MSR_PKG_POWER_SKU);
230 cpu_tdp = msr.lo & 0x7fff;
231
232 return cpu_tdp / power_unit;
233 }
234
235 WEAK_DEV_PTR(dptf_policy);
236
237 #if CONFIG(SOC_INTEL_COMMON_BLOCK_VARIANT_POWER_LIMIT)
variant_update_cpu_power_limits(const struct cpu_tdp_power_limits * limits,size_t num_entries)238 void variant_update_cpu_power_limits(const struct cpu_tdp_power_limits *limits,
239 size_t num_entries)
240 {
241 if (!num_entries) {
242 printk(BIOS_INFO, "CPU Power limits entry not available\n");
243 return;
244 }
245
246 const struct device *policy_dev = DEV_PTR(dptf_policy);
247 if (!policy_dev)
248 return;
249
250 struct drivers_intel_dptf_config *config = policy_dev->chip_info;
251 if (!config) {
252 printk(BIOS_INFO, "DPTF is not enabled\n");
253 return;
254 }
255
256 uint16_t mch_id = pci_s_read_config16(PCI_DEV(0, 0, 0), PCI_DEVICE_ID);
257 if (mch_id == 0xffff) {
258 printk(BIOS_INFO, "No matching PCI DID present\n");
259 return;
260 }
261
262 uint8_t tdp = get_cpu_tdp();
263
264 for (size_t index = 0; index < num_entries; index++) {
265 if (mch_id != limits[index].mch_id || tdp != limits[index].cpu_tdp) {
266 continue;
267 } else {
268 struct dptf_power_limits *settings = &config->controls.power_limits;
269 config_t *conf = config_of_soc();
270 struct soc_power_limits_config *soc_config = conf->power_limits_config;
271 settings->pl1.min_power = limits[index].pl1_min_power;
272 settings->pl1.max_power = limits[index].pl1_max_power;
273 settings->pl2.min_power = limits[index].pl2_min_power;
274 settings->pl2.max_power = limits[index].pl2_max_power;
275 soc_config->tdp_pl4 = DIV_ROUND_UP(limits[index].pl4_power, MILLIWATTS_TO_WATTS);
276 printk(BIOS_INFO, "Overriding power limits PL1 (mW) (%u, %u) PL2 (mW) (%u, %u) PL4 (W) (%u)\n",
277 settings->pl1.min_power,
278 settings->pl1.max_power,
279 settings->pl2.min_power,
280 settings->pl2.max_power,
281 soc_config->tdp_pl4);
282 }
283 }
284 }
285 #endif
286