diff options
author | Tom Rini <trini@konsulko.com> | 2015-08-06 19:56:03 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2015-08-06 19:56:03 -0400 |
commit | ae27120c31d58b8bb694d9155bcffdcfae8552a6 (patch) | |
tree | 8fcd4823406dc3adfb82174314198e9396c24feb /drivers/usb | |
parent | f05fa6781ae1122f348e66b5b26acbfe552f6602 (diff) | |
parent | fac971b2b5efbdb6ed2d12ebdbf7e029c5ed30e8 (diff) | |
download | talos-obmc-uboot-ae27120c31d58b8bb694d9155bcffdcfae8552a6.tar.gz talos-obmc-uboot-ae27120c31d58b8bb694d9155bcffdcfae8552a6.zip |
Merge git://git.denx.de/u-boot-dm
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/eth/smsc95xx.c | 469 | ||||
-rw-r--r-- | drivers/usb/eth/usb_ether.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/dwc2.c | 255 |
3 files changed, 524 insertions, 201 deletions
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index a7e50d6a6c..1dcd088b8d 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2015 Google, Inc * Copyright (c) 2011 The Chromium OS Authors. * Copyright (C) 2009 NVIDIA, Corporation * Copyright (C) 2007-2008 SMSC (Steve Glendinning) @@ -6,12 +7,14 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include <asm/unaligned.h> #include <common.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> #include <usb.h> +#include <asm/unaligned.h> #include <linux/mii.h> #include "usb_ether.h" -#include <malloc.h> /* SMSC LAN95xx based USB 2.0 Ethernet Devices */ @@ -131,16 +134,21 @@ #define USB_BULK_SEND_TIMEOUT 5000 #define USB_BULK_RECV_TIMEOUT 5000 -#define AX_RX_URB_SIZE 2048 +#define RX_URB_SIZE 2048 #define PHY_CONNECT_TIMEOUT 5000 #define TURBO_MODE +#ifndef CONFIG_DM_ETH /* local vars */ static int curr_eth_dev; /* index for name of next device detected */ +#endif /* driver private */ struct smsc95xx_private { +#ifdef CONFIG_DM_ETH + struct ueth_data ueth; +#endif size_t rx_urb_size; /* maximum USB URB size */ u32 mac_cr; /* MAC control register value */ int have_hwaddr; /* 1 if we have a hardware MAC address */ @@ -149,7 +157,7 @@ struct smsc95xx_private { /* * Smsc95xx infrastructure commands */ -static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) +static int smsc95xx_write_reg(struct usb_device *udev, u32 index, u32 data) { int len; ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); @@ -157,32 +165,34 @@ static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) cpu_to_le32s(&data); tmpbuf[0] = data; - len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0), - USB_VENDOR_REQUEST_WRITE_REGISTER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, tmpbuf, sizeof(data), USB_CTRL_SET_TIMEOUT); + len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_VENDOR_REQUEST_WRITE_REGISTER, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, tmpbuf, sizeof(data), + USB_CTRL_SET_TIMEOUT); if (len != sizeof(data)) { debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d", index, data, len); - return -1; + return -EIO; } return 0; } -static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data) +static int smsc95xx_read_reg(struct usb_device *udev, u32 index, u32 *data) { int len; ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); - len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0), - USB_VENDOR_REQUEST_READ_REGISTER, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, tmpbuf, sizeof(data), USB_CTRL_GET_TIMEOUT); + len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_VENDOR_REQUEST_READ_REGISTER, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, tmpbuf, sizeof(data), + USB_CTRL_GET_TIMEOUT); *data = tmpbuf[0]; if (len != sizeof(data)) { debug("smsc95xx_read_reg failed: index=%d, len=%d", index, len); - return -1; + return -EIO; } le32_to_cpus(data); @@ -190,89 +200,89 @@ static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data) } /* Loop until the read is completed with timeout */ -static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev) +static int smsc95xx_phy_wait_not_busy(struct usb_device *udev) { unsigned long start_time = get_timer(0); u32 val; do { - smsc95xx_read_reg(dev, MII_ADDR, &val); + smsc95xx_read_reg(udev, MII_ADDR, &val); if (!(val & MII_BUSY_)) return 0; - } while (get_timer(start_time) < 1 * 1000 * 1000); + } while (get_timer(start_time) < 1000); - return -1; + return -ETIMEDOUT; } -static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx) +static int smsc95xx_mdio_read(struct usb_device *udev, int phy_id, int idx) { u32 val, addr; /* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { + if (smsc95xx_phy_wait_not_busy(udev)) { debug("MII is busy in smsc95xx_mdio_read\n"); - return -1; + return -ETIMEDOUT; } /* set the address, index & direction (read from PHY) */ addr = (phy_id << 11) | (idx << 6) | MII_READ_; - smsc95xx_write_reg(dev, MII_ADDR, addr); + smsc95xx_write_reg(udev, MII_ADDR, addr); - if (smsc95xx_phy_wait_not_busy(dev)) { + if (smsc95xx_phy_wait_not_busy(udev)) { debug("Timed out reading MII reg %02X\n", idx); - return -1; + return -ETIMEDOUT; } - smsc95xx_read_reg(dev, MII_DATA, &val); + smsc95xx_read_reg(udev, MII_DATA, &val); return (u16)(val & 0xFFFF); } -static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx, +static void smsc95xx_mdio_write(struct usb_device *udev, int phy_id, int idx, int regval) { u32 val, addr; /* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { + if (smsc95xx_phy_wait_not_busy(udev)) { debug("MII is busy in smsc95xx_mdio_write\n"); return; } val = regval; - smsc95xx_write_reg(dev, MII_DATA, val); + smsc95xx_write_reg(udev, MII_DATA, val); /* set the address, index & direction (write to PHY) */ addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; - smsc95xx_write_reg(dev, MII_ADDR, addr); + smsc95xx_write_reg(udev, MII_ADDR, addr); - if (smsc95xx_phy_wait_not_busy(dev)) + if (smsc95xx_phy_wait_not_busy(udev)) debug("Timed out writing MII reg %02X\n", idx); } -static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) +static int smsc95xx_eeprom_confirm_not_busy(struct usb_device *udev) { unsigned long start_time = get_timer(0); u32 val; do { - smsc95xx_read_reg(dev, E2P_CMD, &val); + smsc95xx_read_reg(udev, E2P_CMD, &val); if (!(val & E2P_CMD_BUSY_)) return 0; udelay(40); } while (get_timer(start_time) < 1 * 1000 * 1000); debug("EEPROM is busy\n"); - return -1; + return -ETIMEDOUT; } -static int smsc95xx_wait_eeprom(struct ueth_data *dev) +static int smsc95xx_wait_eeprom(struct usb_device *udev) { unsigned long start_time = get_timer(0); u32 val; do { - smsc95xx_read_reg(dev, E2P_CMD, &val); + smsc95xx_read_reg(udev, E2P_CMD, &val); if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) break; udelay(40); @@ -280,30 +290,30 @@ static int smsc95xx_wait_eeprom(struct ueth_data *dev) if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { debug("EEPROM read operation timeout\n"); - return -1; + return -ETIMEDOUT; } return 0; } -static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length, +static int smsc95xx_read_eeprom(struct usb_device *udev, u32 offset, u32 length, u8 *data) { u32 val; int i, ret; - ret = smsc95xx_eeprom_confirm_not_busy(dev); + ret = smsc95xx_eeprom_confirm_not_busy(udev); if (ret) return ret; for (i = 0; i < length; i++) { val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); - smsc95xx_write_reg(dev, E2P_CMD, val); + smsc95xx_write_reg(udev, E2P_CMD, val); - ret = smsc95xx_wait_eeprom(dev); + ret = smsc95xx_wait_eeprom(udev); if (ret < 0) return ret; - smsc95xx_read_reg(dev, E2P_DATA, &val); + smsc95xx_read_reg(udev, E2P_DATA, &val); data[i] = val & 0xFF; offset++; } @@ -315,89 +325,96 @@ static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length, * * Returns 0 on success, negative on error. */ -static int mii_nway_restart(struct ueth_data *dev) +static int mii_nway_restart(struct usb_device *udev, struct ueth_data *dev) { int bmcr; int r = -1; /* if autoneg is off, it's an error */ - bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR); + bmcr = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMCR); if (bmcr & BMCR_ANENABLE) { bmcr |= BMCR_ANRESTART; - smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr); + smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, bmcr); r = 0; } return r; } -static int smsc95xx_phy_initialize(struct ueth_data *dev) +static int smsc95xx_phy_initialize(struct usb_device *udev, + struct ueth_data *dev) { - smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET); - smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); + smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, BMCR_RESET); + smsc95xx_mdio_write(udev, dev->phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); /* read to clear */ - smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC); + smsc95xx_mdio_read(udev, dev->phy_id, PHY_INT_SRC); - smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK, - PHY_INT_MASK_DEFAULT_); - mii_nway_restart(dev); + smsc95xx_mdio_write(udev, dev->phy_id, PHY_INT_MASK, + PHY_INT_MASK_DEFAULT_); + mii_nway_restart(udev, dev); debug("phy initialised succesfully\n"); return 0; } -static int smsc95xx_init_mac_address(struct eth_device *eth, - struct ueth_data *dev) +static int smsc95xx_init_mac_address(unsigned char *enetaddr, + struct usb_device *udev) { + int ret; + /* try reading mac address from EEPROM */ - if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, - eth->enetaddr) == 0) { - if (is_valid_ethaddr(eth->enetaddr)) { - /* eeprom values are valid so use them */ - debug("MAC address read from EEPROM\n"); - return 0; - } + ret = smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN, enetaddr); + if (ret) + return ret; + + if (is_valid_ethaddr(enetaddr)) { + /* eeprom values are valid so use them */ + debug("MAC address read from EEPROM\n"); + return 0; } /* * No eeprom, or eeprom values are invalid. Generating a random MAC * address is not safe. Just return an error. */ - return -1; + debug("Invalid MAC address read from EEPROM\n"); + + return -ENXIO; } -static int smsc95xx_write_hwaddr(struct eth_device *eth) +static int smsc95xx_write_hwaddr_common(struct usb_device *udev, + struct smsc95xx_private *priv, + unsigned char *enetaddr) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct smsc95xx_private *priv = dev->dev_priv; - u32 addr_lo = __get_unaligned_le32(ð->enetaddr[0]); - u32 addr_hi = __get_unaligned_le16(ð->enetaddr[4]); + u32 addr_lo = __get_unaligned_le32(&enetaddr[0]); + u32 addr_hi = __get_unaligned_le16(&enetaddr[4]); int ret; /* set hardware address */ debug("** %s()\n", __func__); - ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); + ret = smsc95xx_write_reg(udev, ADDRL, addr_lo); if (ret < 0) return ret; - ret = smsc95xx_write_reg(dev, ADDRH, addr_hi); + ret = smsc95xx_write_reg(udev, ADDRH, addr_hi); if (ret < 0) return ret; - debug("MAC %pM\n", eth->enetaddr); + debug("MAC %pM\n", enetaddr); priv->have_hwaddr = 1; + return 0; } /* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct ueth_data *dev, - int use_tx_csum, int use_rx_csum) +static int smsc95xx_set_csums(struct usb_device *udev, int use_tx_csum, + int use_rx_csum) { u32 read_buf; - int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); + int ret = smsc95xx_read_reg(udev, COE_CR, &read_buf); if (ret < 0) return ret; @@ -411,7 +428,7 @@ static int smsc95xx_set_csums(struct ueth_data *dev, else read_buf &= ~Rx_COE_EN_; - ret = smsc95xx_write_reg(dev, COE_CR, read_buf); + ret = smsc95xx_write_reg(udev, COE_CR, read_buf); if (ret < 0) return ret; @@ -419,52 +436,45 @@ static int smsc95xx_set_csums(struct ueth_data *dev, return 0; } -static void smsc95xx_set_multicast(struct ueth_data *dev) +static void smsc95xx_set_multicast(struct smsc95xx_private *priv) { - struct smsc95xx_private *priv = dev->dev_priv; - /* No multicast in u-boot */ priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); } /* starts the TX path */ -static void smsc95xx_start_tx_path(struct ueth_data *dev) +static void smsc95xx_start_tx_path(struct usb_device *udev, + struct smsc95xx_private *priv) { - struct smsc95xx_private *priv = dev->dev_priv; u32 reg_val; /* Enable Tx at MAC */ priv->mac_cr |= MAC_CR_TXEN_; - smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); + smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr); /* Enable Tx at SCSRs */ reg_val = TX_CFG_ON_; - smsc95xx_write_reg(dev, TX_CFG, reg_val); + smsc95xx_write_reg(udev, TX_CFG, reg_val); } /* Starts the Receive path */ -static void smsc95xx_start_rx_path(struct ueth_data *dev) +static void smsc95xx_start_rx_path(struct usb_device *udev, + struct smsc95xx_private *priv) { - struct smsc95xx_private *priv = dev->dev_priv; - priv->mac_cr |= MAC_CR_RXEN_; - smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); + smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr); } -/* - * Smsc95xx callbacks - */ -static int smsc95xx_init(struct eth_device *eth, bd_t *bd) +static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev, + struct smsc95xx_private *priv, + unsigned char *enetaddr) { int ret; u32 write_buf; u32 read_buf; u32 burst_cap; int timeout; - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct smsc95xx_private *priv = - (struct smsc95xx_private *)dev->dev_priv; #define TIMEOUT_RESOLUTION 50 /* ms */ int link_detected; @@ -472,13 +482,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */ write_buf = HW_CFG_LRST_; - ret = smsc95xx_write_reg(dev, HW_CFG, write_buf); + ret = smsc95xx_write_reg(udev, HW_CFG, write_buf); if (ret < 0) return ret; timeout = 0; do { - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; udelay(10 * 1000); @@ -487,17 +497,17 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) if (timeout >= 100) { debug("timeout waiting for completion of Lite Reset\n"); - return -1; + return -ETIMEDOUT; } write_buf = PM_CTL_PHY_RST_; - ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf); + ret = smsc95xx_write_reg(udev, PM_CTRL, write_buf); if (ret < 0) return ret; timeout = 0; do { - ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf); + ret = smsc95xx_read_reg(udev, PM_CTRL, &read_buf); if (ret < 0) return ret; udelay(10 * 1000); @@ -505,28 +515,30 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); if (timeout >= 100) { debug("timeout waiting for PHY Reset\n"); - return -1; + return -ETIMEDOUT; } - if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0) + if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) == + 0) priv->have_hwaddr = 1; if (!priv->have_hwaddr) { puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n"); - return -1; + return -EADDRNOTAVAIL; } - if (smsc95xx_write_hwaddr(eth) < 0) - return -1; + ret = smsc95xx_write_hwaddr_common(udev, priv, enetaddr); + if (ret < 0) + return ret; - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG : 0x%08x\n", read_buf); read_buf |= HW_CFG_BIR_; - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); + ret = smsc95xx_write_reg(udev, HW_CFG, read_buf); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG after writing " @@ -546,27 +558,27 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) #endif debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size); - ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); + ret = smsc95xx_write_reg(udev, BURST_CAP, burst_cap); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf); + ret = smsc95xx_read_reg(udev, BURST_CAP, &read_buf); if (ret < 0) return ret; debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf); read_buf = DEFAULT_BULK_IN_DELAY; - ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf); + ret = smsc95xx_write_reg(udev, BULK_IN_DLY, read_buf); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf); + ret = smsc95xx_read_reg(udev, BULK_IN_DLY, &read_buf); if (ret < 0) return ret; debug("Read Value from BULK_IN_DLY after writing: " "0x%08x\n", read_buf); - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG: 0x%08x\n", read_buf); @@ -579,21 +591,21 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) #define NET_IP_ALIGN 0 read_buf |= NET_IP_ALIGN << 9; - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); + ret = smsc95xx_write_reg(udev, HW_CFG, read_buf); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf); write_buf = 0xFFFFFFFF; - ret = smsc95xx_write_reg(dev, INT_STS, write_buf); + ret = smsc95xx_write_reg(udev, INT_STS, write_buf); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, ID_REV, &read_buf); + ret = smsc95xx_read_reg(udev, ID_REV, &read_buf); if (ret < 0) return ret; debug("ID_REV = 0x%08x\n", read_buf); @@ -601,59 +613,60 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) /* Configure GPIO pins as LED outputs */ write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | LED_GPIO_CFG_FDX_LED; - ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf); + ret = smsc95xx_write_reg(udev, LED_GPIO_CFG, write_buf); if (ret < 0) return ret; debug("LED_GPIO_CFG set\n"); /* Init Tx */ write_buf = 0; - ret = smsc95xx_write_reg(dev, FLOW, write_buf); + ret = smsc95xx_write_reg(udev, FLOW, write_buf); if (ret < 0) return ret; read_buf = AFC_CFG_DEFAULT; - ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf); + ret = smsc95xx_write_reg(udev, AFC_CFG, read_buf); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr); + ret = smsc95xx_read_reg(udev, MAC_CR, &priv->mac_cr); if (ret < 0) return ret; /* Init Rx. Set Vlan */ write_buf = (u32)ETH_P_8021Q; - ret = smsc95xx_write_reg(dev, VLAN1, write_buf); + ret = smsc95xx_write_reg(udev, VLAN1, write_buf); if (ret < 0) return ret; /* Disable checksum offload engines */ - ret = smsc95xx_set_csums(dev, 0, 0); + ret = smsc95xx_set_csums(udev, 0, 0); if (ret < 0) { debug("Failed to set csum offload: %d\n", ret); return ret; } - smsc95xx_set_multicast(dev); + smsc95xx_set_multicast(priv); - if (smsc95xx_phy_initialize(dev) < 0) - return -1; - ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); + ret = smsc95xx_phy_initialize(udev, dev); + if (ret < 0) + return ret; + ret = smsc95xx_read_reg(udev, INT_EP_CTL, &read_buf); if (ret < 0) return ret; /* enable PHY interrupts */ read_buf |= INT_EP_CTL_PHY_INT_; - ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf); + ret = smsc95xx_write_reg(udev, INT_EP_CTL, read_buf); if (ret < 0) return ret; - smsc95xx_start_tx_path(dev); - smsc95xx_start_rx_path(dev); + smsc95xx_start_tx_path(udev, priv); + smsc95xx_start_rx_path(udev, priv); timeout = 0; do { - link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR) + link_detected = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMSR) & BMSR_LSTATUS; if (!link_detected) { if (timeout == 0) @@ -667,14 +680,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) printf("done.\n"); } else { printf("unable to connect.\n"); - return -1; + return -EIO; } return 0; } -static int smsc95xx_send(struct eth_device *eth, void* packet, int length) +static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; int err; int actual_len; u32 tx_cmd_a; @@ -684,7 +696,7 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length) debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg); if (length > PKTSIZE) - return -1; + return -ENOSPC; tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; tx_cmd_b = (u32)length; @@ -705,13 +717,35 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length) debug("Tx: len = %u, actual = %u, err = %d\n", length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), actual_len, err); + return err; } +#ifndef CONFIG_DM_ETH +/* + * Smsc95xx callbacks + */ +static int smsc95xx_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct usb_device *udev = dev->pusb_dev; + struct smsc95xx_private *priv = + (struct smsc95xx_private *)dev->dev_priv; + + return smsc95xx_init_common(udev, dev, priv, eth->enetaddr); +} + +static int smsc95xx_send(struct eth_device *eth, void *packet, int length) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + return smsc95xx_send_common(dev, packet, length); +} + static int smsc95xx_recv(struct eth_device *eth) { struct ueth_data *dev = (struct ueth_data *)eth->priv; - DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE); + DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, RX_URB_SIZE); unsigned char *buf_ptr; int err; int actual_len; @@ -720,20 +754,18 @@ static int smsc95xx_recv(struct eth_device *eth) debug("** %s()\n", __func__); err = usb_bulk_msg(dev->pusb_dev, - usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), - (void *)recv_buf, - AX_RX_URB_SIZE, - &actual_len, - USB_BULK_RECV_TIMEOUT); - debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE, + usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), + (void *)recv_buf, RX_URB_SIZE, &actual_len, + USB_BULK_RECV_TIMEOUT); + debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE, actual_len, err); if (err != 0) { debug("Rx: failed to receive\n"); - return -1; + return -err; } - if (actual_len > AX_RX_URB_SIZE) { + if (actual_len > RX_URB_SIZE) { debug("Rx: received too many bytes %d\n", actual_len); - return -1; + return -ENOSPC; } buf_ptr = recv_buf; @@ -744,19 +776,19 @@ static int smsc95xx_recv(struct eth_device *eth) */ if (actual_len < sizeof(packet_len)) { debug("Rx: incomplete packet length\n"); - return -1; + return -EIO; } memcpy(&packet_len, buf_ptr, sizeof(packet_len)); le32_to_cpus(&packet_len); if (packet_len & RX_STS_ES_) { debug("Rx: Error header=%#x", packet_len); - return -1; + return -EIO; } packet_len = ((packet_len & RX_STS_FL_) >> 16); if (packet_len > actual_len - sizeof(packet_len)) { debug("Rx: too large packet: %d\n", packet_len); - return -1; + return -EIO; } /* Notify net stack */ @@ -783,6 +815,15 @@ static void smsc95xx_halt(struct eth_device *eth) debug("** %s()\n", __func__); } +static int smsc95xx_write_hwaddr(struct eth_device *eth) +{ + struct ueth_data *dev = eth->priv; + struct usb_device *udev = dev->pusb_dev; + struct smsc95xx_private *priv = dev->dev_priv; + + return smsc95xx_write_hwaddr_common(udev, priv, eth->enetaddr); +} + /* * SMSC probing functions */ @@ -898,3 +939,137 @@ int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss, eth->priv = ss; return 1; } +#endif /* !CONFIG_DM_ETH */ + +#ifdef CONFIG_DM_ETH +static int smsc95xx_eth_start(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parentdata(dev); + struct smsc95xx_private *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + /* Driver-model Ethernet ensures we have this */ + priv->have_hwaddr = 1; + + return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr); +} + +void smsc95xx_eth_stop(struct udevice *dev) +{ + debug("** %s()\n", __func__); +} + +int smsc95xx_eth_send(struct udevice *dev, void *packet, int length) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + + return smsc95xx_send_common(&priv->ueth, packet, length); +} + +int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + uint8_t *ptr; + int ret, len; + u32 packet_len; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: first try, len=%d\n", __func__, len); + if (!len) { + if (!(flags & ETH_RECV_CHECK_DEVICE)) + return -EAGAIN; + ret = usb_ether_receive(ueth, RX_URB_SIZE); + if (ret == -EAGAIN) + return ret; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: second try, len=%d\n", __func__, len); + } + + /* + * 1st 4 bytes contain the length of the actual data plus error info. + * Extract data length. + */ + if (len < sizeof(packet_len)) { + debug("Rx: incomplete packet length\n"); + goto err; + } + memcpy(&packet_len, ptr, sizeof(packet_len)); + le32_to_cpus(&packet_len); + if (packet_len & RX_STS_ES_) { + debug("Rx: Error header=%#x", packet_len); + goto err; + } + packet_len = ((packet_len & RX_STS_FL_) >> 16); + + if (packet_len > len - sizeof(packet_len)) { + debug("Rx: too large packet: %d\n", packet_len); + goto err; + } + + *packetp = ptr + sizeof(packet_len); + return packet_len; + +err: + usb_ether_advance_rxbuf(ueth, -1); + return -EINVAL; +} + +static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + + packet_len = ALIGN(packet_len, 4); + usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len); + + return 0; +} + +int smsc95xx_write_hwaddr(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parentdata(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct smsc95xx_private *priv = dev_get_priv(dev); + + return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr); +} + +static int smsc95xx_eth_probe(struct udevice *dev) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + + return usb_ether_register(dev, ueth, RX_URB_SIZE); +} + +static const struct eth_ops smsc95xx_eth_ops = { + .start = smsc95xx_eth_start, + .send = smsc95xx_eth_send, + .recv = smsc95xx_eth_recv, + .free_pkt = smsc95xx_free_pkt, + .stop = smsc95xx_eth_stop, + .write_hwaddr = smsc95xx_write_hwaddr, +}; + +U_BOOT_DRIVER(smsc95xx_eth) = { + .name = "smsc95xx_eth", + .id = UCLASS_ETH, + .probe = smsc95xx_eth_probe, + .ops = &smsc95xx_eth_ops, + .priv_auto_alloc_size = sizeof(struct smsc95xx_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +static const struct usb_device_id smsc95xx_eth_id_table[] = { + { USB_DEVICE(0x05ac, 0x1402) }, + { USB_DEVICE(0x0424, 0xec00) }, /* LAN9512/LAN9514 Ethernet */ + { USB_DEVICE(0x0424, 0x9500) }, /* LAN9500 Ethernet */ + { USB_DEVICE(0x0424, 0x9730) }, /* LAN9730 Ethernet (HSIC) */ + { USB_DEVICE(0x0424, 0x9900) }, /* SMSC9500 USB Ethernet (SAL10) */ + { USB_DEVICE(0x0424, 0x9e00) }, /* LAN9500A Ethernet */ + { } /* Terminating entry */ +}; + +U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table); +#endif diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 63785a9c59..3c3e082b27 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -6,6 +6,7 @@ #include <common.h> #include <dm.h> +#include <errno.h> #include <malloc.h> #include <usb.h> #include <dm/device-internal.h> diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index ad35841769..702ef63f87 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -6,6 +6,7 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <usb.h> #include <malloc.h> @@ -21,18 +22,29 @@ #define DWC2_STATUS_BUF_SIZE 64 #define DWC2_DATA_BUF_SIZE (64 * 1024) -/* We need doubleword-aligned buffers for DMA transfers */ -DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8); -DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8); - #define MAX_DEVICE 16 #define MAX_ENDPOINT 16 -static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; -static int root_hub_devnum; +struct dwc2_priv { +#ifdef CONFIG_DM_USB + uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(8); + uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(8); +#else + uint8_t *aligned_buffer; + uint8_t *status_buffer; +#endif + int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; + struct dwc2_core_regs *regs; + int root_hub_devnum; +}; + +#ifndef CONFIG_DM_USB +/* We need doubleword-aligned buffers for DMA transfers */ +DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, 8); +DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE, 8); -static struct dwc2_core_regs *regs = - (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR; +static struct dwc2_priv local; +#endif /* * DWC2 IP interface @@ -428,7 +440,8 @@ static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num, * DWC2 to USB API interface */ /* Direction: In ; Request: Status */ -static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer, +static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs, + struct usb_device *dev, void *buffer, int txlen, struct devrequest *cmd) { uint32_t hprt0 = 0; @@ -602,13 +615,13 @@ static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev, } /* Direction: In */ -static int dwc_otg_submit_rh_msg_in(struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv, + struct usb_device *dev, void *buffer, + int txlen, struct devrequest *cmd) { switch (cmd->request) { case USB_REQ_GET_STATUS: - return dwc_otg_submit_rh_msg_in_status(dev, buffer, + return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer, txlen, cmd); case USB_REQ_GET_DESCRIPTOR: return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer, @@ -623,10 +636,12 @@ static int dwc_otg_submit_rh_msg_in(struct usb_device *dev, } /* Direction: Out */ -static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv, + struct usb_device *dev, + void *buffer, int txlen, + struct devrequest *cmd) { + struct dwc2_core_regs *regs = priv->regs; int len = 0; int stat = 0; uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8); @@ -673,7 +688,7 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, } break; case (USB_REQ_SET_ADDRESS << 8): - root_hub_devnum = wValue; + priv->root_hub_devnum = wValue; break; case (USB_REQ_SET_CONFIGURATION << 8): break; @@ -690,8 +705,8 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, return stat; } -static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int txlen, +static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int txlen, struct devrequest *cmd) { int stat = 0; @@ -702,16 +717,17 @@ static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe, } if (cmd->requesttype & USB_DIR_IN) - stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd); + stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd); else - stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd); + stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd); mdelay(1); return stat; } -int wait_for_chhltd(uint32_t *sub, int *toggle, bool ignore_ack) +int wait_for_chhltd(struct dwc2_core_regs *regs, uint32_t *sub, int *toggle, + bool ignore_ack) { uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP | DWC2_HCINT_CHHLTD; struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; @@ -751,9 +767,11 @@ static int dwc2_eptype[] = { DWC2_HCCHAR_EPTYPE_BULK, }; -int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, - void *buffer, int len, bool ignore_ack) +int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, int *pid, int in, void *buffer, int len, + bool ignore_ack) { + struct dwc2_core_regs *regs = priv->regs; struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe); @@ -802,10 +820,12 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, (*pid << DWC2_HCTSIZ_PID_OFFSET), &hc_regs->hctsiz); - if (!in) - memcpy(aligned_buffer, (char *)buffer + done, len); + if (!in) { + memcpy(priv->aligned_buffer, (char *)buffer + done, + len); + } - writel(phys_to_bus((unsigned long)aligned_buffer), + writel(phys_to_bus((unsigned long)priv->aligned_buffer), &hc_regs->hcdma); /* Set host channel enable after all other setup is complete. */ @@ -814,13 +834,13 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN); - ret = wait_for_chhltd(&sub, pid, ignore_ack); + ret = wait_for_chhltd(regs, &sub, pid, ignore_ack); if (ret) break; if (in) { xfer_len -= sub; - memcpy(buffer + done, aligned_buffer, xfer_len); + memcpy(buffer + done, priv->aligned_buffer, xfer_len); if (sub) stop_transfer = 1; } @@ -839,43 +859,45 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, } /* U-Boot USB transmission interface */ -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len) +int _submit_bulk_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int len) { int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe); - if (devnum == root_hub_devnum) { + if (devnum == priv->root_hub_devnum) { dev->status = 0; return -EINVAL; } - return chunk_msg(dev, pipe, &bulk_data_toggle[devnum][ep], + return chunk_msg(priv, dev, pipe, &priv->bulk_data_toggle[devnum][ep], usb_pipein(pipe), buffer, len, true); } -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, struct devrequest *setup) +static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int len, + struct devrequest *setup) { int devnum = usb_pipedevice(pipe); int pid, ret, act_len; /* For CONTROL endpoint pid should start with DATA1 */ int status_direction; - if (devnum == root_hub_devnum) { + if (devnum == priv->root_hub_devnum) { dev->status = 0; dev->speed = USB_SPEED_HIGH; - return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup); + return dwc_otg_submit_rh_msg(priv, dev, pipe, buffer, len, + setup); } pid = DWC2_HC_PID_SETUP; - ret = chunk_msg(dev, pipe, &pid, 0, setup, 8, true); + ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8, true); if (ret) return ret; if (buffer) { pid = DWC2_HC_PID_DATA1; - ret = chunk_msg(dev, pipe, &pid, usb_pipein(pipe), buffer, + ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe), buffer, len, false); if (ret) return ret; @@ -891,8 +913,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, status_direction = 0; pid = DWC2_HC_PID_DATA1; - ret = chunk_msg(dev, pipe, &pid, status_direction, status_buffer, 0, - false); + ret = chunk_msg(priv, dev, pipe, &pid, status_direction, + priv->status_buffer, 0, false); if (ret) return ret; @@ -901,8 +923,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return 0; } -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, int interval) +int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int len, int interval) { unsigned long timeout; int ret; @@ -915,24 +937,18 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, printf("Timeout poll on interrupt endpoint\n"); return -ETIMEDOUT; } - ret = submit_bulk_msg(dev, pipe, buffer, len); + ret = _submit_bulk_msg(priv, dev, pipe, buffer, len); if (ret != -EAGAIN) return ret; } } -/* U-Boot USB control interface */ -int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +static int dwc2_init_common(struct dwc2_priv *priv) { + struct dwc2_core_regs *regs = priv->regs; uint32_t snpsid; int i, j; - root_hub_devnum = 0; - - /* board dependant init */ - if (board_usb_init(index, USB_INIT_HOST)) - return -1; - snpsid = readl(®s->gsnpsid); printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff); @@ -956,18 +972,149 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) for (i = 0; i < MAX_DEVICE; i++) { for (j = 0; j < MAX_ENDPOINT; j++) - bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0; + priv->bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0; } return 0; } -int usb_lowlevel_stop(int index) +static void dwc2_uninit_common(struct dwc2_core_regs *regs) { /* Put everything in reset. */ clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG, DWC2_HPRT0_PRTRST); +} + +#ifndef CONFIG_DM_USB +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, struct devrequest *setup) +{ + return _submit_control_msg(&local, dev, pipe, buffer, len, setup); +} + +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len) +{ + return _submit_bulk_msg(&local, dev, pipe, buffer, len); +} + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, int interval) +{ + return _submit_int_msg(&local, dev, pipe, buffer, len, interval); +} + +/* U-Boot USB control interface */ +int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +{ + struct dwc2_priv *priv = &local; + + memset(priv, '\0', sizeof(*priv)); + priv->root_hub_devnum = 0; + priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR; + priv->aligned_buffer = aligned_buffer_addr; + priv->status_buffer = status_buffer_addr; + + /* board-dependant init */ + if (board_usb_init(index, USB_INIT_HOST)) + return -1; + + return dwc2_init_common(priv); +} + +int usb_lowlevel_stop(int index) +{ + dwc2_uninit_common(local.regs); + return 0; } +#endif + +#ifdef CONFIG_DM_USB +static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + struct devrequest *setup) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__, + dev->name, udev, udev->dev->name, udev->portnr); + + return _submit_control_msg(priv, udev, pipe, buffer, length, setup); +} + +static int dwc2_submit_bulk_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + + return _submit_bulk_msg(priv, udev, pipe, buffer, length); +} + +static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + int interval) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + + return _submit_int_msg(priv, udev, pipe, buffer, length, interval); +} + +static int dwc2_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + priv->regs = (struct dwc2_core_regs *)addr; + + return 0; +} + +static int dwc2_usb_probe(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + return dwc2_init_common(priv); +} + +static int dwc2_usb_remove(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + dwc2_uninit_common(priv->regs); + + return 0; +} + +struct dm_usb_ops dwc2_usb_ops = { + .control = dwc2_submit_control_msg, + .bulk = dwc2_submit_bulk_msg, + .interrupt = dwc2_submit_int_msg, +}; + +static const struct udevice_id dwc2_usb_ids[] = { + { .compatible = "brcm,bcm2835-usb" }, + { } +}; + +U_BOOT_DRIVER(usb_dwc2) = { + .name = "dwc2_exynos", + .id = UCLASS_USB, + .of_match = dwc2_usb_ids, + .ofdata_to_platdata = dwc2_usb_ofdata_to_platdata, + .probe = dwc2_usb_probe, + .remove = dwc2_usb_remove, + .ops = &dwc2_usb_ops, + .priv_auto_alloc_size = sizeof(struct dwc2_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif |