[documentation][device_driver_model] Add main DM documentation (EN/CN)

Co-authored-by: BernardXiong <1241087+BernardXiong@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-01-02 15:08:02 +00:00
parent c9db19d201
commit 17ecb56cb5
2 changed files with 1340 additions and 0 deletions

View File

@ -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 <drivers/ofw.h>
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 <rtthread.h>
#include <drivers/platform.h>
#include <drivers/ofw.h>
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 <rtdbg.h>
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/`

View File

@ -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 <drivers/ofw.h>
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 <rtthread.h>
#include <drivers/platform.h>
#include <drivers/ofw.h>
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 <rtdbg.h>
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/`