189d48367SSimon Glass /* 289d48367SSimon Glass * Copyright (c) 2011 The Chromium OS Authors. 389d48367SSimon Glass * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 589d48367SSimon Glass */ 689d48367SSimon Glass 789d48367SSimon Glass #include <common.h> 8c0ad74e4SSimon Glass #include <dm.h> 9c8c2797cSSimon Glass #include <malloc.h> 1089d48367SSimon Glass #include <usb.h> 11c0ad74e4SSimon Glass #include <dm/device-internal.h> 1289d48367SSimon Glass 1389d48367SSimon Glass #include "usb_ether.h" 1489d48367SSimon Glass 15c8c2797cSSimon Glass #ifdef CONFIG_DM_ETH 16c8c2797cSSimon Glass 17c8c2797cSSimon Glass #define USB_BULK_RECV_TIMEOUT 500 18c8c2797cSSimon Glass 19c8c2797cSSimon Glass int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize) 20c8c2797cSSimon Glass { 21c8c2797cSSimon Glass struct usb_device *udev = dev_get_parentdata(dev); 22c8c2797cSSimon Glass struct usb_interface_descriptor *iface_desc; 23c8c2797cSSimon Glass bool ep_in_found = false, ep_out_found = false; 24c8c2797cSSimon Glass struct usb_interface *iface; 25c8c2797cSSimon Glass const int ifnum = 0; /* Always use interface 0 */ 26c8c2797cSSimon Glass int ret, i; 27c8c2797cSSimon Glass 28c8c2797cSSimon Glass iface = &udev->config.if_desc[ifnum]; 29c8c2797cSSimon Glass iface_desc = &udev->config.if_desc[ifnum].desc; 30c8c2797cSSimon Glass 31c8c2797cSSimon Glass /* Initialize the ueth_data structure with some useful info */ 32c8c2797cSSimon Glass ueth->ifnum = ifnum; 33c8c2797cSSimon Glass ueth->subclass = iface_desc->bInterfaceSubClass; 34c8c2797cSSimon Glass ueth->protocol = iface_desc->bInterfaceProtocol; 35c8c2797cSSimon Glass 36c8c2797cSSimon Glass /* 37c8c2797cSSimon Glass * We are expecting a minimum of 3 endpoints - in, out (bulk), and int. 38c8c2797cSSimon Glass * We will ignore any others. 39c8c2797cSSimon Glass */ 40c8c2797cSSimon Glass for (i = 0; i < iface_desc->bNumEndpoints; i++) { 41c8c2797cSSimon Glass int ep_addr = iface->ep_desc[i].bEndpointAddress; 42c8c2797cSSimon Glass 43c8c2797cSSimon Glass /* is it an BULK endpoint? */ 44c8c2797cSSimon Glass if ((iface->ep_desc[i].bmAttributes & 45c8c2797cSSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { 46c8c2797cSSimon Glass if (ep_addr & USB_DIR_IN && !ep_in_found) { 47c8c2797cSSimon Glass ueth->ep_in = ep_addr & 48c8c2797cSSimon Glass USB_ENDPOINT_NUMBER_MASK; 49c8c2797cSSimon Glass ep_in_found = true; 50c8c2797cSSimon Glass } else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) { 51c8c2797cSSimon Glass ueth->ep_out = ep_addr & 52c8c2797cSSimon Glass USB_ENDPOINT_NUMBER_MASK; 53c8c2797cSSimon Glass ep_out_found = true; 54c8c2797cSSimon Glass } 55c8c2797cSSimon Glass } 56c8c2797cSSimon Glass 57c8c2797cSSimon Glass /* is it an interrupt endpoint? */ 58c8c2797cSSimon Glass if ((iface->ep_desc[i].bmAttributes & 59c8c2797cSSimon Glass USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { 60c8c2797cSSimon Glass ueth->ep_int = iface->ep_desc[i].bEndpointAddress & 61c8c2797cSSimon Glass USB_ENDPOINT_NUMBER_MASK; 62c8c2797cSSimon Glass ueth->irqinterval = iface->ep_desc[i].bInterval; 63c8c2797cSSimon Glass } 64c8c2797cSSimon Glass } 65c8c2797cSSimon Glass debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out, 66c8c2797cSSimon Glass ueth->ep_int); 67c8c2797cSSimon Glass 68c8c2797cSSimon Glass /* Do some basic sanity checks, and bail if we find a problem */ 69c8c2797cSSimon Glass if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) { 70c8c2797cSSimon Glass debug("%s: %s: Cannot find endpoints\n", __func__, dev->name); 71c8c2797cSSimon Glass return -ENXIO; 72c8c2797cSSimon Glass } 73c8c2797cSSimon Glass 74c8c2797cSSimon Glass ueth->rxsize = rxsize; 75c8c2797cSSimon Glass ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN); 76c8c2797cSSimon Glass if (!ueth->rxbuf) 77c8c2797cSSimon Glass return -ENOMEM; 78c8c2797cSSimon Glass 79c8c2797cSSimon Glass ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum); 80c8c2797cSSimon Glass if (ret) { 81c8c2797cSSimon Glass debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name, 82c8c2797cSSimon Glass ret); 83c8c2797cSSimon Glass return ret; 84c8c2797cSSimon Glass } 85c8c2797cSSimon Glass ueth->pusb_dev = udev; 86c8c2797cSSimon Glass 87c8c2797cSSimon Glass return 0; 88c8c2797cSSimon Glass } 89c8c2797cSSimon Glass 90c8c2797cSSimon Glass int usb_ether_deregister(struct ueth_data *ueth) 91c8c2797cSSimon Glass { 92c8c2797cSSimon Glass return 0; 93c8c2797cSSimon Glass } 94c8c2797cSSimon Glass 95c8c2797cSSimon Glass int usb_ether_receive(struct ueth_data *ueth, int rxsize) 96c8c2797cSSimon Glass { 97c8c2797cSSimon Glass int actual_len; 98c8c2797cSSimon Glass int ret; 99c8c2797cSSimon Glass 100c8c2797cSSimon Glass if (rxsize > ueth->rxsize) 101c8c2797cSSimon Glass return -EINVAL; 102c8c2797cSSimon Glass ret = usb_bulk_msg(ueth->pusb_dev, 103c8c2797cSSimon Glass usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in), 104c8c2797cSSimon Glass ueth->rxbuf, rxsize, &actual_len, 105c8c2797cSSimon Glass USB_BULK_RECV_TIMEOUT); 106c8c2797cSSimon Glass debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret); 107c8c2797cSSimon Glass if (ret) { 108c8c2797cSSimon Glass printf("Rx: failed to receive: %d\n", ret); 109c8c2797cSSimon Glass return ret; 110c8c2797cSSimon Glass } 111c8c2797cSSimon Glass if (actual_len > rxsize) { 112c8c2797cSSimon Glass debug("Rx: received too many bytes %d\n", actual_len); 113c8c2797cSSimon Glass return -ENOSPC; 114c8c2797cSSimon Glass } 115c8c2797cSSimon Glass ueth->rxlen = actual_len; 116c8c2797cSSimon Glass ueth->rxptr = 0; 117c8c2797cSSimon Glass 118c8c2797cSSimon Glass return actual_len ? 0 : -EAGAIN; 119c8c2797cSSimon Glass } 120c8c2797cSSimon Glass 121c8c2797cSSimon Glass void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes) 122c8c2797cSSimon Glass { 123c8c2797cSSimon Glass ueth->rxptr += num_bytes; 124c8c2797cSSimon Glass if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen) 125c8c2797cSSimon Glass ueth->rxlen = 0; 126c8c2797cSSimon Glass } 127c8c2797cSSimon Glass 128c8c2797cSSimon Glass int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp) 129c8c2797cSSimon Glass { 130c8c2797cSSimon Glass if (!ueth->rxlen) 131c8c2797cSSimon Glass return 0; 132c8c2797cSSimon Glass 133c8c2797cSSimon Glass *ptrp = &ueth->rxbuf[ueth->rxptr]; 134c8c2797cSSimon Glass 135c8c2797cSSimon Glass return ueth->rxlen - ueth->rxptr; 136c8c2797cSSimon Glass } 137c8c2797cSSimon Glass 138c8c2797cSSimon Glass #else 139c8c2797cSSimon Glass 14089d48367SSimon Glass typedef void (*usb_eth_before_probe)(void); 14189d48367SSimon Glass typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum, 14289d48367SSimon Glass struct ueth_data *ss); 14389d48367SSimon Glass typedef int (*usb_eth_get_info)(struct usb_device *dev, struct ueth_data *ss, 14489d48367SSimon Glass struct eth_device *dev_desc); 14589d48367SSimon Glass 14689d48367SSimon Glass struct usb_eth_prob_dev { 14789d48367SSimon Glass usb_eth_before_probe before_probe; /* optional */ 14889d48367SSimon Glass usb_eth_probe probe; 14989d48367SSimon Glass usb_eth_get_info get_info; 15089d48367SSimon Glass }; 15189d48367SSimon Glass 15289d48367SSimon Glass /* driver functions go here, each bracketed by #ifdef CONFIG_USB_ETHER_xxx */ 15389d48367SSimon Glass static const struct usb_eth_prob_dev prob_dev[] = { 1549b70e007SSimon Glass #ifdef CONFIG_USB_ETHER_ASIX 1559b70e007SSimon Glass { 1569b70e007SSimon Glass .before_probe = asix_eth_before_probe, 1579b70e007SSimon Glass .probe = asix_eth_probe, 1589b70e007SSimon Glass .get_info = asix_eth_get_info, 1599b70e007SSimon Glass }, 1609b70e007SSimon Glass #endif 161e9954b86SRene Griessl #ifdef CONFIG_USB_ETHER_ASIX88179 162e9954b86SRene Griessl { 163e9954b86SRene Griessl .before_probe = ax88179_eth_before_probe, 164e9954b86SRene Griessl .probe = ax88179_eth_probe, 165e9954b86SRene Griessl .get_info = ax88179_eth_get_info, 166e9954b86SRene Griessl }, 167e9954b86SRene Griessl #endif 168df4fb1c3SGerhard Sittig #ifdef CONFIG_USB_ETHER_MCS7830 169df4fb1c3SGerhard Sittig { 170df4fb1c3SGerhard Sittig .before_probe = mcs7830_eth_before_probe, 171df4fb1c3SGerhard Sittig .probe = mcs7830_eth_probe, 172df4fb1c3SGerhard Sittig .get_info = mcs7830_eth_get_info, 173df4fb1c3SGerhard Sittig }, 174df4fb1c3SGerhard Sittig #endif 175291391beSSimon Glass #ifdef CONFIG_USB_ETHER_SMSC95XX 176291391beSSimon Glass { 177291391beSSimon Glass .before_probe = smsc95xx_eth_before_probe, 178291391beSSimon Glass .probe = smsc95xx_eth_probe, 179291391beSSimon Glass .get_info = smsc95xx_eth_get_info, 180291391beSSimon Glass }, 181291391beSSimon Glass #endif 18289d48367SSimon Glass { }, /* END */ 18389d48367SSimon Glass }; 18489d48367SSimon Glass 18589d48367SSimon Glass static int usb_max_eth_dev; /* number of highest available usb eth device */ 18689d48367SSimon Glass static struct ueth_data usb_eth[USB_MAX_ETH_DEV]; 18789d48367SSimon Glass 18889d48367SSimon Glass /******************************************************************************* 18989d48367SSimon Glass * tell if current ethernet device is a usb dongle 19089d48367SSimon Glass */ 19189d48367SSimon Glass int is_eth_dev_on_usb_host(void) 19289d48367SSimon Glass { 19389d48367SSimon Glass int i; 19489d48367SSimon Glass struct eth_device *dev = eth_get_dev(); 19589d48367SSimon Glass 19689d48367SSimon Glass if (dev) { 19789d48367SSimon Glass for (i = 0; i < usb_max_eth_dev; i++) 19889d48367SSimon Glass if (&usb_eth[i].eth_dev == dev) 19989d48367SSimon Glass return 1; 20089d48367SSimon Glass } 20189d48367SSimon Glass return 0; 20289d48367SSimon Glass } 20389d48367SSimon Glass 20489d48367SSimon Glass /* 20589d48367SSimon Glass * Given a USB device, ask each driver if it can support it, and attach it 20689d48367SSimon Glass * to the first driver that says 'yes' 20789d48367SSimon Glass */ 20889d48367SSimon Glass static void probe_valid_drivers(struct usb_device *dev) 20989d48367SSimon Glass { 2107616e785SSimon Glass struct eth_device *eth; 21189d48367SSimon Glass int j; 21289d48367SSimon Glass 21389d48367SSimon Glass for (j = 0; prob_dev[j].probe && prob_dev[j].get_info; j++) { 21489d48367SSimon Glass if (!prob_dev[j].probe(dev, 0, &usb_eth[usb_max_eth_dev])) 21589d48367SSimon Glass continue; 21689d48367SSimon Glass /* 21789d48367SSimon Glass * ok, it is a supported eth device. Get info and fill it in 21889d48367SSimon Glass */ 2197616e785SSimon Glass eth = &usb_eth[usb_max_eth_dev].eth_dev; 22089d48367SSimon Glass if (prob_dev[j].get_info(dev, 22189d48367SSimon Glass &usb_eth[usb_max_eth_dev], 2227616e785SSimon Glass eth)) { 22389d48367SSimon Glass /* found proper driver */ 22489d48367SSimon Glass /* register with networking stack */ 22589d48367SSimon Glass usb_max_eth_dev++; 22689d48367SSimon Glass 22789d48367SSimon Glass /* 22889d48367SSimon Glass * usb_max_eth_dev must be incremented prior to this 22989d48367SSimon Glass * call since eth_current_changed (internally called) 23089d48367SSimon Glass * relies on it 23189d48367SSimon Glass */ 2327616e785SSimon Glass eth_register(eth); 2337616e785SSimon Glass if (eth_write_hwaddr(eth, "usbeth", 2347616e785SSimon Glass usb_max_eth_dev - 1)) 2357616e785SSimon Glass puts("Warning: failed to set MAC address\n"); 23689d48367SSimon Glass break; 23789d48367SSimon Glass } 23889d48367SSimon Glass } 23989d48367SSimon Glass } 24089d48367SSimon Glass 24189d48367SSimon Glass /******************************************************************************* 24289d48367SSimon Glass * scan the usb and reports device info 24389d48367SSimon Glass * to the user if mode = 1 24489d48367SSimon Glass * returns current device or -1 if no 24589d48367SSimon Glass */ 24689d48367SSimon Glass int usb_host_eth_scan(int mode) 24789d48367SSimon Glass { 24889d48367SSimon Glass int i, old_async; 24989d48367SSimon Glass 25089d48367SSimon Glass if (mode == 1) 25193c2582fSLucas Stach printf(" scanning usb for ethernet devices... "); 25289d48367SSimon Glass 25389d48367SSimon Glass old_async = usb_disable_asynch(1); /* asynch transfer not allowed */ 25489d48367SSimon Glass 255e7e982d6SVincent Palatin /* unregister a previously detected device */ 256e7e982d6SVincent Palatin for (i = 0; i < usb_max_eth_dev; i++) 257e7e982d6SVincent Palatin eth_unregister(&usb_eth[i].eth_dev); 258e7e982d6SVincent Palatin 259e7e982d6SVincent Palatin memset(usb_eth, 0, sizeof(usb_eth)); 26089d48367SSimon Glass 26189d48367SSimon Glass for (i = 0; prob_dev[i].probe; i++) { 26289d48367SSimon Glass if (prob_dev[i].before_probe) 26389d48367SSimon Glass prob_dev[i].before_probe(); 26489d48367SSimon Glass } 26589d48367SSimon Glass 26689d48367SSimon Glass usb_max_eth_dev = 0; 267c0ad74e4SSimon Glass #ifdef CONFIG_DM_USB 268c0ad74e4SSimon Glass /* 269*abb59cffSSimon Glass * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB 270*abb59cffSSimon Glass * Ethernet driver and then most of this file can be removed. 271c0ad74e4SSimon Glass */ 272c0ad74e4SSimon Glass struct udevice *bus; 273c0ad74e4SSimon Glass struct uclass *uc; 274c0ad74e4SSimon Glass int ret; 275c0ad74e4SSimon Glass 276c0ad74e4SSimon Glass ret = uclass_get(UCLASS_USB, &uc); 277c0ad74e4SSimon Glass if (ret) 278c0ad74e4SSimon Glass return ret; 279c0ad74e4SSimon Glass uclass_foreach_dev(bus, uc) { 28089d48367SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 281c0ad74e4SSimon Glass struct usb_device *dev; 282c0ad74e4SSimon Glass 283c0ad74e4SSimon Glass dev = usb_get_dev_index(bus, i); /* get device */ 284c0ad74e4SSimon Glass debug("i=%d, %s\n", i, dev ? dev->dev->name : "(done)"); 285c0ad74e4SSimon Glass if (!dev) 286c0ad74e4SSimon Glass break; /* no more devices available */ 287c0ad74e4SSimon Glass 288c0ad74e4SSimon Glass /* 289c0ad74e4SSimon Glass * find valid usb_ether driver for this device, 290c0ad74e4SSimon Glass * if any 291c0ad74e4SSimon Glass */ 292c0ad74e4SSimon Glass probe_valid_drivers(dev); 293c0ad74e4SSimon Glass 294c0ad74e4SSimon Glass /* check limit */ 295c0ad74e4SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) 296c0ad74e4SSimon Glass break; 297c0ad74e4SSimon Glass } /* for */ 298c0ad74e4SSimon Glass } 299c0ad74e4SSimon Glass #else 300c0ad74e4SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) { 301c0ad74e4SSimon Glass struct usb_device *dev; 302c0ad74e4SSimon Glass 30389d48367SSimon Glass dev = usb_get_dev_index(i); /* get device */ 30489d48367SSimon Glass debug("i=%d\n", i); 305c0ad74e4SSimon Glass if (!dev) 306d1f862f9SPeter Meerwald break; /* no more devices available */ 30789d48367SSimon Glass 30889d48367SSimon Glass /* find valid usb_ether driver for this device, if any */ 30989d48367SSimon Glass probe_valid_drivers(dev); 31089d48367SSimon Glass 31189d48367SSimon Glass /* check limit */ 312c0ad74e4SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) 313c0ad74e4SSimon Glass break; 314c0ad74e4SSimon Glass } /* for */ 315c0ad74e4SSimon Glass #endif 31689d48367SSimon Glass if (usb_max_eth_dev == USB_MAX_ETH_DEV) { 31789d48367SSimon Glass printf("max USB Ethernet Device reached: %d stopping\n", 31889d48367SSimon Glass usb_max_eth_dev); 31989d48367SSimon Glass } 32089d48367SSimon Glass usb_disable_asynch(old_async); /* restore asynch value */ 32189d48367SSimon Glass printf("%d Ethernet Device(s) found\n", usb_max_eth_dev); 32289d48367SSimon Glass if (usb_max_eth_dev > 0) 32389d48367SSimon Glass return 0; 32489d48367SSimon Glass return -1; 32589d48367SSimon Glass } 326c8c2797cSSimon Glass #endif 327