mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
dm: usb: eth: Add driver-model support to the asix driver
This USB Ethernet driver is quite widely use. Allow it to work with CONFIG_DM_ETH enabled. Most of the code remains common but there is a new packet receive flow which is handled specially. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
2b53b078d7
commit
fbc4b8af46
1 changed files with 216 additions and 21 deletions
|
@ -5,11 +5,11 @@
|
|||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <usb.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/mii.h>
|
||||
#include "usb_ether.h"
|
||||
#include <malloc.h>
|
||||
|
||||
|
||||
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
|
||||
|
||||
|
@ -92,14 +92,20 @@
|
|||
#define FLAG_TYPE_AX88772B (1U << 2)
|
||||
#define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */
|
||||
|
||||
/* local vars */
|
||||
static int curr_eth_dev; /* index for name of next device detected */
|
||||
|
||||
/* driver private */
|
||||
struct asix_private {
|
||||
int flags;
|
||||
#ifdef CONFIG_DM_ETH
|
||||
struct ueth_data ueth;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
/* local vars */
|
||||
static int curr_eth_dev; /* index for name of next device detected */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Asix infrastructure commands
|
||||
*/
|
||||
|
@ -284,13 +290,12 @@ static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int asix_write_hwaddr(struct eth_device *eth)
|
||||
static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
int ret;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
|
||||
|
||||
memcpy(buf, eth->enetaddr, ETH_ALEN);
|
||||
memcpy(buf, enetaddr, ETH_ALEN);
|
||||
|
||||
ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
|
||||
if (ret < 0)
|
||||
|
@ -325,12 +330,11 @@ static int mii_nway_restart(struct ueth_data *dev)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int asix_read_mac(struct eth_device *eth)
|
||||
static int asix_read_mac_common(struct ueth_data *dev,
|
||||
struct asix_private *priv, uint8_t *enetaddr)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
struct asix_private *priv = (struct asix_private *)dev->dev_priv;
|
||||
int i;
|
||||
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
|
||||
int i;
|
||||
|
||||
if (priv->flags & FLAG_EEPROM_MAC) {
|
||||
for (i = 0; i < (ETH_ALEN >> 1); i++) {
|
||||
|
@ -339,7 +343,7 @@ static int asix_read_mac(struct eth_device *eth)
|
|||
debug("Failed to read SROM address 04h.\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy((eth->enetaddr + i * 2), buf, 2);
|
||||
memcpy(enetaddr + i * 2, buf, 2);
|
||||
}
|
||||
} else {
|
||||
if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
|
||||
|
@ -347,7 +351,7 @@ static int asix_read_mac(struct eth_device *eth)
|
|||
debug("Failed to read MAC address.\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(eth->enetaddr, buf, ETH_ALEN);
|
||||
memcpy(enetaddr, buf, ETH_ALEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -414,12 +418,8 @@ static int asix_basic_reset(struct ueth_data *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Asix callbacks
|
||||
*/
|
||||
static int asix_init(struct eth_device *eth, bd_t *bd)
|
||||
static int asix_init_common(struct ueth_data *dev)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
int timeout = 0;
|
||||
#define TIMEOUT_RESOLUTION 50 /* ms */
|
||||
int link_detected;
|
||||
|
@ -452,9 +452,8 @@ out_err:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int asix_send(struct eth_device *eth, void *packet, int length)
|
||||
static int asix_send_common(struct ueth_data *dev, void *packet, int length)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
int err;
|
||||
u32 packet_len;
|
||||
int actual_len;
|
||||
|
@ -481,6 +480,24 @@ static int asix_send(struct eth_device *eth, void *packet, int length)
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
/*
|
||||
* Asix callbacks
|
||||
*/
|
||||
static int asix_init(struct eth_device *eth, bd_t *bd)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
|
||||
return asix_init_common(dev);
|
||||
}
|
||||
|
||||
static int asix_send(struct eth_device *eth, void *packet, int length)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
|
||||
return asix_send_common(dev, packet, length);
|
||||
}
|
||||
|
||||
static int asix_recv(struct eth_device *eth)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
|
@ -552,6 +569,13 @@ static void asix_halt(struct eth_device *eth)
|
|||
debug("** %s()\n", __func__);
|
||||
}
|
||||
|
||||
static int asix_write_hwaddr(struct eth_device *eth)
|
||||
{
|
||||
struct ueth_data *dev = (struct ueth_data *)eth->priv;
|
||||
|
||||
return asix_write_hwaddr_common(dev, eth->enetaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Asix probing functions
|
||||
*/
|
||||
|
@ -694,9 +718,180 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
|
|||
return 0;
|
||||
|
||||
/* Get the MAC address */
|
||||
if (asix_read_mac(eth))
|
||||
if (asix_read_mac_common(ss, priv, eth->enetaddr))
|
||||
return 0;
|
||||
debug("MAC %pM\n", eth->enetaddr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
static int asix_eth_start(struct udevice *dev)
|
||||
{
|
||||
struct asix_private *priv = dev_get_priv(dev);
|
||||
|
||||
return asix_init_common(&priv->ueth);
|
||||
}
|
||||
|
||||
void asix_eth_stop(struct udevice *dev)
|
||||
{
|
||||
debug("** %s()\n", __func__);
|
||||
}
|
||||
|
||||
int asix_eth_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct asix_private *priv = dev_get_priv(dev);
|
||||
|
||||
return asix_send_common(&priv->ueth, packet, length);
|
||||
}
|
||||
|
||||
int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
{
|
||||
struct asix_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, AX_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 as two
|
||||
* complementary 16-bit words. Extract the length of the data.
|
||||
*/
|
||||
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 >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
|
||||
debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
|
||||
packet_len, (~packet_len >> 16) & 0x7ff,
|
||||
packet_len & 0x7ff);
|
||||
goto err;
|
||||
}
|
||||
packet_len = packet_len & 0x7ff;
|
||||
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 asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
|
||||
{
|
||||
struct asix_private *priv = dev_get_priv(dev);
|
||||
|
||||
if (packet_len & 1)
|
||||
packet_len++;
|
||||
usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asix_write_hwaddr(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct asix_private *priv = dev_get_priv(dev);
|
||||
|
||||
if (priv->flags & FLAG_TYPE_AX88172)
|
||||
return -ENOSYS;
|
||||
|
||||
return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr);
|
||||
}
|
||||
|
||||
static int asix_eth_probe(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct asix_private *priv = dev_get_priv(dev);
|
||||
struct ueth_data *ss = &priv->ueth;
|
||||
int ret;
|
||||
|
||||
priv->flags = dev->driver_data;
|
||||
ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = asix_basic_reset(ss);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* Get the MAC address */
|
||||
ret = asix_read_mac_common(ss, priv, pdata->enetaddr);
|
||||
if (ret)
|
||||
goto err;
|
||||
debug("MAC %pM\n", pdata->enetaddr);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return usb_ether_deregister(ss);
|
||||
}
|
||||
|
||||
static const struct eth_ops asix_eth_ops = {
|
||||
.start = asix_eth_start,
|
||||
.send = asix_eth_send,
|
||||
.recv = asix_eth_recv,
|
||||
.free_pkt = asix_free_pkt,
|
||||
.stop = asix_eth_stop,
|
||||
.write_hwaddr = asix_write_hwaddr,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(asix_eth) = {
|
||||
.name = "asix_eth",
|
||||
.id = UCLASS_ETH,
|
||||
.probe = asix_eth_probe,
|
||||
.ops = &asix_eth_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct asix_private),
|
||||
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
|
||||
};
|
||||
|
||||
static const struct usb_device_id asix_eth_id_table[] = {
|
||||
/* Apple USB Ethernet Adapter */
|
||||
{ USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* D-Link DUB-E100 H/W Ver B1 */
|
||||
{ USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* D-Link DUB-E100 H/W Ver C1 */
|
||||
{ USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* Cables-to-Go USB Ethernet Adapter */
|
||||
{ USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* Trendnet TU2-ET100 V3.0R */
|
||||
{ USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* SMC */
|
||||
{ USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 },
|
||||
/* MSI - ASIX 88772a */
|
||||
{ USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* Linksys 200M v2.1 */
|
||||
{ USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 },
|
||||
/* 0Q0 cable ethernet */
|
||||
{ USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* DLink DUB-E100 H/W Ver B1 Alternate */
|
||||
{ USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
|
||||
/* ASIX 88772B */
|
||||
{ USB_DEVICE(0x0b95, 0x772b),
|
||||
.driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
|
||||
{ USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table);
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue