平台简介
开发板:tiny4412ADK + S700 + 4GB Flash
要移植的内核版本:Linux-4.4.0 (支持device tree)
u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动)
busybox版本:busybox 1.25
网卡芯片:DM9621NP
交叉编译工具链: arm-none-linux-gnueabi-gcc
(gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29))
概述
tiny4412的网卡部分跟我之前的tq2440差别很大,在tq2440中使用网卡芯片是DM9000,使用的是内存接口,移植起来很容易,但是到了tiny4412就不一样了,tiny4412使用的网卡芯片是DM9621,它是usb接口的,而且并没有直接连接到exynos4412上,中间通过一个hub芯片usb4640,然后usb4640通过HSIC接口(XhsicSTROBE0和XhsicDATA0)连接到exynos4412上,下面是一些参考资料:
HSI介绍
http://www.cnblogs.com/pengdonglin137/p/5151331.html
http://www.cnblogs.com/pengdonglin137/p/5151006.html
exynos4412手册的第31章USB 2.0 Host Controller
原理图
上面这张图就是tiny4412板子上的USB连接图,我们重点关注DM9621和USB4640。
移植
通过阅读usb4640的芯片手册,同时结合tiny4412的原理图发现,usb4640的部分功能在tiny4412上是没有用的,没有外接的SPI Flash和I2C设备,大部分引脚都悬空了,除了数据传输的端口外,我们可以控制的就只剩下USB4640的复位引脚了,并且板子起来后,我用万用表测量了usb4640的复位引脚的电压,发现是0.7v左右,说明usb4640一直处于复位状态,最终针对usb4640我们要做的就是只是板子起来后,将控制usb4640复位的引脚电平拉高即可,当然需要在设备树中添加usb4640用到的GPIO资源,usb4640的驱动文件我参考的是drivers/usb/misc/usb3503.c,只保留了关于控制gpio的代码。
通过对比tiny4412自带的linux-3.0.86版本的内核,对于DM9621的驱动在Linux 4.4中全部在driver/net/usb/dm9601.c中实现了,并且对于dm9601这样的usb设备不需要出现在设备树中。所以针对dm9601我们要做的就是:在内核配置时将DM9601的驱动选中即可,同时发现,为了支持识别bootargs中的mac地址的功能,需要稍微修改dm9601.c,添加解析mac地址的功能,并且还需要将解析到的有效的mac地址设置到dm9621中,否则网络没法用(发现这个问题也废了一些时间)。修改内核配置,添加dm9621的驱动:
make menuconfig
Device Drivers --->
Network device support --->
USB Network Adapters --->
Davicom DM96xx based USB 10/100 ethernet devices
此外,最关键的是一定要在设备树中将用到的片内外设使能:如hsi、ehci、ohci、otg等等。
执行完这些操作后,板子上的三个usb口(USBH1/USBH2/USBH3)都可以识别了,即可以插入U盘等设备了。
下面是patch:
1: diff --git a/Makefile b/Makefile
2: index 70dea02..5d96411 100644
3: --- a/Makefile
4: +++ b/Makefile
5: @@ -248,8 +248,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/
6: # "make" in the configured kernel build directory always uses that.
7: # Default value for CROSS_COMPILE is not to prefix executables
8: # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
9: -ARCH ?= $(SUBARCH)
10: -CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
11: +ARCH ?= arm
12: +CROSS_COMPILE ?= /root/tiny4412_android5/SysPort/cross_compile/arm-2014.05/bin/arm-none-linux-gnueabi-
13:
14: # Architecture as present in compile.h
15: UTS_MACHINE := $(ARCH)
16: diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
17: index 4840bbd..69a0d5d 100644
18: --- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
19: +++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
20: @@ -14,6 +14,7 @@
21: /dts-v1/;
22: #include "exynos4412.dtsi"
23: #include
24: +#include
25:
26: / {
27: model = "FriendlyARM TINY4412 board based on Exynos4412";
28: @@ -21,6 +22,7 @@
29:
30: chosen {
31: stdout-path = &;serial_0;
32: + bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 ethmac=1C:6F:65:34:51:7E init=/linuxrc";
33: };
34:
35: memory {
36: @@ -68,6 +70,12 @@
37: clock-frequency = ;
38: };
39: };
40: +
41: + usb-hub {
42: + compatible = "smsc,usb4640";
43: + reset-gpios = ;
44: + initial-mode = ;
45: + };
46: };
47:
48: &;rtc {
49: @@ -78,7 +86,7 @@
50: bus-width = ;
51: pinctrl-0 = ;
52: pinctrl-names = "default";
53: - status = "okay";
54: + status = "disabled";
55: };
56:
57: &;serial_0 {
58: @@ -96,3 +104,32 @@
59: &;serial_3 {
60: status = "okay";
61: };
62: +
63: +&;exynos_usbphy {
64: + status = "okay";
65: +};
66: +
67: +&;ehci {
68: + status = "okay";
69: + port@0 {
70: + status = "okay";
71: + };
72: + port@1 {
73: + status = "okay";
74: + };
75: + port@2 {
76: + status = "okay";
77: + };
78: +};
79: +
80: +&;ohci {
81: + status = "okay";
82: + port@0 {
83: + status = "okay";
84: + };
85: +};
86: +
87: +&;hsotg {
88: + status = "okay";
89: +};
90: +
91: diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
92: index 0b4bdd3..4361385 100644
93: --- a/drivers/net/usb/dm9601.c
94: +++ b/drivers/net/usb/dm9601.c
95: @@ -58,6 +58,39 @@
96: #define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */
97: #define DM_TIMEOUT 1000
98:
99: +/* Setup ethernet address */
100: +static u8 param_addr[ETH_ALEN];
101: +
102: +static int __init dm9601_set_mac(char *str) {
103: + u8 addr[ETH_ALEN];
104: + uint val;
105: + int idx = 0;
106: + char *p = str, *end;
107: +
108: + while (*p &;& idx < ETH_ALEN) {
109: + val = simple_strtoul(p, &;end, 16);
110: + if (end 111: + break;
112: + } else {
113: + addr[idx++] = val;
114: + p = end;
115: + if (*p == ':'|| *p == '-') {
116: + p++;
117: + } else {
118: + break;
119: + }
120: + }
121: + }
122: +
123: + if (idx == ETH_ALEN) {
124: + printk("Setup ethernet address to %pMn", addr);
125: + memcpy(param_addr, addr, ETH_ALEN);
126: + }
127: +
128: + return 1;
129: +}
130: +__setup("ethmac=", dm9601_set_mac);
131: +
132: static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
133: {
134: int err;
135: @@ -190,8 +223,6 @@ static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
136: return dm_read_shared_word(dev, 0, offset, value);
137: }
138:
139: -
140: -
141: static int dm9601_get_eeprom_len(struct net_device *dev)
142: {
143: return DM_EEPROM_LEN;
144: @@ -389,7 +420,11 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
145: /*
146: * Overwrite the auto-generated address only with good ones.
147: */
148: - if (is_valid_ether_addr(mac))
149: + if (is_valid_ether_addr(param_addr)) {
150: + /* write MAC to dm9621 */
151: + memcpy(dev->;net->dev_addr, param_addr, ETH_ALEN);
152: + __dm9601_set_mac_address(dev);
153: + } else if (is_valid_ether_addr(mac))
154: memcpy(dev->;net->dev_addr, mac, ETH_ALEN);
155: else {
156: printk(KERN_WARNING
157: diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
158: index f7a7fc2..c1fcc2f 100644
159: --- a/drivers/usb/misc/Kconfig
160: +++ b/drivers/usb/misc/Kconfig
161: @@ -249,6 +249,11 @@ config USB_HSIC_USB3503
162: help
163: This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
164:
165: +config USB_HSIC_USB4640
166: + tristate "USB4640 HSIC to USB20 Driver"