本文共 12277 字,大约阅读时间需要 40 分钟。
根据前面文章、所介绍,想必大家已经知道移植的流程应该是如何了,这里再简单的给出大致步骤,如下。
- 移植USB Host Controller驱动
- 使能USB3503 Hub
- 移植DM9621驱动
- 测试验证功能性
接下来就按照这几个步骤进行Uboot中DM9621网卡的移植之路,最终实现在Uboot中使用网络命令进行内核的加载等操作。
该部分驱动已经有三星官方提供到Uboot主线中,我们下载的源码包里面已经有对应的代码,drivers/usb/host/ehci-exynos.c
文件包含了其实现。我们要做的只是将其编译选项打开,编译进Uboot最终bin文件中即可,下面给出详细的步骤。
Device Drivers ---> [*] USB support --->
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
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的配置与使能。
根据前面文章的分析,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设备已经使能,能在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
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为新增配置
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
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/