[xhr4412][extension 4] u-boot-2020.07 DM9621 网卡驱动移植

一、前言

   由于目前没有支持网卡驱动,所以 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 看着还是挺烦人的,以后看能不能解决。

参考


[2020-09-24]
   将 reset usb gpio 的代码放到 do_usb_start() 函数中更合理。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值