[drivers][core] 完善设备模型 (#8384)

This commit is contained in:
fangjianzhou 2024-01-09 23:10:42 +08:00 committed by GitHub
parent cc157baf23
commit 10b16273b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1303 additions and 248 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -10,7 +10,6 @@
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
#include <stdlib.h>
@ -19,16 +18,6 @@
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifdef RT_USING_DM
#include <drivers/core/bus.h>
static struct rt_bus bus_root =
{
.name = "root",
.children = RT_LIST_OBJECT_INIT(bus_root.children),
};
#endif
#ifdef RT_USING_DEV_BUS
#if defined(RT_USING_POSIX_DEVIO)
@ -95,12 +84,19 @@ rt_err_t rt_device_bus_destroy(rt_device_t dev)
#endif
#ifdef RT_USING_DM
/**
* @brief This function get the root bus
*/
rt_bus_t rt_bus_root(void)
#include <drivers/core/bus.h>
static struct rt_spinlock bus_lock = {};
static rt_list_t bus_nodes = RT_LIST_OBJECT_INIT(bus_nodes);
static void _dm_bus_lock(struct rt_spinlock *spinlock)
{
return &bus_root;
rt_hw_spin_lock(&spinlock->lock);
}
static void _dm_bus_unlock(struct rt_spinlock *spinlock)
{
rt_hw_spin_unlock(&spinlock->lock);
}
/**
@ -108,30 +104,43 @@ rt_bus_t rt_bus_root(void)
*
* @param bus the target bus
*
* @param drv the target drv to be matched
* @param data the data push when call fn
*
* @param fn the function callback in each loop
*
* @return the error code, RT_EOK on added successfully.
*/
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_t drv, rt_device_t dev))
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, void *data, int (*fn)(rt_device_t dev, void *))
{
rt_base_t level;
rt_device_t dev;
rt_err_t err = -RT_EEMPTY;
rt_list_t *dev_list;
struct rt_spinlock *dev_lock;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(drv != RT_NULL);
level = rt_spin_lock_irqsave(&bus->spinlock);
dev_list = &bus->dev_list;
dev_lock = &bus->dev_lock;
rt_list_for_each_entry(dev, &bus->dev_list, node)
_dm_bus_lock(dev_lock);
dev = rt_list_entry(dev_list->next, struct rt_device, node);
_dm_bus_unlock(dev_lock);
while (&dev->node != dev_list)
{
fn(drv, dev);
if (!fn(dev, data))
{
err = RT_EOK;
break;
}
_dm_bus_lock(dev_lock);
dev = rt_list_entry(dev->node.next, struct rt_device, node);
_dm_bus_unlock(dev_lock);
}
rt_spin_unlock_irqrestore(&bus->spinlock, level);
return RT_EOK;
return err;
}
/**
@ -139,104 +148,97 @@ rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_
*
* @param bus the target bus
*
* @param dev the target dev to be matched
* @param data the data push when call fn
*
* @param fn the function callback in each loop
*
* @return the error code, RT_EOK on added successfully.
*/
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_t drv, rt_device_t dev))
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, void *data, int (*fn)(rt_driver_t drv, void *))
{
rt_err_t err;
rt_base_t level;
rt_driver_t drv;
rt_err_t err = -RT_EEMPTY;
rt_list_t *drv_list;
struct rt_spinlock *drv_lock;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(dev != RT_NULL);
if (rt_list_isempty(&bus->drv_list))
drv_list = &bus->drv_list;
drv_lock = &bus->drv_lock;
_dm_bus_lock(drv_lock);
drv = rt_list_entry(drv_list->next, struct rt_driver, node);
_dm_bus_unlock(drv_lock);
while (&drv->node != drv_list)
{
return RT_EOK;
}
err = -RT_ERROR;
level = rt_spin_lock_irqsave(&bus->spinlock);
rt_list_for_each_entry(drv, &bus->drv_list, node)
{
if (fn(drv, dev))
if (!fn(drv, data))
{
err = -RT_EOK;
err = RT_EOK;
break;
}
}
rt_spin_unlock_irqrestore(&bus->spinlock, level);
_dm_bus_lock(drv_lock);
drv = rt_list_entry(drv->node.next, struct rt_driver, node);
_dm_bus_unlock(drv_lock);
}
return err;
}
/**
* @brief This function add a bus to the root
*
* @param bus_node the bus to be added
*
* @return the error code, RT_EOK on added successfully.
*/
rt_err_t rt_bus_add(rt_bus_t bus_node)
static rt_err_t bus_probe(rt_driver_t drv, rt_device_t dev)
{
rt_base_t level;
RT_ASSERT(bus_node != RT_NULL);
bus_node->bus = &bus_root;
rt_list_init(&bus_node->list);
level = rt_spin_lock_irqsave(&bus_node->spinlock);
rt_list_insert_before(&bus_root.children, &bus_node->list);
rt_spin_unlock_irqrestore(&bus_node->spinlock, level);
return RT_EOK;
}
/**
* @brief This function match the device and driver, probe them if match successed
*
* @param drv the drv to match/probe
*
* @param dev the dev to match/probe
*
* @return the result of probe, 1 on added successfully.
*/
static int rt_bus_probe(rt_driver_t drv, rt_device_t dev)
{
int ret = 0;
rt_bus_t bus = drv->bus;
rt_err_t err = -RT_EEMPTY;
if (!bus)
{
bus = dev->bus;
}
RT_ASSERT(bus != RT_NULL);
if (!dev->drv && bus->match(drv, dev))
{
dev->drv = drv;
ret = bus->probe(dev);
err = bus->probe(dev);
if (ret)
if (err)
{
dev->drv = RT_NULL;
}
}
return ret;
return err;
}
static int bus_probe_driver(rt_device_t dev, void *drv_ptr)
{
bus_probe(drv_ptr, dev);
/*
* The driver is shared by multiple devices,
* so we always return the '1' to enumerate all devices.
*/
return 1;
}
static int bus_probe_device(rt_driver_t drv, void *dev_ptr)
{
rt_err_t err;
err = bus_probe(drv, dev_ptr);
if (!err)
{
rt_bus_t bus = drv->bus;
_dm_bus_lock(&bus->drv_lock);
++drv->ref_count;
_dm_bus_unlock(&bus->drv_lock);
}
return err;
}
/**
@ -250,20 +252,17 @@ static int rt_bus_probe(rt_driver_t drv, rt_device_t dev)
*/
rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv)
{
rt_base_t level;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(drv != RT_NULL);
drv->bus = bus;
rt_list_init(&drv->node);
level = rt_spin_lock_irqsave(&bus->spinlock);
_dm_bus_lock(&bus->drv_lock);
rt_list_insert_before(&bus->drv_list, &drv->node);
_dm_bus_unlock(&bus->drv_lock);
rt_spin_unlock_irqrestore(&bus->spinlock, level);
rt_bus_for_each_dev(drv->bus, drv, rt_bus_probe);
rt_bus_for_each_dev(bus, drv, bus_probe_driver);
return RT_EOK;
}
@ -279,20 +278,17 @@ rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv)
*/
rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev)
{
rt_base_t level;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(dev != RT_NULL);
dev->bus = bus;
rt_list_init(&dev->node);
level = rt_spin_lock_irqsave(&bus->spinlock);
_dm_bus_lock(&bus->dev_lock);
rt_list_insert_before(&bus->dev_list, &dev->node);
_dm_bus_unlock(&bus->dev_lock);
rt_spin_unlock_irqrestore(&bus->spinlock, level);
rt_bus_for_each_drv(dev->bus, dev, rt_bus_probe);
rt_bus_for_each_drv(bus, dev, bus_probe_device);
return RT_EOK;
}
@ -306,13 +302,31 @@ rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev)
*/
rt_err_t rt_bus_remove_driver(rt_driver_t drv)
{
rt_err_t err;
rt_bus_t bus;
RT_ASSERT(drv != RT_NULL);
RT_ASSERT(drv->bus != RT_NULL);
LOG_D("Bus(%s) remove driver %s", drv->bus->name, drv->name);
bus = drv->bus;
rt_list_remove(&drv->node);
LOG_D("Bus(%s) remove driver %s", bus->name, drv->parent.name);
return RT_EOK;
_dm_bus_lock(&bus->drv_lock);
if (drv->ref_count)
{
err = -RT_EBUSY;
}
else
{
rt_list_remove(&drv->node);
err = RT_EOK;
}
_dm_bus_unlock(&bus->drv_lock);
return err;
}
/**
@ -324,13 +338,104 @@ rt_err_t rt_bus_remove_driver(rt_driver_t drv)
*/
rt_err_t rt_bus_remove_device(rt_device_t dev)
{
rt_bus_t bus;
rt_driver_t drv;
rt_err_t err = RT_EOK;
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(dev->bus != RT_NULL);
LOG_D("Bus(%s) remove device %s", dev->bus->name, dev->name);
bus = dev->bus;
drv = dev->drv;
LOG_D("Bus(%s) remove device %s", bus->name, dev->parent.name);
_dm_bus_lock(&bus->dev_lock);
rt_list_remove(&dev->node);
_dm_bus_unlock(&bus->dev_lock);
return RT_EOK;
if (dev->bus->remove)
{
err = dev->bus->remove(dev);
}
else if (drv)
{
if (drv->shutdown)
{
err = drv->shutdown(dev);
}
/* device and driver are in the same bus */
_dm_bus_lock(&bus->drv_lock);
--drv->ref_count;
_dm_bus_unlock(&bus->drv_lock);
}
return err;
}
struct bus_shutdown_info
{
rt_bus_t bus;
rt_err_t err;
};
static int device_shutdown(rt_device_t dev, void *info_ptr)
{
rt_bus_t bus;
rt_err_t err = RT_EOK;
struct bus_shutdown_info *info = info_ptr;
bus = info->bus;
if (bus->shutdown)
{
LOG_D("Device(%s) shutdown", dev->parent.name);
err = bus->shutdown(dev);
LOG_D(" Result: %s", rt_strerror(err));
}
else if (dev->drv && dev->drv->shutdown)
{
LOG_D("Device(%s) shutdown", dev->parent.name);
err = dev->drv->shutdown(dev);
LOG_D(" Result: %s", rt_strerror(err));
}
if (err)
{
/* Only get the last one while system not crash */
info->err = err;
}
/* Go on, we want to ask all devices to shutdown */
return 1;
}
/**
* @brief This function call all buses' shutdown
*
* @return the error code, RT_EOK on shutdown successfully.
*/
rt_err_t rt_bus_shutdown(void)
{
rt_bus_t bus = RT_NULL;
struct bus_shutdown_info info =
{
.err = RT_EOK,
};
_dm_bus_lock(&bus_lock);
rt_list_for_each_entry(bus, &bus_nodes, list)
{
info.bus = bus;
rt_bus_for_each_dev(bus, &info, device_shutdown);
}
_dm_bus_unlock(&bus_lock);
return info.err;
}
/**
@ -339,24 +444,24 @@ rt_err_t rt_bus_remove_device(rt_device_t dev)
*
* @return the bus finded by name.
*/
rt_bus_t rt_bus_find_by_name(char *name)
rt_bus_t rt_bus_find_by_name(const char *name)
{
rt_bus_t bus = RT_NULL;
struct rt_list_node *node = RT_NULL;
if (!rt_list_isempty(&bus_root.children))
RT_ASSERT(name != RT_NULL);
_dm_bus_lock(&bus_lock);
rt_list_for_each_entry(bus, &bus_nodes, list)
{
rt_list_for_each(node, &bus_root.children)
if (!rt_strncmp(bus->name, name, RT_NAME_MAX))
{
bus = rt_list_entry(node, struct rt_bus, list);
if (!rt_strncmp(bus->name, name, RT_NAME_MAX))
{
return bus;
}
break;
}
}
_dm_bus_unlock(&bus_lock);
return bus;
}
@ -371,22 +476,20 @@ rt_bus_t rt_bus_find_by_name(char *name)
*/
rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev)
{
rt_base_t level;
rt_bus_t old_bus;
RT_ASSERT(new_bus != RT_NULL);
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(dev->bus != RT_NULL);
RT_ASSERT(dev->bus != new_bus);
level = rt_spin_lock_irqsave(&new_bus->spinlock);
old_bus = dev->bus;
_dm_bus_lock(&old_bus->dev_lock);
rt_list_remove(&dev->node);
rt_list_insert_before(&new_bus->dev_list, &dev->node);
_dm_bus_unlock(&old_bus->dev_lock);
rt_list_remove(&dev->drv->node);
rt_list_insert_before(&new_bus->drv_list, &dev->drv->node);
rt_spin_unlock_irqrestore(&new_bus->spinlock, level);
return RT_EOK;
return rt_bus_add_device(new_bus, dev);
}
/**
@ -397,13 +500,20 @@ rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev)
*/
rt_err_t rt_bus_register(rt_bus_t bus)
{
rt_list_init(&bus->children);
RT_ASSERT(bus != RT_NULL);
rt_list_init(&bus->list);
rt_list_init(&bus->dev_list);
rt_list_init(&bus->drv_list);
rt_spin_lock_init(&bus->spinlock);
rt_spin_lock_init(&bus->dev_lock);
rt_spin_lock_init(&bus->drv_lock);
rt_bus_add(bus);
_dm_bus_lock(&bus_lock);
rt_list_insert_before(&bus_nodes, &bus->list);
_dm_bus_unlock(&bus_lock);
return RT_EOK;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -10,6 +10,10 @@
#include <rtthread.h>
#ifdef RT_USING_OFW
#include <drivers/ofw_io.h>
#include <drivers/ofw_irq.h>
#endif
#include <drivers/core/dm.h>
#ifdef RT_USING_SMP
@ -56,10 +60,10 @@ struct prefix_track
int uid;
const char *prefix;
};
static struct rt_spinlock _prefix_nodes_lock;
static struct rt_spinlock _prefix_nodes_lock = { 0 };
static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes);
int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix)
int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix)
{
int uid = -1;
struct prefix_track *pt = RT_NULL;
@ -104,17 +108,17 @@ int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix)
rt_spin_unlock(&_prefix_nodes_lock);
}
return rt_dm_set_dev_name(dev, "%s%u", prefix, uid);
return rt_dm_dev_set_name(dev, "%s%u", prefix, uid);
}
int rt_dm_get_dev_name_id(rt_device_t dev)
int rt_dm_dev_get_name_id(rt_device_t dev)
{
int id = 0, len;
const char *name;
RT_ASSERT(dev != RT_NULL);
name = rt_dm_get_dev_name(dev);
name = rt_dm_dev_get_name(dev);
len = rt_strlen(name) - 1;
name += len;
@ -137,7 +141,7 @@ int rt_dm_get_dev_name_id(rt_device_t dev)
return id;
}
int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...)
int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...)
{
int n;
va_list arg_ptr;
@ -152,9 +156,314 @@ int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...)
return n;
}
const char *rt_dm_get_dev_name(rt_device_t dev)
const char *rt_dm_dev_get_name(rt_device_t dev)
{
RT_ASSERT(dev != RT_NULL);
return dev->parent.name;
}
#ifdef RT_USING_OFW
#define ofw_api_call(name, ...) rt_ofw_##name(__VA_ARGS__)
#define ofw_api_call_ptr(name, ...) ofw_api_call(name, __VA_ARGS__)
#else
#define ofw_api_call(name, ...) (-RT_ENOSYS)
#define ofw_api_call_ptr(name, ...) RT_NULL
#endif
int rt_dm_dev_get_address_count(rt_device_t dev)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_address_count, dev->ofw_node);
}
#endif
return -RT_ENOSYS;
}
rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
rt_uint64_t *out_address, rt_uint64_t *out_size)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_address, dev->ofw_node, index,
out_address, out_size);
}
#endif
return -RT_ENOSYS;
}
rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
rt_uint64_t *out_address, rt_uint64_t *out_size)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_address_by_name, dev->ofw_node, name,
out_address, out_size);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_address_array, dev->ofw_node, nr, out_regs);
}
#endif
return -RT_ENOSYS;
}
void *rt_dm_dev_iomap(rt_device_t dev, int index)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call_ptr(iomap, dev->ofw_node, index);
}
#endif
return RT_NULL;
}
void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call_ptr(iomap_by_name, dev->ofw_node, name);
}
#endif
return RT_NULL;
}
int rt_dm_dev_get_irq_count(rt_device_t dev)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_irq_count, dev->ofw_node);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_get_irq(rt_device_t dev, int index)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_irq, dev->ofw_node, index);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(get_irq_by_name, dev->ofw_node, name);
}
#endif
return -RT_ENOSYS;
}
void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (!dev->ofw_node && fw_np)
{
dev->ofw_node = fw_np;
rt_ofw_data(fw_np) = data;
}
if (dev->ofw_node == RT_NULL)
{
rt_kprintf("[%s:%s] line=%d ofw_node is NULL\r\n", __FILE__, __func__, __LINE__);
return;
}
rt_ofw_data(dev->ofw_node) = data;
#endif
}
void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np)
{
RT_ASSERT(dev!= RT_NULL);
#ifdef RT_USING_OFW
void *dev_fw_np;
if (!dev->ofw_node && fw_np)
{
dev_fw_np = fw_np;
rt_ofw_data(fw_np) = RT_NULL;
}
if (dev_fw_np == RT_NULL)
{
rt_kprintf("[%s:%s] line=%d dev_fw_np is NULL\r\n", __FILE__, __func__, __LINE__);
return;
}
rt_ofw_data(dev_fw_np) = RT_NULL;
#endif
}
int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint8_t *out_values)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_UISNG_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_read_u8_array_index, dev->ofw_node, propname,
index, nr, out_value);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint16_t *out_values)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_read_u16_array_index, dev->ofw_node, propname,
index, nr, out_values);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint32_t *out_values)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_read_u32_array_index, dev->ofw_node, propname,
index, nr, out_values);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint64_t *out_values)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_read_u64_array_index, dev->ofw_node, propname,
index, nr, out_values);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname,
int index, int nr, const char **out_strings)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_read_string_array_index, dev->ofw_node, propname,
index, nr, out_strings);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_count_of_size, dev->ofw_node, propname, size);
}
#endif
return -RT_ENOSYS;
}
int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_index_of_string, dev->ofw_node, propname, string);
}
#endif
return -RT_ENOSYS;
}
rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname)
{
RT_ASSERT(dev != RT_NULL);
#ifdef RT_USING_OFW
if (dev->ofw_node)
{
return ofw_api_call(prop_read_bool, dev->ofw_node, propname);
}
#endif
return RT_FALSE;
}

