hisi_pwrc.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*
  2. * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <platform_def.h>
  8. #include <arch_helpers.h>
  9. #include <lib/mmio.h>
  10. #include <plat/common/platform.h>
  11. #include <../hikey960_def.h>
  12. #include <hisi_ipc.h>
  13. #include "hisi_pwrc.h"
  14. /* resource lock api */
  15. #define RES0_LOCK_BASE (SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE))
  16. #define RES1_LOCK_BASE (SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE))
  17. #define RES2_LOCK_BASE (SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE))
  18. #define LOCK_BIT (0x1 << 28)
  19. #define LOCK_ID_MASK (0x7u << 29)
  20. #define CPUIDLE_LOCK_ID(core) (0x6 - (core))
  21. #define LOCK_UNLOCK_OFFSET 0x4
  22. #define LOCK_STAT_OFFSET 0x8
  23. #define CLUSTER0_CPUS_ONLINE_MASK (0xF << 16)
  24. #define CLUSTER1_CPUS_ONLINE_MASK (0xF << 20)
  25. /* cpu hotplug flag api */
  26. #define SCTRL_BASE (SOC_ACPU_SCTRL_BASE_ADDR)
  27. #define REG_SCBAKDATA3_OFFSET (SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE))
  28. #define REG_SCBAKDATA8_OFFSET (SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE))
  29. #define REG_SCBAKDATA9_OFFSET (SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE))
  30. #define CPUIDLE_FLAG_REG(cluster) \
  31. ((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \
  32. REG_SCBAKDATA9_OFFSET)
  33. #define CLUSTER_IDLE_BIT BIT(8)
  34. #define CLUSTER_IDLE_MASK (CLUSTER_IDLE_BIT | 0x0F)
  35. #define AP_SUSPEND_FLAG (1 << 16)
  36. #define CLUSTER_PWDN_IDLE (0<<28)
  37. #define CLUSTER_PWDN_HOTPLUG (1<<28)
  38. #define CLUSTER_PWDN_SR (2<<28)
  39. #define CLUSTER0_PDC_OFFSET 0x260
  40. #define CLUSTER1_PDC_OFFSET 0x300
  41. #define PDC_EN_OFFSET 0x0
  42. #define PDC_COREPWRINTEN_OFFSET 0x4
  43. #define PDC_COREPWRINTSTAT_OFFSET 0x8
  44. #define PDC_COREGICMASK_OFFSET 0xc
  45. #define PDC_COREPOWERUP_OFFSET 0x10
  46. #define PDC_COREPOWERDN_OFFSET 0x14
  47. #define PDC_COREPOWERSTAT_OFFSET 0x18
  48. #define PDC_COREPWRSTAT_MASK (0XFFFF)
  49. enum pdc_gic_mask {
  50. PDC_MASK_GIC_WAKE_IRQ,
  51. PDC_UNMASK_GIC_WAKE_IRQ
  52. };
  53. enum pdc_finish_int_mask {
  54. PDC_DISABLE_FINISH_INT,
  55. PDC_ENABLE_FINISH_INT
  56. };
  57. static void hisi_resource_lock(unsigned int lockid, unsigned int offset)
  58. {
  59. unsigned int lock_id = (lockid << 29);
  60. unsigned int lock_val = lock_id | LOCK_BIT;
  61. unsigned int lock_state;
  62. do {
  63. mmio_write_32(offset, lock_val);
  64. lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset);
  65. } while ((lock_state & LOCK_ID_MASK) != lock_id);
  66. }
  67. static void hisi_resource_unlock(unsigned int lockid, unsigned int offset)
  68. {
  69. unsigned int lock_val = (lockid << 29) | LOCK_BIT;
  70. mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val);
  71. }
  72. static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core)
  73. {
  74. unsigned int lock_id;
  75. lock_id = (cluster << 2) + core;
  76. hisi_resource_lock(lock_id, RES2_LOCK_BASE);
  77. }
  78. static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core)
  79. {
  80. unsigned int lock_id;
  81. lock_id = (cluster << 2) + core;
  82. hisi_resource_unlock(lock_id, RES2_LOCK_BASE);
  83. }
  84. /* get the resource lock */
  85. void hisi_cpuidle_lock(unsigned int cluster, unsigned int core)
  86. {
  87. unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
  88. hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset);
  89. }
  90. /* release the resource lock */
  91. void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core)
  92. {
  93. unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
  94. hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset);
  95. }
  96. unsigned int hisi_get_cpuidle_flag(unsigned int cluster)
  97. {
  98. unsigned int val;
  99. val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
  100. val &= 0xF;
  101. return val;
  102. }
  103. void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
  104. {
  105. mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
  106. }
  107. void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
  108. {
  109. mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
  110. }
  111. int hisi_test_ap_suspend_flag(void)
  112. {
  113. unsigned int val1;
  114. unsigned int val2;
  115. val1 = mmio_read_32(CPUIDLE_FLAG_REG(0));
  116. val1 &= AP_SUSPEND_FLAG;
  117. val2 = mmio_read_32(CPUIDLE_FLAG_REG(1));
  118. val2 &= AP_SUSPEND_FLAG;
  119. val1 |= val2;
  120. return (val1 != 0);
  121. }
  122. void hisi_set_cluster_pwdn_flag(unsigned int cluster,
  123. unsigned int core, unsigned int value)
  124. {
  125. unsigned int val;
  126. hisi_cpuhotplug_lock(cluster, core);
  127. val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
  128. val &= ~(0x3U << ((2 * cluster) + 28));
  129. val |= (value << (2 * cluster));
  130. mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
  131. hisi_cpuhotplug_unlock(cluster, core);
  132. }
  133. unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
  134. {
  135. unsigned int val;
  136. hisi_cpuhotplug_lock(cluster, core);
  137. val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
  138. val = val >> (16 + (cluster << 2));
  139. val &= 0xF;
  140. hisi_cpuhotplug_unlock(cluster, core);
  141. return val;
  142. }
  143. unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
  144. {
  145. unsigned int val;
  146. hisi_cpuhotplug_lock(cluster, core);
  147. val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
  148. val = val >> (16 + (cluster << 2));
  149. val &= 0xF;
  150. hisi_cpuhotplug_unlock(cluster, core);
  151. if (val)
  152. return 0;
  153. else
  154. return 1;
  155. }
  156. void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
  157. {
  158. unsigned int flag = BIT((cluster<<2) + core + 16);
  159. hisi_cpuhotplug_lock(cluster, core);
  160. mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
  161. hisi_cpuhotplug_unlock(cluster, core);
  162. }
  163. void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
  164. {
  165. unsigned int flag = BIT((cluster<<2) + core + 16);
  166. hisi_cpuhotplug_lock(cluster, core);
  167. mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
  168. hisi_cpuhotplug_unlock(cluster, core);
  169. }
  170. int cluster_is_powered_on(unsigned int cluster)
  171. {
  172. unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
  173. int ret;
  174. if (cluster == 0)
  175. ret = val & CLUSTER0_CPUS_ONLINE_MASK;
  176. else
  177. ret = val & CLUSTER1_CPUS_ONLINE_MASK;
  178. return !!ret;
  179. }
  180. static void *hisi_get_pdc_addr(unsigned int cluster)
  181. {
  182. void *pdc_base_addr;
  183. uintptr_t addr;
  184. if (cluster == 0)
  185. addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
  186. else
  187. addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
  188. pdc_base_addr = (void *)addr;
  189. return pdc_base_addr;
  190. }
  191. static unsigned int hisi_get_pdc_stat(unsigned int cluster)
  192. {
  193. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  194. unsigned int val;
  195. val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
  196. return val;
  197. }
  198. static int check_hotplug(unsigned int cluster, unsigned int boot_flag)
  199. {
  200. unsigned int mask = 0xF;
  201. if (hisi_test_ap_suspend_flag() ||
  202. ((boot_flag & mask) == mask))
  203. return 0;
  204. return 1;
  205. }
  206. int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
  207. {
  208. unsigned int mask = 0xf << (core * 4);
  209. unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
  210. unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
  211. unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
  212. mask = (PDC_COREPWRSTAT_MASK & (~mask));
  213. pdc_stat &= mask;
  214. if ((boot_flag ^ cpuidle_flag) || pdc_stat ||
  215. check_hotplug(cluster, boot_flag))
  216. return 0;
  217. else
  218. return 1;
  219. }
  220. void hisi_disable_pdc(unsigned int cluster)
  221. {
  222. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  223. mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
  224. }
  225. void hisi_enable_pdc(unsigned int cluster)
  226. {
  227. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  228. mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
  229. }
  230. void hisi_pdc_set_intmask(void *pdc_base_addr,
  231. unsigned int core,
  232. enum pdc_finish_int_mask intmask)
  233. {
  234. unsigned int val;
  235. val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
  236. if (intmask == PDC_ENABLE_FINISH_INT)
  237. val |= BIT(core);
  238. else
  239. val &= ~BIT(core);
  240. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
  241. }
  242. static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
  243. unsigned int core,
  244. enum pdc_gic_mask gicmask)
  245. {
  246. unsigned int val;
  247. val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
  248. if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
  249. val |= BIT(core);
  250. else
  251. val &= ~BIT(core);
  252. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
  253. }
  254. void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
  255. {
  256. int i;
  257. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  258. for (i = 0; i < 4; i++)
  259. hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
  260. }
  261. static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
  262. enum pdc_gic_mask gicmask,
  263. enum pdc_finish_int_mask intmask)
  264. {
  265. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  266. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
  267. BIT(core));
  268. }
  269. static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
  270. enum pdc_gic_mask gicmask,
  271. enum pdc_finish_int_mask intmask)
  272. {
  273. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  274. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
  275. BIT(core));
  276. }
  277. void hisi_powerup_core(unsigned int cluster, unsigned int core)
  278. {
  279. hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
  280. PDC_DISABLE_FINISH_INT);
  281. }
  282. void hisi_powerdn_core(unsigned int cluster, unsigned int core)
  283. {
  284. hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
  285. PDC_DISABLE_FINISH_INT);
  286. }
  287. void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
  288. {
  289. hisi_ipc_pm_on_off(core, cluster, PM_ON);
  290. }
  291. void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
  292. {
  293. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  294. hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
  295. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
  296. (0x10001 << core));
  297. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
  298. BIT(core));
  299. }
  300. void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
  301. {
  302. hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
  303. PDC_DISABLE_FINISH_INT);
  304. }
  305. void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
  306. {
  307. void *pdc_base_addr = hisi_get_pdc_addr(cluster);
  308. hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
  309. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
  310. (0x10001 << core));
  311. mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
  312. BIT(core));
  313. }
  314. void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
  315. {
  316. hisi_ipc_pm_suspend(core, cluster, 0x3);
  317. }