博客
关于我
Uboot DM9621网卡移植之路
阅读量:545 次
发布时间:2019-03-07

本文共 12277 字,大约阅读时间需要 40 分钟。

前言

根据前面文章、所介绍,想必大家已经知道移植的流程应该是如何了,这里再简单的给出大致步骤,如下。

  • 移植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.hindex 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 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.cindex 99a2fac..3068cd4 100644--- a/board/samsung/itop4412/itop4412.c+++ b/board/samsung/itop4412/itop4412.c@@ -12,6 +12,14 @@ #include 
#include
#include
+#include
++#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 GHzModel: itop-4412 based on Exynos4412Board: itop-4412 based on Exynos4412DRAM:  1 GiBWARNING: Caches not enabled---> ready to call board_gpio_init()!---> ready to init usb3503USB_udc_probeMMC:   SAMSUNG SDHCI: 0, EXYNOS DWMMC: 1Net:   No ethernet found.Hit any key to stop autoboot:  0 u-boot # usb startstarting USB...USB0:   USB EHCI 1.00scanning bus 0 for devices... 1 USB Device(s) foundu-boot # usb resetresetting USB...USB0:   USB EHCI 1.00scanning bus 0 for devices... 3 USB Device(s) foundu-boot # usb treeUSB 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模型来提供相应的操作集便可。

移植开始

根据上篇文章所介绍,我们需要提供以下标准接口:

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

设备驱动

+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_ETH26      uint8_t *rxbuf;27      int rxsize;28      int rxlen;          /* Total bytes available in rxbuf */29      int rxptr;          /* Current position in rxbuf */30  #else31      struct eth_device eth_dev;  /* used with eth_register */32      /* driver private */33      void *dev_priv;34  #endif35      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 device51	 *52	 * This selects the correct USB interface and figures out the endpoints to use.53	 *54	 * @dev:	USB device55	 * @ss:		Place to put USB ethernet data56	 * @rxsize:	Maximum size to allocate for the receive buffer57	 * @return 0 if OK, -ve on error58	 */59	int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize);60	61	/**62	 * usb_ether_deregister() - deregister a USB ethernet device63	 *64	 * @ueth:	USB Ethernet device65	 * @return 066	 */67	int usb_ether_deregister(struct ueth_data *ueth);68	69	/**70	 * usb_ether_receive() - recieve a packet from the bulk in endpoint71	 *72	 * The packet is stored in the internal buffer ready for processing.73	 *74	 * @ueth:	USB Ethernet device75	 * @rxsize:	Maximum size to receive76	 * @return 0 if a packet was received, -EAGAIN if not, -ENOSPC if @rxsize is77	 * larger than the size passed ot usb_ether_register(), other -ve on error78	 */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 buffer83	 *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 to86	 * the next one.87	 *88	 * @ueth:	USB Ethernet device89	 * @ptrp:	Returns a pointer to the start of the next packet if there is90	 *		one available91	 * @return number of bytes available, or 0 if none92	 */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 buffer97	 *98	 * After processing the data returned by usb_ether_get_rx_bytes(), call this99	 * function to move to the next packet. You must specify the number of bytes100	 * you have processed in @num_bytes.101	 *102	 * @ueth:	USB Ethernet device103	 * @num_bytes:	Number of bytes to skip, or -1 to skip all bytes104	 */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框架即可,具体文件。

编译配置

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

说明

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

  • 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/Kconfigindex 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/Makefileindex 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 abortpc : [<7fe9a2a0>]	   lr : [<7aede325>]reloc pc : [<43e432a0>]	   lr : [<3ee87325>]sp : 7ae54ce0  ip : 00000014	 fp : 00000fffr10: 00000fff  r9 : 7ae54ed8	 r8 : 0000002er7 : 00000fff  r6 : 7aede303	 r5 : 0000001c  r4 : 7aede311r3 : 00000000  r2 : 7aede311	 r1 : 00000014  r0 : 7aede311Flags: nzCv  IRQs off  FIQs off  Mode SVC_32Resetting CPU ...

情况二

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

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

看到这里想必有点懵,不知道从哪里做起,没事,下篇文章博主给你解答。

转载地址:http://zvdjz.baihongyu.com/

你可能感兴趣的文章
MySQL CRUD 数据表基础操作实战
查看>>
multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
查看>>
mysql csv import meets charset
查看>>
multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
查看>>
MySQL DBA 数据库优化策略
查看>>
multi_index_container
查看>>
MySQL DBA 进阶知识详解
查看>>
Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
查看>>
Mysql DBA 高级运维学习之路-DQL语句之select知识讲解
查看>>
mysql deadlock found when trying to get lock暴力解决
查看>>
MuseTalk如何生成高质量视频(使用技巧)
查看>>
mutiplemap 总结
查看>>
MySQL DELETE 表别名问题
查看>>
MySQL Error Handling in Stored Procedures---转载
查看>>
MVC 区域功能
查看>>
MySQL FEDERATED 提示
查看>>
mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
查看>>
Mysql group by
查看>>
MySQL I 有福啦,窗口函数大大提高了取数的效率!
查看>>
mysql id自动增长 初始值 Mysql重置auto_increment初始值
查看>>