1.概述

RK3588有2个USB3.0 DRD控制器,2个USB2.0 Host控制器。USB3.0 DRD控制器既可以做Host,也可以做Device,向下兼容USB2.0和USB1.0。USB3.0 DRD控制器的内部结构如下图所示;总线接口为AXI或AHB;USB3.0和USB2.0及USB1.0硬件上独立;USB3.0控制器数字逻辑部分对应SS MAC,PHY接口为PIPE,PHY为USBDP PHY,和DP使用同一个PHY;USB2.0和USB1.0控制器数字逻辑部分对应HS/FS/LS MAC,PHY接口为UTMI+,PHY为USB2.0 PHY。

USB3.0 DRD控制器作为Host的主要特性如下:

  1. 兼容USB3.0 Revision 1.0规范,兼容USB2.0规范,兼容xHCI Revision 1.1规范。
  2. 支持Control/Bulk (including stream)/Interrupt/Isochronous传输。
  3. USB3.0同时进行输入和输出传输,最大可达到8Gbps带宽。
  4. 具有描述符缓存和数据预取功能,可以改善高延迟系统的性能。
  5. USB2.0支持LPM低功耗协议,USB3.0支持U0、U1、U2、U3四种低功耗状态。
  6. 端点具有动态FIFO memory分配能力。
  7. LS模式具有Keep-Alive特性,HS/FS模式具有(micro-)SOFs特性。
  8. 支持AXI Master和AHB Slave接口。
  9. 最大支持64个设备。
  10. 支持1个中断。
  11. 支持USB2.0 port和USB3.0 port。
  12. 支持标准的和开源的xHCI和USB类驱动。
  13. USB2.0 PHY支持充电检测。
  14. 支持USB Type-C和DP Alt模式。

2.设备树

usbdrd3_1设备树定义如下,默认模式为Host。

[arch/arm64/boot/dts/rockchip/rk3588.dtsi]
/ {
......
usbdrd3_1: usbdrd3_1 {
compatible = "rockchip,rk3588-dwc3", "rockchip,rk3399-dwc3";
clocks = <&cru REF_CLK_USB3OTG1>, <&cru SUSPEND_CLK_USB3OTG1>,
<&cru ACLK_USB3OTG1>;
clock-names = "ref", "suspend", "bus";
#address-cells = <2>;
#size-cells = <2>;
ranges;
status = "disabled"; usbdrd_dwc3_1: usb@fc400000 {
compatible = "snps,dwc3";
reg = <0x0 0xfc400000 0x0 0x400000>;
interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&power RK3588_PD_USB>;
resets = <&cru SRST_A_USB3OTG1>;
reset-names = "usb3-otg";
/* USB模式,host:主机,otg:otg模式,peripheral:设备 */
dr_mode = "host";
/* USB2.0和USB1.0 PHY USB3.0 PHY */
phys = <&u2phy1_otg>, <&usbdp_phy1_u3>;
phy-names = "usb2-phy", "usb3-phy";
phy_type = "utmi_wide"; /* USB2.0 PHY接口 */
/* When set clears the enblslpm in GUSB2PHYCFG,
* disabling the suspend signal to the PHY
*/
snps,dis_enblslpm_quirk;
/* When set, clear the u2_freeclk_exists in GUSB2PHYCFG,
* specify that USB2 PHY doesn't provide a free-running
* PHY clock.
*/
snps,dis-u2-freeclk-exists-quirk;
/* When set core will change PHY power from P0 to
* P1/P2/P3 without delay.
*/
snps,dis-del-phy-power-chg-quirk;
/* When set, disable u2mac linestate check during HS transmit */
snps,dis-tx-ipgap-linecheck-quirk;
status = "disabled";
};
};
}; [arch/arm64/boot/dts/rockchip/rk3588-evb.dtsi]
&usbdrd3_1 {
status = "okay";
};

3.DWC3驱动初始化

在xhci驱动初始化之前,需要dwc3驱动做一些底层的初始化,主要是非XHCI协议的硬件初始化,如模式、时钟、PHY等。dwc3驱动的主要工作如下:

  1. 首先初始化的是外围的rockchip驱动,内部的dwc3驱动由rockchip驱动进行匹配。

  2. 接着进入dwc3的驱动初始化流程,工作流程如下:解复位控制器。

  3. 获取控制器硬件配置的模式,并和软件配置的模式进行比较,起到校验作用

  4. dwc3核心初始化,包括配置PHY接口、初始化PHY、给PHY上电、调整帧长度、使能Auto retry Feature等。

  5. 根据配置的模式,进入对应的模式。若是Host,则需要将USB2.0 PHY和USB3.0 PHY设置为PHY_MODE_USB_HOST,然后注册xhci的platform_device

4.xHCI驱动初始化

dwc3驱动将设备树中的USB Host设备节点转换成platform_device,并将其name设置为"xhci-hcd",然后调用platform_device_add注册到系统中。USB Host驱动通过platform_driver实现,通过xhci_plat_init和xhci_plat_exit注册和注销。当USB Host设备或USB Host驱动注册的时候,都会调用platform_match去匹配对方,若匹配成功,则会调用USB Host驱动中的probe函数,即usb_xhci_driver中的xhci_plat_probe函数。

