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 111738061cSShyam Sundar S K #include <linux/workqueue.h> 121738061cSShyam Sundar S K #include "pmf.h" 131738061cSShyam Sundar S K 141738061cSShyam Sundar S K static struct cnqf_config config_store; 151738061cSShyam Sundar S K 16a82ebb3dSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 17a82ebb3dSShyam Sundar S K static const char *state_as_str_cnqf(unsigned int state) 18a82ebb3dSShyam Sundar S K { 19a82ebb3dSShyam Sundar S K switch (state) { 20a82ebb3dSShyam Sundar S K case APMF_CNQF_TURBO: 21a82ebb3dSShyam Sundar S K return "turbo"; 22a82ebb3dSShyam Sundar S K case APMF_CNQF_PERFORMANCE: 23a82ebb3dSShyam Sundar S K return "performance"; 24a82ebb3dSShyam Sundar S K case APMF_CNQF_BALANCE: 25a82ebb3dSShyam Sundar S K return "balance"; 26a82ebb3dSShyam Sundar S K case APMF_CNQF_QUIET: 27a82ebb3dSShyam Sundar S K return "quiet"; 28a82ebb3dSShyam Sundar S K default: 29a82ebb3dSShyam Sundar S K return "Unknown CnQF State"; 30a82ebb3dSShyam Sundar S K } 31a82ebb3dSShyam Sundar S K } 32a82ebb3dSShyam Sundar S K 33a82ebb3dSShyam Sundar S K static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) 34a82ebb3dSShyam Sundar S K { 35a82ebb3dSShyam Sundar S K int i; 36a82ebb3dSShyam Sundar S K 37a82ebb3dSShyam Sundar S K pr_debug("Dynamic Slider %s Defaults - BEGIN\n", idx ? "DC" : "AC"); 38a82ebb3dSShyam Sundar S K pr_debug("size: %u\n", data->size); 39a82ebb3dSShyam Sundar S K pr_debug("flags: 0x%x\n", data->flags); 40a82ebb3dSShyam Sundar S K 41a82ebb3dSShyam Sundar S K /* Time constants */ 42a82ebb3dSShyam Sundar S K pr_debug("t_perf_to_turbo: %u ms\n", data->t_perf_to_turbo); 43a82ebb3dSShyam Sundar S K pr_debug("t_balanced_to_perf: %u ms\n", data->t_balanced_to_perf); 44a82ebb3dSShyam Sundar S K pr_debug("t_quiet_to_balanced: %u ms\n", data->t_quiet_to_balanced); 45a82ebb3dSShyam Sundar S K pr_debug("t_balanced_to_quiet: %u ms\n", data->t_balanced_to_quiet); 46a82ebb3dSShyam Sundar S K pr_debug("t_perf_to_balanced: %u ms\n", data->t_perf_to_balanced); 47a82ebb3dSShyam Sundar S K pr_debug("t_turbo_to_perf: %u ms\n", data->t_turbo_to_perf); 48a82ebb3dSShyam Sundar S K 49a82ebb3dSShyam Sundar S K for (i = 0 ; i < CNQF_MODE_MAX ; i++) { 50a82ebb3dSShyam Sundar S K pr_debug("pfloor_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].pfloor); 51a82ebb3dSShyam Sundar S K pr_debug("fppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].fppt); 52a82ebb3dSShyam Sundar S K pr_debug("sppt_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].sppt); 53a82ebb3dSShyam Sundar S K pr_debug("sppt_apuonly_%s: %u mW\n", 54a82ebb3dSShyam Sundar S K state_as_str_cnqf(i), data->ps[i].sppt_apu_only); 55a82ebb3dSShyam Sundar S K pr_debug("spl_%s: %u mW\n", state_as_str_cnqf(i), data->ps[i].spl); 56a82ebb3dSShyam Sundar S K pr_debug("stt_minlimit_%s: %u mW\n", 57a82ebb3dSShyam Sundar S K state_as_str_cnqf(i), data->ps[i].stt_min_limit); 58a82ebb3dSShyam Sundar S K pr_debug("stt_skintemp_apu_%s: %u C\n", state_as_str_cnqf(i), 59a82ebb3dSShyam Sundar S K data->ps[i].stt_skintemp[STT_TEMP_APU]); 60a82ebb3dSShyam Sundar S K pr_debug("stt_skintemp_hs2_%s: %u C\n", state_as_str_cnqf(i), 61a82ebb3dSShyam Sundar S K data->ps[i].stt_skintemp[STT_TEMP_HS2]); 62a82ebb3dSShyam Sundar S K pr_debug("fan_id_%s: %u\n", state_as_str_cnqf(i), data->ps[i].fan_id); 63a82ebb3dSShyam Sundar S K } 64a82ebb3dSShyam Sundar S K 65a82ebb3dSShyam Sundar S K pr_debug("Dynamic Slider %s Defaults - END\n", idx ? "DC" : "AC"); 66a82ebb3dSShyam Sundar S K } 67a82ebb3dSShyam Sundar S K #else 68a82ebb3dSShyam Sundar S K static void amd_pmf_cnqf_dump_defaults(struct apmf_dyn_slider_output *data, int idx) {} 69a82ebb3dSShyam Sundar S K #endif 70a82ebb3dSShyam Sundar S K 711738061cSShyam Sundar S K static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx, 721738061cSShyam Sundar S K struct cnqf_config *table) 731738061cSShyam Sundar S K { 741738061cSShyam Sundar S K struct power_table_control *pc; 751738061cSShyam Sundar S K 761738061cSShyam Sundar S K pc = &config_store.mode_set[src][idx].power_control; 771738061cSShyam Sundar S K 781738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL); 791738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL); 801738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL); 811738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL); 821738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL); 831738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU], 841738061cSShyam Sundar S K NULL); 851738061cSShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2], 861738061cSShyam Sundar S K NULL); 871738061cSShyam Sundar S K 881738061cSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX)) 891738061cSShyam Sundar S K apmf_update_fan_idx(dev, 901738061cSShyam Sundar S K config_store.mode_set[src][idx].fan_control.manual, 911738061cSShyam Sundar S K config_store.mode_set[src][idx].fan_control.fan_id); 921738061cSShyam Sundar S K 931738061cSShyam Sundar S K return 0; 941738061cSShyam Sundar S K } 951738061cSShyam Sundar S K 961738061cSShyam Sundar S K static void amd_pmf_update_power_threshold(int src) 971738061cSShyam Sundar S K { 981738061cSShyam Sundar S K struct cnqf_mode_settings *ts; 991738061cSShyam Sundar S K struct cnqf_tran_params *tp; 1001738061cSShyam Sundar S K 1011738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET]; 1021738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; 1039732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1041738061cSShyam Sundar S K 1051738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO]; 1061738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; 1079732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1081738061cSShyam Sundar S K 1091738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 1101738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_BALANCE]; 1119732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1121738061cSShyam Sundar S K 1131738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 1141738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE]; 1159732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1161738061cSShyam Sundar S K 1171738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 1181738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_QUIET]; 1199732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1201738061cSShyam Sundar S K 1211738061cSShyam Sundar S K tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 1221738061cSShyam Sundar S K ts = &config_store.mode_set[src][CNQF_MODE_TURBO]; 1239732f9c7SShyam Sundar S K tp->power_threshold = ts->power_floor; 1241738061cSShyam Sundar S K } 1251738061cSShyam Sundar S K 1261738061cSShyam Sundar S K static const char *state_as_str(unsigned int state) 1271738061cSShyam Sundar S K { 1281738061cSShyam Sundar S K switch (state) { 1291738061cSShyam Sundar S K case CNQF_MODE_QUIET: 1301738061cSShyam Sundar S K return "QUIET"; 1311738061cSShyam Sundar S K case CNQF_MODE_BALANCE: 1321738061cSShyam Sundar S K return "BALANCED"; 1331738061cSShyam Sundar S K case CNQF_MODE_TURBO: 1341738061cSShyam Sundar S K return "TURBO"; 1351738061cSShyam Sundar S K case CNQF_MODE_PERFORMANCE: 1361738061cSShyam Sundar S K return "PERFORMANCE"; 1371738061cSShyam Sundar S K default: 1381738061cSShyam Sundar S K return "Unknown CnQF mode"; 1391738061cSShyam Sundar S K } 1401738061cSShyam Sundar S K } 1411738061cSShyam Sundar S K 1421738061cSShyam Sundar S K static int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev) 1431738061cSShyam Sundar S K { 1441738061cSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) && 1451738061cSShyam Sundar S K is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 1461738061cSShyam Sundar S K return amd_pmf_get_power_source(); 1471738061cSShyam Sundar S K else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 1481738061cSShyam Sundar S K return POWER_SOURCE_DC; 1491738061cSShyam Sundar S K else 1501738061cSShyam Sundar S K return POWER_SOURCE_AC; 1511738061cSShyam Sundar S K } 1521738061cSShyam Sundar S K 1531738061cSShyam Sundar S K int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms) 1541738061cSShyam Sundar S K { 1551738061cSShyam Sundar S K struct cnqf_tran_params *tp; 1561738061cSShyam Sundar S K int src, i, j; 1571738061cSShyam Sundar S K u32 avg_power = 0; 1581738061cSShyam Sundar S K 1591738061cSShyam Sundar S K src = amd_pmf_cnqf_get_power_source(dev); 1601738061cSShyam Sundar S K 16116909aa8SShyam Sundar S K if (is_pprof_balanced(dev)) { 1621738061cSShyam Sundar S K amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 1631738061cSShyam Sundar S K } else { 1641738061cSShyam Sundar S K /* 1651738061cSShyam Sundar S K * Return from here if the platform_profile is not balanced 1661738061cSShyam Sundar S K * so that preference is given to user mode selection, rather 1671738061cSShyam Sundar S K * than enforcing CnQF to run all the time (if enabled) 1681738061cSShyam Sundar S K */ 1691738061cSShyam Sundar S K return -EINVAL; 1701738061cSShyam Sundar S K } 1711738061cSShyam Sundar S K 1721738061cSShyam Sundar S K for (i = 0; i < CNQF_TRANSITION_MAX; i++) { 1731738061cSShyam Sundar S K config_store.trans_param[src][i].timer += time_lapsed_ms; 1741738061cSShyam Sundar S K config_store.trans_param[src][i].total_power += socket_power; 1751738061cSShyam Sundar S K config_store.trans_param[src][i].count++; 1761738061cSShyam Sundar S K 1771738061cSShyam Sundar S K tp = &config_store.trans_param[src][i]; 178*63b5dbfdSShyam Sundar S K 179*63b5dbfdSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 180*63b5dbfdSShyam Sundar S K dev_dbg(dev->dev, "avg_power: %u mW total_power: %u mW count: %u timer: %u ms\n", 181*63b5dbfdSShyam Sundar S K avg_power, config_store.trans_param[src][i].total_power, 182*63b5dbfdSShyam Sundar S K config_store.trans_param[src][i].count, 183*63b5dbfdSShyam Sundar S K config_store.trans_param[src][i].timer); 184*63b5dbfdSShyam Sundar S K #endif 1851738061cSShyam Sundar S K if (tp->timer >= tp->time_constant && tp->count) { 1861738061cSShyam Sundar S K avg_power = tp->total_power / tp->count; 1871738061cSShyam Sundar S K 1881738061cSShyam Sundar S K /* Reset the indices */ 1891738061cSShyam Sundar S K tp->timer = 0; 1901738061cSShyam Sundar S K tp->total_power = 0; 1911738061cSShyam Sundar S K tp->count = 0; 1921738061cSShyam Sundar S K 1931738061cSShyam Sundar S K if ((tp->shifting_up && avg_power >= tp->power_threshold) || 1941738061cSShyam Sundar S K (!tp->shifting_up && avg_power <= tp->power_threshold)) { 1951738061cSShyam Sundar S K tp->priority = true; 1961738061cSShyam Sundar S K } else { 1971738061cSShyam Sundar S K tp->priority = false; 1981738061cSShyam Sundar S K } 1991738061cSShyam Sundar S K } 2001738061cSShyam Sundar S K } 2011738061cSShyam Sundar S K 2021738061cSShyam Sundar S K dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n", 2031738061cSShyam Sundar S K avg_power, socket_power, state_as_str(config_store.current_mode)); 2041738061cSShyam Sundar S K 205*63b5dbfdSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 206*63b5dbfdSShyam Sundar S K dev_dbg(dev->dev, "[CNQF] priority1: %u priority2: %u priority3: %u\n", 207*63b5dbfdSShyam Sundar S K config_store.trans_param[src][0].priority, 208*63b5dbfdSShyam Sundar S K config_store.trans_param[src][1].priority, 209*63b5dbfdSShyam Sundar S K config_store.trans_param[src][2].priority); 210*63b5dbfdSShyam Sundar S K 211*63b5dbfdSShyam Sundar S K dev_dbg(dev->dev, "[CNQF] priority4: %u priority5: %u priority6: %u\n", 212*63b5dbfdSShyam Sundar S K config_store.trans_param[src][3].priority, 213*63b5dbfdSShyam Sundar S K config_store.trans_param[src][4].priority, 214*63b5dbfdSShyam Sundar S K config_store.trans_param[src][5].priority); 215*63b5dbfdSShyam Sundar S K #endif 216*63b5dbfdSShyam Sundar S K 2171738061cSShyam Sundar S K for (j = 0; j < CNQF_TRANSITION_MAX; j++) { 2181738061cSShyam Sundar S K /* apply the highest priority */ 2191738061cSShyam Sundar S K if (config_store.trans_param[src][j].priority) { 2201738061cSShyam Sundar S K if (config_store.current_mode != 2211738061cSShyam Sundar S K config_store.trans_param[src][j].target_mode) { 2221738061cSShyam Sundar S K config_store.current_mode = 2231738061cSShyam Sundar S K config_store.trans_param[src][j].target_mode; 2241738061cSShyam Sundar S K dev_dbg(dev->dev, "Moving to Mode :%s\n", 2251738061cSShyam Sundar S K state_as_str(config_store.current_mode)); 2261738061cSShyam Sundar S K amd_pmf_set_cnqf(dev, src, 2271738061cSShyam Sundar S K config_store.current_mode, NULL); 2281738061cSShyam Sundar S K } 2291738061cSShyam Sundar S K break; 2301738061cSShyam Sundar S K } 2311738061cSShyam Sundar S K } 2321738061cSShyam Sundar S K return 0; 2331738061cSShyam Sundar S K } 2341738061cSShyam Sundar S K 23519c8b524SMuhammad Usama Anjum static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output *out) 2361738061cSShyam Sundar S K { 2371738061cSShyam Sundar S K struct cnqf_tran_params *tp; 2381738061cSShyam Sundar S K 2391738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET]; 24019c8b524SMuhammad Usama Anjum tp->time_constant = out->t_balanced_to_quiet; 2411738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_QUIET; 2421738061cSShyam Sundar S K tp->shifting_up = false; 2431738061cSShyam Sundar S K 2441738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE]; 24519c8b524SMuhammad Usama Anjum tp->time_constant = out->t_balanced_to_perf; 2461738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_PERFORMANCE; 2471738061cSShyam Sundar S K tp->shifting_up = true; 2481738061cSShyam Sundar S K 2491738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE]; 25019c8b524SMuhammad Usama Anjum tp->time_constant = out->t_quiet_to_balanced; 2511738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_BALANCE; 2521738061cSShyam Sundar S K tp->shifting_up = true; 2531738061cSShyam Sundar S K 2541738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE]; 25519c8b524SMuhammad Usama Anjum tp->time_constant = out->t_perf_to_balanced; 2561738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_BALANCE; 2571738061cSShyam Sundar S K tp->shifting_up = false; 2581738061cSShyam Sundar S K 2591738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE]; 26019c8b524SMuhammad Usama Anjum tp->time_constant = out->t_turbo_to_perf; 2611738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_PERFORMANCE; 2621738061cSShyam Sundar S K tp->shifting_up = false; 2631738061cSShyam Sundar S K 2641738061cSShyam Sundar S K tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO]; 26519c8b524SMuhammad Usama Anjum tp->time_constant = out->t_perf_to_turbo; 2661738061cSShyam Sundar S K tp->target_mode = CNQF_MODE_TURBO; 2671738061cSShyam Sundar S K tp->shifting_up = true; 2681738061cSShyam Sundar S K } 2691738061cSShyam Sundar S K 27019c8b524SMuhammad Usama Anjum static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output *out) 2711738061cSShyam Sundar S K { 2721738061cSShyam Sundar S K struct cnqf_mode_settings *ms; 2731738061cSShyam Sundar S K 2741738061cSShyam Sundar S K /* Quiet Mode */ 2751738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_QUIET]; 27619c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_QUIET].pfloor; 27719c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_QUIET].fppt; 27819c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_QUIET].sppt; 27919c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_QUIET].sppt_apu_only; 28019c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_QUIET].spl; 28119c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_QUIET].stt_min_limit; 2821738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 28319c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU]; 2841738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 28519c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2]; 28619c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_QUIET].fan_id; 2871738061cSShyam Sundar S K 2881738061cSShyam Sundar S K /* Balance Mode */ 2891738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE]; 29019c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_BALANCE].pfloor; 29119c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_BALANCE].fppt; 29219c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_BALANCE].sppt; 29319c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_BALANCE].sppt_apu_only; 29419c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_BALANCE].spl; 29519c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_BALANCE].stt_min_limit; 2961738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 29719c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU]; 2981738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 29919c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2]; 30019c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_BALANCE].fan_id; 3011738061cSShyam Sundar S K 3021738061cSShyam Sundar S K /* Performance Mode */ 3031738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE]; 30419c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_PERFORMANCE].pfloor; 30519c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_PERFORMANCE].fppt; 30619c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_PERFORMANCE].sppt; 30719c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_PERFORMANCE].sppt_apu_only; 30819c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_PERFORMANCE].spl; 30919c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_PERFORMANCE].stt_min_limit; 3101738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 31119c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU]; 3121738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 31319c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2]; 31419c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_PERFORMANCE].fan_id; 3151738061cSShyam Sundar S K 3161738061cSShyam Sundar S K /* Turbo Mode */ 3171738061cSShyam Sundar S K ms = &config_store.mode_set[idx][CNQF_MODE_TURBO]; 31819c8b524SMuhammad Usama Anjum ms->power_floor = out->ps[APMF_CNQF_TURBO].pfloor; 31919c8b524SMuhammad Usama Anjum ms->power_control.fppt = out->ps[APMF_CNQF_TURBO].fppt; 32019c8b524SMuhammad Usama Anjum ms->power_control.sppt = out->ps[APMF_CNQF_TURBO].sppt; 32119c8b524SMuhammad Usama Anjum ms->power_control.sppt_apu_only = out->ps[APMF_CNQF_TURBO].sppt_apu_only; 32219c8b524SMuhammad Usama Anjum ms->power_control.spl = out->ps[APMF_CNQF_TURBO].spl; 32319c8b524SMuhammad Usama Anjum ms->power_control.stt_min = out->ps[APMF_CNQF_TURBO].stt_min_limit; 3241738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_APU] = 32519c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU]; 3261738061cSShyam Sundar S K ms->power_control.stt_skin_temp[STT_TEMP_HS2] = 32719c8b524SMuhammad Usama Anjum out->ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2]; 32819c8b524SMuhammad Usama Anjum ms->fan_control.fan_id = out->ps[APMF_CNQF_TURBO].fan_id; 3291738061cSShyam Sundar S K } 3301738061cSShyam Sundar S K 3311738061cSShyam Sundar S K static int amd_pmf_check_flags(struct amd_pmf_dev *dev) 3321738061cSShyam Sundar S K { 3331738061cSShyam Sundar S K struct apmf_dyn_slider_output out = {}; 3341738061cSShyam Sundar S K 3351738061cSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC)) 3361738061cSShyam Sundar S K apmf_get_dyn_slider_def_ac(dev, &out); 3371738061cSShyam Sundar S K else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) 3381738061cSShyam Sundar S K apmf_get_dyn_slider_def_dc(dev, &out); 3391738061cSShyam Sundar S K 3401738061cSShyam Sundar S K return out.flags; 3411738061cSShyam Sundar S K } 3421738061cSShyam Sundar S K 3431738061cSShyam Sundar S K static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev) 3441738061cSShyam Sundar S K { 3451738061cSShyam Sundar S K struct apmf_dyn_slider_output out; 3461738061cSShyam Sundar S K int i, j, ret; 3471738061cSShyam Sundar S K 3481738061cSShyam Sundar S K for (i = 0; i < POWER_SOURCE_MAX; i++) { 3491738061cSShyam Sundar S K if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i)) 3501738061cSShyam Sundar S K continue; 3511738061cSShyam Sundar S K 3521738061cSShyam Sundar S K if (i == POWER_SOURCE_AC) 3531738061cSShyam Sundar S K ret = apmf_get_dyn_slider_def_ac(dev, &out); 3541738061cSShyam Sundar S K else 3551738061cSShyam Sundar S K ret = apmf_get_dyn_slider_def_dc(dev, &out); 3561738061cSShyam Sundar S K if (ret) { 3571738061cSShyam Sundar S K dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret); 3581738061cSShyam Sundar S K return ret; 3591738061cSShyam Sundar S K } 3601738061cSShyam Sundar S K 361a82ebb3dSShyam Sundar S K amd_pmf_cnqf_dump_defaults(&out, i); 36219c8b524SMuhammad Usama Anjum amd_pmf_update_mode_set(i, &out); 36319c8b524SMuhammad Usama Anjum amd_pmf_update_trans_data(i, &out); 3641738061cSShyam Sundar S K amd_pmf_update_power_threshold(i); 3651738061cSShyam Sundar S K 3661738061cSShyam Sundar S K for (j = 0; j < CNQF_MODE_MAX; j++) { 3671738061cSShyam Sundar S K if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO) 3681738061cSShyam Sundar S K config_store.mode_set[i][j].fan_control.manual = false; 3691738061cSShyam Sundar S K else 3701738061cSShyam Sundar S K config_store.mode_set[i][j].fan_control.manual = true; 3711738061cSShyam Sundar S K } 3721738061cSShyam Sundar S K } 3731738061cSShyam Sundar S K 3741738061cSShyam Sundar S K /* set to initial default values */ 3751738061cSShyam Sundar S K config_store.current_mode = CNQF_MODE_BALANCE; 3761738061cSShyam Sundar S K 3771738061cSShyam Sundar S K return 0; 3781738061cSShyam Sundar S K } 3791738061cSShyam Sundar S K 3803dae5825SShyam Sundar S K static ssize_t cnqf_enable_store(struct device *dev, 3813dae5825SShyam Sundar S K struct device_attribute *attr, 3823dae5825SShyam Sundar S K const char *buf, size_t count) 3833dae5825SShyam Sundar S K { 3843dae5825SShyam Sundar S K struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 385c5258d39SShyam Sundar S K int result, src; 3863dae5825SShyam Sundar S K bool input; 3873dae5825SShyam Sundar S K 3883dae5825SShyam Sundar S K result = kstrtobool(buf, &input); 3893dae5825SShyam Sundar S K if (result) 3903dae5825SShyam Sundar S K return result; 3913dae5825SShyam Sundar S K 3923dae5825SShyam Sundar S K src = amd_pmf_cnqf_get_power_source(pdev); 3933dae5825SShyam Sundar S K pdev->cnqf_enabled = input; 3943dae5825SShyam Sundar S K 39516909aa8SShyam Sundar S K if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) { 3963dae5825SShyam Sundar S K amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL); 3973dae5825SShyam Sundar S K } else { 3983dae5825SShyam Sundar S K if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) 399c5258d39SShyam Sundar S K amd_pmf_set_sps_power_limits(pdev); 4003dae5825SShyam Sundar S K } 4013dae5825SShyam Sundar S K 4023dae5825SShyam Sundar S K dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off"); 4033dae5825SShyam Sundar S K return count; 4043dae5825SShyam Sundar S K } 4053dae5825SShyam Sundar S K 4063dae5825SShyam Sundar S K static ssize_t cnqf_enable_show(struct device *dev, 4073dae5825SShyam Sundar S K struct device_attribute *attr, 4083dae5825SShyam Sundar S K char *buf) 4093dae5825SShyam Sundar S K { 4103dae5825SShyam Sundar S K struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 4113dae5825SShyam Sundar S K 4123dae5825SShyam Sundar S K return sysfs_emit(buf, "%s\n", pdev->cnqf_enabled ? "on" : "off"); 4133dae5825SShyam Sundar S K } 4143dae5825SShyam Sundar S K 4153dae5825SShyam Sundar S K static DEVICE_ATTR_RW(cnqf_enable); 4163dae5825SShyam Sundar S K 4173dae5825SShyam Sundar S K static umode_t cnqf_feature_is_visible(struct kobject *kobj, 4183dae5825SShyam Sundar S K struct attribute *attr, int n) 4193dae5825SShyam Sundar S K { 4203dae5825SShyam Sundar S K struct device *dev = kobj_to_dev(kobj); 4213dae5825SShyam Sundar S K struct amd_pmf_dev *pdev = dev_get_drvdata(dev); 4223dae5825SShyam Sundar S K 4233dae5825SShyam Sundar S K return pdev->cnqf_supported ? attr->mode : 0; 4243dae5825SShyam Sundar S K } 4253dae5825SShyam Sundar S K 4263dae5825SShyam Sundar S K static struct attribute *cnqf_feature_attrs[] = { 4273dae5825SShyam Sundar S K &dev_attr_cnqf_enable.attr, 4283dae5825SShyam Sundar S K NULL 4293dae5825SShyam Sundar S K }; 4303dae5825SShyam Sundar S K 4313dae5825SShyam Sundar S K const struct attribute_group cnqf_feature_attribute_group = { 4323dae5825SShyam Sundar S K .is_visible = cnqf_feature_is_visible, 4333dae5825SShyam Sundar S K .attrs = cnqf_feature_attrs, 4343dae5825SShyam Sundar S K }; 4353dae5825SShyam Sundar S K 4361738061cSShyam Sundar S K void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev) 4371738061cSShyam Sundar S K { 4381738061cSShyam Sundar S K cancel_delayed_work_sync(&dev->work_buffer); 4391738061cSShyam Sundar S K } 4401738061cSShyam Sundar S K 4411738061cSShyam Sundar S K int amd_pmf_init_cnqf(struct amd_pmf_dev *dev) 4421738061cSShyam Sundar S K { 4431738061cSShyam Sundar S K int ret, src; 4441738061cSShyam Sundar S K 4451738061cSShyam Sundar S K /* 4461738061cSShyam Sundar S K * Note the caller of this function has already checked that both 4471738061cSShyam Sundar S K * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported. 4481738061cSShyam Sundar S K */ 4491738061cSShyam Sundar S K 4501738061cSShyam Sundar S K ret = amd_pmf_load_defaults_cnqf(dev); 4511738061cSShyam Sundar S K if (ret < 0) 4521738061cSShyam Sundar S K return ret; 4531738061cSShyam Sundar S K 4541738061cSShyam Sundar S K amd_pmf_init_metrics_table(dev); 4551738061cSShyam Sundar S K 4561738061cSShyam Sundar S K dev->cnqf_supported = true; 4571738061cSShyam Sundar S K dev->cnqf_enabled = amd_pmf_check_flags(dev); 4581738061cSShyam Sundar S K 4591738061cSShyam Sundar S K /* update the thermal for CnQF */ 46016909aa8SShyam Sundar S K if (dev->cnqf_enabled && is_pprof_balanced(dev)) { 4611738061cSShyam Sundar S K src = amd_pmf_cnqf_get_power_source(dev); 4621738061cSShyam Sundar S K amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL); 4631738061cSShyam Sundar S K } 4641738061cSShyam Sundar S K 4651738061cSShyam Sundar S K return 0; 4661738061cSShyam Sundar S K } 467