mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-11-09 20:45:41 +08:00
[Feature] Support simple power domain API (#9005)
* [Feature] Power domain for device 1.Support device power on/off. 2.Support attach/detach device. 3.Support power domain driver api. Signed-off-by: GuEe-GUI <2991707448@qq.com> * [DM/platform] Enhanced platform bus 1.Add power domain for device. 2.Support `remove` and `shutdown` bus interface. Signed-off-by: GuEe-GUI <2991707448@qq.com> --------- Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
10 files changed
+725
-3
No files matched your search
@@ -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']
|
||||
src = src + ['dm.c', 'driver.c', 'numa.c', 'platform.c', 'power_domain.c']
|
||||
|
||||
if GetDepend(['RT_USING_DFS']):
|
||||
src += ['mnt.c'];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -135,16 +145,52 @@ 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);
|
||||
rt_platform_ofw_free(pdev);
|
||||
|
||||
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);
|
||||
rt_platform_ofw_free(pdev);
|
||||
|
||||
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)
|
||||
|
||||
@@ -92,9 +92,7 @@ static struct rt_platform_device *alloc_ofw_platform_device(struct rt_ofw_node *
|
||||
rt_ofw_node_get(np);
|
||||
rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
pdev->parent.ofw_node = np;
|
||||
#endif
|
||||
|
||||
ofw_device_rename(&pdev->parent);
|
||||
}
|
||||
@@ -232,3 +230,27 @@ static int platform_ofw_device_probe(void)
|
||||
return (int)err;
|
||||
}
|
||||
INIT_PLATFORM_EXPORT(platform_ofw_device_probe);
|
||||
|
||||
rt_err_t rt_platform_ofw_free(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
if (pdev)
|
||||
{
|
||||
struct rt_ofw_node *np = pdev->parent.ofw_node;
|
||||
|
||||
if (np)
|
||||
{
|
||||
rt_ofw_node_clear_flag(np, RT_OFW_F_PLATFORM);
|
||||
rt_ofw_node_put(np);
|
||||
|
||||
pdev->parent.ofw_node = RT_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-21 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __RT_DM_POWER_DOMAIN_H__
|
||||
#define __RT_DM_POWER_DOMAIN_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <ref.h>
|
||||
|
||||
#define RT_POWER_DOMAIN_OBJ_NAME "PMD"
|
||||
#define RT_POWER_DOMAIN_PROXY_OBJ_NAME "PMP"
|
||||
|
||||
struct rt_ofw_node;
|
||||
struct rt_ofw_cell_args;
|
||||
|
||||
struct rt_dm_power_domain_unit
|
||||
{
|
||||
rt_list_t list;
|
||||
|
||||
int id;
|
||||
struct rt_dm_power_domain *domain;
|
||||
};
|
||||
|
||||
struct rt_dm_power_domain_proxy
|
||||
{
|
||||
struct rt_object parent;
|
||||
|
||||
struct rt_dm_power_domain *(*ofw_parse)(struct rt_dm_power_domain_proxy *proxy,
|
||||
struct rt_ofw_cell_args *args);
|
||||
};
|
||||
|
||||
struct rt_dm_power_domain
|
||||
{
|
||||
struct rt_object parent;
|
||||
|
||||
struct rt_device *dev;
|
||||
struct rt_dm_power_domain *parent_domain;
|
||||
|
||||
rt_list_t list;
|
||||
rt_list_t child_nodes;
|
||||
rt_list_t unit_nodes;
|
||||
|
||||
struct rt_ref ref;
|
||||
struct rt_spinlock lock;
|
||||
|
||||
rt_err_t (*power_on)(struct rt_dm_power_domain *domain);
|
||||
rt_err_t (*power_off)(struct rt_dm_power_domain *domain);
|
||||
rt_err_t (*attach_dev)(struct rt_dm_power_domain *domain, struct rt_device *dev);
|
||||
rt_err_t (*detach_dev)(struct rt_dm_power_domain *domain, struct rt_device *dev);
|
||||
|
||||
void *pirv;
|
||||
};
|
||||
|
||||
void rt_dm_power_domain_proxy_default_name(struct rt_dm_power_domain_proxy *proxy);
|
||||
void rt_dm_power_domain_proxy_ofw_bind(struct rt_dm_power_domain_proxy *proxy,
|
||||
struct rt_ofw_node *np);
|
||||
|
||||
rt_err_t rt_dm_power_domain_register(struct rt_dm_power_domain *domain);
|
||||
rt_err_t rt_dm_power_domain_unregister(struct rt_dm_power_domain *domain);
|
||||
|
||||
rt_err_t rt_dm_power_domain_register_child(struct rt_dm_power_domain *domain,
|
||||
struct rt_dm_power_domain *child_domain);
|
||||
rt_err_t rt_dm_power_domain_unregister_child(struct rt_dm_power_domain *domain,
|
||||
struct rt_dm_power_domain *child_domain);
|
||||
|
||||
rt_err_t rt_dm_power_domain_power_on(struct rt_dm_power_domain *domain);
|
||||
rt_err_t rt_dm_power_domain_power_off(struct rt_dm_power_domain *domain);
|
||||
|
||||
struct rt_dm_power_domain *rt_dm_power_domain_get_by_index(struct rt_device *dev, int index);
|
||||
struct rt_dm_power_domain *rt_dm_power_domain_get_by_name(struct rt_device *dev, const char *name);
|
||||
rt_err_t rt_dm_power_domain_put(struct rt_dm_power_domain *domain);
|
||||
|
||||
rt_err_t rt_dm_power_domain_attach(struct rt_device *dev, rt_bool_t on);
|
||||
rt_err_t rt_dm_power_domain_detach(struct rt_device *dev, rt_bool_t off);
|
||||
|
||||
#endif /* __RT_DM_POWER_DOMAIN_H__ */
|
||||
@@ -430,6 +430,8 @@ rt_inline rt_bool_t rt_ofw_node_is_type(const struct rt_ofw_node *np, const char
|
||||
struct rt_ofw_stub *rt_ofw_stub_probe_range(struct rt_ofw_node *np,
|
||||
const struct rt_ofw_stub *stub_start, const struct rt_ofw_stub *stub_end);
|
||||
|
||||
struct rt_object *rt_ofw_parse_object(struct rt_ofw_node *np, const char *obj_name, const char *cells_name);
|
||||
|
||||
rt_err_t rt_ofw_console_setup(void);
|
||||
const char *rt_ofw_bootargs_select(const char *key, int index);
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv);
|
||||
rt_err_t rt_platform_device_register(struct rt_platform_device *pdev);
|
||||
|
||||
rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np);
|
||||
rt_err_t rt_platform_ofw_free(struct rt_platform_device *pdev);
|
||||
|
||||
#define RT_PLATFORM_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, platform, BUILIN)
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ extern "C" {
|
||||
#ifdef RT_USING_DM
|
||||
#include "drivers/core/dm.h"
|
||||
#include "drivers/core/numa.h"
|
||||
#include "drivers/core/power_domain.h"
|
||||
#include "drivers/platform.h"
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
|
||||
@@ -60,6 +60,93 @@ struct rt_ofw_stub *rt_ofw_stub_probe_range(struct rt_ofw_node *np,
|
||||
return (struct rt_ofw_stub *)stub;
|
||||
}
|
||||
|
||||
struct ofw_obj_cmp_list
|
||||
{
|
||||
const char *cells_name;
|
||||
const char *obj_name;
|
||||
rt_size_t obj_size;
|
||||
};
|
||||
|
||||
static const struct ofw_obj_cmp_list ofw_obj_cmp_list[] =
|
||||
{
|
||||
{ "#power-domain-cells", RT_POWER_DOMAIN_PROXY_OBJ_NAME, sizeof(struct rt_dm_power_domain_proxy) },
|
||||
{ "#power-domain-cells", RT_POWER_DOMAIN_OBJ_NAME, sizeof(struct rt_dm_power_domain) },
|
||||
};
|
||||
|
||||
static struct rt_object *ofw_parse_object(struct rt_ofw_node *np, const char *cells_name)
|
||||
{
|
||||
const struct ofw_obj_cmp_list *item;
|
||||
struct rt_object *obj = rt_ofw_data(np), *ret_obj = RT_NULL;
|
||||
RT_BITMAP_DECLARE(idx_mask, RT_ARRAY_SIZE(ofw_obj_cmp_list)) = {};
|
||||
|
||||
for (int i = 0; i < RT_ARRAY_SIZE(ofw_obj_cmp_list); ++i)
|
||||
{
|
||||
item = &ofw_obj_cmp_list[i];
|
||||
|
||||
if (!rt_ofw_prop_read_bool(np, item->cells_name))
|
||||
{
|
||||
rt_bitmap_set_bit(idx_mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
while (!ret_obj)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Is print ? */
|
||||
if (!((rt_uint32_t)(obj->name[0] - 0x20) < 0x5f))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rt_bitmap_for_each_clear_bit(idx_mask, i, RT_ARRAY_SIZE(ofw_obj_cmp_list))
|
||||
{
|
||||
item = &ofw_obj_cmp_list[i];
|
||||
|
||||
if (!rt_strcmp(item->cells_name, cells_name))
|
||||
{
|
||||
ret_obj = obj;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rt_strncmp(item->obj_name, obj->name, RT_NAME_MAX))
|
||||
{
|
||||
obj = (struct rt_object *)((rt_ubase_t)obj + item->obj_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= RT_ARRAY_SIZE(ofw_obj_cmp_list))
|
||||
{
|
||||
LOG_E("Invalid rt_object = %s", obj->name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_obj;
|
||||
}
|
||||
|
||||
struct rt_object *rt_ofw_parse_object(struct rt_ofw_node *np, const char *obj_name, const char *cells_name)
|
||||
{
|
||||
struct rt_object *obj = RT_NULL, *test_obj;
|
||||
|
||||
if (np && (test_obj = rt_ofw_data(np)) && cells_name)
|
||||
{
|
||||
/* The composite object is rare, so we try to find this object as much as possible at once. */
|
||||
if (obj_name && rt_strcmp(test_obj->name, obj_name))
|
||||
{
|
||||
obj = test_obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = ofw_parse_object(np, cells_name);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static const char *ofw_console_serial_find(char *dst_con, struct rt_ofw_node *np)
|
||||
{
|
||||
rt_object_t rt_obj = RT_NULL;
|
||||
|
||||
@@ -1363,6 +1363,7 @@ struct rt_device
|
||||
#ifdef RT_USING_OFW
|
||||
void *ofw_node; /**< ofw node get from device tree */
|
||||
#endif /* RT_USING_OFW */
|
||||
void *power_domain_unit;
|
||||
#endif /* RT_USING_DM */
|
||||
|
||||
enum rt_device_class_type type; /**< device type */
|
||||
|
||||
Reference in new issue
Block a user