View File

@ -11,6 +11,10 @@
#include <rtthread.h>
#define DBG_TAG "rtdm.pltaform"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include <drivers/platform.h>
#include <drivers/core/bus.h>
#include <drivers/core/dm.h>
@ -28,6 +32,11 @@ struct rt_platform_device *rt_platform_device_alloc(const char *name)
{
struct rt_platform_device *pdev = rt_calloc(1, sizeof(*pdev));
if (!pdev)
{
return RT_NULL;
}
pdev->parent.bus = &platform_bus;
pdev->name = name;
@ -44,7 +53,11 @@ rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv)
RT_ASSERT(pdrv != RT_NULL);
pdrv->parent.bus = &platform_bus;
#if RT_NAME_MAX > 0
rt_strcpy(pdrv->parent.parent.name, pdrv->name);
#else
pdrv->parent.parent.name = pdrv->name;
#endif
return rt_driver_register(&pdrv->parent);
}
@ -67,20 +80,22 @@ static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev)
#ifdef RT_USING_OFW
struct rt_ofw_node *np = dev->ofw_node;
#endif
#ifdef RT_USING_OFW
/* 1、match with ofw node */
if (np)
{
/* 1、match with ofw node */
pdev->id = rt_ofw_node_match(np, pdrv->ids);
return !!pdev->id;
if (pdev->id)
{
return RT_TRUE;
}
}
#endif
/* 2、match with name */
if (pdev->name && pdrv->name)
{
/* 2、match with name */
if (pdev->name == pdrv->name)
{
return RT_TRUE;
@ -97,7 +112,6 @@ static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev)
static rt_err_t platform_probe(rt_device_t dev)
{
rt_err_t err;
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);
#ifdef RT_USING_OFW
@ -106,22 +120,22 @@ static rt_err_t platform_probe(rt_device_t dev)
err = pdrv->probe(pdev);
#ifdef RT_USING_OFW
if (!err)
{
#ifdef RT_USING_OFW
if (np)
{
rt_ofw_node_set_flag(np, RT_OFW_F_READLY);
}
#endif
}
else
{
if (np)
if (err == -RT_ENOMEM)
{
rt_ofw_data(np) = &pdev->parent;
LOG_W("System not memory in driver %s", pdrv->name);
}
}
#endif
return err;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -14,9 +14,13 @@
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include <drivers/ofw_io.h>
#include <drivers/ofw_fdt.h>
#include <drivers/platform.h>
#include <drivers/core/dm.h>
#include "../ofw/ofw_internal.h"
static const struct rt_ofw_node_id platform_ofw_ids[] =
{
{ .compatible = "simple-bus", },
@ -36,10 +40,76 @@ static const struct rt_ofw_node_id platform_ofw_ids[] =
{ /* sentinel */ }
};
static void ofw_device_rename(struct rt_device *dev)
{
rt_uint32_t mask;
rt_uint64_t addr;
const char *dev_name = dev->parent.name;
struct rt_ofw_node *np = dev->ofw_node;
#if RT_NAME_MAX > 0
if (dev_name[0] == '\0')
{
dev_name = RT_NULL;
}
#endif
while (np->parent)
{
if (!rt_ofw_get_address(np, 0, &addr, RT_NULL))
{
const char *node_name = rt_fdt_node_name(np->full_name);
rt_size_t tag_len = strchrnul(node_name, '@') - node_name;
if (!rt_ofw_prop_read_u32(np, "mask", &mask))
{
rt_dm_dev_set_name(dev, dev_name ? "%lx.%x.%.*s:%s" : "%lx.%x.%.*s",
addr, __rt_ffs(mask) - 1, tag_len, node_name, dev_name);
}
else
{
rt_dm_dev_set_name(dev, dev_name ? "%lx.%.*s:%s" : "%lx.%.*s",
addr, tag_len, node_name, dev_name);
}
return;
}
rt_dm_dev_set_name(dev, dev_name ? "%s:%s" : "%s",
rt_fdt_node_name(np->full_name), dev_name);
np = np->parent;
}
}
static struct rt_platform_device *alloc_ofw_platform_device(struct rt_ofw_node *np)
{
struct rt_platform_device *pdev = rt_platform_device_alloc("");
if (pdev)
{
/* inc reference of dt-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);
}
else
{
LOG_E("Alloc device fail for %s", rt_ofw_node_full_name(np));
}
return pdev;
}
static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
{
rt_err_t err = RT_EOK;
struct rt_ofw_node *np, *child;
struct rt_ofw_node *np;
struct rt_platform_device *pdev;
rt_ofw_foreach_available_child_node(parent_np, np)
@ -48,6 +118,8 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
struct rt_ofw_node_id *id;
struct rt_ofw_prop *compat_prop = RT_NULL;
LOG_D("%s found in %s", np->full_name, parent_np->full_name);
/* Is system node or have driver */
if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) ||
rt_ofw_node_test_flag(np, RT_OFW_F_READLY))
@ -66,35 +138,32 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
id = rt_ofw_prop_match(compat_prop, platform_ofw_ids);
if (id && (child = rt_ofw_get_next_child(np, RT_NULL)))
if (id && np->child)
{
/* scan next level */
err = platform_ofw_device_probe_once(child);
rt_ofw_node_put(child);
err = platform_ofw_device_probe_once(np);
if (err)
{
rt_ofw_node_put(np);
LOG_E("%s bus probe fail", np->full_name);
break;
}
}
pdev = rt_platform_device_alloc(np->name);
pdev = alloc_ofw_platform_device(np);
if (!pdev)
{
rt_ofw_node_put(np);
err = -RT_ENOMEM;
break;
}
/* inc reference of dt-node */
rt_ofw_node_get(np);
rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM);
pdev->parent.ofw_node = np;
pdev->dev_id = ofw_alias_node_id(np);
LOG_D("%s register to bus", np->full_name);
rt_platform_device_register(pdev);
}
@ -102,18 +171,58 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
return err;
}
rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np)
{
rt_err_t err;
struct rt_ofw_node *parent = rt_ofw_get_parent(np);
if (parent && rt_strcmp(parent->name, "/") &&
rt_ofw_get_prop(np, "compatible", RT_NULL) &&
!rt_ofw_node_test_flag(np, RT_OFW_F_PLATFORM))
{
struct rt_platform_device *pdev = alloc_ofw_platform_device(np);
if (pdev)
{
err = rt_platform_device_register(pdev);
}
else
{
err = -RT_ENOMEM;
}
}
else
{
err = -RT_EINVAL;
}
rt_ofw_node_put(parent);
return err;
}
static int platform_ofw_device_probe(void)
{
rt_err_t err = RT_EOK;
struct rt_ofw_node *root_np;
struct rt_ofw_node *node;
root_np = rt_ofw_find_node_by_path("/");
if (root_np)
if (ofw_node_root)
{
err = platform_ofw_device_probe_once(root_np);
err = platform_ofw_device_probe_once(ofw_node_root);
rt_ofw_node_put(root_np);
rt_ofw_node_put(ofw_node_root);
if ((node = rt_ofw_find_node_by_path("/firmware")))
{
platform_ofw_device_probe_once(node);
rt_ofw_node_put(node);
}
if ((node = rt_ofw_get_child_by_compatible(ofw_node_chosen, "simple-framebuffer")))
{
platform_ofw_device_probe_once(node);
rt_ofw_node_put(node);
}
}
else
{

View File

@ -21,32 +21,32 @@ struct rt_bus
{
struct rt_object parent; /**< inherit from rt_object */
char *name;
struct rt_bus *bus;
const char *name;
rt_list_t list;
rt_list_t children;
rt_list_t dev_list;
rt_list_t drv_list;
struct rt_spinlock spinlock;
struct rt_spinlock dev_lock;
struct rt_spinlock drv_lock;
rt_bool_t (*match)(rt_driver_t drv, rt_device_t dev);
rt_err_t (*probe)(rt_device_t dev);
rt_err_t (*remove)(rt_device_t dev);
rt_err_t (*shutdown)(rt_device_t dev);
};
rt_bus_t rt_bus_root(void);
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, void *data, int (*fn)(rt_device_t dev, void *));
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, void *data, int (*fn)(rt_driver_t drv, void *));
rt_err_t rt_bus_for_each_dev(rt_bus_t bus, rt_driver_t drv, int (*fn)(rt_driver_t drv, rt_device_t dev));
rt_err_t rt_bus_for_each_drv(rt_bus_t bus, rt_device_t dev, int (*fn)(rt_driver_t drv, rt_device_t dev));
rt_err_t rt_bus_add(rt_bus_t bus);
rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv);
rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev);
rt_err_t rt_bus_remove_driver(rt_driver_t drv);
rt_err_t rt_bus_remove_device(rt_device_t dev);
rt_bus_t rt_bus_find_by_name(char *name);
rt_err_t rt_bus_shutdown(void);
rt_bus_t rt_bus_find_by_name(const char *name);
rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev);
rt_err_t rt_bus_register(rt_bus_t bus);

