7.12.1. 配置指南

ZX 提供了 2 路 USB Host 端口 和 1 路 USB Device 端口,需要分别进行配置。

7.12.1.1. USB Host 配置

7.12.1.1.1. USB Host Controller 配置

首先需要配置好 USB Host Contoller ,ZX 在 1 个 USB Host 端口中提供了 2 类 Host Contoller:

  • 针对 USB 2.0 (High Speed) 的 EHCI 控制器

  • 针对 USB 1.0/1.1 (Low/Full Speed) 的 OHCI 控制器

在软件上需要需要分开配置。

7.12.1.1.1.1. EHCI 配置

  • Linux Kernel Kconfig 文件中使能相应 EHCI Driver:

> Device Drivers > USB support

 <*>   EHCI HCD (USB 2.0) support
 [*]     Root Hub Transaction Translators
 [*]     Improved Transaction Translator scheduling
 <*>     Support for ZX on-chip EHCI USB controller

备注

内核配置主要是通过 make menuconfig 命令进行kernel的功能选择

  • DTS 文件中配置相应 EHCI Device:

usbh0: usb@10210000 {
    compatible = "zx,aic-usbh-v1.0";
    reg = <0x0 0x10210000 0x0 0x100>;
    interrupts-extended = <&plic0 35 IRQ_TYPE_LEVEL_HIGH>, <&plic0 4 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cmu CLK_USBH0>;
    clock-names = "usbh";
    resets = <&rst RESET_USBH0>;
    reset-names = "usbh";
    dr_mode = "host";
};

usbh1: usb@10220000 {
    compatible = "zx,aic-usbh-v1.0";
    reg = <0x0 0x10220000 0x0 0x100>;
    interrupts-extended = <&plic0 37 IRQ_TYPE_LEVEL_HIGH>,
                        <&plic0 38 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cmu CLK_USBH1>;
    clock-names = "usbh";
    resets = <&rst RESET_USBH1>, <&rst RESET_USBPHY1>;
    reset-names = "usbh", "usbh-phy";
    dr_mode = "host";
};

备注

这些参数主要在文件 m4.dtsi 中,模块系统参数随 IC 的设定而定,一般不能进行更改,除非更换了新的 IC,则需要在专业人士的指导下进行更改。

7.12.1.1.1.2. OHCI 配置

  • Linux Kernel Kconfig 文件中使能相应 EHCI Driver:

> Device Drivers > USB support

 <*>   OHCI HCD (USB 1.1) support
 <*>     Support for ZX on-chip OHCI USB controller
  • DTS 文件中配置相应 EHCI Device:

ohci0: usb@10210400 {
    compatible = "zx,aic-ohci-v1.0";
    reg = <0x10210400 0x100>;
    interrupts = <&plic0 4 IRQ_TYPE_LEVEL_HIGH>;
    num-ports = <1>;
};

ohci1: usb@10220400 {
    compatible = "zx,aic-ohci-v1.0";
    reg = <0x10220400 0x100>;
    interrupts = <&plic0 6 IRQ_TYPE_LEVEL_HIGH>;
};

7.12.1.1.2. USB Interface 驱动配置

在配置好 USB Host Controller 以后,就能够正确识别插入 USB 总线的 Device 设备了。

但是 USB Device 有很多不同类型 (例如:U 盘、键盘鼠标、无线网卡 …) ,这些功能都是在 USB Device 中以 Interface 为单位提供的。所以要使用 USB Device 的具体功能,还需要配置不同类型 USB Interface 的驱动。

7.12.1.1.2.1. U 盘 配置

  • U 盘是 USB 2.0 设备,所以首先得配置好上节中的 EHCI,再进行下面的配置。

  • 在 Linux Kernel Kconfig 中使能对 USB Mass Storage 类型的 USB Interface 驱动的支持。

> Device Drivers > USB support

 <*>   USB Mass Storage support
  • 还需要使能其他相关配置:

块设备:

> Device Drivers

 [*] Block devices  --->

SCSI 设备:

> Device Drivers > SCSI device support

 <*> SCSI device support
 [*] legacy /proc/scsi/ support
     *** SCSI support type (disk, tape, CD-ROM) ***
 <*> SCSI disk support

文件系统:

> File systems > DOS/FAT/EXFAT/NT Filesystems

 <*> VFAT (Windows-95) fs support
  • 插入 U 盘,通过 mount 命令将 U 盘挂载到合适的目录下就可以操作了:

