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 void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx, 194 struct amd_pmf_static_slider_granular *table) 195 { 196 int src = amd_pmf_get_power_source(); 197 198 if (op == SLIDER_OP_SET) { 199 amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL); 200 amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL); 201 amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL); 202 amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, 203 config_store.prop[src][idx].sppt_apu_only, NULL); 204 amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, 205 config_store.prop[src][idx].stt_min, NULL); 206 amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, 207 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL); 208 amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, 209 config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL); 210 } else if (op == SLIDER_OP_GET) { 211 amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl); 212 amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt); 213 amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt); 214 amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE, 215 &table->prop[src][idx].sppt_apu_only); 216 amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE, 217 &table->prop[src][idx].stt_min); 218 amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE, 219 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]); 220 amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE, 221 (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]); 222 } 223 } 224 225 int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf) 226 { 227 int mode; 228 229 mode = amd_pmf_get_pprof_modes(pmf); 230 if (mode < 0) 231 return mode; 232 233 amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL); 234 235 return 0; 236 } 237 238 bool is_pprof_balanced(struct amd_pmf_dev *pmf) 239 { 240 return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false; 241 } 242 243 static int amd_pmf_profile_get(struct platform_profile_handler *pprof, 244 enum platform_profile_option *profile) 245 { 246 struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 247 248 *profile = pmf->current_profile; 249 return 0; 250 } 251 252 int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf) 253 { 254 int mode; 255 256 switch (pmf->current_profile) { 257 case PLATFORM_PROFILE_PERFORMANCE: 258 mode = POWER_MODE_PERFORMANCE; 259 break; 260 case PLATFORM_PROFILE_BALANCED: 261 mode = POWER_MODE_BALANCED_POWER; 262 break; 263 case PLATFORM_PROFILE_LOW_POWER: 264 mode = POWER_MODE_POWER_SAVER; 265 break; 266 default: 267 dev_err(pmf->dev, "Unknown Platform Profile.\n"); 268 return -EOPNOTSUPP; 269 } 270 271 return mode; 272 } 273 274 int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev) 275 { 276 u8 flag = 0; 277 int mode; 278 int src; 279 280 mode = amd_pmf_get_pprof_modes(dev); 281 if (mode < 0) 282 return mode; 283 284 src = amd_pmf_get_power_source(); 285 286 if (src == POWER_SOURCE_AC) { 287 switch (mode) { 288 case POWER_MODE_PERFORMANCE: 289 flag |= BIT(AC_BEST_PERF); 290 break; 291 case POWER_MODE_BALANCED_POWER: 292 flag |= BIT(AC_BETTER_PERF); 293 break; 294 case POWER_MODE_POWER_SAVER: 295 flag |= BIT(AC_BETTER_BATTERY); 296 break; 297 default: 298 dev_err(dev->dev, "unsupported platform profile\n"); 299 return -EOPNOTSUPP; 300 } 301 302 } else if (src == POWER_SOURCE_DC) { 303 switch (mode) { 304 case POWER_MODE_PERFORMANCE: 305 flag |= BIT(DC_BEST_PERF); 306 break; 307 case POWER_MODE_BALANCED_POWER: 308 flag |= BIT(DC_BETTER_PERF); 309 break; 310 case POWER_MODE_POWER_SAVER: 311 flag |= BIT(DC_BATTERY_SAVER); 312 break; 313 default: 314 dev_err(dev->dev, "unsupported platform profile\n"); 315 return -EOPNOTSUPP; 316 } 317 } 318 319 apmf_os_power_slider_update(dev, flag); 320 321 return 0; 322 } 323 324 static int amd_pmf_profile_set(struct platform_profile_handler *pprof, 325 enum platform_profile_option profile) 326 { 327 struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof); 328 int ret = 0; 329 330 pmf->current_profile = profile; 331 332 /* Notify EC about the slider position change */ 333 if (is_apmf_func_supported(pmf, APMF_FUNC_OS_POWER_SLIDER_UPDATE)) { 334 ret = amd_pmf_power_slider_update_event(pmf); 335 if (ret) 336 return ret; 337 } 338 339 if (is_apmf_func_supported(pmf, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 340 ret = amd_pmf_set_sps_power_limits(pmf); 341 if (ret) 342 return ret; 343 } 344 345 return 0; 346 } 347 348 int amd_pmf_init_sps(struct amd_pmf_dev *dev) 349 { 350 int err; 351 352 dev->current_profile = PLATFORM_PROFILE_BALANCED; 353 354 if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) { 355 if (dev->pmf_if_version == PMF_IF_V2) { 356 amd_pmf_load_defaults_sps_v2(dev); 357 amd_pmf_load_apts_defaults_sps_v2(dev); 358 } else { 359 amd_pmf_load_defaults_sps(dev); 360 } 361 362 /* update SPS balanced power mode thermals */ 363 amd_pmf_set_sps_power_limits(dev); 364 } 365 366 dev->pprof.profile_get = amd_pmf_profile_get; 367 dev->pprof.profile_set = amd_pmf_profile_set; 368 369 /* Setup supported modes */ 370 set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices); 371 set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices); 372 set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices); 373 374 /* Create platform_profile structure and register */ 375 err = platform_profile_register(&dev->pprof); 376 if (err) 377 dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n", 378 err); 379 380 return err; 381 } 382 383 void amd_pmf_deinit_sps(struct amd_pmf_dev *dev) 384 { 385 platform_profile_remove(); 386 } 387