11738061cSShyam Sundar S K // SPDX-License-Identifier: GPL-2.0 21738061cSShyam Sundar S K /* 31738061cSShyam Sundar S K * AMD Platform Management Framework Driver 41738061cSShyam Sundar S K * 51738061cSShyam Sundar S K * Copyright (c) 2022, Advanced Micro Devices, Inc. 61738061cSShyam Sundar S K * All Rights Reserved. 71738061cSShyam Sundar S K * 81738061cSShyam Sundar S K * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 91738061cSShyam Sundar S K */ 101738061cSShyam Sundar S K 11*cd99ebe5SAndy Shevchenko #include <linux/string_choices.h> 121738061cSShyam Sundar S K #include <linux/workqueue.h> 131738061cSShyam Sundar S K #include "pmf.h" 141738061cSShyam Sundar S K 151738061cSShyam Sundar S K static struct cnqf_config config_store; 161738061cSShyam Sundar S K 17a82ebb3dSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 18a82ebb3dSShyam Sundar S K static const char *state_as_str_cnqf(unsigned int state) 19a82ebb3dSShyam Sundar S K { 20a82ebb3dSShyam Sundar S K switch (state) { 21a82ebb3dSShyam Sundar S K case APMF_CNQF_TURBO: 22a82ebb3dSShyam Sundar S K return "turbo"; 23a82ebb3dSShyam Sundar S K case APMF_CNQF_PERFORMANCE: 24a82ebb3dSShyam Sundar S K return "performance"; 25a82ebb3dSShyam Sundar S K case APMF_CNQF_BALANCE: 26a82ebb3dSShyam Sundar S K return "balance"; 27a82ebb3dSShyam Sundar S K case APMF_CNQF_QUIET: 28a82ebb3dSShyam Sundar S K return "quiet"; 29a82ebb3dSShyam Sundar S K default: 30a82ebb3dSShyam Sundar S K return "Unknown CnQF State"; 31a82ebb3dSShyam Sundar S K } 32a82ebb3dSShyam Sundar S K } 33a82ebb3dSShyam Sundar S K 34a82ebb3dSShyam Sundar S K static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) 35a82ebb3dSShyam Sundar S K { 36a82ebb3dSShyam Sundar S K int i; 37a82ebb3dSShyam Sundar S K 38a82ebb3dSShyam Sundar S K pr_debug("Dynamic Slider %s Defaults - BEGIN\n", idx ? "DC" : "AC"); 39a82ebb3dSShyam Sundar S K pr_debug("size: %u\n", data->size); 40a82ebb3dSShyam Sundar S K pr_debug("flags: 0x%x\n", data->flags); 41a82ebb3dSShyam Sundar S K 42a82ebb3dSShyam Sundar S K /* Time constants */ 43a82ebb3dSShyam Sundar S K pr_debug("t_perf_to_turbo: %u ms\n", data->t_perf_to_turbo); 44a82ebb3dSShyam Sundar S K pr_debug("t_balanced_to_perf: %u ms\n", data->t_balanced_to_perf); 45a82ebb3dSShyam Sundar S K pr_debug("t_quiet_to_balanced: %u ms\n", data->t_quiet_to_balanced); 46a82ebb3dSShyam Sundar S K pr_debug("t_balanced_to_quiet: %u ms\n", data->t_balanced_to_quiet); 47a82ebb3dSShyam Sundar S K pr_debug("t_perf_to_balanced: %u ms\n", data->t_perf_to_balanced); 48a82ebb3dSShyam Sundar S K pr_debug("t_turbo_to_perf: %u ms\n", data->t_turbo_to_perf); 49a82ebb3dSShyam Sundar S K 50a82ebb3dSShyam Sundar S K for (i = 0 ; i < CNQF_MODE_MAX ; i++) { 51a82ebb3dSShyam Sundar S K pr_debug("pfloor_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].pfloor); 52a82ebb3dSShyam Sundar S K pr_debug("fppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].fppt); 53a82ebb3dSShyam Sundar S K pr_debug("sppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].sppt); 54a82ebb3dSShyam Sundar S K pr_debug("sppt_apuonly_%s: %u mW\n", 55a82ebb3dSShyam Sundar S K state_as_str_cnqf(i), data->ps[i].sppt_apu_only); 56a82ebb3dSShyam Sundar S K pr_debug("spl_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].spl); 57a82ebb3dSShyam Sundar S K pr_debug("stt_minlimit_%s: %u mW\n", 58a82ebb3dSShyam Sundar S K state_as_str_cnqf(i), data->ps[i].stt_min_limit); 59a82ebb3dSShyam Sundar S K pr_debug("stt_skintemp_apu_%s: %u C\n", state_as_str_cnqf(i), 60a82ebb3dSShyam Sundar S K data->ps[i].stt_skintemp[STT_TEMP_APU]); 61a82ebb3dSShyam Sundar S K pr_debug("stt_skintemp_hs2_%s: %u C\n", state_as_str_cnqf(i), 62a82ebb3dSShyam Sundar S K data->ps[i].stt_skintemp[STT_TEMP_HS2]); 63a82ebb3dSShyam Sundar S K pr_debug("fan_id_%s: %u\n", state_as_str_cnqf(i), data->ps[i].fan_id); 64a82ebb3dSShyam Sundar S K } 65a82ebb3dSShyam Sundar S K 66a82ebb3dSShyam Sundar S K pr_debug("Dynamic Slider %s Defaults - END\n", idx ? "DC" : "AC"); 67a82ebb3dSShyam Sundar S K } 68a82ebb3dSShyam Sundar S K #else 69a82ebb3dSShyam Sundar S K static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) {} 70a82ebb3dSShyam Sundar S K #endif 71a82ebb3dSShyam Sundar S K 721738061cSShyam Sundar S K static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx, 731738061cSShyam Sundar S K struct cnqf_config *table) 741738061cSShyam Sundar S K { 751738061cSShyam Sundar S K struct power_table_control *pc; 761738061cSShyam Sundar S K 771738061cSShyam Sundar S K pc = &config_store.mode_set[src][idx].power_control; 781738061cSShyam Sundar S K 791738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL); 801738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL); 811738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL); 821738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL); 831738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL); 841738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU], 851738061cSShyam Sundar S K NULL); 861738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2], 871738061cSShyam Sundar S K NULL); 881738061cSShyam Sundar S K 891738061cSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) 901738061cSShyam Sundar S K apmf_update_fan_idx(dev, 911738061cSShyam Sundar S K config_store.mode_set[src][idx].fan_control.manual, 921738061cSShyam Sundar S K config_store.mode_set[src][idx].fan_control.fan_id); 931738061cSShyam Sundar S K 941738061cSShyam Sundar S K return 0; 951738061cSShyam Sundar S K } 961738061cSShyam Sundar S K 971738061cSShyam Sundar S K static void amd_pmf_update_power_threshold(int src) 981738061cSShyam Sundar S K { 991738061cSShyam Sundar S K struct cnqf_mode_settings *ts; 1001738061cSShyam Sundar S K struct cnqf_tran_params *tp; 1011738061cSShyam Sundar S K 1021738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET]; 1031738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; 1049732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1051738061cSShyam Sundar S K 1061738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO]; 1071738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; 1089732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1091738061cSShyam Sundar S K 1101738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 1111738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; 1129732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1131738061cSShyam Sundar S K 1141738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 1151738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; 1169732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1171738061cSShyam Sundar S K 1181738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 1191738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_QUIET]; 1209732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1211738061cSShyam Sundar S K 1221738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 1231738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_TURBO]; 1249732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1251738061cSShyam Sundar S K } 1261738061cSShyam Sundar S K 1271738061cSShyam Sundar S K static const char *state_as_str(unsigned int state) 1281738061cSShyam Sundar S K { 1291738061cSShyam Sundar S K switch (state) { 1301738061cSShyam Sundar S K case CNQF_MODE_QUIET: 1311738061cSShyam Sundar S K return "QUIET"; 1321738061cSShyam Sundar S K case CNQF_MODE_BALANCE: 1331738061cSShyam Sundar S K return "BALANCED"; 1341738061cSShyam Sundar S K case CNQF_MODE_TURBO: 1351738061cSShyam Sundar S K return "TURBO"; 1361738061cSShyam Sundar S K case CNQF_MODE_PERFORMANCE: 1371738061cSShyam Sundar S K return "PERFORMANCE"; 1381738061cSShyam Sundar S K default: 1391738061cSShyam Sundar S K return "Unknown CnQF mode"; 1401738061cSShyam Sundar S K } 1411738061cSShyam Sundar S K } 1421738061cSShyam Sundar S K 1431738061cSShyam Sundar S K static int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev) 1441738061cSShyam Sundar S K { 1451738061cSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) && 1461738061cSShyam Sundar S K is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 1471738061cSShyam Sundar S K return amd_pmf_get_power_source(); 1481738061cSShyam Sundar S K else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 1491738061cSShyam Sundar S K return POWER_SOURCE_DC; 1501738061cSShyam Sundar S K else 1511738061cSShyam Sundar S K return POWER_SOURCE_AC; 1521738061cSShyam Sundar S K } 1531738061cSShyam Sundar S K 1541738061cSShyam Sundar S K int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms) 1551738061cSShyam Sundar S K { 1561738061cSShyam Sundar S K struct cnqf_tran_params *tp; 1571738061cSShyam Sundar S K int src, i, j; 1581738061cSShyam Sundar S K u32 avg_power = 0; 1591738061cSShyam Sundar S K 1601738061cSShyam Sundar S K src = amd_pmf_cnqf_get_power_source(dev); 1611738061cSShyam Sundar S K 16216909aa8SShyam Sundar S K if (is_pprof_balanced(dev)) { 1631738061cSShyam Sundar S K amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 1641738061cSShyam Sundar S K } else { 1651738061cSShyam Sundar S K /* 1661738061cSShyam Sundar S K * Return from here if the platform_profile is not balanced 1671738061cSShyam Sundar S K * so that preference is given to user mode selection, rather 1681738061cSShyam Sundar S K * than enforcing CnQF to run all the time (if enabled) 1691738061cSShyam Sundar S K */ 1701738061cSShyam Sundar S K return -EINVAL; 1711738061cSShyam Sundar S K } 1721738061cSShyam Sundar S K 1731738061cSShyam Sundar S K for (i = 0; i < CNQF_TRANSITION_MAX; i++) { 1741738061cSShyam Sundar S K config_store.trans_param[src][i].timer += time_lapsed_ms; 1751738061cSShyam Sundar S K config_store.trans_param[src][i].total_power += socket_power; 1761738061cSShyam Sundar S K config_store.trans_param[src][i].count++; 1771738061cSShyam Sundar S K 1781738061cSShyam Sundar S K tp = &config_store.trans_param[src][i]; 17963b5dbfdSShyam Sundar S K 18063b5dbfdSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 18163b5dbfdSShyam Sundar S K dev_dbg(dev->dev, "avg_power: %u mW total_power: %u mW count: %u timer: %u ms\n", 18263b5dbfdSShyam Sundar S K avg_power, config_store.trans_param[src][i].total_power, 18363b5dbfdSShyam Sundar S K config_store.trans_param[src][i].count, 18463b5dbfdSShyam Sundar S K config_store.trans_param[src][i].timer); 18563b5dbfdSShyam Sundar S K #endif 1861738061cSShyam Sundar S K if (tp->timer >= tp->time_constant && tp->count) { 1871738061cSShyam Sundar S K avg_power = tp->total_power / tp->count; 1881738061cSShyam Sundar S K 1891738061cSShyam Sundar S K /* Reset the indices */ 1901738061cSShyam Sundar S K tp->timer = 0; 1911738061cSShyam Sundar S K tp->total_power = 0; 1921738061cSShyam Sundar S K tp->count = 0; 1931738061cSShyam Sundar S K 1941738061cSShyam Sundar S K if ((tp->shifting_up && avg_power >= tp->power_threshold) || 1951738061cSShyam Sundar S K (!tp->shifting_up && avg_power <= tp->power_threshold)) { 1961738061cSShyam Sundar S K tp->priority = true; 1971738061cSShyam Sundar S K } else { 1981738061cSShyam Sundar S K tp->priority = false; 1991738061cSShyam Sundar S K } 2001738061cSShyam Sundar S K } 2011738061cSShyam Sundar S K } 2021738061cSShyam Sundar S K 2031738061cSShyam Sundar S K dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n", 2041738061cSShyam Sundar S K avg_power, socket_power, state_as_str(config_store.current_mode)); 2051738061cSShyam Sundar S K 20663b5dbfdSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 20763b5dbfdSShyam Sundar S K dev_dbg(dev->dev, "[CNQF] priority1: %u priority2: %u priority3: %u\n", 20863b5dbfdSShyam Sundar S K config_store.trans_param[src][0].priority, 20963b5dbfdSShyam Sundar S K config_store.trans_param[src][1].priority, 21063b5dbfdSShyam Sundar S K config_store.trans_param[src][2].priority); 21163b5dbfdSShyam Sundar S K 21263b5dbfdSShyam Sundar S K dev_dbg(dev->dev, "[CNQF] priority4: %u priority5: %u priority6: %u\n", 21363b5dbfdSShyam Sundar S K config_store.trans_param[src][3].priority, 21463b5dbfdSShyam Sundar S K config_store.trans_param[src][4].priority, 21563b5dbfdSShyam Sundar S K config_store.trans_param[src][5].priority); 21663b5dbfdSShyam Sundar S K #endif 21763b5dbfdSShyam Sundar S K 2181738061cSShyam Sundar S K for (j = 0; j < CNQF_TRANSITION_MAX; j++) { 2191738061cSShyam Sundar S K /* apply the highest priority */ 2201738061cSShyam Sundar S K if (config_store.trans_param[src][j].priority) { 2211738061cSShyam Sundar S K if (config_store.current_mode != 2221738061cSShyam Sundar S K config_store.trans_param[src][j].target_mode) { 2231738061cSShyam Sundar S K config_store.current_mode = 2241738061cSShyam Sundar S K config_store.trans_param[src][j].target_mode; 2251738061cSShyam Sundar S K dev_dbg(dev->dev, "Moving to Mode :%s\n", 2261738061cSShyam Sundar S K state_as_str(config_store.current_mode)); 2271738061cSShyam Sundar S K amd_pmf_set_cnqf(dev, src, 2281738061cSShyam Sundar S K config_store.current_mode, NULL); 2291738061cSShyam Sundar S K } 2301738061cSShyam Sundar S K break; 2311738061cSShyam Sundar S K } 2321738061cSShyam Sundar S K } 2331738061cSShyam Sundar S K return 0; 2341738061cSShyam Sundar S K } 2351738061cSShyam Sundar S K 23619c8b524SMuhammad Usama Anjum static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out) 2371738061cSShyam Sundar S K { 2381738061cSShyam Sundar S K struct cnqf_tran_params *tp; 2391738061cSShyam Sundar S K 2401738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET]; 24119c8b524SMuhammad Usama Anjum tp->time_constant = out->t_balanced_to_quiet; 2421738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_QUIET; 2431738061cSShyam Sundar S K tp->shifting_up = false; 2441738061cSShyam Sundar S K 2451738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 24619c8b524SMuhammad Usama Anjum tp->time_constant = out->t_balanced_to_perf; 2471738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_PERFORMANCE; 2481738061cSShyam Sundar S K tp->shifting_up = true; 2491738061cSShyam Sundar S K 2501738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 25119c8b524SMuhammad Usama Anjum tp->time_constant = out->t_quiet_to_balanced; 2521738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_BALANCE; 2531738061cSShyam Sundar S K tp->shifting_up = true; 2541738061cSShyam Sundar S K 2551738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 25619c8b524SMuhammad Usama Anjum tp->time_constant = out->t_perf_to_balanced; 2571738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_BALANCE; 2581738061cSShyam Sundar S K tp->shifting_up = false; 2591738061cSShyam Sundar S K 2601738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 26119c8b524SMuhammad Usama Anjum tp->time_constant = out->t_turbo_to_perf; 2621738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_PERFORMANCE; 2631738061cSShyam Sundar S K tp->shifting_up = false; 2641738061cSShyam Sundar S K 2651738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO]; 26619c8b524SMuhammad Usama Anjum tp->time_constant = out->t_perf_to_turbo; 2671738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_TURBO; 2681738061cSShyam Sundar S K tp->shifting_up = true; 2691738061cSShyam Sundar S K } 2701738061cSShyam Sundar S K 27119c8b524SMuhammad Usama Anjum static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out) 2721738061cSShyam Sundar S K { 2731738061cSShyam Sundar S K struct cnqf_mode_settings *ms; 2741738061cSShyam Sundar S K 2751738061cSShyam Sundar S K /* Quiet Mode */ 2761738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_QUIET]; 27719c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor; 27819c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt; 27919c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt; 28019c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only; 28119c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl; 28219c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit; 2831738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 28419c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; 2851738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 28619c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; 28719c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id; 2881738061cSShyam Sundar S K 2891738061cSShyam Sundar S K /* Balance Mode */ 2901738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE]; 29119c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor; 29219c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt; 29319c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt; 29419c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only; 29519c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl; 29619c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit; 2971738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 29819c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; 2991738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 30019c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; 30119c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id; 3021738061cSShyam Sundar S K 3031738061cSShyam Sundar S K /* Performance Mode */ 3041738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE]; 30519c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor; 30619c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt; 30719c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt; 30819c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; 30919c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl; 31019c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit; 3111738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 31219c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; 3131738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 31419c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; 31519c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id; 3161738061cSShyam Sundar S K 3171738061cSShyam Sundar S K /* Turbo Mode */ 3181738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_TURBO]; 31919c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor; 32019c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt; 32119c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt; 32219c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only; 32319c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl; 32419c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit; 3251738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 32619c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; 3271738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 32819c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; 32919c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id; 3301738061cSShyam Sundar S K } 3311738061cSShyam Sundar S K 3321738061cSShyam Sundar S K static int amd_pmf_check_flags(struct amd_pmf_dev *dev) 3331738061cSShyam Sundar S K { 3341738061cSShyam Sundar S K struct apmf_dyn_slider_output out = {}; 3351738061cSShyam Sundar S K 3361738061cSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC)) 3371738061cSShyam Sundar S K apmf_get_dyn_slider_def_ac(dev, &out); 3381738061cSShyam Sundar S K else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 3391738061cSShyam Sundar S K apmf_get_dyn_slider_def_dc(dev, &out); 3401738061cSShyam Sundar S K 3411738061cSShyam Sundar S K return out.flags; 3421738061cSShyam Sundar S K } 3431738061cSShyam Sundar S K 3441738061cSShyam Sundar S K static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) 3451738061cSShyam Sundar S K { 3461738061cSShyam Sundar S K struct apmf_dyn_slider_output out; 3471738061cSShyam Sundar S K int i, j, ret; 3481738061cSShyam Sundar S K 3491738061cSShyam Sundar S K for (i = 0; i < POWER_SOURCE_MAX; i++) { 3501738061cSShyam Sundar S K if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i)) 3511738061cSShyam Sundar S K continue; 3521738061cSShyam Sundar S K 3531738061cSShyam Sundar S K if (i == POWER_SOURCE_AC) 3541738061cSShyam Sundar S K ret = apmf_get_dyn_slider_def_ac(dev, &out); 3551738061cSShyam Sundar S K else 3561738061cSShyam Sundar S K ret = apmf_get_dyn_slider_def_dc(dev, &out); 3571738061cSShyam Sundar S K if (ret) { 3581738061cSShyam Sundar S K dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret); 3591738061cSShyam Sundar S K return ret; 3601738061cSShyam Sundar S K } 3611738061cSShyam Sundar S K 362a82ebb3dSShyam Sundar S K amd_pmf_cnqf_dump_defaults(&out, i); 36319c8b524SMuhammad Usama Anjum amd_pmf_update_mode_set(i, &out); 36419c8b524SMuhammad Usama Anjum amd_pmf_update_trans_data(i, &out); 3651738061cSShyam Sundar S K amd_pmf_update_power_threshold(i); 3661738061cSShyam Sundar S K 3671738061cSShyam Sundar S K for (j = 0; j < CNQF_MODE_MAX; j++) { 3681738061cSShyam Sundar S K if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO) 3691738061cSShyam Sundar S K config_store.mode_set[i][j].fan_control.manual = false; 3701738061cSShyam Sundar S K else 3711738061cSShyam Sundar S K config_store.mode_set[i][j].fan_control.manual = true; 3721738061cSShyam Sundar S K } 3731738061cSShyam Sundar S K } 3741738061cSShyam Sundar S K 3751738061cSShyam Sundar S K /* set to initial default values */ 3761738061cSShyam Sundar S K config_store.current_mode = CNQF_MODE_BALANCE; 3771738061cSShyam Sundar S K 3781738061cSShyam Sundar S K return 0; 3791738061cSShyam Sundar S K } 3801738061cSShyam Sundar S K 3813dae5825SShyam Sundar S K static ssize_t cnqf_enable_store(struct device *dev, 3823dae5825SShyam Sundar S K struct device_attribute *attr, 3833dae5825SShyam Sundar S K const char *buf, size_t count) 3843dae5825SShyam Sundar S K { 3853dae5825SShyam Sundar S K struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 386c5258d39SShyam Sundar S K int result, src; 3873dae5825SShyam Sundar S K bool input; 3883dae5825SShyam Sundar S K 3893dae5825SShyam Sundar S K result = kstrtobool(buf, &input); 3903dae5825SShyam Sundar S K if (result) 3913dae5825SShyam Sundar S K return result; 3923dae5825SShyam Sundar S K 3933dae5825SShyam Sundar S K src = amd_pmf_cnqf_get_power_source(pdev); 3943dae5825SShyam Sundar S K pdev->cnqf_enabled = input; 3953dae5825SShyam Sundar S K 39616909aa8SShyam Sundar S K if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) { 3973dae5825SShyam Sundar S K amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL); 3983dae5825SShyam Sundar S K } else { 3993dae5825SShyam Sundar S K if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) 400c5258d39SShyam Sundar S K amd_pmf_set_sps_power_limits(pdev); 4013dae5825SShyam Sundar S K } 4023dae5825SShyam Sundar S K 403*cd99ebe5SAndy Shevchenko dev_dbg(pdev->dev, "Received CnQF %s\n", str_on_off(input)); 4043dae5825SShyam Sundar S K return count; 4053dae5825SShyam Sundar S K } 4063dae5825SShyam Sundar S K 4073dae5825SShyam Sundar S K static ssize_t cnqf_enable_show(struct device *dev, 4083dae5825SShyam Sundar S K struct device_attribute *attr, 4093dae5825SShyam Sundar S K char *buf) 4103dae5825SShyam Sundar S K { 4113dae5825SShyam Sundar S K struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 4123dae5825SShyam Sundar S K 413*cd99ebe5SAndy Shevchenko return sysfs_emit(buf, "%s\n", str_on_off(pdev->cnqf_enabled)); 4143dae5825SShyam Sundar S K } 4153dae5825SShyam Sundar S K 4163dae5825SShyam Sundar S K static DEVICE_ATTR_RW(cnqf_enable); 4173dae5825SShyam Sundar S K 4183dae5825SShyam Sundar S K static umode_t cnqf_feature_is_visible(struct kobject *kobj, 4193dae5825SShyam Sundar S K struct attribute *attr, int n) 4203dae5825SShyam Sundar S K { 4213dae5825SShyam Sundar S K struct device *dev = kobj_to_dev(kobj); 4223dae5825SShyam Sundar S K struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 4233dae5825SShyam Sundar S K 4243dae5825SShyam Sundar S K return pdev->cnqf_supported ? attr->mode : 0; 4253dae5825SShyam Sundar S K } 4263dae5825SShyam Sundar S K 4273dae5825SShyam Sundar S K static struct attribute *cnqf_feature_attrs[] = { 4283dae5825SShyam Sundar S K &dev_attr_cnqf_enable.attr, 4293dae5825SShyam Sundar S K NULL 4303dae5825SShyam Sundar S K }; 4313dae5825SShyam Sundar S K 4323dae5825SShyam Sundar S K const struct attribute_group cnqf_feature_attribute_group = { 4333dae5825SShyam Sundar S K .is_visible = cnqf_feature_is_visible, 4343dae5825SShyam Sundar S K .attrs = cnqf_feature_attrs, 4353dae5825SShyam Sundar S K }; 4363dae5825SShyam Sundar S K 4371738061cSShyam Sundar S K void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev) 4381738061cSShyam Sundar S K { 4391738061cSShyam Sundar S K cancel_delayed_work_sync(&dev->work_buffer); 4401738061cSShyam Sundar S K } 4411738061cSShyam Sundar S K 4421738061cSShyam Sundar S K int amd_pmf_init_cnqf(struct amd_pmf_dev *dev) 4431738061cSShyam Sundar S K { 4441738061cSShyam Sundar S K int ret, src; 4451738061cSShyam Sundar S K 4461738061cSShyam Sundar S K /* 4471738061cSShyam Sundar S K * Note the caller of this function has already checked that both 4481738061cSShyam Sundar S K * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported. 4491738061cSShyam Sundar S K */ 4501738061cSShyam Sundar S K 4511738061cSShyam Sundar S K ret = amd_pmf_load_defaults_cnqf(dev); 4521738061cSShyam Sundar S K if (ret < 0) 4531738061cSShyam Sundar S K return ret; 4541738061cSShyam Sundar S K 4551738061cSShyam Sundar S K amd_pmf_init_metrics_table(dev); 4561738061cSShyam Sundar S K 4571738061cSShyam Sundar S K dev->cnqf_supported = true; 4581738061cSShyam Sundar S K dev->cnqf_enabled = amd_pmf_check_flags(dev); 4591738061cSShyam Sundar S K 4601738061cSShyam Sundar S K /* update the thermal for CnQF */ 46116909aa8SShyam Sundar S K if (dev->cnqf_enabled && is_pprof_balanced(dev)) { 4621738061cSShyam Sundar S K src = amd_pmf_cnqf_get_power_source(dev); 4631738061cSShyam Sundar S K amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 4641738061cSShyam Sundar S K } 4651738061cSShyam Sundar S K 4661738061cSShyam Sundar S K return 0; 4671738061cSShyam Sundar S K } 468