xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/power_limit/power_limit.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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