sps.c 12 KB

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