[aic@] #
[ 1591.469696] usb 1-1: new high-speed USB device number 3 using aic-ehci
[ 1591.674435] usb-storage 1-1:1.0: USB Mass Storage device detected
[ 1591.682567] scsi host0: usb-storage 1-1:1.0
[ 1592.692021] scsi 0:0:0:0: Direct-Access     SanDisk  Cruzer Blade     1.00 PQ: 0 ANSI: 6
[ 1592.714329] sd 0:0:0:0: [sda] 30842880 512-byte logical blocks: (15.8 GB/14.7 GiB)
[ 1592.724171] sd 0:0:0:0: [sda] Write Protect is off
[ 1592.730166] sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[ 1592.751720]  sda: sda1
[ 1592.768330] sd 0:0:0:0: [sda] Attached SCSI removable disk

[aic@] # mount -t vfat /dev/sda1 /mnt/u
[aic@] # ls /mnt/u
System Volume Information  u-boot-spl-dtb.bin
u-boot-dtb.bin             vmlinux
u-boot-dtb.img             zImage
u-boot-spl-dtb.aic
[aic@] #

7.12.1.1.2.2. USB 键盘/鼠标 配置

  • U 盘是 USB 1.0/1.1 设备,所以首先得配置好上节中的 OHCI,再进行下面的配置。

  • 在 Linux Kernel Kconfig 中使能对 USB HID 类型的 USB Interface 驱动的支持。

> Device Drivers > HID support > USB HID support

 <*> USB HID transport layer
  • 插入键盘鼠标,可以通过 /dev/input/event 文件读取到键盘鼠标上报的数据:

[aic@] #
[   14.210983] usb 2-1: new low-speed USB device number 2 using aic-ohci
[   14.478006] random: fast init done
[   14.497013] input: PixArt Dell MS116 USB Optical Mouse as /devices/platform/soc/10220400.usb/usb2/2-1/2-1:1.0/0003:413C:301A.0001/input/input2
[   14.510871] hid-generic 0003:413C:301A.0001: input: USB HID v1.11 Mouse [PixArt Dell MS116 USB Optical Mouse] on usb-10220400.usb-1/input0

[aic@] # hexdump /dev/input/event2
0000000 e138 5e0b 4c30 0004 0004 0004 0001 0009
0000010 e138 5e0b 4c30 0004 0001 0110 0001 0000
0000020 e138 5e0b 4c30 0004 0000 0000 0000 0000
0000030 e138 5e0b d657 0007 0004 0004 0001 0009
0000040 e138 5e0b d657 0007 0001 0110 0000 0000
0000050 e138 5e0b d657 0007 0000 0000 0000 0000
0000060 e139 5e0b 9085 0003 0004 0004 0001 0009
0000070 e139 5e0b 9085 0003 0001 0110 0001 0000
0000080 e139 5e0b 9085 0003 0000 0000 0000 0000
0000090 e139 5e0b a3bc 0005 0004 0004 0001 0009
00000a0 e139 5e0b a3bc 0005 0001 0110 0000 0000
00000b0 e139 5e0b a3bc 0005 0000 0000 0000 0000

7.12.1.2. USB Device 配置

首先要配置好 USB Device Controller。

7.12.1.2.1. USB Device Controller 配置

  • Linux Kernel Kconfig 文件中使能相应 UDC Driver:

> Device Drivers > USB support > USB Gadget Support > USB Peripheral Controller

 <*> ZX USB2.0 Device Controller
  • DTS 文件中配置相应 UDC Device:

aicudc: udc@10200000 {
    compatible = "zx,aic-udc-v1.0";
    reg = <0x0 0x10200000 0x0 0x1000>;
    interrupts-extended = <&plic0 34 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cmu CLK_USBD>, <&cmu CLK_USB_PHY0>;
    clock-names = "udc_clk";
    resets = <&rst RESET_USBD>, <&rst RESET_USBPHY0>;
    reset-names = "aicudc", "aicudc-ecc";
    status = "okay";
};

7.12.1.2.2. USB Gadget 配置

为了方便 Linux 系统模拟成各种类型的 USB Device,Linux 设计了一个 Gadget Device 。为了方便用户使用 ,Linux 又将 ConfigFS 引入 USB Device 子系统,用来灵活配置 Gadget Device

所以在使用 USB Device 时,在 Linux Kernel 中把这两者都配置成使能。

7.12.1.2.2.1. Gadget 配置

> Device Drivers > USB support

 <*>   USB Gadget Support  --->

