pm_domains.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. /*
  2. * Rockchip Generic power domain support.
  3. *
  4. * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <linux/io.h>
  11. #include <linux/iopoll.h>
  12. #include <linux/err.h>
  13. #include <linux/pm_clock.h>
  14. #include <linux/pm_domain.h>
  15. #include <linux/of_address.h>
  16. #include <linux/of_clk.h>
  17. #include <linux/of_platform.h>
  18. #include <linux/clk.h>
  19. #include <linux/regmap.h>
  20. #include <linux/mfd/syscon.h>
  21. #include <dt-bindings/power/px30-power.h>
  22. #include <dt-bindings/power/rk3036-power.h>
  23. #include <dt-bindings/power/rk3128-power.h>
  24. #include <dt-bindings/power/rk3228-power.h>
  25. #include <dt-bindings/power/rk3288-power.h>
  26. #include <dt-bindings/power/rk3328-power.h>
  27. #include <dt-bindings/power/rk3366-power.h>
  28. #include <dt-bindings/power/rk3368-power.h>
  29. #include <dt-bindings/power/rk3399-power.h>
  30. struct rockchip_domain_info {
  31. int pwr_mask;
  32. int status_mask;
  33. int req_mask;
  34. int idle_mask;
  35. int ack_mask;
  36. bool active_wakeup;
  37. int pwr_w_mask;
  38. int req_w_mask;
  39. };
  40. struct rockchip_pmu_info {
  41. u32 pwr_offset;
  42. u32 status_offset;
  43. u32 req_offset;
  44. u32 idle_offset;
  45. u32 ack_offset;
  46. u32 core_pwrcnt_offset;
  47. u32 gpu_pwrcnt_offset;
  48. unsigned int core_power_transition_time;
  49. unsigned int gpu_power_transition_time;
  50. int num_domains;
  51. const struct rockchip_domain_info *domain_info;
  52. };
  53. #define MAX_QOS_REGS_NUM 5
  54. #define QOS_PRIORITY 0x08
  55. #define QOS_MODE 0x0c
  56. #define QOS_BANDWIDTH 0x10
  57. #define QOS_SATURATION 0x14
  58. #define QOS_EXTCONTROL 0x18
  59. struct rockchip_pm_domain {
  60. struct generic_pm_domain genpd;
  61. const struct rockchip_domain_info *info;
  62. struct rockchip_pmu *pmu;
  63. int num_qos;
  64. struct regmap **qos_regmap;
  65. u32 *qos_save_regs[MAX_QOS_REGS_NUM];
  66. int num_clks;
  67. struct clk_bulk_data *clks;
  68. };
  69. struct rockchip_pmu {
  70. struct device *dev;
  71. struct regmap *regmap;
  72. const struct rockchip_pmu_info *info;
  73. struct mutex mutex; /* mutex lock for pmu */
  74. struct genpd_onecell_data genpd_data;
  75. struct generic_pm_domain *domains[];
  76. };
  77. #define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
  78. #define DOMAIN(pwr, status, req, idle, ack, wakeup) \
  79. { \
  80. .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \
  81. .status_mask = (status >= 0) ? BIT(status) : 0, \
  82. .req_mask = (req >= 0) ? BIT(req) : 0, \
  83. .idle_mask = (idle >= 0) ? BIT(idle) : 0, \
  84. .ack_mask = (ack >= 0) ? BIT(ack) : 0, \
  85. .active_wakeup = wakeup, \
  86. }
  87. #define DOMAIN_M(pwr, status, req, idle, ack, wakeup) \
  88. { \
  89. .pwr_w_mask = (pwr >= 0) ? BIT(pwr + 16) : 0, \
  90. .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \
  91. .status_mask = (status >= 0) ? BIT(status) : 0, \
  92. .req_w_mask = (req >= 0) ? BIT(req + 16) : 0, \
  93. .req_mask = (req >= 0) ? BIT(req) : 0, \
  94. .idle_mask = (idle >= 0) ? BIT(idle) : 0, \
  95. .ack_mask = (ack >= 0) ? BIT(ack) : 0, \
  96. .active_wakeup = wakeup, \
  97. }
  98. #define DOMAIN_RK3036(req, ack, idle, wakeup) \
  99. { \
  100. .req_mask = (req >= 0) ? BIT(req) : 0, \
  101. .req_w_mask = (req >= 0) ? BIT(req + 16) : 0, \
  102. .ack_mask = (ack >= 0) ? BIT(ack) : 0, \
  103. .idle_mask = (idle >= 0) ? BIT(idle) : 0, \
  104. .active_wakeup = wakeup, \
  105. }
  106. #define DOMAIN_PX30(pwr, status, req, wakeup) \
  107. DOMAIN_M(pwr, status, req, (req) + 16, req, wakeup)
  108. #define DOMAIN_RK3288(pwr, status, req, wakeup) \
  109. DOMAIN(pwr, status, req, req, (req) + 16, wakeup)
  110. #define DOMAIN_RK3328(pwr, status, req, wakeup) \
  111. DOMAIN_M(pwr, pwr, req, (req) + 10, req, wakeup)
  112. #define DOMAIN_RK3368(pwr, status, req, wakeup) \
  113. DOMAIN(pwr, status, req, (req) + 16, req, wakeup)
  114. #define DOMAIN_RK3399(pwr, status, req, wakeup) \
  115. DOMAIN(pwr, status, req, req, req, wakeup)
  116. static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
  117. {
  118. struct rockchip_pmu *pmu = pd->pmu;
  119. const struct rockchip_domain_info *pd_info = pd->info;
  120. unsigned int val;
  121. regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
  122. return (val & pd_info->idle_mask) == pd_info->idle_mask;
  123. }
  124. static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)
  125. {
  126. unsigned int val;
  127. regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
  128. return val;
  129. }
  130. static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
  131. bool idle)
  132. {
  133. const struct rockchip_domain_info *pd_info = pd->info;
  134. struct generic_pm_domain *genpd = &pd->genpd;
  135. struct rockchip_pmu *pmu = pd->pmu;
  136. unsigned int target_ack;
  137. unsigned int val;
  138. bool is_idle;
  139. int ret;
  140. if (pd_info->req_mask == 0)
  141. return 0;
  142. else if (pd_info->req_w_mask)
  143. regmap_write(pmu->regmap, pmu->info->req_offset,
  144. idle ? (pd_info->req_mask | pd_info->req_w_mask) :
  145. pd_info->req_w_mask);
  146. else
  147. regmap_update_bits(pmu->regmap, pmu->info->req_offset,
  148. pd_info->req_mask, idle ? -1U : 0);
  149. dsb(sy);
  150. /* Wait util idle_ack = 1 */
  151. target_ack = idle ? pd_info->ack_mask : 0;
  152. ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,
  153. (val & pd_info->ack_mask) == target_ack,
  154. 0, 10000);
  155. if (ret) {
  156. dev_err(pmu->dev,
  157. "failed to get ack on domain '%s', val=0x%x\n",
  158. genpd->name, val);
  159. return ret;
  160. }
  161. ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,
  162. is_idle, is_idle == idle, 0, 10000);
  163. if (ret) {
  164. dev_err(pmu->dev,
  165. "failed to set idle on domain '%s', val=%d\n",
  166. genpd->name, is_idle);
  167. return ret;
  168. }
  169. return 0;
  170. }
  171. static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
  172. {
  173. int i;
  174. for (i = 0; i < pd->num_qos; i++) {
  175. regmap_read(pd->qos_regmap[i],
  176. QOS_PRIORITY,
  177. &pd->qos_save_regs[0][i]);
  178. regmap_read(pd->qos_regmap[i],
  179. QOS_MODE,
  180. &pd->qos_save_regs[1][i]);
  181. regmap_read(pd->qos_regmap[i],
  182. QOS_BANDWIDTH,
  183. &pd->qos_save_regs[2][i]);
  184. regmap_read(pd->qos_regmap[i],
  185. QOS_SATURATION,
  186. &pd->qos_save_regs[3][i]);
  187. regmap_read(pd->qos_regmap[i],
  188. QOS_EXTCONTROL,
  189. &pd->qos_save_regs[4][i]);
  190. }
  191. return 0;
  192. }
  193. static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
  194. {
  195. int i;
  196. for (i = 0; i < pd->num_qos; i++) {
  197. regmap_write(pd->qos_regmap[i],
  198. QOS_PRIORITY,
  199. pd->qos_save_regs[0][i]);
  200. regmap_write(pd->qos_regmap[i],
  201. QOS_MODE,
  202. pd->qos_save_regs[1][i]);
  203. regmap_write(pd->qos_regmap[i],
  204. QOS_BANDWIDTH,
  205. pd->qos_save_regs[2][i]);
  206. regmap_write(pd->qos_regmap[i],
  207. QOS_SATURATION,
  208. pd->qos_save_regs[3][i]);
  209. regmap_write(pd->qos_regmap[i],
  210. QOS_EXTCONTROL,
  211. pd->qos_save_regs[4][i]);
  212. }
  213. return 0;
  214. }
  215. static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
  216. {
  217. struct rockchip_pmu *pmu = pd->pmu;
  218. unsigned int val;
  219. /* check idle status for idle-only domains */
  220. if (pd->info->status_mask == 0)
  221. return !rockchip_pmu_domain_is_idle(pd);
  222. regmap_read(pmu->regmap, pmu->info->status_offset, &val);
  223. /* 1'b0: power on, 1'b1: power off */
  224. return !(val & pd->info->status_mask);
  225. }
  226. static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
  227. bool on)
  228. {
  229. struct rockchip_pmu *pmu = pd->pmu;
  230. struct generic_pm_domain *genpd = &pd->genpd;
  231. bool is_on;
  232. if (pd->info->pwr_mask == 0)
  233. return;
  234. else if (pd->info->pwr_w_mask)
  235. regmap_write(pmu->regmap, pmu->info->pwr_offset,
  236. on ? pd->info->pwr_w_mask :
  237. (pd->info->pwr_mask | pd->info->pwr_w_mask));
  238. else
  239. regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
  240. pd->info->pwr_mask, on ? 0 : -1U);
  241. dsb(sy);
  242. if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
  243. is_on == on, 0, 10000)) {
  244. dev_err(pmu->dev,
  245. "failed to set domain '%s', val=%d\n",
  246. genpd->name, is_on);
  247. return;
  248. }
  249. }
  250. static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
  251. {
  252. struct rockchip_pmu *pmu = pd->pmu;
  253. int ret;
  254. mutex_lock(&pmu->mutex);
  255. if (rockchip_pmu_domain_is_on(pd) != power_on) {
  256. ret = clk_bulk_enable(pd->num_clks, pd->clks);
  257. if (ret < 0) {
  258. dev_err(pmu->dev, "failed to enable clocks\n");
  259. mutex_unlock(&pmu->mutex);
  260. return ret;
  261. }
  262. if (!power_on) {
  263. rockchip_pmu_save_qos(pd);
  264. /* if powering down, idle request to NIU first */
  265. rockchip_pmu_set_idle_request(pd, true);
  266. }
  267. rockchip_do_pmu_set_power_domain(pd, power_on);
  268. if (power_on) {
  269. /* if powering up, leave idle mode */
  270. rockchip_pmu_set_idle_request(pd, false);
  271. rockchip_pmu_restore_qos(pd);
  272. }
  273. clk_bulk_disable(pd->num_clks, pd->clks);
  274. }
  275. mutex_unlock(&pmu->mutex);
  276. return 0;
  277. }
  278. static int rockchip_pd_power_on(struct generic_pm_domain *domain)
  279. {
  280. struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
  281. return rockchip_pd_power(pd, true);
  282. }
  283. static int rockchip_pd_power_off(struct generic_pm_domain *domain)
  284. {
  285. struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
  286. return rockchip_pd_power(pd, false);
  287. }
  288. static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
  289. struct device *dev)
  290. {
  291. struct clk *clk;
  292. int i;
  293. int error;
  294. dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
  295. error = pm_clk_create(dev);
  296. if (error) {
  297. dev_err(dev, "pm_clk_create failed %d\n", error);
  298. return error;
  299. }
  300. i = 0;
  301. while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
  302. dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
  303. error = pm_clk_add_clk(dev, clk);
  304. if (error) {
  305. dev_err(dev, "pm_clk_add_clk failed %d\n", error);
  306. clk_put(clk);
  307. pm_clk_destroy(dev);
  308. return error;
  309. }
  310. }
  311. return 0;
  312. }
  313. static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
  314. struct device *dev)
  315. {
  316. dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
  317. pm_clk_destroy(dev);
  318. }
  319. static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
  320. struct device_node *node)
  321. {
  322. const struct rockchip_domain_info *pd_info;
  323. struct rockchip_pm_domain *pd;
  324. struct device_node *qos_node;
  325. int i, j;
  326. u32 id;
  327. int error;
  328. error = of_property_read_u32(node, "reg", &id);
  329. if (error) {
  330. dev_err(pmu->dev,
  331. "%s: failed to retrieve domain id (reg): %d\n",
  332. node->name, error);
  333. return -EINVAL;
  334. }
  335. if (id >= pmu->info->num_domains) {
  336. dev_err(pmu->dev, "%s: invalid domain id %d\n",
  337. node->name, id);
  338. return -EINVAL;
  339. }
  340. pd_info = &pmu->info->domain_info[id];
  341. if (!pd_info) {
  342. dev_err(pmu->dev, "%s: undefined domain id %d\n",
  343. node->name, id);
  344. return -EINVAL;
  345. }
  346. pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
  347. if (!pd)
  348. return -ENOMEM;
  349. pd->info = pd_info;
  350. pd->pmu = pmu;
  351. pd->num_clks = of_clk_get_parent_count(node);
  352. if (pd->num_clks > 0) {
  353. pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
  354. sizeof(*pd->clks), GFP_KERNEL);
  355. if (!pd->clks)
  356. return -ENOMEM;
  357. } else {
  358. dev_dbg(pmu->dev, "%s: doesn't have clocks: %d\n",
  359. node->name, pd->num_clks);
  360. pd->num_clks = 0;
  361. }
  362. for (i = 0; i < pd->num_clks; i++) {
  363. pd->clks[i].clk = of_clk_get(node, i);
  364. if (IS_ERR(pd->clks[i].clk)) {
  365. error = PTR_ERR(pd->clks[i].clk);
  366. dev_err(pmu->dev,
  367. "%s: failed to get clk at index %d: %d\n",
  368. node->name, i, error);
  369. return error;
  370. }
  371. }
  372. error = clk_bulk_prepare(pd->num_clks, pd->clks);
  373. if (error)
  374. goto err_put_clocks;
  375. pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
  376. NULL);
  377. if (pd->num_qos > 0) {
  378. pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
  379. sizeof(*pd->qos_regmap),
  380. GFP_KERNEL);
  381. if (!pd->qos_regmap) {
  382. error = -ENOMEM;
  383. goto err_unprepare_clocks;
  384. }
  385. for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
  386. pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
  387. pd->num_qos,
  388. sizeof(u32),
  389. GFP_KERNEL);
  390. if (!pd->qos_save_regs[j]) {
  391. error = -ENOMEM;
  392. goto err_unprepare_clocks;
  393. }
  394. }
  395. for (j = 0; j < pd->num_qos; j++) {
  396. qos_node = of_parse_phandle(node, "pm_qos", j);
  397. if (!qos_node) {
  398. error = -ENODEV;
  399. goto err_unprepare_clocks;
  400. }
  401. pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
  402. if (IS_ERR(pd->qos_regmap[j])) {
  403. error = -ENODEV;
  404. of_node_put(qos_node);
  405. goto err_unprepare_clocks;
  406. }
  407. of_node_put(qos_node);
  408. }
  409. }
  410. error = rockchip_pd_power(pd, true);
  411. if (error) {
  412. dev_err(pmu->dev,
  413. "failed to power on domain '%s': %d\n",
  414. node->name, error);
  415. goto err_unprepare_clocks;
  416. }
  417. pd->genpd.name = node->name;
  418. pd->genpd.power_off = rockchip_pd_power_off;
  419. pd->genpd.power_on = rockchip_pd_power_on;
  420. pd->genpd.attach_dev = rockchip_pd_attach_dev;
  421. pd->genpd.detach_dev = rockchip_pd_detach_dev;
  422. pd->genpd.flags = GENPD_FLAG_PM_CLK;
  423. if (pd_info->active_wakeup)
  424. pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
  425. pm_genpd_init(&pd->genpd, NULL, false);
  426. pmu->genpd_data.domains[id] = &pd->genpd;
  427. return 0;
  428. err_unprepare_clocks:
  429. clk_bulk_unprepare(pd->num_clks, pd->clks);
  430. err_put_clocks:
  431. clk_bulk_put(pd->num_clks, pd->clks);
  432. return error;
  433. }
  434. static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
  435. {
  436. int ret;
  437. /*
  438. * We're in the error cleanup already, so we only complain,
  439. * but won't emit another error on top of the original one.
  440. */
  441. ret = pm_genpd_remove(&pd->genpd);
  442. if (ret < 0)
  443. dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
  444. pd->genpd.name, ret);
  445. clk_bulk_unprepare(pd->num_clks, pd->clks);
  446. clk_bulk_put(pd->num_clks, pd->clks);
  447. /* protect the zeroing of pm->num_clks */
  448. mutex_lock(&pd->pmu->mutex);
  449. pd->num_clks = 0;
  450. mutex_unlock(&pd->pmu->mutex);
  451. /* devm will free our memory */
  452. }
  453. static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
  454. {
  455. struct generic_pm_domain *genpd;
  456. struct rockchip_pm_domain *pd;
  457. int i;
  458. for (i = 0; i < pmu->genpd_data.num_domains; i++) {
  459. genpd = pmu->genpd_data.domains[i];
  460. if (genpd) {
  461. pd = to_rockchip_pd(genpd);
  462. rockchip_pm_remove_one_domain(pd);
  463. }
  464. }
  465. /* devm will free our memory */
  466. }
  467. static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
  468. u32 domain_reg_offset,
  469. unsigned int count)
  470. {
  471. /* First configure domain power down transition count ... */
  472. regmap_write(pmu->regmap, domain_reg_offset, count);
  473. /* ... and then power up count. */
  474. regmap_write(pmu->regmap, domain_reg_offset + 4, count);
  475. }
  476. static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
  477. struct device_node *parent)
  478. {
  479. struct device_node *np;
  480. struct generic_pm_domain *child_domain, *parent_domain;
  481. int error;
  482. for_each_child_of_node(parent, np) {
  483. u32 idx;
  484. error = of_property_read_u32(parent, "reg", &idx);
  485. if (error) {
  486. dev_err(pmu->dev,
  487. "%s: failed to retrieve domain id (reg): %d\n",
  488. parent->name, error);
  489. goto err_out;
  490. }
  491. parent_domain = pmu->genpd_data.domains[idx];
  492. error = rockchip_pm_add_one_domain(pmu, np);
  493. if (error) {
  494. dev_err(pmu->dev, "failed to handle node %s: %d\n",
  495. np->name, error);
  496. goto err_out;
  497. }
  498. error = of_property_read_u32(np, "reg", &idx);
  499. if (error) {
  500. dev_err(pmu->dev,
  501. "%s: failed to retrieve domain id (reg): %d\n",
  502. np->name, error);
  503. goto err_out;
  504. }
  505. child_domain = pmu->genpd_data.domains[idx];
  506. error = pm_genpd_add_subdomain(parent_domain, child_domain);
  507. if (error) {
  508. dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
  509. parent_domain->name, child_domain->name, error);
  510. goto err_out;
  511. } else {
  512. dev_dbg(pmu->dev, "%s add subdomain: %s\n",
  513. parent_domain->name, child_domain->name);
  514. }
  515. rockchip_pm_add_subdomain(pmu, np);
  516. }
  517. return 0;
  518. err_out:
  519. of_node_put(np);
  520. return error;
  521. }
  522. static int rockchip_pm_domain_probe(struct platform_device *pdev)
  523. {
  524. struct device *dev = &pdev->dev;
  525. struct device_node *np = dev->of_node;
  526. struct device_node *node;
  527. struct device *parent;
  528. struct rockchip_pmu *pmu;
  529. const struct of_device_id *match;
  530. const struct rockchip_pmu_info *pmu_info;
  531. int error;
  532. if (!np) {
  533. dev_err(dev, "device tree node not found\n");
  534. return -ENODEV;
  535. }
  536. match = of_match_device(dev->driver->of_match_table, dev);
  537. if (!match || !match->data) {
  538. dev_err(dev, "missing pmu data\n");
  539. return -EINVAL;
  540. }
  541. pmu_info = match->data;
  542. pmu = devm_kzalloc(dev,
  543. struct_size(pmu, domains, pmu_info->num_domains),
  544. GFP_KERNEL);
  545. if (!pmu)
  546. return -ENOMEM;
  547. pmu->dev = &pdev->dev;
  548. mutex_init(&pmu->mutex);
  549. pmu->info = pmu_info;
  550. pmu->genpd_data.domains = pmu->domains;
  551. pmu->genpd_data.num_domains = pmu_info->num_domains;
  552. parent = dev->parent;
  553. if (!parent) {
  554. dev_err(dev, "no parent for syscon devices\n");
  555. return -ENODEV;
  556. }
  557. pmu->regmap = syscon_node_to_regmap(parent->of_node);
  558. if (IS_ERR(pmu->regmap)) {
  559. dev_err(dev, "no regmap available\n");
  560. return PTR_ERR(pmu->regmap);
  561. }
  562. /*
  563. * Configure power up and down transition delays for CORE
  564. * and GPU domains.
  565. */
  566. if (pmu_info->core_power_transition_time)
  567. rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
  568. pmu_info->core_power_transition_time);
  569. if (pmu_info->gpu_pwrcnt_offset)
  570. rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
  571. pmu_info->gpu_power_transition_time);
  572. error = -ENODEV;
  573. for_each_available_child_of_node(np, node) {
  574. error = rockchip_pm_add_one_domain(pmu, node);
  575. if (error) {
  576. dev_err(dev, "failed to handle node %s: %d\n",
  577. node->name, error);
  578. of_node_put(node);
  579. goto err_out;
  580. }
  581. error = rockchip_pm_add_subdomain(pmu, node);
  582. if (error < 0) {
  583. dev_err(dev, "failed to handle subdomain node %s: %d\n",
  584. node->name, error);
  585. of_node_put(node);
  586. goto err_out;
  587. }
  588. }
  589. if (error) {
  590. dev_dbg(dev, "no power domains defined\n");
  591. goto err_out;
  592. }
  593. error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
  594. if (error) {
  595. dev_err(dev, "failed to add provider: %d\n", error);
  596. goto err_out;
  597. }
  598. return 0;
  599. err_out:
  600. rockchip_pm_domain_cleanup(pmu);
  601. return error;
  602. }
  603. static const struct rockchip_domain_info px30_pm_domains[] = {
  604. [PX30_PD_USB] = DOMAIN_PX30(5, 5, 10, false),
  605. [PX30_PD_SDCARD] = DOMAIN_PX30(8, 8, 9, false),
  606. [PX30_PD_GMAC] = DOMAIN_PX30(10, 10, 6, false),
  607. [PX30_PD_MMC_NAND] = DOMAIN_PX30(11, 11, 5, false),
  608. [PX30_PD_VPU] = DOMAIN_PX30(12, 12, 14, false),
  609. [PX30_PD_VO] = DOMAIN_PX30(13, 13, 7, false),
  610. [PX30_PD_VI] = DOMAIN_PX30(14, 14, 8, false),
  611. [PX30_PD_GPU] = DOMAIN_PX30(15, 15, 2, false),
  612. };
  613. static const struct rockchip_domain_info rk3036_pm_domains[] = {
  614. [RK3036_PD_MSCH] = DOMAIN_RK3036(14, 23, 30, true),
  615. [RK3036_PD_CORE] = DOMAIN_RK3036(13, 17, 24, false),
  616. [RK3036_PD_PERI] = DOMAIN_RK3036(12, 18, 25, false),
  617. [RK3036_PD_VIO] = DOMAIN_RK3036(11, 19, 26, false),
  618. [RK3036_PD_VPU] = DOMAIN_RK3036(10, 20, 27, false),
  619. [RK3036_PD_GPU] = DOMAIN_RK3036(9, 21, 28, false),
  620. [RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false),
  621. };
  622. static const struct rockchip_domain_info rk3128_pm_domains[] = {
  623. [RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false),
  624. [RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true),
  625. [RK3128_PD_VIO] = DOMAIN_RK3288(3, 3, 2, false),
  626. [RK3128_PD_VIDEO] = DOMAIN_RK3288(2, 2, 1, false),
  627. [RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false),
  628. };
  629. static const struct rockchip_domain_info rk3228_pm_domains[] = {
  630. [RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true),
  631. [RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true),
  632. [RK3228_PD_BUS] = DOMAIN_RK3036(2, 2, 18, true),
  633. [RK3228_PD_SYS] = DOMAIN_RK3036(3, 3, 19, true),
  634. [RK3228_PD_VIO] = DOMAIN_RK3036(4, 4, 20, false),
  635. [RK3228_PD_VOP] = DOMAIN_RK3036(5, 5, 21, false),
  636. [RK3228_PD_VPU] = DOMAIN_RK3036(6, 6, 22, false),
  637. [RK3228_PD_RKVDEC] = DOMAIN_RK3036(7, 7, 23, false),
  638. [RK3228_PD_GPU] = DOMAIN_RK3036(8, 8, 24, false),
  639. [RK3228_PD_PERI] = DOMAIN_RK3036(9, 9, 25, true),
  640. [RK3228_PD_GMAC] = DOMAIN_RK3036(10, 10, 26, false),
  641. };
  642. static const struct rockchip_domain_info rk3288_pm_domains[] = {
  643. [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4, false),
  644. [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9, false),
  645. [RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3, false),
  646. [RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2, false),
  647. };
  648. static const struct rockchip_domain_info rk3328_pm_domains[] = {
  649. [RK3328_PD_CORE] = DOMAIN_RK3328(-1, 0, 0, false),
  650. [RK3328_PD_GPU] = DOMAIN_RK3328(-1, 1, 1, false),
  651. [RK3328_PD_BUS] = DOMAIN_RK3328(-1, 2, 2, true),
  652. [RK3328_PD_MSCH] = DOMAIN_RK3328(-1, 3, 3, true),
  653. [RK3328_PD_PERI] = DOMAIN_RK3328(-1, 4, 4, true),
  654. [RK3328_PD_VIDEO] = DOMAIN_RK3328(-1, 5, 5, false),
  655. [RK3328_PD_HEVC] = DOMAIN_RK3328(-1, 6, 6, false),
  656. [RK3328_PD_VIO] = DOMAIN_RK3328(-1, 8, 8, false),
  657. [RK3328_PD_VPU] = DOMAIN_RK3328(-1, 9, 9, false),
  658. };
  659. static const struct rockchip_domain_info rk3366_pm_domains[] = {
  660. [RK3366_PD_PERI] = DOMAIN_RK3368(10, 10, 6, true),
  661. [RK3366_PD_VIO] = DOMAIN_RK3368(14, 14, 8, false),
  662. [RK3366_PD_VIDEO] = DOMAIN_RK3368(13, 13, 7, false),
  663. [RK3366_PD_RKVDEC] = DOMAIN_RK3368(11, 11, 7, false),
  664. [RK3366_PD_WIFIBT] = DOMAIN_RK3368(8, 8, 9, false),
  665. [RK3366_PD_VPU] = DOMAIN_RK3368(12, 12, 7, false),
  666. [RK3366_PD_GPU] = DOMAIN_RK3368(15, 15, 2, false),
  667. };
  668. static const struct rockchip_domain_info rk3368_pm_domains[] = {
  669. [RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6, true),
  670. [RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8, false),
  671. [RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7, false),
  672. [RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2, false),
  673. [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2, false),
  674. };
  675. static const struct rockchip_domain_info rk3399_pm_domains[] = {
  676. [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1, false),
  677. [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1, false),
  678. [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1, true),
  679. [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15, true),
  680. [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16, true),
  681. [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1, true),
  682. [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2, true),
  683. [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14, true),
  684. [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17, false),
  685. [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0, false),
  686. [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3, false),
  687. [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4, false),
  688. [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5, false),
  689. [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6, false),
  690. [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1, false),
  691. [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7, false),
  692. [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8, false),
  693. [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9, false),
  694. [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10, false),
  695. [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11, false),
  696. [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23, true),
  697. [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24, true),
  698. [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12, true),
  699. [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22, false),
  700. [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27, true),
  701. [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28, true),
  702. [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29, true),
  703. };
  704. static const struct rockchip_pmu_info px30_pmu = {
  705. .pwr_offset = 0x18,
  706. .status_offset = 0x20,
  707. .req_offset = 0x64,
  708. .idle_offset = 0x6c,
  709. .ack_offset = 0x6c,
  710. .num_domains = ARRAY_SIZE(px30_pm_domains),
  711. .domain_info = px30_pm_domains,
  712. };
  713. static const struct rockchip_pmu_info rk3036_pmu = {
  714. .req_offset = 0x148,
  715. .idle_offset = 0x14c,
  716. .ack_offset = 0x14c,
  717. .num_domains = ARRAY_SIZE(rk3036_pm_domains),
  718. .domain_info = rk3036_pm_domains,
  719. };
  720. static const struct rockchip_pmu_info rk3128_pmu = {
  721. .pwr_offset = 0x04,
  722. .status_offset = 0x08,
  723. .req_offset = 0x0c,
  724. .idle_offset = 0x10,
  725. .ack_offset = 0x10,
  726. .num_domains = ARRAY_SIZE(rk3128_pm_domains),
  727. .domain_info = rk3128_pm_domains,
  728. };
  729. static const struct rockchip_pmu_info rk3228_pmu = {
  730. .req_offset = 0x40c,
  731. .idle_offset = 0x488,
  732. .ack_offset = 0x488,
  733. .num_domains = ARRAY_SIZE(rk3228_pm_domains),
  734. .domain_info = rk3228_pm_domains,
  735. };
  736. static const struct rockchip_pmu_info rk3288_pmu = {
  737. .pwr_offset = 0x08,
  738. .status_offset = 0x0c,
  739. .req_offset = 0x10,
  740. .idle_offset = 0x14,
  741. .ack_offset = 0x14,
  742. .core_pwrcnt_offset = 0x34,
  743. .gpu_pwrcnt_offset = 0x3c,
  744. .core_power_transition_time = 24, /* 1us */
  745. .gpu_power_transition_time = 24, /* 1us */
  746. .num_domains = ARRAY_SIZE(rk3288_pm_domains),
  747. .domain_info = rk3288_pm_domains,
  748. };
  749. static const struct rockchip_pmu_info rk3328_pmu = {
  750. .req_offset = 0x414,
  751. .idle_offset = 0x484,
  752. .ack_offset = 0x484,
  753. .num_domains = ARRAY_SIZE(rk3328_pm_domains),
  754. .domain_info = rk3328_pm_domains,
  755. };
  756. static const struct rockchip_pmu_info rk3366_pmu = {
  757. .pwr_offset = 0x0c,
  758. .status_offset = 0x10,
  759. .req_offset = 0x3c,
  760. .idle_offset = 0x40,
  761. .ack_offset = 0x40,
  762. .core_pwrcnt_offset = 0x48,
  763. .gpu_pwrcnt_offset = 0x50,
  764. .core_power_transition_time = 24,
  765. .gpu_power_transition_time = 24,
  766. .num_domains = ARRAY_SIZE(rk3366_pm_domains),
  767. .domain_info = rk3366_pm_domains,
  768. };
  769. static const struct rockchip_pmu_info rk3368_pmu = {
  770. .pwr_offset = 0x0c,
  771. .status_offset = 0x10,
  772. .req_offset = 0x3c,
  773. .idle_offset = 0x40,
  774. .ack_offset = 0x40,
  775. .core_pwrcnt_offset = 0x48,
  776. .gpu_pwrcnt_offset = 0x50,
  777. .core_power_transition_time = 24,
  778. .gpu_power_transition_time = 24,
  779. .num_domains = ARRAY_SIZE(rk3368_pm_domains),
  780. .domain_info = rk3368_pm_domains,
  781. };
  782. static const struct rockchip_pmu_info rk3399_pmu = {
  783. .pwr_offset = 0x14,
  784. .status_offset = 0x18,
  785. .req_offset = 0x60,
  786. .idle_offset = 0x64,
  787. .ack_offset = 0x68,
  788. /* ARM Trusted Firmware manages power transition times */
  789. .num_domains = ARRAY_SIZE(rk3399_pm_domains),
  790. .domain_info = rk3399_pm_domains,
  791. };
  792. static const struct of_device_id rockchip_pm_domain_dt_match[] = {
  793. {
  794. .compatible = "rockchip,px30-power-controller",
  795. .data = (void *)&px30_pmu,
  796. },
  797. {
  798. .compatible = "rockchip,rk3036-power-controller",
  799. .data = (void *)&rk3036_pmu,
  800. },
  801. {
  802. .compatible = "rockchip,rk3128-power-controller",
  803. .data = (void *)&rk3128_pmu,
  804. },
  805. {
  806. .compatible = "rockchip,rk3228-power-controller",
  807. .data = (void *)&rk3228_pmu,
  808. },
  809. {
  810. .compatible = "rockchip,rk3288-power-controller",
  811. .data = (void *)&rk3288_pmu,
  812. },
  813. {
  814. .compatible = "rockchip,rk3328-power-controller",
  815. .data = (void *)&rk3328_pmu,
  816. },
  817. {
  818. .compatible = "rockchip,rk3366-power-controller",
  819. .data = (void *)&rk3366_pmu,
  820. },
  821. {
  822. .compatible = "rockchip,rk3368-power-controller",
  823. .data = (void *)&rk3368_pmu,
  824. },
  825. {
  826. .compatible = "rockchip,rk3399-power-controller",
  827. .data = (void *)&rk3399_pmu,
  828. },
  829. { /* sentinel */ },
  830. };
  831. static struct platform_driver rockchip_pm_domain_driver = {
  832. .probe = rockchip_pm_domain_probe,
  833. .driver = {
  834. .name = "rockchip-pm-domain",
  835. .of_match_table = rockchip_pm_domain_dt_match,
  836. /*
  837. * We can't forcibly eject devices form power domain,
  838. * so we can't really remove power domains once they
  839. * were added.
  840. */
  841. .suppress_bind_attrs = true,
  842. },
  843. };
  844. static int __init rockchip_pm_domain_drv_register(void)
  845. {
  846. return platform_driver_register(&rockchip_pm_domain_driver);
  847. }
  848. postcore_initcall(rockchip_pm_domain_drv_register);