uboot-驱动开发-驱动模型
- 软件开发
- 2025-08-15 09:15:02

说明 类似于linux,为了规范、统一驱动适配和驱动接口调用,uboot定义了一套驱动模型(Driver Model),简称DM。本文基于:u-boot-2021.10。 优点 为同一类ip的驱动定义了统一的操作接口,DM在软件层面做了一定的抽象。分层设计,将上层使用、设备以及驱动实现区分开来,降低了耦合性。 核心概念/数据结构 DM模型抽象出了以下四个概念/数据结构。 uclassuclass_driverudevicedriver uclass uclass(uboot class)是同一类外设(I2C、GPIO等)总的组织结构体,定义如下: // file:include/dm/uclass.h /** * struct uclass - a U-Boot drive class, collecting together similar drivers * * A uclass provides an interface to a particular function, which is * implemented by one or more drivers. Every driver belongs to a uclass even * if it is the only driver in that uclass. An example uclass is GPIO, which * provides the ability to change read inputs, set and clear outputs, etc. * There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and * PMIC IO lines, all made available in a unified way through the uclass. * * @priv_: Private data for this uclass (do not access outside driver model) * @uc_drv: The driver for the uclass itself, not to be confused with a * 'struct driver' * @dev_head: List of devices in this uclass (devices are attached to their * uclass when their bind method is called) * @sibling_node: Next uclass in the linked list of uclasses */ struct uclass { void *priv_; struct uclass_driver *uc_drv; struct list_head dev_head; struct list_head sibling_node; }; uclass 包含 uc_drv: uclass driver。dev_head: udevice list(设备列表)。sibling_node: 链表的下一个uclass结构。 uclass_driver uclass_driver是uclass的驱动,并不是具体硬件驱动,做一些uclass通用的的准备/回收等工作。 // file:include/dm/uclass.h struct uclass_driver { const char *name; enum uclass_id id; int (*post_bind)(struct udevice *dev); int (*pre_unbind)(struct udevice *dev); int (*pre_probe)(struct udevice *dev); int (*post_probe)(struct udevice *dev); int (*pre_remove)(struct udevice *dev); int (*child_post_bind)(struct udevice *dev); int (*child_pre_probe)(struct udevice *dev); int (*child_post_probe)(struct udevice *dev); int (*init)(struct uclass *class); int (*destroy)(struct uclass *class); int priv_auto; int per_device_auto; int per_device_plat_auto; int per_child_auto; int per_child_plat_auto; uint32_t flags; }; 使用宏UCLASS_DRIVER定义一个uclass driver,每一类ip会定义一个,如下: //file: drivers/timer/timer-uclass.c UCLASS_DRIVER(timer) = { .id = UCLASS_TIMER, .name = "timer", .pre_probe = timer_pre_probe, .flags = DM_UC_FLAG_SEQ_ALIAS, .post_probe = timer_post_probe, .per_device_auto = sizeof(struct timer_dev_priv), }; 预定义的uclass id。 //file: include/dm/uclass-id.h enum uclass_id { /* These are used internally by driver model */ UCLASS_ROOT = 0, UCLASS_DEMO, UCLASS_TEST, UCLASS_TEST_FDT, UCLASS_TEST_FDT_MANUAL, UCLASS_TEST_BUS, UCLASS_TEST_PROBE, UCLASS_TEST_DUMMY, UCLASS_TEST_DEVRES, UCLASS_TEST_ACPI, ... } udevice udevice是具体硬件的实例,例如:dts中配置了两个timer,就会有两个timer udevice,uboot会将udevice和它所属的uclass以及具体的驱动driver绑定起来。 //file:include/dm/device.h struct udevice { const struct driver *driver; const char *name; void *plat_; void *parent_plat_; void *uclass_plat_; ulong driver_data; struct udevice *parent; void *priv_; struct uclass *uclass; void *uclass_priv_; void *parent_priv_; struct list_head uclass_node; struct list_head child_head; struct list_head sibling_node; #if !CONFIG_IS_ENABLED(OF_PLATDATA_RT) u32 flags_; #endif int seq_; #if !CONFIG_IS_ENABLED(OF_PLATDATA) ofnode node_; #endif #ifdef CONFIG_DEVRES struct list_head devres_head; #endif #if CONFIG_IS_ENABLED(DM_DMA) ulong dma_offset; #endif }; driver 具体硬件的驱动,对应每个硬件的驱动实现,例如:dw wdt(drivers/watchdog/designware_wdt.c), mtk wdt(drivers/watchdog/mtk_wdt.c) 。 //file: include/dm/device.h struct driver { char *name; enum uclass_id id; const struct udevice_id *of_match; int (*bind)(struct udevice *dev); int (*probe)(struct udevice *dev); int (*remove)(struct udevice *dev); int (*unbind)(struct udevice *dev); int (*of_to_plat)(struct udevice *dev); int (*child_post_bind)(struct udevice *dev); int (*child_pre_probe)(struct udevice *dev); int (*child_post_remove)(struct udevice *dev); int priv_auto; int plat_auto; int per_child_auto; int per_child_plat_auto; const void *ops; /* driver-specific operations */ uint32_t flags; #if CONFIG_IS_ENABLED(ACPIGEN) struct acpi_ops *acpi_ops; #endif }; * const void *ops; 是该驱动支持的接口。 ops 指向该类ip统一驱动接口结构体,在include目录的头文件中有各种ip需要支持的ops接口,例如: include/thermal.h //温度传感器需要支持的接口(ops) include/wdt.h //wdt需要支持的ops include/timer.h //timer需要支持的ops * include/timer.h struct timer_ops { /** * @get_count: Get the current timer count * * @dev: The timer device * * This function may be called at any time after the driver is probed. * All necessary initialization must be completed by the time probe() * returns. The count returned by this functions should be monotonic. * This function must succeed. * * Return: The current 64-bit timer count */ u64 (*get_count)(struct udevice *dev); }; 新思定时器(dw apb timer)定义: static const struct timer_ops dw_apb_timer_ops = { .get_count = dw_apb_timer_get_count, }; U_BOOT_DRIVER(dw_apb_timer) = { .name = "dw_apb_timer", .id = UCLASS_TIMER, .ops = &dw_apb_timer_ops, .probe = dw_apb_timer_probe, .of_match = dw_apb_timer_ids, .of_to_plat = dw_apb_timer_of_to_plat, .remove = dw_apb_timer_remove, .priv_auto = sizeof(struct dw_apb_timer_priv), }; 使用宏U_BOOT_DRIVER定义一个驱动实例 /* Declare a new U-Boot driver */ #define U_BOOT_DRIVER(__name) \ ll_entry_declare(struct driver, __name, driver) 联系 uclass和udevice是动态生成的。udevice在解析fdt中的设备的时候自动生成,然后udevice找到对应的driver,driver中保存了uclass_id,根据它找到uclass_driver_id,从uclass链表中查找对应的uclass是否已经生成,若没有生成,则动态生成,重点是解析设备树,生成udevice,并找到对应的driver。 代码流程 模型的全局数据结构,包含根节点。 typedef struct global_data { // dts中的根节点,第一个创建的udevice struct udevice *dm_root; // relocation之前的根设备 struct udevice *dm_root_f; // uclass的链表, 挂的是有udevice的uclass struct list_head uclass_root; } gd_t; 初始化与扫描设备树 int dm_init_and_scan(bool pre_reloc_only) { int ret; ret = dm_init(CONFIG_IS_ENABLED(OF_LIVE)); if (ret) { debug("dm_init() failed: %d\n", ret); return ret; } if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) { ret = dm_scan(pre_reloc_only); if (ret) { log_debug("dm_scan() failed: %d\n", ret); return ret; } } return 0; } DM模型初始化(dm_init) int dm_init(bool of_live) { gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST; //初始化uclass_root链表头 INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST); //创建一个device dm_root并将其绑定到driver name “root_driver”。 device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); //探测设备udevice dm_root并激活它 ret = device_probe(DM_ROOT_NON_CONST); } 待补充 DM模型Device Tree节点的设备初始化(dm_scan) 待补充 绑定udevice和driver(device_bind_common) 待补充 使用 整体使能 配置:CONFIG_DM 不同类型外设需要专门使能 串口配置:CONFIG_DM_SERIAL wdt配置:CONFIG_WDT
uboot-驱动开发-驱动模型由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“uboot-驱动开发-驱动模型”