Skip to content

Commit

Permalink
add power domain
Browse files Browse the repository at this point in the history
  • Loading branch information
zmshahaha committed Apr 2, 2024
1 parent d856f77 commit cc20a8b
Show file tree
Hide file tree
Showing 11 changed files with 984 additions and 1 deletion.
2 changes: 1 addition & 1 deletion components/drivers/core/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -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', 'platform.c']
src = src + ['dm.c', 'driver.c', 'platform.c', 'power.c', 'power_domain.c']

if GetDepend(['RT_USING_OFW']):
src += ['platform_ofw.c']
Expand Down
44 changes: 44 additions & 0 deletions components/drivers/core/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <drivers/platform.h>
#include <drivers/core/bus.h>
#include <drivers/core/dm.h>
#include <drivers/core/power_domain.h>

static struct rt_bus platform_bus;

Expand Down Expand Up @@ -118,6 +119,15 @@ static rt_err_t platform_probe(rt_device_t dev)
struct rt_ofw_node *np = dev->ofw_node;
#endif

err = rt_dm_power_domain_attach(dev, RT_TRUE);

if (err && err != -RT_EEMPTY)
{
LOG_E("Attach power domain error = %s in device %s", pdev->name, rt_strerror(err));

return err;
}

err = pdrv->probe(pdev);

if (!err)
Expand All @@ -135,16 +145,50 @@ static rt_err_t platform_probe(rt_device_t dev)
{
LOG_W("System not memory in driver %s", pdrv->name);
}

rt_dm_power_domain_detach(dev, RT_TRUE);
}

return err;
}

static rt_err_t platform_remove(rt_device_t dev)
{
struct rt_platform_driver *pdrv = rt_container_of(dev->drv, struct rt_platform_driver, parent);
struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent);

if (pdrv && pdrv->remove)
{
pdrv->remove(pdev);
}

rt_dm_power_domain_detach(dev, RT_TRUE);

return RT_EOK;
}

static rt_err_t platform_shutdown(rt_device_t dev)
{
struct rt_platform_driver *pdrv = rt_container_of(dev->drv, struct rt_platform_driver, parent);
struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent);

if (pdrv && pdrv->shutdown)
{
pdrv->shutdown(pdev);
}

rt_dm_power_domain_detach(dev, RT_TRUE);

return RT_EOK;
}

static struct rt_bus platform_bus =
{
.name = "platform",
.match = platform_match,
.probe = platform_probe,
.remove = platform_remove,
.shutdown = platform_shutdown,
};

static int platform_bus_init(void)
Expand Down
235 changes: 235 additions & 0 deletions components/drivers/core/power.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
/*
* 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 struct rt_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 struct rt_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;
}

static rt_err_t dm_reboot_notifiy(struct rt_device *)
{
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 struct rt_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);
}

void rt_hw_cpu_shutdown(void)
{
register rt_ubase_t level;

dm_power_off_handler(RT_DM_POWER_OFF_MODE_SHUTDOWN);

rt_bus_shutdown();

#ifdef RT_USING_PIC
rt_pic_irq_finit();
#endif

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;

dm_power_off_handler(RT_DM_POWER_OFF_MODE_RESET);

rt_bus_shutdown();

#ifdef RT_USING_PIC
rt_pic_irq_finit();
#endif

LOG_I("Reset");

/* Machine reset */
if (rt_dm_machine_reset)
{
rt_dm_machine_reset();
}

level = rt_hw_interrupt_disable();
while (level)
{
RT_ASSERT(0);
}
}
MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_reset, reset, reset machine);
Loading

0 comments on commit cc20a8b

Please sign in to comment.