162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AMD Platform Management Framework (PMF) Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2022, Advanced Micro Devices, Inc. 662306a36Sopenharmony_ci * All Rights Reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "pmf.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic struct amd_pmf_static_slider_granular config_store; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#ifdef CONFIG_AMD_PMF_DEBUG 1662306a36Sopenharmony_cistatic const char *slider_as_str(unsigned int state) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci switch (state) { 1962306a36Sopenharmony_ci case POWER_MODE_PERFORMANCE: 2062306a36Sopenharmony_ci return "PERFORMANCE"; 2162306a36Sopenharmony_ci case POWER_MODE_BALANCED_POWER: 2262306a36Sopenharmony_ci return "BALANCED_POWER"; 2362306a36Sopenharmony_ci case POWER_MODE_POWER_SAVER: 2462306a36Sopenharmony_ci return "POWER_SAVER"; 2562306a36Sopenharmony_ci default: 2662306a36Sopenharmony_ci return "Unknown Slider State"; 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const char *source_as_str(unsigned int state) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci switch (state) { 3362306a36Sopenharmony_ci case POWER_SOURCE_AC: 3462306a36Sopenharmony_ci return "AC"; 3562306a36Sopenharmony_ci case POWER_SOURCE_DC: 3662306a36Sopenharmony_ci return "DC"; 3762306a36Sopenharmony_ci default: 3862306a36Sopenharmony_ci return "Unknown Power State"; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci int i, j; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci pr_debug("Static Slider Data - BEGIN\n"); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci for (i = 0; i < POWER_SOURCE_MAX; i++) { 4962306a36Sopenharmony_ci for (j = 0; j < POWER_MODE_MAX; j++) { 5062306a36Sopenharmony_ci pr_debug("--- Source:%s Mode:%s ---\n", source_as_str(i), slider_as_str(j)); 5162306a36Sopenharmony_ci pr_debug("SPL: %u mW\n", data->prop[i][j].spl); 5262306a36Sopenharmony_ci pr_debug("SPPT: %u mW\n", data->prop[i][j].sppt); 5362306a36Sopenharmony_ci pr_debug("SPPT_ApuOnly: %u mW\n", data->prop[i][j].sppt_apu_only); 5462306a36Sopenharmony_ci pr_debug("FPPT: %u mW\n", data->prop[i][j].fppt); 5562306a36Sopenharmony_ci pr_debug("STTMinLimit: %u mW\n", data->prop[i][j].stt_min); 5662306a36Sopenharmony_ci pr_debug("STT_SkinTempLimit_APU: %u C\n", 5762306a36Sopenharmony_ci data->prop[i][j].stt_skin_temp[STT_TEMP_APU]); 5862306a36Sopenharmony_ci pr_debug("STT_SkinTempLimit_HS2: %u C\n", 5962306a36Sopenharmony_ci data->prop[i][j].stt_skin_temp[STT_TEMP_HS2]); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci pr_debug("Static Slider Data - END\n"); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci#else 6662306a36Sopenharmony_cistatic void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {} 6762306a36Sopenharmony_ci#endif 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct apmf_static_slider_granular_output output; 7262306a36Sopenharmony_ci int i, j, idx = 0; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci memset(&config_store, 0, sizeof(config_store)); 7562306a36Sopenharmony_ci apmf_get_static_slider_granular(dev, &output); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci for (i = 0; i < POWER_SOURCE_MAX; i++) { 7862306a36Sopenharmony_ci for (j = 0; j < POWER_MODE_MAX; j++) { 7962306a36Sopenharmony_ci config_store.prop[i][j].spl = output.prop[idx].spl; 8062306a36Sopenharmony_ci config_store.prop[i][j].sppt = output.prop[idx].sppt; 8162306a36Sopenharmony_ci config_store.prop[i][j].sppt_apu_only = 8262306a36Sopenharmony_ci output.prop[idx].sppt_apu_only; 8362306a36Sopenharmony_ci config_store.prop[i][j].fppt = output.prop[idx].fppt; 8462306a36Sopenharmony_ci config_store.prop[i][j].stt_min = output.prop[idx].stt_min; 8562306a36Sopenharmony_ci config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] = 8662306a36Sopenharmony_ci output.prop[idx].stt_skin_temp[STT_TEMP_APU]; 8762306a36Sopenharmony_ci config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] = 8862306a36Sopenharmony_ci output.prop[idx].stt_skin_temp[STT_TEMP_HS2]; 8962306a36Sopenharmony_ci config_store.prop[i][j].fan_id = output.prop[idx].fan_id; 9062306a36Sopenharmony_ci idx++; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci amd_pmf_dump_sps_defaults(&config_store); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, 9762306a36Sopenharmony_ci struct amd_pmf_static_slider_granular *table) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci int src = amd_pmf_get_power_source(); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (op == SLIDER_OP_SET) { 10262306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); 10362306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); 10462306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); 10562306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, 10662306a36Sopenharmony_ci config_store.prop[src][idx].sppt_apu_only, NULL); 10762306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 10862306a36Sopenharmony_ci config_store.prop[src][idx].stt_min, NULL); 10962306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 11062306a36Sopenharmony_ci config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); 11162306a36Sopenharmony_ci amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 11262306a36Sopenharmony_ci config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); 11362306a36Sopenharmony_ci } else if (op == SLIDER_OP_GET) { 11462306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); 11562306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); 11662306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); 11762306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, 11862306a36Sopenharmony_ci &table->prop[src][idx].sppt_apu_only); 11962306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, 12062306a36Sopenharmony_ci &table->prop[src][idx].stt_min); 12162306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, 12262306a36Sopenharmony_ci (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); 12362306a36Sopenharmony_ci amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, 12462306a36Sopenharmony_ci (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciint amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int mode; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci mode = amd_pmf_get_pprof_modes(pmf); 13362306a36Sopenharmony_ci if (mode < 0) 13462306a36Sopenharmony_ci return mode; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cibool is_pprof_balanced(struct amd_pmf_dev *pmf) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int amd_pmf_profile_get(struct platform_profile_handler *pprof, 14762306a36Sopenharmony_ci enum platform_profile_option *profile) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci *profile = pmf->current_profile; 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciint amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci int mode; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci switch (pmf->current_profile) { 16062306a36Sopenharmony_ci case PLATFORM_PROFILE_PERFORMANCE: 16162306a36Sopenharmony_ci mode = POWER_MODE_PERFORMANCE; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci case PLATFORM_PROFILE_BALANCED: 16462306a36Sopenharmony_ci mode = POWER_MODE_BALANCED_POWER; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci case PLATFORM_PROFILE_LOW_POWER: 16762306a36Sopenharmony_ci mode = POWER_MODE_POWER_SAVER; 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci default: 17062306a36Sopenharmony_ci dev_err(pmf->dev, "Unknown Platform Profile.\n"); 17162306a36Sopenharmony_ci return -EOPNOTSUPP; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return mode; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciint amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci u8 flag = 0; 18062306a36Sopenharmony_ci int mode; 18162306a36Sopenharmony_ci int src; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci mode = amd_pmf_get_pprof_modes(dev); 18462306a36Sopenharmony_ci if (mode < 0) 18562306a36Sopenharmony_ci return mode; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci src = amd_pmf_get_power_source(); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (src == POWER_SOURCE_AC) { 19062306a36Sopenharmony_ci switch (mode) { 19162306a36Sopenharmony_ci case POWER_MODE_PERFORMANCE: 19262306a36Sopenharmony_ci flag |= BIT(AC_BEST_PERF); 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci case POWER_MODE_BALANCED_POWER: 19562306a36Sopenharmony_ci flag |= BIT(AC_BETTER_PERF); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci case POWER_MODE_POWER_SAVER: 19862306a36Sopenharmony_ci flag |= BIT(AC_BETTER_BATTERY); 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci default: 20162306a36Sopenharmony_ci dev_err(dev->dev, "unsupported platform profile\n"); 20262306a36Sopenharmony_ci return -EOPNOTSUPP; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci } else if (src == POWER_SOURCE_DC) { 20662306a36Sopenharmony_ci switch (mode) { 20762306a36Sopenharmony_ci case POWER_MODE_PERFORMANCE: 20862306a36Sopenharmony_ci flag |= BIT(DC_BEST_PERF); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci case POWER_MODE_BALANCED_POWER: 21162306a36Sopenharmony_ci flag |= BIT(DC_BETTER_PERF); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci case POWER_MODE_POWER_SAVER: 21462306a36Sopenharmony_ci flag |= BIT(DC_BATTERY_SAVER); 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci default: 21762306a36Sopenharmony_ci dev_err(dev->dev, "unsupported platform profile\n"); 21862306a36Sopenharmony_ci return -EOPNOTSUPP; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci apmf_os_power_slider_update(dev, flag); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int amd_pmf_profile_set(struct platform_profile_handler *pprof, 22862306a36Sopenharmony_ci enum platform_profile_option profile) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 23162306a36Sopenharmony_ci int ret = 0; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci pmf->current_profile = profile; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Notify EC about the slider position change */ 23662306a36Sopenharmony_ci if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { 23762306a36Sopenharmony_ci ret = amd_pmf_power_slider_update_event(pmf); 23862306a36Sopenharmony_ci if (ret) 23962306a36Sopenharmony_ci return ret; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 24362306a36Sopenharmony_ci ret = amd_pmf_set_sps_power_limits(pmf); 24462306a36Sopenharmony_ci if (ret) 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ciint amd_pmf_init_sps(struct amd_pmf_dev *dev) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int err; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dev->current_profile = PLATFORM_PROFILE_BALANCED; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 25862306a36Sopenharmony_ci amd_pmf_load_defaults_sps(dev); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* update SPS balanced power mode thermals */ 26162306a36Sopenharmony_ci amd_pmf_set_sps_power_limits(dev); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dev->pprof.profile_get = amd_pmf_profile_get; 26562306a36Sopenharmony_ci dev->pprof.profile_set = amd_pmf_profile_set; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Setup supported modes */ 26862306a36Sopenharmony_ci set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); 26962306a36Sopenharmony_ci set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); 27062306a36Sopenharmony_ci set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Create platform_profile structure and register */ 27362306a36Sopenharmony_ci err = platform_profile_register(&dev->pprof); 27462306a36Sopenharmony_ci if (err) 27562306a36Sopenharmony_ci dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", 27662306a36Sopenharmony_ci err); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return err; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_civoid amd_pmf_deinit_sps(struct amd_pmf_dev *dev) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci platform_profile_remove(); 28462306a36Sopenharmony_ci} 285