amd_powerplay.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. /*
  2. * Copyright 2015 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. */
  23. #include <linux/types.h>
  24. #include <linux/kernel.h>
  25. #include <linux/gfp.h>
  26. #include <linux/slab.h>
  27. #include "amd_shared.h"
  28. #include "amd_powerplay.h"
  29. #include "pp_instance.h"
  30. #include "power_state.h"
  31. #include "eventmanager.h"
  32. #include "pp_debug.h"
  33. #define PP_CHECK(handle) \
  34. do { \
  35. if ((handle) == NULL || (handle)->pp_valid != PP_VALID) \
  36. return -EINVAL; \
  37. } while (0)
  38. #define PP_CHECK_HW(hwmgr) \
  39. do { \
  40. if ((hwmgr) == NULL || (hwmgr)->hwmgr_func == NULL) \
  41. return -EINVAL; \
  42. } while (0)
  43. static int pp_early_init(void *handle)
  44. {
  45. return 0;
  46. }
  47. static int pp_sw_init(void *handle)
  48. {
  49. struct pp_instance *pp_handle;
  50. struct pp_hwmgr *hwmgr;
  51. int ret = 0;
  52. if (handle == NULL)
  53. return -EINVAL;
  54. pp_handle = (struct pp_instance *)handle;
  55. hwmgr = pp_handle->hwmgr;
  56. PP_CHECK_HW(hwmgr);
  57. if (hwmgr->pptable_func == NULL ||
  58. hwmgr->pptable_func->pptable_init == NULL ||
  59. hwmgr->hwmgr_func->backend_init == NULL)
  60. return -EINVAL;
  61. ret = hwmgr->pptable_func->pptable_init(hwmgr);
  62. if (ret)
  63. goto err;
  64. ret = hwmgr->hwmgr_func->backend_init(hwmgr);
  65. if (ret)
  66. goto err1;
  67. pr_info("amdgpu: powerplay initialized\n");
  68. return 0;
  69. err1:
  70. if (hwmgr->pptable_func->pptable_fini)
  71. hwmgr->pptable_func->pptable_fini(hwmgr);
  72. err:
  73. pr_err("amdgpu: powerplay initialization failed\n");
  74. return ret;
  75. }
  76. static int pp_sw_fini(void *handle)
  77. {
  78. struct pp_instance *pp_handle;
  79. struct pp_hwmgr *hwmgr;
  80. int ret = 0;
  81. if (handle == NULL)
  82. return -EINVAL;
  83. pp_handle = (struct pp_instance *)handle;
  84. hwmgr = pp_handle->hwmgr;
  85. PP_CHECK_HW(hwmgr);
  86. if (hwmgr->hwmgr_func->backend_fini != NULL)
  87. ret = hwmgr->hwmgr_func->backend_fini(hwmgr);
  88. if (hwmgr->pptable_func->pptable_fini)
  89. hwmgr->pptable_func->pptable_fini(hwmgr);
  90. return ret;
  91. }
  92. static int pp_hw_init(void *handle)
  93. {
  94. struct pp_instance *pp_handle;
  95. struct pp_smumgr *smumgr;
  96. struct pp_eventmgr *eventmgr;
  97. int ret = 0;
  98. if (handle == NULL)
  99. return -EINVAL;
  100. pp_handle = (struct pp_instance *)handle;
  101. smumgr = pp_handle->smu_mgr;
  102. if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
  103. smumgr->smumgr_funcs->smu_init == NULL ||
  104. smumgr->smumgr_funcs->start_smu == NULL)
  105. return -EINVAL;
  106. ret = smumgr->smumgr_funcs->smu_init(smumgr);
  107. if (ret) {
  108. printk(KERN_ERR "[ powerplay ] smc initialization failed\n");
  109. return ret;
  110. }
  111. ret = smumgr->smumgr_funcs->start_smu(smumgr);
  112. if (ret) {
  113. printk(KERN_ERR "[ powerplay ] smc start failed\n");
  114. smumgr->smumgr_funcs->smu_fini(smumgr);
  115. return ret;
  116. }
  117. hw_init_power_state_table(pp_handle->hwmgr);
  118. eventmgr = pp_handle->eventmgr;
  119. if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
  120. return -EINVAL;
  121. ret = eventmgr->pp_eventmgr_init(eventmgr);
  122. return 0;
  123. }
  124. static int pp_hw_fini(void *handle)
  125. {
  126. struct pp_instance *pp_handle;
  127. struct pp_smumgr *smumgr;
  128. struct pp_eventmgr *eventmgr;
  129. if (handle == NULL)
  130. return -EINVAL;
  131. pp_handle = (struct pp_instance *)handle;
  132. eventmgr = pp_handle->eventmgr;
  133. if (eventmgr != NULL || eventmgr->pp_eventmgr_fini != NULL)
  134. eventmgr->pp_eventmgr_fini(eventmgr);
  135. smumgr = pp_handle->smu_mgr;
  136. if (smumgr != NULL || smumgr->smumgr_funcs != NULL ||
  137. smumgr->smumgr_funcs->smu_fini != NULL)
  138. smumgr->smumgr_funcs->smu_fini(smumgr);
  139. return 0;
  140. }
  141. static bool pp_is_idle(void *handle)
  142. {
  143. return false;
  144. }
  145. static int pp_wait_for_idle(void *handle)
  146. {
  147. return 0;
  148. }
  149. static int pp_sw_reset(void *handle)
  150. {
  151. return 0;
  152. }
  153. static int pp_set_clockgating_state(void *handle,
  154. enum amd_clockgating_state state)
  155. {
  156. struct pp_hwmgr *hwmgr;
  157. uint32_t msg_id, pp_state;
  158. if (handle == NULL)
  159. return -EINVAL;
  160. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  161. PP_CHECK_HW(hwmgr);
  162. if (hwmgr->hwmgr_func->update_clock_gatings == NULL) {
  163. printk(KERN_INFO "%s was not implemented.\n", __func__);
  164. return 0;
  165. }
  166. if (state == AMD_CG_STATE_UNGATE)
  167. pp_state = 0;
  168. else
  169. pp_state = PP_STATE_CG | PP_STATE_LS;
  170. /* Enable/disable GFX blocks clock gating through SMU */
  171. msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
  172. PP_BLOCK_GFX_CG,
  173. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  174. pp_state);
  175. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  176. msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
  177. PP_BLOCK_GFX_3D,
  178. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  179. pp_state);
  180. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  181. msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
  182. PP_BLOCK_GFX_RLC,
  183. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  184. pp_state);
  185. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  186. msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
  187. PP_BLOCK_GFX_CP,
  188. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  189. pp_state);
  190. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  191. msg_id = PP_CG_MSG_ID(PP_GROUP_GFX,
  192. PP_BLOCK_GFX_MG,
  193. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  194. pp_state);
  195. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  196. /* Enable/disable System blocks clock gating through SMU */
  197. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  198. PP_BLOCK_SYS_BIF,
  199. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  200. pp_state);
  201. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  202. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  203. PP_BLOCK_SYS_BIF,
  204. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  205. pp_state);
  206. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  207. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  208. PP_BLOCK_SYS_MC,
  209. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  210. pp_state);
  211. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  212. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  213. PP_BLOCK_SYS_ROM,
  214. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  215. pp_state);
  216. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  217. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  218. PP_BLOCK_SYS_DRM,
  219. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  220. pp_state);
  221. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  222. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  223. PP_BLOCK_SYS_HDP,
  224. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  225. pp_state);
  226. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  227. msg_id = PP_CG_MSG_ID(PP_GROUP_SYS,
  228. PP_BLOCK_SYS_SDMA,
  229. PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS,
  230. pp_state);
  231. hwmgr->hwmgr_func->update_clock_gatings(hwmgr, &msg_id);
  232. return 0;
  233. }
  234. static int pp_set_powergating_state(void *handle,
  235. enum amd_powergating_state state)
  236. {
  237. struct pp_hwmgr *hwmgr;
  238. if (handle == NULL)
  239. return -EINVAL;
  240. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  241. PP_CHECK_HW(hwmgr);
  242. if (hwmgr->hwmgr_func->enable_per_cu_power_gating == NULL) {
  243. printk(KERN_INFO "%s was not implemented.\n", __func__);
  244. return 0;
  245. }
  246. /* Enable/disable GFX per cu powergating through SMU */
  247. return hwmgr->hwmgr_func->enable_per_cu_power_gating(hwmgr,
  248. state == AMD_PG_STATE_GATE ? true : false);
  249. }
  250. static int pp_suspend(void *handle)
  251. {
  252. struct pp_instance *pp_handle;
  253. struct pp_eventmgr *eventmgr;
  254. struct pem_event_data event_data = { {0} };
  255. if (handle == NULL)
  256. return -EINVAL;
  257. pp_handle = (struct pp_instance *)handle;
  258. eventmgr = pp_handle->eventmgr;
  259. pem_handle_event(eventmgr, AMD_PP_EVENT_SUSPEND, &event_data);
  260. return 0;
  261. }
  262. static int pp_resume(void *handle)
  263. {
  264. struct pp_instance *pp_handle;
  265. struct pp_eventmgr *eventmgr;
  266. struct pem_event_data event_data = { {0} };
  267. struct pp_smumgr *smumgr;
  268. int ret;
  269. if (handle == NULL)
  270. return -EINVAL;
  271. pp_handle = (struct pp_instance *)handle;
  272. smumgr = pp_handle->smu_mgr;
  273. if (smumgr == NULL || smumgr->smumgr_funcs == NULL ||
  274. smumgr->smumgr_funcs->start_smu == NULL)
  275. return -EINVAL;
  276. ret = smumgr->smumgr_funcs->start_smu(smumgr);
  277. if (ret) {
  278. printk(KERN_ERR "[ powerplay ] smc start failed\n");
  279. smumgr->smumgr_funcs->smu_fini(smumgr);
  280. return ret;
  281. }
  282. eventmgr = pp_handle->eventmgr;
  283. pem_handle_event(eventmgr, AMD_PP_EVENT_RESUME, &event_data);
  284. return 0;
  285. }
  286. const struct amd_ip_funcs pp_ip_funcs = {
  287. .name = "powerplay",
  288. .early_init = pp_early_init,
  289. .late_init = NULL,
  290. .sw_init = pp_sw_init,
  291. .sw_fini = pp_sw_fini,
  292. .hw_init = pp_hw_init,
  293. .hw_fini = pp_hw_fini,
  294. .suspend = pp_suspend,
  295. .resume = pp_resume,
  296. .is_idle = pp_is_idle,
  297. .wait_for_idle = pp_wait_for_idle,
  298. .soft_reset = pp_sw_reset,
  299. .set_clockgating_state = pp_set_clockgating_state,
  300. .set_powergating_state = pp_set_powergating_state,
  301. };
  302. static int pp_dpm_load_fw(void *handle)
  303. {
  304. return 0;
  305. }
  306. static int pp_dpm_fw_loading_complete(void *handle)
  307. {
  308. return 0;
  309. }
  310. static int pp_dpm_force_performance_level(void *handle,
  311. enum amd_dpm_forced_level level)
  312. {
  313. struct pp_instance *pp_handle;
  314. struct pp_hwmgr *hwmgr;
  315. if (handle == NULL)
  316. return -EINVAL;
  317. pp_handle = (struct pp_instance *)handle;
  318. hwmgr = pp_handle->hwmgr;
  319. PP_CHECK_HW(hwmgr);
  320. if (hwmgr->hwmgr_func->force_dpm_level == NULL) {
  321. printk(KERN_INFO "%s was not implemented.\n", __func__);
  322. return 0;
  323. }
  324. hwmgr->hwmgr_func->force_dpm_level(hwmgr, level);
  325. return 0;
  326. }
  327. static enum amd_dpm_forced_level pp_dpm_get_performance_level(
  328. void *handle)
  329. {
  330. struct pp_hwmgr *hwmgr;
  331. if (handle == NULL)
  332. return -EINVAL;
  333. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  334. if (hwmgr == NULL)
  335. return -EINVAL;
  336. return (((struct pp_instance *)handle)->hwmgr->dpm_level);
  337. }
  338. static int pp_dpm_get_sclk(void *handle, bool low)
  339. {
  340. struct pp_hwmgr *hwmgr;
  341. if (handle == NULL)
  342. return -EINVAL;
  343. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  344. PP_CHECK_HW(hwmgr);
  345. if (hwmgr->hwmgr_func->get_sclk == NULL) {
  346. printk(KERN_INFO "%s was not implemented.\n", __func__);
  347. return 0;
  348. }
  349. return hwmgr->hwmgr_func->get_sclk(hwmgr, low);
  350. }
  351. static int pp_dpm_get_mclk(void *handle, bool low)
  352. {
  353. struct pp_hwmgr *hwmgr;
  354. if (handle == NULL)
  355. return -EINVAL;
  356. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  357. PP_CHECK_HW(hwmgr);
  358. if (hwmgr->hwmgr_func->get_mclk == NULL) {
  359. printk(KERN_INFO "%s was not implemented.\n", __func__);
  360. return 0;
  361. }
  362. return hwmgr->hwmgr_func->get_mclk(hwmgr, low);
  363. }
  364. static int pp_dpm_powergate_vce(void *handle, bool gate)
  365. {
  366. struct pp_hwmgr *hwmgr;
  367. if (handle == NULL)
  368. return -EINVAL;
  369. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  370. PP_CHECK_HW(hwmgr);
  371. if (hwmgr->hwmgr_func->powergate_vce == NULL) {
  372. printk(KERN_INFO "%s was not implemented.\n", __func__);
  373. return 0;
  374. }
  375. return hwmgr->hwmgr_func->powergate_vce(hwmgr, gate);
  376. }
  377. static int pp_dpm_powergate_uvd(void *handle, bool gate)
  378. {
  379. struct pp_hwmgr *hwmgr;
  380. if (handle == NULL)
  381. return -EINVAL;
  382. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  383. PP_CHECK_HW(hwmgr);
  384. if (hwmgr->hwmgr_func->powergate_uvd == NULL) {
  385. printk(KERN_INFO "%s was not implemented.\n", __func__);
  386. return 0;
  387. }
  388. return hwmgr->hwmgr_func->powergate_uvd(hwmgr, gate);
  389. }
  390. static enum PP_StateUILabel power_state_convert(enum amd_pm_state_type state)
  391. {
  392. switch (state) {
  393. case POWER_STATE_TYPE_BATTERY:
  394. return PP_StateUILabel_Battery;
  395. case POWER_STATE_TYPE_BALANCED:
  396. return PP_StateUILabel_Balanced;
  397. case POWER_STATE_TYPE_PERFORMANCE:
  398. return PP_StateUILabel_Performance;
  399. default:
  400. return PP_StateUILabel_None;
  401. }
  402. }
  403. int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input, void *output)
  404. {
  405. int ret = 0;
  406. struct pp_instance *pp_handle;
  407. struct pem_event_data data = { {0} };
  408. pp_handle = (struct pp_instance *)handle;
  409. if (pp_handle == NULL)
  410. return -EINVAL;
  411. switch (event_id) {
  412. case AMD_PP_EVENT_DISPLAY_CONFIG_CHANGE:
  413. ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
  414. break;
  415. case AMD_PP_EVENT_ENABLE_USER_STATE:
  416. {
  417. enum amd_pm_state_type ps;
  418. if (input == NULL)
  419. return -EINVAL;
  420. ps = *(unsigned long *)input;
  421. data.requested_ui_label = power_state_convert(ps);
  422. ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
  423. break;
  424. }
  425. case AMD_PP_EVENT_COMPLETE_INIT:
  426. ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
  427. break;
  428. case AMD_PP_EVENT_READJUST_POWER_STATE:
  429. pp_handle->hwmgr->current_ps = pp_handle->hwmgr->boot_ps;
  430. ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
  431. break;
  432. default:
  433. break;
  434. }
  435. return ret;
  436. }
  437. enum amd_pm_state_type pp_dpm_get_current_power_state(void *handle)
  438. {
  439. struct pp_hwmgr *hwmgr;
  440. struct pp_power_state *state;
  441. if (handle == NULL)
  442. return -EINVAL;
  443. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  444. if (hwmgr == NULL || hwmgr->current_ps == NULL)
  445. return -EINVAL;
  446. state = hwmgr->current_ps;
  447. switch (state->classification.ui_label) {
  448. case PP_StateUILabel_Battery:
  449. return POWER_STATE_TYPE_BATTERY;
  450. case PP_StateUILabel_Balanced:
  451. return POWER_STATE_TYPE_BALANCED;
  452. case PP_StateUILabel_Performance:
  453. return POWER_STATE_TYPE_PERFORMANCE;
  454. default:
  455. if (state->classification.flags & PP_StateClassificationFlag_Boot)
  456. return POWER_STATE_TYPE_INTERNAL_BOOT;
  457. else
  458. return POWER_STATE_TYPE_DEFAULT;
  459. }
  460. }
  461. static void
  462. pp_debugfs_print_current_performance_level(void *handle,
  463. struct seq_file *m)
  464. {
  465. struct pp_hwmgr *hwmgr;
  466. if (handle == NULL)
  467. return;
  468. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  469. if (hwmgr == NULL || hwmgr->hwmgr_func == NULL)
  470. return;
  471. if (hwmgr->hwmgr_func->print_current_perforce_level == NULL) {
  472. printk(KERN_INFO "%s was not implemented.\n", __func__);
  473. return;
  474. }
  475. hwmgr->hwmgr_func->print_current_perforce_level(hwmgr, m);
  476. }
  477. static int pp_dpm_set_fan_control_mode(void *handle, uint32_t mode)
  478. {
  479. struct pp_hwmgr *hwmgr;
  480. if (handle == NULL)
  481. return -EINVAL;
  482. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  483. PP_CHECK_HW(hwmgr);
  484. if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) {
  485. printk(KERN_INFO "%s was not implemented.\n", __func__);
  486. return 0;
  487. }
  488. return hwmgr->hwmgr_func->set_fan_control_mode(hwmgr, mode);
  489. }
  490. static int pp_dpm_get_fan_control_mode(void *handle)
  491. {
  492. struct pp_hwmgr *hwmgr;
  493. if (handle == NULL)
  494. return -EINVAL;
  495. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  496. PP_CHECK_HW(hwmgr);
  497. if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) {
  498. printk(KERN_INFO "%s was not implemented.\n", __func__);
  499. return 0;
  500. }
  501. return hwmgr->hwmgr_func->get_fan_control_mode(hwmgr);
  502. }
  503. static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent)
  504. {
  505. struct pp_hwmgr *hwmgr;
  506. if (handle == NULL)
  507. return -EINVAL;
  508. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  509. PP_CHECK_HW(hwmgr);
  510. if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) {
  511. printk(KERN_INFO "%s was not implemented.\n", __func__);
  512. return 0;
  513. }
  514. return hwmgr->hwmgr_func->set_fan_speed_percent(hwmgr, percent);
  515. }
  516. static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed)
  517. {
  518. struct pp_hwmgr *hwmgr;
  519. if (handle == NULL)
  520. return -EINVAL;
  521. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  522. PP_CHECK_HW(hwmgr);
  523. if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) {
  524. printk(KERN_INFO "%s was not implemented.\n", __func__);
  525. return 0;
  526. }
  527. return hwmgr->hwmgr_func->get_fan_speed_percent(hwmgr, speed);
  528. }
  529. static int pp_dpm_get_temperature(void *handle)
  530. {
  531. struct pp_hwmgr *hwmgr;
  532. if (handle == NULL)
  533. return -EINVAL;
  534. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  535. PP_CHECK_HW(hwmgr);
  536. if (hwmgr->hwmgr_func->get_temperature == NULL) {
  537. printk(KERN_INFO "%s was not implemented.\n", __func__);
  538. return 0;
  539. }
  540. return hwmgr->hwmgr_func->get_temperature(hwmgr);
  541. }
  542. static int pp_dpm_get_pp_num_states(void *handle,
  543. struct pp_states_info *data)
  544. {
  545. struct pp_hwmgr *hwmgr;
  546. int i;
  547. if (!handle)
  548. return -EINVAL;
  549. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  550. if (hwmgr == NULL || hwmgr->ps == NULL)
  551. return -EINVAL;
  552. data->nums = hwmgr->num_ps;
  553. for (i = 0; i < hwmgr->num_ps; i++) {
  554. struct pp_power_state *state = (struct pp_power_state *)
  555. ((unsigned long)hwmgr->ps + i * hwmgr->ps_size);
  556. switch (state->classification.ui_label) {
  557. case PP_StateUILabel_Battery:
  558. data->states[i] = POWER_STATE_TYPE_BATTERY;
  559. break;
  560. case PP_StateUILabel_Balanced:
  561. data->states[i] = POWER_STATE_TYPE_BALANCED;
  562. break;
  563. case PP_StateUILabel_Performance:
  564. data->states[i] = POWER_STATE_TYPE_PERFORMANCE;
  565. break;
  566. default:
  567. if (state->classification.flags & PP_StateClassificationFlag_Boot)
  568. data->states[i] = POWER_STATE_TYPE_INTERNAL_BOOT;
  569. else
  570. data->states[i] = POWER_STATE_TYPE_DEFAULT;
  571. }
  572. }
  573. return 0;
  574. }
  575. static int pp_dpm_get_pp_table(void *handle, char **table)
  576. {
  577. struct pp_hwmgr *hwmgr;
  578. if (!handle)
  579. return -EINVAL;
  580. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  581. PP_CHECK_HW(hwmgr);
  582. if (!hwmgr->soft_pp_table)
  583. return -EINVAL;
  584. *table = (char *)hwmgr->soft_pp_table;
  585. return hwmgr->soft_pp_table_size;
  586. }
  587. static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size)
  588. {
  589. struct pp_hwmgr *hwmgr;
  590. if (!handle)
  591. return -EINVAL;
  592. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  593. PP_CHECK_HW(hwmgr);
  594. if (!hwmgr->hardcode_pp_table) {
  595. hwmgr->hardcode_pp_table =
  596. kzalloc(hwmgr->soft_pp_table_size, GFP_KERNEL);
  597. if (!hwmgr->hardcode_pp_table)
  598. return -ENOMEM;
  599. /* to avoid powerplay crash when hardcode pptable is empty */
  600. memcpy(hwmgr->hardcode_pp_table, hwmgr->soft_pp_table,
  601. hwmgr->soft_pp_table_size);
  602. }
  603. memcpy(hwmgr->hardcode_pp_table, buf, size);
  604. hwmgr->soft_pp_table = hwmgr->hardcode_pp_table;
  605. return amd_powerplay_reset(handle);
  606. }
  607. static int pp_dpm_force_clock_level(void *handle,
  608. enum pp_clock_type type, uint32_t mask)
  609. {
  610. struct pp_hwmgr *hwmgr;
  611. if (!handle)
  612. return -EINVAL;
  613. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  614. PP_CHECK_HW(hwmgr);
  615. if (hwmgr->hwmgr_func->force_clock_level == NULL) {
  616. printk(KERN_INFO "%s was not implemented.\n", __func__);
  617. return 0;
  618. }
  619. return hwmgr->hwmgr_func->force_clock_level(hwmgr, type, mask);
  620. }
  621. static int pp_dpm_print_clock_levels(void *handle,
  622. enum pp_clock_type type, char *buf)
  623. {
  624. struct pp_hwmgr *hwmgr;
  625. if (!handle)
  626. return -EINVAL;
  627. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  628. PP_CHECK_HW(hwmgr);
  629. if (hwmgr->hwmgr_func->print_clock_levels == NULL) {
  630. printk(KERN_INFO "%s was not implemented.\n", __func__);
  631. return 0;
  632. }
  633. return hwmgr->hwmgr_func->print_clock_levels(hwmgr, type, buf);
  634. }
  635. static int pp_dpm_get_sclk_od(void *handle)
  636. {
  637. struct pp_hwmgr *hwmgr;
  638. if (!handle)
  639. return -EINVAL;
  640. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  641. PP_CHECK_HW(hwmgr);
  642. if (hwmgr->hwmgr_func->get_sclk_od == NULL) {
  643. printk(KERN_INFO "%s was not implemented.\n", __func__);
  644. return 0;
  645. }
  646. return hwmgr->hwmgr_func->get_sclk_od(hwmgr);
  647. }
  648. static int pp_dpm_set_sclk_od(void *handle, uint32_t value)
  649. {
  650. struct pp_hwmgr *hwmgr;
  651. if (!handle)
  652. return -EINVAL;
  653. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  654. PP_CHECK_HW(hwmgr);
  655. if (hwmgr->hwmgr_func->set_sclk_od == NULL) {
  656. printk(KERN_INFO "%s was not implemented.\n", __func__);
  657. return 0;
  658. }
  659. return hwmgr->hwmgr_func->set_sclk_od(hwmgr, value);
  660. }
  661. static int pp_dpm_get_mclk_od(void *handle)
  662. {
  663. struct pp_hwmgr *hwmgr;
  664. if (!handle)
  665. return -EINVAL;
  666. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  667. PP_CHECK_HW(hwmgr);
  668. if (hwmgr->hwmgr_func->get_mclk_od == NULL) {
  669. printk(KERN_INFO "%s was not implemented.\n", __func__);
  670. return 0;
  671. }
  672. return hwmgr->hwmgr_func->get_mclk_od(hwmgr);
  673. }
  674. static int pp_dpm_set_mclk_od(void *handle, uint32_t value)
  675. {
  676. struct pp_hwmgr *hwmgr;
  677. if (!handle)
  678. return -EINVAL;
  679. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  680. PP_CHECK_HW(hwmgr);
  681. if (hwmgr->hwmgr_func->set_mclk_od == NULL) {
  682. printk(KERN_INFO "%s was not implemented.\n", __func__);
  683. return 0;
  684. }
  685. return hwmgr->hwmgr_func->set_mclk_od(hwmgr, value);
  686. }
  687. const struct amd_powerplay_funcs pp_dpm_funcs = {
  688. .get_temperature = pp_dpm_get_temperature,
  689. .load_firmware = pp_dpm_load_fw,
  690. .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete,
  691. .force_performance_level = pp_dpm_force_performance_level,
  692. .get_performance_level = pp_dpm_get_performance_level,
  693. .get_current_power_state = pp_dpm_get_current_power_state,
  694. .get_sclk = pp_dpm_get_sclk,
  695. .get_mclk = pp_dpm_get_mclk,
  696. .powergate_vce = pp_dpm_powergate_vce,
  697. .powergate_uvd = pp_dpm_powergate_uvd,
  698. .dispatch_tasks = pp_dpm_dispatch_tasks,
  699. .print_current_performance_level = pp_debugfs_print_current_performance_level,
  700. .set_fan_control_mode = pp_dpm_set_fan_control_mode,
  701. .get_fan_control_mode = pp_dpm_get_fan_control_mode,
  702. .set_fan_speed_percent = pp_dpm_set_fan_speed_percent,
  703. .get_fan_speed_percent = pp_dpm_get_fan_speed_percent,
  704. .get_pp_num_states = pp_dpm_get_pp_num_states,
  705. .get_pp_table = pp_dpm_get_pp_table,
  706. .set_pp_table = pp_dpm_set_pp_table,
  707. .force_clock_level = pp_dpm_force_clock_level,
  708. .print_clock_levels = pp_dpm_print_clock_levels,
  709. .get_sclk_od = pp_dpm_get_sclk_od,
  710. .set_sclk_od = pp_dpm_set_sclk_od,
  711. .get_mclk_od = pp_dpm_get_mclk_od,
  712. .set_mclk_od = pp_dpm_set_mclk_od,
  713. };
  714. static int amd_pp_instance_init(struct amd_pp_init *pp_init,
  715. struct amd_powerplay *amd_pp)
  716. {
  717. int ret;
  718. struct pp_instance *handle;
  719. handle = kzalloc(sizeof(struct pp_instance), GFP_KERNEL);
  720. if (handle == NULL)
  721. return -ENOMEM;
  722. handle->pp_valid = PP_VALID;
  723. ret = smum_init(pp_init, handle);
  724. if (ret)
  725. goto fail_smum;
  726. ret = hwmgr_init(pp_init, handle);
  727. if (ret)
  728. goto fail_hwmgr;
  729. ret = eventmgr_init(handle);
  730. if (ret)
  731. goto fail_eventmgr;
  732. amd_pp->pp_handle = handle;
  733. return 0;
  734. fail_eventmgr:
  735. hwmgr_fini(handle->hwmgr);
  736. fail_hwmgr:
  737. smum_fini(handle->smu_mgr);
  738. fail_smum:
  739. kfree(handle);
  740. return ret;
  741. }
  742. static int amd_pp_instance_fini(void *handle)
  743. {
  744. struct pp_instance *instance = (struct pp_instance *)handle;
  745. if (instance == NULL)
  746. return -EINVAL;
  747. eventmgr_fini(instance->eventmgr);
  748. hwmgr_fini(instance->hwmgr);
  749. smum_fini(instance->smu_mgr);
  750. kfree(handle);
  751. return 0;
  752. }
  753. int amd_powerplay_init(struct amd_pp_init *pp_init,
  754. struct amd_powerplay *amd_pp)
  755. {
  756. int ret;
  757. if (pp_init == NULL || amd_pp == NULL)
  758. return -EINVAL;
  759. ret = amd_pp_instance_init(pp_init, amd_pp);
  760. if (ret)
  761. return ret;
  762. amd_pp->ip_funcs = &pp_ip_funcs;
  763. amd_pp->pp_funcs = &pp_dpm_funcs;
  764. return 0;
  765. }
  766. int amd_powerplay_fini(void *handle)
  767. {
  768. amd_pp_instance_fini(handle);
  769. return 0;
  770. }
  771. int amd_powerplay_reset(void *handle)
  772. {
  773. struct pp_instance *instance = (struct pp_instance *)handle;
  774. struct pp_eventmgr *eventmgr;
  775. struct pem_event_data event_data = { {0} };
  776. int ret;
  777. if (instance == NULL)
  778. return -EINVAL;
  779. eventmgr = instance->eventmgr;
  780. if (!eventmgr || !eventmgr->pp_eventmgr_fini)
  781. return -EINVAL;
  782. eventmgr->pp_eventmgr_fini(eventmgr);
  783. ret = pp_sw_fini(handle);
  784. if (ret)
  785. return ret;
  786. kfree(instance->hwmgr->ps);
  787. ret = pp_sw_init(handle);
  788. if (ret)
  789. return ret;
  790. hw_init_power_state_table(instance->hwmgr);
  791. if (eventmgr == NULL || eventmgr->pp_eventmgr_init == NULL)
  792. return -EINVAL;
  793. ret = eventmgr->pp_eventmgr_init(eventmgr);
  794. if (ret)
  795. return ret;
  796. return pem_handle_event(eventmgr, AMD_PP_EVENT_COMPLETE_INIT, &event_data);
  797. }
  798. /* export this function to DAL */
  799. int amd_powerplay_display_configuration_change(void *handle,
  800. const struct amd_pp_display_configuration *display_config)
  801. {
  802. struct pp_hwmgr *hwmgr;
  803. PP_CHECK((struct pp_instance *)handle);
  804. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  805. phm_store_dal_configuration_data(hwmgr, display_config);
  806. return 0;
  807. }
  808. int amd_powerplay_get_display_power_level(void *handle,
  809. struct amd_pp_simple_clock_info *output)
  810. {
  811. struct pp_hwmgr *hwmgr;
  812. PP_CHECK((struct pp_instance *)handle);
  813. if (output == NULL)
  814. return -EINVAL;
  815. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  816. return phm_get_dal_power_level(hwmgr, output);
  817. }
  818. int amd_powerplay_get_current_clocks(void *handle,
  819. struct amd_pp_clock_info *clocks)
  820. {
  821. struct pp_hwmgr *hwmgr;
  822. struct amd_pp_simple_clock_info simple_clocks;
  823. struct pp_clock_info hw_clocks;
  824. PP_CHECK((struct pp_instance *)handle);
  825. if (clocks == NULL)
  826. return -EINVAL;
  827. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  828. phm_get_dal_power_level(hwmgr, &simple_clocks);
  829. if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PowerContainment)) {
  830. if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_PowerContainment))
  831. PP_ASSERT_WITH_CODE(0, "Error in PHM_GetPowerContainmentClockInfo", return -1);
  832. } else {
  833. if (0 != phm_get_clock_info(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks, PHM_PerformanceLevelDesignation_Activity))
  834. PP_ASSERT_WITH_CODE(0, "Error in PHM_GetClockInfo", return -1);
  835. }
  836. clocks->min_engine_clock = hw_clocks.min_eng_clk;
  837. clocks->max_engine_clock = hw_clocks.max_eng_clk;
  838. clocks->min_memory_clock = hw_clocks.min_mem_clk;
  839. clocks->max_memory_clock = hw_clocks.max_mem_clk;
  840. clocks->min_bus_bandwidth = hw_clocks.min_bus_bandwidth;
  841. clocks->max_bus_bandwidth = hw_clocks.max_bus_bandwidth;
  842. clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
  843. clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
  844. clocks->max_clocks_state = simple_clocks.level;
  845. if (0 == phm_get_current_shallow_sleep_clocks(hwmgr, &hwmgr->current_ps->hardware, &hw_clocks)) {
  846. clocks->max_engine_clock_in_sr = hw_clocks.max_eng_clk;
  847. clocks->min_engine_clock_in_sr = hw_clocks.min_eng_clk;
  848. }
  849. return 0;
  850. }
  851. int amd_powerplay_get_clock_by_type(void *handle, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks)
  852. {
  853. int result = -1;
  854. struct pp_hwmgr *hwmgr;
  855. PP_CHECK((struct pp_instance *)handle);
  856. if (clocks == NULL)
  857. return -EINVAL;
  858. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  859. result = phm_get_clock_by_type(hwmgr, type, clocks);
  860. return result;
  861. }
  862. int amd_powerplay_get_display_mode_validation_clocks(void *handle,
  863. struct amd_pp_simple_clock_info *clocks)
  864. {
  865. int result = -1;
  866. struct pp_hwmgr *hwmgr;
  867. PP_CHECK((struct pp_instance *)handle);
  868. if (clocks == NULL)
  869. return -EINVAL;
  870. hwmgr = ((struct pp_instance *)handle)->hwmgr;
  871. if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DynamicPatchPowerState))
  872. result = phm_get_max_high_clocks(hwmgr, clocks);
  873. return result;
  874. }