View File

@ -13,6 +13,7 @@
#include <rthw.h>
#include <rtdef.h>
#include <ioremap.h>
#include <drivers/misc.h>
#include <drivers/byteorder.h>
@ -26,10 +27,139 @@ extern int rt_hw_cpu_id(void);
void rt_dm_secondary_cpu_init(void);
int rt_dm_set_dev_name_auto(rt_device_t dev, const char *prefix);
int rt_dm_get_dev_name_id(rt_device_t dev);
int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix);
int rt_dm_dev_get_name_id(rt_device_t dev);
int rt_dm_set_dev_name(rt_device_t dev, const char *format, ...);
const char *rt_dm_get_dev_name(rt_device_t dev);
int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...);
const char *rt_dm_dev_get_name(rt_device_t dev);
int rt_dm_dev_get_address_count(rt_device_t dev);
rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
rt_uint64_t *out_address, rt_uint64_t *out_size);
rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
rt_uint64_t *out_address, rt_uint64_t *out_size);
int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs);
void *rt_dm_dev_iomap(rt_device_t dev, int index);
void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name);
int rt_dm_dev_get_irq_count(rt_device_t dev);
int rt_dm_dev_get_irq(rt_device_t dev, int index);
int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name);
void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data);
void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np);
int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint8_t *out_values);
int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint16_t *out_values);
int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint32_t *out_values);
int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint64_t *out_values);
int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname,
int index, int nr, const char **out_strings);
int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size);
int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string);
rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname);
rt_inline rt_err_t rt_dm_dev_prop_read_u8_index(rt_device_t dev, const char *propname,
int index, rt_uint8_t *out_value)
{
int nr = rt_dm_dev_prop_read_u8_array_index(dev, propname, index, 1, out_value);
return nr > 0 ? RT_EOK : (rt_err_t)nr;
}
rt_inline rt_err_t rt_dm_dev_prop_read_u16_index(rt_device_t dev, const char *propname,
int index, rt_uint16_t *out_value)
{
int nr = rt_dm_dev_prop_read_u16_array_index(dev, propname, index, 1, out_value);
return nr > 0 ? RT_EOK : (rt_err_t)nr;
}
rt_inline rt_err_t rt_dm_dev_prop_read_u32_index(rt_device_t dev, const char *propname,
int index, rt_uint32_t *out_value)
{
int nr = rt_dm_dev_prop_read_u32_array_index(dev, propname, index, 1, out_value);
return nr > 0 ? RT_EOK : (rt_err_t)nr;
}
rt_inline rt_err_t rt_dm_dev_prop_read_u64_index(rt_device_t dev, const char *propname,
int index, rt_uint64_t *out_value)
{
int nr = rt_dm_dev_prop_read_u64_array_index(dev, propname, index, 1, out_value);
return nr > 0 ? RT_EOK : (rt_err_t)nr;
}
rt_inline rt_err_t rt_dm_dev_prop_read_string_index(rt_device_t dev, const char *propname,
int index, const char **out_string)
{
int nr = rt_dm_dev_prop_read_string_array_index(dev, propname, index, 1, out_string);
return nr > 0 ? RT_EOK : (rt_err_t)nr;
}
rt_inline rt_err_t rt_dm_dev_prop_read_u8(rt_device_t dev, const char *propname,
rt_uint8_t *out_value)
{
return rt_dm_dev_prop_read_u8_index(dev, propname, 0, out_value);
}
rt_inline rt_err_t rt_dm_dev_prop_read_u16(rt_device_t dev, const char *propname,
rt_uint16_t *out_value)
{
return rt_dm_dev_prop_read_u16_index(dev, propname, 0, out_value);
}
rt_inline rt_err_t rt_dm_dev_prop_read_u32(rt_device_t dev, const char *propname,
rt_uint32_t *out_value)
{
return rt_dm_dev_prop_read_u32_index(dev, propname, 0, out_value);
}
rt_inline rt_err_t rt_dm_dev_prop_read_s32(rt_device_t dev, const char *propname,
rt_int32_t *out_value)
{
return rt_dm_dev_prop_read_u32_index(dev, propname, 0, (rt_uint32_t *)out_value);
}
rt_inline rt_err_t rt_dm_dev_prop_read_u64(rt_device_t dev, const char *propname,
rt_uint64_t *out_value)
{
return rt_dm_dev_prop_read_u64_index(dev, propname, 0, out_value);
}
rt_inline rt_err_t rt_dm_dev_prop_read_string(rt_device_t dev, const char *propname,
const char **out_string)
{
return rt_dm_dev_prop_read_string_index(dev, propname, 0, out_string);
}
rt_inline int rt_dm_dev_prop_count_of_u8(rt_device_t dev, const char *propname)
{
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint8_t));
}
rt_inline int rt_dm_dev_prop_count_of_u16(rt_device_t dev, const char *propname)
{
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint16_t));
}
rt_inline int rt_dm_dev_prop_count_of_u32(rt_device_t dev, const char *propname)
{
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint32_t));
}
rt_inline int rt_dm_dev_prop_count_of_u64(rt_device_t dev, const char *propname)
{
return rt_dm_dev_prop_count_of_size(dev, propname, sizeof(rt_uint64_t));
}
#endif /* __RT_DM_H__ */

