文章目录
一、前言
由于目前没有支持网卡驱动,所以 uboot 网络相关的命令都使用不起来,很不方便 (一直使用 fastboot 命令来烧写,因为我只有平板一条数据线,所以想给平板充电就成了一个问题),如果能用网络烧写那就方便多了。
又看到已经有大佬完成,那更要学习学习。
大佬文章链接:
二、硬件环境
1. Exynos4412 (USB 2.0 Host Controller)
Exynos4412 SOC内部集成了USB 2.0的主机控制器,默认Uboot是不支持USB功能的,主机驱动都是三星官方提供的,只需要我们做一定配置,编译进去便可支持。下面为功能块图,详细细节请查阅手册。
2. USB3503 (USB HUB)
核心板板载一个USB HUB IC,也就是USB3503,与SOC和DM9621直接相连。因其使用和配置简单,我们只需要将其CTL pin
进行相应的IO操作,便可使其正常工作,连接起SOC和下端的DM9621,主要的原理图如下。
3. DM9621 (USB Device)
最后是Davicom DM9621 USB转Ethernet网卡芯片,控制与数据传输都是通过USB总线。这里需要操作CTL pin
去使能该芯片,再做相应的寄存器配置,便可正常驱动该芯片。通过USB总线与SOC进行通信,Uboot有封装完善的USB接口,非常方便。移植成功后,便可以使用Uboot的网络工具,如tftpboot, 进行相应的网络通信,下面为其主要的原理图。
三、移植步骤
1. 移植USB Host Controller驱动
该部分驱动已经有三星官方提供到Uboot主线中,我们下载的源码包里面已经有对应的代码,drivers/usb/host/ehci-exynos.c
文件包含了其实现。我们要做的只是将其编译选项打开,编译进Uboot最终bin文件中即可,下面给出详细的步骤。
1.1 打开编译选项
- Kconfig中打开主机驱动宏,对应路径如下
Device Drivers --->
[*] USB support --->
[*] EHCI HCD (USB 2.0) support
- 打开Exynos4412对应的宏
CONFIG_USB_EHCI_EXYNOS
仿照 include/configs/odroid.h
第 177 行,也添加这样两行到 include/configs/xhr4412.h
中,定义这个宏就可以了。
/* USB */
#define CONFIG_USB_EHCI_EXYNOS
- 打开Uboot的USB命令宏,对应路径如下
Command line interface --->
Device access commands --->
[*] usb
1.2 修改设备树
- 加入ehci设备描述信息,如下:
ehci@12580000 {
compatible = "samsung,exynos-ehci";
reg = <0x12580000 0x100>;
#address-cells = <1>;
#size-cells = <1>;
status = "okay";
/* In order to reset USB ethernet, DM9621 RESET IO pin */
samsung,vbus-gpio = <&gpc0 1 0>;
phy {
compatible = "samsung,exynos-usb-phy";
reg = <0x125B0000 0x100>;
};
};
1.3 编译与调试
在上述操作编译完成后,就能使用USB主机控制器了,在终端键入 usb start
便可以看到有相应的USB信息输出,接下来便可以进行 USB 3503 的配置与使能。
2. 使能USB3503 Hub
2.1 配置GPIO
根据前面文章《USB和Ethernet协议了解与原理图分析的分析》,USB 3503 Hub芯片配置简单,只需要做些IO操作便可。通过地板原理图核心板原理图查找分析,需要操作 GPM3_3 (USB3503_CONNECT)
和 GPM2_4 (USB3503_RESET)
。这里使用Uboot的IO驱动模型,而不是直接写寄存器,通过对应的宏和标准GPIO接口调用,便可以完成对USB Hub芯片的初始化,下面给出代码。
board/samsung/xhr4412/xhr4412.c
exynos_init()
函数中添加 usb gpio 的操作。
int exynos_init(void)
{
#ifdef CONFIG_CMD_USB
debug("---> ready to init usb3503\n");
/* USB3503A Connect */
gpio_request(EXYNOS4X12_GPIO_M33, "USB3503A Connect");
/* USB3503A Reset */
gpio_request(EXYNOS4X12_GPIO_M24, "USB3503A Reset");
/* USB3503A Disconnect, Reset, Connect */
gpio_direction_output(EXYNOS4X12_GPIO_M33, 0);
gpio_direction_output(EXYNOS4X12_GPIO_M24, 0);
gpio_direction_output(EXYNOS4X12_GPIO_M24, 1);
gpio_direction_output(EXYNOS4X12_GPIO_M33, 1);
#endif
return 0;
}
2.2 编译与调试
在执行完这步骤的时候,执行 usb start; usb reset; usb tree
后,便会有下面的对应输出,说明 USB 3503 已经在正常工作了,并且DM9621网卡已经使能了,接下来就是初始化并配置设备和适配到DM_ETH模型的操作了。
xhr4412 # usb start
starting USB...
Bus ehci@12580000: USB EHCI 1.00
scanning bus ehci@12580000 for devices... 1 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
xhr4412 # usb reset
resetting USB...
Bus ehci@12580000: USB EHCI 1.00
scanning bus ehci@12580000 for devices... 3 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
xhr4412 # usb tree
USB device tree:
1 Hub (480 Mb/s, 0mA)
| u-boot EHCI Host Controller
|
+-2 Hub (480 Mb/s, 2mA)
|
+-3 See Interface (480 Mb/s, 180mA)
?
xhr4412 #
3. 移植DM9621驱动
在上面的步骤执行完,可以发现DM9621设备已经使能,能在USB总线上看到该设备了,接下来需要初始化和配置,并根据DM_ETH模型来提供相应的操作集便可。
3.1 移植开始
根据上篇文章《Uboot DM_USB与DM_ETH模型》所介绍,我们需要提供以下标准接口:
- 设备驱动
- 设备驱动操作集
- 设备
- 设备相关接口(因物理设备而异)
drivers/usb/eth/
目录下有很多类似的 usb 网卡驱动,可以仿照其中的驱动来写我们的驱动。
创建文件:
drivers/xhr4412_driver/dm9601_eth.c
设备驱动
U_BOOT_DRIVER(dm9601_eth) = {
.name = "dm9601_eth",
.id = UCLASS_ETH,
.probe = dm9601_eth_probe,
.ops = &dm9601_eth_ops,
.priv_auto_alloc_size = sizeof(struct dm9601_private),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};
设备驱动操作集
static const struct eth_ops dm9601_eth_ops = {
.start = dm9601_eth_start,
.send = dm9601_eth_send,
.recv = dm9601_eth_recv,
.free_pkt = dm9601_free_pkt,
.stop = dm9601_eth_stop,
.write_hwaddr = dm9601_write_hwaddr,
};
设备
static const struct usb_device_id dm9601_eth_id_table[] = {
{ USB_DEVICE(0x07aa, 0x9601), }, /* Corega FEther USB-TXC */
{ USB_DEVICE(0x0a46, 0x9601), }, /* Davicom USB-100 */
{ USB_DEVICE(0x0a46, 0x6688), }, /* ZT6688 USB NIC */
{ USB_DEVICE(0x0a46, 0x0268), }, /* ShanTou ST268 USB NIC */
{ USB_DEVICE(0x0a46, 0x8515), }, /* ADMtek ADM8515 USB NIC */
{ USB_DEVICE(0x0a47, 0x9601), }, /* Hirose USB-100 */
{ USB_DEVICE(0x0fe6, 0x8101), }, /* DM9601 USB to Fast Ethernet Adapter */
{ USB_DEVICE(0x0fe6, 0x9700), }, /* DM9601 USB to Fast Ethernet Adapter */
{ USB_DEVICE(0x0a46, 0x9000), }, /* DM9000E */
{ USB_DEVICE(0x0a46, 0x9620), }, /* DM9620 USB to Fast Ethernet Adapter */
{ USB_DEVICE(0x0a46, 0x9621), }, /* DM9621A USB to Fast Ethernet Adapter */
{ USB_DEVICE(0x0a46, 0x9622), }, /* DM9622 USB to Fast Ethernet Adapter */
{ USB_DEVICE(0x0a46, 0x0269), }, /* DM962OA USB to Fast Ethernet Adapter */
{ USB_DEVICE(0x0a46, 0x1269), }, /* DM9621A USB to Fast Ethernet Adapter */
{}, // END
};
关键接口
DM9621系列网卡为USB转以太网卡设备,在主线中已经有相关的驱动框架使用,我们需要使用 usb_ether.c
文件中的关键接口,如下:
usb_ether_register
usb_ether_deregister
usb_ether_receive
usb_ether_advance_rxbuf
usb_ether_get_rx_bytes
ueth_data结构体
struct ueth_data {
/* eth info */
#ifdef CONFIG_DM_ETH
uint8_t *rxbuf;
int rxsize;
int rxlen; /* Total bytes available in rxbuf */
int rxptr; /* Current position in rxbuf */
#else
struct eth_device eth_dev; /* used with eth_register */
/* driver private */
void *dev_priv;
#endif
int phy_id; /* mii phy id */
/* usb info */
struct usb_device *pusb_dev; /* this usb_device */
unsigned char ifnum; /* interface number */
unsigned char ep_in; /* in endpoint */
unsigned char ep_out; /* out ....... */
unsigned char ep_int; /* interrupt . */
unsigned char subclass; /* as in overview */
unsigned char protocol; /* .............. */
unsigned char irqinterval; /* Intervall for IRQ Pipe */
};
3.2 具体实现
首先需要实现 struct eth_ops
里的接口和对应的 probe
接口,如何实现可以参考 driver/usb/eth/asix.c
;对设备内部的操作,可以移植 linux 内核驱动里面的 driver/net/usb/dm9601.c
中的实现到 Uboot 框架即可。
说起来简单,不过真的要把接口都对上那肯定得用不少功才行,看得出大佬也调试了挺久的。
Uboot 网卡移植遇到的问题与解决方法
3.3 编译配置
本次移植是基于 DM_ETH 和 DM_USB 模型移植的,需要先使能如下配置:
CONFIG_DM_USB=y
CONFIG_DM_ETH=y
CONFIG_NET=y
CONFIG_CMD_USB=y
CONFIG_CMD_NET=y
CONFIG_USB_HOST_ETHER=y
CONFIG_USB_ETHER_DM9601=y
由于大佬之前已经移植好了,拿到手上修改了一些头文件就可以编译通过。
3.4 调试
问题一
Misaligned operation at range
xhr4412 # ping 192.168.177.128
CACHE: Misaligned operation at range [7ae6e5ef, 7ae6e600]
CACHE: Misaligned operation at range [7ae6e5ef, 7ae6e600]
CACHE: Misaligned operation at range [7ae6e5ef, 7ae6e600]
Using dm9601_eth device
host 192.168.177.128 is alive
xhr4412 #
该问题是由于某些变量没有按照 cache 对齐,将 dm_read_reg()
等函数做适当的修改,都使用 ALLOC_CACHE_ALIGN_BUFFER
宏定义的 buff 就可以解决该问题。
问题二
EHCI timed out on TD - token=0x8008d80
xhr4412 # run nfs
Waiting for Ethernet connection... done.
Using dm9601_eth device
File transfer via NFS from server 192.168.177.128; our IP address is 192.168.177.132
Filename '/home/xhr/iTop4412/xhr4412/linux/xhr4412-linux-5.8.5/xhr4412-uImage.bin'.
Load address: 0x40007000
Loading: EHCI timed out on TD - token=0x88008d80
Rx: failed to receive: -5
T #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
##############################################EHCI timed out on TD - token=0x8008d80
Rx: failed to receive: -5
T EHCI timed out on TD - token=0x8008d80
Rx: failed to receive: -5
T EHCI timed out on TD - token=0x88008d80
Rx: failed to receive: -5
EHCI timed out on TD - token=0x8008d80
Rx: failed to receive: -5
T EHCI timed out on TD - token=0x88008d80
Rx: failed to receive: -5
done
Bytes transferred = 5223344 (4fb3b0 hex)
xhr4412 # bootm 40007000 - 41000000
drivers/usb/eth/asix.c
第 460 行有说到多延时一下,就可以避免这个问题?
/*
* Wait some more to avoid timeout on first transfer
* (e.g. EHCI timed out on TD - token=0x8008d80)
*/
mdelay(25);
这篇帖子写得很不错,是个大佬,大概意思是说这个问题和不同的硬件有关系,怪不得这个板子启动 linux 后,挂载 nfs 文件系统,有时 10 秒就可以挂载成功,有时要几十秒甚至一分多钟,也会打出 Waiting up to 100 more seconds for network.
的 log,就是在等待 usb 设备准备好吧。
那这个问题暂时不管了,虽然印的 warning log 比较让人心烦,但是并没有影响使用,通过网络下载的 uboot、kernel 都可以正常运行,再也不需要使用 fastboot 了。
四、总结
有前面大佬的开路,移植起来就轻松多了,半天就移植成功了。感谢大佬们的努力。
warning log 看着还是挺烦人的,以后看能不能解决。
参考
- Uboot-2017-11移植DM9621网卡专题【目录汇总】
- USB和Ethernet协议了解与原理图分析的分析
- Uboot DM_USB与DM_ETH模型
- Uboot 网卡移植遇到的问题与解决方法
- [Solved] EHCI timed out on TD - token=XXXX
[2020-09-24]
将 reset usb gpio 的代码放到 do_usb_start()
函数中更合理。