Uboot DM9621网卡移植之路

前言

根据前面文章USB和Ethernet协议了解与原理图分析DM_USB和DM_ETH模型简介所介绍,想必大家已经知道移植的流程应该是如何了,这里再简单的给出大致步骤,如下。

  • 移植USB Host Controller驱动
  • 使能USB3503 Hub
  • 移植DM9621驱动
  • 测试验证功能性

接下来就按照这几个步骤进行Uboot中DM9621网卡的移植之路,最终实现在Uboot中使用网络命令进行内核的加载等操作。

移植开始

移植USB Host Controller驱动

该部分驱动已经有三星官方提供到Uboot主线中,我们下载的源码包里面已经有对应的代码,drivers/usb/host/ehci-exynos.c文件包含了其实现。我们要做的只是将其编译选项打开,编译进Uboot最终bin文件中即可,下面给出详细的步骤。

打开编译选项

  • Kconfig中打开主机驱动宏,对应路径如下
	Device Drivers  --->
		[*] USB support  ---> 

USB主机控制器驱动

  • 打开Exynos4412对应的宏CONFIG_USB_EHCI_EXYNOS
diff --git a/include/configs/itop4412.h b/include/configs/itop4412.h
index c071e02..5bd5fdc 100644
--- a/include/configs/itop4412.h
+++ b/include/configs/itop4412.h
@@ -35,6 +35,9 @@
 /* #define MACH_TYPE_ITOP4412          0xffffffff */
 #define CONFIG_MACH_TYPE                       MACH_TYPE_ITOP4412
 
+/* USB */
+#define CONFIG_USB_EHCI_EXYNOS
+
 /* select serial console configuration */
 #define CONFIG_SERIAL2
  • 打开Uboot的USB命令宏,对应路径如下
	Command line interface  ---> 
		Device access commands  --->
			[*] usb

设备树修改

加入ehci设备描述信息,如下:

 45     ehci@12580000 {
 46         compatible = "samsung,exynos-ehci";
 47         reg = <0x12580000 0x100>;
 48         #address-cells = <1>;
 49         #size-cells = <1>;
 50         status = "okay";
 51         /* In order to reset USB ethernet, DM9621 RESET IO pin */
 52         samsung,vbus-gpio = <&gpc0 1 0>;
 53         phy {
 54             compatible = "samsung,exynos-usb-phy";
 55             reg = <0x125B0000 0x100>;
 56         };
 57     };

编译与调试

在上述操作编译完成后,就能使用USB主机控制器了,在终端键入USB start便可以看到有相应的USB信息输出,接下来便可以进行USB 3503的配置与使能。

使能USB3503 Hub

配置GPIO

根据前面文章USB和Ethernet协议了解与原理图分析的分析,USB 3503 Hub芯片配置简单,只需要做些IO操作便可。通过地板原理图核心板原理图查找分析,需要操作GPM3_3 (USB3503_CONNECT)GPM2_4 (USB3503_RESET)。这里使用Uboot的IO驱动模型,而不是直接写寄存器,通过对应的宏和标准GPIO接口调用,便可以完成对USB Hub芯片的初始化,下面给出代码。

diff --git a/board/samsung/itop4412/itop4412.c b/board/samsung/itop4412/itop4412.c
index 99a2fac..3068cd4 100644
--- a/board/samsung/itop4412/itop4412.c
+++ b/board/samsung/itop4412/itop4412.c
@@ -12,6 +12,14 @@
 #include <asm/arch/periph.h>
 #include <asm/arch/pinmux.h>
 #include <usb.h>
+#include <usb/dwc2_udc.h>
+
+#define DEBUG
+#ifdef  DEBUG
+#undef  debug
+#define debug(fmt, args...) debug_cond(true, fmt, ##args)
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -20,15 +28,82 @@ u32 get_board_rev(void)
        return 0;
 }
 
+static void board_gpio_init(void)
+{
+#ifdef CONFIG_CMD_USB
+    /* USB3503A Connect */
+    gpio_request(EXYNOS4X12_GPIO_M33, "USB3503A Connect");
+
+    /* USB3503A Reset */
+    gpio_request(EXYNOS4X12_GPIO_M24, "USB3503A Reset");
+
+    /* Red LED2 Light On */
+    gpio_request(EXYNOS4X12_GPIO_L20, "Red LED2");
+    gpio_direction_output(EXYNOS4X12_GPIO_L20, 1);
+#endif
+}
+
 int exynos_init(void)
 {
+    debug("---> ready to call board_gpio_init()!\n");
+    board_gpio_init();
+
+    /* FIXME: maybe should be not called in here */
+    board_usb_init(0, USB_INIT_DEVICE);
+
        return 0;
 }
 
