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 30*4984dbb6SShyam Sundar S K const char *amd_pmf_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++) { 50*4984dbb6SShyam Sundar S K pr_debug("--- Source:%s Mode:%s ---\n", amd_pmf_source_as_str(i), 51*4984dbb6SShyam Sundar S K slider_as_str(j)); 52a82ebb3dSShyam Sundar S K pr_debug("SPL: %u mW\n", data->prop[i][j].spl); 53a82ebb3dSShyam Sundar S K pr_debug("SPPT: %u mW\n", data->prop[i][j].sppt); 54a82ebb3dSShyam Sundar S K pr_debug("SPPT_ApuOnly: %u mW\n", data->prop[i][j].sppt_apu_only); 55a82ebb3dSShyam Sundar S K pr_debug("FPPT: %u mW\n", data->prop[i][j].fppt); 56a82ebb3dSShyam Sundar S K pr_debug("STTMinLimit: %u mW\n", data->prop[i][j].stt_min); 57a82ebb3dSShyam Sundar S K pr_debug("STT_SkinTempLimit_APU: %u C\n", 58a82ebb3dSShyam Sundar S K data->prop[i][j].stt_skin_temp[STT_TEMP_APU]); 59a82ebb3dSShyam Sundar S K pr_debug("STT_SkinTempLimit_HS2: %u C\n", 60a82ebb3dSShyam Sundar S K data->prop[i][j].stt_skin_temp[STT_TEMP_HS2]); 61a82ebb3dSShyam Sundar S K } 62a82ebb3dSShyam Sundar S K } 63a82ebb3dSShyam Sundar S K 64a82ebb3dSShyam Sundar S K pr_debug("Static Slider Data - END\n"); 65a82ebb3dSShyam Sundar S K } 66a82ebb3dSShyam Sundar S K #else 67a82ebb3dSShyam Sundar S K static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {} 68a82ebb3dSShyam Sundar S K #endif 69a82ebb3dSShyam Sundar S K 704c71ae41SShyam Sundar S K static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) 714c71ae41SShyam Sundar S K { 724c71ae41SShyam Sundar S K struct apmf_static_slider_granular_output output; 734c71ae41SShyam Sundar S K int i, j, idx = 0; 744c71ae41SShyam Sundar S K 754c71ae41SShyam Sundar S K memset(&config_store, 0, sizeof(config_store)); 764c71ae41SShyam Sundar S K apmf_get_static_slider_granular(dev, &output); 774c71ae41SShyam Sundar S K 784c71ae41SShyam Sundar S K for (i = 0; i < POWER_SOURCE_MAX; i++) { 794c71ae41SShyam Sundar S K for (j = 0; j < POWER_MODE_MAX; j++) { 804c71ae41SShyam Sundar S K config_store.prop[i][j].spl = output.prop[idx].spl; 814c71ae41SShyam Sundar S K config_store.prop[i][j].sppt = output.prop[idx].sppt; 824c71ae41SShyam Sundar S K config_store.prop[i][j].sppt_apu_only = 834c71ae41SShyam Sundar S K output.prop[idx].sppt_apu_only; 844c71ae41SShyam Sundar S K config_store.prop[i][j].fppt = output.prop[idx].fppt; 854c71ae41SShyam Sundar S K config_store.prop[i][j].stt_min = output.prop[idx].stt_min; 864c71ae41SShyam Sundar S K config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] = 874c71ae41SShyam Sundar S K output.prop[idx].stt_skin_temp[STT_TEMP_APU]; 884c71ae41SShyam Sundar S K config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] = 894c71ae41SShyam Sundar S K output.prop[idx].stt_skin_temp[STT_TEMP_HS2]; 904c71ae41SShyam Sundar S K config_store.prop[i][j].fan_id = output.prop[idx].fan_id; 914c71ae41SShyam Sundar S K idx++; 924c71ae41SShyam Sundar S K } 934c71ae41SShyam Sundar S K } 94a82ebb3dSShyam Sundar S K amd_pmf_dump_sps_defaults(&config_store); 954c71ae41SShyam Sundar S K } 964c71ae41SShyam Sundar S K 974c71ae41SShyam Sundar S K void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, 984c71ae41SShyam Sundar S K struct amd_pmf_static_slider_granular *table) 994c71ae41SShyam Sundar S K { 1004c71ae41SShyam Sundar S K int src = amd_pmf_get_power_source(); 1014c71ae41SShyam Sundar S K 1024c71ae41SShyam Sundar S K if (op == SLIDER_OP_SET) { 1034c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); 1044c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); 1054c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); 1064c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, 1074c71ae41SShyam Sundar S K config_store.prop[src][idx].sppt_apu_only, NULL); 1084c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 1094c71ae41SShyam Sundar S K config_store.prop[src][idx].stt_min, NULL); 1104c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 1114c71ae41SShyam Sundar S K config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); 1124c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 1134c71ae41SShyam Sundar S K config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); 1144c71ae41SShyam Sundar S K } else if (op == SLIDER_OP_GET) { 1154c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); 1164c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); 1174c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); 1184c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, 1194c71ae41SShyam Sundar S K &table->prop[src][idx].sppt_apu_only); 1204c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, 1214c71ae41SShyam Sundar S K &table->prop[src][idx].stt_min); 1224c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, 1234c71ae41SShyam Sundar S K (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); 1244c71ae41SShyam Sundar S K amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, 1254c71ae41SShyam Sundar S K (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); 1264c71ae41SShyam Sundar S K } 1274c71ae41SShyam Sundar S K } 1284c71ae41SShyam Sundar S K 129c5258d39SShyam Sundar S K int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) 130c5258d39SShyam Sundar S K { 131c5258d39SShyam Sundar S K int mode; 132c5258d39SShyam Sundar S K 133c5258d39SShyam Sundar S K mode = amd_pmf_get_pprof_modes(pmf); 134c5258d39SShyam Sundar S K if (mode < 0) 135c5258d39SShyam Sundar S K return mode; 136c5258d39SShyam Sundar S K 137c5258d39SShyam Sundar S K amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); 138c5258d39SShyam Sundar S K 139c5258d39SShyam Sundar S K return 0; 140c5258d39SShyam Sundar S K } 141c5258d39SShyam Sundar S K 14216909aa8SShyam Sundar S K bool is_pprof_balanced(struct amd_pmf_dev *pmf) 14316909aa8SShyam Sundar S K { 14416909aa8SShyam Sundar S K return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; 14516909aa8SShyam Sundar S K } 14616909aa8SShyam Sundar S K 1474c71ae41SShyam Sundar S K static int amd_pmf_profile_get(struct platform_profile_handler *pprof, 1484c71ae41SShyam Sundar S K enum platform_profile_option *profile) 1494c71ae41SShyam Sundar S K { 1504c71ae41SShyam Sundar S K struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 1514c71ae41SShyam Sundar S K 1524c71ae41SShyam Sundar S K *profile = pmf->current_profile; 1534c71ae41SShyam Sundar S K return 0; 1544c71ae41SShyam Sundar S K } 1554c71ae41SShyam Sundar S K 156ea522b80SShyam Sundar S K int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) 1574c71ae41SShyam Sundar S K { 158ea522b80SShyam Sundar S K int mode; 1594c71ae41SShyam Sundar S K 1604c71ae41SShyam Sundar S K switch (pmf->current_profile) { 1614c71ae41SShyam Sundar S K case PLATFORM_PROFILE_PERFORMANCE: 1624c71ae41SShyam Sundar S K mode = POWER_MODE_PERFORMANCE; 1634c71ae41SShyam Sundar S K break; 1644c71ae41SShyam Sundar S K case PLATFORM_PROFILE_BALANCED: 1654c71ae41SShyam Sundar S K mode = POWER_MODE_BALANCED_POWER; 1664c71ae41SShyam Sundar S K break; 1674c71ae41SShyam Sundar S K case PLATFORM_PROFILE_LOW_POWER: 1684c71ae41SShyam Sundar S K mode = POWER_MODE_POWER_SAVER; 1694c71ae41SShyam Sundar S K break; 1704c71ae41SShyam Sundar S K default: 1714c71ae41SShyam Sundar S K dev_err(pmf->dev, "Unknown Platform Profile.\n"); 172ea522b80SShyam Sundar S K return -EOPNOTSUPP; 1734c71ae41SShyam Sundar S K } 1744c71ae41SShyam Sundar S K 1754c71ae41SShyam Sundar S K return mode; 1764c71ae41SShyam Sundar S K } 1774c71ae41SShyam Sundar S K 17833c9ab5bSShyam Sundar S K int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) 17933c9ab5bSShyam Sundar S K { 180785c0099SYang Li u8 flag = 0; 181785c0099SYang Li int mode; 18233c9ab5bSShyam Sundar S K int src; 18333c9ab5bSShyam Sundar S K 18433c9ab5bSShyam Sundar S K mode = amd_pmf_get_pprof_modes(dev); 18533c9ab5bSShyam Sundar S K if (mode < 0) 18633c9ab5bSShyam Sundar S K return mode; 18733c9ab5bSShyam Sundar S K 18833c9ab5bSShyam Sundar S K src = amd_pmf_get_power_source(); 18933c9ab5bSShyam Sundar S K 19033c9ab5bSShyam Sundar S K if (src == POWER_SOURCE_AC) { 19133c9ab5bSShyam Sundar S K switch (mode) { 19233c9ab5bSShyam Sundar S K case POWER_MODE_PERFORMANCE: 19333c9ab5bSShyam Sundar S K flag |= BIT(AC_BEST_PERF); 19433c9ab5bSShyam Sundar S K break; 19533c9ab5bSShyam Sundar S K case POWER_MODE_BALANCED_POWER: 19633c9ab5bSShyam Sundar S K flag |= BIT(AC_BETTER_PERF); 19733c9ab5bSShyam Sundar S K break; 19833c9ab5bSShyam Sundar S K case POWER_MODE_POWER_SAVER: 19933c9ab5bSShyam Sundar S K flag |= BIT(AC_BETTER_BATTERY); 20033c9ab5bSShyam Sundar S K break; 20133c9ab5bSShyam Sundar S K default: 20233c9ab5bSShyam Sundar S K dev_err(dev->dev, "unsupported platform profile\n"); 20333c9ab5bSShyam Sundar S K return -EOPNOTSUPP; 20433c9ab5bSShyam Sundar S K } 20533c9ab5bSShyam Sundar S K 20633c9ab5bSShyam Sundar S K } else if (src == POWER_SOURCE_DC) { 20733c9ab5bSShyam Sundar S K switch (mode) { 20833c9ab5bSShyam Sundar S K case POWER_MODE_PERFORMANCE: 20933c9ab5bSShyam Sundar S K flag |= BIT(DC_BEST_PERF); 21033c9ab5bSShyam Sundar S K break; 21133c9ab5bSShyam Sundar S K case POWER_MODE_BALANCED_POWER: 21233c9ab5bSShyam Sundar S K flag |= BIT(DC_BETTER_PERF); 21333c9ab5bSShyam Sundar S K break; 21433c9ab5bSShyam Sundar S K case POWER_MODE_POWER_SAVER: 21533c9ab5bSShyam Sundar S K flag |= BIT(DC_BATTERY_SAVER); 21633c9ab5bSShyam Sundar S K break; 21733c9ab5bSShyam Sundar S K default: 21833c9ab5bSShyam Sundar S K dev_err(dev->dev, "unsupported platform profile\n"); 21933c9ab5bSShyam Sundar S K return -EOPNOTSUPP; 22033c9ab5bSShyam Sundar S K } 22133c9ab5bSShyam Sundar S K } 22233c9ab5bSShyam Sundar S K 22333c9ab5bSShyam Sundar S K apmf_os_power_slider_update(dev, flag); 22433c9ab5bSShyam Sundar S K 22533c9ab5bSShyam Sundar S K return 0; 22633c9ab5bSShyam Sundar S K } 22733c9ab5bSShyam Sundar S K 2284c71ae41SShyam Sundar S K static int amd_pmf_profile_set(struct platform_profile_handler *pprof, 2294c71ae41SShyam Sundar S K enum platform_profile_option profile) 2304c71ae41SShyam Sundar S K { 2314c71ae41SShyam Sundar S K struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 23233c9ab5bSShyam Sundar S K int ret = 0; 2334c71ae41SShyam Sundar S K 2344c71ae41SShyam Sundar S K pmf->current_profile = profile; 235ea522b80SShyam Sundar S K 23633c9ab5bSShyam Sundar S K /* Notify EC about the slider position change */ 23733c9ab5bSShyam Sundar S K if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { 23833c9ab5bSShyam Sundar S K ret = amd_pmf_power_slider_update_event(pmf); 23933c9ab5bSShyam Sundar S K if (ret) 24033c9ab5bSShyam Sundar S K return ret; 24133c9ab5bSShyam Sundar S K } 24233c9ab5bSShyam Sundar S K 24333c9ab5bSShyam Sundar S K if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 24433c9ab5bSShyam Sundar S K ret = amd_pmf_set_sps_power_limits(pmf); 24533c9ab5bSShyam Sundar S K if (ret) 24633c9ab5bSShyam Sundar S K return ret; 24733c9ab5bSShyam Sundar S K } 24833c9ab5bSShyam Sundar S K 24933c9ab5bSShyam Sundar S K return 0; 2504c71ae41SShyam Sundar S K } 2514c71ae41SShyam Sundar S K 2524c71ae41SShyam Sundar S K int amd_pmf_init_sps(struct amd_pmf_dev *dev) 2534c71ae41SShyam Sundar S K { 2544c71ae41SShyam Sundar S K int err; 2554c71ae41SShyam Sundar S K 2564c71ae41SShyam Sundar S K dev->current_profile = PLATFORM_PROFILE_BALANCED; 25733c9ab5bSShyam Sundar S K 25833c9ab5bSShyam Sundar S K if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 2594c71ae41SShyam Sundar S K amd_pmf_load_defaults_sps(dev); 2604c71ae41SShyam Sundar S K 261635f79bcSShyam Sundar S K /* update SPS balanced power mode thermals */ 262635f79bcSShyam Sundar S K amd_pmf_set_sps_power_limits(dev); 26333c9ab5bSShyam Sundar S K } 264635f79bcSShyam Sundar S K 2654c71ae41SShyam Sundar S K dev->pprof.profile_get = amd_pmf_profile_get; 2664c71ae41SShyam Sundar S K dev->pprof.profile_set = amd_pmf_profile_set; 2674c71ae41SShyam Sundar S K 2684c71ae41SShyam Sundar S K /* Setup supported modes */ 2694c71ae41SShyam Sundar S K set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); 2704c71ae41SShyam Sundar S K set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); 2714c71ae41SShyam Sundar S K set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); 2724c71ae41SShyam Sundar S K 2734c71ae41SShyam Sundar S K /* Create platform_profile structure and register */ 2744c71ae41SShyam Sundar S K err = platform_profile_register(&dev->pprof); 2754c71ae41SShyam Sundar S K if (err) 2764c71ae41SShyam Sundar S K dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", 2774c71ae41SShyam Sundar S K err); 2784c71ae41SShyam Sundar S K 2794c71ae41SShyam Sundar S K return err; 2804c71ae41SShyam Sundar S K } 2814c71ae41SShyam Sundar S K 2824c71ae41SShyam Sundar S K void amd_pmf_deinit_sps(struct amd_pmf_dev *dev) 2834c71ae41SShyam Sundar S K { 2844c71ae41SShyam Sundar S K platform_profile_remove(); 2854c71ae41SShyam Sundar S K } 286