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/string_choices.h> 12 #include <linux/workqueue.h> 13 #include "pmf.h" 14 15 static struct cnqf_config config_store; 16 17 #ifdef CONFIG_AMD_PMF_DEBUG 18 static const char *state_as_str_cnqf(unsigned int state) 19 { 20 switch (state) { 21 case APMF_CNQF_TURBO: 22 return "turbo"; 23 case APMF_CNQF_PERFORMANCE: 24 return "performance"; 25 case APMF_CNQF_BALANCE: 26 return "balance"; 27 case APMF_CNQF_QUIET: 28 return "quiet"; 29 default: 30 return "Unknown CnQF State"; 31 } 32 } 33 34 static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) 35 { 36 int i; 37 38 pr_debug("Dynamic Slider %s Defaults - BEGIN\n", idx ? "DC" : "AC"); 39 pr_debug("size: %u\n", data->size); 40 pr_debug("flags: 0x%x\n", data->flags); 41 42 /* Time constants */ 43 pr_debug("t_perf_to_turbo: %u ms\n", data->t_perf_to_turbo); 44 pr_debug("t_balanced_to_perf: %u ms\n", data->t_balanced_to_perf); 45 pr_debug("t_quiet_to_balanced: %u ms\n", data->t_quiet_to_balanced); 46 pr_debug("t_balanced_to_quiet: %u ms\n", data->t_balanced_to_quiet); 47 pr_debug("t_perf_to_balanced: %u ms\n", data->t_perf_to_balanced); 48 pr_debug("t_turbo_to_perf: %u ms\n", data->t_turbo_to_perf); 49 50 for (i = 0 ; i < CNQF_MODE_MAX ; i++) { 51 pr_debug("pfloor_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].pfloor); 52 pr_debug("fppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].fppt); 53 pr_debug("sppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].sppt); 54 pr_debug("sppt_apuonly_%s: %u mW\n", 55 state_as_str_cnqf(i), data->ps[i].sppt_apu_only); 56 pr_debug("spl_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].spl); 57 pr_debug("stt_minlimit_%s: %u mW\n", 58 state_as_str_cnqf(i), data->ps[i].stt_min_limit); 59 pr_debug("stt_skintemp_apu_%s: %u C\n", state_as_str_cnqf(i), 60 data->ps[i].stt_skintemp[STT_TEMP_APU]); 61 pr_debug("stt_skintemp_hs2_%s: %u C\n", state_as_str_cnqf(i), 62 data->ps[i].stt_skintemp[STT_TEMP_HS2]); 63 pr_debug("fan_id_%s: %u\n", state_as_str_cnqf(i), data->ps[i].fan_id); 64 } 65 66 pr_debug("Dynamic Slider %s Defaults - END\n", idx ? "DC" : "AC"); 67 } 68 #else 69 static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) {} 70 #endif 71 72 static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx, 73 struct cnqf_config *table) 74 { 75 struct power_table_control *pc; 76 77 pc = &config_store.mode_set[src][idx].power_control; 78 79 amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL); 80 amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL); 81 amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL); 82 amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL); 83 amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL); 84 amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU], 85 NULL); 86 amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2], 87 NULL); 88 89 if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) 90 apmf_update_fan_idx(dev, 91 config_store.mode_set[src][idx].fan_control.manual, 92 config_store.mode_set[src][idx].fan_control.fan_id); 93 94 return 0; 95 } 96 97 static void amd_pmf_update_power_threshold(int src) 98 { 99 struct cnqf_mode_settings *ts; 100 struct cnqf_tran_params *tp; 101 102 tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET]; 103 ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; 104 tp->power_threshold = ts->power_floor; 105 106 tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO]; 107 ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; 108 tp->power_threshold = ts->power_floor; 109 110 tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 111 ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; 112 tp->power_threshold = ts->power_floor; 113 114 tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 115 ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; 116 tp->power_threshold = ts->power_floor; 117 118 tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 119 ts = &config_store.mode_set[src][CNQF_MODE_QUIET]; 120 tp->power_threshold = ts->power_floor; 121 122 tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 123 ts = &config_store.mode_set[src][CNQF_MODE_TURBO]; 124 tp->power_threshold = ts->power_floor; 125 } 126 127 static const char *state_as_str(unsigned int state) 128 { 129 switch (state) { 130 case CNQF_MODE_QUIET: 131 return "QUIET"; 132 case CNQF_MODE_BALANCE: 133 return "BALANCED"; 134 case CNQF_MODE_TURBO: 135 return "TURBO"; 136 case CNQF_MODE_PERFORMANCE: 137 return "PERFORMANCE"; 138 default: 139 return "Unknown CnQF mode"; 140 } 141 } 142 143 static int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev) 144 { 145 if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) && 146 is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 147 return amd_pmf_get_power_source(); 148 else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 149 return POWER_SOURCE_DC; 150 else 151 return POWER_SOURCE_AC; 152 } 153 154 int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms) 155 { 156 struct cnqf_tran_params *tp; 157 int src, i, j; 158 u32 avg_power = 0; 159 160 src = amd_pmf_cnqf_get_power_source(dev); 161 162 if (is_pprof_balanced(dev)) { 163 amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 164 } else { 165 /* 166 * Return from here if the platform_profile is not balanced 167 * so that preference is given to user mode selection, rather 168 * than enforcing CnQF to run all the time (if enabled) 169 */ 170 return -EINVAL; 171 } 172 173 for (i = 0; i < CNQF_TRANSITION_MAX; i++) { 174 config_store.trans_param[src][i].timer += time_lapsed_ms; 175 config_store.trans_param[src][i].total_power += socket_power; 176 config_store.trans_param[src][i].count++; 177 178 tp = &config_store.trans_param[src][i]; 179 180 #ifdef CONFIG_AMD_PMF_DEBUG 181 dev_dbg(dev->dev, "avg_power: %u mW total_power: %u mW count: %u timer: %u ms\n", 182 avg_power, config_store.trans_param[src][i].total_power, 183 config_store.trans_param[src][i].count, 184 config_store.trans_param[src][i].timer); 185 #endif 186 if (tp->timer >= tp->time_constant && tp->count) { 187 avg_power = tp->total_power / tp->count; 188 189 /* Reset the indices */ 190 tp->timer = 0; 191 tp->total_power = 0; 192 tp->count = 0; 193 194 if ((tp->shifting_up && avg_power >= tp->power_threshold) || 195 (!tp->shifting_up && avg_power <= tp->power_threshold)) { 196 tp->priority = true; 197 } else { 198 tp->priority = false; 199 } 200 } 201 } 202 203 dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n", 204 avg_power, socket_power, state_as_str(config_store.current_mode)); 205 206 #ifdef CONFIG_AMD_PMF_DEBUG 207 dev_dbg(dev->dev, "[CNQF] priority1: %u priority2: %u priority3: %u\n", 208 config_store.trans_param[src][0].priority, 209 config_store.trans_param[src][1].priority, 210 config_store.trans_param[src][2].priority); 211 212 dev_dbg(dev->dev, "[CNQF] priority4: %u priority5: %u priority6: %u\n", 213 config_store.trans_param[src][3].priority, 214 config_store.trans_param[src][4].priority, 215 config_store.trans_param[src][5].priority); 216 #endif 217 218 for (j = 0; j < CNQF_TRANSITION_MAX; j++) { 219 /* apply the highest priority */ 220 if (config_store.trans_param[src][j].priority) { 221 if (config_store.current_mode != 222 config_store.trans_param[src][j].target_mode) { 223 config_store.current_mode = 224 config_store.trans_param[src][j].target_mode; 225 dev_dbg(dev->dev, "Moving to Mode :%s\n", 226 state_as_str(config_store.current_mode)); 227 amd_pmf_set_cnqf(dev, src, 228 config_store.current_mode, NULL); 229 } 230 break; 231 } 232 } 233 return 0; 234 } 235 236 static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out) 237 { 238 struct cnqf_tran_params *tp; 239 240 tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET]; 241 tp->time_constant = out->t_balanced_to_quiet; 242 tp->target_mode = CNQF_MODE_QUIET; 243 tp->shifting_up = false; 244 245 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 246 tp->time_constant = out->t_balanced_to_perf; 247 tp->target_mode = CNQF_MODE_PERFORMANCE; 248 tp->shifting_up = true; 249 250 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 251 tp->time_constant = out->t_quiet_to_balanced; 252 tp->target_mode = CNQF_MODE_BALANCE; 253 tp->shifting_up = true; 254 255 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 256 tp->time_constant = out->t_perf_to_balanced; 257 tp->target_mode = CNQF_MODE_BALANCE; 258 tp->shifting_up = false; 259 260 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 261 tp->time_constant = out->t_turbo_to_perf; 262 tp->target_mode = CNQF_MODE_PERFORMANCE; 263 tp->shifting_up = false; 264 265 tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO]; 266 tp->time_constant = out->t_perf_to_turbo; 267 tp->target_mode = CNQF_MODE_TURBO; 268 tp->shifting_up = true; 269 } 270 271 static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out) 272 { 273 struct cnqf_mode_settings *ms; 274 275 /* Quiet Mode */ 276 ms = &config_store.mode_set[idx][CNQF_MODE_QUIET]; 277 ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor; 278 ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt; 279 ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt; 280 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only; 281 ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl; 282 ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit; 283 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 284 out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; 285 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 286 out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; 287 ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id; 288 289 /* Balance Mode */ 290 ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE]; 291 ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor; 292 ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt; 293 ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt; 294 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only; 295 ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl; 296 ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit; 297 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 298 out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; 299 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 300 out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; 301 ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id; 302 303 /* Performance Mode */ 304 ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE]; 305 ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor; 306 ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt; 307 ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt; 308 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; 309 ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl; 310 ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit; 311 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 312 out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; 313 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 314 out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; 315 ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id; 316 317 /* Turbo Mode */ 318 ms = &config_store.mode_set[idx][CNQF_MODE_TURBO]; 319 ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor; 320 ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt; 321 ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt; 322 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only; 323 ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl; 324 ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit; 325 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 326 out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; 327 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 328 out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; 329 ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id; 330 } 331 332 static int amd_pmf_check_flags(struct amd_pmf_dev *dev) 333 { 334 struct apmf_dyn_slider_output out = {}; 335 336 if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC)) 337 apmf_get_dyn_slider_def_ac(dev, &out); 338 else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 339 apmf_get_dyn_slider_def_dc(dev, &out); 340 341 return out.flags; 342 } 343 344 static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) 345 { 346 struct apmf_dyn_slider_output out; 347 int i, j, ret; 348 349 for (i = 0; i < POWER_SOURCE_MAX; i++) { 350 if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i)) 351 continue; 352 353 if (i == POWER_SOURCE_AC) 354 ret = apmf_get_dyn_slider_def_ac(dev, &out); 355 else 356 ret = apmf_get_dyn_slider_def_dc(dev, &out); 357 if (ret) { 358 dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret); 359 return ret; 360 } 361 362 amd_pmf_cnqf_dump_defaults(&out, i); 363 amd_pmf_update_mode_set(i, &out); 364 amd_pmf_update_trans_data(i, &out); 365 amd_pmf_update_power_threshold(i); 366 367 for (j = 0; j < CNQF_MODE_MAX; j++) { 368 if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO) 369 config_store.mode_set[i][j].fan_control.manual = false; 370 else 371 config_store.mode_set[i][j].fan_control.manual = true; 372 } 373 } 374 375 /* set to initial default values */ 376 config_store.current_mode = CNQF_MODE_BALANCE; 377 378 return 0; 379 } 380 381 static ssize_t cnqf_enable_store(struct device *dev, 382 struct device_attribute *attr, 383 const char *buf, size_t count) 384 { 385 struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 386 int result, src; 387 bool input; 388 389 result = kstrtobool(buf, &input); 390 if (result) 391 return result; 392 393 src = amd_pmf_cnqf_get_power_source(pdev); 394 pdev->cnqf_enabled = input; 395 396 if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) { 397 amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL); 398 } else { 399 if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) 400 amd_pmf_set_sps_power_limits(pdev); 401 } 402 403 dev_dbg(pdev->dev, "Received CnQF %s\n", str_on_off(input)); 404 return count; 405 } 406 407 static ssize_t cnqf_enable_show(struct device *dev, 408 struct device_attribute *attr, 409 char *buf) 410 { 411 struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 412 413 return sysfs_emit(buf, "%s\n", str_on_off(pdev->cnqf_enabled)); 414 } 415 416 static DEVICE_ATTR_RW(cnqf_enable); 417 418 static umode_t cnqf_feature_is_visible(struct kobject *kobj, 419 struct attribute *attr, int n) 420 { 421 struct device *dev = kobj_to_dev(kobj); 422 struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 423 424 return pdev->cnqf_supported ? attr->mode : 0; 425 } 426 427 static struct attribute *cnqf_feature_attrs[] = { 428 &dev_attr_cnqf_enable.attr, 429 NULL 430 }; 431 432 const struct attribute_group cnqf_feature_attribute_group = { 433 .is_visible = cnqf_feature_is_visible, 434 .attrs = cnqf_feature_attrs, 435 }; 436 437 void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev) 438 { 439 cancel_delayed_work_sync(&dev->work_buffer); 440 } 441 442 int amd_pmf_init_cnqf(struct amd_pmf_dev *dev) 443 { 444 int ret, src; 445 446 /* 447 * Note the caller of this function has already checked that both 448 * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported. 449 */ 450 451 ret = amd_pmf_load_defaults_cnqf(dev); 452 if (ret < 0) 453 return ret; 454 455 amd_pmf_init_metrics_table(dev); 456 457 dev->cnqf_supported = true; 458 dev->cnqf_enabled = amd_pmf_check_flags(dev); 459 460 /* update the thermal for CnQF */ 461 if (dev->cnqf_enabled && is_pprof_balanced(dev)) { 462 src = amd_pmf_cnqf_get_power_source(dev); 463 amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 464 } 465 466 return 0; 467 } 468