pm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2012-06-02 Bernard the first version
  9. * 2018-08-02 Tanek split run and sleep modes, support custom mode
  10. * 2019-04-28 Zero-Free improve PM mode and device ops interface
  11. */
  12. #include <rthw.h>
  13. #include <rtthread.h>
  14. #include <drivers/pm.h>
  15. #ifdef RT_USING_PM
  16. static struct rt_pm _pm;
  17. static uint8_t _pm_default_sleep = RT_PM_DEFAULT_SLEEP_MODE;
  18. static struct rt_pm_notify _pm_notify;
  19. #define RT_PM_TICKLESS_THRESH (2)
  20. RT_WEAK uint32_t rt_pm_enter_critical(void)
  21. {
  22. return rt_hw_interrupt_disable();
  23. }
  24. RT_WEAK void rt_pm_exit_critical(uint32_t ctx)
  25. {
  26. rt_hw_interrupt_enable(ctx);
  27. }
  28. /**
  29. * This function will suspend all registered devices
  30. */
  31. static int _pm_device_suspend(uint8_t mode)
  32. {
  33. int index;
  34. for (index = 0; index < _pm.device_pm_number; index++)
  35. {
  36. if (_pm.device_pm[index].ops->suspend != RT_NULL)
  37. {
  38. return _pm.device_pm[index].ops->suspend(_pm.device_pm[index].device, mode);
  39. }
  40. }
  41. return RT_EOK;
  42. }
  43. /**
  44. * This function will resume all registered devices
  45. */
  46. static void _pm_device_resume(uint8_t mode)
  47. {
  48. int index;
  49. for (index = 0; index < _pm.device_pm_number; index++)
  50. {
  51. if (_pm.device_pm[index].ops->resume != RT_NULL)
  52. {
  53. _pm.device_pm[index].ops->resume(_pm.device_pm[index].device, mode);
  54. }
  55. }
  56. }
  57. /**
  58. * This function will update the frequency of all registered devices
  59. */
  60. static void _pm_device_frequency_change(uint8_t mode, uint32_t frequency)
  61. {
  62. rt_uint32_t index;
  63. /* make the frequency change */
  64. for (index = 0; index < _pm.device_pm_number; index ++)
  65. {
  66. if (_pm.device_pm[index].ops->frequency_change != RT_NULL)
  67. _pm.device_pm[index].ops->frequency_change(_pm.device_pm[index].device, mode, frequency);
  68. }
  69. }
  70. /**
  71. * This function will update the system clock frequency when idle
  72. */
  73. static void _pm_frequency_scaling(struct rt_pm *pm)
  74. {
  75. rt_base_t level;
  76. if (pm->flags & RT_PM_FREQUENCY_PENDING)
  77. {
  78. level = rt_hw_interrupt_disable();
  79. /* change system runing mode */
  80. pm->ops->run(pm, pm->run_mode, pm->frequency);
  81. /* changer device frequency */
  82. _pm_device_frequency_change(pm->run_mode, pm->frequency);
  83. pm->flags &= ~RT_PM_FREQUENCY_PENDING;
  84. rt_hw_interrupt_enable(level);
  85. }
  86. }
  87. /**
  88. * This function selects the sleep mode according to the rt_pm_request/rt_pm_release count.
  89. */
  90. static uint8_t _pm_select_sleep_mode(struct rt_pm *pm)
  91. {
  92. int index;
  93. uint8_t mode;
  94. mode = _pm_default_sleep;
  95. for (index = PM_SLEEP_MODE_NONE; index < PM_SLEEP_MODE_MAX; index ++)
  96. {
  97. if (pm->modes[index])
  98. {
  99. mode = index;
  100. break;
  101. }
  102. }
  103. pm->sleep_mode = mode;
  104. return mode;
  105. }
  106. /**
  107. * This function changes the power sleep mode base on the result of selection
  108. */
  109. static void _pm_change_sleep_mode(struct rt_pm *pm, uint8_t mode)
  110. {
  111. rt_tick_t timeout_tick, delta_tick;
  112. rt_base_t level;
  113. int ret = RT_EOK;
  114. if (mode == PM_SLEEP_MODE_NONE)
  115. {
  116. pm->sleep_mode = mode;
  117. pm->ops->sleep(pm, PM_SLEEP_MODE_NONE);
  118. }
  119. else
  120. {
  121. level = rt_pm_enter_critical();
  122. /* Notify app will enter sleep mode */
  123. if (_pm_notify.notify)
  124. _pm_notify.notify(RT_PM_ENTER_SLEEP, mode, _pm_notify.data);
  125. /* Suspend all peripheral device */
  126. ret = _pm_device_suspend(mode);
  127. if (ret != RT_EOK)
  128. {
  129. _pm_device_resume(mode);
  130. if (_pm_notify.notify)
  131. _pm_notify.notify(RT_PM_EXIT_SLEEP, mode, _pm_notify.data);
  132. rt_pm_exit_critical(level);
  133. return;
  134. }
  135. /* Tickless*/
  136. if (pm->timer_mask & (0x01 << mode))
  137. {
  138. timeout_tick = rt_timer_next_timeout_tick();
  139. if (timeout_tick == RT_TICK_MAX)
  140. {
  141. if (pm->ops->timer_start)
  142. {
  143. pm->ops->timer_start(pm, RT_TICK_MAX);
  144. }
  145. }
  146. else
  147. {
  148. timeout_tick = timeout_tick - rt_tick_get();
  149. if (timeout_tick < RT_PM_TICKLESS_THRESH)
  150. {
  151. mode = PM_SLEEP_MODE_IDLE;
  152. }
  153. else
  154. {
  155. pm->ops->timer_start(pm, timeout_tick);
  156. }
  157. }
  158. }
  159. /* enter lower power state */
  160. pm->ops->sleep(pm, mode);
  161. /* wake up from lower power state*/
  162. if (pm->timer_mask & (0x01 << mode))
  163. {
  164. delta_tick = pm->ops->timer_get_tick(pm);
  165. pm->ops->timer_stop(pm);
  166. if (delta_tick)
  167. {
  168. rt_tick_set(rt_tick_get() + delta_tick);
  169. rt_timer_check();
  170. }
  171. }
  172. /* resume all device */
  173. _pm_device_resume(pm->sleep_mode);
  174. if (_pm_notify.notify)
  175. _pm_notify.notify(RT_PM_EXIT_SLEEP, mode, _pm_notify.data);
  176. rt_pm_exit_critical(level);
  177. }
  178. }
  179. /**
  180. * This function will enter corresponding power mode.
  181. */
  182. void rt_system_power_manager(void)
  183. {
  184. uint8_t mode;
  185. /* CPU frequency scaling according to the runing mode settings */
  186. _pm_frequency_scaling(&_pm);
  187. /* Low Power Mode Processing */
  188. mode = _pm_select_sleep_mode(&_pm);
  189. _pm_change_sleep_mode(&_pm, mode);
  190. }
  191. /**
  192. * Upper application or device driver requests the system
  193. * stall in corresponding power mode.
  194. *
  195. * @param parameter the parameter of run mode or sleep mode
  196. */
  197. void rt_pm_request(uint8_t mode)
  198. {
  199. rt_base_t level;
  200. struct rt_pm *pm;
  201. if (mode > (PM_SLEEP_MODE_MAX - 1))
  202. return;
  203. level = rt_hw_interrupt_disable();
  204. pm = &_pm;
  205. if (pm->modes[mode] < 255)
  206. pm->modes[mode] ++;
  207. rt_hw_interrupt_enable(level);
  208. }
  209. /**
  210. * Upper application or device driver releases the stall
  211. * of corresponding power mode.
  212. *
  213. * @param parameter the parameter of run mode or sleep mode
  214. *
  215. */
  216. void rt_pm_release(uint8_t mode)
  217. {
  218. rt_ubase_t level;
  219. struct rt_pm *pm;
  220. if (mode > (PM_SLEEP_MODE_MAX - 1))
  221. return;
  222. level = rt_hw_interrupt_disable();
  223. pm = &_pm;
  224. if (pm->modes[mode] > 0)
  225. pm->modes[mode] --;
  226. rt_hw_interrupt_enable(level);
  227. }
  228. /**
  229. * Register a device with PM feature
  230. *
  231. * @param device the device with PM feature
  232. * @param ops the PM ops for device
  233. */
  234. void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops)
  235. {
  236. rt_base_t level;
  237. struct rt_device_pm *device_pm;
  238. RT_DEBUG_NOT_IN_INTERRUPT;
  239. level = rt_hw_interrupt_disable();
  240. device_pm = (struct rt_device_pm *)RT_KERNEL_REALLOC(_pm.device_pm,
  241. (_pm.device_pm_number + 1) * sizeof(struct rt_device_pm));
  242. if (device_pm != RT_NULL)
  243. {
  244. _pm.device_pm = device_pm;
  245. _pm.device_pm[_pm.device_pm_number].device = device;
  246. _pm.device_pm[_pm.device_pm_number].ops = ops;
  247. _pm.device_pm_number += 1;
  248. }
  249. rt_hw_interrupt_enable(level);
  250. }
  251. /**
  252. * Unregister device from PM manager.
  253. *
  254. * @param device the device with PM feature
  255. */
  256. void rt_pm_device_unregister(struct rt_device *device)
  257. {
  258. rt_ubase_t level;
  259. rt_uint32_t index;
  260. RT_DEBUG_NOT_IN_INTERRUPT;
  261. level = rt_hw_interrupt_disable();
  262. for (index = 0; index < _pm.device_pm_number; index ++)
  263. {
  264. if (_pm.device_pm[index].device == device)
  265. {
  266. /* remove current entry */
  267. for (; index < _pm.device_pm_number - 1; index ++)
  268. {
  269. _pm.device_pm[index] = _pm.device_pm[index + 1];
  270. }
  271. _pm.device_pm[_pm.device_pm_number - 1].device = RT_NULL;
  272. _pm.device_pm[_pm.device_pm_number - 1].ops = RT_NULL;
  273. _pm.device_pm_number -= 1;
  274. /* break out and not touch memory */
  275. break;
  276. }
  277. }
  278. rt_hw_interrupt_enable(level);
  279. }
  280. /**
  281. * This function set notification callback for application
  282. */
  283. void rt_pm_notify_set(void (*notify)(uint8_t event, uint8_t mode, void *data), void *data)
  284. {
  285. _pm_notify.notify = notify;
  286. _pm_notify.data = data;
  287. }
  288. /**
  289. * This function set default sleep mode when no pm_request
  290. */
  291. void rt_pm_default_set(uint8_t sleep_mode)
  292. {
  293. _pm_default_sleep = sleep_mode;
  294. }
  295. /**
  296. * RT-Thread device interface for PM device
  297. */
  298. static rt_size_t _rt_pm_device_read(rt_device_t dev,
  299. rt_off_t pos,
  300. void *buffer,
  301. rt_size_t size)
  302. {
  303. struct rt_pm *pm;
  304. rt_size_t length;
  305. length = 0;
  306. pm = (struct rt_pm *)dev;
  307. RT_ASSERT(pm != RT_NULL);
  308. if (pos < PM_SLEEP_MODE_MAX)
  309. {
  310. int mode;
  311. mode = pm->modes[pos];
  312. length = rt_snprintf(buffer, size, "%d", mode);
  313. }
  314. return length;
  315. }
  316. static rt_size_t _rt_pm_device_write(rt_device_t dev,
  317. rt_off_t pos,
  318. const void *buffer,
  319. rt_size_t size)
  320. {
  321. unsigned char request;
  322. if (size)
  323. {
  324. /* get request */
  325. request = *(unsigned char *)buffer;
  326. if (request == '1')
  327. {
  328. rt_pm_request(pos);
  329. }
  330. else if (request == '0')
  331. {
  332. rt_pm_release(pos);
  333. }
  334. }
  335. return 1;
  336. }
  337. static rt_err_t _rt_pm_device_control(rt_device_t dev,
  338. int cmd,
  339. void *args)
  340. {
  341. rt_uint32_t mode;
  342. switch (cmd)
  343. {
  344. case RT_PM_DEVICE_CTRL_REQUEST:
  345. mode = (rt_uint32_t)args;
  346. rt_pm_request(mode);
  347. break;
  348. case RT_PM_DEVICE_CTRL_RELEASE:
  349. mode = (rt_uint32_t)args;
  350. rt_pm_release(mode);
  351. break;
  352. }
  353. return RT_EOK;
  354. }
  355. int rt_pm_run_mode_set(uint8_t mode, uint32_t frequency)
  356. {
  357. rt_base_t level;
  358. struct rt_pm *pm;
  359. if (mode > PM_RUN_MODE_MAX)
  360. return -RT_EINVAL;
  361. level = rt_hw_interrupt_disable();
  362. pm = &_pm;
  363. if (mode < pm->run_mode)
  364. {
  365. /* change system runing mode */
  366. pm->ops->run(pm, mode, frequency);
  367. /* changer device frequency */
  368. _pm_device_frequency_change(mode, frequency);
  369. }
  370. else
  371. {
  372. pm->flags |= RT_PM_FREQUENCY_PENDING;
  373. }
  374. pm->frequency = frequency;
  375. pm->run_mode = mode;
  376. rt_hw_interrupt_enable(level);
  377. return RT_EOK;
  378. }
  379. /**
  380. * This function will initialize power management.
  381. *
  382. * @param ops the PM operations.
  383. * @param timer_mask indicates which mode has timer feature.
  384. * @param user_data user data
  385. */
  386. void rt_system_pm_init(const struct rt_pm_ops *ops,
  387. rt_uint8_t timer_mask,
  388. void *user_data)
  389. {
  390. struct rt_device *device;
  391. struct rt_pm *pm;
  392. pm = &_pm;
  393. device = &(_pm.parent);
  394. device->type = RT_Device_Class_PM;
  395. device->rx_indicate = RT_NULL;
  396. device->tx_complete = RT_NULL;
  397. device->init = RT_NULL;
  398. device->open = RT_NULL;
  399. device->close = RT_NULL;
  400. device->read = _rt_pm_device_read;
  401. device->write = _rt_pm_device_write;
  402. device->control = _rt_pm_device_control;
  403. device->user_data = user_data;
  404. /* register PM device to the system */
  405. rt_device_register(device, "pm", RT_DEVICE_FLAG_RDWR);
  406. rt_memset(pm->modes, 0, sizeof(pm->modes));
  407. pm->sleep_mode = _pm_default_sleep;
  408. pm->run_mode = RT_PM_DEFAULT_RUN_MODE;
  409. pm->timer_mask = timer_mask;
  410. pm->ops = ops;
  411. pm->device_pm = RT_NULL;
  412. pm->device_pm_number = 0;
  413. }
  414. #ifdef RT_USING_FINSH
  415. #include <finsh.h>
  416. static const char *_pm_sleep_str[] = PM_SLEEP_MODE_NAMES;
  417. static const char *_pm_run_str[] = PM_RUN_MODE_NAMES;
  418. static void rt_pm_release_mode(int argc, char **argv)
  419. {
  420. int mode = 0;
  421. if (argc >= 2)
  422. {
  423. mode = atoi(argv[1]);
  424. }
  425. rt_pm_release(mode);
  426. }
  427. MSH_CMD_EXPORT_ALIAS(rt_pm_release_mode, pm_release, release power management mode);
  428. static void rt_pm_request_mode(int argc, char **argv)
  429. {
  430. int mode = 0;
  431. if (argc >= 2)
  432. {
  433. mode = atoi(argv[1]);
  434. }
  435. rt_pm_request(mode);
  436. }
  437. MSH_CMD_EXPORT_ALIAS(rt_pm_request_mode, pm_request, request power management mode);
  438. static void rt_pm_run_mode_switch(int argc, char **argv)
  439. {
  440. int mode = 0;
  441. if (argc >= 2)
  442. {
  443. mode = atoi(argv[1]);
  444. }
  445. rt_pm_run_mode_set(mode, 0);
  446. }
  447. MSH_CMD_EXPORT_ALIAS(rt_pm_run_mode_switch, pm_run_set, switch power management run mode);
  448. static void rt_pm_dump_status(void)
  449. {
  450. rt_uint32_t index;
  451. struct rt_pm *pm;
  452. pm = &_pm;
  453. rt_kprintf("| Power Management Mode | Counter | Timer |\n");
  454. rt_kprintf("+-----------------------+---------+-------+\n");
  455. for (index = 0; index < PM_SLEEP_MODE_MAX; index ++)
  456. {
  457. int has_timer = 0;
  458. if (pm->timer_mask & (1 << index))
  459. has_timer = 1;
  460. rt_kprintf("| %021s | %7d | %5d |\n", _pm_sleep_str[index], pm->modes[index], has_timer);
  461. }
  462. rt_kprintf("+-----------------------+---------+-------+\n");
  463. rt_kprintf("pm current sleep mode: %s\n", _pm_sleep_str[pm->sleep_mode]);
  464. rt_kprintf("pm current run mode: %s\n", _pm_run_str[pm->run_mode]);
  465. }
  466. FINSH_FUNCTION_EXPORT_ALIAS(rt_pm_dump_status, pm_dump, dump power management status);
  467. MSH_CMD_EXPORT_ALIAS(rt_pm_dump_status, pm_dump, dump power management status);
  468. #endif
  469. #endif /* RT_USING_PM */