7.12.1.2.2.2. ConfigFS 配置

> Device Drivers > USB support > USB Gadget Support

 <*>   USB Gadget functions configurable through configfs

7.12.1.2.3. USB Interface 配置

Gadget Device 基础之上,需要配置具体的 Interface / Function 才能提供具体的 USB Device 功能。

USB Gadget Device 可以模拟成各种功能的 USB 外设,例如:USB 串口、USB 网口、U 盘。。。

7.12.1.2.3.1. ACM 串口 配置

  • Linux Kernel Kconfig 文件中使能 CDC ACM 类型的 Gadget functions

> Device Drivers > USB support > USB Gadget Support

 <*>   USB Gadget functions configurable through configfs
 [*]     Abstract Control Model (CDC ACM)


> Device Drivers

 [*] Block devices  --->
  • 通过用户态的 configfs 文件接口创建包含 ACM 串口功能的 USB Device:

mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g1
cd g1
echo "0x1d6b" > idVendor
echo "0x0104" > idProduct
mkdir strings/0x409
ls strings/0x409/
echo "0123456789" > strings/0x409/serialnumber
echo "AIC Inc." > strings/0x409/manufacturer
echo "Bar Gadget" > strings/0x409/product
mkdir functions/acm.GS0
mkdir configs/c.1
ls configs/c.1
mkdir configs/c.1/strings/0x409
ls configs/c.1/strings/0x409/
echo "ACM" > configs/c.1/strings/0x409/configuration
ln -s functions/acm.GS0 configs/c.1
echo `ls /sys/class/udc` > UDC
  • 用户使用:

    1. 将单板的 USB Device 端口和 Windows PC 的 USB Host 端口连接,在 Windows PC 设备管理器会看到一个新的USB串口节点:

      image0

    2. 在 PC 端使用串口终端工具打开 COM12,波特率使用 115200。

    3. 在单板端执行: echo abd > /dev/ttyGS0 ,在 PC 端串口就会收到该字符串:

      image1

    4. 在单板端执行 cat /dev/ttyGS0 ,在 PC 端写一个字符串 “123412345” ,点回车后,在单板端也能收到该字符串。

7.12.1.2.3.2. U 盘 配置

  • Linux Kernel Kconfig 文件中 :

使能 Mass storage 类型的 Gadget functions ::

> Device Drivers > USB support > USB Gadget Support

 <*>   USB Gadget functions configurable through configfs
 [*]     Mass storage

使能环回块设备:

> Device Drivers

 <*>   Loopback device support
  • Busybox 中使能 losetup 命令:

>  Linux System Utilities

 [*] losetup (5.5 kb)
  • 通过用户态的 configfs 文件接口创建包含 Mass storage 存储功能的 USB Device:

dd if=/dev/zero of=/tmp/mass.img bs=128K count=132
losetup /dev/loop0 /tmp/mass.img
mkdir /tmp/media
mkfs.vfat /dev/loop0
mount -t vfat /dev/loop0 /tmp/media/
cp /linuxrc /tmp/media
sync

mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g_mass
cd g_mass
echo "0x200" > bcdUSB
echo "0x100" > bcdDevice
echo "0x1234" > idVendor
echo "0x5678" > idProduct
mkdir configs/c1.1
mkdir functions/mass_storage.0
echo /dev/loop0 > functions/mass_storage.0/lun.0/file
mkdir strings/0x409
echo "0123456789ABCDEF" > strings/0x409/serialnumber
echo "river" > strings/0x409/manufacturer
echo "river_msc" > strings/0x409/product
mkdir configs/c1.1/strings/0x409
echo "abc" > configs/c1.1/strings/0x409/configuration
ln -s functions/mass_storage.0 configs/c1.1
echo `ls /sys/class/udc` > UDC
  • 用户使用:

    1. 将单板的 USB Device 端口和 Windows PC 的 USB Host 端口连接,在 Windows PC 上会看到一个新增的 U 盘,可以正常读写。

7.12.1.2.3.3. NCM 网口 配置

  • Linux Kernel Kconfig 文件中 :

使能 CDC NCM 类型的 Gadget functions ::

> Device Drivers > USB support > USB Gadget Support

 <*>   USB Gadget functions configurable through configfs
 [*]     Network Control Model (CDC NCM)

使能 TCP/IP 支持:

> Networking support > Networking options

 [*] TCP/IP networking
  • 通过用户态的 configfs 文件接口创建包含 CDC NCM 以太网功能的 USB Device:

mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g_ncm
cd g_ncm
echo "0xA55A" > idVendor
echo "0x0111" > idProduct
mkdir strings/0x409
echo "0123456789" > strings/0x409/serialnumber
echo "Xyz Inc." > strings/0x409/manufacturer
echo "NCM gadget" > strings/0x409/product
mkdir functions/ncm.usb0
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "NCM" > configs/c.1/strings/0x409/configuration
ln -s functions/ncm.usb0 configs/c.1
echo `ls /sys/class/udc` > UDC

ifconfig usb0 up
ifconfig usb0 173.11.1.1
  • 用户使用:

    1. 将单板的 USB Device 端口和 Ubuntu PC 的 USB Host 端口连接,在 Ubuntu PC 会看到一个新的网络接口,名字随机,类似: enx0afcc15d3417

    2. 配置 Ubuntu PC 端的网口为同一网段地址, sudo ifconfig enx0afcc15d3417 173.11.1.2

    3. 两个网口相互可以 ping 通:

    ubuntu@ubuntu $ ping 173.11.1.1
    PING 173.11.1.1 (173.11.1.1) 56(84) bytes of data.
    64 bytes from 173.11.1.1: icmp_seq=1 ttl=64 time=10.3 ms
    64 bytes from 173.11.1.1: icmp_seq=2 ttl=64 time=5.02 ms
    

7.12.1.2.3.4. ECM 网口 配置

  • Linux Kernel Kconfig 文件中 :

使能 CDC ECM 类型的 Gadget functions ::

> Device Drivers > USB support > USB Gadget Support

 <*>   USB Gadget functions configurable through configfs
 [*]     Ethernet Control Model (CDC ECM)

使能 TCP/IP 支持:

> Networking support > Networking options

 [*] TCP/IP networking
  • 通过用户态的 configfs 文件接口创建包含 CDC ECM 以太网功能的 USB Device:

mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g_ecm
cd g_ecm
echo "0x1d6b" > idVendor
echo "0x0104" > idProduct
mkdir strings/0x409
echo "0123456789" > strings/0x409/serialnumber
echo "AIC Inc." > strings/0x409/manufacturer
echo "Bar Gadget" > strings/0x409/product
mkdir functions/ecm.usb0
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ECM" > configs/c.1/strings/0x409/configuration
ln -s functions/ecm.usb0 configs/c.1
echo `ls /sys/class/udc` > UDC

ifconfig usb0 up
ifconfig usb0 173.11.1.1
  • 用户使用:和上一节 NCM 网口 一样。

7.12.1.2.3.5. ADBD 配置

  • Linux Kernel Kconfig 文件中 :

使能 FunctionFS 类型的 Gadget functions ::

> Device Drivers > USB support > USB Gadget Support

 <*>   USB Gadget functions configurable through configfs
 [*]     Function filesystem (FunctionFS)

使能 TCP/IP 支持:

> Networking support > Networking options

 [*] TCP/IP networking
  • 通过用户态的 configfs 文件接口创建 FunctionFS 中的 USB Device,挂载完 FunctionFS 文件系统以后, adbd 通过 /dev/usb-ffs/adb 中映射成文件的 endpoint 直接和 USB Host 进行通讯:

mkdir /dev/pts
mount -t devpts none /dev/pts

mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g_adb
cd g_adb
echo "0x18d1" > idVendor
echo "0x4e26" > idProduct
mkdir configs/c.1
mkdir functions/ffs.adb
mkdir strings/0x409
mkdir configs/c.1/strings/0x409
echo "0123456789ABCDEF" > strings/0x409/serialnumber
echo "AIC Inc." > strings/0x409/manufacturer
echo "FunctionFS gadget (adb)" > strings/0x409/product
echo "Conf 1" > configs/c.1/strings/0x409/configuration
echo 120 > configs/c.1/MaxPower
ln -s functions/ffs.adb configs/c.1

mkdir -p /dev/usb-ffs/adb
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb

ifconfig lo up
ifconfig

cd /root
adbd&

sleep 1
echo `ls /sys/class/udc/` > /sys/kernel/config/usb_gadget/g_adb/UDC
  • 用户使用:

    1. 将单板的 USB Device 端口和 PC 的 USB Host 端口连接,在 PC 端运行 adb shell 命令即可进行 adb 操作。

7.12.1.3. USB OTG 配置

