14c71ae41SShyam Sundar S K // SPDX-License-Identifier: GPL-2.0 24c71ae41SShyam Sundar S K /* 34c71ae41SShyam Sundar S K * AMD Platform Management Framework (PMF) Driver 44c71ae41SShyam Sundar S K * 54c71ae41SShyam Sundar S K * Copyright (c) 2022, Advanced Micro Devices, Inc. 64c71ae41SShyam Sundar S K * All Rights Reserved. 74c71ae41SShyam Sundar S K * 84c71ae41SShyam Sundar S K * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 94c71ae41SShyam Sundar S K */ 104c71ae41SShyam Sundar S K 114c71ae41SShyam Sundar S K #include "pmf.h" 124c71ae41SShyam Sundar S K 134c71ae41SShyam Sundar S K static struct amd_pmf_static_slider_granular config_store; 144c71ae41SShyam Sundar S K 15a82ebb3dSShyam Sundar S K #ifdef CONFIG_AMD_PMF_DEBUG 16506ed33dSShyam Sundar S K static const char *slider_as_str(unsigned int state) 17a82ebb3dSShyam Sundar S K { 18a82ebb3dSShyam Sundar S K switch (state) { 19a82ebb3dSShyam Sundar S K case POWER_MODE_PERFORMANCE: 20a82ebb3dSShyam Sundar S K return "PERFORMANCE"; 21a82ebb3dSShyam Sundar S K case POWER_MODE_BALANCED_POWER: 22a82ebb3dSShyam Sundar S K return "BALANCED_POWER"; 23a82ebb3dSShyam Sundar S K case POWER_MODE_POWER_SAVER: 24a82ebb3dSShyam Sundar S K return "POWER_SAVER"; 25a82ebb3dSShyam Sundar S K default: 26a82ebb3dSShyam Sundar S K return "Unknown Slider State"; 27a82ebb3dSShyam Sundar S K } 28a82ebb3dSShyam Sundar S K } 29a82ebb3dSShyam Sundar S K 30506ed33dSShyam Sundar S K static const char *source_as_str(unsigned int state) 31a82ebb3dSShyam Sundar S K { 32a82ebb3dSShyam Sundar S K switch (state) { 33a82ebb3dSShyam Sundar S K case POWER_SOURCE_AC: 34a82ebb3dSShyam Sundar S K return "AC"; 35a82ebb3dSShyam Sundar S K case POWER_SOURCE_DC: 36a82ebb3dSShyam Sundar S K return "DC"; 37a82ebb3dSShyam Sundar S K default: 38a82ebb3dSShyam Sundar S K return "Unknown Power State"; 39a82ebb3dSShyam Sundar S K } 40a82ebb3dSShyam Sundar S K } 41a82ebb3dSShyam Sundar S K 42a82ebb3dSShyam Sundar S K static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) 43a82ebb3dSShyam Sundar S K { 44a82ebb3dSShyam Sundar S K int i, j; 45a82ebb3dSShyam Sundar S K 46a82ebb3dSShyam Sundar S K pr_debug("Static Slider Data - BEGIN\n"); 47a82ebb3dSShyam Sundar S K 48a82ebb3dSShyam Sundar S K for (i = 0; i < POWER_SOURCE_MAX; i++) { 49a82ebb3dSShyam Sundar S K for (j = 0; j < POWER_MODE_MAX; j++) { 50a82ebb3dSShyam Sundar S K pr_debug("--- Source:%s Mode:%s ---\n", source_as_str(i), slider_as_str(j)); 51a82ebb3dSShyam Sundar S K pr_debug("SPL: %u mW\n", data->prop[i][j].spl); 52a82ebb3dSShyam Sundar S K pr_debug("SPPT: %u mW\n", data->prop[i][j].sppt); 53a82ebb3dSShyam Sundar S K pr_debug("SPPT_ApuOnly: %u mW\n", data->prop[i][j].sppt_apu_only); 54a82ebb3dSShyam Sundar S K pr_debug("FPPT: %u mW\n", data->prop[i][j].fppt); 55a82ebb3dSShyam Sundar S K pr_debug("STTMinLimit: %u mW\n", data->prop[i][j].stt_min); 56a82ebb3dSShyam Sundar S K pr_debug("STT_SkinTempLimit_APU: %u C\n", 57a82ebb3dSShyam Sundar S K data->prop[i][j].stt_skin_temp[STT_TEMP_APU]); 58a82ebb3dSShyam Sundar S K pr_debug("STT_SkinTempLimit_HS2: %u C\n", 59a82ebb3dSShyam Sundar S K data->prop[i][j].stt_skin_temp[STT_TEMP_HS2]); 60a82ebb3dSShyam Sundar S K } 61a82ebb3dSShyam Sundar S K } 62a82ebb3dSShyam Sundar S K 63a82ebb3dSShyam Sundar S K pr_debug("Static Slider Data - END\n"); 64a82ebb3dSShyam Sundar S K } 65a82ebb3dSShyam Sundar S K #else 66a82ebb3dSShyam Sundar S K static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {} 67a82ebb3dSShyam Sundar S K #endif 68a82ebb3dSShyam Sundar S K 694c71ae41SShyam Sundar S K static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) 704c71ae41SShyam Sundar S K { 714c71ae41SShyam Sundar S K struct apmf_static_slider_granular_output output; 724c71ae41SShyam Sundar S K int i, j, idx = 0; 734c71ae41SShyam Sundar S K 744c71ae41SShyam Sundar S K memset(&config_store, 0, sizeof(config_store)); 754c71ae41SShyam Sundar S K apmf_get_static_slider_granular(dev, &output); 764c71ae41SShyam Sundar S K 774c71ae41SShyam Sundar S K for (i = 0; i < POWER_SOURCE_MAX; i++) { 784c71ae41SShyam Sundar S K for (j = 0; j < POWER_MODE_MAX; j++) { 794c71ae41SShyam Sundar S K config_store.prop[i][j].spl = output.prop[idx].spl; 804c71ae41SShyam Sundar S K config_store.prop[i][j].sppt = output.prop[idx].sppt; 814c71ae41SShyam Sundar S K config_store.prop[i][j].sppt_apu_only = 824c71ae41SShyam Sundar S K output.prop[idx].sppt_apu_only; 834c71ae41SShyam Sundar S K config_store.prop[i][j].fppt = output.prop[idx].fppt; 844c71ae41SShyam Sundar S K config_store.prop[i][j].stt_min = output.prop[idx].stt_min; 854c71ae41SShyam Sundar S K config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] = 864c71ae41SShyam Sundar S K output.prop[idx].stt_skin_temp[STT_TEMP_APU]; 874c71ae41SShyam Sundar S K config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] = 884c71ae41SShyam Sundar S K output.prop[idx].stt_skin_temp[STT_TEMP_HS2]; 894c71ae41SShyam Sundar S K config_store.prop[i][j].fan_id = output.prop[idx].fan_id; 904c71ae41SShyam Sundar S K idx++; 914c71ae41SShyam Sundar S K } 924c71ae41SShyam Sundar S K } 93a82ebb3dSShyam Sundar S K amd_pmf_dump_sps_defaults(&config_store); 944c71ae41SShyam Sundar S K } 954c71ae41SShyam Sundar S K 964c71ae41SShyam Sundar S K void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, 974c71ae41SShyam Sundar S K struct amd_pmf_static_slider_granular *table) 984c71ae41SShyam Sundar S K { 994c71ae41SShyam Sundar S K int src = amd_pmf_get_power_source(); 1004c71ae41SShyam Sundar S K 1014c71ae41SShyam Sundar S K if (op == SLIDER_OP_SET) { 1024c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); 1034c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); 1044c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); 1054c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, 1064c71ae41SShyam Sundar S K config_store.prop[src][idx].sppt_apu_only, NULL); 1074c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 1084c71ae41SShyam Sundar S K config_store.prop[src][idx].stt_min, NULL); 1094c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 1104c71ae41SShyam Sundar S K config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); 1114c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 1124c71ae41SShyam Sundar S K config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); 1134c71ae41SShyam Sundar S K } else if (op == SLIDER_OP_GET) { 1144c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); 1154c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); 1164c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); 1174c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, 1184c71ae41SShyam Sundar S K &table->prop[src][idx].sppt_apu_only); 1194c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, 1204c71ae41SShyam Sundar S K &table->prop[src][idx].stt_min); 1214c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, 1224c71ae41SShyam Sundar S K (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); 1234c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, 1244c71ae41SShyam Sundar S K (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); 1254c71ae41SShyam Sundar S K } 1264c71ae41SShyam Sundar S K } 1274c71ae41SShyam Sundar S K 128c5258d39SShyam Sundar S K int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) 129c5258d39SShyam Sundar S K { 130c5258d39SShyam Sundar S K int mode; 131c5258d39SShyam Sundar S K 132c5258d39SShyam Sundar S K mode = amd_pmf_get_pprof_modes(pmf); 133c5258d39SShyam Sundar S K if (mode < 0) 134c5258d39SShyam Sundar S K return mode; 135c5258d39SShyam Sundar S K 136c5258d39SShyam Sundar S K amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); 137c5258d39SShyam Sundar S K 138c5258d39SShyam Sundar S K return 0; 139c5258d39SShyam Sundar S K } 140c5258d39SShyam Sundar S K 14116909aa8SShyam Sundar S K bool is_pprof_balanced(struct amd_pmf_dev *pmf) 14216909aa8SShyam Sundar S K { 14316909aa8SShyam Sundar S K return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; 14416909aa8SShyam Sundar S K } 14516909aa8SShyam Sundar S K 1464c71ae41SShyam Sundar S K static int amd_pmf_profile_get(struct platform_profile_handler *pprof, 1474c71ae41SShyam Sundar S K enum platform_profile_option *profile) 1484c71ae41SShyam Sundar S K { 1494c71ae41SShyam Sundar S K struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 1504c71ae41SShyam Sundar S K 1514c71ae41SShyam Sundar S K *profile = pmf->current_profile; 1524c71ae41SShyam Sundar S K return 0; 1534c71ae41SShyam Sundar S K } 1544c71ae41SShyam Sundar S K 155ea522b80SShyam Sundar S K int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) 1564c71ae41SShyam Sundar S K { 157ea522b80SShyam Sundar S K int mode; 1584c71ae41SShyam Sundar S K 1594c71ae41SShyam Sundar S K switch (pmf->current_profile) { 1604c71ae41SShyam Sundar S K case PLATFORM_PROFILE_PERFORMANCE: 1614c71ae41SShyam Sundar S K mode = POWER_MODE_PERFORMANCE; 1624c71ae41SShyam Sundar S K break; 1634c71ae41SShyam Sundar S K case PLATFORM_PROFILE_BALANCED: 1644c71ae41SShyam Sundar S K mode = POWER_MODE_BALANCED_POWER; 1654c71ae41SShyam Sundar S K break; 1664c71ae41SShyam Sundar S K case PLATFORM_PROFILE_LOW_POWER: 1674c71ae41SShyam Sundar S K mode = POWER_MODE_POWER_SAVER; 1684c71ae41SShyam Sundar S K break; 1694c71ae41SShyam Sundar S K default: 1704c71ae41SShyam Sundar S K dev_err(pmf->dev, "Unknown Platform Profile.\n"); 171ea522b80SShyam Sundar S K return -EOPNOTSUPP; 1724c71ae41SShyam Sundar S K } 1734c71ae41SShyam Sundar S K 1744c71ae41SShyam Sundar S K return mode; 1754c71ae41SShyam Sundar S K } 1764c71ae41SShyam Sundar S K 177*33c9ab5bSShyam Sundar S K int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) 178*33c9ab5bSShyam Sundar S K { 179*33c9ab5bSShyam Sundar S K u8 mode, flag = 0; 180*33c9ab5bSShyam Sundar S K int src; 181*33c9ab5bSShyam Sundar S K 182*33c9ab5bSShyam Sundar S K mode = amd_pmf_get_pprof_modes(dev); 183*33c9ab5bSShyam Sundar S K if (mode < 0) 184*33c9ab5bSShyam Sundar S K return mode; 185*33c9ab5bSShyam Sundar S K 186*33c9ab5bSShyam Sundar S K src = amd_pmf_get_power_source(); 187*33c9ab5bSShyam Sundar S K 188*33c9ab5bSShyam Sundar S K if (src == POWER_SOURCE_AC) { 189*33c9ab5bSShyam Sundar S K switch (mode) { 190*33c9ab5bSShyam Sundar S K case POWER_MODE_PERFORMANCE: 191*33c9ab5bSShyam Sundar S K flag |= BIT(AC_BEST_PERF); 192*33c9ab5bSShyam Sundar S K break; 193*33c9ab5bSShyam Sundar S K case POWER_MODE_BALANCED_POWER: 194*33c9ab5bSShyam Sundar S K flag |= BIT(AC_BETTER_PERF); 195*33c9ab5bSShyam Sundar S K break; 196*33c9ab5bSShyam Sundar S K case POWER_MODE_POWER_SAVER: 197*33c9ab5bSShyam Sundar S K flag |= BIT(AC_BETTER_BATTERY); 198*33c9ab5bSShyam Sundar S K break; 199*33c9ab5bSShyam Sundar S K default: 200*33c9ab5bSShyam Sundar S K dev_err(dev->dev, "unsupported platform profile\n"); 201*33c9ab5bSShyam Sundar S K return -EOPNOTSUPP; 202*33c9ab5bSShyam Sundar S K } 203*33c9ab5bSShyam Sundar S K 204*33c9ab5bSShyam Sundar S K } else if (src == POWER_SOURCE_DC) { 205*33c9ab5bSShyam Sundar S K switch (mode) { 206*33c9ab5bSShyam Sundar S K case POWER_MODE_PERFORMANCE: 207*33c9ab5bSShyam Sundar S K flag |= BIT(DC_BEST_PERF); 208*33c9ab5bSShyam Sundar S K break; 209*33c9ab5bSShyam Sundar S K case POWER_MODE_BALANCED_POWER: 210*33c9ab5bSShyam Sundar S K flag |= BIT(DC_BETTER_PERF); 211*33c9ab5bSShyam Sundar S K break; 212*33c9ab5bSShyam Sundar S K case POWER_MODE_POWER_SAVER: 213*33c9ab5bSShyam Sundar S K flag |= BIT(DC_BATTERY_SAVER); 214*33c9ab5bSShyam Sundar S K break; 215*33c9ab5bSShyam Sundar S K default: 216*33c9ab5bSShyam Sundar S K dev_err(dev->dev, "unsupported platform profile\n"); 217*33c9ab5bSShyam Sundar S K return -EOPNOTSUPP; 218*33c9ab5bSShyam Sundar S K } 219*33c9ab5bSShyam Sundar S K } 220*33c9ab5bSShyam Sundar S K 221*33c9ab5bSShyam Sundar S K apmf_os_power_slider_update(dev, flag); 222*33c9ab5bSShyam Sundar S K 223*33c9ab5bSShyam Sundar S K return 0; 224*33c9ab5bSShyam Sundar S K } 225*33c9ab5bSShyam Sundar S K 2264c71ae41SShyam Sundar S K static int amd_pmf_profile_set(struct platform_profile_handler *pprof, 2274c71ae41SShyam Sundar S K enum platform_profile_option profile) 2284c71ae41SShyam Sundar S K { 2294c71ae41SShyam Sundar S K struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 230*33c9ab5bSShyam Sundar S K int ret = 0; 2314c71ae41SShyam Sundar S K 2324c71ae41SShyam Sundar S K pmf->current_profile = profile; 233ea522b80SShyam Sundar S K 234*33c9ab5bSShyam Sundar S K /* Notify EC about the slider position change */ 235*33c9ab5bSShyam Sundar S K if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { 236*33c9ab5bSShyam Sundar S K ret = amd_pmf_power_slider_update_event(pmf); 237*33c9ab5bSShyam Sundar S K if (ret) 238*33c9ab5bSShyam Sundar S K return ret; 239*33c9ab5bSShyam Sundar S K } 240*33c9ab5bSShyam Sundar S K 241*33c9ab5bSShyam Sundar S K if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 242*33c9ab5bSShyam Sundar S K ret = amd_pmf_set_sps_power_limits(pmf); 243*33c9ab5bSShyam Sundar S K if (ret) 244*33c9ab5bSShyam Sundar S K return ret; 245*33c9ab5bSShyam Sundar S K } 246*33c9ab5bSShyam Sundar S K 247*33c9ab5bSShyam Sundar S K return 0; 2484c71ae41SShyam Sundar S K } 2494c71ae41SShyam Sundar S K 2504c71ae41SShyam Sundar S K int amd_pmf_init_sps(struct amd_pmf_dev *dev) 2514c71ae41SShyam Sundar S K { 2524c71ae41SShyam Sundar S K int err; 2534c71ae41SShyam Sundar S K 2544c71ae41SShyam Sundar S K dev->current_profile = PLATFORM_PROFILE_BALANCED; 255*33c9ab5bSShyam Sundar S K 256*33c9ab5bSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 2574c71ae41SShyam Sundar S K amd_pmf_load_defaults_sps(dev); 2584c71ae41SShyam Sundar S K 259635f79bcSShyam Sundar S K /* update SPS balanced power mode thermals */ 260635f79bcSShyam Sundar S K amd_pmf_set_sps_power_limits(dev); 261*33c9ab5bSShyam Sundar S K } 262635f79bcSShyam Sundar S K 2634c71ae41SShyam Sundar S K dev->pprof.profile_get = amd_pmf_profile_get; 2644c71ae41SShyam Sundar S K dev->pprof.profile_set = amd_pmf_profile_set; 2654c71ae41SShyam Sundar S K 2664c71ae41SShyam Sundar S K /* Setup supported modes */ 2674c71ae41SShyam Sundar S K set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); 2684c71ae41SShyam Sundar S K set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); 2694c71ae41SShyam Sundar S K set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); 2704c71ae41SShyam Sundar S K 2714c71ae41SShyam Sundar S K /* Create platform_profile structure and register */ 2724c71ae41SShyam Sundar S K err = platform_profile_register(&dev->pprof); 2734c71ae41SShyam Sundar S K if (err) 2744c71ae41SShyam Sundar S K dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", 2754c71ae41SShyam Sundar S K err); 2764c71ae41SShyam Sundar S K 2774c71ae41SShyam Sundar S K return err; 2784c71ae41SShyam Sundar S K } 2794c71ae41SShyam Sundar S K 2804c71ae41SShyam Sundar S K void amd_pmf_deinit_sps(struct amd_pmf_dev *dev) 2814c71ae41SShyam Sundar S K { 2824c71ae41SShyam Sundar S K platform_profile_remove(); 2834c71ae41SShyam Sundar S K } 284