Просмотр исходного кода

[dm][core] add common machine power interface

Signed-off-by: GuEe-GUI <2991707448@qq.com>
GuEe-GUI 1 месяц назад
Родитель
Сommit
4913211409

+ 1 - 1
components/drivers/core/SConscript

@@ -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'];

+ 311 - 0
components/drivers/core/power.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);

+ 47 - 0
components/drivers/include/drivers/core/power.h

@@ -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__ */

+ 1 - 0
components/drivers/include/rtdevice.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"