USB Host 0 和 USB Device 0 共享 1 路 phy。要么同时只能启用其中一种功能,要么启用 USB OTG 功能通过 id 管脚的值来动态切换对外功能。

  • Linux Kernel Kconfig 文件中使能相应 OTG Driver:

> Device Drivers > USB support

  [*]   OTG support
  [*]     Support for ZX on-chip OTG Switch
  • DTS 文件中配置相应 OTG Device:

otg: usb-otg {
    compatible = "zx,aic-otg-v2.0";
};

&otg {
    otg-mode = "auto";      //  = auto/host/device
    id-gpios = <&gpio_f 15 GPIO_ACTIVE_HIGH>;
    vbus-en-gpios = <&gpio_a 7 GPIO_ACTIVE_HIGH>;
    dp-sw-gpios = <&gpio_e 14 GPIO_ACTIVE_LOW>;
    status = "okay";
};

7.12.1.3.1. OTG 模式配置

OTG 可以配置成 Auto 模式 或者 Force 模式

  • Auto 模式。根据 id 管脚的电平来决定当前 OTG 端口工作模式为 Host / Device ,通常情况下 id = low 对应 Host 模式, id = high 对应 Device 模式。

  • Force 模式。手工配置工作模式,通过配置 /sys/devices/platform/soc/soc\:usb-otg/otg_mode 文件节点的值来改变当前 OTG 端口的工作模式, host 对应 Host 模式, device 对应 Device 模式。另外 auto 对应 Auto 模式,需要使用 id 管脚来进行判断。

两种模式对应 DTS 文件中的 otg 节点的不同配置:

Mode

DTS otg-mode 属性

DTS xxx-gpios 属性

运行时 Host / Device 切换方法

Auto

otg-mode = "auto"; (如果没有配置 otg-mode 属性, 默认也是 Auto 模式)

id-gpios 属性必须配置; vbus-en-gpiosdp-sw-gpios 属性根据硬件配置选配。

OTG 驱动根据 id-gpios 管脚的电平变化 自动切换 USB 工作模式为 Host / Device

Force

otg-mode = "device"; 或者 otg-mode = "host";

id-gpios 属性不需要配置; vbus-en-gpiosdp-sw-gpios 属性根据硬件配置选配。

需要配置文件节点来手工切换: echo devices > /sys/devices/platform/soc/soc\:usb-otg/otg_mode 或者 echo host > /sys/devices/platform/soc/soc\:usb-otg/otg_mode

7.12.1.3.2. OTG 相关 GPIO

从上面配置可以看到和 OTG 功能相关的 GPIO 管脚有 3 个:

  • id-gpios 。用来检测当前插入的是不是 OTG 线,如果为 OTG 线则需要把本机切换到 USB Host 模式,否则本机切换到 USB Device 模式。该管脚在 Auto 模式 模式下是必须配置的,如果缺少该管脚 OTG 只能工作在 Force 模式 手工进行切换。

  • vbus-en-gpios 。该管脚是用来控制 VBUS 的 5V 输出的,通常情况下:切换到 USB Host 模式时需要使能本机端的 VBUS 5V 输出给对端 Device 供电,切换到 USB Device 模式时需要关闭本机端的 VBUS 5V 输出转而对端 Host 的供电。(实际使用上来说,不论本端是 Host/Device 模式,也可以在 VBUS 上一直供电 5V 两边 VBUS 无压差则无漏电,这种情况下 vbus-en-gpios 无需配置。)

  • dp-sw-gpios 。该管脚是在 OTG 外出两个独立 Host、Device 端口时,用来控制外部 Switch 的。非该模式时, dp-sw-gpios 无需配置。

    image2

3 个 GPIO 管脚的具体使用场景如上图所示,用户根据自己的使用场景来选择配置哪些 GPIO。每个 GPIO 的 输入输出正反电平有效,可以通过 DTS 中的 GPIO_ACTIVE_HIGHGPIO_ACTIVE_LOW 来配置:

GPIO Name

Direction

GPIO_ACTIVE_HIGH

GPIO_ACTIVE_LOW

id-gpios

input

输入低电平 = Host,

输入高电平 = Device

输入低电平 = Device,

输入高电平 = Host

vbus-en-gpios

output

Host (VBUS on) = 输出高电平

Device (VBUS off) = 输出低电平

Host (VBUS on) = 输出低电平

Device (VBUS off) = 输出高电平

dp-sw-gpios

output

Host = 输出高电平

Device = 输出低电平

Host = 低电平

Device = 高电平