zoukankan      html  css  js  c++  java
  • X-010 FriendlyARM tiny4412 uboot移植之移植网卡驱动TFTP用起来

     

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 

    开发环境:win7 64 + VMware12 + Ubuntu14.04 64

    工具链:  gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-gnueabi

    u-boot版本:u-boot-2017-03

    代码仓库地址:https://github.com/X-Project-FriendlyARMTiny4412/u-boot

    Tiny4412开发板硬件版本为:

           底板:  Tiny4412/Super4412SDK 1506

           核心板:Tiny4412 - 1412

    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

     

    1、移植Tiny4412 u-boot DM9621网卡驱动

    Tiny4412 u-boot DM9621网卡驱动参考:

    diff --git a/board/samsung/tiny4412/tiny4412.c b/board/samsung/tiny4412/tiny4412.c

    index 3117b8c..c4da8e1 100644

    --- a/board/samsung/tiny4412/tiny4412.c

    +++ b/board/samsung/tiny4412/tiny4412.c

    @@ -413,6 +413,14 @@ static void board_gpio_init(void)

        gpio_request(EXYNOS4X12_GPIO_X35, "USB3503A Reset");

     #endif

     #endif

    +

    +#ifdef CONFIG_CMD_USB

    +

    +   /* USB4604 Reset */

    +   gpio_request(EXYNOS4X12_GPIO_M24, "USB4604 Reset");

    +

    +#endif

    +

     }

     

     int exynos_early_init_f(void)

    @@ -479,6 +487,10 @@ struct dwc2_plat_otg_data s5pc210_otg_data = {

     int board_usb_init(int index, enum usb_init_type init)

     {

     #ifdef CONFIG_CMD_USB

    +

    +   /* Reset*/

    +   gpio_direction_output(EXYNOS4X12_GPIO_M24, 0);

    +   gpio_direction_output(EXYNOS4X12_GPIO_M24, 1);

     #if 0

        struct udevice *dev;

        int ret;

    diff --git a/configs/tiny4412_defconfig b/configs/tiny4412_defconfig

    index cb4dd3a..4aa9c36 100644

    --- a/configs/tiny4412_defconfig

    +++ b/configs/tiny4412_defconfig

    @@ -58,6 +58,7 @@ CONFIG_G_DNL_MANUFACTURER="Samsung"

     CONFIG_G_DNL_VENDOR_NUM=0x04e8

     CONFIG_G_DNL_PRODUCT_NUM=0x6601

     CONFIG_ERRNO_STR=y

    +CONFIG_USB_ETHER_DM9601=y

     

     #/***DEBUG UART ****/

     #CONFIG_DEBUG_UART=y

    diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig

    index da3ec2f..ea5a152 100644

    --- a/drivers/usb/Kconfig

    +++ b/drivers/usb/Kconfig

    @@ -57,6 +57,8 @@ source "drivers/usb/emul/Kconfig"

     

     source "drivers/usb/ulpi/Kconfig"

     

    +source "drivers/usb/eth/Kconfig"

    +

     comment "USB peripherals"

     

     config USB_STORAGE

    diff --git a/drivers/usb/eth/Kconfig b/drivers/usb/eth/Kconfig

    new file mode 100644

    index 0000000..a65ea03

    --- /dev/null

    +++ b/drivers/usb/eth/Kconfig

    @@ -0,0 +1,9 @@

    +#

    +# USB ETHERNET Drivers

    +#

    +comment "USB ETHERNET Drivers"

    +

    +config USB_ETHER_DM9601

    +   bool "DM9601 device driver"

    +   help

    +     Say Y or if your system has a DM9601 device.

    diff --git a/drivers/usb/eth/Makefile b/drivers/usb/eth/Makefile

    index 4c44efc..6bc327c 100644

    --- a/drivers/usb/eth/Makefile

    +++ b/drivers/usb/eth/Makefile

    @@ -10,3 +10,4 @@ obj-$(CONFIG_USB_ETHER_ASIX88179) += asix88179.o

     obj-$(CONFIG_USB_ETHER_MCS7830) += mcs7830.o

     obj-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o

     obj-$(CONFIG_USB_ETHER_RTL8152) += r8152.o r8152_fw.o

    +obj-$(CONFIG_USB_ETHER_DM9601) += dm9601.o

    diff --git a/drivers/usb/eth/dm9601.c b/drivers/usb/eth/dm9601.c

    new file mode 100644

    index 0000000..2de1e79

    --- /dev/null

    +++ b/drivers/usb/eth/dm9601.c

    @@ -0,0 +1,852 @@

    +/*

    + * Davicom DM96xx USB 10/100Mbps ethernet devices

    + *

    + * Peter Korsgaard <jacmet@sunsite.dk>

    + *

    + * This file is licensed under the terms of the GNU General Public License

    + * version 2.  This program is licensed "as is" without any warranty of any

    + * kind, whether express or implied.

    + */

    +

    +/* #define DEBUG */

    +

    +#if 0

    +#include <linux/module.h>

    +#include <linux/sched.h>

    +#include <linux/stddef.h>

    +#include <linux/netdevice.h>

    +#include <linux/etherdevice.h>

    +#include <linux/ethtool.h>

    +#include <linux/mii.h>

    +#include <linux/usb.h>

    +#include <linux/crc32.h>

    +#include <linux/usb/usbnet.h>

    +#include <linux/slab.h>

    +#endif

    +

    +#include <common.h>

    +#include <usb.h>

    +#include <linux/mii.h>

    +#include "usb_ether.h"

    +#include <malloc.h>

    +#include <errno.h>

    +

    +#include <asm/unaligned.h>

    +#include <memalign.h>

    +#include <dm.h>

    +#include <miiphy.h>

    +

    +#include <command.h>

    +#include <net.h>

    +#include <asm/io.h>

    +

    +

    +/* datasheet:

    + http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf

    +*/

    +

    +#define DM9601_BASE_NAME "Davicom DM96xx USB 10/100 Ethernet"

    +

    +struct dm_dongle {

    +   unsigned short vendor;

    +   unsigned short product;

    +   int flags;

    +};

    +

    +static const struct dm_dongle products[] = {

    +   {0x07aa, 0x9601, 0, }, /* Corega FEther USB-TXC */

    +   {0x0a46, 0x9601, 0, }, /* Davicom USB-100 */

    +   {0x0a46, 0x6688, 0, }, /* ZT6688 USB NIC */

    +   {0x0a46, 0x0268, 0, }, /* ShanTou ST268 USB NIC */

    +   {0x0a46, 0x8515, 0, }, /* ADMtek ADM8515 USB NIC */

    +   {0x0a47, 0x9601, 0, }, /* Hirose USB-100 */

    +   {0x0fe6, 0x8101, 0, }, /* DM9601 USB to Fast Ethernet Adapter */

    +   {0x0fe6, 0x9700, 0, }, /* DM9601 USB to Fast Ethernet Adapter */

    +   {0x0a46, 0x9000, 0, }, /* DM9000E */

    +   {0x0a46, 0x9620, 0, }, /* DM9620 USB to Fast Ethernet Adapter */

    +   {0x0a46, 0x9621, 0, }, /* DM9621A USB to Fast Ethernet Adapter */

    +   {0x0a46, 0x9622, 0, }, /* DM9622 USB to Fast Ethernet Adapter */

    +   {0x0a46, 0x0269, 0, }, /* DM962OA USB to Fast Ethernet Adapter */

    +   {0x0a46, 0x1269, 0, }, /* DM9621A USB to Fast Ethernet Adapter */

    +   {},         /* END */

    +};

    +

    +

    +/* control requests */

    +#define DM_READ_REGS   0x00

    +#define DM_WRITE_REGS  0x01

    +#define DM_READ_MEMS   0x02

    +#define DM_WRITE_REG   0x03

    +#define DM_WRITE_MEMS  0x05

    +#define DM_WRITE_MEM   0x07

    +

    +/* registers */

    +#define DM_NET_CTRL    0x00

    +#define DM_RX_CTRL 0x05

    +#define DM_SHARED_CTRL 0x0b

    +#define DM_SHARED_ADDR 0x0c

    +#define DM_SHARED_DATA 0x0d    /* low + high */

    +#define DM_PHY_ADDR    0x10    /* 6 bytes */

    +#define DM_MCAST_ADDR  0x16    /* 8 bytes */

    +#define DM_GPR_CTRL    0x1e

    +#define DM_GPR_DATA    0x1f

    +#define DM_CHIP_ID 0x2c

    +#define DM_MODE_CTRL   0x91    /* only on dm9620 */

    +

    +/* DM_RX_CTRL */

    +#define DM_RX_DIS_LONG (1 << 5)

    +#define DM_RX_DIS_CRC  (1 << 4)

    +#define DM_RX_ALL  (1 << 3)

    +#define DM_RX_PRMSC    (1 << 1)

    +#define DM_RX_RXEN (1 << 0)

    +

    +/* chip id values */

    +#define ID_DM9601  0

    +#define ID_DM9620  1

    +

    +#define DM_MAX_MCAST   64

    +#define DM_MCAST_SIZE  8

    +#define DM_EEPROM_LEN  256

    +#define DM_TX_OVERHEAD 2   /* 2 byte header */

    +#define DM_RX_OVERHEAD 7   /* 3 byte header + 4 byte crc tail */

    +#define DM_TIMEOUT 1000

    +

    +#define USB_CTRL_SET_TIMEOUT 5000

    +#define USB_CTRL_GET_TIMEOUT 5000

    +#define USB_BULK_SEND_TIMEOUT 5000

    +#define USB_BULK_RECV_TIMEOUT 5000

    +

    +#define AX_RX_URB_SIZE 2048

    +#define PHY_CONNECT_TIMEOUT 5000

    +

    +static int dm_read(struct ueth_data *dev, u8 reg, u16 length, void *data)

    +{

    +   int len;

    +   debug("%s() reg=%d, length=%d ", __func__, reg, length);

    +   len = usb_control_msg(

    +       dev->pusb_dev,

    +       usb_rcvctrlpipe(dev->pusb_dev, 0),

    +       DM_READ_REGS,

    +       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,

    +       0,

    +       reg,

    +       data,

    +       length,

    +       USB_CTRL_SET_TIMEOUT);

    +

    +   return len == length ? 0 : -EINVAL;

    +}

    +

    +static int dm_read_reg(struct ueth_data *dev, u8 reg, u8 *value)

    +{

    +   int res;

    +   ALLOC_CACHE_ALIGN_BUFFER(u8, v, 2);

    +

    +   res = dm_read(dev, reg, 1, v);

    +   *value = v[0];

    +   return res;

    +}

    +

    +static int dm_write(struct ueth_data *dev, u8 reg, u16 length, void *data)

    +{

    +   int len;

    +   debug("%s() reg=%d, length=%d data=%pM ", __func__, reg, length, data);

    +   len = usb_control_msg(

    +       dev->pusb_dev,

    +       usb_sndctrlpipe(dev->pusb_dev, 0),

    +       DM_WRITE_REGS,

    +       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,

    +       0,

    +       reg,

    +       data,

    +       length,

    +       USB_CTRL_SET_TIMEOUT);

    +   return len == length ? 0 : -EINVAL;

    +}

    +

    +static int dm_write_reg(struct ueth_data *dev, u8 reg, u8 value)

    +{

    +   debug("%s() reg=%d, value=0x%x ", __func__, reg, (int)value);

    +   int res = usb_control_msg(

    +       dev->pusb_dev,

    +       usb_sndctrlpipe(dev->pusb_dev, 0),

    +       DM_WRITE_REG,

    +       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,

    +       value,

    +       reg,

    +       NULL,

    +       0,

    +       USB_CTRL_SET_TIMEOUT);

    +   return res;

    +}

    +

    +

    +static int dm_read_shared_word(struct ueth_data *dev, int phy, u8 reg, __le16 *value)

    +{

    +   int ret, i;

    +

    +   /*mutex_lock(&dev->phy_mutex);*/

    +

    +   dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);

    +   dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);

    +

    +   for (i = 0; i < DM_TIMEOUT; i++) {

    +       u8 tmp = 0;

    +

    +       udelay(1);

    +       ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);

    +       if (ret < 0)

    +           goto out;

    +

    +       /* ready */

    +       if ((tmp & 1) == 0)

    +           break;

    +   }

    +

    +   if (i == DM_TIMEOUT) {

    +       printf("%s read timed out! ", phy ? "phy" : "eeprom");

    +       ret = -EIO;

    +       goto out;

    +   }

    +

    +   dm_write_reg(dev, DM_SHARED_CTRL, 0x0);

    +   ret = dm_read(dev, DM_SHARED_DATA, 2, value);

    +

    +   debug("read shared %d 0x%02x returned 0x%04x, %d ",

    +          phy, reg, *value, ret);

    +

    + out:

    +   /*mutex_unlock(&dev->phy_mutex);*/

    +   return ret;

    +}

    +

    +

    +static int dm_write_shared_word(struct ueth_data *dev, int phy, u8 reg, __le16 value)

    +{

    +   int ret, i;

    +   ALLOC_CACHE_ALIGN_BUFFER(__le16, v, 1);

    +   *v = value;

    +

    +   /*mutex_lock(&dev->phy_mutex);*/

    +

    +   ret = dm_write(dev, DM_SHARED_DATA, 2, v);

    +   if (ret < 0)

    +       goto out;

    +

    +   dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);

    +   dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);

    +

    +   for (i = 0; i < DM_TIMEOUT; i++) {

    +       u8 tmp = 0;

    +

    +       udelay(1);

    +       ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);

    +       if (ret < 0)

    +           goto out;

    +

    +       /* ready */

    +       if ((tmp & 1) == 0)

    +           break;

    +   }

    +

    +   if (i == DM_TIMEOUT) {

    +       printf("%s write timed out! ", phy ? "phy" : "eeprom");

    +       ret = -EIO;

    +       goto out;

    +   }

    +

    +   dm_write_reg(dev, DM_SHARED_CTRL, 0x0);

    +

    +out:

    +   /*mutex_unlock(&dev->phy_mutex);*/

    +   return ret;

    +}

    +

    +

    +#if 0

    +static int dm_read_eeprom_word(struct ueth_data *dev, u8 offset, void *value)

    +{

    +   return dm_read_shared_word(dev, 0, offset, value);

    +}

    +

    +

    +static int dm9601_get_eeprom_len(struct net_device *dev)

    +{

    +   return DM_EEPROM_LEN;

    +}

    +

    +

    +static int dm9601_get_eeprom(struct net_device *net,

    +                struct ethtool_eeprom *eeprom, u8 * data)

    +{

    +   struct usbnet *dev = netdev_priv(net);

    +   __le16 *ebuf = (__le16 *) data;

    +   int i;

    +

    +   /* access is 16bit */

    +   if ((eeprom->offset % 2) || (eeprom->len % 2))

    +       return -EINVAL;

    +

    +   for (i = 0; i < eeprom->len / 2; i++) {

    +       if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,

    +                   &ebuf[i]) < 0)

    +           return -EINVAL;

    +   }

    +   return 0;

    +}

    +#endif

    +

    +

    +static int dm9601_mdio_read(struct ueth_data *dev, int phy_id, int loc)

    +{

    +   ALLOC_CACHE_ALIGN_BUFFER(__le16, v, 1);

    +

    +   if (phy_id) {

    +       printf("Only internal phy supported ");

    +       return 0;

    +   }

    +

    +   dm_read_shared_word(dev, 1, loc, v);

    +

    +   debug("dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x|0x%04x ",

    +         phy_id, loc, *v, le16_to_cpu(*v));

    +

    +   return le16_to_cpu(*v);

    +}

    +

    +

    +static int dm9601_mdio_write(struct ueth_data *dev, int phy_id, int loc,

    +                 int val)

    +{

    +   __le16 res = cpu_to_le16(val);

    +

    +   if (phy_id) {

    +       printf("Only internal phy supported ");

    +       return -EINVAL;

    +   }

    +

    +   debug("dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x|0x%04x ",

    +          phy_id, loc, res, val);

    +

    +   return dm_write_shared_word(dev, 1, loc, res);

    +}

    +

    +

    +#if 0

    +static void dm9601_get_drvinfo(struct net_device *net,

    +                  struct ethtool_drvinfo *info)

    +{

    +   /* Inherit standard device info */

    +   usbnet_get_drvinfo(net, info);

    +   info->eedump_len = DM_EEPROM_LEN;

    +}

    +

    +static u32 dm9601_get_link(struct net_device *net)

    +{

    +   struct usbnet *dev = netdev_priv(net);

    +

    +   return mii_link_ok(&dev->mii);

    +}

    +

    +static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)

    +{

    +   struct usbnet *dev = netdev_priv(net);

    +

    +   return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);

    +}

    +#endif

    +

    +

    +static int dm9601_set_mac_address(struct eth_device *eth)

    +{

    +   struct ueth_data *dev = (struct ueth_data *)eth->priv;

    +   ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);

    +

    +   if (!is_valid_ethaddr(eth->enetaddr)) {

    +       printf("not setting invalid mac address %pM ", eth->enetaddr);

    +       return -EINVAL;

    +   }

    +

    +   memcpy(buf, eth->enetaddr, ETH_ALEN);

    +   dm_write(dev, DM_PHY_ADDR, ETH_ALEN, buf);

    +

    +   return 0;

    +}

    +

    +

    +static int dm9601_read_mac_address(struct eth_device *eth)

    +{

    +   struct ueth_data *dev = (struct ueth_data *)eth->priv;

    +   ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);

    +

    +   /* read MAC */

    +   if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, buf) < 0) {

    +       printf("dm9601: Error reading MAC address ");

    +       return -ENODEV;

    +   }

    +

    +   memcpy(eth->enetaddr, buf, ETH_ALEN);

    +

    +   return 0;

    +}

    +

    +

    +static void dm9601_set_multicast(struct ueth_data *dev, u8 mcast[DM_MCAST_SIZE])

    +{

    +   ALLOC_CACHE_ALIGN_BUFFER(unsigned char, hashes, DM_MCAST_SIZE);

    +   u8 rx_ctl = (DM_RX_DIS_LONG | DM_RX_DIS_CRC | DM_RX_RXEN);

    +

    +   memcpy(hashes, mcast, DM_MCAST_SIZE);

    +

    +#if 0

    +   if (net->flags & IFF_PROMISC) {

    +       rx_ctl |= DM_RX_PRMSC;

    +   } else if (net->flags & IFF_ALLMULTI ||

    +          netdev_mc_count(net) > DM_MAX_MCAST) {

    +       rx_ctl |= DM_RX_ALL;

    +   } else if (!netdev_mc_empty(net)) {

    +       struct netdev_hw_addr *ha;

    +

    +       netdev_for_each_mc_addr(ha, net) {

    +           u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;

    +           hashes[crc >> 3] |= 1 << (crc & 0x7);

    +       }

    +   }

    +#endif

    +

    +   dm_write(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);

    +   dm_write_reg(dev, DM_RX_CTRL, rx_ctl);

    +}

    +

    +

    +static int dm9601_link_reset(struct ueth_data *dev)

    +{

    +   u8 mcast0[DM_MCAST_SIZE] = { 0x0 };

    +   u8 mcast1[DM_MCAST_SIZE] = { 0, 0x00, 0, 0x80, 0, 0, 0, 0 };

    +   u8 mcast2[DM_MCAST_SIZE] = { 0, 0x00, 0, 0x84, 0, 0, 0, 0 };

    +   u8 mcast3[DM_MCAST_SIZE] = { 0, 0x80, 0, 0x84, 0, 0, 0, 0 };

    +

    +   dm9601_set_multicast(dev, mcast0);

    +   dm9601_set_multicast(dev, mcast1);

    +   dm9601_set_multicast(dev, mcast2);

    +   dm9601_set_multicast(dev, mcast3);

    +

    +   return 0;

    +}

    +

    +/*

    + * mii_nway_restart - restart NWay (autonegotiation) for this interface

    + *

    + * Returns 0 on success, negative on error.

    + */

    +static int mii_nway_restart(struct ueth_data *dev)

    +{

    +   int bmcr;

    +   int r = -1;

    +

    +   /* if autoneg is off, it's an error */

    +   bmcr = dm9601_mdio_read(dev, dev->phy_id, MII_BMCR);

    +   printf("%s: bmcr: 0x%x ", __func__, bmcr);

    +   if (bmcr & BMCR_ANENABLE) {

    +       bmcr |= BMCR_ANRESTART;

    +       dm9601_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);

    +       r = 0;

    +   }

    +

    +   return r;

    +}

    +

    +

    +#if 0

    +/*

    + * mcs7830_set_autoneg() - setup and trigger ethernet link autonegotiation

    + * @eth:   network device to run link negotiation on

    + * Return: zero upon success, negative upon error

    + *

    + * the routine advertises available media and starts autonegotiation

    + */

    +static int dm_set_autoneg(struct ueth_data *dev)

    +{

    +   int adv, flg;

    +   int rc;

    +

    +   debug("%s() ", __func__);

    +

    +   /*

    +    * algorithm taken from the Linux driver, which took it from

    +    * "the original mcs7830 version 1.4 driver":

    +    *

    +    * enable all media, reset BMCR, enable auto neg, restart

    +    * auto neg while keeping the enable auto neg flag set

    +    */

    +

    +   adv = ADVERTISE_PAUSE_CAP | ADVERTISE_ALL | ADVERTISE_CSMA;

    +   rc = dm9601_mdio_write(dev, dev->phy_id, MII_ADVERTISE, adv);

    +

    +   flg = 0;

    +   if (!rc)

    +       rc = dm9601_mdio_write(dev, dev->phy_id, MII_BMCR, flg);

    +

    +   flg |= BMCR_ANENABLE;

    +   if (!rc)

    +       rc = dm9601_mdio_write(dev, dev->phy_id, MII_BMCR, flg);

    +

    +   flg |= BMCR_ANRESTART;

    +   if (!rc)

    +       rc = dm9601_mdio_write(dev, dev->phy_id, MII_BMCR, flg);

    +

    +   debug("%s() rc: %d ", __func__, rc);

    +

    +   return rc;

    +}

    +#endif

    +

    +

    +static int dm9601_init(struct eth_device *eth, bd_t *bd)

    +{

    +   struct ueth_data    *dev = (struct ueth_data *)eth->priv;

    +   int timeout = 0;

    +   int link_detected;

    +

    +   debug("** %s() ", __func__);

    +

    +   mii_nway_restart(dev);

    +   /*dm_set_autoneg(dev);*/

    +

    +   dm9601_link_reset(dev);

    +

    +#define TIMEOUT_RESOLUTION 50  /* ms */

    +   do {

    +       link_detected = dm9601_mdio_read(dev, dev->phy_id, MII_BMSR) &

    +           BMSR_LSTATUS;

    +       if (!link_detected) {

    +           if (timeout == 0)

    +               printf("Waiting for Ethernet connection... ");

    +           udelay(TIMEOUT_RESOLUTION * 1000);

    +           timeout += TIMEOUT_RESOLUTION;

    +       }

    +   } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);

    +   if (link_detected) {

    +       if (timeout != 0)

    +           printf("done. ");

    +   } else {

    +       printf("unable to connect. ");

    +       goto out_err;

    +   }

    +#undef TIMEOUT_RESOLUTION

    +

    +   return 0;

    +

    +out_err:

    +   printf("dm9601: Error: unable to init device. ");

    +   return -1;

    +}

    +

    +

    +static int dm9601_send(struct eth_device *eth, void *packet, int length)

    +{

    +   struct ueth_data *dev = (struct ueth_data *)eth->priv;

    +   int err;

    +   u16 packet_len;

    +   int actual_len;

    +   ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg, PKTSIZE + sizeof(packet_len));

    +

    +   debug("** %s(), len %d ", __func__, length);

    +

    +   /* format:

    +      b1: packet length low

    +      b2: packet length high

    +      b3..n: packet data

    +   */

    +

    +   packet_len = length;

    +   cpu_to_le16s(&packet_len);

    +

    +   memcpy(msg, &packet_len, sizeof(packet_len));

    +   memcpy(msg + sizeof(packet_len), (void *)packet, length);

    +

    +   err = usb_bulk_msg(dev->pusb_dev,

    +               usb_sndbulkpipe(dev->pusb_dev, dev->ep_out),

    +               (void *)msg,

    +               length + sizeof(packet_len),

    +               &actual_len,

    +               USB_BULK_SEND_TIMEOUT);

    +   debug("Tx: len = %u, actual = %u, err = %d ",

    +           length + sizeof(packet_len), actual_len, err);

    +

    +   return err;

    +}

    +

    +

    +static int dm9601_recv(struct eth_device *eth)

    +{

    +   struct ueth_data *dev = (struct ueth_data *)eth->priv;

    +   ALLOC_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);

    +   ALLOC_CACHE_ALIGN_BUFFER(unsigned char, pkt, PKTSIZE);

    +   unsigned char *buf_ptr;

    +   int err;

    +   int actual_len;

    +   u16 packet_len;

    +   u8 status;

    +

    +   debug("** %s() ", __func__);

    +

    +   /* format:

    +      b1: rx status

    +      b2: packet length (incl crc) low

    +      b3: packet length (incl crc) high

    +      b4..n-4: packet data

    +      bn-3..bn: ethernet crc

    +    */

    +

    +   err = usb_bulk_msg(dev->pusb_dev,

    +               usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),

    +               (void *)recv_buf,

    +               AX_RX_URB_SIZE,

    +               &actual_len,

    +               USB_BULK_RECV_TIMEOUT);

    +   debug("Rx: len = %u, actual = %u, err = %d ", AX_RX_URB_SIZE,

    +       actual_len, err);

    +   if (err != 0) {

    +       printf("Rx: failed to receive ");

    +       return -1;

    +   }

    +   if (actual_len > AX_RX_URB_SIZE) {

    +       printf("Rx: received too many bytes %d ", actual_len);

    +       return -1;

    +   }

    +

    +   buf_ptr = recv_buf;

    +   while (actual_len > 0) {

    +       /*

    +        * First byte contains packet status.

    +        */

    +       if (actual_len < sizeof(status)) {

    +           debug("Rx: incomplete packet length (status) ");

    +           return -1;

    +       }

    +       status = buf_ptr[0];

    +       buf_ptr += sizeof(status);

    +       actual_len -= sizeof(status);

    +

    +       if (unlikely(status & 0xbf)) {

    +           printf("Rx: packet status failure: %d ", (int)status);

    +           /*

    +           if (status & 0x01) dev->net->stats.rx_fifo_errors++;

    +           if (status & 0x02) dev->net->stats.rx_crc_errors++;

    +           if (status & 0x04) dev->net->stats.rx_frame_errors++;

    +           if (status & 0x20) dev->net->stats.rx_missed_errors++;

    +           if (status & 0x90) dev->net->stats.rx_length_errors++;

    +           */

    +           return -1;

    +       }

    +

    +       /*

    +        * 2nd and 3rd bytes contain the length of the actual data.

    +        * Extract the length of the data.

    +        */

    +       if (actual_len < sizeof(packet_len)) {

    +           debug("Rx: incomplete packet length (size) ");

    +           return -1;

    +       }

    +       memcpy(&packet_len, buf_ptr, sizeof(packet_len));

    +       le16_to_cpus(&packet_len);

    +       packet_len -= 4;

    +       buf_ptr += sizeof(packet_len);

    +       actual_len -= sizeof(packet_len);

    +

    +       if (packet_len > actual_len) {

    +           printf("Rx: too large packet: %d, actual: %d ", packet_len, actual_len);

    +           return -1;

    +       }

    +

    +       /* Notify net stack */

    +       memcpy(pkt, buf_ptr, packet_len);

    +       net_process_received_packet(pkt, packet_len);

    +

    +       /* Adjust for next iteration. Packets are padded to 16-bits */

    +       /*if (packet_len & 1)

    +           packet_len++;*/

    +       actual_len -= (packet_len + 4);

    +       buf_ptr += packet_len + 4;

    +   }

    +

    +   return err;

    +}

    +

    +

    +static void dm9601_halt(struct eth_device *eth)

    +{

    +   debug("** %s() ", __func__);

    +}

    +

    +

    +void dm9601_eth_before_probe(void)

    +{

    +   debug("** %s() ", __func__);

    +}

    +

    +

    +int dm9601_eth_probe(struct usb_device *dev, unsigned int ifnum,

    +       struct ueth_data* ss)

    +{

    +   struct usb_interface *iface;

    +   struct usb_interface_descriptor *iface_desc;

    +   int ep_in_found = 0, ep_out_found = 0;

    +   int i;

    +

    +   debug(" ****************** %s ******************* ", __func__);

    +

    +   /* let's examine the device now */

    +   iface = &dev->config.if_desc[ifnum];

    +   iface_desc = &dev->config.if_desc[ifnum].desc;

    +

    +   for (i = 0; products[i].vendor != 0; i++) {

    +       debug(" ******************dev->descriptor.idVendor = %#04x ******************* ", dev->descriptor.idVendor);

    +       debug(" ******************dev->descriptor.idProduct = %#04x ******************* ", dev->descriptor.idProduct);

    +       if (dev->descriptor.idVendor == products[i].vendor &&

    +           dev->descriptor.idProduct == products[i].product)

    +           /* Found a supported dongle */

    +           break;

    +   }

    +

    +   if (products[i].vendor == 0)

    +       {

    +       debug(" ****************** products[i].vendor == 0 ******************* ");

    +       return 0;

    +       }

    +

    +   memset(ss, 0, sizeof(struct ueth_data));

    +

    +   /* At this point, we know we've got a live one */

    +   debug(" USB Ethernet device detected: %#04x:%#04x ",

    +         dev->descriptor.idVendor, dev->descriptor.idProduct);

    +

    +   /* Initialize the ueth_data structure with some useful info */

    +   ss->ifnum = ifnum;

    +   ss->pusb_dev = dev;

    +   ss->subclass = iface_desc->bInterfaceSubClass;

    +   ss->protocol = iface_desc->bInterfaceProtocol;

    +

    +   /*

    +    * We are expecting a minimum of 3 endpoints - in, out (bulk), and

    +    * int. We will ignore any others.

    +    */

    +   for (i = 0; i < iface_desc->bNumEndpoints; i++) {

    +       /* is it an BULK endpoint? */

    +       if ((iface->ep_desc[i].bmAttributes &

    +            USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {

    +           u8 ep_addr = iface->ep_desc[i].bEndpointAddress;

    +           if (ep_addr & USB_DIR_IN) {

    +               if (!ep_in_found) {

    +                   ss->ep_in = ep_addr &

    +                       USB_ENDPOINT_NUMBER_MASK;

    +                   ep_in_found = 1;

    +               }

    +           } else {

    +               if (!ep_out_found) {

    +                   ss->ep_out = ep_addr &

    +                       USB_ENDPOINT_NUMBER_MASK;

    +                   ep_out_found = 1;

    +               }

    +           }

    +       }

    +

    +       /* is it an interrupt endpoint? */

    +       if ((iface->ep_desc[i].bmAttributes &

    +           USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {

    +           ss->ep_int = iface->ep_desc[i].bEndpointAddress &

    +               USB_ENDPOINT_NUMBER_MASK;

    +           ss->irqinterval = iface->ep_desc[i].bInterval;

    +       }

    +   }

    +   debug("Endpoints In %d Out %d Int %d ",

    +         ss->ep_in, ss->ep_out, ss->ep_int);

    +

    +   /* Do some basic sanity checks, and bail if we find a problem */

    +   if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||

    +       !ss->ep_in || !ss->ep_out || !ss->ep_int) {

    +       printf("Problems with device ");

    +       return 0;

    +   }

    +

    +   return 1;

    +}

    +

    +

    +int dm9601_eth_get_info(struct usb_device *usb_dev, struct ueth_data *ss,

    +               struct eth_device *eth)

    +{

    +   u8 id = 0xff;

    +   u8 mcast0[DM_MCAST_SIZE] = { 0x0 };

    +

    +   debug(" %s ", __func__);

    +

    +   if (!eth) {

    +       printf("%s: missing parameter. ", __func__);

    +       return 0;

    +   }

    +

    +   sprintf(eth->name, "%s%d", DM9601_BASE_NAME, 0 /*curr_eth_dev++*/);

    +   eth->init = dm9601_init;

    +   eth->send = dm9601_send;

    +   eth->recv = dm9601_recv;

    +   eth->halt = dm9601_halt;

    +#ifdef CONFIG_MCAST_TFTP

    +   /*

    +   eth->mcast = dm9601_mcast(struct eth_device *, const u8 *enetaddr, u8 set);

    +   */

    +#endif

    +   eth->write_hwaddr = dm9601_set_mac_address;

    +   eth->priv = ss;

    +

    +   /* reset */

    +   dm_write_reg(ss, DM_NET_CTRL, 1);

    +   udelay(20);

    +

    +   /* read MAC */

    +   if (dm9601_read_mac_address(eth))

    +       return 0;

    +   printf(" Davicom DM96xx MAC address is %pM ", eth->enetaddr);

    +

    +   /*

    +    * Overwrite the auto-generated address only with good ones.

    +    */

    +   if (!is_valid_ethaddr(eth->enetaddr)) {

    +       printf("dm9601: No valid MAC address in EEPROM, using %pM ",

    +           eth->enetaddr);

    +       /*__dm9601_set_mac_address(ss);*/

    +   }

    +

    +   if (dm_read_reg(ss, DM_CHIP_ID, &id) < 0) {

    +       printf("dm9601: Error reading chip ID ");

    +       return 0;

    +   }

    +

    +   debug("Chip ID = %d ", id);

    +   /* put dm9620 devices in dm9601 mode */

    +   if (id == ID_DM9620) {

    +       u8 mode;

    +

    +       if (dm_read_reg(ss, DM_MODE_CTRL, &mode) < 0) {

    +           printf("dm9601: Error reading MODE_CTRL ");

    +           return 0;

    +       }

    +       dm_write_reg(ss, DM_MODE_CTRL, mode & 0x7f);

    +   }

    +

    +   /* power up phy */

    +   dm_write_reg(ss, DM_GPR_CTRL, 1);

    +   dm_write_reg(ss, DM_GPR_DATA, 0);

    +

    +   /* receive broadcast packets */

    +   dm9601_set_multicast(ss, mcast0);

    +

    +   dm9601_mdio_read(ss, ss->phy_id, MII_BMSR);

    +   dm9601_mdio_write(ss, ss->phy_id, MII_BMCR, BMCR_RESET);

    +   dm9601_mdio_write(ss, ss->phy_id, MII_ADVERTISE,

    +             ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);

    +   mii_nway_restart(ss);

    +

    +   return 1;

    +}

    diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c

    index 36734e2..dd01cd4 100644

    --- a/drivers/usb/eth/usb_ether.c

    +++ b/drivers/usb/eth/usb_ether.c

    @@ -187,6 +187,13 @@ static const struct usb_eth_prob_dev prob_dev[] = {

            .get_info = r8152_eth_get_info,

        },

     #endif

    +#ifdef CONFIG_USB_ETHER_DM9601

    +   {

    +       .before_probe = dm9601_eth_before_probe,

    +       .probe = dm9601_eth_probe,

    +       .get_info = dm9601_eth_get_info,

    +   },

    +#endif

        { },        /* END */

     };

     

    diff --git a/include/configs/tiny4412.h b/include/configs/tiny4412.h

    index 439ea43..74fb669 100644

    --- a/include/configs/tiny4412.h

    +++ b/include/configs/tiny4412.h

    @@ -15,7 +15,7 @@

     

     #include <configs/exynos4-common.h>

     

    -/*#define DEBUG*/

    +/* #define DEBUG */

     

     #define TINY4412 1

     

    @@ -227,8 +227,8 @@

     #define CONFIG_RANDOM_UUID

     

     /* Security subsystem - enable hw_rand() */

    -#define CONFIG_EXYNOS_ACE_SHA

    -#define CONFIG_LIB_HW_RAND

    +/*#define CONFIG_EXYNOS_ACE_SHA*/

    +/*#define CONFIG_LIB_HW_RAND*/

     

     /* USB */

     #define CONFIG_USB_EHCI

    @@ -236,7 +236,9 @@

     

     #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3

     #define CONFIG_USB_HOST_ETHER

    -#define CONFIG_USB_ETHER_SMSC95XX

    +/*#define CONFIG_USB_ETHER_SMSC95XX*/

    +/* #define CONFIG_USB_ETHER_DM9621 */

    +

     

     /*

      * Supported Odroid boards: X3, U3

    diff --git a/include/usb_ether.h b/include/usb_ether.h

    index 51fce4e..c098f87 100644

    --- a/include/usb_ether.h

    +++ b/include/usb_ether.h

    @@ -132,6 +132,12 @@ int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,

     int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,

                struct eth_device *eth);

     

    +void dm9601_eth_before_probe(void);

    +int dm9601_eth_probe(struct usb_device *dev, unsigned int ifnum,

    +                       struct ueth_data *ss);

    +int dm9601_eth_get_info(struct usb_device *dev, struct ueth_data *ss,

    +                       struct eth_device *eth);

    +

     void r8152_eth_before_probe(void);

     int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum,

                struct ueth_data *ss);

     

     

     2、设置U-boot网络环境

       U-boot命令提示行下使能usbusb网卡:

    $  usb start      //使能usb

    $  usb reset      //搜索usb网卡设备。

    结果如下图所示:

    clip_image001

    从上图我们可看到网卡的MAC地址为00:00:ff:ff:00:00

           3>、设置网卡地址:

                  $ setenv usbethaddr 00:00:ff:ff:00:00

           $ saveenv

           4>、设置开发板IP地址(与宿主机Ubuntu在同一个IP网段):

                  $ setenv ipaddr 192.168.1.103

           $ saveenv

    5>、设置宿主机tftp服务器IP地址:

           $ setenv serverip 192.168.1.102

           $ saveenv

           6> 查看U-boot环境变量:

                  $ printenv

    3、使用TFTP服务

       宿主机tftp服务器配置参考《Ubuntu14.04环境下配置TFTP服务器》。

    使用TFTP服务前,先重启下宿主机的TFTP服务:

           $ sudo  service  tftpd-hpa  restart  //重启服务器

    $ sudo /etc/init.d/xinetd  reload

    $ sudo  /etc/init.d/xinetd  restart  //重启xinetdtftp的一个脚本

    uImageramdisk.imgexynos4412-tiny4412.dtb拷贝到tftp服务器目录下,在U-boot命令提示行执行如下命令下载uImageramdisk.imgexynos4412-tiny4412.dtb:

           # tftp 0x40600000 uImage

           # tftp 0x41000000 ramdisk.img

           # tftp 0x42000000 exynos4412-tiny4412.dtb

           # bootm 0x40600000 0x41000000 0x42000000

    启动信息如下:

    clip_image002

    4、设置开发板上电从TFTP启动

       完成U-boot网络环境设置后,通过设置bootcmd变量使开发板上电从tftp启动:

           # setenv bootcmd  'usb start; usb reset;tftp 0x40007000 uImage; tftp 0x48000000 ramdisk.img; tftp 0x42000000 exynos4412-tiny4412.dtb; bootm 0x40007000 0x48000000 0x42000000; boot'

    # saveenv

    设置完成后重启开发板。

    参考

    https://github.com/ac100-ru/u-boot-ac100-exp/tree/dm9601-dev/drivers/usb/eth

  • 相关阅读:
    Log4Net 生成多个文件、文件名累加解决方法
    HTML name、id、class 的区别
    C# 基础(一) 访问修饰符、ref与out、标志枚举等等
    HTML iframe 和 frameset 的区别
    未在本地计算机上注册"OraOLEDB.Oracle"提供程序
    HTML 页面源代码布局介绍
    HTML 基础控件介绍
    图的BFS与DFS的应用
    迷途指针,从百度百科上摘抄的,语言很幽默
    详解C中volatile关键字
  • 原文地址:https://www.cnblogs.com/LoTGu/p/7027943.html
Copyright © 2011-2022 走看看