442 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * AMD Platform Management Framework Driver4 *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 18#ifdef CONFIG_AMD_PMF_DEBUG19static void amd_pmf_dump_auto_mode_defaults(struct auto_mode_mode_config *data)20{21 struct auto_mode_mode_settings *its_mode;22 23 pr_debug("Auto Mode Data - BEGIN\n");24 25 /* time constant */26 pr_debug("balanced_to_perf: %u ms\n",27 data->transition[AUTO_TRANSITION_TO_PERFORMANCE].time_constant);28 pr_debug("perf_to_balanced: %u ms\n",29 data->transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].time_constant);30 pr_debug("quiet_to_balanced: %u ms\n",31 data->transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].time_constant);32 pr_debug("balanced_to_quiet: %u ms\n",33 data->transition[AUTO_TRANSITION_TO_QUIET].time_constant);34 35 /* power floor */36 pr_debug("pfloor_perf: %u mW\n", data->mode_set[AUTO_PERFORMANCE].power_floor);37 pr_debug("pfloor_balanced: %u mW\n", data->mode_set[AUTO_BALANCE].power_floor);38 pr_debug("pfloor_quiet: %u mW\n", data->mode_set[AUTO_QUIET].power_floor);39 40 /* Power delta for mode change */41 pr_debug("pd_balanced_to_perf: %u mW\n",42 data->transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta);43 pr_debug("pd_perf_to_balanced: %u mW\n",44 data->transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta);45 pr_debug("pd_quiet_to_balanced: %u mW\n",46 data->transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta);47 pr_debug("pd_balanced_to_quiet: %u mW\n",48 data->transition[AUTO_TRANSITION_TO_QUIET].power_delta);49 50 /* skin temperature limits */51 its_mode = &data->mode_set[AUTO_PERFORMANCE_ON_LAP];52 pr_debug("stt_apu_perf_on_lap: %u C\n",53 its_mode->power_control.stt_skin_temp[STT_TEMP_APU]);54 pr_debug("stt_hs2_perf_on_lap: %u C\n",55 its_mode->power_control.stt_skin_temp[STT_TEMP_HS2]);56 pr_debug("stt_min_limit_perf_on_lap: %u mW\n", its_mode->power_control.stt_min);57 58 its_mode = &data->mode_set[AUTO_PERFORMANCE];59 pr_debug("stt_apu_perf: %u C\n", its_mode->power_control.stt_skin_temp[STT_TEMP_APU]);60 pr_debug("stt_hs2_perf: %u C\n", its_mode->power_control.stt_skin_temp[STT_TEMP_HS2]);61 pr_debug("stt_min_limit_perf: %u mW\n", its_mode->power_control.stt_min);62 63 its_mode = &data->mode_set[AUTO_BALANCE];64 pr_debug("stt_apu_balanced: %u C\n", its_mode->power_control.stt_skin_temp[STT_TEMP_APU]);65 pr_debug("stt_hs2_balanced: %u C\n", its_mode->power_control.stt_skin_temp[STT_TEMP_HS2]);66 pr_debug("stt_min_limit_balanced: %u mW\n", its_mode->power_control.stt_min);67 68 its_mode = &data->mode_set[AUTO_QUIET];69 pr_debug("stt_apu_quiet: %u C\n", its_mode->power_control.stt_skin_temp[STT_TEMP_APU]);70 pr_debug("stt_hs2_quiet: %u C\n", its_mode->power_control.stt_skin_temp[STT_TEMP_HS2]);71 pr_debug("stt_min_limit_quiet: %u mW\n", its_mode->power_control.stt_min);72 73 /* SPL based power limits */74 its_mode = &data->mode_set[AUTO_PERFORMANCE_ON_LAP];75 pr_debug("fppt_perf_on_lap: %u mW\n", its_mode->power_control.fppt);76 pr_debug("sppt_perf_on_lap: %u mW\n", its_mode->power_control.sppt);77 pr_debug("spl_perf_on_lap: %u mW\n", its_mode->power_control.spl);78 pr_debug("sppt_apu_only_perf_on_lap: %u mW\n", its_mode->power_control.sppt_apu_only);79 80 its_mode = &data->mode_set[AUTO_PERFORMANCE];81 pr_debug("fppt_perf: %u mW\n", its_mode->power_control.fppt);82 pr_debug("sppt_perf: %u mW\n", its_mode->power_control.sppt);83 pr_debug("spl_perf: %u mW\n", its_mode->power_control.spl);84 pr_debug("sppt_apu_only_perf: %u mW\n", its_mode->power_control.sppt_apu_only);85 86 its_mode = &data->mode_set[AUTO_BALANCE];87 pr_debug("fppt_balanced: %u mW\n", its_mode->power_control.fppt);88 pr_debug("sppt_balanced: %u mW\n", its_mode->power_control.sppt);89 pr_debug("spl_balanced: %u mW\n", its_mode->power_control.spl);90 pr_debug("sppt_apu_only_balanced: %u mW\n", its_mode->power_control.sppt_apu_only);91 92 its_mode = &data->mode_set[AUTO_QUIET];93 pr_debug("fppt_quiet: %u mW\n", its_mode->power_control.fppt);94 pr_debug("sppt_quiet: %u mW\n", its_mode->power_control.sppt);95 pr_debug("spl_quiet: %u mW\n", its_mode->power_control.spl);96 pr_debug("sppt_apu_only_quiet: %u mW\n", its_mode->power_control.sppt_apu_only);97 98 /* Fan ID */99 pr_debug("fan_id_perf: %lu\n",100 data->mode_set[AUTO_PERFORMANCE].fan_control.fan_id);101 pr_debug("fan_id_balanced: %lu\n",102 data->mode_set[AUTO_BALANCE].fan_control.fan_id);103 pr_debug("fan_id_quiet: %lu\n",104 data->mode_set[AUTO_QUIET].fan_control.fan_id);105 106 pr_debug("Auto Mode Data - END\n");107}108#else109static void amd_pmf_dump_auto_mode_defaults(struct auto_mode_mode_config *data) {}110#endif111 112static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,113 struct auto_mode_mode_config *table)114{115 struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control;116 117 amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL);118 amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL);119 amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL);120 amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);121 amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);122 amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,123 pwr_ctrl->stt_skin_temp[STT_TEMP_APU], NULL);124 amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,125 pwr_ctrl->stt_skin_temp[STT_TEMP_HS2], NULL);126 127 if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))128 apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual,129 config_store.mode_set[idx].fan_control.fan_id);130}131 132static int amd_pmf_get_moving_avg(struct amd_pmf_dev *pdev, int socket_power)133{134 int i, total = 0;135 136 if (pdev->socket_power_history_idx == -1) {137 for (i = 0; i < AVG_SAMPLE_SIZE; i++)138 pdev->socket_power_history[i] = socket_power;139 }140 141 pdev->socket_power_history_idx = (pdev->socket_power_history_idx + 1) % AVG_SAMPLE_SIZE;142 pdev->socket_power_history[pdev->socket_power_history_idx] = socket_power;143 144 for (i = 0; i < AVG_SAMPLE_SIZE; i++)145 total += pdev->socket_power_history[i];146 147 return total / AVG_SAMPLE_SIZE;148}149 150void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms)151{152 int avg_power = 0;153 bool update = false;154 int i, j;155 156 /* Get the average moving average computed by auto mode algorithm */157 avg_power = amd_pmf_get_moving_avg(dev, socket_power);158 159 for (i = 0; i < AUTO_TRANSITION_MAX; i++) {160 if ((config_store.transition[i].shifting_up && avg_power >=161 config_store.transition[i].power_threshold) ||162 (!config_store.transition[i].shifting_up && avg_power <=163 config_store.transition[i].power_threshold)) {164 if (config_store.transition[i].timer <165 config_store.transition[i].time_constant)166 config_store.transition[i].timer += time_elapsed_ms;167 } else {168 config_store.transition[i].timer = 0;169 }170 171 if (config_store.transition[i].timer >=172 config_store.transition[i].time_constant &&173 !config_store.transition[i].applied) {174 config_store.transition[i].applied = true;175 update = true;176 } else if (config_store.transition[i].timer <=177 config_store.transition[i].time_constant &&178 config_store.transition[i].applied) {179 config_store.transition[i].applied = false;180 update = true;181 }182 183#ifdef CONFIG_AMD_PMF_DEBUG184 dev_dbg(dev->dev, "[AUTO MODE] average_power : %d mW mode: %s\n", avg_power,185 state_as_str(config_store.current_mode));186 187 dev_dbg(dev->dev, "[AUTO MODE] time: %lld ms timer: %u ms tc: %u ms\n",188 time_elapsed_ms, config_store.transition[i].timer,189 config_store.transition[i].time_constant);190 191 dev_dbg(dev->dev, "[AUTO MODE] shiftup: %u pt: %u mW pf: %u mW pd: %u mW\n",192 config_store.transition[i].shifting_up,193 config_store.transition[i].power_threshold,194 config_store.mode_set[i].power_floor,195 config_store.transition[i].power_delta);196#endif197 }198 199 dev_dbg(dev->dev, "[AUTO_MODE] avg power: %u mW mode: %s\n", avg_power,200 state_as_str(config_store.current_mode));201 202#ifdef CONFIG_AMD_PMF_DEBUG203 dev_dbg(dev->dev, "[AUTO MODE] priority1: %u priority2: %u priority3: %u priority4: %u\n",204 config_store.transition[0].applied,205 config_store.transition[1].applied,206 config_store.transition[2].applied,207 config_store.transition[3].applied);208#endif209 210 if (update) {211 for (j = 0; j < AUTO_TRANSITION_MAX; j++) {212 /* Apply the mode with highest priority indentified */213 if (config_store.transition[j].applied) {214 if (config_store.current_mode !=215 config_store.transition[j].target_mode) {216 config_store.current_mode =217 config_store.transition[j].target_mode;218 dev_dbg(dev->dev, "[AUTO_MODE] moving to mode:%s\n",219 state_as_str(config_store.current_mode));220 amd_pmf_set_automode(dev, config_store.current_mode, NULL);221 }222 break;223 }224 }225 }226}227 228void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event)229{230 int mode = config_store.current_mode;231 232 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode =233 is_cql_event ? AUTO_PERFORMANCE_ON_LAP : AUTO_PERFORMANCE;234 235 if ((mode == AUTO_PERFORMANCE || mode == AUTO_PERFORMANCE_ON_LAP) &&236 mode != config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode) {237 mode = config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode;238 amd_pmf_set_automode(dev, mode, NULL);239 }240 dev_dbg(dev->dev, "updated CQL thermals\n");241}242 243static void amd_pmf_get_power_threshold(void)244{245 config_store.transition[AUTO_TRANSITION_TO_QUIET].power_threshold =246 config_store.mode_set[AUTO_BALANCE].power_floor -247 config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta;248 249 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_threshold =250 config_store.mode_set[AUTO_BALANCE].power_floor -251 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta;252 253 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_threshold =254 config_store.mode_set[AUTO_QUIET].power_floor -255 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta;256 257 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_threshold =258 config_store.mode_set[AUTO_PERFORMANCE].power_floor -259 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta;260 261#ifdef CONFIG_AMD_PMF_DEBUG262 pr_debug("[AUTO MODE TO_QUIET] pt: %u mW pf: %u mW pd: %u mW\n",263 config_store.transition[AUTO_TRANSITION_TO_QUIET].power_threshold,264 config_store.mode_set[AUTO_BALANCE].power_floor,265 config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta);266 267 pr_debug("[AUTO MODE TO_PERFORMANCE] pt: %u mW pf: %u mW pd: %u mW\n",268 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_threshold,269 config_store.mode_set[AUTO_BALANCE].power_floor,270 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta);271 272 pr_debug("[AUTO MODE QUIET_TO_BALANCE] pt: %u mW pf: %u mW pd: %u mW\n",273 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE]274 .power_threshold,275 config_store.mode_set[AUTO_QUIET].power_floor,276 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta);277 278 pr_debug("[AUTO MODE PERFORMANCE_TO_BALANCE] pt: %u mW pf: %u mW pd: %u mW\n",279 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]280 .power_threshold,281 config_store.mode_set[AUTO_PERFORMANCE].power_floor,282 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta);283#endif284}285 286static const char *state_as_str(unsigned int state)287{288 switch (state) {289 case AUTO_QUIET:290 return "QUIET";291 case AUTO_BALANCE:292 return "BALANCED";293 case AUTO_PERFORMANCE_ON_LAP:294 return "ON_LAP";295 case AUTO_PERFORMANCE:296 return "PERFORMANCE";297 default:298 return "Unknown Auto Mode State";299 }300}301 302static void amd_pmf_load_defaults_auto_mode(struct amd_pmf_dev *dev)303{304 struct apmf_auto_mode output;305 struct power_table_control *pwr_ctrl;306 int i;307 308 apmf_get_auto_mode_def(dev, &output);309 /* time constant */310 config_store.transition[AUTO_TRANSITION_TO_QUIET].time_constant =311 output.balanced_to_quiet;312 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].time_constant =313 output.balanced_to_perf;314 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].time_constant =315 output.quiet_to_balanced;316 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].time_constant =317 output.perf_to_balanced;318 319 /* power floor */320 config_store.mode_set[AUTO_QUIET].power_floor = output.pfloor_quiet;321 config_store.mode_set[AUTO_BALANCE].power_floor = output.pfloor_balanced;322 config_store.mode_set[AUTO_PERFORMANCE].power_floor = output.pfloor_perf;323 config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_floor = output.pfloor_perf;324 325 /* Power delta for mode change */326 config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta =327 output.pd_balanced_to_quiet;328 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta =329 output.pd_balanced_to_perf;330 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta =331 output.pd_quiet_to_balanced;332 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta =333 output.pd_perf_to_balanced;334 335 /* Power threshold */336 amd_pmf_get_power_threshold();337 338 /* skin temperature limits */339 pwr_ctrl = &config_store.mode_set[AUTO_QUIET].power_control;340 pwr_ctrl->spl = output.spl_quiet;341 pwr_ctrl->sppt = output.sppt_quiet;342 pwr_ctrl->fppt = output.fppt_quiet;343 pwr_ctrl->sppt_apu_only = output.sppt_apu_only_quiet;344 pwr_ctrl->stt_min = output.stt_min_limit_quiet;345 pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_quiet;346 pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_quiet;347 348 pwr_ctrl = &config_store.mode_set[AUTO_BALANCE].power_control;349 pwr_ctrl->spl = output.spl_balanced;350 pwr_ctrl->sppt = output.sppt_balanced;351 pwr_ctrl->fppt = output.fppt_balanced;352 pwr_ctrl->sppt_apu_only = output.sppt_apu_only_balanced;353 pwr_ctrl->stt_min = output.stt_min_limit_balanced;354 pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_balanced;355 pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_balanced;356 357 pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE].power_control;358 pwr_ctrl->spl = output.spl_perf;359 pwr_ctrl->sppt = output.sppt_perf;360 pwr_ctrl->fppt = output.fppt_perf;361 pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf;362 pwr_ctrl->stt_min = output.stt_min_limit_perf;363 pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf;364 pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf;365 366 pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_control;367 pwr_ctrl->spl = output.spl_perf_on_lap;368 pwr_ctrl->sppt = output.sppt_perf_on_lap;369 pwr_ctrl->fppt = output.fppt_perf_on_lap;370 pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf_on_lap;371 pwr_ctrl->stt_min = output.stt_min_limit_perf_on_lap;372 pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf_on_lap;373 pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf_on_lap;374 375 /* Fan ID */376 config_store.mode_set[AUTO_QUIET].fan_control.fan_id = output.fan_id_quiet;377 config_store.mode_set[AUTO_BALANCE].fan_control.fan_id = output.fan_id_balanced;378 config_store.mode_set[AUTO_PERFORMANCE].fan_control.fan_id = output.fan_id_perf;379 config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].fan_control.fan_id =380 output.fan_id_perf;381 382 config_store.transition[AUTO_TRANSITION_TO_QUIET].target_mode = AUTO_QUIET;383 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode =384 AUTO_PERFORMANCE;385 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].target_mode =386 AUTO_BALANCE;387 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].target_mode =388 AUTO_BALANCE;389 390 config_store.transition[AUTO_TRANSITION_TO_QUIET].shifting_up = false;391 config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].shifting_up = true;392 config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].shifting_up = true;393 config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].shifting_up =394 false;395 396 for (i = 0 ; i < AUTO_MODE_MAX ; i++) {397 if (config_store.mode_set[i].fan_control.fan_id == FAN_INDEX_AUTO)398 config_store.mode_set[i].fan_control.manual = false;399 else400 config_store.mode_set[i].fan_control.manual = true;401 }402 403 /* set to initial default values */404 config_store.current_mode = AUTO_BALANCE;405 dev->socket_power_history_idx = -1;406 407 amd_pmf_dump_auto_mode_defaults(&config_store);408}409 410int amd_pmf_reset_amt(struct amd_pmf_dev *dev)411{412 /*413 * OEM BIOS implementation guide says that if the auto mode is enabled414 * the platform_profile registration shall be done by the OEM driver.415 * There could be cases where both static slider and auto mode BIOS416 * functions are enabled, in that case enable static slider updates417 * only if it advertised as supported.418 */419 420 if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {421 dev_dbg(dev->dev, "resetting AMT thermals\n");422 amd_pmf_set_sps_power_limits(dev);423 }424 return 0;425}426 427void amd_pmf_handle_amt(struct amd_pmf_dev *dev)428{429 amd_pmf_set_automode(dev, config_store.current_mode, NULL);430}431 432void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev)433{434 cancel_delayed_work_sync(&dev->work_buffer);435}436 437void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev)438{439 amd_pmf_load_defaults_auto_mode(dev);440 amd_pmf_init_metrics_table(dev);441}442