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