X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fusb%2Feth%2Fasix.c;h=ad083cf8ae4a28b4a6e56202f26dab0fcd56e592;hb=2ef98d33166e5c22a61eba29c20e236b72f1e8a2;hp=ce133f00698de8ef6346604079c202f07e1534ba;hpb=247161b8160fc699b0a517f081220bb50bc502a8;p=oweals%2Fu-boot.git diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index ce133f0069..ad083cf8ae 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -1,15 +1,18 @@ /* * Copyright (c) 2011 The Chromium OS Authors. * + * Patched for AX88772B by Antmicro Ltd + * * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include +#include +#include #include #include "usb_ether.h" -#include - /* ASIX AX8817X based USB 2.0 Ethernet Devices */ @@ -64,8 +67,11 @@ AX_MEDIUM_AC | AX_MEDIUM_RE) /* AX88772 & AX88178 RX_CTL values */ -#define AX_RX_CTL_SO 0x0080 -#define AX_RX_CTL_AB 0x0008 +#define AX_RX_CTL_RH2M 0x0200 /* 32-bit aligned RX IP header */ +#define AX_RX_CTL_RH1M 0x0100 /* Enable RX header format type 1 */ +#define AX_RX_CTL_SO 0x0080 +#define AX_RX_CTL_AB 0x0008 +#define AX_RX_HEADER_DEFAULT (AX_RX_CTL_RH1M | AX_RX_CTL_RH2M) #define AX_DEFAULT_RX_CTL \ (AX_RX_CTL_SO | AX_RX_CTL_AB) @@ -92,14 +98,22 @@ #define FLAG_TYPE_AX88772B (1U << 2) #define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */ -/* local vars */ -static int curr_eth_dev; /* index for name of next device detected */ +#define ASIX_USB_VENDOR_ID 0x0b95 +#define AX88772B_USB_PRODUCT_ID 0x772b /* driver private */ struct asix_private { int flags; +#ifdef CONFIG_DM_ETH + struct ueth_data ueth; +#endif }; +#ifndef CONFIG_DM_ETH +/* local vars */ +static int curr_eth_dev; /* index for name of next device detected */ +#endif + /* * Asix infrastructure commands */ @@ -284,13 +298,12 @@ static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep) return ret; } -static int asix_write_hwaddr(struct eth_device *eth) +static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; int ret; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); - memcpy(buf, eth->enetaddr, ETH_ALEN); + memcpy(buf, enetaddr, ETH_ALEN); ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf); if (ret < 0) @@ -325,12 +338,11 @@ static int mii_nway_restart(struct ueth_data *dev) return r; } -static int asix_read_mac(struct eth_device *eth) +static int asix_read_mac_common(struct ueth_data *dev, + struct asix_private *priv, uint8_t *enetaddr) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct asix_private *priv = (struct asix_private *)dev->dev_priv; - int i; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); + int i; if (priv->flags & FLAG_EEPROM_MAC) { for (i = 0; i < (ETH_ALEN >> 1); i++) { @@ -339,7 +351,7 @@ static int asix_read_mac(struct eth_device *eth) debug("Failed to read SROM address 04h.\n"); return -1; } - memcpy((eth->enetaddr + i * 2), buf, 2); + memcpy(enetaddr + i * 2, buf, 2); } } else { if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf) @@ -347,7 +359,7 @@ static int asix_read_mac(struct eth_device *eth) debug("Failed to read MAC address.\n"); return -1; } - memcpy(eth->enetaddr, buf, ETH_ALEN); + memcpy(enetaddr, buf, ETH_ALEN); } return 0; @@ -414,19 +426,23 @@ static int asix_basic_reset(struct ueth_data *dev) return 0; } -/* - * Asix callbacks - */ -static int asix_init(struct eth_device *eth, bd_t *bd) +static int asix_init_common(struct ueth_data *dev, uint8_t *enetaddr) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; int timeout = 0; #define TIMEOUT_RESOLUTION 50 /* ms */ int link_detected; + u32 ctl = AX_DEFAULT_RX_CTL; debug("** %s()\n", __func__); - if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0) + if ((dev->pusb_dev->descriptor.idVendor == ASIX_USB_VENDOR_ID) && + (dev->pusb_dev->descriptor.idProduct == AX88772B_USB_PRODUCT_ID)) + ctl |= AX_RX_HEADER_DEFAULT; + + if (asix_write_rx_ctl(dev, ctl) < 0) + goto out_err; + + if (asix_write_hwaddr_common(dev, enetaddr) < 0) goto out_err; do { @@ -447,14 +463,19 @@ static int asix_init(struct eth_device *eth, bd_t *bd) goto out_err; } + /* + * Wait some more to avoid timeout on first transfer + * (e.g. EHCI timed out on TD - token=0x8008d80) + */ + mdelay(25); + return 0; out_err: return -1; } -static int asix_send(struct eth_device *eth, void *packet, int length) +static int asix_send_common(struct ueth_data *dev, void *packet, int length) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; int err; u32 packet_len; int actual_len; @@ -475,12 +496,30 @@ static int asix_send(struct eth_device *eth, void *packet, int length) length + sizeof(packet_len), &actual_len, USB_BULK_SEND_TIMEOUT); - debug("Tx: len = %u, actual = %u, err = %d\n", + debug("Tx: len = %zu, actual = %u, err = %d\n", length + sizeof(packet_len), actual_len, err); return err; } +#ifndef CONFIG_DM_ETH +/* + * Asix callbacks + */ +static int asix_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + return asix_init_common(dev, eth->enetaddr); +} + +static int asix_send(struct eth_device *eth, void *packet, int length) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + return asix_send_common(dev, packet, length); +} + static int asix_recv(struct eth_device *eth) { struct ueth_data *dev = (struct ueth_data *)eth->priv; @@ -533,8 +572,15 @@ static int asix_recv(struct eth_device *eth) return -1; } + if ((dev->pusb_dev->descriptor.idVendor == + ASIX_USB_VENDOR_ID) && + (dev->pusb_dev->descriptor.idProduct == + AX88772B_USB_PRODUCT_ID)) + buf_ptr += 2; + /* Notify net stack */ - NetReceive(buf_ptr + sizeof(packet_len), packet_len); + net_process_received_packet(buf_ptr + sizeof(packet_len), + packet_len); /* Adjust for next iteration. Packets are padded to 16-bits */ if (packet_len & 1) @@ -551,6 +597,13 @@ static void asix_halt(struct eth_device *eth) debug("** %s()\n", __func__); } +static int asix_write_hwaddr(struct eth_device *eth) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + return asix_write_hwaddr_common(dev, eth->enetaddr); +} + /* * Asix probing functions */ @@ -565,7 +618,7 @@ struct asix_dongle { int flags; }; -static const struct asix_dongle const asix_dongles[] = { +static const struct asix_dongle asix_dongles[] = { { 0x05ac, 0x1402, FLAG_TYPE_AX88772 }, /* Apple USB Ethernet Adapter */ { 0x07d1, 0x3c05, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */ { 0x2001, 0x1a02, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver C1 */ @@ -580,6 +633,7 @@ static const struct asix_dongle const asix_dongles[] = { { 0x2001, 0x3c05, FLAG_TYPE_AX88772 }, /* ASIX 88772B */ { 0x0b95, 0x772b, FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC }, + { 0x0b95, 0x7e2b, FLAG_TYPE_AX88772B }, { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */ }; @@ -692,9 +746,181 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss, return 0; /* Get the MAC address */ - if (asix_read_mac(eth)) + if (asix_read_mac_common(ss, priv, eth->enetaddr)) return 0; debug("MAC %pM\n", eth->enetaddr); return 1; } +#endif + +#ifdef CONFIG_DM_ETH +static int asix_eth_start(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct asix_private *priv = dev_get_priv(dev); + + return asix_init_common(&priv->ueth, pdata->enetaddr); +} + +void asix_eth_stop(struct udevice *dev) +{ + debug("** %s()\n", __func__); +} + +int asix_eth_send(struct udevice *dev, void *packet, int length) +{ + struct asix_private *priv = dev_get_priv(dev); + + return asix_send_common(&priv->ueth, packet, length); +} + +int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct asix_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + uint8_t *ptr; + int ret, len; + u32 packet_len; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: first try, len=%d\n", __func__, len); + if (!len) { + if (!(flags & ETH_RECV_CHECK_DEVICE)) + return -EAGAIN; + ret = usb_ether_receive(ueth, AX_RX_URB_SIZE); + if (ret == -EAGAIN) + return ret; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: second try, len=%d\n", __func__, len); + } + + /* + * 1st 4 bytes contain the length of the actual data as two + * complementary 16-bit words. Extract the length of the data. + */ + if (len < sizeof(packet_len)) { + debug("Rx: incomplete packet length\n"); + goto err; + } + memcpy(&packet_len, ptr, sizeof(packet_len)); + le32_to_cpus(&packet_len); + if (((~packet_len >> 16) & 0x7ff) != (packet_len & 0x7ff)) { + debug("Rx: malformed packet length: %#x (%#x:%#x)\n", + packet_len, (~packet_len >> 16) & 0x7ff, + packet_len & 0x7ff); + goto err; + } + packet_len = packet_len & 0x7ff; + if (packet_len > len - sizeof(packet_len)) { + debug("Rx: too large packet: %d\n", packet_len); + goto err; + } + + *packetp = ptr + sizeof(packet_len); + return packet_len; + +err: + usb_ether_advance_rxbuf(ueth, -1); + return -EINVAL; +} + +static int asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len) +{ + struct asix_private *priv = dev_get_priv(dev); + + if (packet_len & 1) + packet_len++; + usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len); + + return 0; +} + +int asix_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct asix_private *priv = dev_get_priv(dev); + + if (priv->flags & FLAG_TYPE_AX88172) + return -ENOSYS; + + return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr); +} + +static int asix_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct asix_private *priv = dev_get_priv(dev); + struct ueth_data *ss = &priv->ueth; + int ret; + + priv->flags = dev->driver_data; + ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE); + if (ret) + return ret; + + ret = asix_basic_reset(ss); + if (ret) + goto err; + + /* Get the MAC address */ + ret = asix_read_mac_common(ss, priv, pdata->enetaddr); + if (ret) + goto err; + debug("MAC %pM\n", pdata->enetaddr); + + return 0; + +err: + return usb_ether_deregister(ss); +} + +static const struct eth_ops asix_eth_ops = { + .start = asix_eth_start, + .send = asix_eth_send, + .recv = asix_eth_recv, + .free_pkt = asix_free_pkt, + .stop = asix_eth_stop, + .write_hwaddr = asix_write_hwaddr, +}; + +U_BOOT_DRIVER(asix_eth) = { + .name = "asix_eth", + .id = UCLASS_ETH, + .probe = asix_eth_probe, + .ops = &asix_eth_ops, + .priv_auto_alloc_size = sizeof(struct asix_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +static const struct usb_device_id asix_eth_id_table[] = { + /* Apple USB Ethernet Adapter */ + { USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 }, + /* D-Link DUB-E100 H/W Ver B1 */ + { USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 }, + /* D-Link DUB-E100 H/W Ver C1 */ + { USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 }, + /* Cables-to-Go USB Ethernet Adapter */ + { USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 }, + /* Trendnet TU2-ET100 V3.0R */ + { USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 }, + /* SMC */ + { USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 }, + /* MSI - ASIX 88772a */ + { USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 }, + /* Linksys 200M v2.1 */ + { USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 }, + /* 0Q0 cable ethernet */ + { USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 }, + /* DLink DUB-E100 H/W Ver B1 Alternate */ + { USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 }, + /* ASIX 88772B */ + { USB_DEVICE(0x0b95, 0x772b), + .driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC }, + { USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B }, + { } /* Terminating entry */ +}; + +U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table); +#endif