diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dfu/dfu.c | 24 | ||||
-rw-r--r-- | drivers/dfu/dfu_mmc.c | 8 | ||||
-rw-r--r-- | drivers/gpio/intel_ich6_gpio.c | 20 | ||||
-rw-r--r-- | drivers/serial/Makefile | 2 | ||||
-rw-r--r-- | drivers/serial/serial_x86.c (renamed from drivers/serial/serial_coreboot.c) | 12 | ||||
-rw-r--r-- | drivers/usb/eth/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/eth/asix88179.c | 700 | ||||
-rw-r--r-- | drivers/usb/eth/usb_ether.c | 7 | ||||
-rw-r--r-- | drivers/usb/gadget/atmel_usba_udc.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/f_dfu.c | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 14 | ||||
-rw-r--r-- | drivers/usb/gadget/f_thor.c | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/g_dnl.c | 17 |
13 files changed, 786 insertions, 38 deletions
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 14cb366..ad0a7e7 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -17,7 +17,6 @@ #include <linux/list.h> #include <linux/compiler.h> -static bool dfu_detach_request; static LIST_HEAD(dfu_list); static int dfu_alt_num; static int alt_num_cnt; @@ -39,21 +38,6 @@ __weak bool dfu_usb_get_reset(void) return true; } -bool dfu_detach(void) -{ - return dfu_detach_request; -} - -void dfu_trigger_detach(void) -{ - dfu_detach_request = true; -} - -void dfu_clear_detach(void) -{ - dfu_detach_request = false; -} - static int dfu_find_alt_num(const char *s) { int i = 0; @@ -111,8 +95,12 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu) return dfu_buf; s = getenv("dfu_bufsiz"); - dfu_buf_size = s ? (unsigned long)simple_strtol(s, NULL, 16) : - CONFIG_SYS_DFU_DATA_BUF_SIZE; + if (s) + dfu_buf_size = (unsigned long)simple_strtol(s, NULL, 0); + + if (!s || !dfu_buf_size) + dfu_buf_size = CONFIG_SYS_DFU_DATA_BUF_SIZE; + if (dfu->max_buf_size && dfu_buf_size > dfu->max_buf_size) dfu_buf_size = dfu->max_buf_size; diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 72fa03e..62d72fe 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -40,10 +40,16 @@ static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part) static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, u64 offset, void *buf, long *len) { - struct mmc *mmc = find_mmc_device(dfu->data.mmc.dev_num); + struct mmc *mmc; u32 blk_start, blk_count, n = 0; int ret, part_num_bkp = 0; + mmc = find_mmc_device(dfu->data.mmc.dev_num); + if (!mmc) { + error("Device MMC %d - not found!", dfu->data.mmc.dev_num); + return -ENODEV; + } + /* * We must ensure that we work in lba_blk_size chunks, so ALIGN * this value. diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c index 3433216..7720cc3 100644 --- a/drivers/gpio/intel_ich6_gpio.c +++ b/drivers/gpio/intel_ich6_gpio.c @@ -39,9 +39,9 @@ struct ich6_bank_priv { /* These are I/O addresses */ - uint32_t use_sel; - uint32_t io_sel; - uint32_t lvl; + uint16_t use_sel; + uint16_t io_sel; + uint16_t lvl; }; /* TODO: Move this to device tree, or platform data */ @@ -57,7 +57,7 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) u8 tmpbyte; u16 tmpword; u32 tmplong; - u32 gpiobase; + u16 gpiobase; int offset; /* Where should it be? */ @@ -116,11 +116,15 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) /* * GPIOBASE moved to its current offset with ICH6, but prior to * that it was unused (or undocumented). Check that it looks - * okay: not all ones or zeros, and mapped to I/O space (bit 0). + * okay: not all ones or zeros. + * + * Note we don't need check bit0 here, because the Tunnel Creek + * GPIO base address register bit0 is reserved (read returns 0), + * while on the Ivybridge the bit0 is used to indicate it is an + * I/O space. */ tmplong = pci_read_config32(pci_dev, PCI_CFG_GPIOBASE); - if (tmplong == 0x00000000 || tmplong == 0xffffffff || - !(tmplong & 0x00000001)) { + if (tmplong == 0x00000000 || tmplong == 0xffffffff) { debug("%s: unexpected GPIOBASE value\n", __func__); return -ENODEV; } @@ -131,7 +135,7 @@ static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) * at the offset that we just read. Bit 0 indicates that it's * an I/O address, not a memory address, so mask that off. */ - gpiobase = tmplong & 0xfffffffe; + gpiobase = tmplong & 0xfffe; offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1); if (offset == -1) { debug("%s: Invalid register offset %d\n", __func__, offset); diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 8c84942..4cc00cd 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -43,7 +43,7 @@ obj-$(CONFIG_ARC_SERIAL) += serial_arc.o obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o -obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o +obj-$(CONFIG_X86_SERIAL) += serial_x86.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_x86.c index 5c6a76c..e81e035 100644 --- a/drivers/serial/serial_coreboot.c +++ b/drivers/serial/serial_x86.c @@ -9,12 +9,12 @@ #include <ns16550.h> #include <serial.h> -static const struct udevice_id coreboot_serial_ids[] = { - { .compatible = "coreboot-uart" }, +static const struct udevice_id x86_serial_ids[] = { + { .compatible = "x86-uart" }, { } }; -static int coreboot_serial_ofdata_to_platdata(struct udevice *dev) +static int x86_serial_ofdata_to_platdata(struct udevice *dev) { struct ns16550_platdata *plat = dev_get_platdata(dev); int ret; @@ -27,10 +27,10 @@ static int coreboot_serial_ofdata_to_platdata(struct udevice *dev) return 0; } U_BOOT_DRIVER(serial_ns16550) = { - .name = "serial_coreboot", + .name = "serial_x86", .id = UCLASS_SERIAL, - .of_match = coreboot_serial_ids, - .ofdata_to_platdata = coreboot_serial_ofdata_to_platdata, + .of_match = x86_serial_ids, + .ofdata_to_platdata = x86_serial_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), .priv_auto_alloc_size = sizeof(struct NS16550), .probe = ns16550_serial_probe, diff --git a/drivers/usb/eth/Makefile b/drivers/usb/eth/Makefile index e6ae9f1..c92d2b0 100644 --- a/drivers/usb/eth/Makefile +++ b/drivers/usb/eth/Makefile @@ -6,5 +6,6 @@ # new USB host ethernet layer dependencies obj-$(CONFIG_USB_HOST_ETHER) += usb_ether.o obj-$(CONFIG_USB_ETHER_ASIX) += asix.o +obj-$(CONFIG_USB_ETHER_ASIX88179) += asix88179.o obj-$(CONFIG_USB_ETHER_MCS7830) += mcs7830.o obj-$(CONFIG_USB_ETHER_SMSC95XX) += smsc95xx.o diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c new file mode 100644 index 0000000..b8ca720 --- /dev/null +++ b/drivers/usb/eth/asix88179.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2014 Rene Griessl <rgriessl@cit-ec.uni-bielefeld.de> + * based on the U-Boot Asix driver as well as information + * from the Linux AX88179_178a driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <usb.h> +#include <net.h> +#include <linux/mii.h> +#include "usb_ether.h" +#include <malloc.h> +#include <errno.h> + +/* ASIX AX88179 based USB 3.0 Ethernet Devices */ +#define AX88179_PHY_ID 0x03 +#define AX_EEPROM_LEN 0x100 +#define AX88179_EEPROM_MAGIC 0x17900b95 +#define AX_MCAST_FLTSIZE 8 +#define AX_MAX_MCAST 64 +#define AX_INT_PPLS_LINK (1 << 16) +#define AX_RXHDR_L4_TYPE_MASK 0x1c +#define AX_RXHDR_L4_TYPE_UDP 4 +#define AX_RXHDR_L4_TYPE_TCP 16 +#define AX_RXHDR_L3CSUM_ERR 2 +#define AX_RXHDR_L4CSUM_ERR 1 +#define AX_RXHDR_CRC_ERR (1 << 29) +#define AX_RXHDR_DROP_ERR (1 << 31) +#define AX_ENDPOINT_INT 0x01 +#define AX_ENDPOINT_IN 0x02 +#define AX_ENDPOINT_OUT 0x03 +#define AX_ACCESS_MAC 0x01 +#define AX_ACCESS_PHY 0x02 +#define AX_ACCESS_EEPROM 0x04 +#define AX_ACCESS_EFUS 0x05 +#define AX_PAUSE_WATERLVL_HIGH 0x54 +#define AX_PAUSE_WATERLVL_LOW 0x55 + +#define PHYSICAL_LINK_STATUS 0x02 + #define AX_USB_SS (1 << 2) + #define AX_USB_HS (1 << 1) + +#define GENERAL_STATUS 0x03 + #define AX_SECLD (1 << 2) + +#define AX_SROM_ADDR 0x07 +#define AX_SROM_CMD 0x0a + #define EEP_RD (1 << 2) + #define EEP_BUSY (1 << 4) + +#define AX_SROM_DATA_LOW 0x08 +#define AX_SROM_DATA_HIGH 0x09 + +#define AX_RX_CTL 0x0b + #define AX_RX_CTL_DROPCRCERR (1 << 8) + #define AX_RX_CTL_IPE (1 << 9) + #define AX_RX_CTL_START (1 << 7) + #define AX_RX_CTL_AP (1 << 5) + #define AX_RX_CTL_AM (1 << 4) + #define AX_RX_CTL_AB (1 << 3) + #define AX_RX_CTL_AMALL (1 << 1) + #define AX_RX_CTL_PRO (1 << 0) + #define AX_RX_CTL_STOP 0 + +#define AX_NODE_ID 0x10 +#define AX_MULFLTARY 0x16 + +#define AX_MEDIUM_STATUS_MODE 0x22 + #define AX_MEDIUM_GIGAMODE (1 << 0) + #define AX_MEDIUM_FULL_DUPLEX (1 << 1) + #define AX_MEDIUM_EN_125MHZ (1 << 3) + #define AX_MEDIUM_RXFLOW_CTRLEN (1 << 4) + #define AX_MEDIUM_TXFLOW_CTRLEN (1 << 5) + #define AX_MEDIUM_RECEIVE_EN (1 << 8) + #define AX_MEDIUM_PS (1 << 9) + #define AX_MEDIUM_JUMBO_EN 0x8040 + +#define AX_MONITOR_MOD 0x24 + #define AX_MONITOR_MODE_RWLC (1 << 1) + #define AX_MONITOR_MODE_RWMP (1 << 2) + #define AX_MONITOR_MODE_PMEPOL (1 << 5) + #define AX_MONITOR_MODE_PMETYPE (1 << 6) + +#define AX_GPIO_CTRL 0x25 + #define AX_GPIO_CTRL_GPIO3EN (1 << 7) + #define AX_GPIO_CTRL_GPIO2EN (1 << 6) + #define AX_GPIO_CTRL_GPIO1EN (1 << 5) + +#define AX_PHYPWR_RSTCTL 0x26 + #define AX_PHYPWR_RSTCTL_BZ (1 << 4) + #define AX_PHYPWR_RSTCTL_IPRL (1 << 5) + #define AX_PHYPWR_RSTCTL_AT (1 << 12) + +#define AX_RX_BULKIN_QCTRL 0x2e +#define AX_CLK_SELECT 0x33 + #define AX_CLK_SELECT_BCS (1 << 0) + #define AX_CLK_SELECT_ACS (1 << 1) + #define AX_CLK_SELECT_ULR (1 << 3) + +#define AX_RXCOE_CTL 0x34 + #define AX_RXCOE_IP (1 << 0) + #define AX_RXCOE_TCP (1 << 1) + #define AX_RXCOE_UDP (1 << 2) + #define AX_RXCOE_TCPV6 (1 << 5) + #define AX_RXCOE_UDPV6 (1 << 6) + +#define AX_TXCOE_CTL 0x35 + #define AX_TXCOE_IP (1 << 0) + #define AX_TXCOE_TCP (1 << 1) + #define AX_TXCOE_UDP (1 << 2) + #define AX_TXCOE_TCPV6 (1 << 5) + #define AX_TXCOE_UDPV6 (1 << 6) + +#define AX_LEDCTRL 0x73 + +#define GMII_PHY_PHYSR 0x11 + #define GMII_PHY_PHYSR_SMASK 0xc000 + #define GMII_PHY_PHYSR_GIGA (1 << 15) + #define GMII_PHY_PHYSR_100 (1 << 14) + #define GMII_PHY_PHYSR_FULL (1 << 13) + #define GMII_PHY_PHYSR_LINK (1 << 10) + +#define GMII_LED_ACT 0x1a + #define GMII_LED_ACTIVE_MASK 0xff8f + #define GMII_LED0_ACTIVE (1 << 4) + #define GMII_LED1_ACTIVE (1 << 5) + #define GMII_LED2_ACTIVE (1 << 6) + +#define GMII_LED_LINK 0x1c + #define GMII_LED_LINK_MASK 0xf888 + #define GMII_LED0_LINK_10 (1 << 0) + #define GMII_LED0_LINK_100 (1 << 1) + #define GMII_LED0_LINK_1000 (1 << 2) + #define GMII_LED1_LINK_10 (1 << 4) + #define GMII_LED1_LINK_100 (1 << 5) + #define GMII_LED1_LINK_1000 (1 << 6) + #define GMII_LED2_LINK_10 (1 << 8) + #define GMII_LED2_LINK_100 (1 << 9) + #define GMII_LED2_LINK_1000 (1 << 10) + #define LED0_ACTIVE (1 << 0) + #define LED0_LINK_10 (1 << 1) + #define LED0_LINK_100 (1 << 2) + #define LED0_LINK_1000 (1 << 3) + #define LED0_FD (1 << 4) + #define LED0_USB3_MASK 0x001f + #define LED1_ACTIVE (1 << 5) + #define LED1_LINK_10 (1 << 6) + #define LED1_LINK_100 (1 << 7) + #define LED1_LINK_1000 (1 << 8) + #define LED1_FD (1 << 9) + #define LED1_USB3_MASK 0x03e0 + #define LED2_ACTIVE (1 << 10) + #define LED2_LINK_1000 (1 << 13) + #define LED2_LINK_100 (1 << 12) + #define LED2_LINK_10 (1 << 11) + #define LED2_FD (1 << 14) + #define LED_VALID (1 << 15) + #define LED2_USB3_MASK 0x7c00 + +#define GMII_PHYPAGE 0x1e +#define GMII_PHY_PAGE_SELECT 0x1f + #define GMII_PHY_PGSEL_EXT 0x0007 + #define GMII_PHY_PGSEL_PAGE0 0x0000 + +/* local defines */ +#define ASIX_BASE_NAME "axg" +#define USB_CTRL_SET_TIMEOUT 5000 +#define USB_CTRL_GET_TIMEOUT 5000 +#define USB_BULK_SEND_TIMEOUT 5000 +#define USB_BULK_RECV_TIMEOUT 5000 + +#define AX_RX_URB_SIZE 1024 * 0x12 +#define BLK_FRAME_SIZE 0x200 +#define PHY_CONNECT_TIMEOUT 5000 + +#define TIMEOUT_RESOLUTION 50 /* ms */ + +#define FLAG_NONE 0 +#define FLAG_TYPE_AX88179 (1U << 0) +#define FLAG_TYPE_AX88178a (1U << 1) +#define FLAG_TYPE_DLINK_DUB1312 (1U << 2) +#define FLAG_TYPE_SITECOM (1U << 3) +#define FLAG_TYPE_SAMSUNG (1U << 4) +#define FLAG_TYPE_LENOVO (1U << 5) + +/* local vars */ +static const struct { + unsigned char ctrl, timer_l, timer_h, size, ifg; +} AX88179_BULKIN_SIZE[] = { + {7, 0x4f, 0, 0x02, 0xff}, + {7, 0x20, 3, 0x03, 0xff}, + {7, 0xae, 7, 0x04, 0xff}, + {7, 0xcc, 0x4c, 0x04, 8}, +}; + +static int curr_eth_dev; /* index for name of next device detected */ + +/* driver private */ +struct asix_private { + int flags; + int rx_urb_size; + int maxpacketsize; +}; + +/* + * Asix infrastructure commands + */ +static int asix_write_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int len; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, size); + + debug("asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", + cmd, value, index, size); + + memcpy(buf, data, size); + + len = usb_control_msg( + dev->pusb_dev, + usb_sndctrlpipe(dev->pusb_dev, 0), + cmd, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + buf, + size, + USB_CTRL_SET_TIMEOUT); + + return len == size ? 0 : ECOMM; +} + +static int asix_read_cmd(struct ueth_data *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int len; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, size); + + debug("asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", + cmd, value, index, size); + + len = usb_control_msg( + dev->pusb_dev, + usb_rcvctrlpipe(dev->pusb_dev, 0), + cmd, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + buf, + size, + USB_CTRL_GET_TIMEOUT); + + memcpy(data, buf, size); + + return len == size ? 0 : ECOMM; +} + +static int asix_read_mac(struct eth_device *eth) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + u8 buf[ETH_ALEN]; + + asix_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, 6, 6, buf); + debug("asix_read_mac() returning %02x:%02x:%02x:%02x:%02x:%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + memcpy(eth->enetaddr, buf, ETH_ALEN); + + return 0; +} + +static int asix_basic_reset(struct ueth_data *dev) +{ + struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv; + u8 buf[5]; + u16 *tmp16; + u8 *tmp; + + tmp16 = (u16 *)buf; + tmp = (u8 *)buf; + + /* Power up ethernet PHY */ + *tmp16 = 0; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + + *tmp16 = AX_PHYPWR_RSTCTL_IPRL; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); + mdelay(200); + + *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); + mdelay(200); + + /* RX bulk configuration */ + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); + asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + + dev_priv->rx_urb_size = 128 * 20; + + /* Water Level configuration */ + *tmp = 0x34; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); + + *tmp = 0x52; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, 1, 1, tmp); + + /* Enable checksum offload */ + *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); + + *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); + + /* Configure RX control register => start operation */ + *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); + + *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | + AX_MONITOR_MODE_RWMP; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); + + /* Configure default medium type => giga */ + *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | + AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX | + AX_MEDIUM_GIGAMODE | AX_MEDIUM_JUMBO_EN; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, 2, 2, tmp16); + + u16 adv = 0; + adv = ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_LPACK | + ADVERTISE_NPAGE | ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP; + asix_write_cmd(dev, AX_ACCESS_PHY, 0x03, MII_ADVERTISE, 2, &adv); + + adv = ADVERTISE_1000FULL; + asix_write_cmd(dev, AX_ACCESS_PHY, 0x03, MII_CTRL1000, 2, &adv); + + return 0; +} + +static int asix_wait_link(struct ueth_data *dev) +{ + int timeout = 0; + int link_detected; + u8 buf[2]; + u16 *tmp16; + + tmp16 = (u16 *)buf; + + do { + asix_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_BMSR, 2, buf); + link_detected = *tmp16 & BMSR_LSTATUS; + if (!link_detected) { + if (timeout == 0) + printf("Waiting for Ethernet connection... "); + mdelay(TIMEOUT_RESOLUTION); + timeout += TIMEOUT_RESOLUTION; + } + } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT); + + if (link_detected) { + if (timeout > 0) + printf("done.\n"); + return 0; + } else { + printf("unable to connect.\n"); + return -ENETUNREACH; + } +} + +/* + * Asix callbacks + */ +static int asix_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv; + u8 buf[2], tmp[5], link_sts; + u16 *tmp16, mode; + + + tmp16 = (u16 *)buf; + + debug("** %s()\n", __func__); + + /* Configure RX control register => start operation */ + *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; + if (asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16) != 0) + goto out_err; + + if (asix_wait_link(dev) != 0) { + /*reset device and try again*/ + printf("Reset Ethernet Device\n"); + asix_basic_reset(dev); + if (asix_wait_link(dev) != 0) + goto out_err; + } + + /* Configure link */ + mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | + AX_MEDIUM_RXFLOW_CTRLEN; + + asix_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS, + 1, 1, &link_sts); + + asix_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PHYSR, 2, tmp16); + + if (!(*tmp16 & GMII_PHY_PHYSR_LINK)) { + return 0; + } else if (GMII_PHY_PHYSR_GIGA == (*tmp16 & GMII_PHY_PHYSR_SMASK)) { + mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ | + AX_MEDIUM_JUMBO_EN; + + if (link_sts & AX_USB_SS) + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); + else if (link_sts & AX_USB_HS) + memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5); + else + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); + } else if (GMII_PHY_PHYSR_100 == (*tmp16 & GMII_PHY_PHYSR_SMASK)) { + mode |= AX_MEDIUM_PS; + + if (link_sts & (AX_USB_SS | AX_USB_HS)) + memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5); + else + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); + } else { + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); + } + + /* RX bulk configuration */ + asix_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); + + dev_priv->rx_urb_size = (1024 * (tmp[3] + 2)); + if (*tmp16 & GMII_PHY_PHYSR_FULL) + mode |= AX_MEDIUM_FULL_DUPLEX; + asix_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, + 2, 2, &mode); + + return 0; +out_err: + return -1; +} + +static int asix_send(struct eth_device *eth, void *packet, int length) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv; + + int err; + u32 packet_len, tx_hdr2; + int actual_len, framesize; + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg, + PKTSIZE + (2 * sizeof(packet_len))); + + debug("** %s(), len %d\n", __func__, length); + + packet_len = length; + cpu_to_le32s(&packet_len); + + memcpy(msg, &packet_len, sizeof(packet_len)); + framesize = dev_priv->maxpacketsize; + tx_hdr2 = 0; + if (((length + 8) % framesize) == 0) + tx_hdr2 |= 0x80008000; /* Enable padding */ + + cpu_to_le32s(&tx_hdr2); + + memcpy(msg + sizeof(packet_len), &tx_hdr2, sizeof(tx_hdr2)); + + memcpy(msg + sizeof(packet_len) + sizeof(tx_hdr2), + (void *)packet, length); + + err = usb_bulk_msg(dev->pusb_dev, + usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), + (void *)msg, + length + sizeof(packet_len) + sizeof(tx_hdr2), + &actual_len, + USB_BULK_SEND_TIMEOUT); + debug("Tx: len = %u, actual = %u, err = %d\n", + length + sizeof(packet_len), actual_len, err); + + return err; +} + +static int asix_recv(struct eth_device *eth) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct asix_private *dev_priv = (struct asix_private *)dev->dev_priv; + + u16 frame_pos; + int err; + int actual_len; + + int pkt_cnt; + u32 rx_hdr; + u16 hdr_off; + u32 *pkt_hdr; + ALLOC_CACHE_ALIGN_BUFFER(u8, recv_buf, dev_priv->rx_urb_size); + + actual_len = -1; + + debug("** %s()\n", __func__); + + err = usb_bulk_msg(dev->pusb_dev, + usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), + (void *)recv_buf, + dev_priv->rx_urb_size, + &actual_len, + USB_BULK_RECV_TIMEOUT); + debug("Rx: len = %u, actual = %u, err = %d\n", dev_priv->rx_urb_size, + actual_len, err); + + if (err != 0) { + debug("Rx: failed to receive\n"); + return -ECOMM; + } + if (actual_len > dev_priv->rx_urb_size) { + debug("Rx: received too many bytes %d\n", actual_len); + return -EMSGSIZE; + } + + + rx_hdr = *(u32 *)(recv_buf + actual_len - 4); + le32_to_cpus(&pkt_hdr); + + pkt_cnt = (u16)rx_hdr; + hdr_off = (u16)(rx_hdr >> 16); + pkt_hdr = (u32 *)(recv_buf + hdr_off); + + + frame_pos = 0; + + while (pkt_cnt--) { + u16 pkt_len; + + le32_to_cpus(pkt_hdr); + pkt_len = (*pkt_hdr >> 16) & 0x1fff; + + frame_pos += 2; + + NetReceive(recv_buf + frame_pos, pkt_len); + + pkt_hdr++; + frame_pos += ((pkt_len + 7) & 0xFFF8)-2; + + if (pkt_cnt == 0) + return 0; + } + return err; +} + +static void asix_halt(struct eth_device *eth) +{ + debug("** %s()\n", __func__); +} + +/* + * Asix probing functions + */ +void ax88179_eth_before_probe(void) +{ + curr_eth_dev = 0; +} + +struct asix_dongle { + unsigned short vendor; + unsigned short product; + int flags; +}; + +static const struct asix_dongle asix_dongles[] = { + { 0x0b95, 0x1790, FLAG_TYPE_AX88179 }, + { 0x0b95, 0x178a, FLAG_TYPE_AX88178a }, + { 0x2001, 0x4a00, FLAG_TYPE_DLINK_DUB1312 }, + { 0x0df6, 0x0072, FLAG_TYPE_SITECOM }, + { 0x04e8, 0xa100, FLAG_TYPE_SAMSUNG }, + { 0x17ef, 0x304b, FLAG_TYPE_LENOVO }, + { 0x0000, 0x0000, FLAG_NONE } /* END - Do not remove */ +}; + +/* Probe to see if a new device is actually an asix device */ +int ax88179_eth_probe(struct usb_device *dev, unsigned int ifnum, + struct ueth_data *ss) +{ + struct usb_interface *iface; + struct usb_interface_descriptor *iface_desc; + struct asix_private *dev_priv; + int ep_in_found = 0, ep_out_found = 0; + int i; + + /* let's examine the device now */ + iface = &dev->config.if_desc[ifnum]; + iface_desc = &dev->config.if_desc[ifnum].desc; + + for (i = 0; asix_dongles[i].vendor != 0; i++) { + if (dev->descriptor.idVendor == asix_dongles[i].vendor && + dev->descriptor.idProduct == asix_dongles[i].product) + /* Found a supported dongle */ + break; + } + + if (asix_dongles[i].vendor == 0) + return 0; + + memset(ss, 0, sizeof(struct ueth_data)); + + /* At this point, we know we've got a live one */ + debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n", + dev->descriptor.idVendor, dev->descriptor.idProduct); + + /* Initialize the ueth_data structure with some useful info */ + ss->ifnum = ifnum; + ss->pusb_dev = dev; + ss->subclass = iface_desc->bInterfaceSubClass; + ss->protocol = iface_desc->bInterfaceProtocol; + + /* alloc driver private */ + ss->dev_priv = calloc(1, sizeof(struct asix_private)); + if (!ss->dev_priv) + return 0; + dev_priv = ss->dev_priv; + dev_priv->flags = asix_dongles[i].flags; + + /* + * We are expecting a minimum of 3 endpoints - in, out (bulk), and + * int. We will ignore any others. + */ + for (i = 0; i < iface_desc->bNumEndpoints; i++) { + /* is it an interrupt endpoint? */ + if ((iface->ep_desc[i].bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { + ss->ep_int = iface->ep_desc[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + ss->irqinterval = iface->ep_desc[i].bInterval; + continue; + } + + /* is it an BULK endpoint? */ + if (!((iface->ep_desc[i].bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) + continue; + + u8 ep_addr = iface->ep_desc[i].bEndpointAddress; + if ((ep_addr & USB_DIR_IN) && !ep_in_found) { + ss->ep_in = ep_addr & + USB_ENDPOINT_NUMBER_MASK; + ep_in_found = 1; + } + if (!(ep_addr & USB_DIR_IN) && !ep_out_found) { + ss->ep_out = ep_addr & + USB_ENDPOINT_NUMBER_MASK; + dev_priv->maxpacketsize = + dev->epmaxpacketout[AX_ENDPOINT_OUT]; + ep_out_found = 1; + } + } + debug("Endpoints In %d Out %d Int %d\n", + ss->ep_in, ss->ep_out, ss->ep_int); + + /* Do some basic sanity checks, and bail if we find a problem */ + if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || + !ss->ep_in || !ss->ep_out || !ss->ep_int) { + debug("Problems with device\n"); + return 0; + } + dev->privptr = (void *)ss; + return 1; +} + +int ax88179_eth_get_info(struct usb_device *dev, struct ueth_data *ss, + struct eth_device *eth) +{ + if (!eth) { + debug("%s: missing parameter.\n", __func__); + return 0; + } + sprintf(eth->name, "%s%d", ASIX_BASE_NAME, curr_eth_dev++); + eth->init = asix_init; + eth->send = asix_send; + eth->recv = asix_recv; + eth->halt = asix_halt; + eth->priv = ss; + + if (asix_basic_reset(ss)) + return 0; + + /* Get the MAC address */ + if (asix_read_mac(eth)) + return 0; + debug("MAC %pM\n", eth->enetaddr); + + return 1; +} diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 1dda54c..7cb96e3 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -30,6 +30,13 @@ static const struct usb_eth_prob_dev prob_dev[] = { .get_info = asix_eth_get_info, }, #endif +#ifdef CONFIG_USB_ETHER_ASIX88179 + { + .before_probe = ax88179_eth_before_probe, + .probe = ax88179_eth_probe, + .get_info = ax88179_eth_get_info, + }, +#endif #ifdef CONFIG_USB_ETHER_MCS7830 { .before_probe = mcs7830_eth_before_probe, diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 12628ef..fbc74f3 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1062,7 +1062,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) if ((epstatus & epctrl) & USBA_RX_BK_RDY) { DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); receive_data(ep); - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); } } diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 16fc9dd..ead71eb 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -366,7 +366,7 @@ static int state_dfu_idle(struct f_dfu *f_dfu, to_runtime_mode(f_dfu); f_dfu->dfu_state = DFU_STATE_appIDLE; - dfu_trigger_detach(); + g_dnl_trigger_detach(); break; default: f_dfu->dfu_state = DFU_STATE_dfuERROR; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 71b62e5..310175a 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -480,6 +480,17 @@ static void cb_boot(struct usb_ep *ep, struct usb_request *req) fastboot_tx_write_str("OKAY"); } +static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req) +{ + g_dnl_trigger_detach(); +} + +static void cb_continue(struct usb_ep *ep, struct usb_request *req) +{ + fastboot_func->in_req->complete = do_exit_on_complete; + fastboot_tx_write_str("OKAY"); +} + #ifdef CONFIG_FASTBOOT_FLASH static void cb_flash(struct usb_ep *ep, struct usb_request *req) { @@ -520,6 +531,9 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { }, { .cmd = "boot", .cb = cb_boot, + }, { + .cmd = "continue", + .cb = cb_continue, }, #ifdef CONFIG_FASTBOOT_FLASH { diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index 78519fa..2d0410d 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -205,12 +205,24 @@ static long long int download_head(unsigned long long total, static int download_tail(long long int left, int cnt) { - struct dfu_entity *dfu_entity = dfu_get_entity(alt_setting_num); - void *transfer_buffer = dfu_get_buf(dfu_entity); + struct dfu_entity *dfu_entity; + void *transfer_buffer; int ret; debug("%s: left: %llu cnt: %d\n", __func__, left, cnt); + dfu_entity = dfu_get_entity(alt_setting_num); + if (!dfu_entity) { + error("Alt setting: %d entity not found!\n", alt_setting_num); + return -ENOENT; + } + + transfer_buffer = dfu_get_buf(dfu_entity); + if (!transfer_buffer) { + error("Transfer buffer not allocated!"); + return -ENXIO; + } + if (left) { ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++); if (ret) { diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index 25611ac..ee52a29 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -163,6 +163,23 @@ __weak int g_dnl_board_usb_cable_connected(void) return -EOPNOTSUPP; } +static bool g_dnl_detach_request; + +bool g_dnl_detach(void) +{ + return g_dnl_detach_request; +} + +void g_dnl_trigger_detach(void) +{ + g_dnl_detach_request = true; +} + +void g_dnl_clear_detach(void) +{ + g_dnl_detach_request = false; +} + static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; |