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_v2 config_store_v2; 14 static struct amd_pmf_static_slider_granular config_store; 15 static struct amd_pmf_apts_granular apts_config_store; 16 17 #ifdef CONFIG_AMD_PMF_DEBUG 18 static const char *slider_v2_as_str(unsigned int state) 19 { 20 switch (state) { 21 case POWER_MODE_BEST_PERFORMANCE: 22 return "Best Performance"; 23 case POWER_MODE_BALANCED: 24 return "Balanced"; 25 case POWER_MODE_BEST_POWER_EFFICIENCY: 26 return "Best Power Efficiency"; 27 case POWER_MODE_ENERGY_SAVE: 28 return "Energy Save"; 29 default: 30 return "Unknown Power Mode"; 31 } 32 } 33 34 static const char *slider_as_str(unsigned int state) 35 { 36 switch (state) { 37 case POWER_MODE_PERFORMANCE: 38 return "PERFORMANCE"; 39 case POWER_MODE_BALANCED_POWER: 40 return "BALANCED_POWER"; 41 case POWER_MODE_POWER_SAVER: 42 return "POWER_SAVER"; 43 default: 44 return "Unknown Slider State"; 45 } 46 } 47 48 const char *amd_pmf_source_as_str(unsigned int state) 49 { 50 switch (state) { 51 case POWER_SOURCE_AC: 52 return "AC"; 53 case POWER_SOURCE_DC: 54 return "DC"; 55 default: 56 return "Unknown Power State"; 57 } 58 } 59 60 static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) 61 { 62 int i, j; 63 64 pr_debug("Static Slider Data - BEGIN\n"); 65 66 for (i = 0; i < POWER_SOURCE_MAX; i++) { 67 for (j = 0; j < POWER_MODE_MAX; j++) { 68 pr_debug("--- Source:%s Mode:%s ---\n", amd_pmf_source_as_str(i), 69 slider_as_str(j)); 70 pr_debug("SPL: %u mW\n", data->prop[i][j].spl); 71 pr_debug("SPPT: %u mW\n", data->prop[i][j].sppt); 72 pr_debug("SPPT_ApuOnly: %u mW\n", data->prop[i][j].sppt_apu_only); 73 pr_debug("FPPT: %u mW\n", data->prop[i][j].fppt); 74 pr_debug("STTMinLimit: %u mW\n", data->prop[i][j].stt_min); 75 pr_debug("STT_SkinTempLimit_APU: %u C\n", 76 data->prop[i][j].stt_skin_temp[STT_TEMP_APU]); 77 pr_debug("STT_SkinTempLimit_HS2: %u C\n", 78 data->prop[i][j].stt_skin_temp[STT_TEMP_HS2]); 79 } 80 } 81 82 pr_debug("Static Slider Data - END\n"); 83 } 84 85 static void amd_pmf_dump_sps_defaults_v2(struct amd_pmf_static_slider_granular_v2 *data) 86 { 87 unsigned int i, j; 88 89 pr_debug("Static Slider APTS state index data - BEGIN"); 90 pr_debug("size: %u\n", data->size); 91 92 for (i = 0; i < POWER_SOURCE_MAX; i++) 93 for (j = 0; j < POWER_MODE_V2_MAX; j++) 94 pr_debug("%s %s: %u\n", amd_pmf_source_as_str(i), slider_v2_as_str(j), 95 data->sps_idx.power_states[i][j]); 96 97 pr_debug("Static Slider APTS state index data - END\n"); 98 } 99 100 static void amd_pmf_dump_apts_sps_defaults(struct amd_pmf_apts_granular *info) 101 { 102 int i; 103 104 pr_debug("Static Slider APTS index default values data - BEGIN"); 105 106 for (i = 0; i < APTS_MAX_STATES; i++) { 107 pr_debug("Table Version[%d] = %u\n", i, info->val[i].table_version); 108 pr_debug("Fan Index[%d] = %u\n", i, info->val[i].fan_table_idx); 109 pr_debug("PPT[%d] = %u\n", i, info->val[i].pmf_ppt); 110 pr_debug("PPT APU[%d] = %u\n", i, info->val[i].ppt_pmf_apu_only); 111 pr_debug("STT Min[%d] = %u\n", i, info->val[i].stt_min_limit); 112 pr_debug("STT APU[%d] = %u\n", i, info->val[i].stt_skin_temp_limit_apu); 113 pr_debug("STT HS2[%d] = %u\n", i, info->val[i].stt_skin_temp_limit_hs2); 114 } 115 116 pr_debug("Static Slider APTS index default values data - END"); 117 } 118 #else 119 static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {} 120 static void amd_pmf_dump_sps_defaults_v2(struct amd_pmf_static_slider_granular_v2 *data) {} 121 static void amd_pmf_dump_apts_sps_defaults(struct amd_pmf_apts_granular *info) {} 122 #endif 123 124 static void amd_pmf_load_apts_defaults_sps_v2(struct amd_pmf_dev *pdev) 125 { 126 struct amd_pmf_apts_granular_output output; 127 struct amd_pmf_apts_output *ps; 128 int i; 129 130 memset(&apts_config_store, 0, sizeof(apts_config_store)); 131 132 ps = apts_config_store.val; 133 134 for (i = 0; i < APTS_MAX_STATES; i++) { 135 apts_get_static_slider_granular_v2(pdev, &output, i); 136 ps[i].table_version = output.val.table_version; 137 ps[i].fan_table_idx = output.val.fan_table_idx; 138 ps[i].pmf_ppt = output.val.pmf_ppt; 139 ps[i].ppt_pmf_apu_only = output.val.ppt_pmf_apu_only; 140 ps[i].stt_min_limit = output.val.stt_min_limit; 141 ps[i].stt_skin_temp_limit_apu = output.val.stt_skin_temp_limit_apu; 142 ps[i].stt_skin_temp_limit_hs2 = output.val.stt_skin_temp_limit_hs2; 143 } 144 145 amd_pmf_dump_apts_sps_defaults(&apts_config_store); 146 } 147 148 static void amd_pmf_load_defaults_sps_v2(struct amd_pmf_dev *dev) 149 { 150 struct apmf_static_slider_granular_output_v2 output; 151 unsigned int i, j; 152 153 memset(&config_store_v2, 0, sizeof(config_store_v2)); 154 apmf_get_static_slider_granular_v2(dev, &output); 155 156 config_store_v2.size = output.size; 157 158 for (i = 0; i < POWER_SOURCE_MAX; i++) 159 for (j = 0; j < POWER_MODE_V2_MAX; j++) 160 config_store_v2.sps_idx.power_states[i][j] = 161 output.sps_idx.power_states[i][j]; 162 163 amd_pmf_dump_sps_defaults_v2(&config_store_v2); 164 } 165 166 static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev) 167 { 168 struct apmf_static_slider_granular_output output; 169 int i, j, idx = 0; 170 171 memset(&config_store, 0, sizeof(config_store)); 172 apmf_get_static_slider_granular(dev, &output); 173 174 for (i = 0; i < POWER_SOURCE_MAX; i++) { 175 for (j = 0; j < POWER_MODE_MAX; j++) { 176 config_store.prop[i][j].spl = output.prop[idx].spl; 177 config_store.prop[i][j].sppt = output.prop[idx].sppt; 178 config_store.prop[i][j].sppt_apu_only = 179 output.prop[idx].sppt_apu_only; 180 config_store.prop[i][j].fppt = output.prop[idx].fppt; 181 config_store.prop[i][j].stt_min = output.prop[idx].stt_min; 182 config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] = 183 output.prop[idx].stt_skin_temp[STT_TEMP_APU]; 184 config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] = 185 output.prop[idx].stt_skin_temp[STT_TEMP_HS2]; 186 config_store.prop[i][j].fan_id = output.prop[idx].fan_id; 187 idx++; 188 } 189 } 190 amd_pmf_dump_sps_defaults(&config_store); 191 } 192 193 static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx) 194 { 195 amd_pmf_send_cmd(dev, SET_PMF_PPT, false, apts_config_store.val[idx].pmf_ppt, NULL); 196 amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false, 197 apts_config_store.val[idx].ppt_pmf_apu_only, NULL); 198 amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 199 apts_config_store.val[idx].stt_min_limit, NULL); 200 amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 201 apts_config_store.val[idx].stt_skin_temp_limit_apu, NULL); 202 amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 203 apts_config_store.val[idx].stt_skin_temp_limit_hs2, NULL); 204 } 205 206 void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, 207 struct amd_pmf_static_slider_granular *table) 208 { 209 int src = amd_pmf_get_power_source(); 210 211 if (op == SLIDER_OP_SET) { 212 amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); 213 amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); 214 amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); 215 amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, 216 config_store.prop[src][idx].sppt_apu_only, NULL); 217 amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 218 config_store.prop[src][idx].stt_min, NULL); 219 amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 220 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); 221 amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 222 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); 223 } else if (op == SLIDER_OP_GET) { 224 amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); 225 amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); 226 amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); 227 amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, 228 &table->prop[src][idx].sppt_apu_only); 229 amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, 230 &table->prop[src][idx].stt_min); 231 amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, 232 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); 233 amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, 234 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); 235 } 236 } 237 238 static int amd_pmf_update_sps_power_limits_v2(struct amd_pmf_dev *pdev, int pwr_mode) 239 { 240 int src, index; 241 242 src = amd_pmf_get_power_source(); 243 244 switch (pwr_mode) { 245 case POWER_MODE_PERFORMANCE: 246 index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BEST_PERFORMANCE]; 247 amd_pmf_update_slider_v2(pdev, index); 248 break; 249 case POWER_MODE_BALANCED_POWER: 250 index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BALANCED]; 251 amd_pmf_update_slider_v2(pdev, index); 252 break; 253 case POWER_MODE_POWER_SAVER: 254 index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BEST_POWER_EFFICIENCY]; 255 amd_pmf_update_slider_v2(pdev, index); 256 break; 257 default: 258 return -EINVAL; 259 } 260 261 return 0; 262 } 263 264 int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) 265 { 266 int mode; 267 268 mode = amd_pmf_get_pprof_modes(pmf); 269 if (mode < 0) 270 return mode; 271 272 if (pmf->pmf_if_version == PMF_IF_V2) 273 return amd_pmf_update_sps_power_limits_v2(pmf, mode); 274 275 amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); 276 277 return 0; 278 } 279 280 bool is_pprof_balanced(struct amd_pmf_dev *pmf) 281 { 282 return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; 283 } 284 285 static int amd_pmf_profile_get(struct platform_profile_handler *pprof, 286 enum platform_profile_option *profile) 287 { 288 struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 289 290 *profile = pmf->current_profile; 291 return 0; 292 } 293 294 int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) 295 { 296 int mode; 297 298 switch (pmf->current_profile) { 299 case PLATFORM_PROFILE_PERFORMANCE: 300 mode = POWER_MODE_PERFORMANCE; 301 break; 302 case PLATFORM_PROFILE_BALANCED: 303 mode = POWER_MODE_BALANCED_POWER; 304 break; 305 case PLATFORM_PROFILE_LOW_POWER: 306 mode = POWER_MODE_POWER_SAVER; 307 break; 308 default: 309 dev_err(pmf->dev, "Unknown Platform Profile.\n"); 310 return -EOPNOTSUPP; 311 } 312 313 return mode; 314 } 315 316 int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) 317 { 318 u8 flag = 0; 319 int mode; 320 int src; 321 322 mode = amd_pmf_get_pprof_modes(dev); 323 if (mode < 0) 324 return mode; 325 326 src = amd_pmf_get_power_source(); 327 328 if (src == POWER_SOURCE_AC) { 329 switch (mode) { 330 case POWER_MODE_PERFORMANCE: 331 flag |= BIT(AC_BEST_PERF); 332 break; 333 case POWER_MODE_BALANCED_POWER: 334 flag |= BIT(AC_BETTER_PERF); 335 break; 336 case POWER_MODE_POWER_SAVER: 337 flag |= BIT(AC_BETTER_BATTERY); 338 break; 339 default: 340 dev_err(dev->dev, "unsupported platform profile\n"); 341 return -EOPNOTSUPP; 342 } 343 344 } else if (src == POWER_SOURCE_DC) { 345 switch (mode) { 346 case POWER_MODE_PERFORMANCE: 347 flag |= BIT(DC_BEST_PERF); 348 break; 349 case POWER_MODE_BALANCED_POWER: 350 flag |= BIT(DC_BETTER_PERF); 351 break; 352 case POWER_MODE_POWER_SAVER: 353 flag |= BIT(DC_BATTERY_SAVER); 354 break; 355 default: 356 dev_err(dev->dev, "unsupported platform profile\n"); 357 return -EOPNOTSUPP; 358 } 359 } 360 361 apmf_os_power_slider_update(dev, flag); 362 363 return 0; 364 } 365 366 static int amd_pmf_profile_set(struct platform_profile_handler *pprof, 367 enum platform_profile_option profile) 368 { 369 struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 370 int ret = 0; 371 372 pmf->current_profile = profile; 373 374 /* Notify EC about the slider position change */ 375 if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { 376 ret = amd_pmf_power_slider_update_event(pmf); 377 if (ret) 378 return ret; 379 } 380 381 if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 382 ret = amd_pmf_set_sps_power_limits(pmf); 383 if (ret) 384 return ret; 385 } 386 387 return 0; 388 } 389 390 int amd_pmf_init_sps(struct amd_pmf_dev *dev) 391 { 392 int err; 393 394 dev->current_profile = PLATFORM_PROFILE_BALANCED; 395 396 if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 397 if (dev->pmf_if_version == PMF_IF_V2) { 398 amd_pmf_load_defaults_sps_v2(dev); 399 amd_pmf_load_apts_defaults_sps_v2(dev); 400 } else { 401 amd_pmf_load_defaults_sps(dev); 402 } 403 404 /* update SPS balanced power mode thermals */ 405 amd_pmf_set_sps_power_limits(dev); 406 } 407 408 dev->pprof.profile_get = amd_pmf_profile_get; 409 dev->pprof.profile_set = amd_pmf_profile_set; 410 411 /* Setup supported modes */ 412 set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); 413 set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); 414 set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); 415 416 /* Create platform_profile structure and register */ 417 err = platform_profile_register(&dev->pprof); 418 if (err) 419 dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", 420 err); 421 422 return err; 423 } 424 425 void amd_pmf_deinit_sps(struct amd_pmf_dev *dev) 426 { 427 platform_profile_remove(); 428 } 429