uboot 2020.04 DM驱动模型实战:从设备树到驱动绑定的完整流程解析

张开发
2026/4/8 9:16:41 15 分钟阅读

分享文章

uboot 2020.04 DM驱动模型实战:从设备树到驱动绑定的完整流程解析
U-Boot 2020.04 DM驱动模型深度解析从设备树到驱动绑定的全流程指南1. 引言为什么需要DM驱动模型在嵌入式系统开发中启动引导程序U-Boot承担着硬件初始化、操作系统加载等关键任务。随着SoC架构日益复杂传统的硬编码驱动方式面临诸多挑战代码臃肿每个板级配置需要单独维护驱动代码兼容性差不同硬件模块间的接口标准不统一扩展困难新增设备需要修改核心代码U-Boot 2020.04引入的Driver ModelDM驱动模型通过标准化设备管理框架解决了这些问题。本文将深入剖析DM模型的核心组件并演示从设备树配置到驱动绑定的完整工作流程。2. DM模型四大核心组件解析2.1 设备实例struct udevicestruct udevice { const struct driver *driver; // 关联的驱动 const char *name; // 设备名称通常为设备树节点名 void *platdata; // 设备平台数据 ofnode node; // 关联的设备树节点 struct udevice *parent; // 父设备指针 struct uclass *uclass; // 所属uclass struct list_head uclass_node; // uclass设备链表节点 struct list_head child_head; // 子设备链表头 int seq; // 设备序列号 uint32_t flags; // 状态标志位 };关键特性层次结构通过parent/child_head构建设备树自动内存管理支持platdata/priv空间的自动分配状态跟踪flags标记设备状态已绑定/已激活等2.2 驱动描述struct driverstruct driver { char *name; // 驱动名称 enum uclass_id id; // 所属uclass ID const struct udevice_id *of_match; // 设备树兼容性匹配表 int (*bind)(struct udevice *dev); // 绑定回调 int (*probe)(struct udevice *dev); // 探测回调 int priv_auto_alloc_size; // 私有数据自动分配大小 int platdata_auto_alloc_size; // 平台数据自动分配大小 const void *ops; // 设备操作函数集 };典型驱动声明示例U_BOOT_DRIVER(serial_ns16550) { .name serial_ns16550, .id UCLASS_SERIAL, .of_match ns16550_serial_ids, .platdata_auto_alloc_size sizeof(struct ns16550_platdata), .priv_auto_alloc_size sizeof(struct NS16550), .ops ns16550_serial_ops, .probe ns16550_serial_probe, };2.3 设备分类struct uclassstruct uclass { struct uclass_driver *uc_drv; // uclass驱动 struct list_head dev_head; // 设备链表头 void *priv; // uclass私有数据 };常见uclass类型UCLASS_GPIO通用GPIO接口UCLASS_I2CI2C总线控制器UCLASS_MMC存储卡控制器UCLASS_PINCTRL引脚复用控制器2.4 类驱动struct uclass_driverstruct uclass_driver { const char *name; // uclass名称 enum uclass_id id; // uclass ID int (*post_bind)(struct udevice *dev); // 绑定后回调 int (*pre_probe)(struct udevice *dev); // 探测前回调 int per_device_auto_alloc_size; // 每设备私有数据大小 const void *ops; // uclass标准操作集 };3. DM初始化全流程剖析3.1 初始化入口dm_init_and_scan()int dm_init_and_scan(bool pre_reloc_only) { int ret; // 1. 初始化根设备 ret dm_init(IS_ENABLED(CONFIG_OF_LIVE)); // 2. 扫描平台数据定义的设备 ret dm_scan_platdata(pre_reloc_only); // 3. 扫描设备树定义的设备 ret dm_extended_scan_fdt(gd-fdt_blob, pre_reloc_only); return 0; }3.2 根设备创建流程分配根设备结构dev calloc(1, sizeof(struct udevice));绑定root_driverdrv lists_driver_lookup_name(root_driver); device_bind_common(NULL, drv, root_driver, ...);创建root uclassuclass_add(UCLASS_ROOT, uc);设备探测device_probe(gd-dm_root);3.3 设备树设备绑定流程遍历设备树节点for (offset fdt_first_subnode(blob, 0); offset 0; offset fdt_next_subnode(blob, offset))匹配compatible属性compat_list ofnode_get_property(node, compatible, compat_length);查找匹配驱动for (entry driver; entry ! driver n_ents; entry) { ret driver_check_compatible(entry-of_match, id, compat); }创建设备实例device_bind_with_driver_data(parent, entry, name, ...);4. 实战GPIO控制器驱动绑定示例4.1 设备树节点定义gpio1: gpio209c000 { compatible fsl,imx6ul-gpio, fsl,imx35-gpio; reg 0x209c000 0x4000; interrupts GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH; gpio-controller; #gpio-cells 2; interrupt-controller; #interrupt-cells 2; };4.2 驱动匹配过程驱动声明static const struct udevice_id mxc_gpio_ids[] { { .compatible fsl,imx35-gpio }, { } }; U_BOOT_DRIVER(gpio_mxc) { .name gpio_mxc, .id UCLASS_GPIO, .of_match mxc_gpio_ids, .ops gpio_mxc_ops, .probe gpio_mxc_probe, .priv_auto_alloc_size sizeof(struct mxc_gpio_priv), };绑定过程解析设备树节点匹配compatible字符串分配priv内存空间调用probe函数初始化硬件4.3 关键API调用栈dm_init_and_scan(false) dm_extended_scan_fdt() dm_scan_fdt_node() lists_bind_fdt() device_bind_with_driver_data() device_bind_common() uclass_get() uclass_bind_device() drv-bind()5. 调试技巧与常见问题5.1 DM调试命令# 查看DM设备树 dm tree # 查看设备信息 dm info # 测试设备操作 dm test5.2 典型问题排查问题1驱动未正确绑定现象设备树节点存在但dm tree中未显示排查步骤检查compatible字符串是否完全匹配确认驱动是否通过U_BOOT_DRIVER注册检查probe函数返回值问题2内存分配失败现象系统启动时出现Out of memory错误解决方案调整CONFIG_SYS_MALLOC_F_LEN大小检查priv_auto_alloc_size设置是否合理问题3设备初始化顺序错误现象依赖其他设备的驱动probe失败解决方案使用dm_scan_platdata()优先初始化关键设备调整设备树节点顺序6. 高级应用场景6.1 自定义uclass创建定义uclass IDenum uclass_id { UCLASS_MYDEV UCLASS_COUNT, UCLASS_COUNT };实现uclass驱动UCLASS_DRIVER(mydev) { .id UCLASS_MYDEV, .name mydev, .per_device_auto_alloc_size sizeof(struct mydev_priv), .ops mydev_ops, };注册设备驱动U_BOOT_DRIVER(mydev_instance) { .name mydev_instance, .id UCLASS_MYDEV, .of_match mydev_ids, .probe mydev_probe, };6.2 延迟初始化机制对于非关键外设可实现按需初始化int lazy_init(struct udevice *dev) { if (!(dev-flags DM_FLAG_ACTIVATED)) { int ret device_probe(dev); if (ret) return ret; } return 0; }6.3 动态设备管理运行时添加/移除设备/* 动态添加设备 */ int add_dynamic_device(const char *name, struct udevice *parent) { struct driver_info info { .name name, .platdata NULL, }; return device_bind_by_name(parent, false, info, dev); } /* 动态移除设备 */ int remove_device(struct udevice *dev) { return device_remove(dev, DM_REMOVE_NORMAL); }7. 性能优化建议内存优化精确计算priv_auto_alloc_size需求对大批量设备使用共享uclass数据启动加速/* 标记仅需重定位前初始化的设备 */ U_BOOT_DRIVER(critical_drv) { .flags DM_FLAG_PRE_RELOC, };延迟非关键设备初始化int board_init(void) { // 只初始化关键设备 dm_init_and_scan(true); // 后续阶段初始化其他设备 dm_init_and_scan(false); }通过本文的深度解析开发者可以全面掌握U-Boot DM驱动模型的工作机制在实际项目中高效实现设备驱动管理。建议结合具体硬件平台通过dm tree命令观察设备绑定情况逐步验证各环节的正确性。

更多文章