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