scmi_pd.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Copyright 2021-2024 NXP
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <inttypes.h>
  7. #include <lib/libc/errno.h>
  8. #include <stdint.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <common/debug.h>
  12. #include <drivers/scmi.h>
  13. #include <lib/mmio.h>
  14. #include <lib/utils_def.h>
  15. #include <platform_def.h>
  16. #include <scmi.h>
  17. #include <upower_api.h>
  18. #define POWER_STATE_ON (0 << 30)
  19. #define POWER_STATE_OFF (1 << 30)
  20. extern bool is_lpav_owned_by_apd(void);
  21. enum {
  22. PS0 = 0,
  23. PS1 = 1,
  24. PS2 = 2,
  25. PS3 = 3,
  26. PS4 = 4,
  27. PS5 = 5,
  28. PS6 = 6,
  29. PS7 = 7,
  30. PS8 = 8,
  31. PS9 = 9,
  32. PS10 = 10,
  33. PS11 = 11,
  34. PS12 = 12,
  35. PS13 = 13,
  36. PS14 = 14,
  37. PS15 = 15,
  38. PS16 = 16,
  39. PS17 = 17,
  40. PS18 = 18,
  41. PS19 = 19,
  42. };
  43. #define SRAM_DMA1 BIT(6)
  44. #define SRAM_FLEXSPI2 BIT(7)
  45. #define SRAM_USB0 BIT(10)
  46. #define SRAM_USDHC0 BIT(11)
  47. #define SRAM_USDHC1 BIT(12)
  48. #define SRAM_USDHC2_USB1 BIT(13)
  49. #define SRAM_DCNANO GENMASK_32(18, 17)
  50. #define SRAM_EPDC GENMASK_32(20, 19)
  51. #define SRAM_DMA2 BIT(21)
  52. #define SRAM_GPU2D GENMASK_32(23, 22)
  53. #define SRAM_GPU3D GENMASK_32(25, 24)
  54. #define SRAM_HIFI4 BIT(26)
  55. #define SRAM_ISI_BUFFER BIT(27)
  56. #define SRAM_MIPI_CSI_FIFO BIT(28)
  57. #define SRAM_MIPI_DSI_FIFO BIT(29)
  58. #define SRAM_PXP BIT(30)
  59. #define SRAM_DMA0 BIT_64(33)
  60. #define SRAM_FLEXCAN BIT_64(34)
  61. #define SRAM_FLEXSPI0 BIT_64(35)
  62. #define SRAM_FLEXSPI1 BIT_64(36)
  63. struct psw {
  64. char *name;
  65. uint32_t reg;
  66. int power_state;
  67. uint32_t count;
  68. int flags;
  69. };
  70. #define ALWAYS_ON BIT(0)
  71. static struct psw imx8ulp_psw[] = {
  72. [PS6] = { .name = "PS6", .reg = PS6, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
  73. [PS7] = { .name = "PS7", .reg = PS7, .power_state = POWER_STATE_OFF },
  74. [PS8] = { .name = "PS8", .reg = PS8, .power_state = POWER_STATE_OFF },
  75. [PS13] = { .name = "PS13", .reg = PS13, .power_state = POWER_STATE_OFF },
  76. [PS14] = { .name = "PS14", .reg = PS14, .flags = ALWAYS_ON, .power_state = POWER_STATE_OFF },
  77. [PS15] = { .name = "PS15", .reg = PS15, .power_state = POWER_STATE_OFF },
  78. [PS16] = { .name = "PS16", .reg = PS16, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
  79. };
  80. struct power_domain {
  81. char *name;
  82. uint32_t reg;
  83. uint32_t psw_parent;
  84. uint32_t sram_parent;
  85. uint64_t bits;
  86. uint32_t power_state;
  87. bool lpav; /* belong to lpav domain */
  88. uint32_t sw_rst_reg; /* pcc sw reset reg offset */
  89. };
  90. /* The Rich OS need flow the macro */
  91. #define IMX8ULP_PD_DMA1 0
  92. #define IMX8ULP_PD_FLEXSPI2 1
  93. #define IMX8ULP_PD_USB0 2
  94. #define IMX8ULP_PD_USDHC0 3
  95. #define IMX8ULP_PD_USDHC1 4
  96. #define IMX8ULP_PD_USDHC2_USB1 5
  97. #define IMX8ULP_PD_DCNANO 6
  98. #define IMX8ULP_PD_EPDC 7
  99. #define IMX8ULP_PD_DMA2 8
  100. #define IMX8ULP_PD_GPU2D 9
  101. #define IMX8ULP_PD_GPU3D 10
  102. #define IMX8ULP_PD_HIFI4 11
  103. #define IMX8ULP_PD_ISI 12
  104. #define IMX8ULP_PD_MIPI_CSI 13
  105. #define IMX8ULP_PD_MIPI_DSI 14
  106. #define IMX8ULP_PD_PXP 15
  107. #define IMX8ULP_PD_PS6 16
  108. #define IMX8ULP_PD_PS7 17
  109. #define IMX8ULP_PD_PS8 18
  110. #define IMX8ULP_PD_PS13 19
  111. #define IMX8ULP_PD_PS14 20
  112. #define IMX8ULP_PD_PS15 21
  113. #define IMX8ULP_PD_PS16 22
  114. #define IMX8ULP_PD_MAX 23
  115. /* LPAV peripheral PCC */
  116. #define PCC_GPU2D (IMX_PCC5_BASE + 0xf0)
  117. #define PCC_GPU3D (IMX_PCC5_BASE + 0xf4)
  118. #define PCC_EPDC (IMX_PCC5_BASE + 0xcc)
  119. #define PCC_CSI (IMX_PCC5_BASE + 0xbc)
  120. #define PCC_PXP (IMX_PCC5_BASE + 0xd0)
  121. #define PCC_SW_RST BIT(28)
  122. #define PWR_DOMAIN(_name, _reg, _psw_parent, _sram_parent, \
  123. _bits, _state, _lpav, _rst_reg) \
  124. { \
  125. .name = _name, \
  126. .reg = _reg, \
  127. .psw_parent = _psw_parent, \
  128. .sram_parent = _sram_parent, \
  129. .bits = _bits, \
  130. .power_state = _state, \
  131. .lpav = _lpav, \
  132. .sw_rst_reg = _rst_reg, \
  133. }
  134. static struct power_domain scmi_power_domains[] = {
  135. PWR_DOMAIN("DMA1", IMX8ULP_PD_DMA1, PS6, PS6, SRAM_DMA1, POWER_STATE_OFF, false, 0U),
  136. PWR_DOMAIN("FLEXSPI2", IMX8ULP_PD_FLEXSPI2, PS6, PS6, SRAM_FLEXSPI2, POWER_STATE_OFF, false, 0U),
  137. PWR_DOMAIN("USB0", IMX8ULP_PD_USB0, PS6, PS6, SRAM_USB0, POWER_STATE_OFF, false, 0U),
  138. PWR_DOMAIN("USDHC0", IMX8ULP_PD_USDHC0, PS6, PS6, SRAM_USDHC0, POWER_STATE_OFF, false, 0U),
  139. PWR_DOMAIN("USDHC1", IMX8ULP_PD_USDHC1, PS6, PS6, SRAM_USDHC1, POWER_STATE_OFF, false, 0U),
  140. PWR_DOMAIN("USDHC2_USB1", IMX8ULP_PD_USDHC2_USB1, PS6, PS6, SRAM_USDHC2_USB1, POWER_STATE_OFF, false, 0U),
  141. PWR_DOMAIN("DCNano", IMX8ULP_PD_DCNANO, PS16, PS16, SRAM_DCNANO, POWER_STATE_OFF, true, 0U),
  142. PWR_DOMAIN("EPDC", IMX8ULP_PD_EPDC, PS13, PS13, SRAM_EPDC, POWER_STATE_OFF, true, PCC_EPDC),
  143. PWR_DOMAIN("DMA2", IMX8ULP_PD_DMA2, PS16, PS16, SRAM_DMA2, POWER_STATE_OFF, true, 0U),
  144. PWR_DOMAIN("GPU2D", IMX8ULP_PD_GPU2D, PS16, PS16, SRAM_GPU2D, POWER_STATE_OFF, true, PCC_GPU2D),
  145. PWR_DOMAIN("GPU3D", IMX8ULP_PD_GPU3D, PS7, PS7, SRAM_GPU3D, POWER_STATE_OFF, true, PCC_GPU3D),
  146. PWR_DOMAIN("HIFI4", IMX8ULP_PD_HIFI4, PS8, PS8, SRAM_HIFI4, POWER_STATE_OFF, true, 0U),
  147. PWR_DOMAIN("ISI", IMX8ULP_PD_ISI, PS16, PS16, SRAM_ISI_BUFFER, POWER_STATE_OFF, true, 0U),
  148. PWR_DOMAIN("MIPI_CSI", IMX8ULP_PD_MIPI_CSI, PS15, PS16, SRAM_MIPI_CSI_FIFO, POWER_STATE_OFF, true, PCC_CSI),
  149. PWR_DOMAIN("MIPI_DSI", IMX8ULP_PD_MIPI_DSI, PS14, PS16, SRAM_MIPI_DSI_FIFO, POWER_STATE_OFF, true, 0U),
  150. PWR_DOMAIN("PXP", IMX8ULP_PD_PXP, PS13, PS13, SRAM_PXP | SRAM_EPDC, POWER_STATE_OFF, true, PCC_PXP)
  151. };
  152. size_t plat_scmi_pd_count(unsigned int agent_id __unused)
  153. {
  154. return ARRAY_SIZE(scmi_power_domains);
  155. }
  156. const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
  157. unsigned int pd_id)
  158. {
  159. if (pd_id >= IMX8ULP_PD_PS6) {
  160. return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].name;
  161. }
  162. return scmi_power_domains[pd_id].name;
  163. }
  164. unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
  165. unsigned int pd_id __unused)
  166. {
  167. if (pd_id >= IMX8ULP_PD_PS6) {
  168. return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].power_state;
  169. }
  170. return scmi_power_domains[pd_id].power_state;
  171. }
  172. extern void upower_wait_resp(void);
  173. int upwr_pwm_power(const uint32_t swton[], const uint32_t memon[], bool on)
  174. {
  175. int ret_val;
  176. int ret;
  177. if (on == true) {
  178. ret = upwr_pwm_power_on(swton, memon, NULL);
  179. } else {
  180. ret = upwr_pwm_power_off(swton, memon, NULL);
  181. }
  182. if (ret != 0U) {
  183. WARN("%s failed: ret: %d, state: %x\n", __func__, ret, on);
  184. return ret;
  185. }
  186. upower_wait_resp();
  187. ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000);
  188. if (ret != UPWR_REQ_OK) {
  189. WARN("Failure %d, %s\n", ret, __func__);
  190. if (ret == UPWR_REQ_BUSY) {
  191. return -EBUSY;
  192. } else {
  193. return -EINVAL;
  194. }
  195. }
  196. return 0;
  197. }
  198. int32_t plat_scmi_pd_psw(unsigned int index, unsigned int state)
  199. {
  200. uint32_t psw_parent = scmi_power_domains[index].psw_parent;
  201. uint32_t sram_parent = scmi_power_domains[index].sram_parent;
  202. uint64_t swt;
  203. bool on;
  204. int ret = 0;
  205. if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) != 0U &&
  206. (imx8ulp_psw[sram_parent].flags & ALWAYS_ON) != 0U) {
  207. return 0;
  208. }
  209. on = (state == POWER_STATE_ON) ? true : false;
  210. if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) == 0U) {
  211. swt = 1 << imx8ulp_psw[psw_parent].reg;
  212. if (imx8ulp_psw[psw_parent].count == 0U) {
  213. if (on == false) {
  214. WARN("off PSW[%d] that already in off state\n", psw_parent);
  215. ret = -EACCES;
  216. } else {
  217. ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
  218. imx8ulp_psw[psw_parent].count++;
  219. }
  220. } else {
  221. if (on == true) {
  222. imx8ulp_psw[psw_parent].count++;
  223. } else {
  224. imx8ulp_psw[psw_parent].count--;
  225. }
  226. if (imx8ulp_psw[psw_parent].count == 0U) {
  227. ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
  228. }
  229. }
  230. }
  231. if (!(imx8ulp_psw[sram_parent].flags & ALWAYS_ON) && (psw_parent != sram_parent)) {
  232. swt = 1 << imx8ulp_psw[sram_parent].reg;
  233. if (imx8ulp_psw[sram_parent].count == 0U) {
  234. if (on == false) {
  235. WARN("off PSW[%d] that already in off state\n", sram_parent);
  236. ret = -EACCES;
  237. } else {
  238. ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
  239. imx8ulp_psw[sram_parent].count++;
  240. }
  241. } else {
  242. if (on == true) {
  243. imx8ulp_psw[sram_parent].count++;
  244. } else {
  245. imx8ulp_psw[sram_parent].count--;
  246. }
  247. if (imx8ulp_psw[sram_parent].count == 0U) {
  248. ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
  249. }
  250. }
  251. }
  252. return ret;
  253. }
  254. bool pd_allow_power_off(unsigned int pd_id)
  255. {
  256. if (scmi_power_domains[pd_id].lpav) {
  257. if (!is_lpav_owned_by_apd()) {
  258. return false;
  259. }
  260. }
  261. return true;
  262. }
  263. void assert_pcc_reset(unsigned int pcc)
  264. {
  265. /* if sw_rst_reg is valid, assert the pcc reset */
  266. if (pcc != 0U) {
  267. mmio_clrbits_32(pcc, PCC_SW_RST);
  268. }
  269. }
  270. int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
  271. unsigned int flags,
  272. unsigned int pd_id,
  273. unsigned int state)
  274. {
  275. unsigned int ps_idx;
  276. uint64_t mem;
  277. bool on;
  278. int ret;
  279. if (flags != 0U || pd_id >= IMX8ULP_PD_PS6) {
  280. return SCMI_NOT_SUPPORTED;
  281. }
  282. ps_idx = 0;
  283. while (ps_idx < IMX8ULP_PD_PS6 && scmi_power_domains[ps_idx].reg != pd_id) {
  284. ps_idx++;
  285. }
  286. if (ps_idx == IMX8ULP_PD_PS6) {
  287. return SCMI_NOT_FOUND;
  288. }
  289. if (state == scmi_power_domains[ps_idx].power_state) {
  290. return SCMI_SUCCESS;
  291. }
  292. mem = scmi_power_domains[ps_idx].bits;
  293. on = (state == POWER_STATE_ON ? true : false);
  294. if (on == true) {
  295. /* Assert pcc sw reset if necessary */
  296. assert_pcc_reset(scmi_power_domains[ps_idx].sw_rst_reg);
  297. ret = plat_scmi_pd_psw(ps_idx, state);
  298. if (ret != 0U) {
  299. return SCMI_DENIED;
  300. }
  301. ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
  302. if (ret != 0U) {
  303. return SCMI_DENIED;
  304. }
  305. } else {
  306. if (!pd_allow_power_off(ps_idx)) {
  307. return SCMI_DENIED;
  308. }
  309. ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
  310. if (ret != 0U) {
  311. return SCMI_DENIED;
  312. }
  313. ret = plat_scmi_pd_psw(ps_idx, state);
  314. if (ret != 0U) {
  315. return SCMI_DENIED;
  316. }
  317. }
  318. scmi_power_domains[pd_id].power_state = state;
  319. return SCMI_SUCCESS;
  320. }