View File

@ -13,13 +13,14 @@
#include <rtdef.h>
struct rt_bus;
struct rt_driver
{
struct rt_object parent;
struct rt_bus *bus;
rt_list_t node;
rt_uint32_t ref_count;
#ifdef RT_USING_DEVICE_OPS
const struct rt_device_ops *dev_ops;
#else
@ -34,16 +35,10 @@ struct rt_driver
const struct filesystem_ops *fops;
const char *name;
int (*probe)(struct rt_device *dev);
int (*remove)(struct rt_device *dev);
void *priv;
int (*shutdown)(struct rt_device *dev);
};
typedef struct rt_driver* rt_driver_t;
int rt_driver_probe_device(struct rt_driver *drv, struct rt_device *dev);
rt_err_t rt_driver_register(rt_driver_t drv);
rt_err_t rt_driver_unregister(rt_driver_t drv);

View File

@ -205,11 +205,15 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id);
int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag);
int rt_ofw_get_alias_last_id(const char *tag);
struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name);
rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value);
struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index);
rt_err_t rt_ofw_parse_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name,
int index, struct rt_ofw_cell_args *out_args);
int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_name, const char *cells_name);
const char *rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name);
struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length);
rt_inline const void *rt_ofw_prop_read_raw(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length)

