pm33xx-core.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * AM33XX Arch Power Management Routines
  4. *
  5. * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
  6. * Dave Gerlach
  7. */
  8. #include <asm/smp_scu.h>
  9. #include <asm/suspend.h>
  10. #include <linux/errno.h>
  11. #include <linux/platform_data/pm33xx.h>
  12. #include "cm33xx.h"
  13. #include "common.h"
  14. #include "control.h"
  15. #include "clockdomain.h"
  16. #include "iomap.h"
  17. #include "omap_hwmod.h"
  18. #include "pm.h"
  19. #include "powerdomain.h"
  20. #include "prm33xx.h"
  21. #include "soc.h"
  22. #include "sram.h"
  23. static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
  24. static struct clockdomain *gfx_l4ls_clkdm;
  25. static void __iomem *scu_base;
  26. static struct omap_hwmod *rtc_oh;
  27. static int __init am43xx_map_scu(void)
  28. {
  29. scu_base = ioremap(scu_a9_get_base(), SZ_256);
  30. if (!scu_base)
  31. return -ENOMEM;
  32. return 0;
  33. }
  34. static int amx3_common_init(void)
  35. {
  36. gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
  37. per_pwrdm = pwrdm_lookup("per_pwrdm");
  38. mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
  39. if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm))
  40. return -ENODEV;
  41. (void)clkdm_for_each(omap_pm_clkdms_setup, NULL);
  42. /* CEFUSE domain can be turned off post bootup */
  43. cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
  44. if (!cefuse_pwrdm)
  45. pr_err("PM: Failed to get cefuse_pwrdm\n");
  46. else if (omap_type() != OMAP2_DEVICE_TYPE_GP)
  47. pr_info("PM: Leaving EFUSE power domain active\n");
  48. else
  49. omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
  50. return 0;
  51. }
  52. static int am33xx_suspend_init(void)
  53. {
  54. int ret;
  55. gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
  56. if (!gfx_l4ls_clkdm) {
  57. pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n");
  58. return -ENODEV;
  59. }
  60. ret = amx3_common_init();
  61. return ret;
  62. }
  63. static int am43xx_suspend_init(void)
  64. {
  65. int ret = 0;
  66. ret = am43xx_map_scu();
  67. if (ret) {
  68. pr_err("PM: Could not ioremap SCU\n");
  69. return ret;
  70. }
  71. ret = amx3_common_init();
  72. return ret;
  73. }
  74. static void amx3_pre_suspend_common(void)
  75. {
  76. omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
  77. }
  78. static void amx3_post_suspend_common(void)
  79. {
  80. int status;
  81. /*
  82. * Because gfx_pwrdm is the only one under MPU control,
  83. * comment on transition status
  84. */
  85. status = pwrdm_read_pwrst(gfx_pwrdm);
  86. if (status != PWRDM_POWER_OFF)
  87. pr_err("PM: GFX domain did not transition: %x\n", status);
  88. }
  89. static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long),
  90. unsigned long args)
  91. {
  92. int ret = 0;
  93. amx3_pre_suspend_common();
  94. ret = cpu_suspend(args, fn);
  95. amx3_post_suspend_common();
  96. /*
  97. * BUG: GFX_L4LS clock domain needs to be woken up to
  98. * ensure thet L4LS clock domain does not get stuck in
  99. * transition. If that happens L3 module does not get
  100. * disabled, thereby leading to PER power domain
  101. * transition failing
  102. */
  103. clkdm_wakeup(gfx_l4ls_clkdm);
  104. clkdm_sleep(gfx_l4ls_clkdm);
  105. return ret;
  106. }
  107. static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
  108. unsigned long args)
  109. {
  110. int ret = 0;
  111. amx3_pre_suspend_common();
  112. scu_power_mode(scu_base, SCU_PM_POWEROFF);
  113. ret = cpu_suspend(args, fn);
  114. scu_power_mode(scu_base, SCU_PM_NORMAL);
  115. amx3_post_suspend_common();
  116. return ret;
  117. }
  118. static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
  119. {
  120. if (soc_is_am33xx())
  121. return &am33xx_pm_sram;
  122. else if (soc_is_am437x())
  123. return &am43xx_pm_sram;
  124. else
  125. return NULL;
  126. }
  127. void __iomem *am43xx_get_rtc_base_addr(void)
  128. {
  129. rtc_oh = omap_hwmod_lookup("rtc");
  130. return omap_hwmod_get_mpu_rt_va(rtc_oh);
  131. }
  132. static struct am33xx_pm_platform_data am33xx_ops = {
  133. .init = am33xx_suspend_init,
  134. .soc_suspend = am33xx_suspend,
  135. .get_sram_addrs = amx3_get_sram_addrs,
  136. .get_rtc_base_addr = am43xx_get_rtc_base_addr,
  137. };
  138. static struct am33xx_pm_platform_data am43xx_ops = {
  139. .init = am43xx_suspend_init,
  140. .soc_suspend = am43xx_suspend,
  141. .get_sram_addrs = amx3_get_sram_addrs,
  142. .get_rtc_base_addr = am43xx_get_rtc_base_addr,
  143. };
  144. static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void)
  145. {
  146. if (soc_is_am33xx())
  147. return &am33xx_ops;
  148. else if (soc_is_am437x())
  149. return &am43xx_ops;
  150. else
  151. return NULL;
  152. }
  153. int __init amx3_common_pm_init(void)
  154. {
  155. struct am33xx_pm_platform_data *pdata;
  156. struct platform_device_info devinfo;
  157. pdata = am33xx_pm_get_pdata();
  158. memset(&devinfo, 0, sizeof(devinfo));
  159. devinfo.name = "pm33xx";
  160. devinfo.data = pdata;
  161. devinfo.size_data = sizeof(*pdata);
  162. devinfo.id = -1;
  163. platform_device_register_full(&devinfo);
  164. return 0;
  165. }