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 if (tp->timer >= tp->time_constant && tp->count) { 179 avg_power = tp->total_power / tp->count; 180 181 /* Reset the indices */ 182 tp->timer = 0; 183 tp->total_power = 0; 184 tp->count = 0; 185 186 if ((tp->shifting_up && avg_power >= tp->power_threshold) || 187 (!tp->shifting_up && avg_power <= tp->power_threshold)) { 188 tp->priority = true; 189 } else { 190 tp->priority = false; 191 } 192 } 193 } 194 195 dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n", 196 avg_power, socket_power, state_as_str(config_store.current_mode)); 197 198 for (j = 0; j < CNQF_TRANSITION_MAX; j++) { 199 /* apply the highest priority */ 200 if (config_store.trans_param[src][j].priority) { 201 if (config_store.current_mode != 202 config_store.trans_param[src][j].target_mode) { 203 config_store.current_mode = 204 config_store.trans_param[src][j].target_mode; 205 dev_dbg(dev->dev, "Moving to Mode :%s\n", 206 state_as_str(config_store.current_mode)); 207 amd_pmf_set_cnqf(dev, src, 208 config_store.current_mode, NULL); 209 } 210 break; 211 } 212 } 213 return 0; 214 } 215 216 static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out) 217 { 218 struct cnqf_tran_params *tp; 219 220 tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET]; 221 tp->time_constant = out->t_balanced_to_quiet; 222 tp->target_mode = CNQF_MODE_QUIET; 223 tp->shifting_up = false; 224 225 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 226 tp->time_constant = out->t_balanced_to_perf; 227 tp->target_mode = CNQF_MODE_PERFORMANCE; 228 tp->shifting_up = true; 229 230 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 231 tp->time_constant = out->t_quiet_to_balanced; 232 tp->target_mode = CNQF_MODE_BALANCE; 233 tp->shifting_up = true; 234 235 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 236 tp->time_constant = out->t_perf_to_balanced; 237 tp->target_mode = CNQF_MODE_BALANCE; 238 tp->shifting_up = false; 239 240 tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 241 tp->time_constant = out->t_turbo_to_perf; 242 tp->target_mode = CNQF_MODE_PERFORMANCE; 243 tp->shifting_up = false; 244 245 tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO]; 246 tp->time_constant = out->t_perf_to_turbo; 247 tp->target_mode = CNQF_MODE_TURBO; 248 tp->shifting_up = true; 249 } 250 251 static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out) 252 { 253 struct cnqf_mode_settings *ms; 254 255 /* Quiet Mode */ 256 ms = &config_store.mode_set[idx][CNQF_MODE_QUIET]; 257 ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor; 258 ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt; 259 ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt; 260 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only; 261 ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl; 262 ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit; 263 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 264 out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; 265 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 266 out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; 267 ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id; 268 269 /* Balance Mode */ 270 ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE]; 271 ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor; 272 ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt; 273 ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt; 274 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only; 275 ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl; 276 ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit; 277 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 278 out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; 279 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 280 out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; 281 ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id; 282 283 /* Performance Mode */ 284 ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE]; 285 ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor; 286 ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt; 287 ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt; 288 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; 289 ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl; 290 ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit; 291 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 292 out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; 293 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 294 out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; 295 ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id; 296 297 /* Turbo Mode */ 298 ms = &config_store.mode_set[idx][CNQF_MODE_TURBO]; 299 ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor; 300 ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt; 301 ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt; 302 ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only; 303 ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl; 304 ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit; 305 ms->power_control.stt_skin_temp[STT_TEMP_APU] = 306 out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; 307 ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 308 out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; 309 ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id; 310 } 311 312 static int amd_pmf_check_flags(struct amd_pmf_dev *dev) 313 { 314 struct apmf_dyn_slider_output out = {}; 315 316 if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC)) 317 apmf_get_dyn_slider_def_ac(dev, &out); 318 else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 319 apmf_get_dyn_slider_def_dc(dev, &out); 320 321 return out.flags; 322 } 323 324 static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) 325 { 326 struct apmf_dyn_slider_output out; 327 int i, j, ret; 328 329 for (i = 0; i < POWER_SOURCE_MAX; i++) { 330 if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i)) 331 continue; 332 333 if (i == POWER_SOURCE_AC) 334 ret = apmf_get_dyn_slider_def_ac(dev, &out); 335 else 336 ret = apmf_get_dyn_slider_def_dc(dev, &out); 337 if (ret) { 338 dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret); 339 return ret; 340 } 341 342 amd_pmf_cnqf_dump_defaults(&out, i); 343 amd_pmf_update_mode_set(i, &out); 344 amd_pmf_update_trans_data(i, &out); 345 amd_pmf_update_power_threshold(i); 346 347 for (j = 0; j < CNQF_MODE_MAX; j++) { 348 if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO) 349 config_store.mode_set[i][j].fan_control.manual = false; 350 else 351 config_store.mode_set[i][j].fan_control.manual = true; 352 } 353 } 354 355 /* set to initial default values */ 356 config_store.current_mode = CNQF_MODE_BALANCE; 357 358 return 0; 359 } 360 361 static ssize_t cnqf_enable_store(struct device *dev, 362 struct device_attribute *attr, 363 const char *buf, size_t count) 364 { 365 struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 366 int result, src; 367 bool input; 368 369 result = kstrtobool(buf, &input); 370 if (result) 371 return result; 372 373 src = amd_pmf_cnqf_get_power_source(pdev); 374 pdev->cnqf_enabled = input; 375 376 if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) { 377 amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL); 378 } else { 379 if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) 380 amd_pmf_set_sps_power_limits(pdev); 381 } 382 383 dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off"); 384 return count; 385 } 386 387 static ssize_t cnqf_enable_show(struct device *dev, 388 struct device_attribute *attr, 389 char *buf) 390 { 391 struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 392 393 return sysfs_emit(buf, "%s\n", pdev->cnqf_enabled ? "on" : "off"); 394 } 395 396 static DEVICE_ATTR_RW(cnqf_enable); 397 398 static umode_t cnqf_feature_is_visible(struct kobject *kobj, 399 struct attribute *attr, int n) 400 { 401 struct device *dev = kobj_to_dev(kobj); 402 struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 403 404 return pdev->cnqf_supported ? attr->mode : 0; 405 } 406 407 static struct attribute *cnqf_feature_attrs[] = { 408 &dev_attr_cnqf_enable.attr, 409 NULL 410 }; 411 412 const struct attribute_group cnqf_feature_attribute_group = { 413 .is_visible = cnqf_feature_is_visible, 414 .attrs = cnqf_feature_attrs, 415 }; 416 417 void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev) 418 { 419 cancel_delayed_work_sync(&dev->work_buffer); 420 } 421 422 int amd_pmf_init_cnqf(struct amd_pmf_dev *dev) 423 { 424 int ret, src; 425 426 /* 427 * Note the caller of this function has already checked that both 428 * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported. 429 */ 430 431 ret = amd_pmf_load_defaults_cnqf(dev); 432 if (ret < 0) 433 return ret; 434 435 amd_pmf_init_metrics_table(dev); 436 437 dev->cnqf_supported = true; 438 dev->cnqf_enabled = amd_pmf_check_flags(dev); 439 440 /* update the thermal for CnQF */ 441 if (dev->cnqf_enabled && is_pprof_balanced(dev)) { 442 src = amd_pmf_cnqf_get_power_source(dev); 443 amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 444 } 445 446 return 0; 447 } 448