View File

@ -20,6 +20,7 @@ struct rt_fdt_earlycon
union { rt_ubase_t size, width; };
void *fdt;
char options[32];
long nodeoffset;
void *data;
@ -41,8 +42,6 @@ struct rt_fdt_earlycon_id
rt_err_t (*setup)(struct rt_fdt_earlycon *earlycon, const char *options);
};
#define RT_FDT_EARLYCON_OPTION_SIGNATURE '\n'
#define RT_FDT_EARLYCON_EXPORT(_name, _type, _compatible, _setup) \
static const struct rt_fdt_earlycon_id __rt_fdt_##_name##_earlycon \
rt_used RT_OFW_SYMBOL(earlycon, _) = \

View File

@ -11,6 +11,7 @@
#ifndef __OFW_IO_H__
#define __OFW_IO_H__
#include <ioremap.h>
#include <drivers/ofw.h>
int rt_ofw_bus_addr_cells(struct rt_ofw_node *np);

View File

@ -22,6 +22,8 @@ struct rt_platform_device
{
struct rt_device parent;
int dev_id;
const char *name;
#ifdef RT_USING_OFW
@ -42,6 +44,8 @@ struct rt_platform_driver
#endif
rt_err_t (*probe)(struct rt_platform_device *pdev);
rt_err_t (*remove)(struct rt_platform_device *pdev);
rt_err_t (*shutdown)(struct rt_platform_device *pdev);
};
struct rt_platform_device *rt_platform_device_alloc(const char *name);
@ -49,6 +53,8 @@ struct rt_platform_device *rt_platform_device_alloc(const char *name);
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);
#define RT_PLATFORM_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, platform, BUILIN)
#endif /* __PLATFORM_H__ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -8,7 +8,7 @@
* 2022-08-25 GuEe-GUI first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <drivers/ofw.h>
@ -28,7 +28,7 @@ struct rt_ofw_node *ofw_node_chosen = RT_NULL;
struct rt_ofw_node *ofw_node_aliases = RT_NULL;
struct rt_ofw_node *ofw_node_reserved_memory = RT_NULL;
static rt_phandle _phandle_range[2] = { 1, 1 };
static rt_phandle _phandle_range[2] = { 1, 1 }, _phandle_next = 1;
static struct rt_ofw_node **_phandle_hash = RT_NULL;
static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes);
@ -36,6 +36,7 @@ static rt_list_t _aliases_nodes = RT_LIST_OBJECT_INIT(_aliases_nodes);
rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
{
rt_err_t err = RT_EOK;
rt_phandle next = max;
struct rt_ofw_node **hash_ptr = RT_NULL;
max = RT_ALIGN(max, OFW_NODE_MIN_HASH);
@ -69,7 +70,7 @@ rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
_phandle_range[0] = min;
}
_phandle_range[1] = max;
_phandle_next = next + 1;
_phandle_hash = hash_ptr;
}
else
@ -80,6 +81,39 @@ rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max)
return err;
}
static rt_phandle ofw_phandle_next(void)
{
rt_phandle next;
static struct rt_spinlock op_lock = {};
rt_hw_spin_lock(&op_lock.lock);
RT_ASSERT(_phandle_next != OFW_PHANDLE_MAX);
if (_phandle_next <= _phandle_range[1])
{
next = _phandle_next++;
}
else
{
rt_err_t err = ofw_phandle_hash_reset(_phandle_range[0], _phandle_next);
if (!err)
{
next = _phandle_next++;
}
else
{
next = 0;
LOG_E("Expanded phandle hash[%u, %u] fail error = %s",
_phandle_range[0], _phandle_next + 1, rt_strerror(err));
}
}
rt_hw_spin_unlock(&op_lock.lock);
return next;
}
static void ofw_prop_destroy(struct rt_ofw_prop *prop)
{
struct rt_ofw_prop *next;
@ -230,6 +264,7 @@ static void ofw_node_release(struct rt_ref *r)
struct rt_ofw_node *np = rt_container_of(r, struct rt_ofw_node, ref);
LOG_E("%s is release", np->full_name);
(void)np;
RT_ASSERT(0);
}
@ -610,7 +645,7 @@ struct rt_ofw_node *rt_ofw_find_node_by_path(const char *path)
break;
}
path += len;
path += len + !!*next;
}
np = tmp;
@ -1031,9 +1066,9 @@ rt_err_t ofw_alias_scan(void)
continue;
}
end = name + rt_strlen(name);
end = name + rt_strlen(name) - 1;
while (*end && !(*end >= '0' && *end <= '9'))
while (*end && !(*end >= '0' && *end <= '9') && end > name)
{
--end;
}
@ -1043,7 +1078,7 @@ rt_err_t ofw_alias_scan(void)
id += (*end - '0') * rate;
rate *= 10;
--end;
++end;
}
info = rt_malloc(sizeof(*info));
@ -1058,7 +1093,7 @@ rt_err_t ofw_alias_scan(void)
info->id = id;
info->tag = name;
info->tag_len = end - name;
info->tag_len = end - name - 1;
info->np = tmp;
rt_list_insert_after(&_aliases_nodes, &info->list);
@ -1092,6 +1127,32 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id)
return np;
}
int ofw_alias_node_id(struct rt_ofw_node *np)
{
int id;
struct alias_info *info;
if (np)
{
id = -1;
rt_list_for_each_entry(info, &_aliases_nodes, list)
{
if (info->np == np)
{
id = info->id;
break;
}
}
}
else
{
id = -RT_EINVAL;
}
return id;
}
int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag)
{
int id;
@ -1153,6 +1214,109 @@ int rt_ofw_get_alias_last_id(const char *tag)
return id;
}
struct rt_ofw_node *rt_ofw_append_child(struct rt_ofw_node *parent, const char *full_name)
{
rt_phandle phandle;
rt_err_t err = RT_EOK;
fdt32_t *phandle_value;
struct rt_ofw_node *np = RT_NULL, *child;
if (full_name)
{
if ((phandle = ofw_phandle_next()))
{
np = rt_calloc(1, sizeof(*np) + sizeof(*phandle_value));
}
}
if (np)
{
parent = parent ? : ofw_node_root;
np->full_name = full_name;
np->phandle = phandle;
np->parent = parent;
rt_ref_init(&np->ref);
phandle_value = (void *)np + sizeof(*np);
*phandle_value = cpu_to_fdt32(phandle);
err = rt_ofw_append_prop(np, "phandle", sizeof(*phandle_value), phandle_value);
if (!err)
{
if (parent->child)
{
rt_ofw_foreach_child_node(parent, child)
{
if (!child->sibling)
{
child->sibling = np;
rt_ofw_node_put(child);
break;
}
}
}
else
{
parent->child = np;
}
}
else
{
rt_free(np);
np = RT_NULL;
}
}
return np;
}
rt_err_t rt_ofw_append_prop(struct rt_ofw_node *np, const char *name, int length, void *value)
{
rt_err_t err = RT_EOK;
if (np && name && ((length && value) || (!length && !value)))
{
struct rt_ofw_prop *prop = rt_malloc(sizeof(*prop)), *last_prop;
if (prop)
{
prop->name = name;
prop->length = length;
prop->value = value;
prop->next = RT_NULL;
if (np->props)
{
rt_ofw_foreach_prop(np, last_prop)
{
if (!last_prop->next)
{
last_prop->next = prop;
break;
}
}
}
else
{
np->props = prop;
}
}
else
{
err = -RT_ENOMEM;
}
}
else
{
err = -RT_EINVAL;
}
return err;
}
struct rt_ofw_node *rt_ofw_parse_phandle(const struct rt_ofw_node *np, const char *phandle_name, int index)
{
struct rt_ofw_cell_args args;
@ -1296,6 +1460,170 @@ int rt_ofw_count_phandle_cells(const struct rt_ofw_node *np, const char *list_na
return count;
}
static const char *ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
{
char *sf, split_field[64];
rt_size_t len = 0, max_ak = 0;
const char *str, *result = RT_NULL;
RT_DECLARE_BITMAP(ak, sizeof(split_field));
struct rt_ofw_prop *prop;
/*
* List:
*
* node {
* property;
* front-prop-rear;
* front-prop;
* prop-rear;
* };
*
* if call:
* ofw_get_prop_fuzzy_name(node, name):
* ["prop"] => property
* ["-prop"] => front-prop-rear
* ["prop-"] => front-prop-rear
* ["-prop$"] => front-prop
* ["^prop-"] => prop-rear
* ["-prop-"] => front-prop-rear
* ["front-*-rear"] => front-prop-rear
*/
str = name;
sf = split_field;
if (str[0] != '^')
{
/* As '*' */
*sf++ = '\0';
rt_bitmap_set_bit(ak, len++);
}
else
{
++str;
}
for (; *str && len < sizeof(split_field); ++str, ++sf, ++len)
{
if (*str != '*')
{
*sf = *str;
rt_bitmap_clear_bit(ak, len);
}
else
{
max_ak = len;
*sf = '\0';
rt_bitmap_set_bit(ak, len);
}
}
*sf = '\0';
if (str[-1] != '$')
{
/* As '*' */
max_ak = len;
rt_bitmap_set_bit(ak, len++);
}
else
{
sf[-1] = '\0';
--len;
}
sf = split_field;
if (len >= sizeof(split_field))
{
LOG_W("%s fuzzy name = %s len is %d out of %d", np->full_name, name, rt_strlen(name), sizeof(split_field));
}
rt_ofw_foreach_prop(np, prop)
{
int prep_ak = 0, next_ak, field;
rt_bool_t match = RT_TRUE;
const char *propname = prop->name, *fuzzy_name = sf;
if (!rt_bitmap_test_bit(ak, prep_ak))
{
next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak) ? : len;
field = next_ak - prep_ak;
if (rt_strncmp(propname, fuzzy_name, field))
{
continue;
}
propname += field;
fuzzy_name += field;
prep_ak = next_ak;
}
rt_bitmap_for_each_set_bit_from(ak, prep_ak, next_ak, max_ak)
{
/* Skip the '*' */
if (prep_ak == next_ak)
{
++fuzzy_name;
next_ak = rt_bitmap_next_set_bit(ak, prep_ak + 1, max_ak);
}
if (!(str = rt_strstr(propname, fuzzy_name)))
{
match = RT_FALSE;
break;
}
field = next_ak - prep_ak;
propname = str + field - 1;
fuzzy_name += field;
prep_ak = next_ak;
}
if (match)
{
if ((max_ak || !split_field[0]) && next_ak >= max_ak && len - max_ak > 1)
{
if (next_ak == max_ak)
{
/* Skip the last '*' */
++fuzzy_name;
}
if (!(propname = rt_strstr(propname, fuzzy_name)))
{
continue;
}
/* Check end flag */
if (propname[len - max_ak - 1] != '\0')
{
continue;
}
}
result = prop->name;
break;
}
}
return result;
}
const char *rt_ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const char *name)
{
const char *propname = RT_NULL;
if (np && name)
{
propname = ofw_get_prop_fuzzy_name(np, name);
}
return propname;
}
struct rt_ofw_prop *rt_ofw_get_prop(const struct rt_ofw_node *np, const char *name, rt_ssize_t *out_length)
{
struct rt_ofw_prop *prop = RT_NULL;

50
components/drivers/ofw/fdt.c Executable file → Normal file
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -321,7 +321,7 @@ static rt_err_t fdt_reserved_memory_reg(int nodeoffset, const char *uname)
}
else
{
while (len >= t_len)
for (; len >= t_len; len -= t_len)
{
base = rt_fdt_next_cell(&prop, _root_addr_cells);
size = rt_fdt_next_cell(&prop, _root_size_cells);
@ -664,12 +664,17 @@ void rt_fdt_earlycon_kick(int why)
fdt_earlycon.console_kick(&fdt_earlycon, why);
}
if (why == FDT_EARLYCON_KICK_COMPLETED && fdt_earlycon.msg_idx)
if (why == FDT_EARLYCON_KICK_COMPLETED)
{
fdt_earlycon.msg_idx = 0;
fdt_earlycon.console_putc = RT_NULL;
/* Dump old messages */
rt_kputs(fdt_earlycon.msg);
if (fdt_earlycon.msg_idx)
{
fdt_earlycon.msg_idx = 0;
/* Dump old messages */
rt_kputs(fdt_earlycon.msg);
}
}
}
@ -787,6 +792,8 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
if (options && *options && *options != ' ')
{
options_len = strchrnul(options, ' ') - options;
rt_strncpy(fdt_earlycon.options, options, options_len);
}
/* console > stdout-path */
@ -824,7 +831,7 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
if (best_earlycon_id && best_earlycon_id->setup)
{
rt_bool_t used_options = RT_FALSE;
const char earlycon_magic[] = { 'O', 'F', 'W', '\0' };
if (!con_type)
{
@ -833,24 +840,25 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
fdt_earlycon.fdt = _fdt;
fdt_earlycon.nodeoffset = offset;
err = best_earlycon_id->setup(&fdt_earlycon, options);
options = &fdt_earlycon.options[options_len + 1];
rt_strncpy((void *)options, earlycon_magic, RT_ARRAY_SIZE(earlycon_magic));
for (int i = 0; i < options_len; ++i)
err = best_earlycon_id->setup(&fdt_earlycon, fdt_earlycon.options);
if (rt_strncmp(options, earlycon_magic, RT_ARRAY_SIZE(earlycon_magic)))
{
if (options[i] == RT_FDT_EARLYCON_OPTION_SIGNATURE)
const char *option_start = options - 1;
while (option_start[-1] != '\0')
{
/* Restore ',' */
((char *)options)[i++] = ',';
options = &options[i];
options_len -= i;
used_options = RT_TRUE;
break;
--option_start;
}
rt_memmove(fdt_earlycon.options, option_start, options - option_start);
}
if (!used_options)
else
{
options = RT_NULL;
options_len = 0;
fdt_earlycon.options[0] = '\0';
}
}
}
@ -877,8 +885,8 @@ rt_err_t rt_fdt_scan_chosen_stdout(void)
if (fdt_earlycon.mmio)
{
LOG_I("Earlycon: %s at MMIO/PIO %p (options '%.*s')",
con_type, fdt_earlycon.mmio, options_len, options ? options : "");
LOG_I("Earlycon: %s at MMIO/PIO %p (options '%s')",
con_type, fdt_earlycon.mmio, fdt_earlycon.options);
}
return err;

