diff --git a/components/drivers/core/bus.c b/components/drivers/core/bus.c index 0717d48649..13e154f40c 100644 --- a/components/drivers/core/bus.c +++ b/components/drivers/core/bus.c @@ -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 -#include #include #include @@ -19,16 +18,6 @@ #define DBG_LVL DBG_INFO #include -#ifdef RT_USING_DM -#include - -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 + +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; } diff --git a/components/drivers/core/dm.c b/components/drivers/core/dm.c index c8a7792d64..ecae24945c 100644 --- a/components/drivers/core/dm.c +++ b/components/drivers/core/dm.c @@ -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 +#ifdef RT_USING_OFW +#include +#include +#endif #include #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; +} + diff --git a/components/drivers/core/platform.c b/components/drivers/core/platform.c index e6d62817ab..18c044f6c4 100644 --- a/components/drivers/core/platform.c +++ b/components/drivers/core/platform.c @@ -11,6 +11,10 @@ #include +#define DBG_TAG "rtdm.pltaform" +#define DBG_LVL DBG_INFO +#include + #include #include #include @@ -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; } diff --git a/components/drivers/core/platform_ofw.c b/components/drivers/core/platform_ofw.c index 4496f2370e..408dec9dc7 100644 --- a/components/drivers/core/platform_ofw.c +++ b/components/drivers/core/platform_ofw.c @@ -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 +#include +#include #include #include +#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 { diff --git a/components/drivers/include/drivers/core/bus.h b/components/drivers/include/drivers/core/bus.h index 4a010d797d..ab821240bb 100644 --- a/components/drivers/include/drivers/core/bus.h +++ b/components/drivers/include/drivers/core/bus.h @@ -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); diff --git a/components/drivers/include/drivers/core/dm.h b/components/drivers/include/drivers/core/dm.h index f016906499..94821fe395 100644 --- a/components/drivers/include/drivers/core/dm.h +++ b/components/drivers/include/drivers/core/dm.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -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__ */ diff --git a/components/drivers/include/drivers/core/driver.h b/components/drivers/include/drivers/core/driver.h index 75608e2732..f576c812af 100644 --- a/components/drivers/include/drivers/core/driver.h +++ b/components/drivers/include/drivers/core/driver.h @@ -13,13 +13,14 @@ #include -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); diff --git a/components/drivers/include/drivers/ofw.h b/components/drivers/include/drivers/ofw.h index c760cf7e83..4ee2049e8f 100644 --- a/components/drivers/include/drivers/ofw.h +++ b/components/drivers/include/drivers/ofw.h @@ -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) diff --git a/components/drivers/include/drivers/ofw_fdt.h b/components/drivers/include/drivers/ofw_fdt.h index a9c951ca40..4db4ecef6b 100755 --- a/components/drivers/include/drivers/ofw_fdt.h +++ b/components/drivers/include/drivers/ofw_fdt.h @@ -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, _) = \ diff --git a/components/drivers/include/drivers/ofw_io.h b/components/drivers/include/drivers/ofw_io.h index 5fdfe8f5e6..4ebfbe2c82 100755 --- a/components/drivers/include/drivers/ofw_io.h +++ b/components/drivers/include/drivers/ofw_io.h @@ -11,6 +11,7 @@ #ifndef __OFW_IO_H__ #define __OFW_IO_H__ +#include #include int rt_ofw_bus_addr_cells(struct rt_ofw_node *np); diff --git a/components/drivers/include/drivers/platform.h b/components/drivers/include/drivers/platform.h index 9ea1c9803a..d63980fc65 100644 --- a/components/drivers/include/drivers/platform.h +++ b/components/drivers/include/drivers/platform.h @@ -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__ */ diff --git a/components/drivers/ofw/base.c b/components/drivers/ofw/base.c index d8c33033a3..8b081bc9d4 100644 --- a/components/drivers/ofw/base.c +++ b/components/drivers/ofw/base.c @@ -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 #include #include @@ -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; diff --git a/components/drivers/ofw/fdt.c b/components/drivers/ofw/fdt.c old mode 100755 new mode 100644 index 8745fbc993..9f65436d7d --- a/components/drivers/ofw/fdt.c +++ b/components/drivers/ofw/fdt.c @@ -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; diff --git a/components/drivers/ofw/io.c b/components/drivers/ofw/io.c index b5d6b58425..5f4892c148 100755 --- a/components/drivers/ofw/io.c +++ b/components/drivers/ofw/io.c @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -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, ®s[0], ®s[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, ®s[0], ®s[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]); } } diff --git a/components/drivers/ofw/ofw.c b/components/drivers/ofw/ofw.c old mode 100755 new mode 100644 index cd9532349d..c66724c7b7 --- a/components/drivers/ofw/ofw.c +++ b/components/drivers/ofw/ofw.c @@ -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; diff --git a/components/drivers/ofw/ofw_internal.h b/components/drivers/ofw/ofw_internal.h index b8bffe41c4..f536b382ca 100755 --- a/components/drivers/ofw/ofw_internal.h +++ b/components/drivers/ofw/ofw_internal.h @@ -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__ */ diff --git a/include/rtdef.h b/include/rtdef.h index 0e3601090a..7599e73983 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -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