19b70e007SSimon Glass /* 29b70e007SSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 39b70e007SSimon Glass * See file CREDITS for list of people who contributed to this 49b70e007SSimon Glass * project. 59b70e007SSimon Glass * 69b70e007SSimon Glass * This program is free software; you can redistribute it and/or 79b70e007SSimon Glass * modify it under the terms of the GNU General Public License as 89b70e007SSimon Glass * published by the Free Software Foundation; either version 2 of 99b70e007SSimon Glass * the License, or (at your option) any later version. 109b70e007SSimon Glass * 119b70e007SSimon Glass * This program is distributed in the hope that it will be useful, 129b70e007SSimon Glass * but WITHOUT ANY WARRANTY; without even the implied warranty of 139b70e007SSimon Glass * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149b70e007SSimon Glass * GNU General Public License for more details. 159b70e007SSimon Glass * 169b70e007SSimon Glass * You should have received a copy of the GNU General Public License 179b70e007SSimon Glass * along with this program; if not, write to the Free Software 189b70e007SSimon Glass * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 199b70e007SSimon Glass * MA 02111-1307 USA 209b70e007SSimon Glass */ 219b70e007SSimon Glass 229b70e007SSimon Glass #include <common.h> 239b70e007SSimon Glass #include <usb.h> 249b70e007SSimon Glass #include <linux/mii.h> 259b70e007SSimon Glass #include "usb_ether.h" 269b70e007SSimon Glass 279b70e007SSimon Glass 289b70e007SSimon Glass /* ASIX AX8817X based USB 2.0 Ethernet Devices */ 299b70e007SSimon Glass 309b70e007SSimon Glass #define AX_CMD_SET_SW_MII 0x06 319b70e007SSimon Glass #define AX_CMD_READ_MII_REG 0x07 329b70e007SSimon Glass #define AX_CMD_WRITE_MII_REG 0x08 339b70e007SSimon Glass #define AX_CMD_SET_HW_MII 0x0a 349b70e007SSimon Glass #define AX_CMD_READ_RX_CTL 0x0f 359b70e007SSimon Glass #define AX_CMD_WRITE_RX_CTL 0x10 369b70e007SSimon Glass #define AX_CMD_WRITE_IPG0 0x12 379b70e007SSimon Glass #define AX_CMD_READ_NODE_ID 0x13 389b70e007SSimon Glass #define AX_CMD_READ_PHY_ID 0x19 399b70e007SSimon Glass #define AX_CMD_WRITE_MEDIUM_MODE 0x1b 409b70e007SSimon Glass #define AX_CMD_WRITE_GPIOS 0x1f 419b70e007SSimon Glass #define AX_CMD_SW_RESET 0x20 429b70e007SSimon Glass #define AX_CMD_SW_PHY_SELECT 0x22 439b70e007SSimon Glass 449b70e007SSimon Glass #define AX_SWRESET_CLEAR 0x00 459b70e007SSimon Glass #define AX_SWRESET_PRTE 0x04 469b70e007SSimon Glass #define AX_SWRESET_PRL 0x08 479b70e007SSimon Glass #define AX_SWRESET_IPRL 0x20 489b70e007SSimon Glass #define AX_SWRESET_IPPD 0x40 499b70e007SSimon Glass 509b70e007SSimon Glass #define AX88772_IPG0_DEFAULT 0x15 519b70e007SSimon Glass #define AX88772_IPG1_DEFAULT 0x0c 529b70e007SSimon Glass #define AX88772_IPG2_DEFAULT 0x12 539b70e007SSimon Glass 549b70e007SSimon Glass /* AX88772 & AX88178 Medium Mode Register */ 559b70e007SSimon Glass #define AX_MEDIUM_PF 0x0080 569b70e007SSimon Glass #define AX_MEDIUM_JFE 0x0040 579b70e007SSimon Glass #define AX_MEDIUM_TFC 0x0020 589b70e007SSimon Glass #define AX_MEDIUM_RFC 0x0010 599b70e007SSimon Glass #define AX_MEDIUM_ENCK 0x0008 609b70e007SSimon Glass #define AX_MEDIUM_AC 0x0004 619b70e007SSimon Glass #define AX_MEDIUM_FD 0x0002 629b70e007SSimon Glass #define AX_MEDIUM_GM 0x0001 639b70e007SSimon Glass #define AX_MEDIUM_SM 0x1000 649b70e007SSimon Glass #define AX_MEDIUM_SBP 0x0800 659b70e007SSimon Glass #define AX_MEDIUM_PS 0x0200 669b70e007SSimon Glass #define AX_MEDIUM_RE 0x0100 679b70e007SSimon Glass 689b70e007SSimon Glass #define AX88178_MEDIUM_DEFAULT \ 699b70e007SSimon Glass (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ 709b70e007SSimon Glass AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ 719b70e007SSimon Glass AX_MEDIUM_RE) 729b70e007SSimon Glass 739b70e007SSimon Glass #define AX88772_MEDIUM_DEFAULT \ 749b70e007SSimon Glass (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ 759b70e007SSimon Glass AX_MEDIUM_TFC | AX_MEDIUM_PS | \ 769b70e007SSimon Glass AX_MEDIUM_AC | AX_MEDIUM_RE) 779b70e007SSimon Glass 789b70e007SSimon Glass /* AX88772 & AX88178 RX_CTL values */ 799b70e007SSimon Glass #define AX_RX_CTL_SO 0x0080 809b70e007SSimon Glass #define AX_RX_CTL_AB 0x0008 819b70e007SSimon Glass 829b70e007SSimon Glass #define AX_DEFAULT_RX_CTL \ 839b70e007SSimon Glass (AX_RX_CTL_SO | AX_RX_CTL_AB) 849b70e007SSimon Glass 859b70e007SSimon Glass /* GPIO 2 toggles */ 869b70e007SSimon Glass #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ 879b70e007SSimon Glass #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ 889b70e007SSimon Glass #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ 899b70e007SSimon Glass 909b70e007SSimon Glass /* local defines */ 919b70e007SSimon Glass #define ASIX_BASE_NAME "asx" 929b70e007SSimon Glass #define USB_CTRL_SET_TIMEOUT 5000 939b70e007SSimon Glass #define USB_CTRL_GET_TIMEOUT 5000 949b70e007SSimon Glass #define USB_BULK_SEND_TIMEOUT 5000 959b70e007SSimon Glass #define USB_BULK_RECV_TIMEOUT 5000 969b70e007SSimon Glass 979b70e007SSimon Glass #define AX_RX_URB_SIZE 2048 989b70e007SSimon Glass #define PHY_CONNECT_TIMEOUT 5000 999b70e007SSimon Glass 1009b70e007SSimon Glass /* local vars */ 1019b70e007SSimon Glass static int curr_eth_dev; /* index for name of next device detected */ 1029b70e007SSimon Glass 1039b70e007SSimon Glass /* 1049b70e007SSimon Glass * Asix infrastructure commands 1059b70e007SSimon Glass */ 1069b70e007SSimon Glass static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index, 1079b70e007SSimon Glass u16 size, void *data) 1089b70e007SSimon Glass { 1099b70e007SSimon Glass int len; 1109b70e007SSimon Glass 1119b70e007SSimon Glass debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x " 1129b70e007SSimon Glass "size=%d\n", cmd, value, index, size); 1139b70e007SSimon Glass 1149b70e007SSimon Glass len = usb_control_msg( 1159b70e007SSimon Glass dev->pusb_dev, 1169b70e007SSimon Glass usb_sndctrlpipe(dev->pusb_dev, 0), 1179b70e007SSimon Glass cmd, 1189b70e007SSimon Glass USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1199b70e007SSimon Glass value, 1209b70e007SSimon Glass index, 1219b70e007SSimon Glass data, 1229b70e007SSimon Glass size, 1239b70e007SSimon Glass USB_CTRL_SET_TIMEOUT); 1249b70e007SSimon Glass 1259b70e007SSimon Glass return len == size ? 0 : -1; 1269b70e007SSimon Glass } 1279b70e007SSimon Glass 1289b70e007SSimon Glass static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index, 1299b70e007SSimon Glass u16 size, void *data) 1309b70e007SSimon Glass { 1319b70e007SSimon Glass int len; 1329b70e007SSimon Glass 1339b70e007SSimon Glass debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 1349b70e007SSimon Glass cmd, value, index, size); 1359b70e007SSimon Glass 1369b70e007SSimon Glass len = usb_control_msg( 1379b70e007SSimon Glass dev->pusb_dev, 1389b70e007SSimon Glass usb_rcvctrlpipe(dev->pusb_dev, 0), 1399b70e007SSimon Glass cmd, 1409b70e007SSimon Glass USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1419b70e007SSimon Glass value, 1429b70e007SSimon Glass index, 1439b70e007SSimon Glass data, 1449b70e007SSimon Glass size, 1459b70e007SSimon Glass USB_CTRL_GET_TIMEOUT); 1469b70e007SSimon Glass return len == size ? 0 : -1; 1479b70e007SSimon Glass } 1489b70e007SSimon Glass 1499b70e007SSimon Glass static inline int asix_set_sw_mii(struct ueth_data *dev) 1509b70e007SSimon Glass { 1519b70e007SSimon Glass int ret; 1529b70e007SSimon Glass 1539b70e007SSimon Glass ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); 1549b70e007SSimon Glass if (ret < 0) 1559b70e007SSimon Glass debug("Failed to enable software MII access\n"); 1569b70e007SSimon Glass return ret; 1579b70e007SSimon Glass } 1589b70e007SSimon Glass 1599b70e007SSimon Glass static inline int asix_set_hw_mii(struct ueth_data *dev) 1609b70e007SSimon Glass { 1619b70e007SSimon Glass int ret; 1629b70e007SSimon Glass 1639b70e007SSimon Glass ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); 1649b70e007SSimon Glass if (ret < 0) 1659b70e007SSimon Glass debug("Failed to enable hardware MII access\n"); 1669b70e007SSimon Glass return ret; 1679b70e007SSimon Glass } 1689b70e007SSimon Glass 1699b70e007SSimon Glass static int asix_mdio_read(struct ueth_data *dev, int phy_id, int loc) 1709b70e007SSimon Glass { 1719b70e007SSimon Glass __le16 res; 1729b70e007SSimon Glass 1739b70e007SSimon Glass asix_set_sw_mii(dev); 1749b70e007SSimon Glass asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res); 1759b70e007SSimon Glass asix_set_hw_mii(dev); 1769b70e007SSimon Glass 1779b70e007SSimon Glass debug("asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", 1789b70e007SSimon Glass phy_id, loc, le16_to_cpu(res)); 1799b70e007SSimon Glass 1809b70e007SSimon Glass return le16_to_cpu(res); 1819b70e007SSimon Glass } 1829b70e007SSimon Glass 1839b70e007SSimon Glass static void 1849b70e007SSimon Glass asix_mdio_write(struct ueth_data *dev, int phy_id, int loc, int val) 1859b70e007SSimon Glass { 1869b70e007SSimon Glass __le16 res = cpu_to_le16(val); 1879b70e007SSimon Glass 1889b70e007SSimon Glass debug("asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", 1899b70e007SSimon Glass phy_id, loc, val); 1909b70e007SSimon Glass asix_set_sw_mii(dev); 1919b70e007SSimon Glass asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); 1929b70e007SSimon Glass asix_set_hw_mii(dev); 1939b70e007SSimon Glass } 1949b70e007SSimon Glass 1959b70e007SSimon Glass /* 1969b70e007SSimon Glass * Asix "high level" commands 1979b70e007SSimon Glass */ 1989b70e007SSimon Glass static int asix_sw_reset(struct ueth_data *dev, u8 flags) 1999b70e007SSimon Glass { 2009b70e007SSimon Glass int ret; 2019b70e007SSimon Glass 2029b70e007SSimon Glass ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); 2039b70e007SSimon Glass if (ret < 0) 2049b70e007SSimon Glass debug("Failed to send software reset: %02x\n", ret); 2059b70e007SSimon Glass else 2069b70e007SSimon Glass udelay(150 * 1000); 2079b70e007SSimon Glass 2089b70e007SSimon Glass return ret; 2099b70e007SSimon Glass } 2109b70e007SSimon Glass 2119b70e007SSimon Glass static inline int asix_get_phy_addr(struct ueth_data *dev) 2129b70e007SSimon Glass { 2139b70e007SSimon Glass u8 buf[2]; 2149b70e007SSimon Glass int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); 2159b70e007SSimon Glass 2169b70e007SSimon Glass debug("asix_get_phy_addr()\n"); 2179b70e007SSimon Glass 2189b70e007SSimon Glass if (ret < 0) { 2199b70e007SSimon Glass debug("Error reading PHYID register: %02x\n", ret); 2209b70e007SSimon Glass goto out; 2219b70e007SSimon Glass } 222*0ed1eb6fSMarek Vasut debug("asix_get_phy_addr() returning 0x%02x%02x\n", buf[0], buf[1]); 2239b70e007SSimon Glass ret = buf[1]; 2249b70e007SSimon Glass 2259b70e007SSimon Glass out: 2269b70e007SSimon Glass return ret; 2279b70e007SSimon Glass } 2289b70e007SSimon Glass 2299b70e007SSimon Glass static int asix_write_medium_mode(struct ueth_data *dev, u16 mode) 2309b70e007SSimon Glass { 2319b70e007SSimon Glass int ret; 2329b70e007SSimon Glass 2339b70e007SSimon Glass debug("asix_write_medium_mode() - mode = 0x%04x\n", mode); 2349b70e007SSimon Glass ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 2359b70e007SSimon Glass 0, 0, NULL); 2369b70e007SSimon Glass if (ret < 0) { 2379b70e007SSimon Glass debug("Failed to write Medium Mode mode to 0x%04x: %02x\n", 2389b70e007SSimon Glass mode, ret); 2399b70e007SSimon Glass } 2409b70e007SSimon Glass return ret; 2419b70e007SSimon Glass } 2429b70e007SSimon Glass 2439b70e007SSimon Glass static u16 asix_read_rx_ctl(struct ueth_data *dev) 2449b70e007SSimon Glass { 2459b70e007SSimon Glass __le16 v; 2469b70e007SSimon Glass int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); 2479b70e007SSimon Glass 2489b70e007SSimon Glass if (ret < 0) 2499b70e007SSimon Glass debug("Error reading RX_CTL register: %02x\n", ret); 2509b70e007SSimon Glass else 2519b70e007SSimon Glass ret = le16_to_cpu(v); 2529b70e007SSimon Glass return ret; 2539b70e007SSimon Glass } 2549b70e007SSimon Glass 2559b70e007SSimon Glass static int asix_write_rx_ctl(struct ueth_data *dev, u16 mode) 2569b70e007SSimon Glass { 2579b70e007SSimon Glass int ret; 2589b70e007SSimon Glass 2599b70e007SSimon Glass debug("asix_write_rx_ctl() - mode = 0x%04x\n", mode); 2609b70e007SSimon Glass ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); 2619b70e007SSimon Glass if (ret < 0) { 2629b70e007SSimon Glass debug("Failed to write RX_CTL mode to 0x%04x: %02x\n", 2639b70e007SSimon Glass mode, ret); 2649b70e007SSimon Glass } 2659b70e007SSimon Glass return ret; 2669b70e007SSimon Glass } 2679b70e007SSimon Glass 2689b70e007SSimon Glass static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep) 2699b70e007SSimon Glass { 2709b70e007SSimon Glass int ret; 2719b70e007SSimon Glass 2729b70e007SSimon Glass debug("asix_write_gpio() - value = 0x%04x\n", value); 2739b70e007SSimon Glass ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); 2749b70e007SSimon Glass if (ret < 0) { 2759b70e007SSimon Glass debug("Failed to write GPIO value 0x%04x: %02x\n", 2769b70e007SSimon Glass value, ret); 2779b70e007SSimon Glass } 2789b70e007SSimon Glass if (sleep) 2799b70e007SSimon Glass udelay(sleep * 1000); 2809b70e007SSimon Glass 2819b70e007SSimon Glass return ret; 2829b70e007SSimon Glass } 2839b70e007SSimon Glass 2849b70e007SSimon Glass /* 2859b70e007SSimon Glass * mii commands 2869b70e007SSimon Glass */ 2879b70e007SSimon Glass 2889b70e007SSimon Glass /* 2899b70e007SSimon Glass * mii_nway_restart - restart NWay (autonegotiation) for this interface 2909b70e007SSimon Glass * 2919b70e007SSimon Glass * Returns 0 on success, negative on error. 2929b70e007SSimon Glass */ 2939b70e007SSimon Glass static int mii_nway_restart(struct ueth_data *dev) 2949b70e007SSimon Glass { 2959b70e007SSimon Glass int bmcr; 2969b70e007SSimon Glass int r = -1; 2979b70e007SSimon Glass 2989b70e007SSimon Glass /* if autoneg is off, it's an error */ 2999b70e007SSimon Glass bmcr = asix_mdio_read(dev, dev->phy_id, MII_BMCR); 3009b70e007SSimon Glass 3019b70e007SSimon Glass if (bmcr & BMCR_ANENABLE) { 3029b70e007SSimon Glass bmcr |= BMCR_ANRESTART; 3039b70e007SSimon Glass asix_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr); 3049b70e007SSimon Glass r = 0; 3059b70e007SSimon Glass } 3069b70e007SSimon Glass 3079b70e007SSimon Glass return r; 3089b70e007SSimon Glass } 3099b70e007SSimon Glass 3109b70e007SSimon Glass /* 3119b70e007SSimon Glass * Asix callbacks 3129b70e007SSimon Glass */ 3139b70e007SSimon Glass static int asix_init(struct eth_device *eth, bd_t *bd) 3149b70e007SSimon Glass { 3159b70e007SSimon Glass int embd_phy; 3169b70e007SSimon Glass unsigned char buf[ETH_ALEN]; 3179b70e007SSimon Glass u16 rx_ctl; 3189b70e007SSimon Glass struct ueth_data *dev = (struct ueth_data *)eth->priv; 3199b70e007SSimon Glass int timeout = 0; 3209b70e007SSimon Glass #define TIMEOUT_RESOLUTION 50 /* ms */ 3219b70e007SSimon Glass int link_detected; 3229b70e007SSimon Glass 3239b70e007SSimon Glass debug("** %s()\n", __func__); 3249b70e007SSimon Glass 3259b70e007SSimon Glass if (asix_write_gpio(dev, 3269b70e007SSimon Glass AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5) < 0) 3279b70e007SSimon Glass goto out_err; 3289b70e007SSimon Glass 3299b70e007SSimon Glass /* 0x10 is the phy id of the embedded 10/100 ethernet phy */ 3309b70e007SSimon Glass embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); 3319b70e007SSimon Glass if (asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 3329b70e007SSimon Glass embd_phy, 0, 0, NULL) < 0) { 3339b70e007SSimon Glass debug("Select PHY #1 failed\n"); 3349b70e007SSimon Glass goto out_err; 3359b70e007SSimon Glass } 3369b70e007SSimon Glass 3379b70e007SSimon Glass if (asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL) < 0) 3389b70e007SSimon Glass goto out_err; 3399b70e007SSimon Glass 3409b70e007SSimon Glass if (asix_sw_reset(dev, AX_SWRESET_CLEAR) < 0) 3419b70e007SSimon Glass goto out_err; 3429b70e007SSimon Glass 3439b70e007SSimon Glass if (embd_phy) { 3449b70e007SSimon Glass if (asix_sw_reset(dev, AX_SWRESET_IPRL) < 0) 3459b70e007SSimon Glass goto out_err; 3469b70e007SSimon Glass } else { 3479b70e007SSimon Glass if (asix_sw_reset(dev, AX_SWRESET_PRTE) < 0) 3489b70e007SSimon Glass goto out_err; 3499b70e007SSimon Glass } 3509b70e007SSimon Glass 3519b70e007SSimon Glass rx_ctl = asix_read_rx_ctl(dev); 3529b70e007SSimon Glass debug("RX_CTL is 0x%04x after software reset\n", rx_ctl); 3539b70e007SSimon Glass if (asix_write_rx_ctl(dev, 0x0000) < 0) 3549b70e007SSimon Glass goto out_err; 3559b70e007SSimon Glass 3569b70e007SSimon Glass rx_ctl = asix_read_rx_ctl(dev); 3579b70e007SSimon Glass debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); 3589b70e007SSimon Glass 3599b70e007SSimon Glass /* Get the MAC address */ 3609b70e007SSimon Glass if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 3619b70e007SSimon Glass 0, 0, ETH_ALEN, buf) < 0) { 3629b70e007SSimon Glass debug("Failed to read MAC address.\n"); 3639b70e007SSimon Glass goto out_err; 3649b70e007SSimon Glass } 3659b70e007SSimon Glass memcpy(eth->enetaddr, buf, ETH_ALEN); 3669b70e007SSimon Glass debug("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", 3679b70e007SSimon Glass eth->enetaddr[0], eth->enetaddr[1], 3689b70e007SSimon Glass eth->enetaddr[2], eth->enetaddr[3], 3699b70e007SSimon Glass eth->enetaddr[4], eth->enetaddr[5]); 3709b70e007SSimon Glass 3719b70e007SSimon Glass dev->phy_id = asix_get_phy_addr(dev); 3729b70e007SSimon Glass if (dev->phy_id < 0) 3739b70e007SSimon Glass debug("Failed to read phy id\n"); 3749b70e007SSimon Glass 3759b70e007SSimon Glass if (asix_sw_reset(dev, AX_SWRESET_PRL) < 0) 3769b70e007SSimon Glass goto out_err; 3779b70e007SSimon Glass 3789b70e007SSimon Glass if (asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL) < 0) 3799b70e007SSimon Glass goto out_err; 3809b70e007SSimon Glass 3819b70e007SSimon Glass asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET); 3829b70e007SSimon Glass asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE, 3839b70e007SSimon Glass ADVERTISE_ALL | ADVERTISE_CSMA); 3849b70e007SSimon Glass mii_nway_restart(dev); 3859b70e007SSimon Glass 3869b70e007SSimon Glass if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0) 3879b70e007SSimon Glass goto out_err; 3889b70e007SSimon Glass 3899b70e007SSimon Glass if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0, 3909b70e007SSimon Glass AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, 3919b70e007SSimon Glass AX88772_IPG2_DEFAULT, 0, NULL) < 0) { 3929b70e007SSimon Glass debug("Write IPG,IPG1,IPG2 failed\n"); 3939b70e007SSimon Glass goto out_err; 3949b70e007SSimon Glass } 3959b70e007SSimon Glass 3969b70e007SSimon Glass if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0) 3979b70e007SSimon Glass goto out_err; 3989b70e007SSimon Glass 3999b70e007SSimon Glass do { 4009b70e007SSimon Glass link_detected = asix_mdio_read(dev, dev->phy_id, MII_BMSR) & 4019b70e007SSimon Glass BMSR_LSTATUS; 4029b70e007SSimon Glass if (!link_detected) { 4039b70e007SSimon Glass if (timeout == 0) 4049b70e007SSimon Glass printf("Waiting for Ethernet connection... "); 4059b70e007SSimon Glass udelay(TIMEOUT_RESOLUTION * 1000); 4069b70e007SSimon Glass timeout += TIMEOUT_RESOLUTION; 4079b70e007SSimon Glass } 4089b70e007SSimon Glass } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT); 4099b70e007SSimon Glass if (link_detected) { 4109b70e007SSimon Glass if (timeout != 0) 4119b70e007SSimon Glass printf("done.\n"); 4129b70e007SSimon Glass } else { 4139b70e007SSimon Glass printf("unable to connect.\n"); 4149b70e007SSimon Glass goto out_err; 4159b70e007SSimon Glass } 4169b70e007SSimon Glass 4179b70e007SSimon Glass return 0; 4189b70e007SSimon Glass out_err: 4199b70e007SSimon Glass return -1; 4209b70e007SSimon Glass } 4219b70e007SSimon Glass 4229b70e007SSimon Glass static int asix_send(struct eth_device *eth, volatile void *packet, int length) 4239b70e007SSimon Glass { 4249b70e007SSimon Glass struct ueth_data *dev = (struct ueth_data *)eth->priv; 4259b70e007SSimon Glass int err; 4269b70e007SSimon Glass u32 packet_len; 4279b70e007SSimon Glass int actual_len; 4289b70e007SSimon Glass unsigned char msg[PKTSIZE + sizeof(packet_len)]; 4299b70e007SSimon Glass 4309b70e007SSimon Glass debug("** %s(), len %d\n", __func__, length); 4319b70e007SSimon Glass 4329b70e007SSimon Glass packet_len = (((length) ^ 0x0000ffff) << 16) + (length); 4339b70e007SSimon Glass cpu_to_le32s(&packet_len); 4349b70e007SSimon Glass 4359b70e007SSimon Glass memcpy(msg, &packet_len, sizeof(packet_len)); 4369b70e007SSimon Glass memcpy(msg + sizeof(packet_len), (void *)packet, length); 4379b70e007SSimon Glass if (length & 1) 4389b70e007SSimon Glass length++; 4399b70e007SSimon Glass 4409b70e007SSimon Glass err = usb_bulk_msg(dev->pusb_dev, 4419b70e007SSimon Glass usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), 4429b70e007SSimon Glass (void *)msg, 4439b70e007SSimon Glass length + sizeof(packet_len), 4449b70e007SSimon Glass &actual_len, 4459b70e007SSimon Glass USB_BULK_SEND_TIMEOUT); 4469b70e007SSimon Glass debug("Tx: len = %u, actual = %u, err = %d\n", 4479b70e007SSimon Glass length + sizeof(packet_len), actual_len, err); 4489b70e007SSimon Glass 4499b70e007SSimon Glass return err; 4509b70e007SSimon Glass } 4519b70e007SSimon Glass 4529b70e007SSimon Glass static int asix_recv(struct eth_device *eth) 4539b70e007SSimon Glass { 4549b70e007SSimon Glass struct ueth_data *dev = (struct ueth_data *)eth->priv; 4559b70e007SSimon Glass static unsigned char recv_buf[AX_RX_URB_SIZE]; 4569b70e007SSimon Glass unsigned char *buf_ptr; 4579b70e007SSimon Glass int err; 4589b70e007SSimon Glass int actual_len; 4599b70e007SSimon Glass u32 packet_len; 4609b70e007SSimon Glass 4619b70e007SSimon Glass debug("** %s()\n", __func__); 4629b70e007SSimon Glass 4639b70e007SSimon Glass err = usb_bulk_msg(dev->pusb_dev, 4649b70e007SSimon Glass usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), 4659b70e007SSimon Glass (void *)recv_buf, 4669b70e007SSimon Glass AX_RX_URB_SIZE, 4679b70e007SSimon Glass &actual_len, 4689b70e007SSimon Glass USB_BULK_RECV_TIMEOUT); 4699b70e007SSimon Glass debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE, 4709b70e007SSimon Glass actual_len, err); 4719b70e007SSimon Glass if (err != 0) { 4729b70e007SSimon Glass debug("Rx: failed to receive\n"); 4739b70e007SSimon Glass return -1; 4749b70e007SSimon Glass } 4759b70e007SSimon Glass if (actual_len > AX_RX_URB_SIZE) { 4769b70e007SSimon Glass debug("Rx: received too many bytes %d\n", actual_len); 4779b70e007SSimon Glass return -1; 4789b70e007SSimon Glass } 4799b70e007SSimon Glass 4809b70e007SSimon Glass buf_ptr = recv_buf; 4819b70e007SSimon Glass while (actual_len > 0) { 4829b70e007SSimon Glass /* 4839b70e007SSimon Glass * 1st 4 bytes contain the length of the actual data as two 4849b70e007SSimon Glass * complementary 16-bit words. Extract the length of the data. 4859b70e007SSimon Glass */ 4869b70e007SSimon Glass if (actual_len < sizeof(packet_len)) { 4879b70e007SSimon Glass debug("Rx: incomplete packet length\n"); 4889b70e007SSimon Glass return -1; 4899b70e007SSimon Glass } 4909b70e007SSimon Glass memcpy(&packet_len, buf_ptr, sizeof(packet_len)); 4919b70e007SSimon Glass le32_to_cpus(&packet_len); 4929b70e007SSimon Glass if (((packet_len >> 16) ^ 0xffff) != (packet_len & 0xffff)) { 4939b70e007SSimon Glass debug("Rx: malformed packet length: %#x (%#x:%#x)\n", 4949b70e007SSimon Glass packet_len, (packet_len >> 16) ^ 0xffff, 4959b70e007SSimon Glass packet_len & 0xffff); 4969b70e007SSimon Glass return -1; 4979b70e007SSimon Glass } 4989b70e007SSimon Glass packet_len = packet_len & 0xffff; 4999b70e007SSimon Glass if (packet_len > actual_len - sizeof(packet_len)) { 5009b70e007SSimon Glass debug("Rx: too large packet: %d\n", packet_len); 5019b70e007SSimon Glass return -1; 5029b70e007SSimon Glass } 5039b70e007SSimon Glass 5049b70e007SSimon Glass /* Notify net stack */ 5059b70e007SSimon Glass NetReceive(buf_ptr + sizeof(packet_len), packet_len); 5069b70e007SSimon Glass 5079b70e007SSimon Glass /* Adjust for next iteration. Packets are padded to 16-bits */ 5089b70e007SSimon Glass if (packet_len & 1) 5099b70e007SSimon Glass packet_len++; 5109b70e007SSimon Glass actual_len -= sizeof(packet_len) + packet_len; 5119b70e007SSimon Glass buf_ptr += sizeof(packet_len) + packet_len; 5129b70e007SSimon Glass } 5139b70e007SSimon Glass 5149b70e007SSimon Glass return err; 5159b70e007SSimon Glass } 5169b70e007SSimon Glass 5179b70e007SSimon Glass static void asix_halt(struct eth_device *eth) 5189b70e007SSimon Glass { 5199b70e007SSimon Glass debug("** %s()\n", __func__); 5209b70e007SSimon Glass } 5219b70e007SSimon Glass 5229b70e007SSimon Glass /* 5239b70e007SSimon Glass * Asix probing functions 5249b70e007SSimon Glass */ 5259b70e007SSimon Glass void asix_eth_before_probe(void) 5269b70e007SSimon Glass { 5279b70e007SSimon Glass curr_eth_dev = 0; 5289b70e007SSimon Glass } 5299b70e007SSimon Glass 5309b70e007SSimon Glass struct asix_dongle { 5319b70e007SSimon Glass unsigned short vendor; 5329b70e007SSimon Glass unsigned short product; 5339b70e007SSimon Glass }; 5349b70e007SSimon Glass 5359b70e007SSimon Glass static struct asix_dongle asix_dongles[] = { 5369b70e007SSimon Glass { 0x05ac, 0x1402 }, /* Apple USB Ethernet Adapter */ 5379b70e007SSimon Glass { 0x07d1, 0x3c05 }, /* D-Link DUB-E100 H/W Ver B1 */ 5389b70e007SSimon Glass { 0x0b95, 0x772a }, /* Cables-to-Go USB Ethernet Adapter */ 5399b70e007SSimon Glass { 0x0b95, 0x7720 }, /* Trendnet TU2-ET100 V3.0R */ 5409b70e007SSimon Glass { 0x0b95, 0x1720 }, /* SMC */ 5419b70e007SSimon Glass { 0x0db0, 0xa877 }, /* MSI - ASIX 88772a */ 5429b70e007SSimon Glass { 0x13b1, 0x0018 }, /* Linksys 200M v2.1 */ 5439b70e007SSimon Glass { 0x1557, 0x7720 }, /* 0Q0 cable ethernet */ 5449b70e007SSimon Glass { 0x2001, 0x3c05 }, /* DLink DUB-E100 H/W Ver B1 Alternate */ 5459b70e007SSimon Glass { 0x0000, 0x0000 } /* END - Do not remove */ 5469b70e007SSimon Glass }; 5479b70e007SSimon Glass 5489b70e007SSimon Glass /* Probe to see if a new device is actually an asix device */ 5499b70e007SSimon Glass int asix_eth_probe(struct usb_device *dev, unsigned int ifnum, 5509b70e007SSimon Glass struct ueth_data *ss) 5519b70e007SSimon Glass { 5529b70e007SSimon Glass struct usb_interface *iface; 5539b70e007SSimon Glass struct usb_interface_descriptor *iface_desc; 5549b70e007SSimon Glass int i; 5559b70e007SSimon Glass 5569b70e007SSimon Glass /* let's examine the device now */ 5579b70e007SSimon Glass iface = &dev->config.if_desc[ifnum]; 5589b70e007SSimon Glass iface_desc = &dev->config.if_desc[ifnum].desc; 5599b70e007SSimon Glass 5609b70e007SSimon Glass for (i = 0; asix_dongles[i].vendor != 0; i++) { 5619b70e007SSimon Glass if (dev->descriptor.idVendor == asix_dongles[i].vendor && 5629b70e007SSimon Glass dev->descriptor.idProduct == asix_dongles[i].product) 5639b70e007SSimon Glass /* Found a supported dongle */ 5649b70e007SSimon Glass break; 5659b70e007SSimon Glass } 5669b70e007SSimon Glass 5679b70e007SSimon Glass if (asix_dongles[i].vendor == 0) 5689b70e007SSimon Glass return 0; 5699b70e007SSimon Glass 5709b70e007SSimon Glass memset(ss, 0, sizeof(struct ueth_data)); 5719b70e007SSimon Glass 5729b70e007SSimon Glass /* At this point, we know we've got a live one */ 5739b70e007SSimon Glass debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n", 5749b70e007SSimon Glass dev->descriptor.idVendor, dev->descriptor.idProduct); 5759b70e007SSimon Glass 5769b70e007SSimon Glass /* Initialize the ueth_data structure with some useful info */ 5779b70e007SSimon Glass ss->ifnum = ifnum; 5789b70e007SSimon Glass ss->pusb_dev = dev; 5799b70e007SSimon Glass ss->subclass = iface_desc->bInterfaceSubClass; 5809b70e007SSimon Glass ss->protocol = iface_desc->bInterfaceProtocol; 5819b70e007SSimon Glass 5829b70e007SSimon Glass /* 5839b70e007SSimon Glass * We are expecting a minimum of 3 endpoints - in, out (bulk), and 5849b70e007SSimon Glass * int. We will ignore any others. 5859b70e007SSimon Glass */ 5869b70e007SSimon Glass for (i = 0; i < iface_desc->bNumEndpoints; i++) { 5879b70e007SSimon Glass /* is it an BULK endpoint? */ 5889b70e007SSimon Glass if ((iface->ep_desc[i].bmAttributes & 5899b70e007SSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { 5909b70e007SSimon Glass if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) 5919b70e007SSimon Glass ss->ep_in = iface->ep_desc[i].bEndpointAddress & 5929b70e007SSimon Glass USB_ENDPOINT_NUMBER_MASK; 5939b70e007SSimon Glass else 5949b70e007SSimon Glass ss->ep_out = 5959b70e007SSimon Glass iface->ep_desc[i].bEndpointAddress & 5969b70e007SSimon Glass USB_ENDPOINT_NUMBER_MASK; 5979b70e007SSimon Glass } 5989b70e007SSimon Glass 5999b70e007SSimon Glass /* is it an interrupt endpoint? */ 6009b70e007SSimon Glass if ((iface->ep_desc[i].bmAttributes & 6019b70e007SSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { 6029b70e007SSimon Glass ss->ep_int = iface->ep_desc[i].bEndpointAddress & 6039b70e007SSimon Glass USB_ENDPOINT_NUMBER_MASK; 6049b70e007SSimon Glass ss->irqinterval = iface->ep_desc[i].bInterval; 6059b70e007SSimon Glass } 6069b70e007SSimon Glass } 6079b70e007SSimon Glass debug("Endpoints In %d Out %d Int %d\n", 6089b70e007SSimon Glass ss->ep_in, ss->ep_out, ss->ep_int); 6099b70e007SSimon Glass 6109b70e007SSimon Glass /* Do some basic sanity checks, and bail if we find a problem */ 6119b70e007SSimon Glass if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || 6129b70e007SSimon Glass !ss->ep_in || !ss->ep_out || !ss->ep_int) { 6139b70e007SSimon Glass debug("Problems with device\n"); 6149b70e007SSimon Glass return 0; 6159b70e007SSimon Glass } 6169b70e007SSimon Glass dev->privptr = (void *)ss; 6179b70e007SSimon Glass return 1; 6189b70e007SSimon Glass } 6199b70e007SSimon Glass 6209b70e007SSimon Glass int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss, 6219b70e007SSimon Glass struct eth_device *eth) 6229b70e007SSimon Glass { 6239b70e007SSimon Glass if (!eth) { 6249b70e007SSimon Glass debug("%s: missing parameter.\n", __func__); 6259b70e007SSimon Glass return 0; 6269b70e007SSimon Glass } 6279b70e007SSimon Glass sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++); 6289b70e007SSimon Glass eth->init = asix_init; 6299b70e007SSimon Glass eth->send = asix_send; 6309b70e007SSimon Glass eth->recv = asix_recv; 6319b70e007SSimon Glass eth->halt = asix_halt; 6329b70e007SSimon Glass eth->priv = ss; 6339b70e007SSimon Glass 6349b70e007SSimon Glass return 1; 6359b70e007SSimon Glass } 636