View File

@ -10,7 +10,6 @@
#include <rtthread.h>
#include <ioremap.h>
#include <drivers/ofw.h>
#include <drivers/ofw_io.h>
#include <drivers/ofw_fdt.h>
@ -155,7 +154,7 @@ static rt_err_t ofw_get_address_by_name(struct rt_ofw_node *np, const char *name
{
int index = 0;
rt_err_t err = RT_EOK;
rt_err_t err = -RT_EEMPTY;
const char *reg_name;
struct rt_ofw_prop *prop;
@ -386,6 +385,22 @@ rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_t
return cpu_addr;
}
#ifdef ARCH_CPU_64BIT
#define ofw_address_cpu_cast(np, address) (void *)(address)
#else
#define ofw_address_cpu_cast(np, address) \
({ \
if (((address) >> 32)) \
{ \
LOG_W("%s find 64 bits address = %x%x", \
rt_ofw_node_full_name(np), \
ofw_static_cast(rt_ubase_t, (address) >> 32), \
ofw_static_cast(rt_ubase_t, (address))); \
} \
(void *)ofw_static_cast(rt_ubase_t, (address)); \
})
#endif
void *rt_ofw_iomap(struct rt_ofw_node *np, int index)
{
void *iomem = RT_NULL;
@ -396,7 +411,7 @@ void *rt_ofw_iomap(struct rt_ofw_node *np, int index)
if (!ofw_get_address(np, index, &regs[0], &regs[1]))
{
iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]);
iomem = rt_ioremap(ofw_address_cpu_cast(np, regs[0]), (size_t)regs[1]);
}
}
@ -413,7 +428,7 @@ void *rt_ofw_iomap_by_name(struct rt_ofw_node *np, const char *name)
if (!ofw_get_address_by_name(np, name, &regs[0], &regs[1]))
{
iomem = rt_ioremap((void *)regs[0], (size_t)regs[1]);
iomem = rt_ioremap(ofw_address_cpu_cast(np, regs[0]), (size_t)regs[1]);
}
}

