| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-09-24 GuEe-GUI the first version
- */
- #include <rtdevice.h>
- #define DBG_TAG "rtdm.power"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- struct power_off_track
- {
- rt_slist_t list;
- struct rt_device *dev;
- rt_err_t (*callback)(struct rt_device *);
- };
- void (*rt_dm_machine_shutdown)(void) = RT_NULL;
- void (*rt_dm_machine_reset)(void) = RT_NULL;
- static RT_DEFINE_SPINLOCK(_power_off_lock);
- static rt_slist_t _power_off_handler_nodes[RT_DM_POWER_OFF_MODE_NR][RT_DM_POWER_OFF_PRIO_NR] =
- {
- [0 ... RT_DM_POWER_OFF_MODE_NR - 1] =
- {
- [0 ... RT_DM_POWER_OFF_PRIO_NR - 1] =
- {
- RT_NULL,
- }
- }
- };
- static rt_used char * const _mode_name[] =
- {
- [RT_DM_POWER_OFF_MODE_SHUTDOWN] = "SHUTDOWN",
- [RT_DM_POWER_OFF_MODE_RESET] = "RESET",
- };
- rt_err_t rt_dm_power_off_handler(struct rt_device *dev, int mode, int priority,
- rt_err_t (*callback)(struct rt_device *dev))
- {
- struct power_off_track *track;
- RT_ASSERT(mode < RT_DM_POWER_OFF_MODE_NR);
- RT_ASSERT(priority < RT_DM_POWER_OFF_PRIO_NR);
- track = rt_malloc(sizeof(*track));
- if (!track)
- {
- return -RT_ENOMEM;
- }
- rt_slist_init(&track->list);
- track->dev = dev;
- track->callback = callback;
- rt_hw_spin_lock(&_power_off_lock.lock);
- rt_slist_insert(&_power_off_handler_nodes[mode][priority], &track->list);
- rt_hw_spin_unlock(&_power_off_lock.lock);
- return RT_EOK;
- }
- static void dm_power_off_handler(int mode)
- {
- struct power_off_track *track;
- rt_hw_spin_lock(&_power_off_lock.lock);
- for (int i = 0; i < RT_DM_POWER_OFF_PRIO_NR; ++i)
- {
- rt_slist_t *nodes = &_power_off_handler_nodes[mode][i];
- rt_slist_for_each_entry(track, nodes, list)
- {
- rt_err_t err;
- struct rt_device *dev = track->dev;
- if ((err = track->callback(dev)))
- {
- LOG_E("%s: %s fail error = %s", dev ? rt_dm_dev_get_name(dev) : RT_NULL,
- _mode_name[mode], rt_strerror(err));
- }
- }
- }
- rt_hw_spin_unlock(&_power_off_lock.lock);
- }
- struct reboot_mode_track
- {
- rt_slist_t list;
- struct rt_device *dev;
- rt_err_t (*callback)(struct rt_device *, char *cmd);
- };
- static char *_reboot_mode_cmd = "normal";
- static RT_DEFINE_SPINLOCK(_reboot_mode_lock);
- static rt_slist_t _reboot_mode_handler_nodes = { RT_NULL };
- rt_err_t rt_dm_reboot_mode_register(struct rt_device *dev,
- rt_err_t (*callback)(struct rt_device *, char *cmd))
- {
- struct reboot_mode_track *track;
- track = rt_malloc(sizeof(*track));
- if (!track)
- {
- return -RT_ENOMEM;
- }
- rt_slist_init(&track->list);
- track->dev = dev;
- track->callback = callback;
- rt_hw_spin_lock(&_reboot_mode_lock.lock);
- rt_slist_insert(&_reboot_mode_handler_nodes, &track->list);
- rt_hw_spin_unlock(&_reboot_mode_lock.lock);
- return RT_EOK;
- }
- rt_err_t rt_dm_reboot_mode_unregister(struct rt_device *dev)
- {
- struct reboot_mode_track *track, *target_track = RT_NULL;
- rt_hw_spin_lock(&_reboot_mode_lock.lock);
- rt_slist_for_each_entry(track, &_reboot_mode_handler_nodes, list)
- {
- if (track->dev == dev)
- {
- target_track = track;
- rt_slist_remove(&_reboot_mode_handler_nodes, &track->list);
- break;
- }
- }
- rt_hw_spin_unlock(&_reboot_mode_lock.lock);
- if (target_track)
- {
- rt_free(target_track);
- }
- return target_track ? RT_EOK : -RT_EEMPTY;
- }
- static rt_err_t dm_reboot_notifiy(struct rt_device *request_dev)
- {
- struct reboot_mode_track *track;
- rt_hw_spin_lock(&_reboot_mode_lock.lock);
- rt_slist_for_each_entry(track, &_reboot_mode_handler_nodes, list)
- {
- rt_err_t err;
- struct rt_device *dev = track->dev;
- if ((err = track->callback(dev, _reboot_mode_cmd)))
- {
- LOG_E("%s: %s fail error = %s", dev ? rt_dm_dev_get_name(dev) : RT_NULL,
- "reboot mode apply", rt_strerror(err));
- }
- }
- rt_hw_spin_unlock(&_reboot_mode_lock.lock);
- return RT_EOK;
- }
- static int reboot_mode_init(void)
- {
- return rt_dm_power_off_handler(RT_NULL, RT_DM_POWER_OFF_MODE_RESET,
- RT_DM_POWER_OFF_PRIO_HIGH, &dm_reboot_notifiy);
- }
- INIT_CORE_EXPORT(reboot_mode_init);
- void rt_hw_cpu_reset_mode(char *cmd)
- {
- static RT_DEFINE_SPINLOCK(pe_lock);
- rt_hw_spin_lock(&pe_lock.lock);
- _reboot_mode_cmd = cmd ? : _reboot_mode_cmd;
- rt_hw_cpu_reset();
- /* Unreachable */
- rt_hw_spin_unlock(&pe_lock.lock);
- }
- static struct rt_thread power_task;
- static void power_task_async(void (*fn)(void));
- rt_inline rt_bool_t power_need_async(void)
- {
- struct rt_thread *tid = rt_thread_self();
- return tid && tid != &power_task && rt_interrupt_get_nest();
- }
- void rt_hw_cpu_shutdown(void)
- {
- register rt_ubase_t level;
- if (power_need_async())
- {
- power_task_async(&rt_hw_cpu_shutdown);
- return;
- }
- dm_power_off_handler(RT_DM_POWER_OFF_MODE_SHUTDOWN);
- LOG_I("Shutdown");
- /* Machine shutdown */
- if (rt_dm_machine_shutdown)
- {
- rt_dm_machine_shutdown();
- }
- level = rt_hw_interrupt_disable();
- while (level)
- {
- RT_ASSERT(0);
- }
- }
- MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_shutdown, shutdown, shutdown machine);
- void rt_hw_cpu_reset(void)
- {
- register rt_ubase_t level;
- if (power_need_async())
- {
- power_task_async(&rt_hw_cpu_reset);
- return;
- }
- dm_power_off_handler(RT_DM_POWER_OFF_MODE_RESET);
- LOG_I("Reset");
- /* Machine reset */
- if (rt_dm_machine_reset)
- {
- rt_dm_machine_reset();
- }
- level = rt_hw_interrupt_disable();
- while (level)
- {
- RT_ASSERT(0);
- }
- }
- static int reset(int args, char**argv)
- {
- if (args > 1)
- {
- rt_hw_cpu_reset_mode(argv[1]);
- }
- else
- {
- rt_hw_cpu_reset();
- }
- return 0;
- }
- MSH_CMD_EXPORT(reset, reset machine);
- static void power_task_entry(void *param)
- {
- void (*fn)(void) = rt_thread_self()->parameter;
- fn();
- }
- static void power_task_async(void (*fn)(void))
- {
- power_task.parameter = fn;
- rt_thread_startup(&power_task);
- }
- static int power_init(void)
- {
- static rt_uint8_t power_task_stack[DM_THREAD_STACK_SIZE];
- return rt_thread_init(&power_task, "pwr", power_task_entry, RT_NULL,
- &power_task_stack, sizeof(power_task_stack),
- RT_THREAD_PRIORITY_MAX / 2, 32);
- }
- INIT_CORE_EXPORT(power_init);
|