From 17ecb56cb517abdc37bee04ab32bd59d668302f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 2 Jan 2026 15:08:02 +0000 Subject: [PATCH] [documentation][device_driver_model] Add main DM documentation (EN/CN) Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com> --- .../device_driver_model/README.md | 670 ++++++++++++++++++ .../device_driver_model/README_zh.md | 670 ++++++++++++++++++ 2 files changed, 1340 insertions(+) create mode 100644 documentation/6.components/device-driver/device_driver_model/README.md create mode 100644 documentation/6.components/device-driver/device_driver_model/README_zh.md diff --git a/documentation/6.components/device-driver/device_driver_model/README.md b/documentation/6.components/device-driver/device_driver_model/README.md new file mode 100644 index 0000000000..43917d000c --- /dev/null +++ b/documentation/6.components/device-driver/device_driver_model/README.md @@ -0,0 +1,670 @@ +# RT-Thread Device Driver Model (DM) + +## Overview + +The RT-Thread Device Driver Model (DM) is a comprehensive framework that provides a standardized, hierarchical approach to managing hardware devices and their drivers. Enabled through the `RT_USING_DM` configuration option, it introduces a sophisticated device-driver matching mechanism, bus abstraction, and seamless integration with device tree (Open Firmware) support. + +The DM framework significantly enhances RT-Thread's capability to handle complex hardware systems, particularly those requiring dynamic device discovery, power management, clock control, and other hardware resource management. + +### Key Features + +- **Bus-Driver-Device Architecture**: Hierarchical organization of hardware components +- **Device Tree Integration**: Full Open Firmware (OFW) support for hardware description +- **Dynamic Device Management**: Runtime device discovery and driver binding +- **Resource Management**: Unified APIs for clocks, regulators, resets, power domains, etc. +- **Platform Device Model**: Abstraction for memory-mapped and non-discoverable devices +- **Reference Counting**: Safe resource lifecycle management +- **Extensible Framework**: Easy addition of new bus types and device classes + +## Architecture + +### Core Components + +The DM framework consists of several key components: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Application Layer │ +│ (Uses device APIs: clk, regulator, pinctrl, gpio, etc.) │ +└────────────────────┬────────────────────────────────────────┘ + │ +┌────────────────────┴────────────────────────────────────────┐ +│ Device Driver Model (DM) │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ Bus │ │ Driver │ │ Device │ │ Platform │ │ +│ │ Subsys │ │ Subsys │ │ Subsys │ │ Layer │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ OFW (Open Firmware/Device Tree) │ │ +│ │ - FDT parsing - Property reading - IRQ mapping │ │ +│ └──────────────────────────────────────────────────────┘ │ +└────────────────────┬────────────────────────────────────────┘ + │ +┌────────────────────┴────────────────────────────────────────┐ +│ Hardware Resources │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ Clocks │ │Regulator │ │ Resets │ │ GPIOs │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ Pinctrl │ │ DMA │ │ IRQs │ │ Memory │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +#### 1. Bus Subsystem + +The bus subsystem (`rt_bus`) provides the foundation for organizing devices and drivers: + +- **Bus Registration**: Buses are registered with the system and maintain lists of devices and drivers +- **Device-Driver Matching**: Each bus implements a match function to pair compatible drivers with devices +- **Probe/Remove**: Buses coordinate the lifecycle of device-driver bindings +- **Lock Management**: Thread-safe operations on device and driver lists + +**Key Structures**: +```c +struct rt_bus { + struct rt_object parent; + const char *name; + rt_list_t list; + rt_list_t dev_list; /* List of devices on this bus */ + rt_list_t drv_list; /* List of drivers on this bus */ + 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); +}; +``` + +#### 2. Driver Subsystem + +Drivers implement hardware-specific functionality and are bound to compatible devices: + +- **Driver Registration**: Drivers register with a specific bus +- **Device Operations**: Standard operations (init, open, close, read, write, control) +- **Probe/Remove Callbacks**: Initialization and cleanup when bound to devices +- **Reference Counting**: Tracks the number of active device bindings + +**Key Structures**: +```c +struct rt_driver { + struct rt_object parent; + struct rt_bus *bus; + rt_list_t node; + rt_uint32_t ref_count; + + /* Device operations */ + rt_err_t (*init)(rt_device_t dev); + rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag); + rt_err_t (*close)(rt_device_t dev); + rt_ssize_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); + rt_ssize_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); + rt_err_t (*control)(rt_device_t dev, int cmd, void *args); + + /* Lifecycle callbacks */ + int (*probe)(struct rt_device *dev); + int (*remove)(struct rt_device *dev); + int (*shutdown)(struct rt_device *dev); +}; +``` + +#### 3. Platform Device Model + +The platform device model is the most common usage of DM in RT-Thread, handling memory-mapped devices: + +- **Platform Bus**: A virtual bus for devices not on a physical bus +- **Device Tree Integration**: Automatic device creation from FDT nodes +- **Resource Abstraction**: Unified access to memory regions, IRQs, clocks, etc. +- **Driver Binding**: Automatic matching based on compatible strings + +**Key Structures**: +```c +struct rt_platform_device { + struct rt_device parent; + int dev_id; + const char *name; + const struct rt_ofw_node_id *id; + void *priv; +}; + +struct rt_platform_driver { + struct rt_driver parent; + const char *name; + const struct rt_ofw_node_id *ids; /* Compatible strings */ + + 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); +}; +``` + +#### 4. OFW (Open Firmware) Support + +The OFW subsystem provides device tree support: + +- **FDT Parsing**: Flattened Device Tree (FDT) binary format parsing +- **Device Node Management**: Hierarchical device tree node representation +- **Property Reading**: APIs to read device tree properties +- **Resource Mapping**: Translation of DT resources to system resources (IRQ, memory, etc.) + +### Device Lifecycle + +The typical lifecycle of a device in the DM framework: + +``` + Device Tree Platform Driver + │ │ │ + │ Parse DT │ │ + ├──────────────────>│ │ + │ │ │ + │ Create Platform │ │ + │ Device │ │ + │ │ │ + │ Register Device │ │ + │ on Platform Bus │ │ + │ │ │ + │ │ Match Device │ + │ │ with Driver │ + │ ├─────────────────>│ + │ │ │ + │ │ Driver Probe │ + │ │<─────────────────┤ + │ │ │ + │ │ Initialize HW │ + │ │ │ + │ │ Register APIs │ + │ │ │ + │ │ RUNNING │ + │ │ │ + │ │ Driver Remove │ + │ ├─────────────────>│ + │ │ │ + │ │ Cleanup │ + │ │<─────────────────┤ + │ │ │ +``` + +## Kconfig Configuration + +### Main DM Option + +The Device Driver Model is enabled through the main Kconfig option: + +```kconfig +config RT_USING_DM + bool "Enable device driver model with device tree" + default n + help + Enable device driver model with device tree (FDT). It will use more memory + to parse and support device tree feature. +``` + +**Location in menuconfig**: `RT-Thread Components → Device Drivers → Enable device driver model with device tree` + +### Related Options + +#### Device Bus +```kconfig +config RT_USING_DEV_BUS + bool "Using Device Bus device drivers" + default y if RT_USING_SMART + default n +``` + +#### Open Firmware (OFW) +```kconfig +menuconfig RT_USING_OFW + bool "Using Open Firmware (OFW)" + select RT_USING_ADT + select RT_USING_ADT_REF + select RT_USING_ADT_BITMAP + select RT_USING_MEMBLOCK + depends on RT_USING_DM + default n +``` + +**Location**: `RT-Thread Components → Device Drivers → Using Open Firmware (OFW)` + +#### Builtin FDT +```kconfig +config RT_USING_BUILTIN_FDT + bool "Using builtin fdt in kernel" + depends on RT_USING_OFW + default n + +config RT_BUILTIN_FDT_PATH + string "Builtin fdt path, will rebuild if have dts" + depends on RT_USING_BUILTIN_FDT + default "rtthread.dtb" +``` + +## Device Tree Integration + +### Device Tree Basics + +When `RT_USING_DM` and `RT_USING_OFW` are enabled, RT-Thread can parse and use device tree (FDT) to describe hardware: + +#### Example Device Tree Node + +```dts +/ { + compatible = "myboard,example"; + #address-cells = <1>; + #size-cells = <1>; + + clocks { + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + uart0: serial@10000000 { + compatible = "myvendor,uart"; + reg = <0x10000000 0x1000>; + interrupts = <32>; + clocks = <&osc24M>; + clock-names = "baudclk"; + status = "okay"; + }; + }; + + regulators { + vcc_3v3: regulator-vcc-3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; +``` + +### Using Device Tree in Drivers + +#### Getting Device Node + +```c +#include + +struct rt_ofw_node *np = dev->ofw_node; +``` + +#### Reading Properties + +```c +/* Read string property */ +const char *status; +rt_ofw_prop_read_string(np, "status", &status); + +/* Read u32 property */ +rt_uint32_t freq; +rt_ofw_prop_read_u32(np, "clock-frequency", &freq); + +/* Read array */ +rt_uint32_t reg[2]; +rt_ofw_prop_read_u32_array(np, "reg", reg, 2); +``` + +#### Getting Resources + +```c +/* Get memory resources */ +rt_uint64_t addr, size; +rt_dm_dev_get_address(dev, 0, &addr, &size); + +/* Get IRQ */ +int irq = rt_dm_dev_get_irq(dev, 0); + +/* Map MMIO */ +void *base = rt_dm_dev_iomap(dev, 0); + +/* Get clock */ +struct rt_clk *clk = rt_clk_get_by_name(dev, "baudclk"); +``` + +## DM-Dependent Modules + +The Device Driver Model supports numerous hardware subsystems. Each module provides standardized APIs for both application layer and driver implementation: + +| Module | Description | Documentation | +|--------|-------------|---------------| +| **clk** | Clock management framework | [clk.md](clk/README.md) | +| **regulator** | Voltage/current regulation | [regulator.md](regulator/README.md) | +| **pinctrl** | Pin multiplexing and configuration | [pinctrl.md](pinctrl/README.md) | +| **reset** | Reset controller management | [reset.md](reset/README.md) | +| **pmdomain** | Power domain management | [pmdomain.md](pmdomain/README.md) | +| **pic** | Platform interrupt controller | [pic.md](pic/README.md) | +| **nvmem** | Non-volatile memory framework | [nvmem.md](nvmem/README.md) | +| **mailbox** | Mailbox/doorbell communication | [mailbox.md](mailbox/README.md) | +| **thermal** | Thermal management | [thermal.md](thermal/README.md) | +| **mfd** | Multi-function device | [mfd.md](mfd/README.md) | +| **dma** | DMA engine management | [dma.md](dma/README.md) | +| **iio** | Industrial I/O subsystem | [iio.md](iio/README.md) | +| **phy** | PHY (physical layer) framework | [phy.md](phy/README.md) | +| **phye** | Ethernet PHY framework | [phye.md](phye/README.md) | +| **pci** | PCI bus support | [pci.md](pci/README.md) | +| **ofw** | Open Firmware/Device Tree | [ofw.md](ofw/README.md) | + +## Common APIs + +### Device Management + +```c +/* Find device by master_id and device_id */ +rt_device_t rt_dm_device_find(int master_id, int device_id); + +/* Set device name */ +int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...); +int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix); + +/* Get device name */ +const char *rt_dm_dev_get_name(rt_device_t dev); +int rt_dm_dev_get_name_id(rt_device_t dev); +``` + +### Device Tree APIs + +```c +/* Get address resources */ +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); + +/* Map MMIO regions */ +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); + +/* Get IRQ resources */ +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); +``` + +### Property Reading + +```c +/* Read various property types */ +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_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_string_index(rt_device_t dev, const char *propname, + int index, const char **out_string); + +/* Simplified single-value reading */ +#define rt_dm_dev_prop_read_u32(dev, propname, out_value) \ + rt_dm_dev_prop_read_u32_array_index(dev, propname, 0, 1, out_value) +``` + +### Platform Device APIs + +```c +/* Register platform driver */ +rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv); + +/* Register platform device */ +rt_err_t rt_platform_device_register(struct rt_platform_device *pdev); + +/* Create platform device from device tree */ +rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np); +``` + +## Writing a Platform Driver + +### Basic Driver Structure + +```c +#include +#include +#include + +struct mydevice_data { + void *base; + int irq; + struct rt_clk *clk; +}; + +static rt_err_t mydevice_probe(struct rt_platform_device *pdev) +{ + struct mydevice_data *data; + struct rt_device *dev = &pdev->parent; + + /* Allocate private data */ + data = rt_calloc(1, sizeof(*data)); + if (!data) + return -RT_ENOMEM; + + /* Map MMIO region */ + data->base = rt_dm_dev_iomap(dev, 0); + if (!data->base) { + rt_free(data); + return -RT_ERROR; + } + + /* Get IRQ */ + data->irq = rt_dm_dev_get_irq(dev, 0); + + /* Get clock */ + data->clk = rt_clk_get_by_name(dev, "baudclk"); + if (data->clk) { + rt_clk_prepare_enable(data->clk); + } + + /* Store private data */ + pdev->priv = data; + + /* Initialize hardware */ + /* ... */ + + return RT_EOK; +} + +static rt_err_t mydevice_remove(struct rt_platform_device *pdev) +{ + struct mydevice_data *data = pdev->priv; + + /* Cleanup hardware */ + /* ... */ + + /* Release resources */ + if (data->clk) { + rt_clk_disable_unprepare(data->clk); + rt_clk_put(data->clk); + } + + rt_free(data); + + return RT_EOK; +} + +static const struct rt_ofw_node_id mydevice_ofw_ids[] = { + { .compatible = "myvendor,mydevice" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver mydevice_driver = { + .name = "mydevice", + .ids = mydevice_ofw_ids, + .probe = mydevice_probe, + .remove = mydevice_remove, +}; + +/* Auto-register driver at boot */ +RT_PLATFORM_DRIVER_EXPORT(mydevice_driver); +``` + +### Device Tree Binding + +```dts +mydev: mydevice@10000000 { + compatible = "myvendor,mydevice"; + reg = <0x10000000 0x1000>; + interrupts = <32>; + clocks = <&osc24M>; + clock-names = "baudclk"; + status = "okay"; +}; +``` + +## Best Practices + +### 1. Resource Management + +- Always check return values when getting resources +- Use reference counting for shared resources (clocks, regulators) +- Clean up resources in the remove callback +- Handle probe deferral for dependencies + +### 2. Device Tree + +- Use standard bindings when available +- Document custom properties in driver documentation +- Use labels for phandle references +- Keep device tree and driver in sync + +### 3. Error Handling + +```c +static rt_err_t mydevice_probe(struct rt_platform_device *pdev) +{ + rt_err_t ret; + struct mydevice_data *data; + + data = rt_calloc(1, sizeof(*data)); + if (!data) + return -RT_ENOMEM; + + data->base = rt_dm_dev_iomap(&pdev->parent, 0); + if (!data->base) { + ret = -RT_ERROR; + goto err_free; + } + + data->clk = rt_clk_get_by_name(&pdev->parent, "baudclk"); + if (!data->clk) { + ret = -RT_ERROR; + goto err_unmap; + } + + ret = rt_clk_prepare_enable(data->clk); + if (ret) + goto err_put_clk; + + /* Success */ + pdev->priv = data; + return RT_EOK; + +err_put_clk: + rt_clk_put(data->clk); +err_unmap: + rt_iounmap(data->base); +err_free: + rt_free(data); + return ret; +} +``` + +### 4. Thread Safety + +- Use spinlocks for hardware register access +- Use mutexes for long operations +- Consider interrupt context in ISRs +- Protect shared data structures + +## Performance Considerations + +### Memory Usage + +DM adds memory overhead: +- Device tree parsing requires memory for FDT and node structures +- Each device/driver adds object overhead +- Additional metadata for resource management + +**Recommendations**: +- Only enable DM for systems that need it +- Consider memory constraints when designing device trees +- Use static allocation where possible + +### Boot Time + +- Device tree parsing happens early in boot +- Driver probing can be deferred +- Parallel initialization where possible + +## Debugging + +### Enable Debug Output + +```c +#define DBG_TAG "mydriver" +#define DBG_LVL DBG_INFO +#include + +LOG_D("Debug message"); +LOG_I("Info message"); +LOG_W("Warning message"); +LOG_E("Error message"); +``` + +### DM-Specific Debugging + +``` +/* In menuconfig, enable OFW debugging */ +RT-Thread Components → Device Drivers → Using Open Firmware (OFW) +``` + +### Common Issues + +1. **Device not probing**: Check compatible string matches +2. **Resource not found**: Verify device tree properties +3. **Probe deferral loop**: Check for circular dependencies +4. **Memory access fault**: Verify MMIO mapping is correct + +## Migration Guide + +### From Traditional RT-Thread Drivers + +Traditional RT-Thread drivers: +```c +rt_device_t dev = rt_device_find("uart0"); +rt_device_open(dev, RT_DEVICE_OFLAG_RDWR); +``` + +With DM: +```c +/* Device automatically created from device tree */ +rt_device_t dev = rt_device_find("uart0"); +rt_device_open(dev, RT_DEVICE_OFLAG_RDWR); +/* API remains the same for users */ +``` + +Driver implementation changes: +- Add platform driver structure +- Implement probe/remove callbacks +- Use DM APIs for resource management +- Add device tree binding + +## Related Documentation + +- [Open Firmware (OFW) Documentation](../ofw/dtc.md) +- [Device Framework](../framework/device.md) +- For module-specific documentation, see the links in the DM-Dependent Modules section + +## References + +- [Device Tree Specification](https://devicetree-specification.readthedocs.io/) +- [Linux Kernel Driver Model](https://www.kernel.org/doc/html/latest/driver-api/driver-model/index.html) +- RT-Thread Source Code: `components/drivers/core/`, `components/drivers/ofw/` diff --git a/documentation/6.components/device-driver/device_driver_model/README_zh.md b/documentation/6.components/device-driver/device_driver_model/README_zh.md new file mode 100644 index 0000000000..5d9870479a --- /dev/null +++ b/documentation/6.components/device-driver/device_driver_model/README_zh.md @@ -0,0 +1,670 @@ +# RT-Thread 设备驱动模型 (DM) + +## 概述 + +RT-Thread 设备驱动模型(Device Driver Model,简称 DM)是一个全面的框架,提供了标准化的层次化方法来管理硬件设备及其驱动程序。通过 `RT_USING_DM` 配置选项启用,它引入了复杂的设备-驱动匹配机制、总线抽象以及与设备树(Open Firmware)的无缝集成。 + +DM 框架显著增强了 RT-Thread 处理复杂硬件系统的能力,特别是那些需要动态设备发现、电源管理、时钟控制和其他硬件资源管理的系统。 + +### 主要特性 + +- **总线-驱动-设备架构**:硬件组件的层次化组织 +- **设备树集成**:完整的 Open Firmware (OFW) 支持用于硬件描述 +- **动态设备管理**:运行时设备发现和驱动绑定 +- **资源管理**:统一的时钟、电压调节器、复位、电源域等 API +- **平台设备模型**:内存映射和不可发现设备的抽象 +- **引用计数**:安全的资源生命周期管理 +- **可扩展框架**:轻松添加新的总线类型和设备类 + +## 架构 + +### 核心组件 + +DM 框架由几个关键组件组成: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 应用层 │ +│ (使用设备 API: clk, regulator, pinctrl, gpio 等) │ +└────────────────────┬────────────────────────────────────────┘ + │ +┌────────────────────┴────────────────────────────────────────┐ +│ 设备驱动模型 (DM) │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 总线 │ │ 驱动 │ │ 设备 │ │ 平台 │ │ +│ │ 子系统 │ │ 子系统 │ │ 子系统 │ │ 层 │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ OFW (开放固件/设备树) │ │ +│ │ - FDT 解析 - 属性读取 - IRQ 映射 │ │ +│ └──────────────────────────────────────────────────────┘ │ +└────────────────────┬────────────────────────────────────────┘ + │ +┌────────────────────┴────────────────────────────────────────┐ +│ 硬件资源 │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 时钟 │ │ 调节器 │ │ 复位 │ │ GPIO │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 引脚控制 │ │ DMA │ │ 中断 │ │ 内存 │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +#### 1. 总线子系统 + +总线子系统(`rt_bus`)为组织设备和驱动程序提供了基础: + +- **总线注册**:总线在系统中注册并维护设备和驱动程序列表 +- **设备-驱动匹配**:每个总线实现匹配函数以配对兼容的驱动程序和设备 +- **探测/移除**:总线协调设备-驱动绑定的生命周期 +- **锁管理**:设备和驱动程序列表的线程安全操作 + +**核心结构**: +```c +struct rt_bus { + struct rt_object parent; + const char *name; + rt_list_t list; + rt_list_t dev_list; /* 此总线上的设备列表 */ + rt_list_t drv_list; /* 此总线上的驱动程序列表 */ + 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); +}; +``` + +#### 2. 驱动子系统 + +驱动程序实现硬件特定功能并绑定到兼容的设备: + +- **驱动注册**:驱动程序向特定总线注册 +- **设备操作**:标准操作(init、open、close、read、write、control) +- **探测/移除回调**:绑定到设备时的初始化和清理 +- **引用计数**:跟踪活动设备绑定的数量 + +**核心结构**: +```c +struct rt_driver { + struct rt_object parent; + struct rt_bus *bus; + rt_list_t node; + rt_uint32_t ref_count; + + /* 设备操作 */ + rt_err_t (*init)(rt_device_t dev); + rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag); + rt_err_t (*close)(rt_device_t dev); + rt_ssize_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); + rt_ssize_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); + rt_err_t (*control)(rt_device_t dev, int cmd, void *args); + + /* 生命周期回调 */ + int (*probe)(struct rt_device *dev); + int (*remove)(struct rt_device *dev); + int (*shutdown)(struct rt_device *dev); +}; +``` + +#### 3. 平台设备模型 + +平台设备模型是 RT-Thread 中 DM 最常见的用法,处理内存映射设备: + +- **平台总线**:用于非物理总线上设备的虚拟总线 +- **设备树集成**:从 FDT 节点自动创建设备 +- **资源抽象**:统一访问内存区域、中断、时钟等 +- **驱动绑定**:基于 compatible 字符串的自动匹配 + +**核心结构**: +```c +struct rt_platform_device { + struct rt_device parent; + int dev_id; + const char *name; + const struct rt_ofw_node_id *id; + void *priv; +}; + +struct rt_platform_driver { + struct rt_driver parent; + const char *name; + const struct rt_ofw_node_id *ids; /* Compatible 字符串 */ + + 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); +}; +``` + +#### 4. OFW(开放固件)支持 + +OFW 子系统提供设备树支持: + +- **FDT 解析**:扁平设备树(FDT)二进制格式解析 +- **设备节点管理**:层次化设备树节点表示 +- **属性读取**:读取设备树属性的 API +- **资源映射**:将 DT 资源转换为系统资源(IRQ、内存等) + +### 设备生命周期 + +DM 框架中设备的典型生命周期: + +``` + 设备树 平台 驱动 + │ │ │ + │ 解析 DT │ │ + ├──────────────────>│ │ + │ │ │ + │ 创建平台 │ │ + │ 设备 │ │ + │ │ │ + │ 在平台总线上 │ │ + │ 注册设备 │ │ + │ │ │ + │ │ 匹配设备 │ + │ │ 与驱动 │ + │ ├─────────────────>│ + │ │ │ + │ │ 驱动探测 │ + │ │<─────────────────┤ + │ │ │ + │ │ 初始化硬件 │ + │ │ │ + │ │ 注册 API │ + │ │ │ + │ │ 运行中 │ + │ │ │ + │ │ 驱动移除 │ + │ ├─────────────────>│ + │ │ │ + │ │ 清理 │ + │ │<─────────────────┤ + │ │ │ +``` + +## Kconfig 配置 + +### 主 DM 选项 + +通过主 Kconfig 选项启用设备驱动模型: + +```kconfig +config RT_USING_DM + bool "Enable device driver model with device tree" + default n + help + Enable device driver model with device tree (FDT). It will use more memory + to parse and support device tree feature. +``` + +**在 menuconfig 中的位置**:`RT-Thread Components → Device Drivers → Enable device driver model with device tree` + +### 相关选项 + +#### 设备总线 +```kconfig +config RT_USING_DEV_BUS + bool "Using Device Bus device drivers" + default y if RT_USING_SMART + default n +``` + +#### 开放固件(OFW) +```kconfig +menuconfig RT_USING_OFW + bool "Using Open Firmware (OFW)" + select RT_USING_ADT + select RT_USING_ADT_REF + select RT_USING_ADT_BITMAP + select RT_USING_MEMBLOCK + depends on RT_USING_DM + default n +``` + +**位置**:`RT-Thread Components → Device Drivers → Using Open Firmware (OFW)` + +#### 内置 FDT +```kconfig +config RT_USING_BUILTIN_FDT + bool "Using builtin fdt in kernel" + depends on RT_USING_OFW + default n + +config RT_BUILTIN_FDT_PATH + string "Builtin fdt path, will rebuild if have dts" + depends on RT_USING_BUILTIN_FDT + default "rtthread.dtb" +``` + +## 设备树集成 + +### 设备树基础 + +当启用 `RT_USING_DM` 和 `RT_USING_OFW` 时,RT-Thread 可以解析和使用设备树(FDT)来描述硬件: + +#### 设备树节点示例 + +```dts +/ { + compatible = "myboard,example"; + #address-cells = <1>; + #size-cells = <1>; + + clocks { + osc24M: osc24M_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc24M"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + uart0: serial@10000000 { + compatible = "myvendor,uart"; + reg = <0x10000000 0x1000>; + interrupts = <32>; + clocks = <&osc24M>; + clock-names = "baudclk"; + status = "okay"; + }; + }; + + regulators { + vcc_3v3: regulator-vcc-3v3 { + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; +``` + +### 在驱动中使用设备树 + +#### 获取设备节点 + +```c +#include + +struct rt_ofw_node *np = dev->ofw_node; +``` + +#### 读取属性 + +```c +/* 读取字符串属性 */ +const char *status; +rt_ofw_prop_read_string(np, "status", &status); + +/* 读取 u32 属性 */ +rt_uint32_t freq; +rt_ofw_prop_read_u32(np, "clock-frequency", &freq); + +/* 读取数组 */ +rt_uint32_t reg[2]; +rt_ofw_prop_read_u32_array(np, "reg", reg, 2); +``` + +#### 获取资源 + +```c +/* 获取内存资源 */ +rt_uint64_t addr, size; +rt_dm_dev_get_address(dev, 0, &addr, &size); + +/* 获取 IRQ */ +int irq = rt_dm_dev_get_irq(dev, 0); + +/* 映射 MMIO */ +void *base = rt_dm_dev_iomap(dev, 0); + +/* 获取时钟 */ +struct rt_clk *clk = rt_clk_get_by_name(dev, "baudclk"); +``` + +## DM 依赖模块 + +设备驱动模型支持众多硬件子系统。每个模块为应用层和驱动实现提供标准化的 API: + +| 模块 | 描述 | 文档 | +|------|------|------| +| **clk** | 时钟管理框架 | [clk.md](clk/README_zh.md) | +| **regulator** | 电压/电流调节 | [regulator.md](regulator/README_zh.md) | +| **pinctrl** | 引脚复用和配置 | [pinctrl.md](pinctrl/README_zh.md) | +| **reset** | 复位控制器管理 | [reset.md](reset/README_zh.md) | +| **pmdomain** | 电源域管理 | [pmdomain.md](pmdomain/README_zh.md) | +| **pic** | 平台中断控制器 | [pic.md](pic/README_zh.md) | +| **nvmem** | 非易失性内存框架 | [nvmem.md](nvmem/README_zh.md) | +| **mailbox** | 邮箱/门铃通信 | [mailbox.md](mailbox/README_zh.md) | +| **thermal** | 热管理 | [thermal.md](thermal/README_zh.md) | +| **mfd** | 多功能设备 | [mfd.md](mfd/README_zh.md) | +| **dma** | DMA 引擎管理 | [dma.md](dma/README_zh.md) | +| **iio** | 工业 I/O 子系统 | [iio.md](iio/README_zh.md) | +| **phy** | PHY(物理层)框架 | [phy.md](phy/README_zh.md) | +| **phye** | 以太网 PHY 框架 | [phye.md](phye/README_zh.md) | +| **pci** | PCI 总线支持 | [pci.md](pci/README_zh.md) | +| **ofw** | 开放固件/设备树 | [ofw.md](ofw/README_zh.md) | + +## 常用 API + +### 设备管理 + +```c +/* 通过 master_id 和 device_id 查找设备 */ +rt_device_t rt_dm_device_find(int master_id, int device_id); + +/* 设置设备名称 */ +int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...); +int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix); + +/* 获取设备名称 */ +const char *rt_dm_dev_get_name(rt_device_t dev); +int rt_dm_dev_get_name_id(rt_device_t dev); +``` + +### 设备树 API + +```c +/* 获取地址资源 */ +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); + +/* 映射 MMIO 区域 */ +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); + +/* 获取 IRQ 资源 */ +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); +``` + +### 属性读取 + +```c +/* 读取各种属性类型 */ +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_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_string_index(rt_device_t dev, const char *propname, + int index, const char **out_string); + +/* 简化的单值读取 */ +#define rt_dm_dev_prop_read_u32(dev, propname, out_value) \ + rt_dm_dev_prop_read_u32_array_index(dev, propname, 0, 1, out_value) +``` + +### 平台设备 API + +```c +/* 注册平台驱动 */ +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); +``` + +## 编写平台驱动 + +### 基本驱动结构 + +```c +#include +#include +#include + +struct mydevice_data { + void *base; + int irq; + struct rt_clk *clk; +}; + +static rt_err_t mydevice_probe(struct rt_platform_device *pdev) +{ + struct mydevice_data *data; + struct rt_device *dev = &pdev->parent; + + /* 分配私有数据 */ + data = rt_calloc(1, sizeof(*data)); + if (!data) + return -RT_ENOMEM; + + /* 映射 MMIO 区域 */ + data->base = rt_dm_dev_iomap(dev, 0); + if (!data->base) { + rt_free(data); + return -RT_ERROR; + } + + /* 获取 IRQ */ + data->irq = rt_dm_dev_get_irq(dev, 0); + + /* 获取时钟 */ + data->clk = rt_clk_get_by_name(dev, "baudclk"); + if (data->clk) { + rt_clk_prepare_enable(data->clk); + } + + /* 存储私有数据 */ + pdev->priv = data; + + /* 初始化硬件 */ + /* ... */ + + return RT_EOK; +} + +static rt_err_t mydevice_remove(struct rt_platform_device *pdev) +{ + struct mydevice_data *data = pdev->priv; + + /* 清理硬件 */ + /* ... */ + + /* 释放资源 */ + if (data->clk) { + rt_clk_disable_unprepare(data->clk); + rt_clk_put(data->clk); + } + + rt_free(data); + + return RT_EOK; +} + +static const struct rt_ofw_node_id mydevice_ofw_ids[] = { + { .compatible = "myvendor,mydevice" }, + { /* sentinel */ } +}; + +static struct rt_platform_driver mydevice_driver = { + .name = "mydevice", + .ids = mydevice_ofw_ids, + .probe = mydevice_probe, + .remove = mydevice_remove, +}; + +/* 启动时自动注册驱动 */ +RT_PLATFORM_DRIVER_EXPORT(mydevice_driver); +``` + +### 设备树绑定 + +```dts +mydev: mydevice@10000000 { + compatible = "myvendor,mydevice"; + reg = <0x10000000 0x1000>; + interrupts = <32>; + clocks = <&osc24M>; + clock-names = "baudclk"; + status = "okay"; +}; +``` + +## 最佳实践 + +### 1. 资源管理 + +- 获取资源时始终检查返回值 +- 对共享资源(时钟、调节器)使用引用计数 +- 在移除回调中清理资源 +- 处理依赖项的探测延迟 + +### 2. 设备树 + +- 尽可能使用标准绑定 +- 在驱动文档中记录自定义属性 +- 使用标签进行 phandle 引用 +- 保持设备树和驱动同步 + +### 3. 错误处理 + +```c +static rt_err_t mydevice_probe(struct rt_platform_device *pdev) +{ + rt_err_t ret; + struct mydevice_data *data; + + data = rt_calloc(1, sizeof(*data)); + if (!data) + return -RT_ENOMEM; + + data->base = rt_dm_dev_iomap(&pdev->parent, 0); + if (!data->base) { + ret = -RT_ERROR; + goto err_free; + } + + data->clk = rt_clk_get_by_name(&pdev->parent, "baudclk"); + if (!data->clk) { + ret = -RT_ERROR; + goto err_unmap; + } + + ret = rt_clk_prepare_enable(data->clk); + if (ret) + goto err_put_clk; + + /* 成功 */ + pdev->priv = data; + return RT_EOK; + +err_put_clk: + rt_clk_put(data->clk); +err_unmap: + rt_iounmap(data->base); +err_free: + rt_free(data); + return ret; +} +``` + +### 4. 线程安全 + +- 对硬件寄存器访问使用自旋锁 +- 对长操作使用互斥锁 +- 在 ISR 中考虑中断上下文 +- 保护共享数据结构 + +## 性能考虑 + +### 内存使用 + +DM 增加了内存开销: +- 设备树解析需要 FDT 和节点结构的内存 +- 每个设备/驱动添加对象开销 +- 资源管理的额外元数据 + +**建议**: +- 仅为需要它的系统启用 DM +- 设计设备树时考虑内存限制 +- 尽可能使用静态分配 + +### 启动时间 + +- 设备树解析在启动早期进行 +- 驱动探测可以延迟 +- 尽可能并行初始化 + +## 调试 + +### 启用调试输出 + +```c +#define DBG_TAG "mydriver" +#define DBG_LVL DBG_INFO +#include + +LOG_D("调试消息"); +LOG_I("信息消息"); +LOG_W("警告消息"); +LOG_E("错误消息"); +``` + +### DM 特定调试 + +``` +/* 在 menuconfig 中启用 OFW 调试 */ +RT-Thread Components → Device Drivers → Using Open Firmware (OFW) +``` + +### 常见问题 + +1. **设备未探测**:检查 compatible 字符串是否匹配 +2. **资源未找到**:验证设备树属性 +3. **探测延迟循环**:检查循环依赖 +4. **内存访问错误**:验证 MMIO 映射正确 + +## 迁移指南 + +### 从传统 RT-Thread 驱动 + +传统 RT-Thread 驱动: +```c +rt_device_t dev = rt_device_find("uart0"); +rt_device_open(dev, RT_DEVICE_OFLAG_RDWR); +``` + +使用 DM: +```c +/* 设备从设备树自动创建 */ +rt_device_t dev = rt_device_find("uart0"); +rt_device_open(dev, RT_DEVICE_OFLAG_RDWR); +/* 用户 API 保持不变 */ +``` + +驱动实现变化: +- 添加平台驱动结构 +- 实现探测/移除回调 +- 使用 DM API 进行资源管理 +- 添加设备树绑定 + +## 相关文档 + +- [开放固件(OFW)文档](../ofw/dtc.md) +- [设备框架](../framework/device.md) +- 有关模块特定文档,请参阅 DM 依赖模块部分中的链接 + +## 参考资料 + +- [设备树规范](https://devicetree-specification.readthedocs.io/) +- [Linux 内核驱动模型](https://www.kernel.org/doc/html/latest/driver-api/driver-model/index.html) +- RT-Thread 源代码:`components/drivers/core/`、`components/drivers/ofw/`