mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-18 02:58:57 +08:00
[dm][core] add common machine power interface
Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
@@ -8,7 +8,7 @@ if GetDepend(['RT_USING_DEV_BUS']) or GetDepend(['RT_USING_DM']):
|
||||
src = src + ['bus.c']
|
||||
|
||||
if GetDepend(['RT_USING_DM']):
|
||||
src = src + ['dm.c', 'driver.c', 'numa.c', 'platform.c', 'power_domain.c']
|
||||
src = src + ['dm.c', 'driver.c', 'numa.c', 'platform.c', 'power.c', 'power_domain.c']
|
||||
|
||||
if GetDepend(['RT_USING_DFS']):
|
||||
src += ['mnt.c'];
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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);
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __RT_DM_POWER_H__
|
||||
#define __RT_DM_POWER_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
enum rt_dm_power_off_mode
|
||||
{
|
||||
RT_DM_POWER_OFF_MODE_SHUTDOWN,
|
||||
RT_DM_POWER_OFF_MODE_RESET,
|
||||
|
||||
RT_DM_POWER_OFF_MODE_NR,
|
||||
};
|
||||
|
||||
enum rt_dm_power_off_priority
|
||||
{
|
||||
RT_DM_POWER_OFF_PRIO_PLATFORM,
|
||||
RT_DM_POWER_OFF_PRIO_LOW,
|
||||
RT_DM_POWER_OFF_PRIO_DEFAULT,
|
||||
RT_DM_POWER_OFF_PRIO_HIGH,
|
||||
RT_DM_POWER_OFF_PRIO_FIRMWARE,
|
||||
|
||||
RT_DM_POWER_OFF_PRIO_NR,
|
||||
};
|
||||
|
||||
rt_err_t rt_dm_power_off_handler(struct rt_device *dev, int mode, int priority,
|
||||
rt_err_t (*callback)(struct rt_device *));
|
||||
|
||||
rt_err_t rt_dm_reboot_mode_register(struct rt_device *dev,
|
||||
rt_err_t (*callback)(struct rt_device *, char *cmd));
|
||||
rt_err_t rt_dm_reboot_mode_unregister(struct rt_device *dev);
|
||||
|
||||
void rt_hw_cpu_reset_mode(char *cmd);
|
||||
|
||||
extern void (*rt_dm_machine_shutdown)(void);
|
||||
extern void (*rt_dm_machine_reset)(void);
|
||||
|
||||
#endif /* __RT_DM_POWER_H__ */
|
||||
@@ -42,6 +42,7 @@ extern "C" {
|
||||
#ifdef RT_USING_DM
|
||||
#include "drivers/core/dm.h"
|
||||
#include "drivers/core/numa.h"
|
||||
#include "drivers/core/power.h"
|
||||
#include "drivers/core/power_domain.h"
|
||||
#include "drivers/platform.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user