[drivers/usb/host/xhci-plat.c]
static struct platform_driver usb_xhci_driver = {
.probe = xhci_plat_probe,
.remove = xhci_plat_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xhci-hcd",
.pm = &xhci_plat_pm_ops,
.of_match_table = of_match_ptr(usb_xhci_of_match),
.acpi_match_table = ACPI_PTR(usb_xhci_acpi_match),
},
};
MODULE_ALIAS("platform:xhci-hcd"); static int __init xhci_plat_init(void)
{
xhci_init_driver(&xhci_plat_hc_driver, &xhci_plat_overrides);
return platform_driver_register(&usb_xhci_driver);
}
module_init(xhci_plat_init); static void __exit xhci_plat_exit(void)
{
platform_driver_unregister(&usb_xhci_driver);
}
module_exit(xhci_plat_exit);

xhci_plat_probe函数中会注册xHCI控制器的硬件操作函数集合,即xhci_hc_driver数据结构,如下所示。

[drivers/usb/host/xhci.c]
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd),
/* generic hardware linkage */
.irq = xhci_irq,
.flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED | HCD_BH,
/* basic lifecycle operations */
.reset = NULL, /* xhci_plat_setup */
.start = xhci_run, /* xhci_plat_start */
.stop = xhci_stop,
.shutdown = xhci_shutdown,
/* managing i/o requests and associated device resources */
.map_urb_for_dma = xhci_map_urb_for_dma,
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.alloc_streams = xhci_alloc_streams,
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
.endpoint_disable = xhci_endpoint_disable,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.enable_device = xhci_enable_device,
.update_hub_device = xhci_update_hub_device,
.reset_device = xhci_discover_or_reset_device,
/* scheduling support */
.get_frame_number = xhci_get_frame,
/* root hub support */
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
.get_resuming_ports = xhci_get_resuming_ports,
/* call back when device connected and addressed */
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
.clear_tt_buffer_complete = xhci_clear_tt_buffer_complete,
};

USB主机驱动的初始化过程如下图所示,具体的流程如下:

  1. USB主机的设备和驱动通过platform_match匹配,匹配成功后,驱动的xhci_plat_probe函数被调用。
  2. 调用__usb_create_hcd函数 创建USB主机数据结构,即main_hcd(primary_hcd)和shared_hcd,前者为USB2.0,后者为USB3.0;创建USB主机数据结构的时候会初始化一个非常重要的定时器rh_timer,到期会调用rh_timer_func函数,该定时器的作用是轮询Hub的状态,检测USB设备连接、断开等情况。
  3. 调用usb_add_hcd注册USB2.0和USB3.0主机控制器,USB主机驱动的核心初始化工作在注册控制器时完成。
    1. 注册USB总线。
    2. 分配root hub的数据结构usb_device(root hub不是一个真实的USB设备,无需调用xhci_alloc_dev分配主机控制器资源);设置总线类型、设备类型和属性,总线类型usb_bus_type中的usb_device_match函数用于匹配USB设备和USB设备驱动,具体的匹配过程后面分析;使能使能root hub端点0,即将端点0的数据结构usb_host_endpoint放到usb_device输入输出端点的数组中,便于后续和USB设备通信。
    3. 调用xhci_plat_setup通过读取控制器的hcs_params寄存器获取寄存器地址、能力等信息,然后复位复位控制器,最后初始化xHCI需要的数据结构。
    4. 初始化root hub的tasklets,设置回调函数为usb_giveback_urb_bh,当root hub的port状态变化时,会调用usb_giveback_urb_bh处理。
    5. 注册USB2.0控制器的中断处理函数usb_hcd_irq(中断只需要注册一次,2.0和3.0公用),usb_hcd_irq内部会调用xhci_irq,该中断用于处理控制器传输数据、事件。
    6. 调用xhci_run使能xHCI控制器。
    7. 调用register_root_hub注册root hub。root hub虽然不是真实的USB设备,但也需要获取描述符,走枚举的流程。
      1. 获取设备描述符。使用控制传输,调用usb_control_msg
      2. 初始化root hub。主要是获取配置描述符(获取配置描述符时,会一并获取该配置下的接口描述符、端点描述符等)。
      3. 枚举成功后,打印root hub的设备信息(需要开启对应的选项,否则不打印)。
      4. 注册USB设备。内部会调用usb_device_match匹配USB设备驱动,对于hub,则会匹配到hub_driver,调用hub_probe函数。
    8. 当设置uses_new_pollingHCD_POLL_RH(hcd)标志时,内核会调用usb_hcd_poll_rh_status函数轮询hub状态,以此探测设备的连接、断开等状态变化。详细的轮询过程在下一节分析。

