Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  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
 15static struct auto_mode_mode_config config_store;
 16static const char *state_as_str(unsigned int state);
 17
 18static 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
 38static 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
 56void 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
111void 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
126static 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
145static 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
161static 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
267int 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
284void amd_pmf_handle_amt(struct amd_pmf_dev *dev)
285{
286	amd_pmf_set_automode(dev, config_store.current_mode, NULL);
287}
288
289void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev)
290{
291	cancel_delayed_work_sync(&dev->work_buffer);
292}
293
294void 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}