+#ifdef CONFIG_USB_GADGET
+static int s5pc210_phy_control(int on)
+{
+    /* FIXME: need to set power? */
+#if 0
+    struct udevice *dev;
+    int ret;
+
+    ret = regulator_get_by_platname("VDD_UOTG_3.0V", &dev);
+    if (ret) {
+        pr_err("Regulator get error: %d", ret);
+        return ret;
+    }
+
+    if (on)
+        return regulator_set_mode(dev, OPMODE_ON);
+    else
+        return regulator_set_mode(dev, OPMODE_LPM);
+#else
+    return 0;
+#endif
+}
+
+struct dwc2_plat_otg_data s5pc210_otg_data = {
+    .phy_control    = s5pc210_phy_control,
+    .regs_phy   = EXYNOS4X12_USBPHY_BASE,
+    .regs_otg   = EXYNOS4X12_USBOTG_BASE,
+    .usb_phy_ctrl   = EXYNOS4X12_USBPHY_CONTROL,
+    .usb_flags  = PHY0_SLEEP,
+};
+#endif
+
+#if defined(CONFIG_USB_GADGET) || defined(CONFIG_CMD_USB)
+
 int board_usb_init(int index, enum usb_init_type init)
 {
-       return 0;
+#ifdef CONFIG_CMD_USB
+    debug("---> ready to init usb3503\n");
+
+    /* 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
+    debug("USB_udc_probe\n");
+       return dwc2_udc_probe(&s5pc210_otg_data);
 }
+#endif
 
 #ifdef CONFIG_BOARD_EARLY_INIT_F
 int exynos_early_init_f(void)

编译与调试

在执行完这步骤的时候,执行usb start; usb reset后,便会有下面的对应输出,说明USB 3503已经在正常工作了,并且DM9621网卡已经使能了,接下来就是初始化并配置设备和适配到DM_ETH模型的操作了。

CPU:   Exynos4412 @ 1 GHz
Model: itop-4412 based on Exynos4412
Board: itop-4412 based on Exynos4412
DRAM:  1 GiB
WARNING: Caches not enabled
---> ready to call board_gpio_init()!
---> ready to init usb3503
USB_udc_probe
MMC:   SAMSUNG SDHCI: 0, EXYNOS DWMMC: 1
Net:   No ethernet found.
Hit any key to stop autoboot:  0 
u-boot # usb start
starting USB...
USB0:   USB EHCI 1.00
scanning bus 0 for devices... 1 USB Device(s) found
u-boot # usb reset
resetting USB...
USB0:   USB EHCI 1.00
scanning bus 0 for devices... 3 USB Device(s) found
u-boot # 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)
         ?  
       
u-boot # 

移植DM9621驱动

说明

在上面的步骤执行完,可以发现DM9621设备已经使能,能在USB总线上看到该设备了,接下来需要初始化和配置,并根据DM_ETH模型来提供相应的操作集便可。

移植开始

根据上篇文章DM_USB和DM_ETH模型简介所介绍,我们需要提供以下标准接口:

  • 设备驱动
  • 设备驱动操作集
  • 设备
  • 设备相关接口(因物理设备而异)

设备驱动

+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
+};
+
+U_BOOT_USB_DEVICE(dm9601_eth, dm9601_eth_id_table);

关键接口

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结构体

23  struct ueth_data {
24      /* eth info */
25  #ifdef CONFIG_DM_ETH
26      uint8_t *rxbuf;
27      int rxsize;
28      int rxlen;          /* Total bytes available in rxbuf */
29      int rxptr;          /* Current position in rxbuf */
30  #else
31      struct eth_device eth_dev;  /* used with eth_register */
32      /* driver private */
33      void *dev_priv;
34  #endif
35      int phy_id;         /* mii phy id */
36  
37      /* usb info */
38      struct usb_device *pusb_dev;    /* this usb_device */
39      unsigned char   ifnum;      /* interface number */
40      unsigned char   ep_in;      /* in endpoint */
41      unsigned char   ep_out;     /* out ....... */
42      unsigned char   ep_int;     /* interrupt . */
43      unsigned char   subclass;   /* as in overview */
44      unsigned char   protocol;   /* .............. */
45      unsigned char   irqinterval;    /* Intervall for IRQ Pipe */
46  };

主要接口

博主原本想简单的概括一下关键接口的作用即可,但是觉得还是头文件中的声明和注释更能说明其用途,这里直接给出头文件include/usb_ether.h中的内容,如下所示。

49	/**
50	 * usb_ether_register() - register a new USB ethernet device
51	 *
52	 * This selects the correct USB interface and figures out the endpoints to use.
53	 *
54	 * @dev:	USB device
55	 * @ss:		Place to put USB ethernet data
56	 * @rxsize:	Maximum size to allocate for the receive buffer
57	 * @return 0 if OK, -ve on error
58	 */
59	int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize);
60	
61	/**
62	 * usb_ether_deregister() - deregister a USB ethernet device
63	 *
64	 * @ueth:	USB Ethernet device
65	 * @return 0
66	 */
67	int usb_ether_deregister(struct ueth_data *ueth);
68	
69	/**
70	 * usb_ether_receive() - recieve a packet from the bulk in endpoint
71	 *
72	 * The packet is stored in the internal buffer ready for processing.
73	 *
74	 * @ueth:	USB Ethernet device
75	 * @rxsize:	Maximum size to receive
76	 * @return 0 if a packet was received, -EAGAIN if not, -ENOSPC if @rxsize is
77	 * larger than the size passed ot usb_ether_register(), other -ve on error
78	 */
79	int usb_ether_receive(struct ueth_data *ueth, int rxsize);
80	
81	/**
82	 * usb_ether_get_rx_bytes() - obtain bytes from the internal packet buffer
83	 *
84	 * This should be called repeatedly to obtain packet data until it returns 0.
85	 * After each packet is processed, call usb_ether_advance_rxbuf() to move to
86	 * the next one.
87	 *
88	 * @ueth:	USB Ethernet device
89	 * @ptrp:	Returns a pointer to the start of the next packet if there is
90	 *		one available
91	 * @return number of bytes available, or 0 if none
92	 */
93	int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp);
94	
95	/**
96	 * usb_ether_advance_rxbuf() - Advance to the next packet in the internal buffer
97	 *
98	 * After processing the data returned by usb_ether_get_rx_bytes(), call this
99	 * function to move to the next packet. You must specify the number of bytes
100	 * you have processed in @num_bytes.
101	 *
102	 * @ueth:	USB Ethernet device
103	 * @num_bytes:	Number of bytes to skip, or -1 to skip all bytes
104	 */
105	void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes);

