1291391beSSimon Glass /* 20990fcb7SSimon Glass * Copyright (c) 2015 Google, Inc 3291391beSSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 4291391beSSimon Glass * Copyright (C) 2009 NVIDIA, Corporation 5ad6e48e5SSimon Glass * Copyright (C) 2007-2008 SMSC (Steve Glendinning) 6291391beSSimon Glass * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8291391beSSimon Glass */ 9291391beSSimon Glass 10291391beSSimon Glass #include <common.h> 110990fcb7SSimon Glass #include <dm.h> 12a2692591SSimon Glass #include <errno.h> 13a2692591SSimon Glass #include <malloc.h> 14cf92e05cSSimon Glass #include <memalign.h> 15291391beSSimon Glass #include <usb.h> 16a2692591SSimon Glass #include <asm/unaligned.h> 17291391beSSimon Glass #include <linux/mii.h> 18291391beSSimon Glass #include "usb_ether.h" 19291391beSSimon Glass 20291391beSSimon Glass /* SMSC LAN95xx based USB 2.0 Ethernet Devices */ 21291391beSSimon Glass 2298f686c2SSuriyan Ramasami /* LED defines */ 2398f686c2SSuriyan Ramasami #define LED_GPIO_CFG (0x24) 2498f686c2SSuriyan Ramasami #define LED_GPIO_CFG_SPD_LED (0x01000000) 2598f686c2SSuriyan Ramasami #define LED_GPIO_CFG_LNK_LED (0x00100000) 2698f686c2SSuriyan Ramasami #define LED_GPIO_CFG_FDX_LED (0x00010000) 2798f686c2SSuriyan Ramasami 28291391beSSimon Glass /* Tx command words */ 29291391beSSimon Glass #define TX_CMD_A_FIRST_SEG_ 0x00002000 30291391beSSimon Glass #define TX_CMD_A_LAST_SEG_ 0x00001000 31291391beSSimon Glass 32291391beSSimon Glass /* Rx status word */ 33291391beSSimon Glass #define RX_STS_FL_ 0x3FFF0000 /* Frame Length */ 34291391beSSimon Glass #define RX_STS_ES_ 0x00008000 /* Error Summary */ 35291391beSSimon Glass 36291391beSSimon Glass /* SCSRs */ 37291391beSSimon Glass #define ID_REV 0x00 38291391beSSimon Glass 39291391beSSimon Glass #define INT_STS 0x08 40291391beSSimon Glass 41291391beSSimon Glass #define TX_CFG 0x10 42291391beSSimon Glass #define TX_CFG_ON_ 0x00000004 43291391beSSimon Glass 44291391beSSimon Glass #define HW_CFG 0x14 45291391beSSimon Glass #define HW_CFG_BIR_ 0x00001000 46291391beSSimon Glass #define HW_CFG_RXDOFF_ 0x00000600 47291391beSSimon Glass #define HW_CFG_MEF_ 0x00000020 48291391beSSimon Glass #define HW_CFG_BCE_ 0x00000002 49291391beSSimon Glass #define HW_CFG_LRST_ 0x00000008 50291391beSSimon Glass 51291391beSSimon Glass #define PM_CTRL 0x20 52291391beSSimon Glass #define PM_CTL_PHY_RST_ 0x00000010 53291391beSSimon Glass 54291391beSSimon Glass #define AFC_CFG 0x2C 55291391beSSimon Glass 56291391beSSimon Glass /* 57291391beSSimon Glass * Hi watermark = 15.5Kb (~10 mtu pkts) 58291391beSSimon Glass * low watermark = 3k (~2 mtu pkts) 59291391beSSimon Glass * backpressure duration = ~ 350us 60291391beSSimon Glass * Apply FC on any frame. 61291391beSSimon Glass */ 62291391beSSimon Glass #define AFC_CFG_DEFAULT 0x00F830A1 63291391beSSimon Glass 64291391beSSimon Glass #define E2P_CMD 0x30 65291391beSSimon Glass #define E2P_CMD_BUSY_ 0x80000000 66291391beSSimon Glass #define E2P_CMD_READ_ 0x00000000 67291391beSSimon Glass #define E2P_CMD_TIMEOUT_ 0x00000400 68291391beSSimon Glass #define E2P_CMD_LOADED_ 0x00000200 69291391beSSimon Glass #define E2P_CMD_ADDR_ 0x000001FF 70291391beSSimon Glass 71291391beSSimon Glass #define E2P_DATA 0x34 72291391beSSimon Glass 73291391beSSimon Glass #define BURST_CAP 0x38 74291391beSSimon Glass 75291391beSSimon Glass #define INT_EP_CTL 0x68 76291391beSSimon Glass #define INT_EP_CTL_PHY_INT_ 0x00008000 77291391beSSimon Glass 78291391beSSimon Glass #define BULK_IN_DLY 0x6C 79291391beSSimon Glass 80291391beSSimon Glass /* MAC CSRs */ 81291391beSSimon Glass #define MAC_CR 0x100 82291391beSSimon Glass #define MAC_CR_MCPAS_ 0x00080000 83291391beSSimon Glass #define MAC_CR_PRMS_ 0x00040000 84291391beSSimon Glass #define MAC_CR_HPFILT_ 0x00002000 85291391beSSimon Glass #define MAC_CR_TXEN_ 0x00000008 86291391beSSimon Glass #define MAC_CR_RXEN_ 0x00000004 87291391beSSimon Glass 88291391beSSimon Glass #define ADDRH 0x104 89291391beSSimon Glass 90291391beSSimon Glass #define ADDRL 0x108 91291391beSSimon Glass 92291391beSSimon Glass #define MII_ADDR 0x114 93291391beSSimon Glass #define MII_WRITE_ 0x02 94291391beSSimon Glass #define MII_BUSY_ 0x01 95291391beSSimon Glass #define MII_READ_ 0x00 /* ~of MII Write bit */ 96291391beSSimon Glass 97291391beSSimon Glass #define MII_DATA 0x118 98291391beSSimon Glass 99291391beSSimon Glass #define FLOW 0x11C 100291391beSSimon Glass 101291391beSSimon Glass #define VLAN1 0x120 102291391beSSimon Glass 103291391beSSimon Glass #define COE_CR 0x130 104291391beSSimon Glass #define Tx_COE_EN_ 0x00010000 105291391beSSimon Glass #define Rx_COE_EN_ 0x00000001 106291391beSSimon Glass 107291391beSSimon Glass /* Vendor-specific PHY Definitions */ 108291391beSSimon Glass #define PHY_INT_SRC 29 109291391beSSimon Glass 110291391beSSimon Glass #define PHY_INT_MASK 30 111291391beSSimon Glass #define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) 112291391beSSimon Glass #define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) 113291391beSSimon Glass #define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \ 114291391beSSimon Glass PHY_INT_MASK_LINK_DOWN_) 115291391beSSimon Glass 116291391beSSimon Glass /* USB Vendor Requests */ 117291391beSSimon Glass #define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 118291391beSSimon Glass #define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 119291391beSSimon Glass 120291391beSSimon Glass /* Some extra defines */ 121291391beSSimon Glass #define HS_USB_PKT_SIZE 512 122291391beSSimon Glass #define FS_USB_PKT_SIZE 64 123*0d2837ccSStefan Brüns /* 5/33 is lower limit for BURST_CAP to work */ 124*0d2837ccSStefan Brüns #define DEFAULT_HS_BURST_CAP_SIZE (5 * HS_USB_PKT_SIZE) 125*0d2837ccSStefan Brüns #define DEFAULT_FS_BURST_CAP_SIZE (33 * FS_USB_PKT_SIZE) 126291391beSSimon Glass #define DEFAULT_BULK_IN_DELAY 0x00002000 127291391beSSimon Glass #define MAX_SINGLE_PACKET_SIZE 2048 128291391beSSimon Glass #define EEPROM_MAC_OFFSET 0x01 129291391beSSimon Glass #define SMSC95XX_INTERNAL_PHY_ID 1 130291391beSSimon Glass #define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ 131291391beSSimon Glass 132291391beSSimon Glass /* local defines */ 133291391beSSimon Glass #define SMSC95XX_BASE_NAME "sms" 134291391beSSimon Glass #define USB_CTRL_SET_TIMEOUT 5000 135291391beSSimon Glass #define USB_CTRL_GET_TIMEOUT 5000 136291391beSSimon Glass #define USB_BULK_SEND_TIMEOUT 5000 137291391beSSimon Glass #define USB_BULK_RECV_TIMEOUT 5000 138291391beSSimon Glass 139*0d2837ccSStefan Brüns #define RX_URB_SIZE DEFAULT_HS_BURST_CAP_SIZE 140291391beSSimon Glass #define PHY_CONNECT_TIMEOUT 5000 141291391beSSimon Glass 142291391beSSimon Glass #define TURBO_MODE 143291391beSSimon Glass 1440990fcb7SSimon Glass #ifndef CONFIG_DM_ETH 145291391beSSimon Glass /* local vars */ 146291391beSSimon Glass static int curr_eth_dev; /* index for name of next device detected */ 1470990fcb7SSimon Glass #endif 148291391beSSimon Glass 149e1dbdf91SLucas Stach /* driver private */ 150e1dbdf91SLucas Stach struct smsc95xx_private { 1510990fcb7SSimon Glass #ifdef CONFIG_DM_ETH 1520990fcb7SSimon Glass struct ueth_data ueth; 1530990fcb7SSimon Glass #endif 154e1dbdf91SLucas Stach size_t rx_urb_size; /* maximum USB URB size */ 155e1dbdf91SLucas Stach u32 mac_cr; /* MAC control register value */ 156e1dbdf91SLucas Stach int have_hwaddr; /* 1 if we have a hardware MAC address */ 157e1dbdf91SLucas Stach }; 158291391beSSimon Glass 159291391beSSimon Glass /* 160291391beSSimon Glass * Smsc95xx infrastructure commands 161291391beSSimon Glass */ 162527298c4SSimon Glass static int smsc95xx_write_reg(struct usb_device *udev, u32 index, u32 data) 163291391beSSimon Glass { 164291391beSSimon Glass int len; 165e3b31c8dSIlya Yanok ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); 166291391beSSimon Glass 167291391beSSimon Glass cpu_to_le32s(&data); 168e3b31c8dSIlya Yanok tmpbuf[0] = data; 169291391beSSimon Glass 170527298c4SSimon Glass len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 171291391beSSimon Glass USB_VENDOR_REQUEST_WRITE_REGISTER, 172291391beSSimon Glass USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 173527298c4SSimon Glass 0, index, tmpbuf, sizeof(data), 174527298c4SSimon Glass USB_CTRL_SET_TIMEOUT); 175291391beSSimon Glass if (len != sizeof(data)) { 176291391beSSimon Glass debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d", 177291391beSSimon Glass index, data, len); 17825a9e980SSimon Glass return -EIO; 179291391beSSimon Glass } 180291391beSSimon Glass return 0; 181291391beSSimon Glass } 182291391beSSimon Glass 183527298c4SSimon Glass static int smsc95xx_read_reg(struct usb_device *udev, u32 index, u32 *data) 184291391beSSimon Glass { 185291391beSSimon Glass int len; 186e3b31c8dSIlya Yanok ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); 187291391beSSimon Glass 188527298c4SSimon Glass len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 189291391beSSimon Glass USB_VENDOR_REQUEST_READ_REGISTER, 190291391beSSimon Glass USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 191527298c4SSimon Glass 0, index, tmpbuf, sizeof(data), 192527298c4SSimon Glass USB_CTRL_GET_TIMEOUT); 193e3b31c8dSIlya Yanok *data = tmpbuf[0]; 194291391beSSimon Glass if (len != sizeof(data)) { 195291391beSSimon Glass debug("smsc95xx_read_reg failed: index=%d, len=%d", 196291391beSSimon Glass index, len); 19725a9e980SSimon Glass return -EIO; 198291391beSSimon Glass } 199291391beSSimon Glass 200291391beSSimon Glass le32_to_cpus(data); 201291391beSSimon Glass return 0; 202291391beSSimon Glass } 203291391beSSimon Glass 204291391beSSimon Glass /* Loop until the read is completed with timeout */ 205527298c4SSimon Glass static int smsc95xx_phy_wait_not_busy(struct usb_device *udev) 206291391beSSimon Glass { 207291391beSSimon Glass unsigned long start_time = get_timer(0); 208291391beSSimon Glass u32 val; 209291391beSSimon Glass 210291391beSSimon Glass do { 211527298c4SSimon Glass smsc95xx_read_reg(udev, MII_ADDR, &val); 212291391beSSimon Glass if (!(val & MII_BUSY_)) 213291391beSSimon Glass return 0; 214527298c4SSimon Glass } while (get_timer(start_time) < 1000); 215291391beSSimon Glass 21625a9e980SSimon Glass return -ETIMEDOUT; 217291391beSSimon Glass } 218291391beSSimon Glass 219527298c4SSimon Glass static int smsc95xx_mdio_read(struct usb_device *udev, int phy_id, int idx) 220291391beSSimon Glass { 221291391beSSimon Glass u32 val, addr; 222291391beSSimon Glass 223291391beSSimon Glass /* confirm MII not busy */ 224527298c4SSimon Glass if (smsc95xx_phy_wait_not_busy(udev)) { 225291391beSSimon Glass debug("MII is busy in smsc95xx_mdio_read\n"); 22625a9e980SSimon Glass return -ETIMEDOUT; 227291391beSSimon Glass } 228291391beSSimon Glass 229291391beSSimon Glass /* set the address, index & direction (read from PHY) */ 230291391beSSimon Glass addr = (phy_id << 11) | (idx << 6) | MII_READ_; 231527298c4SSimon Glass smsc95xx_write_reg(udev, MII_ADDR, addr); 232291391beSSimon Glass 233527298c4SSimon Glass if (smsc95xx_phy_wait_not_busy(udev)) { 234291391beSSimon Glass debug("Timed out reading MII reg %02X\n", idx); 23525a9e980SSimon Glass return -ETIMEDOUT; 236291391beSSimon Glass } 237291391beSSimon Glass 238527298c4SSimon Glass smsc95xx_read_reg(udev, MII_DATA, &val); 239291391beSSimon Glass 240291391beSSimon Glass return (u16)(val & 0xFFFF); 241291391beSSimon Glass } 242291391beSSimon Glass 243527298c4SSimon Glass static void smsc95xx_mdio_write(struct usb_device *udev, int phy_id, int idx, 244291391beSSimon Glass int regval) 245291391beSSimon Glass { 246291391beSSimon Glass u32 val, addr; 247291391beSSimon Glass 248291391beSSimon Glass /* confirm MII not busy */ 249527298c4SSimon Glass if (smsc95xx_phy_wait_not_busy(udev)) { 250291391beSSimon Glass debug("MII is busy in smsc95xx_mdio_write\n"); 251291391beSSimon Glass return; 252291391beSSimon Glass } 253291391beSSimon Glass 254291391beSSimon Glass val = regval; 255527298c4SSimon Glass smsc95xx_write_reg(udev, MII_DATA, val); 256291391beSSimon Glass 257291391beSSimon Glass /* set the address, index & direction (write to PHY) */ 258291391beSSimon Glass addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; 259527298c4SSimon Glass smsc95xx_write_reg(udev, MII_ADDR, addr); 260291391beSSimon Glass 261527298c4SSimon Glass if (smsc95xx_phy_wait_not_busy(udev)) 262291391beSSimon Glass debug("Timed out writing MII reg %02X\n", idx); 263291391beSSimon Glass } 264291391beSSimon Glass 265527298c4SSimon Glass static int smsc95xx_eeprom_confirm_not_busy(struct usb_device *udev) 266291391beSSimon Glass { 267291391beSSimon Glass unsigned long start_time = get_timer(0); 268291391beSSimon Glass u32 val; 269291391beSSimon Glass 270291391beSSimon Glass do { 271527298c4SSimon Glass smsc95xx_read_reg(udev, E2P_CMD, &val); 272291391beSSimon Glass if (!(val & E2P_CMD_BUSY_)) 273291391beSSimon Glass return 0; 274291391beSSimon Glass udelay(40); 275291391beSSimon Glass } while (get_timer(start_time) < 1 * 1000 * 1000); 276291391beSSimon Glass 277291391beSSimon Glass debug("EEPROM is busy\n"); 27825a9e980SSimon Glass return -ETIMEDOUT; 279291391beSSimon Glass } 280291391beSSimon Glass 281527298c4SSimon Glass static int smsc95xx_wait_eeprom(struct usb_device *udev) 282291391beSSimon Glass { 283291391beSSimon Glass unsigned long start_time = get_timer(0); 284291391beSSimon Glass u32 val; 285291391beSSimon Glass 286291391beSSimon Glass do { 287527298c4SSimon Glass smsc95xx_read_reg(udev, E2P_CMD, &val); 288291391beSSimon Glass if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) 289291391beSSimon Glass break; 290291391beSSimon Glass udelay(40); 291291391beSSimon Glass } while (get_timer(start_time) < 1 * 1000 * 1000); 292291391beSSimon Glass 293291391beSSimon Glass if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { 294291391beSSimon Glass debug("EEPROM read operation timeout\n"); 29525a9e980SSimon Glass return -ETIMEDOUT; 296291391beSSimon Glass } 297291391beSSimon Glass return 0; 298291391beSSimon Glass } 299291391beSSimon Glass 300527298c4SSimon Glass static int smsc95xx_read_eeprom(struct usb_device *udev, u32 offset, u32 length, 301291391beSSimon Glass u8 *data) 302291391beSSimon Glass { 303291391beSSimon Glass u32 val; 304291391beSSimon Glass int i, ret; 305291391beSSimon Glass 306527298c4SSimon Glass ret = smsc95xx_eeprom_confirm_not_busy(udev); 307291391beSSimon Glass if (ret) 308291391beSSimon Glass return ret; 309291391beSSimon Glass 310291391beSSimon Glass for (i = 0; i < length; i++) { 311291391beSSimon Glass val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); 312527298c4SSimon Glass smsc95xx_write_reg(udev, E2P_CMD, val); 313291391beSSimon Glass 314527298c4SSimon Glass ret = smsc95xx_wait_eeprom(udev); 315291391beSSimon Glass if (ret < 0) 316291391beSSimon Glass return ret; 317291391beSSimon Glass 318527298c4SSimon Glass smsc95xx_read_reg(udev, E2P_DATA, &val); 319291391beSSimon Glass data[i] = val & 0xFF; 320291391beSSimon Glass offset++; 321291391beSSimon Glass } 322291391beSSimon Glass return 0; 323291391beSSimon Glass } 324291391beSSimon Glass 325291391beSSimon Glass /* 326291391beSSimon Glass * mii_nway_restart - restart NWay (autonegotiation) for this interface 327291391beSSimon Glass * 328291391beSSimon Glass * Returns 0 on success, negative on error. 329291391beSSimon Glass */ 330527298c4SSimon Glass static int mii_nway_restart(struct usb_device *udev, struct ueth_data *dev) 331291391beSSimon Glass { 332291391beSSimon Glass int bmcr; 333291391beSSimon Glass int r = -1; 334291391beSSimon Glass 335291391beSSimon Glass /* if autoneg is off, it's an error */ 336527298c4SSimon Glass bmcr = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMCR); 337291391beSSimon Glass 338291391beSSimon Glass if (bmcr & BMCR_ANENABLE) { 339291391beSSimon Glass bmcr |= BMCR_ANRESTART; 340527298c4SSimon Glass smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, bmcr); 341291391beSSimon Glass r = 0; 342291391beSSimon Glass } 343291391beSSimon Glass return r; 344291391beSSimon Glass } 345291391beSSimon Glass 346527298c4SSimon Glass static int smsc95xx_phy_initialize(struct usb_device *udev, 347527298c4SSimon Glass struct ueth_data *dev) 348291391beSSimon Glass { 349527298c4SSimon Glass smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, BMCR_RESET); 350527298c4SSimon Glass smsc95xx_mdio_write(udev, dev->phy_id, MII_ADVERTISE, 351527298c4SSimon Glass ADVERTISE_ALL | ADVERTISE_CSMA | 352527298c4SSimon Glass ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); 353291391beSSimon Glass 354291391beSSimon Glass /* read to clear */ 355527298c4SSimon Glass smsc95xx_mdio_read(udev, dev->phy_id, PHY_INT_SRC); 356291391beSSimon Glass 357527298c4SSimon Glass smsc95xx_mdio_write(udev, dev->phy_id, PHY_INT_MASK, 358291391beSSimon Glass PHY_INT_MASK_DEFAULT_); 359527298c4SSimon Glass mii_nway_restart(udev, dev); 360291391beSSimon Glass 361291391beSSimon Glass debug("phy initialised succesfully\n"); 362291391beSSimon Glass return 0; 363291391beSSimon Glass } 364291391beSSimon Glass 365527298c4SSimon Glass static int smsc95xx_init_mac_address(unsigned char *enetaddr, 366527298c4SSimon Glass struct usb_device *udev) 367291391beSSimon Glass { 368527298c4SSimon Glass int ret; 369527298c4SSimon Glass 370291391beSSimon Glass /* try reading mac address from EEPROM */ 371527298c4SSimon Glass ret = smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN, enetaddr); 372527298c4SSimon Glass if (ret) 373527298c4SSimon Glass return ret; 374527298c4SSimon Glass 375527298c4SSimon Glass if (is_valid_ethaddr(enetaddr)) { 376291391beSSimon Glass /* eeprom values are valid so use them */ 377291391beSSimon Glass debug("MAC address read from EEPROM\n"); 378291391beSSimon Glass return 0; 379291391beSSimon Glass } 380291391beSSimon Glass 381291391beSSimon Glass /* 382291391beSSimon Glass * No eeprom, or eeprom values are invalid. Generating a random MAC 383291391beSSimon Glass * address is not safe. Just return an error. 384291391beSSimon Glass */ 38525a9e980SSimon Glass debug("Invalid MAC address read from EEPROM\n"); 38625a9e980SSimon Glass 38725a9e980SSimon Glass return -ENXIO; 388291391beSSimon Glass } 389291391beSSimon Glass 390527298c4SSimon Glass static int smsc95xx_write_hwaddr_common(struct usb_device *udev, 391527298c4SSimon Glass struct smsc95xx_private *priv, 392527298c4SSimon Glass unsigned char *enetaddr) 393291391beSSimon Glass { 394527298c4SSimon Glass u32 addr_lo = __get_unaligned_le32(&enetaddr[0]); 395527298c4SSimon Glass u32 addr_hi = __get_unaligned_le16(&enetaddr[4]); 396291391beSSimon Glass int ret; 397291391beSSimon Glass 398291391beSSimon Glass /* set hardware address */ 399291391beSSimon Glass debug("** %s()\n", __func__); 400527298c4SSimon Glass ret = smsc95xx_write_reg(udev, ADDRL, addr_lo); 4010d9679e6SWolfgang Grandegger if (ret < 0) 402291391beSSimon Glass return ret; 403291391beSSimon Glass 404527298c4SSimon Glass ret = smsc95xx_write_reg(udev, ADDRH, addr_hi); 405291391beSSimon Glass if (ret < 0) 406291391beSSimon Glass return ret; 4070d9679e6SWolfgang Grandegger 408527298c4SSimon Glass debug("MAC %pM\n", enetaddr); 409e1dbdf91SLucas Stach priv->have_hwaddr = 1; 410527298c4SSimon Glass 411291391beSSimon Glass return 0; 412291391beSSimon Glass } 413291391beSSimon Glass 414291391beSSimon Glass /* Enable or disable Tx & Rx checksum offload engines */ 415527298c4SSimon Glass static int smsc95xx_set_csums(struct usb_device *udev, int use_tx_csum, 416527298c4SSimon Glass int use_rx_csum) 417291391beSSimon Glass { 418291391beSSimon Glass u32 read_buf; 419527298c4SSimon Glass int ret = smsc95xx_read_reg(udev, COE_CR, &read_buf); 420291391beSSimon Glass if (ret < 0) 421291391beSSimon Glass return ret; 422291391beSSimon Glass 423291391beSSimon Glass if (use_tx_csum) 424291391beSSimon Glass read_buf |= Tx_COE_EN_; 425291391beSSimon Glass else 426291391beSSimon Glass read_buf &= ~Tx_COE_EN_; 427291391beSSimon Glass 428291391beSSimon Glass if (use_rx_csum) 429291391beSSimon Glass read_buf |= Rx_COE_EN_; 430291391beSSimon Glass else 431291391beSSimon Glass read_buf &= ~Rx_COE_EN_; 432291391beSSimon Glass 433527298c4SSimon Glass ret = smsc95xx_write_reg(udev, COE_CR, read_buf); 434291391beSSimon Glass if (ret < 0) 435291391beSSimon Glass return ret; 436291391beSSimon Glass 437291391beSSimon Glass debug("COE_CR = 0x%08x\n", read_buf); 438291391beSSimon Glass return 0; 439291391beSSimon Glass } 440291391beSSimon Glass 441527298c4SSimon Glass static void smsc95xx_set_multicast(struct smsc95xx_private *priv) 442291391beSSimon Glass { 443291391beSSimon Glass /* No multicast in u-boot */ 444e1dbdf91SLucas Stach priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); 445291391beSSimon Glass } 446291391beSSimon Glass 447291391beSSimon Glass /* starts the TX path */ 448527298c4SSimon Glass static void smsc95xx_start_tx_path(struct usb_device *udev, 449527298c4SSimon Glass struct smsc95xx_private *priv) 450291391beSSimon Glass { 451291391beSSimon Glass u32 reg_val; 452291391beSSimon Glass 453291391beSSimon Glass /* Enable Tx at MAC */ 454e1dbdf91SLucas Stach priv->mac_cr |= MAC_CR_TXEN_; 455291391beSSimon Glass 456527298c4SSimon Glass smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr); 457291391beSSimon Glass 458291391beSSimon Glass /* Enable Tx at SCSRs */ 459291391beSSimon Glass reg_val = TX_CFG_ON_; 460527298c4SSimon Glass smsc95xx_write_reg(udev, TX_CFG, reg_val); 461291391beSSimon Glass } 462291391beSSimon Glass 463291391beSSimon Glass /* Starts the Receive path */ 464527298c4SSimon Glass static void smsc95xx_start_rx_path(struct usb_device *udev, 465527298c4SSimon Glass struct smsc95xx_private *priv) 466291391beSSimon Glass { 467e1dbdf91SLucas Stach priv->mac_cr |= MAC_CR_RXEN_; 468527298c4SSimon Glass smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr); 469291391beSSimon Glass } 470291391beSSimon Glass 471527298c4SSimon Glass static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev, 472527298c4SSimon Glass struct smsc95xx_private *priv, 473527298c4SSimon Glass unsigned char *enetaddr) 474291391beSSimon Glass { 475291391beSSimon Glass int ret; 476291391beSSimon Glass u32 write_buf; 477291391beSSimon Glass u32 read_buf; 478291391beSSimon Glass u32 burst_cap; 479291391beSSimon Glass int timeout; 480291391beSSimon Glass #define TIMEOUT_RESOLUTION 50 /* ms */ 481291391beSSimon Glass int link_detected; 482291391beSSimon Glass 483291391beSSimon Glass debug("** %s()\n", __func__); 484291391beSSimon Glass dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */ 485291391beSSimon Glass 486291391beSSimon Glass write_buf = HW_CFG_LRST_; 487527298c4SSimon Glass ret = smsc95xx_write_reg(udev, HW_CFG, write_buf); 488291391beSSimon Glass if (ret < 0) 489291391beSSimon Glass return ret; 490291391beSSimon Glass 491291391beSSimon Glass timeout = 0; 492291391beSSimon Glass do { 493527298c4SSimon Glass ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); 494291391beSSimon Glass if (ret < 0) 495291391beSSimon Glass return ret; 496291391beSSimon Glass udelay(10 * 1000); 497291391beSSimon Glass timeout++; 498291391beSSimon Glass } while ((read_buf & HW_CFG_LRST_) && (timeout < 100)); 499291391beSSimon Glass 500291391beSSimon Glass if (timeout >= 100) { 501291391beSSimon Glass debug("timeout waiting for completion of Lite Reset\n"); 50225a9e980SSimon Glass return -ETIMEDOUT; 503291391beSSimon Glass } 504291391beSSimon Glass 505291391beSSimon Glass write_buf = PM_CTL_PHY_RST_; 506527298c4SSimon Glass ret = smsc95xx_write_reg(udev, PM_CTRL, write_buf); 507291391beSSimon Glass if (ret < 0) 508291391beSSimon Glass return ret; 509291391beSSimon Glass 510291391beSSimon Glass timeout = 0; 511291391beSSimon Glass do { 512527298c4SSimon Glass ret = smsc95xx_read_reg(udev, PM_CTRL, &read_buf); 513291391beSSimon Glass if (ret < 0) 514291391beSSimon Glass return ret; 515291391beSSimon Glass udelay(10 * 1000); 516291391beSSimon Glass timeout++; 517291391beSSimon Glass } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); 518291391beSSimon Glass if (timeout >= 100) { 519291391beSSimon Glass debug("timeout waiting for PHY Reset\n"); 52025a9e980SSimon Glass return -ETIMEDOUT; 521291391beSSimon Glass } 522527298c4SSimon Glass if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) == 523527298c4SSimon Glass 0) 524e1dbdf91SLucas Stach priv->have_hwaddr = 1; 525e1dbdf91SLucas Stach if (!priv->have_hwaddr) { 526291391beSSimon Glass puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n"); 52725a9e980SSimon Glass return -EADDRNOTAVAIL; 528291391beSSimon Glass } 529527298c4SSimon Glass ret = smsc95xx_write_hwaddr_common(udev, priv, enetaddr); 53025a9e980SSimon Glass if (ret < 0) 53125a9e980SSimon Glass return ret; 532291391beSSimon Glass 533527298c4SSimon Glass ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); 534291391beSSimon Glass if (ret < 0) 535291391beSSimon Glass return ret; 536291391beSSimon Glass debug("Read Value from HW_CFG : 0x%08x\n", read_buf); 537291391beSSimon Glass 538291391beSSimon Glass read_buf |= HW_CFG_BIR_; 539527298c4SSimon Glass ret = smsc95xx_write_reg(udev, HW_CFG, read_buf); 540291391beSSimon Glass if (ret < 0) 541291391beSSimon Glass return ret; 542291391beSSimon Glass 543527298c4SSimon Glass ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); 544291391beSSimon Glass if (ret < 0) 545291391beSSimon Glass return ret; 546291391beSSimon Glass debug("Read Value from HW_CFG after writing " 547291391beSSimon Glass "HW_CFG_BIR_: 0x%08x\n", read_buf); 548291391beSSimon Glass 549291391beSSimon Glass #ifdef TURBO_MODE 550291391beSSimon Glass if (dev->pusb_dev->speed == USB_SPEED_HIGH) { 551291391beSSimon Glass burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; 552e1dbdf91SLucas Stach priv->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; 553291391beSSimon Glass } else { 554291391beSSimon Glass burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; 555e1dbdf91SLucas Stach priv->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; 556291391beSSimon Glass } 557291391beSSimon Glass #else 558291391beSSimon Glass burst_cap = 0; 559e1dbdf91SLucas Stach priv->rx_urb_size = MAX_SINGLE_PACKET_SIZE; 560291391beSSimon Glass #endif 561e1dbdf91SLucas Stach debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size); 562291391beSSimon Glass 563527298c4SSimon Glass ret = smsc95xx_write_reg(udev, BURST_CAP, burst_cap); 564291391beSSimon Glass if (ret < 0) 565291391beSSimon Glass return ret; 566291391beSSimon Glass 567527298c4SSimon Glass ret = smsc95xx_read_reg(udev, BURST_CAP, &read_buf); 568291391beSSimon Glass if (ret < 0) 569291391beSSimon Glass return ret; 570291391beSSimon Glass debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf); 571291391beSSimon Glass 572291391beSSimon Glass read_buf = DEFAULT_BULK_IN_DELAY; 573527298c4SSimon Glass ret = smsc95xx_write_reg(udev, BULK_IN_DLY, read_buf); 574291391beSSimon Glass if (ret < 0) 575291391beSSimon Glass return ret; 576291391beSSimon Glass 577527298c4SSimon Glass ret = smsc95xx_read_reg(udev, BULK_IN_DLY, &read_buf); 578291391beSSimon Glass if (ret < 0) 579291391beSSimon Glass return ret; 580291391beSSimon Glass debug("Read Value from BULK_IN_DLY after writing: " 581291391beSSimon Glass "0x%08x\n", read_buf); 582291391beSSimon Glass 583527298c4SSimon Glass ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); 584291391beSSimon Glass if (ret < 0) 585291391beSSimon Glass return ret; 586291391beSSimon Glass debug("Read Value from HW_CFG: 0x%08x\n", read_buf); 587291391beSSimon Glass 588291391beSSimon Glass #ifdef TURBO_MODE 589291391beSSimon Glass read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_); 590291391beSSimon Glass #endif 591291391beSSimon Glass read_buf &= ~HW_CFG_RXDOFF_; 592291391beSSimon Glass 593291391beSSimon Glass #define NET_IP_ALIGN 0 594291391beSSimon Glass read_buf |= NET_IP_ALIGN << 9; 595291391beSSimon Glass 596527298c4SSimon Glass ret = smsc95xx_write_reg(udev, HW_CFG, read_buf); 597291391beSSimon Glass if (ret < 0) 598291391beSSimon Glass return ret; 599291391beSSimon Glass 600527298c4SSimon Glass ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); 601291391beSSimon Glass if (ret < 0) 602291391beSSimon Glass return ret; 603291391beSSimon Glass debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf); 604291391beSSimon Glass 605291391beSSimon Glass write_buf = 0xFFFFFFFF; 606527298c4SSimon Glass ret = smsc95xx_write_reg(udev, INT_STS, write_buf); 607291391beSSimon Glass if (ret < 0) 608291391beSSimon Glass return ret; 609291391beSSimon Glass 610527298c4SSimon Glass ret = smsc95xx_read_reg(udev, ID_REV, &read_buf); 611291391beSSimon Glass if (ret < 0) 612291391beSSimon Glass return ret; 613291391beSSimon Glass debug("ID_REV = 0x%08x\n", read_buf); 614291391beSSimon Glass 61598f686c2SSuriyan Ramasami /* Configure GPIO pins as LED outputs */ 61698f686c2SSuriyan Ramasami write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | 61798f686c2SSuriyan Ramasami LED_GPIO_CFG_FDX_LED; 618527298c4SSimon Glass ret = smsc95xx_write_reg(udev, LED_GPIO_CFG, write_buf); 61998f686c2SSuriyan Ramasami if (ret < 0) 62098f686c2SSuriyan Ramasami return ret; 62198f686c2SSuriyan Ramasami debug("LED_GPIO_CFG set\n"); 62298f686c2SSuriyan Ramasami 623291391beSSimon Glass /* Init Tx */ 624291391beSSimon Glass write_buf = 0; 625527298c4SSimon Glass ret = smsc95xx_write_reg(udev, FLOW, write_buf); 626291391beSSimon Glass if (ret < 0) 627291391beSSimon Glass return ret; 628291391beSSimon Glass 629291391beSSimon Glass read_buf = AFC_CFG_DEFAULT; 630527298c4SSimon Glass ret = smsc95xx_write_reg(udev, AFC_CFG, read_buf); 631291391beSSimon Glass if (ret < 0) 632291391beSSimon Glass return ret; 633291391beSSimon Glass 634527298c4SSimon Glass ret = smsc95xx_read_reg(udev, MAC_CR, &priv->mac_cr); 635291391beSSimon Glass if (ret < 0) 636291391beSSimon Glass return ret; 637291391beSSimon Glass 638291391beSSimon Glass /* Init Rx. Set Vlan */ 639291391beSSimon Glass write_buf = (u32)ETH_P_8021Q; 640527298c4SSimon Glass ret = smsc95xx_write_reg(udev, VLAN1, write_buf); 641291391beSSimon Glass if (ret < 0) 642291391beSSimon Glass return ret; 643291391beSSimon Glass 644291391beSSimon Glass /* Disable checksum offload engines */ 645527298c4SSimon Glass ret = smsc95xx_set_csums(udev, 0, 0); 646291391beSSimon Glass if (ret < 0) { 647291391beSSimon Glass debug("Failed to set csum offload: %d\n", ret); 648291391beSSimon Glass return ret; 649291391beSSimon Glass } 650527298c4SSimon Glass smsc95xx_set_multicast(priv); 651291391beSSimon Glass 652527298c4SSimon Glass ret = smsc95xx_phy_initialize(udev, dev); 65325a9e980SSimon Glass if (ret < 0) 65425a9e980SSimon Glass return ret; 655527298c4SSimon Glass ret = smsc95xx_read_reg(udev, INT_EP_CTL, &read_buf); 656291391beSSimon Glass if (ret < 0) 657291391beSSimon Glass return ret; 658291391beSSimon Glass 659291391beSSimon Glass /* enable PHY interrupts */ 660291391beSSimon Glass read_buf |= INT_EP_CTL_PHY_INT_; 661291391beSSimon Glass 662527298c4SSimon Glass ret = smsc95xx_write_reg(udev, INT_EP_CTL, read_buf); 663291391beSSimon Glass if (ret < 0) 664291391beSSimon Glass return ret; 665291391beSSimon Glass 666527298c4SSimon Glass smsc95xx_start_tx_path(udev, priv); 667527298c4SSimon Glass smsc95xx_start_rx_path(udev, priv); 668291391beSSimon Glass 669291391beSSimon Glass timeout = 0; 670291391beSSimon Glass do { 671527298c4SSimon Glass link_detected = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMSR) 672291391beSSimon Glass & BMSR_LSTATUS; 673291391beSSimon Glass if (!link_detected) { 674291391beSSimon Glass if (timeout == 0) 675291391beSSimon Glass printf("Waiting for Ethernet connection... "); 676291391beSSimon Glass udelay(TIMEOUT_RESOLUTION * 1000); 677291391beSSimon Glass timeout += TIMEOUT_RESOLUTION; 678291391beSSimon Glass } 679291391beSSimon Glass } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT); 680291391beSSimon Glass if (link_detected) { 681291391beSSimon Glass if (timeout != 0) 682291391beSSimon Glass printf("done.\n"); 683291391beSSimon Glass } else { 684291391beSSimon Glass printf("unable to connect.\n"); 68525a9e980SSimon Glass return -EIO; 686291391beSSimon Glass } 687291391beSSimon Glass return 0; 688291391beSSimon Glass } 689291391beSSimon Glass 690527298c4SSimon Glass static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length) 691291391beSSimon Glass { 692291391beSSimon Glass int err; 693291391beSSimon Glass int actual_len; 694291391beSSimon Glass u32 tx_cmd_a; 695291391beSSimon Glass u32 tx_cmd_b; 696e3b31c8dSIlya Yanok ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg, 697e3b31c8dSIlya Yanok PKTSIZE + sizeof(tx_cmd_a) + sizeof(tx_cmd_b)); 698291391beSSimon Glass 699291391beSSimon Glass debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg); 700291391beSSimon Glass if (length > PKTSIZE) 70125a9e980SSimon Glass return -ENOSPC; 702291391beSSimon Glass 703291391beSSimon Glass tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; 704291391beSSimon Glass tx_cmd_b = (u32)length; 705291391beSSimon Glass cpu_to_le32s(&tx_cmd_a); 706291391beSSimon Glass cpu_to_le32s(&tx_cmd_b); 707291391beSSimon Glass 708291391beSSimon Glass /* prepend cmd_a and cmd_b */ 709291391beSSimon Glass memcpy(msg, &tx_cmd_a, sizeof(tx_cmd_a)); 710291391beSSimon Glass memcpy(msg + sizeof(tx_cmd_a), &tx_cmd_b, sizeof(tx_cmd_b)); 711291391beSSimon Glass memcpy(msg + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), (void *)packet, 712291391beSSimon Glass length); 713291391beSSimon Glass err = usb_bulk_msg(dev->pusb_dev, 714291391beSSimon Glass usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), 715291391beSSimon Glass (void *)msg, 716291391beSSimon Glass length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), 717291391beSSimon Glass &actual_len, 718291391beSSimon Glass USB_BULK_SEND_TIMEOUT); 719291391beSSimon Glass debug("Tx: len = %u, actual = %u, err = %d\n", 720291391beSSimon Glass length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), 721291391beSSimon Glass actual_len, err); 722527298c4SSimon Glass 723291391beSSimon Glass return err; 724291391beSSimon Glass } 725291391beSSimon Glass 7260990fcb7SSimon Glass #ifndef CONFIG_DM_ETH 727527298c4SSimon Glass /* 728527298c4SSimon Glass * Smsc95xx callbacks 729527298c4SSimon Glass */ 730527298c4SSimon Glass static int smsc95xx_init(struct eth_device *eth, bd_t *bd) 731527298c4SSimon Glass { 732527298c4SSimon Glass struct ueth_data *dev = (struct ueth_data *)eth->priv; 733527298c4SSimon Glass struct usb_device *udev = dev->pusb_dev; 734527298c4SSimon Glass struct smsc95xx_private *priv = 735527298c4SSimon Glass (struct smsc95xx_private *)dev->dev_priv; 736527298c4SSimon Glass 737527298c4SSimon Glass return smsc95xx_init_common(udev, dev, priv, eth->enetaddr); 738527298c4SSimon Glass } 739527298c4SSimon Glass 740527298c4SSimon Glass static int smsc95xx_send(struct eth_device *eth, void *packet, int length) 741527298c4SSimon Glass { 742527298c4SSimon Glass struct ueth_data *dev = (struct ueth_data *)eth->priv; 743527298c4SSimon Glass 744527298c4SSimon Glass return smsc95xx_send_common(dev, packet, length); 745527298c4SSimon Glass } 746527298c4SSimon Glass 747291391beSSimon Glass static int smsc95xx_recv(struct eth_device *eth) 748291391beSSimon Glass { 749291391beSSimon Glass struct ueth_data *dev = (struct ueth_data *)eth->priv; 750d62a1dc6SSimon Glass DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, RX_URB_SIZE); 751291391beSSimon Glass unsigned char *buf_ptr; 752291391beSSimon Glass int err; 753291391beSSimon Glass int actual_len; 754291391beSSimon Glass u32 packet_len; 755291391beSSimon Glass int cur_buf_align; 756291391beSSimon Glass 757291391beSSimon Glass debug("** %s()\n", __func__); 758291391beSSimon Glass err = usb_bulk_msg(dev->pusb_dev, 759291391beSSimon Glass usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), 760527298c4SSimon Glass (void *)recv_buf, RX_URB_SIZE, &actual_len, 761291391beSSimon Glass USB_BULK_RECV_TIMEOUT); 762d62a1dc6SSimon Glass debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE, 763291391beSSimon Glass actual_len, err); 764291391beSSimon Glass if (err != 0) { 765291391beSSimon Glass debug("Rx: failed to receive\n"); 766527298c4SSimon Glass return -err; 767291391beSSimon Glass } 768d62a1dc6SSimon Glass if (actual_len > RX_URB_SIZE) { 769291391beSSimon Glass debug("Rx: received too many bytes %d\n", actual_len); 77025a9e980SSimon Glass return -ENOSPC; 771291391beSSimon Glass } 772291391beSSimon Glass 773291391beSSimon Glass buf_ptr = recv_buf; 774291391beSSimon Glass while (actual_len > 0) { 775291391beSSimon Glass /* 776291391beSSimon Glass * 1st 4 bytes contain the length of the actual data plus error 777291391beSSimon Glass * info. Extract data length. 778291391beSSimon Glass */ 779291391beSSimon Glass if (actual_len < sizeof(packet_len)) { 780291391beSSimon Glass debug("Rx: incomplete packet length\n"); 78125a9e980SSimon Glass return -EIO; 782291391beSSimon Glass } 783291391beSSimon Glass memcpy(&packet_len, buf_ptr, sizeof(packet_len)); 784291391beSSimon Glass le32_to_cpus(&packet_len); 785291391beSSimon Glass if (packet_len & RX_STS_ES_) { 786291391beSSimon Glass debug("Rx: Error header=%#x", packet_len); 78725a9e980SSimon Glass return -EIO; 788291391beSSimon Glass } 789291391beSSimon Glass packet_len = ((packet_len & RX_STS_FL_) >> 16); 790291391beSSimon Glass 791291391beSSimon Glass if (packet_len > actual_len - sizeof(packet_len)) { 792291391beSSimon Glass debug("Rx: too large packet: %d\n", packet_len); 79325a9e980SSimon Glass return -EIO; 794291391beSSimon Glass } 795291391beSSimon Glass 796291391beSSimon Glass /* Notify net stack */ 7971fd92db8SJoe Hershberger net_process_received_packet(buf_ptr + sizeof(packet_len), 7981fd92db8SJoe Hershberger packet_len - 4); 799291391beSSimon Glass 800291391beSSimon Glass /* Adjust for next iteration */ 801291391beSSimon Glass actual_len -= sizeof(packet_len) + packet_len; 802291391beSSimon Glass buf_ptr += sizeof(packet_len) + packet_len; 803291391beSSimon Glass cur_buf_align = (int)buf_ptr - (int)recv_buf; 804291391beSSimon Glass 805291391beSSimon Glass if (cur_buf_align & 0x03) { 806291391beSSimon Glass int align = 4 - (cur_buf_align & 0x03); 807291391beSSimon Glass 808291391beSSimon Glass actual_len -= align; 809291391beSSimon Glass buf_ptr += align; 810291391beSSimon Glass } 811291391beSSimon Glass } 812291391beSSimon Glass return err; 813291391beSSimon Glass } 814291391beSSimon Glass 815291391beSSimon Glass static void smsc95xx_halt(struct eth_device *eth) 816291391beSSimon Glass { 817291391beSSimon Glass debug("** %s()\n", __func__); 818291391beSSimon Glass } 819291391beSSimon Glass 820527298c4SSimon Glass static int smsc95xx_write_hwaddr(struct eth_device *eth) 821527298c4SSimon Glass { 822527298c4SSimon Glass struct ueth_data *dev = eth->priv; 823527298c4SSimon Glass struct usb_device *udev = dev->pusb_dev; 824527298c4SSimon Glass struct smsc95xx_private *priv = dev->dev_priv; 825527298c4SSimon Glass 826527298c4SSimon Glass return smsc95xx_write_hwaddr_common(udev, priv, eth->enetaddr); 827527298c4SSimon Glass } 828527298c4SSimon Glass 829291391beSSimon Glass /* 830291391beSSimon Glass * SMSC probing functions 831291391beSSimon Glass */ 832291391beSSimon Glass void smsc95xx_eth_before_probe(void) 833291391beSSimon Glass { 834291391beSSimon Glass curr_eth_dev = 0; 835291391beSSimon Glass } 836291391beSSimon Glass 837291391beSSimon Glass struct smsc95xx_dongle { 838291391beSSimon Glass unsigned short vendor; 839291391beSSimon Glass unsigned short product; 840291391beSSimon Glass }; 841291391beSSimon Glass 842291391beSSimon Glass static const struct smsc95xx_dongle smsc95xx_dongles[] = { 843291391beSSimon Glass { 0x0424, 0xec00 }, /* LAN9512/LAN9514 Ethernet */ 844291391beSSimon Glass { 0x0424, 0x9500 }, /* LAN9500 Ethernet */ 845e7dceceaSLubomir Popov { 0x0424, 0x9730 }, /* LAN9730 Ethernet (HSIC) */ 8462eb60902SStefan Roese { 0x0424, 0x9900 }, /* SMSC9500 USB Ethernet Device (SAL10) */ 84708ebd467SIlya Ledvich { 0x0424, 0x9e00 }, /* LAN9500A Ethernet */ 848291391beSSimon Glass { 0x0000, 0x0000 } /* END - Do not remove */ 849291391beSSimon Glass }; 850291391beSSimon Glass 851291391beSSimon Glass /* Probe to see if a new device is actually an SMSC device */ 852291391beSSimon Glass int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum, 853291391beSSimon Glass struct ueth_data *ss) 854291391beSSimon Glass { 855291391beSSimon Glass struct usb_interface *iface; 856291391beSSimon Glass struct usb_interface_descriptor *iface_desc; 857291391beSSimon Glass int i; 858291391beSSimon Glass 859291391beSSimon Glass /* let's examine the device now */ 860291391beSSimon Glass iface = &dev->config.if_desc[ifnum]; 861291391beSSimon Glass iface_desc = &dev->config.if_desc[ifnum].desc; 862291391beSSimon Glass 863291391beSSimon Glass for (i = 0; smsc95xx_dongles[i].vendor != 0; i++) { 864291391beSSimon Glass if (dev->descriptor.idVendor == smsc95xx_dongles[i].vendor && 865291391beSSimon Glass dev->descriptor.idProduct == smsc95xx_dongles[i].product) 866291391beSSimon Glass /* Found a supported dongle */ 867291391beSSimon Glass break; 868291391beSSimon Glass } 869291391beSSimon Glass if (smsc95xx_dongles[i].vendor == 0) 870291391beSSimon Glass return 0; 871291391beSSimon Glass 872291391beSSimon Glass /* At this point, we know we've got a live one */ 873291391beSSimon Glass debug("\n\nUSB Ethernet device detected\n"); 874291391beSSimon Glass memset(ss, '\0', sizeof(struct ueth_data)); 875291391beSSimon Glass 876291391beSSimon Glass /* Initialize the ueth_data structure with some useful info */ 877291391beSSimon Glass ss->ifnum = ifnum; 878291391beSSimon Glass ss->pusb_dev = dev; 879291391beSSimon Glass ss->subclass = iface_desc->bInterfaceSubClass; 880291391beSSimon Glass ss->protocol = iface_desc->bInterfaceProtocol; 881291391beSSimon Glass 882291391beSSimon Glass /* 883291391beSSimon Glass * We are expecting a minimum of 3 endpoints - in, out (bulk), and int. 884291391beSSimon Glass * We will ignore any others. 885291391beSSimon Glass */ 886291391beSSimon Glass for (i = 0; i < iface_desc->bNumEndpoints; i++) { 887291391beSSimon Glass /* is it an BULK endpoint? */ 888291391beSSimon Glass if ((iface->ep_desc[i].bmAttributes & 889291391beSSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { 890291391beSSimon Glass if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) 891291391beSSimon Glass ss->ep_in = 892291391beSSimon Glass iface->ep_desc[i].bEndpointAddress & 893291391beSSimon Glass USB_ENDPOINT_NUMBER_MASK; 894291391beSSimon Glass else 895291391beSSimon Glass ss->ep_out = 896291391beSSimon Glass iface->ep_desc[i].bEndpointAddress & 897291391beSSimon Glass USB_ENDPOINT_NUMBER_MASK; 898291391beSSimon Glass } 899291391beSSimon Glass 900291391beSSimon Glass /* is it an interrupt endpoint? */ 901291391beSSimon Glass if ((iface->ep_desc[i].bmAttributes & 902291391beSSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { 903291391beSSimon Glass ss->ep_int = iface->ep_desc[i].bEndpointAddress & 904291391beSSimon Glass USB_ENDPOINT_NUMBER_MASK; 905291391beSSimon Glass ss->irqinterval = iface->ep_desc[i].bInterval; 906291391beSSimon Glass } 907291391beSSimon Glass } 908291391beSSimon Glass debug("Endpoints In %d Out %d Int %d\n", 909291391beSSimon Glass ss->ep_in, ss->ep_out, ss->ep_int); 910291391beSSimon Glass 911291391beSSimon Glass /* Do some basic sanity checks, and bail if we find a problem */ 912291391beSSimon Glass if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || 913291391beSSimon Glass !ss->ep_in || !ss->ep_out || !ss->ep_int) { 914291391beSSimon Glass debug("Problems with device\n"); 915291391beSSimon Glass return 0; 916291391beSSimon Glass } 917291391beSSimon Glass dev->privptr = (void *)ss; 918e1dbdf91SLucas Stach 919e1dbdf91SLucas Stach /* alloc driver private */ 920e1dbdf91SLucas Stach ss->dev_priv = calloc(1, sizeof(struct smsc95xx_private)); 921e1dbdf91SLucas Stach if (!ss->dev_priv) 922e1dbdf91SLucas Stach return 0; 923e1dbdf91SLucas Stach 924291391beSSimon Glass return 1; 925291391beSSimon Glass } 926291391beSSimon Glass 927291391beSSimon Glass int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss, 928291391beSSimon Glass struct eth_device *eth) 929291391beSSimon Glass { 930291391beSSimon Glass debug("** %s()\n", __func__); 931291391beSSimon Glass if (!eth) { 932291391beSSimon Glass debug("%s: missing parameter.\n", __func__); 933291391beSSimon Glass return 0; 934291391beSSimon Glass } 935291391beSSimon Glass sprintf(eth->name, "%s%d", SMSC95XX_BASE_NAME, curr_eth_dev++); 936291391beSSimon Glass eth->init = smsc95xx_init; 937291391beSSimon Glass eth->send = smsc95xx_send; 938291391beSSimon Glass eth->recv = smsc95xx_recv; 939291391beSSimon Glass eth->halt = smsc95xx_halt; 940291391beSSimon Glass eth->write_hwaddr = smsc95xx_write_hwaddr; 941291391beSSimon Glass eth->priv = ss; 942291391beSSimon Glass return 1; 943291391beSSimon Glass } 9440990fcb7SSimon Glass #endif /* !CONFIG_DM_ETH */ 9450990fcb7SSimon Glass 9460990fcb7SSimon Glass #ifdef CONFIG_DM_ETH 9470990fcb7SSimon Glass static int smsc95xx_eth_start(struct udevice *dev) 9480990fcb7SSimon Glass { 9490990fcb7SSimon Glass struct usb_device *udev = dev_get_parentdata(dev); 9500990fcb7SSimon Glass struct smsc95xx_private *priv = dev_get_priv(dev); 9510990fcb7SSimon Glass struct eth_pdata *pdata = dev_get_platdata(dev); 9520990fcb7SSimon Glass 9530990fcb7SSimon Glass /* Driver-model Ethernet ensures we have this */ 9540990fcb7SSimon Glass priv->have_hwaddr = 1; 9550990fcb7SSimon Glass 9560990fcb7SSimon Glass return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr); 9570990fcb7SSimon Glass } 9580990fcb7SSimon Glass 9590990fcb7SSimon Glass void smsc95xx_eth_stop(struct udevice *dev) 9600990fcb7SSimon Glass { 9610990fcb7SSimon Glass debug("** %s()\n", __func__); 9620990fcb7SSimon Glass } 9630990fcb7SSimon Glass 9640990fcb7SSimon Glass int smsc95xx_eth_send(struct udevice *dev, void *packet, int length) 9650990fcb7SSimon Glass { 9660990fcb7SSimon Glass struct smsc95xx_private *priv = dev_get_priv(dev); 9670990fcb7SSimon Glass 9680990fcb7SSimon Glass return smsc95xx_send_common(&priv->ueth, packet, length); 9690990fcb7SSimon Glass } 9700990fcb7SSimon Glass 9710990fcb7SSimon Glass int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp) 9720990fcb7SSimon Glass { 9730990fcb7SSimon Glass struct smsc95xx_private *priv = dev_get_priv(dev); 9740990fcb7SSimon Glass struct ueth_data *ueth = &priv->ueth; 9750990fcb7SSimon Glass uint8_t *ptr; 9760990fcb7SSimon Glass int ret, len; 9770990fcb7SSimon Glass u32 packet_len; 9780990fcb7SSimon Glass 9790990fcb7SSimon Glass len = usb_ether_get_rx_bytes(ueth, &ptr); 9800990fcb7SSimon Glass debug("%s: first try, len=%d\n", __func__, len); 9810990fcb7SSimon Glass if (!len) { 9820990fcb7SSimon Glass if (!(flags & ETH_RECV_CHECK_DEVICE)) 9830990fcb7SSimon Glass return -EAGAIN; 9840990fcb7SSimon Glass ret = usb_ether_receive(ueth, RX_URB_SIZE); 9850990fcb7SSimon Glass if (ret == -EAGAIN) 9860990fcb7SSimon Glass return ret; 9870990fcb7SSimon Glass 9880990fcb7SSimon Glass len = usb_ether_get_rx_bytes(ueth, &ptr); 9890990fcb7SSimon Glass debug("%s: second try, len=%d\n", __func__, len); 9900990fcb7SSimon Glass } 9910990fcb7SSimon Glass 9920990fcb7SSimon Glass /* 9930990fcb7SSimon Glass * 1st 4 bytes contain the length of the actual data plus error info. 9940990fcb7SSimon Glass * Extract data length. 9950990fcb7SSimon Glass */ 9960990fcb7SSimon Glass if (len < sizeof(packet_len)) { 9970990fcb7SSimon Glass debug("Rx: incomplete packet length\n"); 9980990fcb7SSimon Glass goto err; 9990990fcb7SSimon Glass } 10000990fcb7SSimon Glass memcpy(&packet_len, ptr, sizeof(packet_len)); 10010990fcb7SSimon Glass le32_to_cpus(&packet_len); 10020990fcb7SSimon Glass if (packet_len & RX_STS_ES_) { 10030990fcb7SSimon Glass debug("Rx: Error header=%#x", packet_len); 10040990fcb7SSimon Glass goto err; 10050990fcb7SSimon Glass } 10060990fcb7SSimon Glass packet_len = ((packet_len & RX_STS_FL_) >> 16); 10070990fcb7SSimon Glass 10080990fcb7SSimon Glass if (packet_len > len - sizeof(packet_len)) { 10090990fcb7SSimon Glass debug("Rx: too large packet: %d\n", packet_len); 10100990fcb7SSimon Glass goto err; 10110990fcb7SSimon Glass } 10120990fcb7SSimon Glass 10130990fcb7SSimon Glass *packetp = ptr + sizeof(packet_len); 10140990fcb7SSimon Glass return packet_len; 10150990fcb7SSimon Glass 10160990fcb7SSimon Glass err: 10170990fcb7SSimon Glass usb_ether_advance_rxbuf(ueth, -1); 10180990fcb7SSimon Glass return -EINVAL; 10190990fcb7SSimon Glass } 10200990fcb7SSimon Glass 10210990fcb7SSimon Glass static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len) 10220990fcb7SSimon Glass { 10230990fcb7SSimon Glass struct smsc95xx_private *priv = dev_get_priv(dev); 10240990fcb7SSimon Glass 10250990fcb7SSimon Glass packet_len = ALIGN(packet_len, 4); 10260990fcb7SSimon Glass usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len); 10270990fcb7SSimon Glass 10280990fcb7SSimon Glass return 0; 10290990fcb7SSimon Glass } 10300990fcb7SSimon Glass 10310990fcb7SSimon Glass int smsc95xx_write_hwaddr(struct udevice *dev) 10320990fcb7SSimon Glass { 10330990fcb7SSimon Glass struct usb_device *udev = dev_get_parentdata(dev); 10340990fcb7SSimon Glass struct eth_pdata *pdata = dev_get_platdata(dev); 10350990fcb7SSimon Glass struct smsc95xx_private *priv = dev_get_priv(dev); 10360990fcb7SSimon Glass 10370990fcb7SSimon Glass return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr); 10380990fcb7SSimon Glass } 10390990fcb7SSimon Glass 10400990fcb7SSimon Glass static int smsc95xx_eth_probe(struct udevice *dev) 10410990fcb7SSimon Glass { 10420990fcb7SSimon Glass struct smsc95xx_private *priv = dev_get_priv(dev); 10430990fcb7SSimon Glass struct ueth_data *ueth = &priv->ueth; 10440990fcb7SSimon Glass 10450990fcb7SSimon Glass return usb_ether_register(dev, ueth, RX_URB_SIZE); 10460990fcb7SSimon Glass } 10470990fcb7SSimon Glass 10480990fcb7SSimon Glass static const struct eth_ops smsc95xx_eth_ops = { 10490990fcb7SSimon Glass .start = smsc95xx_eth_start, 10500990fcb7SSimon Glass .send = smsc95xx_eth_send, 10510990fcb7SSimon Glass .recv = smsc95xx_eth_recv, 10520990fcb7SSimon Glass .free_pkt = smsc95xx_free_pkt, 10530990fcb7SSimon Glass .stop = smsc95xx_eth_stop, 10540990fcb7SSimon Glass .write_hwaddr = smsc95xx_write_hwaddr, 10550990fcb7SSimon Glass }; 10560990fcb7SSimon Glass 10570990fcb7SSimon Glass U_BOOT_DRIVER(smsc95xx_eth) = { 10580990fcb7SSimon Glass .name = "smsc95xx_eth", 10590990fcb7SSimon Glass .id = UCLASS_ETH, 10600990fcb7SSimon Glass .probe = smsc95xx_eth_probe, 10610990fcb7SSimon Glass .ops = &smsc95xx_eth_ops, 10620990fcb7SSimon Glass .priv_auto_alloc_size = sizeof(struct smsc95xx_private), 10630990fcb7SSimon Glass .platdata_auto_alloc_size = sizeof(struct eth_pdata), 10640990fcb7SSimon Glass }; 10650990fcb7SSimon Glass 10660990fcb7SSimon Glass static const struct usb_device_id smsc95xx_eth_id_table[] = { 10670990fcb7SSimon Glass { USB_DEVICE(0x05ac, 0x1402) }, 10680990fcb7SSimon Glass { USB_DEVICE(0x0424, 0xec00) }, /* LAN9512/LAN9514 Ethernet */ 10690990fcb7SSimon Glass { USB_DEVICE(0x0424, 0x9500) }, /* LAN9500 Ethernet */ 10700990fcb7SSimon Glass { USB_DEVICE(0x0424, 0x9730) }, /* LAN9730 Ethernet (HSIC) */ 10710990fcb7SSimon Glass { USB_DEVICE(0x0424, 0x9900) }, /* SMSC9500 USB Ethernet (SAL10) */ 10720990fcb7SSimon Glass { USB_DEVICE(0x0424, 0x9e00) }, /* LAN9500A Ethernet */ 10730990fcb7SSimon Glass { } /* Terminating entry */ 10740990fcb7SSimon Glass }; 10750990fcb7SSimon Glass 10760990fcb7SSimon Glass U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table); 10770990fcb7SSimon Glass #endif 1078