1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * AMD Platform Management Framework (PMF) Driver 4 * 5 * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 * All Rights Reserved. 7 * 8 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 9 */ 10 11 #include "pmf.h" 12 13 static struct amd_pmf_static_slider_granular config_store; 14 15 #ifdef CONFIG_AMD_PMF_DEBUG 16 static const char *slider_as_str(unsigned int state) 17 { 18 switch (state) { 19 case POWER_MODE_PERFORMANCE: 20 return "PERFORMANCE"; 21 case POWER_MODE_BALANCED_POWER: 22 return "BALANCED_POWER"; 23 case POWER_MODE_POWER_SAVER: 24 return "POWER_SAVER"; 25 default: 26 return "Unknown Slider State"; 27 } 28 } 29 30 const char *amd_pmf_source_as_str(unsigned int state) 31 { 32 switch (state) { 33 case POWER_SOURCE_AC: 34 return "AC"; 35 case POWER_SOURCE_DC: 36 return "DC"; 37 default: 38 return "Unknown Power State"; 39 } 40 } 41 42 static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) 43 { 44 int i, j; 45 46 pr_debug("Static Slider Data - BEGIN\n"); 47 48 for (i = 0; i < POWER_SOURCE_MAX; i++) { 49 for (j = 0; j < POWER_MODE_MAX; j++) { 50 pr_debug("--- Source:%s Mode:%s ---\n", amd_pmf_source_as_str(i), 51 slider_as_str(j)); 52 pr_debug("SPL: %u mW\n", data->prop[i][j].spl); 53 pr_debug("SPPT: %u mW\n", data->prop[i][j].sppt); 54 pr_debug("SPPT_ApuOnly: %u mW\n", data->prop[i][j].sppt_apu_only); 55 pr_debug("FPPT: %u mW\n", data->prop[i][j].fppt); 56 pr_debug("STTMinLimit: %u mW\n", data->prop[i][j].stt_min); 57 pr_debug("STT_SkinTempLimit_APU: %u C\n", 58 data->prop[i][j].stt_skin_temp[STT_TEMP_APU]); 59 pr_debug("STT_SkinTempLimit_HS2: %u C\n", 60 data->prop[i][j].stt_skin_temp[STT_TEMP_HS2]); 61 } 62 } 63 64 pr_debug("Static Slider Data - END\n"); 65 } 66 #else 67 static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {} 68 #endif 69 70 static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) 71 { 72 struct apmf_static_slider_granular_output output; 73 int i, j, idx = 0; 74 75 memset(&config_store, 0, sizeof(config_store)); 76 apmf_get_static_slider_granular(dev, &output); 77 78 for (i = 0; i < POWER_SOURCE_MAX; i++) { 79 for (j = 0; j < POWER_MODE_MAX; j++) { 80 config_store.prop[i][j].spl = output.prop[idx].spl; 81 config_store.prop[i][j].sppt = output.prop[idx].sppt; 82 config_store.prop[i][j].sppt_apu_only = 83 output.prop[idx].sppt_apu_only; 84 config_store.prop[i][j].fppt = output.prop[idx].fppt; 85 config_store.prop[i][j].stt_min = output.prop[idx].stt_min; 86 config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] = 87 output.prop[idx].stt_skin_temp[STT_TEMP_APU]; 88 config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] = 89 output.prop[idx].stt_skin_temp[STT_TEMP_HS2]; 90 config_store.prop[i][j].fan_id = output.prop[idx].fan_id; 91 idx++; 92 } 93 } 94 amd_pmf_dump_sps_defaults(&config_store); 95 } 96 97 void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, 98 struct amd_pmf_static_slider_granular *table) 99 { 100 int src = amd_pmf_get_power_source(); 101 102 if (op == SLIDER_OP_SET) { 103 amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); 104 amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); 105 amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); 106 amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, 107 config_store.prop[src][idx].sppt_apu_only, NULL); 108 amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 109 config_store.prop[src][idx].stt_min, NULL); 110 amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 111 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); 112 amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 113 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); 114 } else if (op == SLIDER_OP_GET) { 115 amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); 116 amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); 117 amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); 118 amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, 119 &table->prop[src][idx].sppt_apu_only); 120 amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, 121 &table->prop[src][idx].stt_min); 122 amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, 123 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); 124 amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, 125 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); 126 } 127 } 128 129 int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) 130 { 131 int mode; 132 133 mode = amd_pmf_get_pprof_modes(pmf); 134 if (mode < 0) 135 return mode; 136 137 amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); 138 139 return 0; 140 } 141 142 bool is_pprof_balanced(struct amd_pmf_dev *pmf) 143 { 144 return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; 145 } 146 147 static int amd_pmf_profile_get(struct platform_profile_handler *pprof, 148 enum platform_profile_option *profile) 149 { 150 struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 151 152 *profile = pmf->current_profile; 153 return 0; 154 } 155 156 int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) 157 { 158 int mode; 159 160 switch (pmf->current_profile) { 161 case PLATFORM_PROFILE_PERFORMANCE: 162 mode = POWER_MODE_PERFORMANCE; 163 break; 164 case PLATFORM_PROFILE_BALANCED: 165 mode = POWER_MODE_BALANCED_POWER; 166 break; 167 case PLATFORM_PROFILE_LOW_POWER: 168 mode = POWER_MODE_POWER_SAVER; 169 break; 170 default: 171 dev_err(pmf->dev, "Unknown Platform Profile.\n"); 172 return -EOPNOTSUPP; 173 } 174 175 return mode; 176 } 177 178 int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) 179 { 180 u8 flag = 0; 181 int mode; 182 int src; 183 184 mode = amd_pmf_get_pprof_modes(dev); 185 if (mode < 0) 186 return mode; 187 188 src = amd_pmf_get_power_source(); 189 190 if (src == POWER_SOURCE_AC) { 191 switch (mode) { 192 case POWER_MODE_PERFORMANCE: 193 flag |= BIT(AC_BEST_PERF); 194 break; 195 case POWER_MODE_BALANCED_POWER: 196 flag |= BIT(AC_BETTER_PERF); 197 break; 198 case POWER_MODE_POWER_SAVER: 199 flag |= BIT(AC_BETTER_BATTERY); 200 break; 201 default: 202 dev_err(dev->dev, "unsupported platform profile\n"); 203 return -EOPNOTSUPP; 204 } 205 206 } else if (src == POWER_SOURCE_DC) { 207 switch (mode) { 208 case POWER_MODE_PERFORMANCE: 209 flag |= BIT(DC_BEST_PERF); 210 break; 211 case POWER_MODE_BALANCED_POWER: 212 flag |= BIT(DC_BETTER_PERF); 213 break; 214 case POWER_MODE_POWER_SAVER: 215 flag |= BIT(DC_BATTERY_SAVER); 216 break; 217 default: 218 dev_err(dev->dev, "unsupported platform profile\n"); 219 return -EOPNOTSUPP; 220 } 221 } 222 223 apmf_os_power_slider_update(dev, flag); 224 225 return 0; 226 } 227 228 static int amd_pmf_profile_set(struct platform_profile_handler *pprof, 229 enum platform_profile_option profile) 230 { 231 struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 232 int ret = 0; 233 234 pmf->current_profile = profile; 235 236 /* Notify EC about the slider position change */ 237 if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { 238 ret = amd_pmf_power_slider_update_event(pmf); 239 if (ret) 240 return ret; 241 } 242 243 if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 244 ret = amd_pmf_set_sps_power_limits(pmf); 245 if (ret) 246 return ret; 247 } 248 249 return 0; 250 } 251 252 int amd_pmf_init_sps(struct amd_pmf_dev *dev) 253 { 254 int err; 255 256 dev->current_profile = PLATFORM_PROFILE_BALANCED; 257 258 if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 259 amd_pmf_load_defaults_sps(dev); 260 261 /* update SPS balanced power mode thermals */ 262 amd_pmf_set_sps_power_limits(dev); 263 } 264 265 dev->pprof.profile_get = amd_pmf_profile_get; 266 dev->pprof.profile_set = amd_pmf_profile_set; 267 268 /* Setup supported modes */ 269 set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); 270 set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); 271 set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); 272 273 /* Create platform_profile structure and register */ 274 err = platform_profile_register(&dev->pprof); 275 if (err) 276 dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", 277 err); 278 279 return err; 280 } 281 282 void amd_pmf_deinit_sps(struct amd_pmf_dev *dev) 283 { 284 platform_profile_remove(); 285 } 286