关于uboot驱动模型,这篇文章讲得很好,不再描述:
[uboot] (番外篇)uboot 驱动模型_ooonebook的博客-CSDN博客
linux usb总线架构:
Linux USB总线架构_ZhY_Rening的博客-CSDN博客
uboot版本:uboot2018.01
平台:ti-am5728
usb控制器:xhci-dwc3
usb 命令:cmd/usb.c
usb uclass:drivers/usb/host/usb-uclass.c
usb 控制器驱动:drivers/usb/host/xhci-dwc3.c
usb hub驱动:common/usb_hub.c
usb存储驱动:common/usb_storage.c
uboot DM驱动模型图:
注:图来自网络,是以serial驱动为例,其他驱动也是一样的。
这里涉及到的uclass有 UCLASS_USB,UCLASS_USB_HUB,UCLASS_MASS_STORAGE。
对于UCLASS_USB:一个udevice对应一个 usb控制器(bus、root hub)。udevice从设备树解析,driver在驱动程序里定义。
对于UCLASS_USB_HUB:一个udevice对应一个 usb hub(非root hub)。udevice在父设备(usb或usb hub)扫描时创建并和驱动程序match,driver在驱动程序里定义。
对于UCLASS_MASS_STORAGE:一个udevice对应一个 mass 存储设备。udevice在父设备(usb或usb hub)扫描时创建并和驱动程序match,driver在驱动程序里定义。
这三种udevice的关系如下:
一个usb控制器有且仅有一个root hub设备(和控制器作为一个整体),这个根Hub下可以接多级的Hub(以child udevice的形式),每个子Hub又可以接子Hub。每个USB设备作为一个节点接在不同级别的Hub上。 每条USB总线上最多可以接127个设备。mass storage是一种usb设备。
1.usb控制器驱动(以xhci-dwc3为例):
U_BOOT_DRIVER(xhci_dwc3) = {
.name = "xhci-dwc3",
.id = UCLASS_USB,
.of_match = xhci_dwc3_ids,
.probe = xhci_dwc3_probe,
.remove = xhci_dwc3_remove,
.ops = &xhci_usb_ops,
.priv_auto_alloc_size = sizeof(struct xhci_ctrl),
.platdata_auto_alloc_size = sizeof(struct xhci_dwc3_platdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
2.usb控制器设备树节点:
usb1: usb@48890000 {
compatible = "snps,dwc3";
reg = <0x48890000 0x17000>;
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "peripheral",
"host",
"otg";
phys = <&usb2_phy1>, <&usb3_phy1>;
phy-names = "usb2-phy", "usb3-phy";
maximum-speed = "super-speed";
dr_mode = "host";
snps,dis_u3_susphy_quirk;
snps,dis_u2_susphy_quirk;
};
3.usb uclass驱动:
UCLASS_DRIVER(usb) = {
.id = UCLASS_USB,
.name = "usb",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = dm_scan_fdt_dev,
.priv_auto_alloc_size = sizeof(struct usb_uclass_priv),
.per_child_auto_alloc_size = sizeof(struct usb_device),
.per_device_auto_alloc_size = sizeof(struct usb_bus_priv),
.child_post_bind = usb_child_post_bind,
.child_pre_probe = usb_child_pre_probe,
.per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
};
4.usb hub 设备驱动和 uclass驱动:
U_BOOT_DRIVER(usb_generic_hub) = {
.name = "usb_hub",
.id = UCLASS_USB_HUB,
.of_match = usb_hub_ids,
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
UCLASS_DRIVER(usb_hub) = {
.id = UCLASS_USB_HUB,
.name = "usb_hub",
.post_bind = dm_scan_fdt_dev,
.post_probe = usb_hub_post_probe,
.child_pre_probe = usb_child_pre_probe,
.per_child_auto_alloc_size = sizeof(struct usb_device),
.per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
.per_device_auto_alloc_size = sizeof(struct usb_hub_device),
};
5.usb mass storage 设备驱动和uclass驱动:
U_BOOT_DRIVER(usb_mass_storage) = {
.name = "usb_mass_storage",
.id = UCLASS_MASS_STORAGE,
.of_match = usb_mass_storage_ids,
.probe = usb_mass_storage_probe,
#ifdef CONFIG_BLK
.platdata_auto_alloc_size = sizeof(struct us_data),
#endif
};
UCLASS_DRIVER(usb_mass_storage) = {
.id = UCLASS_MASS_STORAGE,
.name = "usb_mass_storage",
};
6.usb start过程:
do_usb
do_usb_start
usb_init //drivers/usb/host/usb-uclass.c
uclass_get(UCLASS_USB, &uc); //根据uclass id获取usb uclass
uclass_foreach_dev(bus, uc) { //遍历 probe uclass下的udevice(控制器)
device_probe(bus); //drivers/core/device.c
device_probe(dev->parent); //递归probe父节点
uclass_resolve_seq//父节点都probe之后,会分配一个seq给该设备
dev->flags |= DM_FLAG_ACTIVATED//设置该设备的flag为激活状态
pinctrl_select_state(dev, "default")//和引脚相关的初始化设置
uclass_pre_probe_device //uc_drv->pre_probe
dev->parent->driver->child_pre_probe(dev)//执行父节点驱动的child_pre_probe
drv->ofdata_to_platdata(dev)//执行设备驱动的ofdata_to_platdata接口函数
clk_set_defaults(dev)//设备时钟相关的设置
drv->probe(dev)//调用设备驱动的probe接口函数
uclass_post_probe_device(dev)//调用所属CLASS驱动的post_probe接口函数
}
uclass_foreach_dev(bus, uc) { //遍历 扫描 uclass下的udevice(控制器)
if (!device_active(bus)) //跳过active的设备
continue;
usb_scan_bus(bus, true); //扫描bus(usb控制器)下的设备
usb_scan_device(bus, 0, USB_SPEED_FULL, &dev);
struct usb_device *parent_udev; //定义usb_devide
usb_setup_device //配置设备
usb_prepare_device //设置地址和描述符
usb_select_config //选择设备的配置
usb_find_child //寻找子设备
usb_find_and_bind_driver //遍历usb驱动(hub、keyboard、storage)并和子设备绑定
device_probe //子设备probe,最终会调用子设备驱动里面的方法,如果是hub就递归扫描,如果是storage就初始化并获取描述符等。