[U-Boot] [PATCH] USB: Ethernet: asix.c: Added support for AX88178 based devices
David Jander
david at protonic.nl
Tue May 31 14:58:26 CEST 2011
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 <david at protonic.nl>
---
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 <linux/mii.h>
#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;
};
/*
--
1.7.4.1
More information about the U-Boot
mailing list