基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于tiny4412的Linux内核移植 -- DM9621NP网卡驱动移植相关的知识,希望对你有一定的参考价值。

作者信息

作者: 彭东林

邮箱:[email protected]

QQ:405728433

平台简介

开发板: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资源。

    通过对比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中,否则网络没法用(发现这个问题也废了一些时间)。

    此外,最关键的是一定要在设备树中将用到的片内外设使能:如hsi、ehci、ohci、otg等等。

下面是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 <;dt-bindings/gpio/gpio.h>
  24: +#include <;dt-bindings/usb4640/usb4640.h>
  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 = <;24000000>;
  38:          };
  39:      };
  40: +
  41: +    usb-hub {
  42: +        compatible = "smsc,usb4640";
  43: +        reset-gpios = <&gpm2 4 GPIO_ACTIVE_LOW>;
  44: +        initial-mode = <;USB4640_MODE_HUB>;
  45: +    };
  46:  };
  47:  
  48:  &;rtc {
  49: @@ -78,7 +86,7 @@
  50:      bus-width = <;4>;
  51:      pinctrl-0 = <;&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
  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: +    [email protected] {
  70: +        status = "okay";
  71: +    };
  72: +    [email protected] {
  73: +        status = "okay";
  74: +    };
  75: +    [email protected] {
  76: +        status = "okay";
  77: +    };
  78: +};
  79: +
  80: +&;ohci {
  81: +    status = "okay";
  82: +    [email protected] {
  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 <;= p) {
 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 %pM
", 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"
 167: +       help
 168: +         This option enables support for SMSC USB4640 HSIC to USB 2.0 Driver.
 169: +
 170:  config USB_LINK_LAYER_TEST
 171:      tristate "USB Link Layer Test driver"
 172:      help
 173: diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
 174: index 45fd4ac..05b6344 100644
 175: --- a/drivers/usb/misc/Makefile
 176: +++ b/drivers/usb/misc/Makefile
 177: @@ -25,6 +25,7 @@ obj-$(CONFIG_USB_USS720)        += uss720.o
 178:  obj-$(CONFIG_USB_SEVSEG)        += usbsevseg.o
 179:  obj-$(CONFIG_USB_YUREX)            += yurex.o
 180:  obj-$(CONFIG_USB_HSIC_USB3503)        += usb3503.o
 181: +obj-$(CONFIG_USB_HSIC_USB4640)        += usb4640.o
 182:  obj-$(CONFIG_USB_CHAOSKEY)        += chaoskey.o
 183:  
 184:  obj-$(CONFIG_USB_SISUSBVGA)        += sisusbvga/
 185: diff --git a/drivers/usb/misc/usb4640.c b/drivers/usb/misc/usb4640.c
 186: new file mode 100644
 187: index 0000000..9c9c01b
 188: --- /dev/null
 189: +++ b/drivers/usb/misc/usb4640.c
 190: @@ -0,0 +1,154 @@
 191: +/*
 192: + * Driver for SMSC USB4640 USB 2.0 hub controller driver
 193: + *
 194: + */
 195: +
 196: +#include <;linux/gpio.h>
 197: +#include <;linux/delay.h>
 198: +#include <;linux/slab.h>
 199: +#include <;linux/module.h>
 200: +#include <;linux/of_gpio.h>
 201: +#include <;linux/platform_device.h>
 202: +#include <;linux/platform_data/usb4640.h>
 203: +
 204: +struct usb4640 {
 205: +    enum usb4640_mode    mode;
 206: +    struct device        *dev;
 207: +    int    gpio_reset;
 208: +};
 209: +
 210: +static int usb4640_reset(struct usb4640 *hub, int state)
 211: +{
 212: +    if (gpio_is_valid(hub->;gpio_reset))
 213: +        gpio_set_value_cansleep(hub->;gpio_reset, state);
 214: +
 215: +    /* Wait 1ms for hub logic to stabilize */
 216: +    if (state)
 217: +        usleep_range(1, 10);
 218: +
 219: +    return 0;
 220: +}
 221: +
 222: +static int usb4640_connect(struct usb4640 *hub)
 223: +{
 224: +    struct device *dev = hub->;dev;
 225: +
 226: +    usb4640_reset(hub, 1);
 227: +    hub->mode = USB4640_MODE_HUB;
 228: +    dev_info(dev, "switched to HUB mode
");
 229: +
 230: +    return 0;
 231: +}
 232: +
 233: +static int usb4640_switch_mode(struct usb4640 *hub, enum usb4640_mode mode)
 234: +{
 235: +    struct device *dev = hub->;dev;
 236: +    int err = 0;
 237: +
 238: +    switch (mode) {
 239: +    case USB4640_MODE_HUB:
 240: +        err = usb4640_connect(hub);
 241: +        break;
 242: +
 243: +    case USB4640_MODE_STANDBY:
 244: +        usb4640_reset(hub, 0);
 245: +        dev_info(dev, "switched to STANDBY mode
");
 246: +        break;
 247: +
 248: +    default:
 249: +        dev_err(dev, "unknown mode is requested
");
 250: +        err = -EINVAL;
 251: +        break;
 252: +    }
 253: +
 254: +    return err;
 255: +}
 256: +
 257: +
 258: +static int usb4640_probe(struct usb4640 *hub)
 259: +{
 260: +    struct device *dev = hub->;dev;
 261: +    struct usb4640_platform_data *pdata = dev_get_platdata(dev);
 262: +    struct device_node *np = dev->of_node;
 263: +    int err;
 264: +    u32 mode = USB4640_MODE_HUB;
 265: +
 266: +    if (pdata) {
 267: +        hub->;gpio_reset        = pdata->gpio_reset;
 268: +        hub->;mode        = pdata->initial_mode;
 269: +    } else if (np) {
 270: +        hub->;gpio_reset = of_get_named_gpio(np, "reset-gpios", 0);
 271: +        if (hub->;gpio_reset == -EPROBE_DEFER)
 272: +            return -EPROBE_DEFER;
 273: +        of_property_read_u32(np, "initial-mode", &mode);
 274: +        hub->;mode = mode;
 275: +    }
 276: +
 277: +    if (gpio_is_valid(hub->;gpio_reset)) {
 278: +        err = devm_gpio_request_one(dev, hub->;gpio_reset,
 279: +                GPIOF_OUT_INIT_LOW, "usb4640 reset");
 280: +        if (err) {
 281: +            dev_err(dev,
 282: +                "unable to request GPIO %d as reset pin (%d)
",
 283: +                hub->;gpio_reset, err);
 284: +            return err;
 285: +        }
 286: +    }
 287: +
 288: +    usb4640_switch_mode(hub, hub->;mode);
 289: +
 290: +    dev_info(dev, "%s: probed in %s mode
", __func__,
 291: +            (hub->;mode == USB4640_MODE_HUB) ? "hub" : "standby");
 292: +
 293: +    return 0;
 294: +}
 295: +
 296: +static int usb4640_platform_probe(struct platform_device *pdev)
 297: +{
 298: +    struct usb4640 *hub;
 299: +
 300: +    hub = devm_kzalloc(&;pdev->dev, sizeof(struct usb4640), GFP_KERNEL);
 301: +    if (!hub)
 302: +        return -ENOMEM;
 303: +    hub->dev = &pdev->dev;
 304: +
 305: +    return usb4640_probe(hub);
 306: +}
 307: +
 308: +#ifdef CONFIG_OF
 309: +static const struct of_device_id usb4640_of_match[] = {
 310: +    { .compatible = "smsc,usb4640", },
 311: +    {},
 312: +};
 313: +MODULE_DEVICE_TABLE(of, usb4640_of_match);
 314: +#endif
 315: +
 316: +static struct platform_driver usb4640_platform_driver = {
 317: +    .driver = {
 318: +        .name = USB4640_NAME,
 319: +        .of_match_table = of_match_ptr(usb4640_of_match),
 320: +    },
 321: +    .probe        = usb4640_platform_probe,
 322: +};
 323: +
 324: +static int __init usb4640_init(void)
 325: +{
 326: +    int err;
 327: +
 328: +    err = platform_driver_register(&;usb4640_platform_driver);
 329: +    if (err != 0)
 330: +        pr_err("usb4640: Failed to register platform driver: %d
",
 331: +               err);
 332: +
 333: +    return 0;
 334: +}
 335: +module_init(usb4640_init);
 336: +
 337: +static void __exit usb4640_exit(void)
 338: +{
 339: +    platform_driver_unregister(&;usb4640_platform_driver);
 340: +}
 341: +module_exit(usb4640_exit);
 342: +
 343: +MODULE_DESCRIPTION("USB4640 USB HUB driver");
 344: +MODULE_LICENSE("GPL");
 345: diff --git a/include/dt-bindings/usb4640/usb4640.h b/include/dt-bindings/usb4640/usb4640.h
 346: new file mode 100644
 347: index 0000000..ef3e1e1
 348: --- /dev/null
 349: +++ b/include/dt-bindings/usb4640/usb4640.h
 350: @@ -0,0 +1,7 @@
 351: +#ifndef _DT_BINDINGS_USB4640
 352: +#define _DT_BINDINGS_USB4640
 353: +
 354: +#define USB4640_MODE_UNKNOWN   1
 355: +#define USB4640_MODE_HUB       2
 356: +#define USB4640_MODE_STANDBY   3
 357: +#endif
 358: diff --git a/include/linux/platform_data/usb4640.h b/include/linux/platform_data/usb4640.h
 359: new file mode 100644
 360: index 0000000..5a416ab
 361: --- /dev/null
 362: +++ b/include/linux/platform_data/usb4640.h
 363: @@ -0,0 +1,17 @@
 364: +#ifndef __USB4640_H__
 365: +#define __USB4640_H__
 366: +
 367: +#define USB4640_NAME    "usb4640"
 368: +
 369: +enum usb4640_mode {
 370: +    USB4640_MODE_UNKNOWN = 1,
 371: +    USB4640_MODE_HUB,
 372: +    USB4640_MODE_STANDBY,
 373: +};
 374: +
 375: +struct usb4640_platform_data {
 376: +    enum usb4640_mode    initial_mode;
 377: +    int    gpio_reset;
 378: +};
 379: +
 380: +#endif

 

测试

用ramdisk启动内核,可以看到如下log

[    2.690100] usb 2-2.2: new full-speed USB device number 4 using exynos-ehci
[    2.795595] usb 2-2.2: not running at top speed; connect to a high speed hub
[    2.869980] usb 2-2.2: New USB device found, idVendor=0a46, idProduct=9621
[    2.870147] usb 2-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    2.883960] dm9601 2-2.2:1.0 eth0: register ‘dm9601‘ at usb-12580000.ehci-2.2, Davicom DM96xx USB 10/100 Ethernet, 1c:6f:65:34:51:7e

执行如下命令:

ifconfig eth0 192.168.1.8

我的开发机使用桥接的方式连接到物理网卡上,ip是192.168.1.10,在板子上执行如下命令:

ping 192.168.1.10

看到如下log:

   1: [[email protected] ]# ping 192.168.1.10
   2: PING 192.168.1.10 (192.168.1.10): 56 data bytes
   3: 64 bytes from 192.168.1.10: seq=0 ttl=64 time=1.354 ms
   4: 64 bytes from 192.168.1.10: seq=1 ttl=64 time=1.210 ms
   5: 64 bytes from 192.168.1.10: seq=2 ttl=64 time=1.550 ms
   6: 64 bytes from 192.168.1.10: seq=3 ttl=64 time=2.336 ms
   7: 64 bytes from 192.168.1.10: seq=4 ttl=64 time=1.612 ms
   8: ^C
   9: --- 192.168.1.10 ping statistics ---
  10: 5 packets transmitted, 5 packets received, 0% packet loss
  11: round-trip min/avg/max = 1.210/1.612/2.336 ms

可以将配置IP的命令写到/etc/profile中,就不用每次都配置ip了。

    下面我们看看系统的GPIO使用情况,再次之前需要挂载debugfs文件系统到/sys/kernel/debug下,修改配置文件/etc/fstab (需要在开发机上修改,然后重新制作ramdisk镜像),添加一行:

debugfs        /sys/kernel/debug    debugfs        defaults    0    0

然后重新制作生成ramdisk.img,启动系统,执行如下命令:

   1:  [[email protected] ]# mount
   2:  /dev/root on / type ext4 (rw,relatime,data=ordered)
   3:  devtmpfs on /dev type devtmpfs (rw,relatime,size=480388k,nr_inodes=120097,mode=755)
   4:  proc on /proc type proc (rw,relatime)
   5:  tmpfs on /tmp type tmpfs (rw,relatime)
   6:  sysfs on /sys type sysfs (rw,relatime)
   7:  debugfs on /sys/kernel/debug type debugfs (rw,relatime)
   8:  devpts on /dev/pts type devpts (rw,relatime,mode=600)
   9:   
  10:  [[email protected] ]# cat /sys/kernel/debug/gpio 
  11:  ......
  12:   
  13:  GPIOs 128-135, platform/11000000.pinctrl, gpm0:
  14:   
  15:  GPIOs 136-142, platform/11000000.pinctrl, gpm1:
  16:   
  17:  GPIOs 143-147, platform/11000000.pinctrl, gpm2:
  18:   gpio-147 (                    |usb4640 reset       ) out hi    
  19:   
  20:  GPIOs 148-155, platform/11000000.pinctrl, gpm3:
  21:   
  22:  GPIOs 156-163, platform/11000000.pinctrl, gpm4:
  23:   gpio-156 (                    |?                   ) out hi    
  24:   gpio-157 (                    |?                   ) out hi    
  25:   gpio-158 (                    |?                   ) out hi    
  26:   gpio-159 (                    |?                   ) out hi    
  27:   
  28:  GPIOs 164-169, platform/11000000.pinctrl, gpy0:
  29:   
  30:  ......

可以看到控制usb4640的gpio资源状态以及控制led灯的gpio状态。

    下面我们执行命令,将开发机上的一个共享目录用nfs挂载到tiny4412上: