drv_pm.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-06-12 CDT first version
  9. * 2024-06-14 CDT Move common function SysTick_Configuration to _pm_run
  10. */
  11. #include <board.h>
  12. #include <drv_pm.h>
  13. #include <drv_common.h>
  14. #include <drv_wktm.h>
  15. #include <drv_config.h>
  16. #if defined(RT_USING_PM)
  17. #if defined(BSP_USING_PM)
  18. #define LOG_TAG "drv_pm"
  19. #include <drv_log.h>
  20. #define IS_PWC_UNLOCKED() ((CM_PWC->FPRC & PWC_FPRC_FPRCB1) == PWC_FPRC_FPRCB1)
  21. typedef void (* run_switch_func_type)(void);
  22. typedef void (* sleep_enter_func_type)(void);
  23. static void _sleep_enter_idle(void);
  24. static void _sleep_enter_deep(void);
  25. static void _sleep_enter_standby(void);
  26. static void _sleep_enter_shutdown(void);
  27. static void _run_switch_high_to_low(void);
  28. static void _run_switch_low_to_high(void);
  29. static run_switch_func_type _run_switch_func[PM_RUN_MODE_MAX][PM_RUN_MODE_MAX] =
  30. {
  31. {RT_NULL, RT_NULL, RT_NULL, _run_switch_high_to_low},
  32. {RT_NULL, RT_NULL, RT_NULL, _run_switch_high_to_low},
  33. {RT_NULL, RT_NULL, RT_NULL, RT_NULL},
  34. {_run_switch_low_to_high, _run_switch_low_to_high, RT_NULL, RT_NULL},
  35. };
  36. static sleep_enter_func_type _sleep_enter_func[PM_SLEEP_MODE_MAX] =
  37. {
  38. RT_NULL,
  39. _sleep_enter_idle,
  40. RT_NULL,
  41. _sleep_enter_deep,
  42. _sleep_enter_standby,
  43. _sleep_enter_shutdown,
  44. };
  45. static void _uart_console_reconfig(void)
  46. {
  47. struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
  48. rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
  49. }
  50. static void _sleep_enter_idle(void)
  51. {
  52. struct pm_sleep_mode_idle_config sleep_idle_cfg = PM_SLEEP_IDLE_CFG;
  53. PWC_SLEEP_Enter(sleep_idle_cfg.pwc_sleep_type);
  54. }
  55. static void _sleep_enter_deep(void)
  56. {
  57. struct pm_sleep_mode_deep_config sleep_deep_cfg = PM_SLEEP_DEEP_CFG;
  58. RT_ASSERT(PM_SLEEP_CHECK(PM_SLEEP_MODE_DEEP));
  59. (void)PWC_STOP_Config(&sleep_deep_cfg.cfg);
  60. #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448) || defined(HC32F4A8)
  61. if (PWC_PWRC2_DVS == (READ_REG8(CM_PWC->PWRC2) & PWC_PWRC2_DVS))
  62. {
  63. CLR_REG8_BIT(CM_PWC->PWRC1, PWC_PWRC1_STPDAS);
  64. }
  65. else
  66. {
  67. SET_REG8_BIT(CM_PWC->PWRC1, PWC_PWRC1_STPDAS);
  68. }
  69. #endif
  70. PWC_STOP_Enter(sleep_deep_cfg.pwc_stop_type);
  71. }
  72. static void _sleep_enter_standby(void)
  73. {
  74. struct pm_sleep_mode_standby_config sleep_standby_cfg = PM_SLEEP_STANDBY_CFG;
  75. RT_ASSERT(PM_SLEEP_CHECK(PM_SLEEP_MODE_SHUTDOWN));
  76. RT_ASSERT(sleep_standby_cfg.cfg.u8Mode == PWC_PD_MD1 || sleep_standby_cfg.cfg.u8Mode == PWC_PD_MD2);
  77. (void)PWC_PD_Config(&sleep_standby_cfg.cfg);
  78. PWC_PD_ClearWakeupStatus(PWC_PD_WKUP_FLAG_ALL);
  79. __set_FAULTMASK(1);
  80. PWC_PD_Enter();
  81. }
  82. static void _sleep_enter_shutdown(void)
  83. {
  84. struct pm_sleep_mode_shutdown_config sleep_shutdown_cfg = PM_SLEEP_SHUTDOWN_CFG;
  85. RT_ASSERT(PM_SLEEP_CHECK(PM_SLEEP_MODE_SHUTDOWN));
  86. RT_ASSERT(sleep_shutdown_cfg.cfg.u8Mode == PWC_PD_MD3 || sleep_shutdown_cfg.cfg.u8Mode == PWC_PD_MD4);
  87. (void)PWC_PD_Config(&sleep_shutdown_cfg.cfg);
  88. PWC_PD_ClearWakeupStatus(PWC_PD_WKUP_FLAG_ALL);
  89. __set_FAULTMASK(1);
  90. PWC_PD_Enter();
  91. }
  92. /**
  93. * @param pm pointer to power manage structure
  94. */
  95. static void _pm_sleep(struct rt_pm *pm, uint8_t mode)
  96. {
  97. RT_ASSERT(mode < PM_SLEEP_MODE_MAX);
  98. if (_sleep_enter_func[mode] != NULL)
  99. {
  100. _sleep_enter_func[mode]();
  101. }
  102. }
  103. static void _run_switch_high_to_low(void)
  104. {
  105. struct pm_run_mode_config st_run_mode_cfg = PM_RUN_MODE_CFG;
  106. st_run_mode_cfg.sys_clk_cfg(PM_RUN_MODE_LOW_SPEED);
  107. #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448) || defined(HC32F4A8)
  108. PWC_HighSpeedToLowSpeed();
  109. #endif
  110. }
  111. static void _run_switch_low_to_high(void)
  112. {
  113. struct pm_run_mode_config st_run_mode_cfg = PM_RUN_MODE_CFG;
  114. #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448) || defined(HC32F4A8)
  115. PWC_LowSpeedToHighSpeed();
  116. #endif
  117. st_run_mode_cfg.sys_clk_cfg(PM_RUN_MODE_HIGH_SPEED);
  118. }
  119. static void _pm_run(struct rt_pm *pm, uint8_t mode)
  120. {
  121. static uint8_t last_mode = PM_RUN_MODE_NORMAL_SPEED;
  122. if (mode == last_mode)
  123. return;
  124. if (_run_switch_func[last_mode][mode] != RT_NULL)
  125. {
  126. _run_switch_func[last_mode][mode]();
  127. SysTick_Configuration();
  128. }
  129. _uart_console_reconfig();
  130. last_mode = mode;
  131. }
  132. /**
  133. * This function calculate the PM tick from OS tick
  134. *
  135. * @param tick OS tick
  136. *
  137. * @return the PM tick
  138. */
  139. static rt_tick_t _pm_wakeup_timer_tick_from_os_tick(rt_tick_t tick)
  140. {
  141. rt_uint32_t freq = hc32_wktm_get_countfreq();
  142. return (freq * tick / RT_TICK_PER_SECOND);
  143. }
  144. /**
  145. * This function start the timer of pm
  146. *
  147. * @param pm Pointer to power manage structure
  148. * @param timeout How many OS Ticks that MCU can sleep
  149. */
  150. static void _pm_wakeup_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
  151. {
  152. RT_ASSERT(pm != RT_NULL);
  153. /* Convert OS Tick to pmtimer timeout value */
  154. timeout = _pm_wakeup_timer_tick_from_os_tick(timeout);
  155. /* Enter __WAKEUP_TIMER_MODE */
  156. hc32_wktm_start(timeout);
  157. }
  158. /**
  159. * This function stop the timer of pm
  160. *
  161. * @param pm Pointer to power manage structure
  162. */
  163. static void _pm_wakeup_timer_stop(struct rt_pm *pm)
  164. {
  165. RT_ASSERT(pm != RT_NULL);
  166. /* Reset pmtimer status */
  167. hc32_wktm_stop();
  168. }
  169. static rt_tick_t _timer_get_tick(struct rt_pm *pm)
  170. {
  171. RT_ASSERT(pm != RT_NULL);
  172. /* Get timeout tick */
  173. return hc32_wktm_get_timeout_tick();
  174. }
  175. /**
  176. * This function initialize the power manager
  177. * @note timer feature: only work as wake up timer
  178. */
  179. int rt_hw_pm_init(void)
  180. {
  181. static const struct rt_pm_ops _ops =
  182. {
  183. _pm_sleep,
  184. _pm_run,
  185. _pm_wakeup_timer_start,
  186. _pm_wakeup_timer_stop,
  187. _timer_get_tick,
  188. };
  189. rt_uint8_t timer_mask = PM_TICKLESS_TIMER_ENABLE_MASK;
  190. /* initialize system pm module */
  191. rt_system_pm_init(&_ops, timer_mask, RT_NULL);
  192. return 0;
  193. }
  194. INIT_DEVICE_EXPORT(rt_hw_pm_init);
  195. #endif
  196. #endif /* RT_USING_PM */