ti-power-domain.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Texas Instruments power domain driver
  4. *
  5. * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
  6. * Tero Kristo <t-kristo@ti.com>
  7. */
  8. #include <asm/io.h>
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <errno.h>
  12. #include <power-domain-uclass.h>
  13. #include <soc.h>
  14. #include <k3-dev.h>
  15. #include <linux/iopoll.h>
  16. #define PSC_PTCMD 0x120
  17. #define PSC_PTSTAT 0x128
  18. #define PSC_PDSTAT 0x200
  19. #define PSC_PDCTL 0x300
  20. #define PSC_MDSTAT 0x800
  21. #define PSC_MDCTL 0xa00
  22. #define PDCTL_STATE_MASK 0x1
  23. #define PDCTL_STATE_OFF 0x0
  24. #define PDCTL_STATE_ON 0x1
  25. #define MDSTAT_STATE_MASK 0x3f
  26. #define MDSTAT_BUSY_MASK 0x30
  27. #define MDSTAT_STATE_SWRSTDISABLE 0x0
  28. #define MDSTAT_STATE_ENABLE 0x3
  29. #define LPSC_TIMEOUT 1000
  30. #define PD_TIMEOUT 1000
  31. static u32 psc_read(struct ti_psc *psc, u32 reg)
  32. {
  33. u32 val;
  34. val = readl(psc->base + reg);
  35. debug("%s: 0x%x from %p\n", __func__, val, psc->base + reg);
  36. return val;
  37. }
  38. static void psc_write(u32 val, struct ti_psc *psc, u32 reg)
  39. {
  40. debug("%s: 0x%x to %p\n", __func__, val, psc->base + reg);
  41. writel(val, psc->base + reg);
  42. }
  43. static u32 pd_read(struct ti_pd *pd, u32 reg)
  44. {
  45. return psc_read(pd->psc, reg + 4 * pd->id);
  46. }
  47. static void pd_write(u32 val, struct ti_pd *pd, u32 reg)
  48. {
  49. psc_write(val, pd->psc, reg + 4 * pd->id);
  50. }
  51. static u32 lpsc_read(struct ti_lpsc *lpsc, u32 reg)
  52. {
  53. return psc_read(lpsc->psc, reg + 4 * lpsc->id);
  54. }
  55. static void lpsc_write(u32 val, struct ti_lpsc *lpsc, u32 reg)
  56. {
  57. psc_write(val, lpsc->psc, reg + 4 * lpsc->id);
  58. }
  59. static const struct soc_attr ti_k3_soc_pd_data[] = {
  60. #if IS_ENABLED(CONFIG_SOC_K3_J721E)
  61. {
  62. .family = "J721E",
  63. .data = &j721e_pd_platdata,
  64. },
  65. {
  66. .family = "J7200",
  67. .data = &j7200_pd_platdata,
  68. },
  69. #endif
  70. { /* sentinel */ }
  71. };
  72. static int ti_power_domain_probe(struct udevice *dev)
  73. {
  74. struct ti_k3_pd_platdata *data = dev_get_priv(dev);
  75. const struct soc_attr *soc_match_data;
  76. const struct ti_k3_pd_platdata *pdata;
  77. printf("%s(dev=%p)\n", __func__, dev);
  78. if (!data)
  79. return -ENOMEM;
  80. soc_match_data = soc_device_match(ti_k3_soc_pd_data);
  81. if (!soc_match_data)
  82. return -ENODEV;
  83. pdata = (const struct ti_k3_pd_platdata *)soc_match_data->data;
  84. data->psc = pdata->psc;
  85. data->pd = pdata->pd;
  86. data->lpsc = pdata->lpsc;
  87. data->devs = pdata->devs;
  88. data->num_psc = pdata->num_psc;
  89. data->num_pd = pdata->num_pd;
  90. data->num_lpsc = pdata->num_lpsc;
  91. data->num_devs = pdata->num_devs;
  92. return 0;
  93. }
  94. static int ti_pd_wait(struct ti_pd *pd)
  95. {
  96. u32 ptstat;
  97. int ret;
  98. ret = readl_poll_timeout(pd->psc->base + PSC_PTSTAT, ptstat,
  99. !(ptstat & BIT(pd->id)), PD_TIMEOUT);
  100. if (ret)
  101. printf("%s: psc%d, pd%d failed to transition.\n", __func__,
  102. pd->psc->id, pd->id);
  103. return ret;
  104. }
  105. static void ti_pd_transition(struct ti_pd *pd)
  106. {
  107. psc_write(BIT(pd->id), pd->psc, PSC_PTCMD);
  108. }
  109. u8 ti_pd_state(struct ti_pd *pd)
  110. {
  111. return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
  112. }
  113. static int ti_pd_get(struct ti_pd *pd)
  114. {
  115. u32 pdctl;
  116. int ret;
  117. pd->usecount++;
  118. if (pd->usecount > 1)
  119. return 0;
  120. if (pd->depend) {
  121. ret = ti_pd_get(pd->depend);
  122. if (ret)
  123. return ret;
  124. ti_pd_transition(pd->depend);
  125. ret = ti_pd_wait(pd->depend);
  126. if (ret)
  127. return ret;
  128. }
  129. pdctl = pd_read(pd, PSC_PDCTL);
  130. if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_ON)
  131. return 0;
  132. debug("%s: enabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
  133. pdctl &= ~PDCTL_STATE_MASK;
  134. pdctl |= PDCTL_STATE_ON;
  135. pd_write(pdctl, pd, PSC_PDCTL);
  136. return 0;
  137. }
  138. static int ti_pd_put(struct ti_pd *pd)
  139. {
  140. u32 pdctl;
  141. int ret;
  142. pd->usecount--;
  143. if (pd->usecount > 0)
  144. return 0;
  145. pdctl = pd_read(pd, PSC_PDCTL);
  146. if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_OFF)
  147. return 0;
  148. pdctl &= ~PDCTL_STATE_MASK;
  149. pdctl |= PDCTL_STATE_OFF;
  150. debug("%s: disabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
  151. pd_write(pdctl, pd, PSC_PDCTL);
  152. if (pd->depend) {
  153. ti_pd_transition(pd);
  154. ret = ti_pd_wait(pd);
  155. if (ret)
  156. return ret;
  157. ret = ti_pd_put(pd->depend);
  158. if (ret)
  159. return ret;
  160. ti_pd_transition(pd->depend);
  161. ret = ti_pd_wait(pd->depend);
  162. if (ret)
  163. return ret;
  164. }
  165. return 0;
  166. }
  167. static int ti_lpsc_wait(struct ti_lpsc *lpsc)
  168. {
  169. u32 mdstat;
  170. int ret;
  171. ret = readl_poll_timeout(lpsc->psc->base + PSC_MDSTAT + lpsc->id * 4,
  172. mdstat,
  173. !(mdstat & MDSTAT_BUSY_MASK), LPSC_TIMEOUT);
  174. if (ret)
  175. printf("%s: module %d failed to transition.\n", __func__,
  176. lpsc->id);
  177. return ret;
  178. }
  179. u8 lpsc_get_state(struct ti_lpsc *lpsc)
  180. {
  181. return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
  182. }
  183. int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
  184. {
  185. struct ti_pd *psc_pd;
  186. int ret;
  187. u32 mdctl;
  188. psc_pd = lpsc->pd;
  189. if (state == MDSTAT_STATE_ENABLE) {
  190. lpsc->usecount++;
  191. if (lpsc->usecount > 1)
  192. return 0;
  193. } else {
  194. lpsc->usecount--;
  195. if (lpsc->usecount >= 1)
  196. return 0;
  197. }
  198. debug("%s: transitioning psc:%d, lpsc:%d to %x\n", __func__,
  199. lpsc->psc->id, lpsc->id, state);
  200. if (lpsc->depend)
  201. ti_lpsc_transition(lpsc->depend, state);
  202. mdctl = lpsc_read(lpsc, PSC_MDCTL);
  203. if ((mdctl & MDSTAT_STATE_MASK) == state)
  204. return 0;
  205. if (state == MDSTAT_STATE_ENABLE)
  206. ti_pd_get(psc_pd);
  207. else
  208. ti_pd_put(psc_pd);
  209. mdctl &= ~MDSTAT_STATE_MASK;
  210. mdctl |= state;
  211. lpsc_write(mdctl, lpsc, PSC_MDCTL);
  212. ti_pd_transition(psc_pd);
  213. ret = ti_pd_wait(psc_pd);
  214. if (ret)
  215. return ret;
  216. return ti_lpsc_wait(lpsc);
  217. }
  218. static int ti_power_domain_transition(struct power_domain *pd, u8 state)
  219. {
  220. struct ti_lpsc *lpsc = pd->priv;
  221. return ti_lpsc_transition(lpsc, state);
  222. }
  223. static int ti_power_domain_on(struct power_domain *pd)
  224. {
  225. debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
  226. return ti_power_domain_transition(pd, MDSTAT_STATE_ENABLE);
  227. }
  228. static int ti_power_domain_off(struct power_domain *pd)
  229. {
  230. debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
  231. return ti_power_domain_transition(pd, MDSTAT_STATE_SWRSTDISABLE);
  232. }
  233. static struct ti_lpsc *lpsc_lookup(struct ti_k3_pd_platdata *data, int id)
  234. {
  235. int idx;
  236. for (idx = 0; idx < data->num_devs; idx++)
  237. if (data->devs[idx].id == id)
  238. return data->devs[idx].lpsc;
  239. return NULL;
  240. }
  241. static int ti_power_domain_of_xlate(struct power_domain *pd,
  242. struct ofnode_phandle_args *args)
  243. {
  244. struct ti_k3_pd_platdata *data = dev_get_priv(pd->dev);
  245. struct ti_lpsc *lpsc;
  246. debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
  247. if (args->args_count < 1) {
  248. printf("Invalid args_count: %d\n", args->args_count);
  249. return -EINVAL;
  250. }
  251. lpsc = lpsc_lookup(data, args->args[0]);
  252. if (!lpsc) {
  253. printf("%s: invalid dev-id: %d\n", __func__, args->args[0]);
  254. return -ENOENT;
  255. }
  256. pd->id = lpsc->id;
  257. pd->priv = lpsc;
  258. return 0;
  259. }
  260. static int ti_power_domain_request(struct power_domain *pd)
  261. {
  262. return 0;
  263. }
  264. static int ti_power_domain_free(struct power_domain *pd)
  265. {
  266. return 0;
  267. }
  268. static const struct udevice_id ti_power_domain_of_match[] = {
  269. { .compatible = "ti,sci-pm-domain" },
  270. { /* sentinel */ }
  271. };
  272. static struct power_domain_ops ti_power_domain_ops = {
  273. .on = ti_power_domain_on,
  274. .off = ti_power_domain_off,
  275. .of_xlate = ti_power_domain_of_xlate,
  276. .request = ti_power_domain_request,
  277. .rfree = ti_power_domain_free,
  278. };
  279. U_BOOT_DRIVER(ti_pm_domains) = {
  280. .name = "ti-pm-domains",
  281. .id = UCLASS_POWER_DOMAIN,
  282. .of_match = ti_power_domain_of_match,
  283. .probe = ti_power_domain_probe,
  284. .priv_auto = sizeof(struct ti_k3_pd_platdata),
  285. .ops = &ti_power_domain_ops,
  286. };