73
components/drivers/ofw/ofw.c Executable file → Normal file
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -85,6 +85,41 @@ static const char *ofw_console_serial_find(char *dst_con, struct rt_ofw_node *np
return ofw_name;
}
static int tty_device_compare(rt_device_t dev, void *data)
{
rt_ubase_t *args_list;
char *dst_con;
const char *console, **ofw_name;
const struct rt_ofw_node_id *id;
struct rt_platform_device *pdev;
int *tty_idx, tty_id, tty_name_len;
pdev = rt_container_of(dev, struct rt_platform_device, parent);
id = pdev->id;
args_list = data;
tty_idx = (int *)args_list[0];
tty_id = args_list[1];
console = (const char *)args_list[2];
tty_name_len = args_list[3];
dst_con = (char *)args_list[4];
ofw_name = (const char **)args_list[5];
if (id && id->type[0] && !strncmp(id->type, console, tty_name_len))
{
if (*tty_idx == tty_id)
{
*ofw_name = ofw_console_serial_find(dst_con, pdev->parent.ofw_node);
return RT_EOK;
}
++*tty_idx;
}
return -RT_EEMPTY;
}
static const char *ofw_console_tty_find(char *dst_con, const char *con)
{
const char *ofw_name = RT_NULL;
@ -97,8 +132,7 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con)
if (platform_bus)
{
rt_device_t dev;
rt_ubase_t level;
rt_ubase_t args_list[6];
const char *console = con;
int tty_idx = 0, tty_id = 0, tty_name_len;
@ -119,27 +153,13 @@ static const char *ofw_console_tty_find(char *dst_con, const char *con)
++con;
}
level = rt_spin_lock_irqsave(&platform_bus->spinlock);
rt_list_for_each_entry(dev, &platform_bus->dev_list, node)
{
struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent);
const struct rt_ofw_node_id *id = pdev->id;
if (id && id->type[0] && !rt_strncmp(id->type, console, tty_name_len))
{
if (tty_idx == tty_id)
{
ofw_name = ofw_console_serial_find(dst_con, pdev->parent.ofw_node);
break;
}
++tty_idx;
}
}
rt_spin_unlock_irqrestore(&platform_bus->spinlock, level);
args_list[0] = (rt_ubase_t)&tty_idx;
args_list[1] = tty_id;
args_list[2] = (rt_ubase_t)console;
args_list[3] = tty_name_len;
args_list[4] = (rt_ubase_t)dst_con;
args_list[5] = (rt_ubase_t)&ofw_name;
rt_bus_for_each_dev(platform_bus, &args_list, tty_device_compare);
}
return ofw_name;
@ -463,6 +483,11 @@ static void ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too)
dts_put_depth(depth);
rt_kputs("};\n");
if (!sibling_too && org_np == np)
{
break;
}
while (np->parent && !np->sibling)
{
np = np->parent;

View File

@ -68,6 +68,7 @@ extern struct rt_fdt_earlycon fdt_earlycon;
(to_type)(((value) >> ((sizeof(value) - sizeof(to_type)) * 8)))
rt_err_t ofw_alias_scan(void);
int ofw_alias_node_id(struct rt_ofw_node *np);
rt_err_t ofw_phandle_hash_reset(rt_phandle min, rt_phandle max);
#endif /* __OFW_INTERNAL_H__ */

View File

@ -1470,6 +1470,7 @@ enum rt_device_class_type
*/
#define RT_DEVICE_CTRL_BASE(Type) ((RT_Device_Class_##Type + 1) * 0x100)
typedef struct rt_driver *rt_driver_t;
typedef struct rt_device *rt_device_t;
#ifdef RT_USING_DEVICE_OPS