xref: /linux/drivers/platform/x86/amd/pmf/auto-mode.c (revision d6296cb65320be16dbf20f2fd584ddc25f3437cd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * AMD Platform Management Framework Driver
4  *
5  * Copyright (c) 2022, Advanced Micro Devices, Inc.
6  * All Rights Reserved.
7  *
8  * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
9  */
10 
11 #include <linux/acpi.h>
12 #include <linux/workqueue.h>
13 #include "pmf.h"
14 
15 static struct auto_mode_mode_config config_store;
16 static const char *state_as_str(unsigned int state);
17 
18 static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,
19 				 struct auto_mode_mode_config *table)
20 {
21 	struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control;
22 
23 	amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL);
24 	amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL);
25 	amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL);
26 	amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);
27 	amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);
28 	amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
29 			 pwr_ctrl->stt_skin_temp[STT_TEMP_APU], NULL);
30 	amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
31 			 pwr_ctrl->stt_skin_temp[STT_TEMP_HS2], NULL);
32 
33 	if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
34 		apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual,
35 				    config_store.mode_set[idx].fan_control.fan_id);
36 }
37 
38 static int amd_pmf_get_moving_avg(struct amd_pmf_dev *pdev, int socket_power)
39 {
40 	int i, total = 0;
41 
42 	if (pdev->socket_power_history_idx == -1) {
43 		for (i = 0; i < AVG_SAMPLE_SIZE; i++)
44 			pdev->socket_power_history[i] = socket_power;
45 	}
46 
47 	pdev->socket_power_history_idx = (pdev->socket_power_history_idx + 1) % AVG_SAMPLE_SIZE;
48 	pdev->socket_power_history[pdev->socket_power_history_idx] = socket_power;
49 
50 	for (i = 0; i < AVG_SAMPLE_SIZE; i++)
51 		total += pdev->socket_power_history[i];
52 
53 	return total / AVG_SAMPLE_SIZE;
54 }
55 
56 void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms)
57 {
58 	int avg_power = 0;
59 	bool update = false;
60 	int i, j;
61 
62 	/* Get the average moving average computed by auto mode algorithm */
63 	avg_power = amd_pmf_get_moving_avg(dev, socket_power);
64 
65 	for (i = 0; i < AUTO_TRANSITION_MAX; i++) {
66 		if ((config_store.transition[i].shifting_up && avg_power >=
67 		     config_store.transition[i].power_threshold) ||
68 		    (!config_store.transition[i].shifting_up && avg_power <=
69 		     config_store.transition[i].power_threshold)) {
70 			if (config_store.transition[i].timer <
71 			    config_store.transition[i].time_constant)
72 				config_store.transition[i].timer += time_elapsed_ms;
73 		} else {
74 			config_store.transition[i].timer = 0;
75 		}
76 
77 		if (config_store.transition[i].timer >=
78 		    config_store.transition[i].time_constant &&
79 		    !config_store.transition[i].applied) {
80 			config_store.transition[i].applied = true;
81 			update = true;
82 		} else if (config_store.transition[i].timer <=
83 			   config_store.transition[i].time_constant &&
84 			   config_store.transition[i].applied) {
85 			config_store.transition[i].applied = false;
86 			update = true;
87 		}
88 	}
89 
90 	dev_dbg(dev->dev, "[AUTO_MODE] avg power: %u mW mode: %s\n", avg_power,
91 		state_as_str(config_store.current_mode));
92 
93 	if (update) {
94 		for (j = 0; j < AUTO_TRANSITION_MAX; j++) {
95 			/* Apply the mode with highest priority indentified */
96 			if (config_store.transition[j].applied) {
97 				if (config_store.current_mode !=
98 				    config_store.transition[j].target_mode) {
99 					config_store.current_mode =
100 							config_store.transition[j].target_mode;
101 					dev_dbg(dev->dev, "[AUTO_MODE] moving to mode:%s\n",
102 						state_as_str(config_store.current_mode));
103 					amd_pmf_set_automode(dev, config_store.current_mode, NULL);
104 				}
105 				break;
106 			}
107 		}
108 	}
109 }
110 
111 void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event)
112 {
113 	int mode = config_store.current_mode;
114 
115 	config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode =
116 				   is_cql_event ? AUTO_PERFORMANCE_ON_LAP : AUTO_PERFORMANCE;
117 
118 	if ((mode == AUTO_PERFORMANCE || mode == AUTO_PERFORMANCE_ON_LAP) &&
119 	    mode != config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode) {
120 		mode = config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode;
121 		amd_pmf_set_automode(dev, mode, NULL);
122 	}
123 	dev_dbg(dev->dev, "updated CQL thermals\n");
124 }
125 
126 static void amd_pmf_get_power_threshold(void)
127 {
128 	config_store.transition[AUTO_TRANSITION_TO_QUIET].power_threshold =
129 				config_store.mode_set[AUTO_BALANCE].power_floor -
130 				config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta;
131 
132 	config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_threshold =
133 				config_store.mode_set[AUTO_BALANCE].power_floor -
134 				config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta;
135 
136 	config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_threshold =
137 			config_store.mode_set[AUTO_QUIET].power_floor -
138 			config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta;
139 
140 	config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_threshold =
141 		config_store.mode_set[AUTO_PERFORMANCE].power_floor -
142 		config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta;
143 }
144 
145 static const char *state_as_str(unsigned int state)
146 {
147 	switch (state) {
148 	case AUTO_QUIET:
149 		return "QUIET";
150 	case AUTO_BALANCE:
151 		return "BALANCED";
152 	case AUTO_PERFORMANCE_ON_LAP:
153 		return "ON_LAP";
154 	case AUTO_PERFORMANCE:
155 		return "PERFORMANCE";
156 	default:
157 		return "Unknown Auto Mode State";
158 	}
159 }
160 
161 static void amd_pmf_load_defaults_auto_mode(struct amd_pmf_dev *dev)
162 {
163 	struct apmf_auto_mode output;
164 	struct power_table_control *pwr_ctrl;
165 	int i;
166 
167 	apmf_get_auto_mode_def(dev, &output);
168 	/* time constant */
169 	config_store.transition[AUTO_TRANSITION_TO_QUIET].time_constant =
170 								output.balanced_to_quiet;
171 	config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].time_constant =
172 								output.balanced_to_perf;
173 	config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].time_constant =
174 								output.quiet_to_balanced;
175 	config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].time_constant =
176 								output.perf_to_balanced;
177 
178 	/* power floor */
179 	config_store.mode_set[AUTO_QUIET].power_floor = output.pfloor_quiet;
180 	config_store.mode_set[AUTO_BALANCE].power_floor = output.pfloor_balanced;
181 	config_store.mode_set[AUTO_PERFORMANCE].power_floor = output.pfloor_perf;
182 	config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_floor = output.pfloor_perf;
183 
184 	/* Power delta for mode change */
185 	config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta =
186 								output.pd_balanced_to_quiet;
187 	config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta =
188 								output.pd_balanced_to_perf;
189 	config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta =
190 								output.pd_quiet_to_balanced;
191 	config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta =
192 								output.pd_perf_to_balanced;
193 
194 	/* Power threshold */
195 	amd_pmf_get_power_threshold();
196 
197 	/* skin temperature limits */
198 	pwr_ctrl = &config_store.mode_set[AUTO_QUIET].power_control;
199 	pwr_ctrl->spl = output.spl_quiet;
200 	pwr_ctrl->sppt = output.sppt_quiet;
201 	pwr_ctrl->fppt = output.fppt_quiet;
202 	pwr_ctrl->sppt_apu_only = output.sppt_apu_only_quiet;
203 	pwr_ctrl->stt_min = output.stt_min_limit_quiet;
204 	pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_quiet;
205 	pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_quiet;
206 
207 	pwr_ctrl = &config_store.mode_set[AUTO_BALANCE].power_control;
208 	pwr_ctrl->spl = output.spl_balanced;
209 	pwr_ctrl->sppt = output.sppt_balanced;
210 	pwr_ctrl->fppt = output.fppt_balanced;
211 	pwr_ctrl->sppt_apu_only = output.sppt_apu_only_balanced;
212 	pwr_ctrl->stt_min = output.stt_min_limit_balanced;
213 	pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_balanced;
214 	pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_balanced;
215 
216 	pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE].power_control;
217 	pwr_ctrl->spl = output.spl_perf;
218 	pwr_ctrl->sppt = output.sppt_perf;
219 	pwr_ctrl->fppt = output.fppt_perf;
220 	pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf;
221 	pwr_ctrl->stt_min = output.stt_min_limit_perf;
222 	pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf;
223 	pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf;
224 
225 	pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_control;
226 	pwr_ctrl->spl = output.spl_perf_on_lap;
227 	pwr_ctrl->sppt = output.sppt_perf_on_lap;
228 	pwr_ctrl->fppt = output.fppt_perf_on_lap;
229 	pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf_on_lap;
230 	pwr_ctrl->stt_min = output.stt_min_limit_perf_on_lap;
231 	pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf_on_lap;
232 	pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf_on_lap;
233 
234 	/* Fan ID */
235 	config_store.mode_set[AUTO_QUIET].fan_control.fan_id = output.fan_id_quiet;
236 	config_store.mode_set[AUTO_BALANCE].fan_control.fan_id = output.fan_id_balanced;
237 	config_store.mode_set[AUTO_PERFORMANCE].fan_control.fan_id = output.fan_id_perf;
238 	config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].fan_control.fan_id =
239 									output.fan_id_perf;
240 
241 	config_store.transition[AUTO_TRANSITION_TO_QUIET].target_mode = AUTO_QUIET;
242 	config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode =
243 								AUTO_PERFORMANCE;
244 	config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].target_mode =
245 									AUTO_BALANCE;
246 	config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].target_mode =
247 									AUTO_BALANCE;
248 
249 	config_store.transition[AUTO_TRANSITION_TO_QUIET].shifting_up = false;
250 	config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].shifting_up = true;
251 	config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].shifting_up = true;
252 	config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].shifting_up =
253 										false;
254 
255 	for (i = 0 ; i < AUTO_MODE_MAX ; i++) {
256 		if (config_store.mode_set[i].fan_control.fan_id == FAN_INDEX_AUTO)
257 			config_store.mode_set[i].fan_control.manual = false;
258 		else
259 			config_store.mode_set[i].fan_control.manual = true;
260 	}
261 
262 	/* set to initial default values */
263 	config_store.current_mode = AUTO_BALANCE;
264 	dev->socket_power_history_idx = -1;
265 }
266 
267 int amd_pmf_reset_amt(struct amd_pmf_dev *dev)
268 {
269 	/*
270 	 * OEM BIOS implementation guide says that if the auto mode is enabled
271 	 * the platform_profile registration shall be done by the OEM driver.
272 	 * There could be cases where both static slider and auto mode BIOS
273 	 * functions are enabled, in that case enable static slider updates
274 	 * only if it advertised as supported.
275 	 */
276 
277 	if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
278 		dev_dbg(dev->dev, "resetting AMT thermals\n");
279 		amd_pmf_set_sps_power_limits(dev);
280 	}
281 	return 0;
282 }
283 
284 void amd_pmf_handle_amt(struct amd_pmf_dev *dev)
285 {
286 	amd_pmf_set_automode(dev, config_store.current_mode, NULL);
287 }
288 
289 void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev)
290 {
291 	cancel_delayed_work_sync(&dev->work_buffer);
292 }
293 
294 void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev)
295 {
296 	amd_pmf_load_defaults_auto_mode(dev);
297 	amd_pmf_init_metrics_table(dev);
298 }
299