USB总线-Linux内核USB3.0主机控制器驱动初始化流程分析(十三)的更多相关文章

  1. 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级

    Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏: include\linux\init.h #define pure_initcall(fn) __define_initcall(& ...

  2. [RK3288][Android6.0] Display驱动初始化流程小结【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/52584903 Platform: RK3288OS: Android 6.0Kernel: ...

  3. 如何在Ubuntu/CentOS上安装Linux内核4.0

    大家好,今天我们学习一下如何从Elrepo或者源代码来安装最新的Linux内核4.0.代号为‘Hurr durr I'm a sheep’的Linux内核4.0是目前为止最新的主干内核.它是稳定版3. ...

  4. Linux内核3.0移植并基于Initramfs根文件系统启动

    Linux内核移植与启动 Target borad:FL2440 Bootloader:U-boot-2010.09 交叉编译器:buildroot-2012.08 1.linux内核基础知识 首先, ...

  5. 安装 Linux 内核 4.0

    大家好,今天我们学习一下如何从Elrepo或者源代码来安装最新的Linux内核4.0.代号为‘Hurr durr I'm a sheep’的Linux内核4.0是目前为止最新的主干内核.它是稳定版3. ...

  6. Win7原装ISO镜像封装USB3.0&网卡驱动

    Win7原装ISO镜像封装USB3.0&网卡驱动   最新购买的电脑是Windows10系统,想装回Windows7,但是装Windows7发现网络适配器没出现,如果没有USB2.0接口,US ...

  7. Linux内核中的list用法和实现分析

    这些天在思考知识体系的完整性,发现总是对消息队列的实现不满意,索性看看内核里面的链表实现形式,这篇文章就当做是学习的i笔记吧.. 内核代码中有很多的地方使用了list,而这个list的用法又跟我们平时 ...

  8. 基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植(四)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  9. win7安装镜像注入USB3.0,NVMe驱动

    现在的新款主板和笔记本因为原生自带了USB3.0和NVMe,在安装WIN7的时候会出现进入安装界面后不识别USB设备且在硬盘列表中无法读取M.2类型的固态硬盘信息.导致这个现象的原因就是在WIN7安装 ...

  10. Linux内核编程-0:来自内核的 HelloWorld

    Linux内核编程一直是我很想掌握的一个技能.如果问我为什么,我也说不上来. 也许是希望有一天自己的ID也出现在内核开发组的邮件列表里?或是内核发行文件的CREDITS文件上? 也许是吧.其实更多的, ...

随机推荐

  1. 入门Vue+.NET 8 Web Api记录(一)

    做自己感觉有意思的或者能解决自己需求的项目作为入门,我觉得是有帮助的,不会觉得那么无聊. 一个最简单的前后端分离项目应该是怎么样的? 我觉得就是前端有个按钮,点击向后端发送一个get请求,获取到数据后 ...

  2. 【Vue】树状节点接口 与 级联选择框组件

    原来有一个组织机构的渲染, 我自己写的我自己看也8太明白了: https://www.cnblogs.com/mindzone/p/14888046.html 现在,有一个位置选择,使用这个级联选择器 ...

  3. conda环境下安装nvidia-nvcc

    参考: https://www.cnblogs.com/littletreee/p/17234053.html conda安装Pytorch或TensorFlow的时候是默认不安装nvcc,但是有时候 ...

  4. 老版本mujoco: mujoco 1.31 1.40 1.50 2.00 版本下载地址

    下载地址: https://www.roboti.us/download.html 激活码下载地址: https://www.roboti.us/file/mjkey.txt 安装教程: https: ...

  5. 再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(5) —— 第一个用于解决2048游戏的Reinforcement learning方法——《Temporal Difference Learning of N-Tuple Networks for the Game 2048》

    <2048>游戏在线试玩地址: https://play2048.co/ 如何解决<2048>游戏源于外网的一个讨论帖子,而这个帖子则是讨论如何解决该游戏的最早开始,可谓是&q ...

  6. Game of CS 题解

    前言 题目链接:洛谷:UVA. 题意简述 Jolly 和 Emily 在玩一个游戏.游戏在一棵编号为 \([0, n-1]\) 的有根树上进行,根节点是 \(0\),每条边都有一个长度,初始所有边都没 ...

  7. .NET 屏幕录制

    窗口/屏幕截图适用于截图.批注等工具场景,时时获取窗口/屏幕图像数据流呢,下面讲下视频会议共享桌面.远程桌面这些场景是如何实现画面录制的. 常见的屏幕画面时时采集方案,主要有GDI.WGC.DXGI. ...

  8. RabbitMq高级特性之死信队列 通俗易懂 超详细 【内含案例】

    RabbitMq高级特性之死信队列 又称 死信交换机 DLX 介绍 当消息成为 Dead message 后,会重新发送到另一个交换机,这个交换机就是 DLX(死信交换机) 消息成为死信的情况公有三种 ...

  9. springboot代码自动生成

    在项目开始阶段经常需要自动生成一批代码,如果使用了mybatis则可以使用mybatis plus就可以生成mybatis相关代码.不过经常项目中还有一些mvc代码需要生成,比如说前端代码.相关sql ...

  10. Kummer 定理

    \(n!\) 中含素数 \(p\) 的幂次为 \(\displaystyle\sum_{i=1}\lfloor\frac{n}{p^{i}}\rfloor\) Kummer 定理:\({n+m\cho ...