From patchwork Tue May 31 12:58:26 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Jander X-Patchwork-Id: 98030 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 25DCFB6F68 for ; Tue, 31 May 2011 22:58:59 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 555F528171; Tue, 31 May 2011 14:58:57 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 0QsibD2IDrWH; Tue, 31 May 2011 14:58:57 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 650D928179; Tue, 31 May 2011 14:58:54 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 08CC328179 for ; Tue, 31 May 2011 14:58:51 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id wKzjxhWV6pfT for ; Tue, 31 May 2011 14:58:49 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from protonic.xs4all.nl (protonic.xs4all.nl [213.84.116.84]) by theia.denx.de (Postfix) with ESMTP id 08B7528171 for ; Tue, 31 May 2011 14:58:46 +0200 (CEST) Received: from archvile.prtnl (archvile.prtnl [192.168.1.153]) by protonic.xs4all.nl (Postfix) with ESMTP id 6D75229EBA; Tue, 31 May 2011 14:56:37 +0200 (CEST) From: David Jander To: u-boot@lists.denx.de Date: Tue, 31 May 2011 14:58:26 +0200 Message-Id: <1306846706-16766-1-git-send-email-david@protonic.nl> X-Mailer: git-send-email 1.7.4.1 Cc: David Jander Subject: [U-Boot] [PATCH] USB: Ethernet: asix.c: Added support for AX88178 based devices X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Completed command definitions copied from linux driver source. Implemented support for AX88178 by copying and rewriting bits and pieces from the linux asix driver. Signed-off-by: David Jander --- drivers/usb/eth/asix.c | 236 +++++++++++++++++++++++++++++++++++++++++++++--- include/usb_ether.h | 1 + 2 files changed, 224 insertions(+), 13 deletions(-) diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 9b012e4..cecbc76 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -24,6 +24,8 @@ #include #include "usb_ether.h" +#define ASIX_MODEL_AX88772 0 +#define ASIX_MODEL_AX88178 1 /* ASIX AX8817X based USB 2.0 Ethernet Devices */ @@ -31,14 +33,29 @@ #define AX_CMD_READ_MII_REG 0x07 #define AX_CMD_WRITE_MII_REG 0x08 #define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_READ_EEPROM 0x0b +#define AX_CMD_WRITE_EEPROM 0x0c +#define AX_CMD_WRITE_ENABLE 0x0d +#define AX_CMD_WRITE_DISABLE 0x0e #define AX_CMD_READ_RX_CTL 0x0f #define AX_CMD_WRITE_RX_CTL 0x10 +#define AX_CMD_READ_IPG012 0x11 #define AX_CMD_WRITE_IPG0 0x12 +#define AX_CMD_WRITE_IPG1 0x13 #define AX_CMD_READ_NODE_ID 0x13 +#define AX_CMD_WRITE_NODE_ID 0x14 +#define AX_CMD_WRITE_IPG2 0x14 +#define AX_CMD_WRITE_MULTI_FILTER 0x16 +#define AX88172_CMD_READ_NODE_ID 0x17 #define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_READ_MEDIUM_STATUS 0x1a #define AX_CMD_WRITE_MEDIUM_MODE 0x1b +#define AX_CMD_READ_MONITOR_MODE 0x1c +#define AX_CMD_WRITE_MONITOR_MODE 0x1d +#define AX_CMD_READ_GPIOS 0x1e #define AX_CMD_WRITE_GPIOS 0x1f #define AX_CMD_SW_RESET 0x20 +#define AX_CMD_SW_PHY_STATUS 0x21 #define AX_CMD_SW_PHY_SELECT 0x22 #define AX_SWRESET_CLEAR 0x00 @@ -83,6 +100,10 @@ (AX_RX_CTL_SO | AX_RX_CTL_AB) /* GPIO 2 toggles */ +#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ +#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ +#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ +#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ @@ -310,7 +331,7 @@ static int mii_nway_restart(struct ueth_data *dev) /* * Asix callbacks */ -static int asix_init(struct eth_device *eth, bd_t *bd) +static int asix_init_ax88772(struct eth_device *eth, bd_t *bd) { int embd_phy; unsigned char buf[ETH_ALEN]; @@ -419,6 +440,190 @@ out_err: return -1; } +/** + * mii_check_media - check the MII interface for a duplex change + * @mii: the MII interface + * @ok_to_print: OK to print link up/down messages + * @init_media: OK to save duplex mode in @mii + * + * Returns 1 if the duplex mode changed, 0 if not. + * If the media type is forced, always returns 0. + */ +unsigned int mii_check_media (struct eth_device *eth, + unsigned int ok_to_print, + unsigned int init_media) +{ + int advertise, lpa, media, duplex; + int lpa2 = 0; + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + /* get MII advertise and LPA values */ + advertise = asix_mdio_read(dev, dev->phy_id, MII_ADVERTISE); + lpa = asix_mdio_read(dev, dev->phy_id, MII_LPA); + lpa2 = asix_mdio_read(dev, dev->phy_id, MII_STAT1000); + + /* figure out media and duplex from advertise and LPA values */ + media = mii_nway_result(lpa & advertise); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + if (lpa2 & LPA_1000FULL) + duplex = 1; + + printf("link up, %uMbps, %s-duplex, lpa 0x%04X\n", + lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 : + media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? + 100 : 10, + duplex ? "full" : "half", + lpa); + + return 0; /* duplex did not change */ +} + +static int ax88178_link_reset(struct eth_device *eth) +{ + u16 mode; + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + debug("ax88178_link_reset()\n"); + + mii_check_media(eth, 1, 1); + mode = AX88178_MEDIUM_DEFAULT; + + /* All supported ax88178 dongles have GMII */ + mode |= AX_MEDIUM_GM; + mode |= AX_MEDIUM_ENCK; + mode |= AX_MEDIUM_FD; + + asix_write_medium_mode(dev, mode); + + return 0; +} + +static int asix_init_ax88178(struct eth_device *eth, bd_t *bd) +{ + unsigned char buf[ETH_ALEN]; + int phymode, ledmode; + int gpio0 = 0; + u8 status; + __le16 eeprom; + struct ueth_data *dev = (struct ueth_data *)eth->priv; + int timeout = 0; +#define TIMEOUT_RESOLUTION 50 /* ms */ + int link_detected; + + debug("** %s()\n", __func__); + + asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); + debug("GPIO Status: 0x%04x\n", status); + + asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); + asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); + asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); + + debug("EEPROM index 0x17 is 0x%04x\n", eeprom); + if (eeprom == cpu_to_le16(0xffff)) { + printf("Error: Marvell phy not supported\n"); + return -1; + } else { + phymode = le16_to_cpu(eeprom) & 7; + ledmode = le16_to_cpu(eeprom) >> 8; + gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; + } + debug("GPIO0: %d, PhyMode: %d\n", gpio0, phymode); + + asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); + if ((le16_to_cpu(eeprom) >> 8) != 1) { + asix_write_gpio(dev, 0x003c, 30); + asix_write_gpio(dev, 0x001c, 300); + asix_write_gpio(dev, 0x003c, 30); + } else { + debug("gpio phymode == 1 path\n"); + asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); + asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); + } + + asix_sw_reset(dev, 0); + udelay(150000); + + asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); + udelay(150000); + + asix_write_rx_ctl(dev, 0); + + /* Get the MAC address */ + if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, + 0, 0, ETH_ALEN, buf) < 0) { + debug("Failed to read MAC address.\n"); + goto out_err; + } + memcpy(eth->enetaddr, buf, ETH_ALEN); + debug("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + eth->enetaddr[0], eth->enetaddr[1], + eth->enetaddr[2], eth->enetaddr[3], + eth->enetaddr[4], eth->enetaddr[5]); + + dev->phy_id = asix_get_phy_addr(dev); + if (dev->phy_id < 0) + debug("Failed to read phy id\n"); + + asix_mdio_write(dev, dev->phy_id, MII_BMCR, + BMCR_RESET | BMCR_ANENABLE); + asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + asix_mdio_write(dev, dev->phy_id, MII_CTRL1000, + ADVERTISE_1000FULL); + + mii_nway_restart(dev); + + if (asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT) < 0) + goto out_err; + + if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0) + goto out_err; + + do { + link_detected = asix_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.\n"); + } else { + printf("unable to connect.\n"); + goto out_err; + } + + udelay(50000); + ax88178_link_reset(eth); + udelay(50000); + + return 0; +out_err: + return -1; +} + +static int asix_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + switch (dev->asix_model) { + case ASIX_MODEL_AX88772 : + return asix_init_ax88772(eth, bd); + break; + case ASIX_MODEL_AX88178 : + return asix_init_ax88178(eth, bd); + break; + default: + printf("Unsupported asix model!\n"); + return -1; + } +} + static int asix_send(struct eth_device *eth, volatile void *packet, int length) { struct ueth_data *dev = (struct ueth_data *)eth->priv; @@ -530,19 +735,21 @@ void asix_eth_before_probe(void) struct asix_dongle { unsigned short vendor; unsigned short product; + unsigned int asix_model; }; static struct asix_dongle asix_dongles[] = { - { 0x05ac, 0x1402 }, /* Apple USB Ethernet Adapter */ - { 0x07d1, 0x3c05 }, /* D-Link DUB-E100 H/W Ver B1 */ - { 0x0b95, 0x772a }, /* Cables-to-Go USB Ethernet Adapter */ - { 0x0b95, 0x7720 }, /* Trendnet TU2-ET100 V3.0R */ - { 0x0b95, 0x1720 }, /* SMC */ - { 0x0db0, 0xa877 }, /* MSI - ASIX 88772a */ - { 0x13b1, 0x0018 }, /* Linksys 200M v2.1 */ - { 0x1557, 0x7720 }, /* 0Q0 cable ethernet */ - { 0x2001, 0x3c05 }, /* DLink DUB-E100 H/W Ver B1 Alternate */ - { 0x0000, 0x0000 } /* END - Do not remove */ + { 0x05ac, 0x1402, ASIX_MODEL_AX88772 }, /* Apple USB Ethernet Adapter */ + { 0x07d1, 0x3c05, ASIX_MODEL_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */ + { 0x0b95, 0x772a, ASIX_MODEL_AX88772 }, /* Cables-to-Go USB Ethernet Adapter */ + { 0x0b95, 0x7720, ASIX_MODEL_AX88772 }, /* Trendnet TU2-ET100 V3.0R */ + { 0x0b95, 0x1720, ASIX_MODEL_AX88772 }, /* SMC FIXME: isn't this AX88178? */ + { 0x0db0, 0xa877, ASIX_MODEL_AX88772 }, /* MSI - ASIX 88772a */ + { 0x13b1, 0x0018, ASIX_MODEL_AX88772 }, /* Linksys 200M v2.1 */ + { 0x1557, 0x7720, ASIX_MODEL_AX88772 }, /* 0Q0 cable ethernet */ + { 0x2001, 0x3c05, ASIX_MODEL_AX88772 }, /* DLink DUB-E100 H/W Ver B1 Alternate */ + { 0x050d, 0x5055, ASIX_MODEL_AX88178 }, /* Belkin F5D5055 Gig USB */ + { 0x0000, 0x0000, 0 } /* END - Do not remove */ }; /* Probe to see if a new device is actually an asix device */ @@ -569,9 +776,12 @@ int asix_eth_probe(struct usb_device *dev, unsigned int ifnum, memset(ss, 0, sizeof(struct ueth_data)); + ss->asix_model = asix_dongles[i].asix_model; + /* At this point, we know we've got a live one */ - debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n", - dev->descriptor.idVendor, dev->descriptor.idProduct); + debug("\n\nUSB Ethernet device detected: %#04x:%#04x model AX88%s\n", + dev->descriptor.idVendor, dev->descriptor.idProduct, + ss->asix_model? "772" : "178"); /* Initialize the ueth_data structure with some useful info */ ss->ifnum = ifnum; diff --git a/include/usb_ether.h b/include/usb_ether.h index 825c275..28144f1 100644 --- a/include/usb_ether.h +++ b/include/usb_ether.h @@ -51,6 +51,7 @@ struct ueth_data { unsigned char irqinterval; /* Intervall for IRQ Pipe */ /* private fields for each driver can go here if needed */ + unsigned int asix_model; }; /*