rpmpd.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
  3. #include <linux/cleanup.h>
  4. #include <linux/err.h>
  5. #include <linux/init.h>
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/mutex.h>
  9. #include <linux/pm_domain.h>
  10. #include <linux/of.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/pm_opp.h>
  13. #include <linux/soc/qcom/smd-rpm.h>
  14. #include <dt-bindings/power/qcom-rpmpd.h>
  15. #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
  16. static struct qcom_smd_rpm *rpmpd_smd_rpm;
  17. /* Resource types:
  18. * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
  19. #define RPMPD_SMPA 0x61706d73
  20. #define RPMPD_LDOA 0x616f646c
  21. #define RPMPD_SMPB 0x62706d73
  22. #define RPMPD_LDOB 0x626f646c
  23. #define RPMPD_RWCX 0x78637772
  24. #define RPMPD_RWMX 0x786d7772
  25. #define RPMPD_RWLC 0x636c7772
  26. #define RPMPD_RWLM 0x6d6c7772
  27. #define RPMPD_RWSC 0x63737772
  28. #define RPMPD_RWSM 0x6d737772
  29. #define RPMPD_RWGX 0x78677772
  30. /* Operation Keys */
  31. #define KEY_CORNER 0x6e726f63 /* corn */
  32. #define KEY_ENABLE 0x6e657773 /* swen */
  33. #define KEY_FLOOR_CORNER 0x636676 /* vfc */
  34. #define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */
  35. #define KEY_LEVEL 0x6c766c76 /* vlvl */
  36. #define MAX_CORNER_RPMPD_STATE 6
  37. struct rpmpd_req {
  38. __le32 key;
  39. __le32 nbytes;
  40. __le32 value;
  41. };
  42. struct rpmpd {
  43. struct generic_pm_domain pd;
  44. struct generic_pm_domain *parent;
  45. struct rpmpd *peer;
  46. const bool active_only;
  47. unsigned int corner;
  48. bool enabled;
  49. const int res_type;
  50. const int res_id;
  51. unsigned int max_state;
  52. __le32 key;
  53. bool state_synced;
  54. };
  55. struct rpmpd_desc {
  56. struct rpmpd **rpmpds;
  57. size_t num_pds;
  58. unsigned int max_state;
  59. };
  60. static DEFINE_MUTEX(rpmpd_lock);
  61. /* CX */
  62. static struct rpmpd cx_rwcx0_lvl_ao;
  63. static struct rpmpd cx_rwcx0_lvl = {
  64. .pd = { .name = "cx", },
  65. .peer = &cx_rwcx0_lvl_ao,
  66. .res_type = RPMPD_RWCX,
  67. .res_id = 0,
  68. .key = KEY_LEVEL,
  69. };
  70. static struct rpmpd cx_rwcx0_lvl_ao = {
  71. .pd = { .name = "cx_ao", },
  72. .peer = &cx_rwcx0_lvl,
  73. .active_only = true,
  74. .res_type = RPMPD_RWCX,
  75. .res_id = 0,
  76. .key = KEY_LEVEL,
  77. };
  78. static struct rpmpd cx_s1a_corner_ao;
  79. static struct rpmpd cx_s1a_corner = {
  80. .pd = { .name = "cx", },
  81. .peer = &cx_s1a_corner_ao,
  82. .res_type = RPMPD_SMPA,
  83. .res_id = 1,
  84. .key = KEY_CORNER,
  85. };
  86. static struct rpmpd cx_s1a_corner_ao = {
  87. .pd = { .name = "cx_ao", },
  88. .peer = &cx_s1a_corner,
  89. .active_only = true,
  90. .res_type = RPMPD_SMPA,
  91. .res_id = 1,
  92. .key = KEY_CORNER,
  93. };
  94. static struct rpmpd cx_s1a_lvl_ao;
  95. static struct rpmpd cx_s1a_lvl = {
  96. .pd = { .name = "cx", },
  97. .peer = &cx_s1a_lvl_ao,
  98. .res_type = RPMPD_SMPA,
  99. .res_id = 1,
  100. .key = KEY_LEVEL,
  101. };
  102. static struct rpmpd cx_s1a_lvl_ao = {
  103. .pd = { .name = "cx_ao", },
  104. .peer = &cx_s1a_lvl,
  105. .active_only = true,
  106. .res_type = RPMPD_SMPA,
  107. .res_id = 1,
  108. .key = KEY_LEVEL,
  109. };
  110. static struct rpmpd cx_s2a_corner_ao;
  111. static struct rpmpd cx_s2a_corner = {
  112. .pd = { .name = "cx", },
  113. .peer = &cx_s2a_corner_ao,
  114. .res_type = RPMPD_SMPA,
  115. .res_id = 2,
  116. .key = KEY_CORNER,
  117. };
  118. static struct rpmpd cx_s2a_corner_ao = {
  119. .pd = { .name = "cx_ao", },
  120. .peer = &cx_s2a_corner,
  121. .active_only = true,
  122. .res_type = RPMPD_SMPA,
  123. .res_id = 2,
  124. .key = KEY_CORNER,
  125. };
  126. static struct rpmpd cx_s2a_lvl_ao;
  127. static struct rpmpd cx_s2a_lvl = {
  128. .pd = { .name = "cx", },
  129. .peer = &cx_s2a_lvl_ao,
  130. .res_type = RPMPD_SMPA,
  131. .res_id = 2,
  132. .key = KEY_LEVEL,
  133. };
  134. static struct rpmpd cx_s2a_lvl_ao = {
  135. .pd = { .name = "cx_ao", },
  136. .peer = &cx_s2a_lvl,
  137. .active_only = true,
  138. .res_type = RPMPD_SMPA,
  139. .res_id = 2,
  140. .key = KEY_LEVEL,
  141. };
  142. static struct rpmpd cx_s3a_lvl_ao;
  143. static struct rpmpd cx_s3a_lvl = {
  144. .pd = { .name = "cx", },
  145. .peer = &cx_s3a_lvl_ao,
  146. .res_type = RPMPD_SMPA,
  147. .res_id = 3,
  148. .key = KEY_LEVEL,
  149. };
  150. static struct rpmpd cx_s3a_lvl_ao = {
  151. .pd = { .name = "cx_ao", },
  152. .peer = &cx_s3a_lvl,
  153. .active_only = true,
  154. .res_type = RPMPD_SMPA,
  155. .res_id = 3,
  156. .key = KEY_LEVEL,
  157. };
  158. static struct rpmpd cx_rwcx0_vfl = {
  159. .pd = { .name = "cx_vfl", },
  160. .res_type = RPMPD_RWCX,
  161. .res_id = 0,
  162. .key = KEY_FLOOR_LEVEL,
  163. };
  164. static struct rpmpd cx_rwsc2_vfl = {
  165. .pd = { .name = "cx_vfl", },
  166. .res_type = RPMPD_RWSC,
  167. .res_id = 2,
  168. .key = KEY_FLOOR_LEVEL,
  169. };
  170. static struct rpmpd cx_s1a_vfc = {
  171. .pd = { .name = "cx_vfc", },
  172. .res_type = RPMPD_SMPA,
  173. .res_id = 1,
  174. .key = KEY_FLOOR_CORNER,
  175. };
  176. static struct rpmpd cx_s1a_vfl = {
  177. .pd = { .name = "cx_vfl", },
  178. .res_type = RPMPD_SMPA,
  179. .res_id = 1,
  180. .key = KEY_FLOOR_LEVEL,
  181. };
  182. static struct rpmpd cx_s2a_vfc = {
  183. .pd = { .name = "cx_vfc", },
  184. .res_type = RPMPD_SMPA,
  185. .res_id = 2,
  186. .key = KEY_FLOOR_CORNER,
  187. };
  188. static struct rpmpd cx_s2a_vfl = {
  189. .pd = { .name = "cx_vfl", },
  190. .res_type = RPMPD_SMPA,
  191. .res_id = 2,
  192. .key = KEY_FLOOR_LEVEL,
  193. };
  194. static struct rpmpd cx_s3a_vfl = {
  195. .pd = { .name = "cx_vfl", },
  196. .res_type = RPMPD_SMPA,
  197. .res_id = 3,
  198. .key = KEY_FLOOR_LEVEL,
  199. };
  200. static struct rpmpd cx_s2b_corner_ao;
  201. static struct rpmpd cx_s2b_corner = {
  202. .pd = { .name = "cx", },
  203. .peer = &cx_s2b_corner_ao,
  204. .res_type = RPMPD_SMPB,
  205. .res_id = 2,
  206. .key = KEY_CORNER,
  207. };
  208. static struct rpmpd cx_s2b_corner_ao = {
  209. .pd = { .name = "cx_ao", },
  210. .peer = &cx_s2b_corner,
  211. .active_only = true,
  212. .res_type = RPMPD_SMPB,
  213. .res_id = 2,
  214. .key = KEY_CORNER,
  215. };
  216. static struct rpmpd cx_s2b_vfc = {
  217. .pd = { .name = "cx_vfc", },
  218. .res_type = RPMPD_SMPB,
  219. .res_id = 2,
  220. .key = KEY_FLOOR_CORNER,
  221. };
  222. /* G(F)X */
  223. static struct rpmpd gfx_s7a_corner = {
  224. .pd = { .name = "gfx", },
  225. .res_type = RPMPD_SMPA,
  226. .res_id = 7,
  227. .key = KEY_CORNER,
  228. };
  229. static struct rpmpd gfx_s7a_vfc = {
  230. .pd = { .name = "gfx_vfc", },
  231. .res_type = RPMPD_SMPA,
  232. .res_id = 7,
  233. .key = KEY_FLOOR_CORNER,
  234. };
  235. static struct rpmpd gfx_s2b_corner = {
  236. .pd = { .name = "gfx", },
  237. .res_type = RPMPD_SMPB,
  238. .res_id = 2,
  239. .key = KEY_CORNER,
  240. };
  241. static struct rpmpd gfx_s2b_vfc = {
  242. .pd = { .name = "gfx_vfc", },
  243. .res_type = RPMPD_SMPB,
  244. .res_id = 2,
  245. .key = KEY_FLOOR_CORNER,
  246. };
  247. static struct rpmpd gfx_s4b_corner = {
  248. .pd = { .name = "gfx", },
  249. .res_type = RPMPD_SMPB,
  250. .res_id = 4,
  251. .key = KEY_CORNER,
  252. };
  253. static struct rpmpd gfx_s4b_vfc = {
  254. .pd = { .name = "gfx_vfc", },
  255. .res_type = RPMPD_SMPB,
  256. .res_id = 4,
  257. .key = KEY_FLOOR_CORNER,
  258. };
  259. static struct rpmpd mx_rwmx0_lvl;
  260. static struct rpmpd gx_rwgx0_lvl_ao;
  261. static struct rpmpd gx_rwgx0_lvl = {
  262. .pd = { .name = "gx", },
  263. .peer = &gx_rwgx0_lvl_ao,
  264. .res_type = RPMPD_RWGX,
  265. .parent = &mx_rwmx0_lvl.pd,
  266. .res_id = 0,
  267. .key = KEY_LEVEL,
  268. };
  269. static struct rpmpd mx_rwmx0_lvl_ao;
  270. static struct rpmpd gx_rwgx0_lvl_ao = {
  271. .pd = { .name = "gx_ao", },
  272. .peer = &gx_rwgx0_lvl,
  273. .parent = &mx_rwmx0_lvl_ao.pd,
  274. .active_only = true,
  275. .res_type = RPMPD_RWGX,
  276. .res_id = 0,
  277. .key = KEY_LEVEL,
  278. };
  279. /* MX */
  280. static struct rpmpd mx_l2a_lvl_ao;
  281. static struct rpmpd mx_l2a_lvl = {
  282. .pd = { .name = "mx", },
  283. .peer = &mx_l2a_lvl_ao,
  284. .res_type = RPMPD_LDOA,
  285. .res_id = 2,
  286. .key = KEY_LEVEL,
  287. };
  288. static struct rpmpd mx_l2a_lvl_ao = {
  289. .pd = { .name = "mx_ao", },
  290. .peer = &mx_l2a_lvl,
  291. .active_only = true,
  292. .res_type = RPMPD_LDOA,
  293. .res_id = 2,
  294. .key = KEY_LEVEL,
  295. };
  296. static struct rpmpd mx_l3a_corner_ao;
  297. static struct rpmpd mx_l3a_corner = {
  298. .pd = { .name = "mx", },
  299. .peer = &mx_l3a_corner_ao,
  300. .res_type = RPMPD_LDOA,
  301. .res_id = 3,
  302. .key = KEY_CORNER,
  303. };
  304. static struct rpmpd mx_l3a_corner_ao = {
  305. .pd = { .name = "mx_ao", },
  306. .peer = &mx_l3a_corner,
  307. .active_only = true,
  308. .res_type = RPMPD_LDOA,
  309. .res_id = 3,
  310. .key = KEY_CORNER,
  311. };
  312. static struct rpmpd mx_l3a_lvl_ao;
  313. static struct rpmpd mx_l3a_lvl = {
  314. .pd = { .name = "mx", },
  315. .peer = &mx_l3a_lvl_ao,
  316. .res_type = RPMPD_LDOA,
  317. .res_id = 3,
  318. .key = KEY_LEVEL,
  319. };
  320. static struct rpmpd mx_l3a_lvl_ao = {
  321. .pd = { .name = "mx_ao", },
  322. .peer = &mx_l3a_lvl,
  323. .active_only = true,
  324. .res_type = RPMPD_LDOA,
  325. .res_id = 3,
  326. .key = KEY_LEVEL,
  327. };
  328. static struct rpmpd mx_l12a_lvl_ao;
  329. static struct rpmpd mx_l12a_lvl = {
  330. .pd = { .name = "mx", },
  331. .peer = &mx_l12a_lvl_ao,
  332. .res_type = RPMPD_LDOA,
  333. .res_id = 12,
  334. .key = KEY_LEVEL,
  335. };
  336. static struct rpmpd mx_l12a_lvl_ao = {
  337. .pd = { .name = "mx_ao", },
  338. .peer = &mx_l12a_lvl,
  339. .active_only = true,
  340. .res_type = RPMPD_LDOA,
  341. .res_id = 12,
  342. .key = KEY_LEVEL,
  343. };
  344. static struct rpmpd mx_s2a_corner_ao;
  345. static struct rpmpd mx_s2a_corner = {
  346. .pd = { .name = "mx", },
  347. .peer = &mx_s2a_corner_ao,
  348. .res_type = RPMPD_SMPA,
  349. .res_id = 2,
  350. .key = KEY_CORNER,
  351. };
  352. static struct rpmpd mx_s2a_corner_ao = {
  353. .pd = { .name = "mx_ao", },
  354. .peer = &mx_s2a_corner,
  355. .active_only = true,
  356. .res_type = RPMPD_SMPA,
  357. .res_id = 2,
  358. .key = KEY_CORNER,
  359. };
  360. static struct rpmpd mx_rwmx0_lvl_ao;
  361. static struct rpmpd mx_rwmx0_lvl = {
  362. .pd = { .name = "mx", },
  363. .peer = &mx_rwmx0_lvl_ao,
  364. .res_type = RPMPD_RWMX,
  365. .res_id = 0,
  366. .key = KEY_LEVEL,
  367. };
  368. static struct rpmpd mx_rwmx0_lvl_ao = {
  369. .pd = { .name = "mx_ao", },
  370. .peer = &mx_rwmx0_lvl,
  371. .active_only = true,
  372. .res_type = RPMPD_RWMX,
  373. .res_id = 0,
  374. .key = KEY_LEVEL,
  375. };
  376. static struct rpmpd mx_s6a_lvl_ao;
  377. static struct rpmpd mx_s6a_lvl = {
  378. .pd = { .name = "mx", },
  379. .peer = &mx_s6a_lvl_ao,
  380. .res_type = RPMPD_SMPA,
  381. .res_id = 6,
  382. .key = KEY_LEVEL,
  383. };
  384. static struct rpmpd mx_s6a_lvl_ao = {
  385. .pd = { .name = "mx_ao", },
  386. .peer = &mx_s6a_lvl,
  387. .active_only = true,
  388. .res_type = RPMPD_SMPA,
  389. .res_id = 6,
  390. .key = KEY_LEVEL,
  391. };
  392. static struct rpmpd mx_s7a_lvl_ao;
  393. static struct rpmpd mx_s7a_lvl = {
  394. .pd = { .name = "mx", },
  395. .peer = &mx_s7a_lvl_ao,
  396. .res_type = RPMPD_SMPA,
  397. .res_id = 7,
  398. .key = KEY_LEVEL,
  399. };
  400. static struct rpmpd mx_s7a_lvl_ao = {
  401. .pd = { .name = "mx_ao", },
  402. .peer = &mx_s7a_lvl,
  403. .active_only = true,
  404. .res_type = RPMPD_SMPA,
  405. .res_id = 7,
  406. .key = KEY_LEVEL,
  407. };
  408. static struct rpmpd mx_l12a_vfl = {
  409. .pd = { .name = "mx_vfl", },
  410. .res_type = RPMPD_LDOA,
  411. .res_id = 12,
  412. .key = KEY_FLOOR_LEVEL,
  413. };
  414. static struct rpmpd mx_rwmx0_vfl = {
  415. .pd = { .name = "mx_vfl", },
  416. .res_type = RPMPD_RWMX,
  417. .res_id = 0,
  418. .key = KEY_FLOOR_LEVEL,
  419. };
  420. static struct rpmpd mx_rwsm6_vfl = {
  421. .pd = { .name = "mx_vfl", },
  422. .res_type = RPMPD_RWSM,
  423. .res_id = 6,
  424. .key = KEY_FLOOR_LEVEL,
  425. };
  426. /* MD */
  427. static struct rpmpd md_s1a_corner_ao;
  428. static struct rpmpd md_s1a_corner = {
  429. .pd = { .name = "md", },
  430. .peer = &md_s1a_corner_ao,
  431. .res_type = RPMPD_SMPA,
  432. .res_id = 1,
  433. .key = KEY_CORNER,
  434. };
  435. static struct rpmpd md_s1a_corner_ao = {
  436. .pd = { .name = "md_ao", },
  437. .peer = &md_s1a_corner,
  438. .active_only = true,
  439. .res_type = RPMPD_SMPA,
  440. .res_id = 1,
  441. .key = KEY_CORNER,
  442. };
  443. static struct rpmpd md_s1a_lvl_ao;
  444. static struct rpmpd md_s1a_lvl = {
  445. .pd = { .name = "md", },
  446. .peer = &md_s1a_lvl_ao,
  447. .res_type = RPMPD_SMPA,
  448. .res_id = 1,
  449. .key = KEY_LEVEL,
  450. };
  451. static struct rpmpd md_s1a_lvl_ao = {
  452. .pd = { .name = "md_ao", },
  453. .peer = &md_s1a_lvl,
  454. .active_only = true,
  455. .res_type = RPMPD_SMPA,
  456. .res_id = 1,
  457. .key = KEY_LEVEL,
  458. };
  459. static struct rpmpd md_s1a_vfc = {
  460. .pd = { .name = "md_vfc", },
  461. .res_type = RPMPD_SMPA,
  462. .res_id = 1,
  463. .key = KEY_FLOOR_CORNER,
  464. };
  465. /* LPI_CX */
  466. static struct rpmpd lpi_cx_rwlc0_lvl = {
  467. .pd = { .name = "lpi_cx", },
  468. .res_type = RPMPD_RWLC,
  469. .res_id = 0,
  470. .key = KEY_LEVEL,
  471. };
  472. static struct rpmpd lpi_cx_rwlc0_vfl = {
  473. .pd = { .name = "lpi_cx_vfl", },
  474. .res_type = RPMPD_RWLC,
  475. .res_id = 0,
  476. .key = KEY_FLOOR_LEVEL,
  477. };
  478. /* LPI_MX */
  479. static struct rpmpd lpi_mx_rwlm0_lvl = {
  480. .pd = { .name = "lpi_mx", },
  481. .res_type = RPMPD_RWLM,
  482. .res_id = 0,
  483. .key = KEY_LEVEL,
  484. };
  485. static struct rpmpd lpi_mx_rwlm0_vfl = {
  486. .pd = { .name = "lpi_mx_vfl", },
  487. .res_type = RPMPD_RWLM,
  488. .res_id = 0,
  489. .key = KEY_FLOOR_LEVEL,
  490. };
  491. /* SSC_CX */
  492. static struct rpmpd ssc_cx_l26a_corner = {
  493. .pd = { .name = "ssc_cx", },
  494. .res_type = RPMPD_LDOA,
  495. .res_id = 26,
  496. .key = KEY_CORNER,
  497. };
  498. static struct rpmpd ssc_cx_rwlc0_lvl = {
  499. .pd = { .name = "ssc_cx", },
  500. .res_type = RPMPD_RWLC,
  501. .res_id = 0,
  502. .key = KEY_LEVEL,
  503. };
  504. static struct rpmpd ssc_cx_rwsc0_lvl = {
  505. .pd = { .name = "ssc_cx", },
  506. .res_type = RPMPD_RWSC,
  507. .res_id = 0,
  508. .key = KEY_LEVEL,
  509. };
  510. static struct rpmpd ssc_cx_l26a_vfc = {
  511. .pd = { .name = "ssc_cx_vfc", },
  512. .res_type = RPMPD_LDOA,
  513. .res_id = 26,
  514. .key = KEY_FLOOR_CORNER,
  515. };
  516. static struct rpmpd ssc_cx_rwlc0_vfl = {
  517. .pd = { .name = "ssc_cx_vfl", },
  518. .res_type = RPMPD_RWLC,
  519. .res_id = 0,
  520. .key = KEY_FLOOR_LEVEL,
  521. };
  522. static struct rpmpd ssc_cx_rwsc0_vfl = {
  523. .pd = { .name = "ssc_cx_vfl", },
  524. .res_type = RPMPD_RWSC,
  525. .res_id = 0,
  526. .key = KEY_FLOOR_LEVEL,
  527. };
  528. /* SSC_MX */
  529. static struct rpmpd ssc_mx_rwlm0_lvl = {
  530. .pd = { .name = "ssc_mx", },
  531. .res_type = RPMPD_RWLM,
  532. .res_id = 0,
  533. .key = KEY_LEVEL,
  534. };
  535. static struct rpmpd ssc_mx_rwsm0_lvl = {
  536. .pd = { .name = "ssc_mx", },
  537. .res_type = RPMPD_RWSM,
  538. .res_id = 0,
  539. .key = KEY_LEVEL,
  540. };
  541. static struct rpmpd ssc_mx_rwlm0_vfl = {
  542. .pd = { .name = "ssc_mx_vfl", },
  543. .res_type = RPMPD_RWLM,
  544. .res_id = 0,
  545. .key = KEY_FLOOR_LEVEL,
  546. };
  547. static struct rpmpd ssc_mx_rwsm0_vfl = {
  548. .pd = { .name = "ssc_mx_vfl", },
  549. .res_type = RPMPD_RWSM,
  550. .res_id = 0,
  551. .key = KEY_FLOOR_LEVEL,
  552. };
  553. static struct rpmpd *mdm9607_rpmpds[] = {
  554. [RPMPD_VDDCX] = &cx_s3a_lvl,
  555. [RPMPD_VDDCX_AO] = &cx_s3a_lvl_ao,
  556. [RPMPD_VDDCX_VFL] = &cx_s3a_vfl,
  557. [RPMPD_VDDMX] = &mx_l12a_lvl,
  558. [RPMPD_VDDMX_AO] = &mx_l12a_lvl_ao,
  559. [RPMPD_VDDMX_VFL] = &mx_l12a_vfl,
  560. };
  561. static const struct rpmpd_desc mdm9607_desc = {
  562. .rpmpds = mdm9607_rpmpds,
  563. .num_pds = ARRAY_SIZE(mdm9607_rpmpds),
  564. .max_state = RPM_SMD_LEVEL_TURBO,
  565. };
  566. static struct rpmpd *msm8226_rpmpds[] = {
  567. [RPMPD_VDDCX] = &cx_s1a_corner,
  568. [RPMPD_VDDCX_AO] = &cx_s1a_corner_ao,
  569. [RPMPD_VDDCX_VFC] = &cx_s1a_vfc,
  570. };
  571. static const struct rpmpd_desc msm8226_desc = {
  572. .rpmpds = msm8226_rpmpds,
  573. .num_pds = ARRAY_SIZE(msm8226_rpmpds),
  574. .max_state = MAX_CORNER_RPMPD_STATE,
  575. };
  576. static struct rpmpd *msm8939_rpmpds[] = {
  577. [MSM8939_VDDMDCX] = &md_s1a_corner,
  578. [MSM8939_VDDMDCX_AO] = &md_s1a_corner_ao,
  579. [MSM8939_VDDMDCX_VFC] = &md_s1a_vfc,
  580. [MSM8939_VDDCX] = &cx_s2a_corner,
  581. [MSM8939_VDDCX_AO] = &cx_s2a_corner_ao,
  582. [MSM8939_VDDCX_VFC] = &cx_s2a_vfc,
  583. [MSM8939_VDDMX] = &mx_l3a_corner,
  584. [MSM8939_VDDMX_AO] = &mx_l3a_corner_ao,
  585. };
  586. static const struct rpmpd_desc msm8939_desc = {
  587. .rpmpds = msm8939_rpmpds,
  588. .num_pds = ARRAY_SIZE(msm8939_rpmpds),
  589. .max_state = MAX_CORNER_RPMPD_STATE,
  590. };
  591. static struct rpmpd *msm8916_rpmpds[] = {
  592. [RPMPD_VDDCX] = &cx_s1a_corner,
  593. [RPMPD_VDDCX_AO] = &cx_s1a_corner_ao,
  594. [RPMPD_VDDCX_VFC] = &cx_s1a_vfc,
  595. [RPMPD_VDDMX] = &mx_l3a_corner,
  596. [RPMPD_VDDMX_AO] = &mx_l3a_corner_ao,
  597. };
  598. static const struct rpmpd_desc msm8916_desc = {
  599. .rpmpds = msm8916_rpmpds,
  600. .num_pds = ARRAY_SIZE(msm8916_rpmpds),
  601. .max_state = MAX_CORNER_RPMPD_STATE,
  602. };
  603. static struct rpmpd *msm8917_rpmpds[] = {
  604. [RPMPD_VDDCX] = &cx_s2a_lvl,
  605. [RPMPD_VDDCX_AO] = &cx_s2a_lvl_ao,
  606. [RPMPD_VDDCX_VFL] = &cx_s2a_vfl,
  607. [RPMPD_VDDMX] = &mx_l3a_lvl,
  608. [RPMPD_VDDMX_AO] = &mx_l3a_lvl_ao,
  609. };
  610. static const struct rpmpd_desc msm8917_desc = {
  611. .rpmpds = msm8917_rpmpds,
  612. .num_pds = ARRAY_SIZE(msm8917_rpmpds),
  613. .max_state = RPM_SMD_LEVEL_TURBO,
  614. };
  615. static struct rpmpd *msm8953_rpmpds[] = {
  616. [MSM8953_VDDMD] = &md_s1a_lvl,
  617. [MSM8953_VDDMD_AO] = &md_s1a_lvl_ao,
  618. [MSM8953_VDDCX] = &cx_s2a_lvl,
  619. [MSM8953_VDDCX_AO] = &cx_s2a_lvl_ao,
  620. [MSM8953_VDDCX_VFL] = &cx_s2a_vfl,
  621. [MSM8953_VDDMX] = &mx_s7a_lvl,
  622. [MSM8953_VDDMX_AO] = &mx_s7a_lvl_ao,
  623. };
  624. static const struct rpmpd_desc msm8953_desc = {
  625. .rpmpds = msm8953_rpmpds,
  626. .num_pds = ARRAY_SIZE(msm8953_rpmpds),
  627. .max_state = RPM_SMD_LEVEL_TURBO,
  628. };
  629. static struct rpmpd *msm8974_rpmpds[] = {
  630. [MSM8974_VDDCX] = &cx_s2b_corner,
  631. [MSM8974_VDDCX_AO] = &cx_s2b_corner_ao,
  632. [MSM8974_VDDCX_VFC] = &cx_s2b_vfc,
  633. [MSM8974_VDDGFX] = &gfx_s4b_corner,
  634. [MSM8974_VDDGFX_VFC] = &gfx_s4b_vfc,
  635. };
  636. static const struct rpmpd_desc msm8974_desc = {
  637. .rpmpds = msm8974_rpmpds,
  638. .num_pds = ARRAY_SIZE(msm8974_rpmpds),
  639. .max_state = MAX_CORNER_RPMPD_STATE,
  640. };
  641. static struct rpmpd *msm8974pro_pma8084_rpmpds[] = {
  642. [MSM8974_VDDCX] = &cx_s2a_corner,
  643. [MSM8974_VDDCX_AO] = &cx_s2a_corner_ao,
  644. [MSM8974_VDDCX_VFC] = &cx_s2a_vfc,
  645. [MSM8974_VDDGFX] = &gfx_s7a_corner,
  646. [MSM8974_VDDGFX_VFC] = &gfx_s7a_vfc,
  647. };
  648. static const struct rpmpd_desc msm8974pro_pma8084_desc = {
  649. .rpmpds = msm8974pro_pma8084_rpmpds,
  650. .num_pds = ARRAY_SIZE(msm8974pro_pma8084_rpmpds),
  651. .max_state = MAX_CORNER_RPMPD_STATE,
  652. };
  653. static struct rpmpd *msm8976_rpmpds[] = {
  654. [RPMPD_VDDCX] = &cx_s2a_lvl,
  655. [RPMPD_VDDCX_AO] = &cx_s2a_lvl_ao,
  656. [RPMPD_VDDCX_VFL] = &cx_rwsc2_vfl,
  657. [RPMPD_VDDMX] = &mx_s6a_lvl,
  658. [RPMPD_VDDMX_AO] = &mx_s6a_lvl_ao,
  659. [RPMPD_VDDMX_VFL] = &mx_rwsm6_vfl,
  660. };
  661. static const struct rpmpd_desc msm8976_desc = {
  662. .rpmpds = msm8976_rpmpds,
  663. .num_pds = ARRAY_SIZE(msm8976_rpmpds),
  664. .max_state = RPM_SMD_LEVEL_TURBO_HIGH,
  665. };
  666. static struct rpmpd *msm8994_rpmpds[] = {
  667. [MSM8994_VDDCX] = &cx_s1a_corner,
  668. [MSM8994_VDDCX_AO] = &cx_s1a_corner_ao,
  669. [MSM8994_VDDCX_VFC] = &cx_s1a_vfc,
  670. [MSM8994_VDDMX] = &mx_s2a_corner,
  671. [MSM8994_VDDMX_AO] = &mx_s2a_corner_ao,
  672. /* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */
  673. [MSM8994_VDDGFX] = &gfx_s2b_corner,
  674. [MSM8994_VDDGFX_VFC] = &gfx_s2b_vfc,
  675. };
  676. static const struct rpmpd_desc msm8994_desc = {
  677. .rpmpds = msm8994_rpmpds,
  678. .num_pds = ARRAY_SIZE(msm8994_rpmpds),
  679. .max_state = MAX_CORNER_RPMPD_STATE,
  680. };
  681. static struct rpmpd *msm8996_rpmpds[] = {
  682. [MSM8996_VDDCX] = &cx_s1a_corner,
  683. [MSM8996_VDDCX_AO] = &cx_s1a_corner_ao,
  684. [MSM8996_VDDCX_VFC] = &cx_s1a_vfc,
  685. [MSM8996_VDDMX] = &mx_s2a_corner,
  686. [MSM8996_VDDMX_AO] = &mx_s2a_corner_ao,
  687. [MSM8996_VDDSSCX] = &ssc_cx_l26a_corner,
  688. [MSM8996_VDDSSCX_VFC] = &ssc_cx_l26a_vfc,
  689. };
  690. static const struct rpmpd_desc msm8996_desc = {
  691. .rpmpds = msm8996_rpmpds,
  692. .num_pds = ARRAY_SIZE(msm8996_rpmpds),
  693. .max_state = MAX_CORNER_RPMPD_STATE,
  694. };
  695. static struct rpmpd *msm8998_rpmpds[] = {
  696. [RPMPD_VDDCX] = &cx_rwcx0_lvl,
  697. [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao,
  698. [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl,
  699. [RPMPD_VDDMX] = &mx_rwmx0_lvl,
  700. [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  701. [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl,
  702. [RPMPD_SSCCX] = &ssc_cx_rwsc0_lvl,
  703. [RPMPD_SSCCX_VFL] = &ssc_cx_rwsc0_vfl,
  704. [RPMPD_SSCMX] = &ssc_mx_rwsm0_lvl,
  705. [RPMPD_SSCMX_VFL] = &ssc_mx_rwsm0_vfl,
  706. };
  707. static const struct rpmpd_desc msm8998_desc = {
  708. .rpmpds = msm8998_rpmpds,
  709. .num_pds = ARRAY_SIZE(msm8998_rpmpds),
  710. .max_state = RPM_SMD_LEVEL_BINNING,
  711. };
  712. static struct rpmpd *qcs404_rpmpds[] = {
  713. [QCS404_VDDMX] = &mx_rwmx0_lvl,
  714. [QCS404_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  715. [QCS404_VDDMX_VFL] = &mx_rwmx0_vfl,
  716. [QCS404_LPICX] = &lpi_cx_rwlc0_lvl,
  717. [QCS404_LPICX_VFL] = &lpi_cx_rwlc0_vfl,
  718. [QCS404_LPIMX] = &lpi_mx_rwlm0_lvl,
  719. [QCS404_LPIMX_VFL] = &lpi_mx_rwlm0_vfl,
  720. };
  721. static const struct rpmpd_desc qcs404_desc = {
  722. .rpmpds = qcs404_rpmpds,
  723. .num_pds = ARRAY_SIZE(qcs404_rpmpds),
  724. .max_state = RPM_SMD_LEVEL_BINNING,
  725. };
  726. static struct rpmpd *qm215_rpmpds[] = {
  727. [RPMPD_VDDCX] = &cx_s1a_lvl,
  728. [RPMPD_VDDCX_AO] = &cx_s1a_lvl_ao,
  729. [RPMPD_VDDCX_VFL] = &cx_s1a_vfl,
  730. [RPMPD_VDDMX] = &mx_l2a_lvl,
  731. [RPMPD_VDDMX_AO] = &mx_l2a_lvl_ao,
  732. };
  733. static const struct rpmpd_desc qm215_desc = {
  734. .rpmpds = qm215_rpmpds,
  735. .num_pds = ARRAY_SIZE(qm215_rpmpds),
  736. .max_state = RPM_SMD_LEVEL_TURBO,
  737. };
  738. static struct rpmpd *sdm660_rpmpds[] = {
  739. [RPMPD_VDDCX] = &cx_rwcx0_lvl,
  740. [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao,
  741. [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl,
  742. [RPMPD_VDDMX] = &mx_rwmx0_lvl,
  743. [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  744. [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl,
  745. [RPMPD_SSCCX] = &ssc_cx_rwlc0_lvl,
  746. [RPMPD_SSCCX_VFL] = &ssc_cx_rwlc0_vfl,
  747. [RPMPD_SSCMX] = &ssc_mx_rwlm0_lvl,
  748. [RPMPD_SSCMX_VFL] = &ssc_mx_rwlm0_vfl,
  749. };
  750. static const struct rpmpd_desc sdm660_desc = {
  751. .rpmpds = sdm660_rpmpds,
  752. .num_pds = ARRAY_SIZE(sdm660_rpmpds),
  753. .max_state = RPM_SMD_LEVEL_TURBO,
  754. };
  755. static struct rpmpd *sm6115_rpmpds[] = {
  756. [SM6115_VDDCX] = &cx_rwcx0_lvl,
  757. [SM6115_VDDCX_AO] = &cx_rwcx0_lvl_ao,
  758. [SM6115_VDDCX_VFL] = &cx_rwcx0_vfl,
  759. [SM6115_VDDMX] = &mx_rwmx0_lvl,
  760. [SM6115_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  761. [SM6115_VDDMX_VFL] = &mx_rwmx0_vfl,
  762. [SM6115_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl,
  763. [SM6115_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl,
  764. };
  765. static const struct rpmpd_desc sm6115_desc = {
  766. .rpmpds = sm6115_rpmpds,
  767. .num_pds = ARRAY_SIZE(sm6115_rpmpds),
  768. .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
  769. };
  770. static struct rpmpd *sm6125_rpmpds[] = {
  771. [RPMPD_VDDCX] = &cx_rwcx0_lvl,
  772. [RPMPD_VDDCX_AO] = &cx_rwcx0_lvl_ao,
  773. [RPMPD_VDDCX_VFL] = &cx_rwcx0_vfl,
  774. [RPMPD_VDDMX] = &mx_rwmx0_lvl,
  775. [RPMPD_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  776. [RPMPD_VDDMX_VFL] = &mx_rwmx0_vfl,
  777. };
  778. static const struct rpmpd_desc sm6125_desc = {
  779. .rpmpds = sm6125_rpmpds,
  780. .num_pds = ARRAY_SIZE(sm6125_rpmpds),
  781. .max_state = RPM_SMD_LEVEL_BINNING,
  782. };
  783. static struct rpmpd *sm6375_rpmpds[] = {
  784. [SM6375_VDDCX] = &cx_rwcx0_lvl,
  785. [SM6375_VDDCX_AO] = &cx_rwcx0_lvl_ao,
  786. [SM6375_VDDCX_VFL] = &cx_rwcx0_vfl,
  787. [SM6375_VDDMX] = &mx_rwmx0_lvl,
  788. [SM6375_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  789. [SM6375_VDDMX_VFL] = &mx_rwmx0_vfl,
  790. [SM6375_VDDGX] = &gx_rwgx0_lvl,
  791. [SM6375_VDDGX_AO] = &gx_rwgx0_lvl_ao,
  792. [SM6375_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl,
  793. [SM6375_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl,
  794. };
  795. static const struct rpmpd_desc sm6375_desc = {
  796. .rpmpds = sm6375_rpmpds,
  797. .num_pds = ARRAY_SIZE(sm6375_rpmpds),
  798. .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
  799. };
  800. static struct rpmpd *qcm2290_rpmpds[] = {
  801. [QCM2290_VDDCX] = &cx_rwcx0_lvl,
  802. [QCM2290_VDDCX_AO] = &cx_rwcx0_lvl_ao,
  803. [QCM2290_VDDCX_VFL] = &cx_rwcx0_vfl,
  804. [QCM2290_VDDMX] = &mx_rwmx0_lvl,
  805. [QCM2290_VDDMX_AO] = &mx_rwmx0_lvl_ao,
  806. [QCM2290_VDDMX_VFL] = &mx_rwmx0_vfl,
  807. [QCM2290_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl,
  808. [QCM2290_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl,
  809. };
  810. static const struct rpmpd_desc qcm2290_desc = {
  811. .rpmpds = qcm2290_rpmpds,
  812. .num_pds = ARRAY_SIZE(qcm2290_rpmpds),
  813. .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
  814. };
  815. static const struct of_device_id rpmpd_match_table[] = {
  816. { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
  817. { .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
  818. { .compatible = "qcom,msm8909-rpmpd", .data = &msm8916_desc },
  819. { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
  820. { .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc },
  821. { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
  822. { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
  823. { .compatible = "qcom,msm8974-rpmpd", .data = &msm8974_desc },
  824. { .compatible = "qcom,msm8974pro-pma8084-rpmpd", .data = &msm8974pro_pma8084_desc },
  825. { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
  826. { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc },
  827. { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
  828. { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
  829. { .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc },
  830. { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
  831. { .compatible = "qcom,qm215-rpmpd", .data = &qm215_desc },
  832. { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
  833. { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
  834. { .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
  835. { .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },
  836. { }
  837. };
  838. MODULE_DEVICE_TABLE(of, rpmpd_match_table);
  839. static int rpmpd_send_enable(struct rpmpd *pd, bool enable)
  840. {
  841. struct rpmpd_req req = {
  842. .key = KEY_ENABLE,
  843. .nbytes = cpu_to_le32(sizeof(u32)),
  844. .value = cpu_to_le32(enable),
  845. };
  846. return qcom_rpm_smd_write(rpmpd_smd_rpm, QCOM_SMD_RPM_ACTIVE_STATE,
  847. pd->res_type, pd->res_id, &req, sizeof(req));
  848. }
  849. static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner)
  850. {
  851. struct rpmpd_req req = {
  852. .key = pd->key,
  853. .nbytes = cpu_to_le32(sizeof(u32)),
  854. .value = cpu_to_le32(corner),
  855. };
  856. return qcom_rpm_smd_write(rpmpd_smd_rpm, state, pd->res_type, pd->res_id,
  857. &req, sizeof(req));
  858. };
  859. static void to_active_sleep(struct rpmpd *pd, unsigned int corner,
  860. unsigned int *active, unsigned int *sleep)
  861. {
  862. *active = corner;
  863. if (pd->active_only)
  864. *sleep = 0;
  865. else
  866. *sleep = *active;
  867. }
  868. static int rpmpd_aggregate_corner(struct rpmpd *pd)
  869. {
  870. int ret;
  871. struct rpmpd *peer = pd->peer;
  872. unsigned int active_corner, sleep_corner;
  873. unsigned int this_active_corner = 0, this_sleep_corner = 0;
  874. unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
  875. /* Clamp to the highest corner/level if sync_state isn't done yet */
  876. if (!pd->state_synced)
  877. this_active_corner = this_sleep_corner = pd->max_state;
  878. else
  879. to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner);
  880. if (peer && peer->enabled)
  881. to_active_sleep(peer, peer->corner, &peer_active_corner,
  882. &peer_sleep_corner);
  883. active_corner = max(this_active_corner, peer_active_corner);
  884. ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner);
  885. if (ret)
  886. return ret;
  887. sleep_corner = max(this_sleep_corner, peer_sleep_corner);
  888. return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner);
  889. }
  890. static int rpmpd_power_on(struct generic_pm_domain *domain)
  891. {
  892. int ret;
  893. struct rpmpd *pd = domain_to_rpmpd(domain);
  894. guard(mutex)(&rpmpd_lock);
  895. ret = rpmpd_send_enable(pd, true);
  896. if (ret)
  897. return ret;
  898. pd->enabled = true;
  899. if (pd->corner)
  900. ret = rpmpd_aggregate_corner(pd);
  901. return ret;
  902. }
  903. static int rpmpd_power_off(struct generic_pm_domain *domain)
  904. {
  905. int ret;
  906. struct rpmpd *pd = domain_to_rpmpd(domain);
  907. mutex_lock(&rpmpd_lock);
  908. ret = rpmpd_send_enable(pd, false);
  909. if (!ret)
  910. pd->enabled = false;
  911. mutex_unlock(&rpmpd_lock);
  912. return ret;
  913. }
  914. static int rpmpd_set_performance(struct generic_pm_domain *domain,
  915. unsigned int state)
  916. {
  917. struct rpmpd *pd = domain_to_rpmpd(domain);
  918. if (state > pd->max_state)
  919. state = pd->max_state;
  920. guard(mutex)(&rpmpd_lock);
  921. pd->corner = state;
  922. /* Always send updates for vfc and vfl */
  923. if (!pd->enabled && pd->key != cpu_to_le32(KEY_FLOOR_CORNER) &&
  924. pd->key != cpu_to_le32(KEY_FLOOR_LEVEL))
  925. return 0;
  926. return rpmpd_aggregate_corner(pd);
  927. }
  928. static int rpmpd_probe(struct platform_device *pdev)
  929. {
  930. int i;
  931. size_t num;
  932. struct genpd_onecell_data *data;
  933. struct rpmpd **rpmpds;
  934. const struct rpmpd_desc *desc;
  935. rpmpd_smd_rpm = dev_get_drvdata(pdev->dev.parent);
  936. if (!rpmpd_smd_rpm) {
  937. dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
  938. return -ENODEV;
  939. }
  940. desc = of_device_get_match_data(&pdev->dev);
  941. if (!desc)
  942. return -EINVAL;
  943. rpmpds = desc->rpmpds;
  944. num = desc->num_pds;
  945. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  946. if (!data)
  947. return -ENOMEM;
  948. data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
  949. GFP_KERNEL);
  950. if (!data->domains)
  951. return -ENOMEM;
  952. data->num_domains = num;
  953. for (i = 0; i < num; i++) {
  954. if (!rpmpds[i]) {
  955. dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n",
  956. i);
  957. continue;
  958. }
  959. rpmpds[i]->max_state = desc->max_state;
  960. rpmpds[i]->pd.power_off = rpmpd_power_off;
  961. rpmpds[i]->pd.power_on = rpmpd_power_on;
  962. rpmpds[i]->pd.set_performance_state = rpmpd_set_performance;
  963. rpmpds[i]->pd.flags = GENPD_FLAG_ACTIVE_WAKEUP;
  964. pm_genpd_init(&rpmpds[i]->pd, NULL, true);
  965. data->domains[i] = &rpmpds[i]->pd;
  966. }
  967. /* Add subdomains */
  968. for (i = 0; i < num; i++) {
  969. if (!rpmpds[i])
  970. continue;
  971. if (rpmpds[i]->parent)
  972. pm_genpd_add_subdomain(rpmpds[i]->parent, &rpmpds[i]->pd);
  973. }
  974. return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
  975. }
  976. static void rpmpd_sync_state(struct device *dev)
  977. {
  978. const struct rpmpd_desc *desc = of_device_get_match_data(dev);
  979. struct rpmpd **rpmpds = desc->rpmpds;
  980. struct rpmpd *pd;
  981. unsigned int i;
  982. int ret;
  983. of_genpd_sync_state(dev->of_node);
  984. mutex_lock(&rpmpd_lock);
  985. for (i = 0; i < desc->num_pds; i++) {
  986. pd = rpmpds[i];
  987. if (!pd)
  988. continue;
  989. pd->state_synced = true;
  990. if (!pd->enabled)
  991. pd->corner = 0;
  992. ret = rpmpd_aggregate_corner(pd);
  993. if (ret)
  994. dev_err(dev, "failed to sync %s: %d\n", pd->pd.name, ret);
  995. }
  996. mutex_unlock(&rpmpd_lock);
  997. }
  998. static struct platform_driver rpmpd_driver = {
  999. .driver = {
  1000. .name = "qcom-rpmpd",
  1001. .of_match_table = rpmpd_match_table,
  1002. .suppress_bind_attrs = true,
  1003. .sync_state = rpmpd_sync_state,
  1004. },
  1005. .probe = rpmpd_probe,
  1006. };
  1007. static int __init rpmpd_init(void)
  1008. {
  1009. return platform_driver_register(&rpmpd_driver);
  1010. }
  1011. core_initcall(rpmpd_init);
  1012. MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
  1013. MODULE_LICENSE("GPL v2");