具体实现

首先需要实现struct eth_ops里的接口和对应的probe接口,如何实现可以参考driver/usb/eth/asix.c;对设备内部的操作,可以移植linux内核驱动里面的driver/net/usb/dm9601.c中的实现到Uboot框架即可,具体文件dm9601.c

编译配置

在移植好C程序后,还需要将代码编译进最终的u-boot.bin文件中,需要对Kconfig和Makefile文件增加相应的配置选项。

说明

本次移植是基于DM_ETH和DM_USB模型移植的,需要先使能如下配置,更多配置参阅文件itop4412_defconfig

  • CONFIG_DM_USB=y
  • CONFIG_DM_ETH=y
  • CONFIG_USB_HOST_ETHER=y
  • CONFIG_USB_ETHER_DM9601=y
  • CONFIG_NET=y
  • CONFIG_CMD_USB=y
  • CONFIG_CMD_NET=y

其中CONFIG_USB_ETHER_DM9601=y为新增配置

Kconfig文件

diff --git a/u-boot-2017.11-bsp/u-boot-2017.11/drivers/usb/eth/Kconfig b/arm-devlop/uboot-2017-11/drivers/usb/eth/Kconfig
index 496a6d1..01b0d86 100644
--- a/u-boot-2017.11-bsp/u-boot-2017.11/drivers/usb/eth/Kconfig
+++ b/arm-devlop/uboot-2017-11/drivers/usb/eth/Kconfig
@@ -60,4 +60,11 @@ config USB_ETHER_SMSC95XX
 	  Say Y here if you would like to support SMSC LAN95xx based USB 2.0
 	  Ethernet Devices.
 
+config USB_ETHER_DM9601
+	bool "DAVICOM DM9601 (USB 2.0) support"
+	depends on USB_HOST_ETHER && DM_ETH
+	---help---
+	  Say Y here if you would like to support DAVICOM DM9601 based USB 2.0
+	  Ethernet Devices.
+
 endif

Makefile文件

diff --git a/u-boot-2017.11-bsp/u-boot-2017.11/drivers/usb/eth/Makefile b/arm-devlop/uboot-2017-11/drivers/usb/eth/Makefile
index 4b935a3..68491d4 100644
--- a/u-boot-2017.11-bsp/u-boot-2017.11/drivers/usb/eth/Makefile
+++ b/arm-devlop/uboot-2017-11/drivers/usb/eth/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o
 obj-$(CONFIG_USB_ETHER_LAN75XX) += lan7x.o lan75xx.o
 obj-$(CONFIG_USB_ETHER_LAN78XX) += lan7x.o lan78xx.o
 obj-$(CONFIG_USB_ETHER_RTL8152) += r8152.o r8152_fw.o
+obj-$(CONFIG_USB_ETHER_DM9601) += dm9601.o

总结

到这一步已经完成了绝大部分工作了,剩下的便是编译并烧写到TF卡中,再讲拨码开关调到TF卡启动,最终运行查看效果。一运行就发现有如下的错误:

情况一

在运行到接收以太帧的时候,出现了data abrot异常,如下:

data abort
pc : [<7fe9a2a0>]	   lr : [<7aede325>]
reloc pc : [<43e432a0>]	   lr : [<3ee87325>]
sp : 7ae54ce0  ip : 00000014	 fp : 00000fff
r10: 00000fff  r9 : 7ae54ed8	 r8 : 0000002e
r7 : 00000fff  r6 : 7aede303	 r5 : 0000001c  r4 : 7aede311
r3 : 00000000  r2 : 7aede311	 r1 : 00000014  r0 : 7aede311
Flags: nzCv  IRQs off  FIQs off  Mode SVC_32
Resetting CPU ...

情况二

在解决完上面问题后,又出现了启动linux内核的时候,出现校验失败的问题,如下:

 Verifying Checksum ... Bad Data CRC
  ERROR: can't get kernel image!

看到这里想必有点懵,不知道从哪里做起,没事,下篇文章Uboot 网卡移植遇到的问题与解决方法博主给你解答。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值