summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGUI <[email protected]>2024-05-30 15:30:40 +0800
committerGitHub <[email protected]>2024-05-30 15:30:40 +0800
commite7cddf3a5275937b38f95afa7540fcc3fc7e5354 (patch)
tree25bb3a1597a0118585e994e29286dc4734401486
parent2cbe8bdae01cdd2d8fc0c55f363a94f13fb11a47 (diff)
[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 <[email protected]> * [DM/platform] Enhanced platform bus 1.Add power domain for device. 2.Support `remove` and `shutdown` bus interface. Signed-off-by: GuEe-GUI <[email protected]> --------- Signed-off-by: GuEe-GUI <[email protected]>
-rw-r--r--components/drivers/core/SConscript2
-rw-r--r--components/drivers/core/platform.c46
-rw-r--r--components/drivers/core/platform_ofw.c26
-rw-r--r--components/drivers/core/power_domain.c477
-rw-r--r--components/drivers/include/drivers/core/power_domain.h85
-rw-r--r--components/drivers/include/drivers/ofw.h2
-rw-r--r--components/drivers/include/drivers/platform.h1
-rw-r--r--components/drivers/include/rtdevice.h1
-rw-r--r--components/drivers/ofw/ofw.c87
-rw-r--r--include/rtdef.h1
10 files changed, 725 insertions, 3 deletions
diff --git a/components/drivers/core/SConscript b/components/drivers/core/SConscript
index e1f003549f..f3f3fbd313 100644
--- a/components/drivers/core/SConscript
+++ b/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']
+ src = src + ['dm.c', 'driver.c', 'numa.c', 'platform.c', 'power_domain.c']
if GetDepend(['RT_USING_DFS']):
src += ['mnt.c'];
diff --git a/components/drivers/core/platform.c b/components/drivers/core/platform.c
index 18c044f6c4..d8c6679a6d 100644
--- a/components/drivers/core/platform.c
+++ b/components/drivers/core/platform.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)
diff --git a/components/drivers/core/platform_ofw.c b/components/drivers/core/platform_ofw.c
index 408dec9dc7..f305fde62b 100644
--- a/components/drivers/core/platform_ofw.c
+++ b/components/drivers/core/platform_ofw.c
@@ -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;
+}
diff --git a/components/drivers/core/power_domain.c b/components/drivers/core/power_domain.c
new file mode 100644
index 0000000000..254010b4fe
--- /dev/null
+++ b/components/drivers/core/power_domain.c
@@ -0,0 +1,477 @@
+/*
+ * 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_domain"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <drivers/ofw.h>
+
+void rt_dm_power_domain_proxy_default_name(struct rt_dm_power_domain_proxy *proxy)
+{
+#if RT_NAME_MAX > 0
+ rt_strncpy(proxy->parent.name, RT_POWER_DOMAIN_OBJ_NAME, RT_NAME_MAX);
+#else
+ proxy->parent.name = RT_POWER_DOMAIN_OBJ_NAME;
+#endif
+}
+
+void rt_dm_power_domain_proxy_ofw_bind(struct rt_dm_power_domain_proxy *proxy,
+ struct rt_ofw_node *np)
+{
+ if (!proxy || !proxy->ofw_parse || !np)
+ {
+ return;
+ }
+
+ rt_dm_power_domain_proxy_default_name(proxy);
+ rt_ofw_data(np) = proxy;
+}
+
+static void dm_power_domain_init(struct rt_dm_power_domain *domain)
+{
+#if RT_NAME_MAX > 0
+ rt_strncpy(domain->parent.name, RT_POWER_DOMAIN_OBJ_NAME, RT_NAME_MAX);
+#else
+ domain->parent.name = RT_POWER_DOMAIN_OBJ_NAME;
+#endif
+
+ domain->parent_domain = RT_NULL;
+
+ rt_list_init(&domain->list);
+ rt_list_init(&domain->child_nodes);
+ rt_list_init(&domain->unit_nodes);
+
+ rt_ref_init(&domain->ref);
+ rt_spin_lock_init(&domain->lock);
+}
+
+static rt_bool_t dm_power_domain_is_free(struct rt_dm_power_domain *domain)
+{
+ return rt_ref_read(&domain->ref) == 1 && !rt_list_isempty(&domain->child_nodes);
+}
+
+rt_err_t rt_dm_power_domain_register(struct rt_dm_power_domain *domain)
+{
+ if (!domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ dm_power_domain_init(domain);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_dm_power_domain_unregister(struct rt_dm_power_domain *domain)
+{
+ rt_err_t err = RT_EOK;
+
+ if (!domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!dm_power_domain_is_free(domain))
+ {
+ return -RT_EBUSY;
+ }
+
+ if (domain->parent_domain)
+ {
+ err = rt_dm_power_domain_unregister_child(domain->parent_domain, domain);
+ }
+
+ return err;
+}
+
+rt_err_t rt_dm_power_domain_register_child(struct rt_dm_power_domain *domain,
+ struct rt_dm_power_domain *child_domain)
+{
+ if (!domain || !child_domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ dm_power_domain_init(child_domain);
+ child_domain->parent_domain = domain;
+
+ return RT_EOK;
+}
+
+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 err = RT_EOK;
+
+ if (!domain || !child_domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_hw_spin_lock(&domain->lock.lock);
+
+ if (dm_power_domain_is_free(domain))
+ {
+ rt_list_remove(&child_domain->list);
+ }
+ else
+ {
+ err = -RT_EBUSY;
+ }
+
+ rt_hw_spin_unlock(&domain->lock.lock);
+
+ return err;
+}
+
+rt_err_t rt_dm_power_domain_power_on(struct rt_dm_power_domain *domain)
+{
+ rt_err_t err = RT_EOK;
+ struct rt_dm_power_domain *child_domain;
+
+ if (!domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_hw_spin_lock(&domain->lock.lock);
+
+ if (rt_ref_read(&domain->ref) == 1)
+ {
+ err = domain->power_on(domain);
+ }
+
+ if (!err)
+ {
+ struct rt_dm_power_domain *fail_domain = RT_NULL;
+
+ rt_list_for_each_entry(child_domain, &domain->child_nodes, list)
+ {
+ err = rt_dm_power_domain_power_on(child_domain);
+
+ if (err)
+ {
+ fail_domain = child_domain;
+ break;
+ }
+ }
+
+ if (fail_domain)
+ {
+ rt_list_for_each_entry(child_domain, &domain->child_nodes, list)
+ {
+ if (child_domain == fail_domain)
+ {
+ break;
+ }
+
+ rt_dm_power_domain_power_off(child_domain);
+ }
+ }
+ }
+
+ rt_hw_spin_unlock(&domain->lock.lock);
+
+ if (!err)
+ {
+ rt_ref_get(&domain->ref);
+ }
+
+ return err;
+}
+
+static void dm_power_domain_release(struct rt_ref *r)
+{
+ struct rt_dm_power_domain *domain = rt_container_of(r, struct rt_dm_power_domain, ref);
+
+ if (domain->dev)
+ {
+ LOG_E("%s power domain is release", rt_dm_dev_get_name(domain->dev));
+ }
+
+ RT_ASSERT(0);
+}
+
+rt_err_t rt_dm_power_domain_power_off(struct rt_dm_power_domain *domain)
+{
+ rt_err_t err;
+ struct rt_dm_power_domain *child_domain;
+
+ if (!domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_ref_put(&domain->ref, dm_power_domain_release);
+
+ rt_hw_spin_lock(&domain->lock.lock);
+
+ if (rt_ref_read(&domain->ref) == 1)
+ {
+ err = domain->power_off(domain);
+ }
+ else
+ {
+ err = -RT_EBUSY;
+ }
+
+ if (!err)
+ {
+ struct rt_dm_power_domain *fail_domain = RT_NULL;
+
+ rt_list_for_each_entry(child_domain, &domain->child_nodes, list)
+ {
+ err = rt_dm_power_domain_power_off(child_domain);
+
+ if (err)
+ {
+ fail_domain = child_domain;
+ break;
+ }
+ }
+
+ if (fail_domain)
+ {
+ rt_list_for_each_entry(child_domain, &domain->child_nodes, list)
+ {
+ if (child_domain == fail_domain)
+ {
+ break;
+ }
+
+ rt_dm_power_domain_power_on(child_domain);
+ }
+ }
+ }
+
+ rt_hw_spin_unlock(&domain->lock.lock);
+
+ if (err)
+ {
+ rt_ref_get(&domain->ref);
+ }
+
+ return err;
+}
+
+#ifdef RT_USING_OFW
+static struct rt_dm_power_domain *ofw_find_power_domain(struct rt_device *dev,
+ int index, struct rt_ofw_cell_args *args)
+{
+ struct rt_object *obj;
+ struct rt_dm_power_domain_proxy *proxy;
+ struct rt_dm_power_domain *domain = RT_NULL;
+ struct rt_ofw_node *np = dev->ofw_node, *power_domain_np;
+
+ if (!rt_ofw_parse_phandle_cells(np, "power-domains", "#power-domain-cells",
+ index, args))
+ {
+ power_domain_np = args->data;
+
+ if (power_domain_np && (obj = rt_ofw_data(power_domain_np)))
+ {
+ if (!rt_strcmp(obj->name, RT_POWER_DOMAIN_OBJ_NAME))
+ {
+ proxy = rt_container_of(obj, struct rt_dm_power_domain_proxy, parent);
+ domain = proxy->ofw_parse(proxy, args);
+ }
+ else if (!rt_strcmp(obj->name, RT_POWER_DOMAIN_OBJ_NAME))
+ {
+ domain = rt_container_of(obj, struct rt_dm_power_domain, parent);
+ }
+ else if ((obj = rt_ofw_parse_object(power_domain_np,
+ RT_POWER_DOMAIN_PROXY_OBJ_NAME, "#power-domain-cells")))
+ {
+ proxy = rt_container_of(obj, struct rt_dm_power_domain_proxy, parent);
+ domain = proxy->ofw_parse(proxy, args);
+ }
+ else if ((obj = rt_ofw_parse_object(power_domain_np,
+ RT_POWER_DOMAIN_OBJ_NAME, "#power-domain-cells")))
+ {
+ domain = rt_container_of(obj, struct rt_dm_power_domain, parent);
+ }
+
+ rt_ofw_node_put(power_domain_np);
+ }
+ }
+
+ return domain;
+}
+#else
+rt_inline struct rt_dm_power_domain *ofw_find_power_domain(struct rt_device *dev,
+ int index, struct rt_ofw_cell_args *args)
+{
+ return RT_NULL;
+}
+#endif /* RT_USING_OFW */
+
+struct rt_dm_power_domain *rt_dm_power_domain_get_by_index(struct rt_device *dev,
+ int index)
+{
+ struct rt_ofw_cell_args args;
+ struct rt_dm_power_domain *domain;
+
+ if (!dev || index < 0)
+ {
+ return RT_NULL;
+ }
+
+ if ((domain = ofw_find_power_domain(dev, index, &args)))
+ {
+ goto _end;
+ }
+
+_end:
+ return domain;
+}
+
+struct rt_dm_power_domain *rt_dm_power_domain_get_by_name(struct rt_device *dev,
+ const char *name)
+{
+ int index;
+
+ if (!dev || !name)
+ {
+ return RT_NULL;
+ }
+
+ if ((index = rt_dm_dev_prop_index_of_string(dev, "power-domain-names", name)) < 0)
+ {
+ LOG_E("%s find power domain %s not found", rt_dm_dev_get_name(dev));
+
+ return RT_NULL;
+ }
+
+ return rt_dm_power_domain_get_by_index(dev, index);
+}
+
+rt_err_t rt_dm_power_domain_put(struct rt_dm_power_domain *domain)
+{
+ if (!domain)
+ {
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+}
+
+rt_err_t rt_dm_power_domain_attach(struct rt_device *dev, rt_bool_t on)
+{
+ int id = -1;
+ rt_err_t err = RT_EOK;
+ struct rt_ofw_cell_args args;
+ struct rt_dm_power_domain *domain;
+ struct rt_dm_power_domain_unit *unit;
+
+ if (!dev)
+ {
+ return -RT_EINVAL;
+ }
+
+ /* We only attach the first one, get domains self if there are multiple domains */
+ if ((domain = ofw_find_power_domain(dev, 0, &args)))
+ {
+ id = args.args[0];
+ }
+
+ if (!domain)
+ {
+ return -RT_EEMPTY;
+ }
+
+ unit = rt_malloc(sizeof(*unit));
+
+ if (!unit)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rt_list_init(&unit->list);
+ unit->id = id;
+ unit->domain = domain;
+
+ dev->power_domain_unit = unit;
+
+ rt_hw_spin_lock(&domain->lock.lock);
+
+ if (domain->attach_dev)
+ {
+ err = domain->attach_dev(domain, dev);
+ }
+
+ if (!err)
+ {
+ rt_list_insert_before(&domain->unit_nodes, &unit->list);
+ }
+
+ rt_hw_spin_unlock(&domain->lock.lock);
+
+ if (err)
+ {
+ dev->power_domain_unit = RT_NULL;
+ rt_free(unit);
+
+ return err;
+ }
+
+ if (on)
+ {
+ err = rt_dm_power_domain_power_on(domain);
+ }
+
+ return err;
+}
+
+rt_err_t rt_dm_power_domain_detach(struct rt_device *dev, rt_bool_t off)
+{
+ rt_err_t err = RT_EOK;
+ struct rt_dm_power_domain *domain;
+ struct rt_dm_power_domain_unit *unit;
+
+ if (!dev || !dev->power_domain_unit)
+ {
+ return -RT_EINVAL;
+ }
+
+ unit = dev->power_domain_unit;
+ domain = unit->domain;
+
+ rt_hw_spin_lock(&domain->lock.lock);
+
+ if (domain->detach_dev)
+ {
+ err = domain->detach_dev(domain, dev);
+ }
+
+ if (!err)
+ {
+ rt_list_remove(&unit->list);
+ }
+
+ rt_hw_spin_unlock(&domain->lock.lock);
+
+ if (err)
+ {
+ return err;
+ }
+
+ rt_free(unit);
+ dev->power_domain_unit = RT_NULL;
+
+ if (off)
+ {
+ err = rt_dm_power_domain_power_off(domain);
+ }
+
+ return err;
+}
diff --git a/components/drivers/include/drivers/core/power_domain.h b/components/drivers/include/drivers/core/power_domain.h
new file mode 100644
index 0000000000..6b1f7cde65
--- /dev/null
+++ b/components/drivers/include/drivers/core/power_domain.h
@@ -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__ */
diff --git a/components/drivers/include/drivers/ofw.h b/components/drivers/include/drivers/ofw.h
index 809a84d4a4..7531dfe3c5 100644
--- a/components/drivers/include/drivers/ofw.h
+++ b/components/drivers/include/drivers/ofw.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);
diff --git a/components/drivers/include/drivers/platform.h b/components/drivers/include/drivers/platform.h
index d63980fc65..5dac6762b5 100644
--- a/components/drivers/include/drivers/platform.h
+++ b/components/drivers/include/drivers/platform.h
@@ -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)
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index 863e9d8503..5b080fced7 100644
--- a/components/drivers/include/rtdevice.h
+++ b/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_domain.h"
#include "drivers/platform.h"
#ifdef RT_USING_OFW
diff --git a/components/drivers/ofw/ofw.c b/components/drivers/ofw/ofw.c
index 1f30bd98f9..d09fb4e7ca 100644
--- a/components/drivers/ofw/ofw.c
+++ b/components/drivers/ofw/ofw.c
@@ -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;
diff --git a/include/rtdef.h b/include/rtdef.h
index 72b61de7aa..3e48a137f6 100644
--- a/include/rtdef.h
+++ b/include/rtdef.h
@@ -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 */