diff options
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/eth/asix.c | 41 | ||||
| -rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
| -rw-r--r-- | drivers/usb/gadget/composite.c | 4 | ||||
| -rw-r--r-- | drivers/usb/gadget/f_dfu.c | 13 | ||||
| -rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 11 | ||||
| -rw-r--r-- | drivers/usb/gadget/fotg210.c | 948 | ||||
| -rw-r--r-- | drivers/usb/gadget/g_dnl.c | 7 | ||||
| -rw-r--r-- | drivers/usb/gadget/gadget_chips.h | 8 | ||||
| -rw-r--r-- | drivers/usb/gadget/pxa25x_udc.c | 13 | ||||
| -rw-r--r-- | drivers/usb/gadget/pxa27x_udc.c | 14 | ||||
| -rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-faraday.c | 148 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 74 | ||||
| -rw-r--r-- | drivers/usb/musb-new/musb_uboot.c | 2 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_hcd.c | 3 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_udc.c | 3 | 
16 files changed, 1232 insertions, 59 deletions
| diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 75ec8f788..db39bd86f 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -407,46 +407,40 @@ static int asix_basic_reset(struct ueth_data *dev)  	rx_ctl = asix_read_rx_ctl(dev);  	debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); -	return 0; -} - -/* - * Asix callbacks - */ -static int asix_init(struct eth_device *eth, bd_t *bd) -{ -	struct ueth_data	*dev = (struct ueth_data *)eth->priv; -	int timeout = 0; -#define TIMEOUT_RESOLUTION 50	/* ms */ -	int link_detected; - -	debug("** %s()\n", __func__); -  	dev->phy_id = asix_get_phy_addr(dev);  	if (dev->phy_id < 0)  		debug("Failed to read phy id\n"); -	if (asix_sw_reset(dev, AX_SWRESET_PRL) < 0) -		goto out_err; - -	if (asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL) < 0) -		goto out_err; -  	asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);  	asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE,  			ADVERTISE_ALL | ADVERTISE_CSMA);  	mii_nway_restart(dev);  	if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0) -		goto out_err; +		return -1;  	if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0,  				AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,  				AX88772_IPG2_DEFAULT, 0, NULL) < 0) {  		debug("Write IPG,IPG1,IPG2 failed\n"); -		goto out_err; +		return -1;  	} +	return 0; +} + +/* + * Asix callbacks + */ +static int asix_init(struct eth_device *eth, bd_t *bd) +{ +	struct ueth_data	*dev = (struct ueth_data *)eth->priv; +	int timeout = 0; +#define TIMEOUT_RESOLUTION 50	/* ms */ +	int link_detected; + +	debug("** %s()\n", __func__); +  	if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0)  		goto out_err; @@ -591,6 +585,7 @@ struct asix_dongle {  static const struct asix_dongle const asix_dongles[] = {  	{ 0x05ac, 0x1402, FLAG_TYPE_AX88772 },	/* Apple USB Ethernet Adapter */  	{ 0x07d1, 0x3c05, FLAG_TYPE_AX88772 },	/* D-Link DUB-E100 H/W Ver B1 */ +	{ 0x2001, 0x1a02, FLAG_TYPE_AX88772 },	/* D-Link DUB-E100 H/W Ver C1 */  	/* Cables-to-Go USB Ethernet Adapter */  	{ 0x0b95, 0x772a, FLAG_TYPE_AX88772 },  	{ 0x0b95, 0x7720, FLAG_TYPE_AX88772 },	/* Trendnet TU2-ET100 V3.0R */ diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index e545b6be6..432cf178c 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -35,6 +35,7 @@ endif  # new USB gadget layer dependencies  ifdef CONFIG_USB_GADGET  COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o +COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o  COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o  COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o  endif diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 2c5600ed5..f8677931b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -997,7 +997,8 @@ static int composite_bind(struct usb_gadget *gadget)  	if (status < 0)  		goto fail; -	cdev->desc = *composite->dev; +	memcpy(&cdev->desc, composite->dev, +	       sizeof(struct usb_device_descriptor));  	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;  	debug("%s: ready\n", composite->name); @@ -1098,4 +1099,5 @@ void usb_composite_unregister(struct usb_composite_driver *driver)  	if (composite != driver)  		return;  	usb_gadget_unregister_driver(&composite_driver); +	composite = NULL;  } diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index a322ae5eb..d7ae0c0c6 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -5,6 +5,13 @@   * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com>   *          Lukasz Majewski <l.majewski@samsung.com>   * + * Based on OpenMoko u-boot: drivers/usb/usbdfu.c + * (C) 2007 by OpenMoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * + * based on existing SAM7DFU code from OpenPCD: + * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de> + *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by   * the Free Software Foundation; either version 2 of the License, or @@ -183,6 +190,7 @@ static inline void to_dfu_mode(struct f_dfu *f_dfu)  {  	f_dfu->usb_function.strings = dfu_strings;  	f_dfu->usb_function.hs_descriptors = f_dfu->function; +	f_dfu->dfu_state = DFU_STATE_dfuIDLE;  }  static inline void to_runtime_mode(struct f_dfu *f_dfu) @@ -233,7 +241,6 @@ static int state_app_idle(struct f_dfu *f_dfu,  	case USB_REQ_DFU_DETACH:  		f_dfu->dfu_state = DFU_STATE_appDETACH;  		to_dfu_mode(f_dfu); -		f_dfu->dfu_state = DFU_STATE_dfuIDLE;  		value = RET_ZLP;  		break;  	default: @@ -589,7 +596,7 @@ static int dfu_prepare_function(struct f_dfu *f_dfu, int n)  	struct usb_interface_descriptor *d;  	int i = 0; -	f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n); +	f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 1);  	if (!f_dfu->function)  		goto enomem; @@ -653,6 +660,8 @@ static int dfu_bind(struct usb_configuration *c, struct usb_function *f)  			->iInterface = id;  	} +	to_dfu_mode(f_dfu); +  	stringtab_dfu.strings = f_dfu->strings;  	cdev->req->context = f_dfu; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index c28866f7d..5b348d7a6 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -577,9 +577,9 @@ static int fsg_setup(struct usb_function *f,  {  	struct fsg_dev		*fsg = fsg_from_func(f);  	struct usb_request	*req = fsg->common->ep0req; -	u16			w_index = le16_to_cpu(ctrl->wIndex); -	u16			w_value = le16_to_cpu(ctrl->wValue); -	u16			w_length = le16_to_cpu(ctrl->wLength); +	u16			w_index = get_unaligned_le16(&ctrl->wIndex); +	u16			w_value = get_unaligned_le16(&ctrl->wValue); +	u16			w_length = get_unaligned_le16(&ctrl->wLength);  	if (!fsg_is_set(fsg->common))  		return -EOPNOTSUPP; @@ -617,7 +617,7 @@ static int fsg_setup(struct usb_function *f,  	     "unknown class-specific control req "  	     "%02x.%02x v%04x i%04x l%u\n",  	     ctrl->bRequestType, ctrl->bRequest, -	     le16_to_cpu(ctrl->wValue), w_index, w_length); +	     get_unaligned_le16(&ctrl->wValue), w_index, w_length);  	return -EOPNOTSUPP;  } @@ -2261,7 +2261,8 @@ reset:  	if (rc)  		goto reset;  	fsg->bulk_out_enabled = 1; -	common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); +	common->bulk_out_maxpacket = +				le16_to_cpu(get_unaligned(&d->wMaxPacketSize));  	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);  	/* Allocate the requests */ diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c new file mode 100644 index 000000000..d003331ba --- /dev/null +++ b/drivers/usb/gadget/fotg210.c @@ -0,0 +1,948 @@ +/* + * Faraday USB 2.0 OTG Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <command.h> +#include <config.h> +#include <net.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <linux/types.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#include <usb/fotg210.h> + +#define CFG_NUM_ENDPOINTS		4 +#define CFG_EP0_MAX_PACKET_SIZE	64 +#define CFG_EPX_MAX_PACKET_SIZE	512 + +#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */ + +struct fotg210_chip; + +struct fotg210_ep { +	struct usb_ep ep; + +	uint maxpacket; +	uint id; +	uint stopped; + +	struct list_head                      queue; +	struct fotg210_chip                  *chip; +	const struct usb_endpoint_descriptor *desc; +}; + +struct fotg210_request { +	struct usb_request req; +	struct list_head   queue; +	struct fotg210_ep *ep; +}; + +struct fotg210_chip { +	struct usb_gadget         gadget; +	struct usb_gadget_driver *driver; +	struct fotg210_regs      *regs; +	uint8_t                   irq; +	uint16_t                  addr; +	int                       pullup; +	enum usb_device_state     state; +	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS]; +}; + +static struct usb_endpoint_descriptor ep0_desc = { +	.bLength = sizeof(struct usb_endpoint_descriptor), +	.bDescriptorType = USB_DT_ENDPOINT, +	.bEndpointAddress = USB_DIR_IN, +	.bmAttributes = USB_ENDPOINT_XFER_CONTROL, +}; + +static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in) +{ +	return (id < 0) ? 0 : ((id & 0x03) + 1); +} + +static inline int ep_to_fifo(struct fotg210_chip *chip, int id) +{ +	return (id <= 0) ? -1 : ((id - 1) & 0x03); +} + +static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr) +{ +	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK; +	struct fotg210_regs *regs = chip->regs; + +	if (ep_addr & USB_DIR_IN) { +		/* reset endpoint */ +		setbits_le32(®s->iep[ep - 1], IEP_RESET); +		mdelay(1); +		clrbits_le32(®s->iep[ep - 1], IEP_RESET); +		/* clear endpoint stall */ +		clrbits_le32(®s->iep[ep - 1], IEP_STALL); +	} else { +		/* reset endpoint */ +		setbits_le32(®s->oep[ep - 1], OEP_RESET); +		mdelay(1); +		clrbits_le32(®s->oep[ep - 1], OEP_RESET); +		/* clear endpoint stall */ +		clrbits_le32(®s->oep[ep - 1], OEP_STALL); +	} + +	return 0; +} + +static int fotg210_reset(struct fotg210_chip *chip) +{ +	struct fotg210_regs *regs = chip->regs; +	uint32_t i; + +	chip->state = USB_STATE_POWERED; + +	/* chip enable */ +	writel(DEVCTRL_EN, ®s->dev_ctrl); + +	/* device address reset */ +	chip->addr = 0; +	writel(0, ®s->dev_addr); + +	/* set idle counter to 7ms */ +	writel(7, ®s->idle); + +	/* disable all interrupts */ +	writel(IMR_MASK, ®s->imr); +	writel(GIMR_MASK, ®s->gimr); +	writel(GIMR0_MASK, ®s->gimr0); +	writel(GIMR1_MASK, ®s->gimr1); +	writel(GIMR2_MASK, ®s->gimr2); + +	/* clear interrupts */ +	writel(ISR_MASK, ®s->isr); +	writel(0, ®s->gisr); +	writel(0, ®s->gisr0); +	writel(0, ®s->gisr1); +	writel(0, ®s->gisr2); + +	/* chip reset */ +	setbits_le32(®s->dev_ctrl, DEVCTRL_RESET); +	mdelay(10); +	if (readl(®s->dev_ctrl) & DEVCTRL_RESET) { +		printf("fotg210: chip reset failed\n"); +		return -1; +	} + +	/* CX FIFO reset */ +	setbits_le32(®s->cxfifo, CXFIFO_CXFIFOCLR); +	mdelay(10); +	if (readl(®s->cxfifo) & CXFIFO_CXFIFOCLR) { +		printf("fotg210: ep0 fifo reset failed\n"); +		return -1; +	} + +	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */ +	writel(EPMAP14_DEFAULT, ®s->epmap14); +	writel(EPMAP58_DEFAULT, ®s->epmap58); +	writel(FIFOMAP_DEFAULT, ®s->fifomap); +	writel(0, ®s->fifocfg); +	for (i = 0; i < 8; ++i) { +		writel(CFG_EPX_MAX_PACKET_SIZE, ®s->iep[i]); +		writel(CFG_EPX_MAX_PACKET_SIZE, ®s->oep[i]); +	} + +	/* FIFO reset */ +	for (i = 0; i < 4; ++i) { +		writel(FIFOCSR_RESET, ®s->fifocsr[i]); +		mdelay(10); +		if (readl(®s->fifocsr[i]) & FIFOCSR_RESET) { +			printf("fotg210: fifo%d reset failed\n", i); +			return -1; +		} +	} + +	/* enable only device interrupt and triggered at level-high */ +	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, ®s->imr); +	writel(ISR_MASK, ®s->isr); +	/* disable EP0 IN/OUT interrupt */ +	writel(GIMR0_CXOUT | GIMR0_CXIN, ®s->gimr0); +	/* disable EPX IN+SPK+OUT interrupts */ +	writel(GIMR1_MASK, ®s->gimr1); +	/* disable wakeup+idle+dma+zlp interrupts */ +	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN +		| GIMR2_ZLPRX | GIMR2_ZLPTX, ®s->gimr2); +	/* enable all group interrupt */ +	writel(0, ®s->gimr); + +	/* suspend delay = 3 ms */ +	writel(3, ®s->idle); + +	/* turn-on device interrupts */ +	setbits_le32(®s->dev_ctrl, DEVCTRL_GIRQ_EN); + +	return 0; +} + +static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask) +{ +	struct fotg210_regs *regs = chip->regs; +	int ret = -1; +	ulong ts; + +	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +		if ((readl(®s->cxfifo) & mask) != mask) +			continue; +		ret = 0; +		break; +	} + +	if (ret) +		printf("fotg210: cx/ep0 timeout\n"); + +	return ret; +} + +static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req) +{ +	struct fotg210_chip *chip = ep->chip; +	struct fotg210_regs *regs = chip->regs; +	uint32_t tmp, ts; +	uint8_t *buf  = req->req.buf + req->req.actual; +	uint32_t len  = req->req.length - req->req.actual; +	int fifo = ep_to_fifo(chip, ep->id); +	int ret = -EBUSY; + +	/* 1. init dma buffer */ +	if (len > ep->maxpacket) +		len = ep->maxpacket; + +	/* 2. wait for dma ready (hardware) */ +	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +		if (!(readl(®s->dma_ctrl) & DMACTRL_START)) { +			ret = 0; +			break; +		} +	} +	if (ret) { +		printf("fotg210: dma busy\n"); +		req->req.status = ret; +		return ret; +	} + +	/* 3. DMA target setup */ +	if (ep->desc->bEndpointAddress & USB_DIR_IN) +		flush_dcache_range((ulong)buf, (ulong)buf + len); +	else +		invalidate_dcache_range((ulong)buf, (ulong)buf + len); + +	writel(virt_to_phys(buf), ®s->dma_addr); + +	if (ep->desc->bEndpointAddress & USB_DIR_IN) { +		if (ep->id == 0) { +			/* Wait until cx/ep0 fifo empty */ +			fotg210_cxwait(chip, CXFIFO_CXFIFOE); +			writel(DMAFIFO_CX, ®s->dma_fifo); +		} else { +			/* Wait until epx fifo empty */ +			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo)); +			writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); +		} +		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, ®s->dma_ctrl); +	} else { +		uint32_t blen; + +		if (ep->id == 0) { +			writel(DMAFIFO_CX, ®s->dma_fifo); +			do { +				blen = CXFIFO_BYTES(readl(®s->cxfifo)); +			} while (blen < len); +		} else { +			writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); +			blen = FIFOCSR_BYTES(readl(®s->fifocsr[fifo])); +		} +		len  = (len < blen) ? len : blen; +		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, ®s->dma_ctrl); +	} + +	/* 4. DMA start */ +	setbits_le32(®s->dma_ctrl, DMACTRL_START); + +	/* 5. DMA wait */ +	ret = -EBUSY; +	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +		tmp = readl(®s->gisr2); +		/* DMA complete */ +		if (tmp & GISR2_DMAFIN) { +			ret = 0; +			break; +		} +		/* DMA error */ +		if (tmp & GISR2_DMAERR) { +			printf("fotg210: dma error\n"); +			break; +		} +		/* resume, suspend, reset */ +		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) { +			printf("fotg210: dma reset by host\n"); +			break; +		} +	} + +	/* 7. DMA target reset */ +	if (ret) +		writel(DMACTRL_ABORT | DMACTRL_CLRFF, ®s->dma_ctrl); + +	writel(0, ®s->gisr2); +	writel(0, ®s->dma_fifo); + +	req->req.status = ret; +	if (!ret) +		req->req.actual += len; +	else +		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret); + +	return len; +} + +/* + * result of setup packet + */ +#define CX_IDLE		0 +#define CX_FINISH	1 +#define CX_STALL	2 + +static void fotg210_setup(struct fotg210_chip *chip) +{ +	int id, ret = CX_IDLE; +	uint32_t tmp[2]; +	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp; +	struct fotg210_regs *regs = chip->regs; + +	/* +	 * If this is the first Cx 8 byte command, +	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0) +	 */ +	if (chip->state == USB_STATE_POWERED) { +		chip->state = USB_STATE_DEFAULT; +		if (readl(®s->otgcsr) & OTGCSR_DEV_B) { +			/* Mini-B */ +			if (readl(®s->dev_ctrl) & DEVCTRL_HS) { +				puts("fotg210: HS\n"); +				chip->gadget.speed = USB_SPEED_HIGH; +				/* SOF mask timer = 1100 ticks */ +				writel(SOFMTR_TMR(1100), ®s->sof_mtr); +			} else { +				puts("fotg210: FS\n"); +				chip->gadget.speed = USB_SPEED_FULL; +				/* SOF mask timer = 10000 ticks */ +				writel(SOFMTR_TMR(10000), ®s->sof_mtr); +			} +		} else { +			printf("fotg210: mini-A?\n"); +		} +	} + +	/* switch data port to ep0 */ +	writel(DMAFIFO_CX, ®s->dma_fifo); +	/* fetch 8 bytes setup packet */ +	tmp[0] = readl(®s->ep0_data); +	tmp[1] = readl(®s->ep0_data); +	/* release data port */ +	writel(0, ®s->dma_fifo); + +	if (req->bRequestType & USB_DIR_IN) +		ep0_desc.bEndpointAddress = USB_DIR_IN; +	else +		ep0_desc.bEndpointAddress = USB_DIR_OUT; + +	ret = CX_IDLE; + +	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { +		switch (req->bRequest) { +		case USB_REQ_SET_CONFIGURATION: +			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF); +			if (!(req->wValue & 0x00FF)) { +				chip->state = USB_STATE_ADDRESS; +				writel(chip->addr, ®s->dev_addr); +			} else { +				chip->state = USB_STATE_CONFIGURED; +				writel(chip->addr | DEVADDR_CONF, +					®s->dev_addr); +			} +			ret = CX_IDLE; +			break; + +		case USB_REQ_SET_ADDRESS: +			debug("fotg210: set_addr(0x%04X)\n", req->wValue); +			chip->state = USB_STATE_ADDRESS; +			chip->addr  = req->wValue & DEVADDR_ADDR_MASK; +			ret = CX_FINISH; +			writel(chip->addr, ®s->dev_addr); +			break; + +		case USB_REQ_CLEAR_FEATURE: +			debug("fotg210: clr_feature(%d, %d)\n", +				req->bRequestType & 0x03, req->wValue); +			switch (req->wValue) { +			case 0:    /* [Endpoint] halt */ +				ep_reset(chip, req->wIndex); +				ret = CX_FINISH; +				break; +			case 1:    /* [Device] remote wake-up */ +			case 2:    /* [Device] test mode */ +			default: +				ret = CX_STALL; +				break; +			} +			break; + +		case USB_REQ_SET_FEATURE: +			debug("fotg210: set_feature(%d, %d)\n", +				req->wValue, req->wIndex & 0xf); +			switch (req->wValue) { +			case 0:    /* Endpoint Halt */ +				id = req->wIndex & 0xf; +				setbits_le32(®s->iep[id - 1], IEP_STALL); +				setbits_le32(®s->oep[id - 1], OEP_STALL); +				ret = CX_FINISH; +				break; +			case 1:    /* Remote Wakeup */ +			case 2:    /* Test Mode */ +			default: +				ret = CX_STALL; +				break; +			} +			break; + +		case USB_REQ_GET_STATUS: +			debug("fotg210: get_status\n"); +			ret = CX_STALL; +			break; + +		case USB_REQ_SET_DESCRIPTOR: +			debug("fotg210: set_descriptor\n"); +			ret = CX_STALL; +			break; + +		case USB_REQ_SYNCH_FRAME: +			debug("fotg210: sync frame\n"); +			ret = CX_STALL; +			break; +		} +	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */ + +	if (ret == CX_IDLE && chip->driver->setup) { +		if (chip->driver->setup(&chip->gadget, req) < 0) +			ret = CX_STALL; +		else +			ret = CX_FINISH; +	} + +	switch (ret) { +	case CX_FINISH: +		setbits_le32(®s->cxfifo, CXFIFO_CXFIN); +		break; + +	case CX_STALL: +		setbits_le32(®s->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN); +		printf("fotg210: cx_stall!\n"); +		break; + +	case CX_IDLE: +		debug("fotg210: cx_idle?\n"); +	default: +		break; +	} +} + +/* + * fifo - FIFO id + * zlp  - zero length packet + */ +static void fotg210_recv(struct fotg210_chip *chip, int ep_id) +{ +	struct fotg210_regs *regs = chip->regs; +	struct fotg210_ep *ep = chip->ep + ep_id; +	struct fotg210_request *req; +	int len; + +	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) { +		printf("fotg210: ep%d recv, invalid!\n", ep->id); +		return; +	} + +	if (list_empty(&ep->queue)) { +		printf("fotg210: ep%d recv, drop!\n", ep->id); +		return; +	} + +	req = list_first_entry(&ep->queue, struct fotg210_request, queue); +	len = fotg210_dma(ep, req); +	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) { +		list_del_init(&req->queue); +		if (req->req.complete) +			req->req.complete(&ep->ep, &req->req); +	} + +	if (ep->id > 0 && list_empty(&ep->queue)) { +		setbits_le32(®s->gimr1, +			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); +	} +} + +/* + * USB Gadget Layer + */ +static int fotg210_ep_enable( +	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ +	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); +	struct fotg210_chip *chip = ep->chip; +	struct fotg210_regs *regs = chip->regs; +	int id = ep_to_fifo(chip, ep->id); +	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0; + +	if (!_ep || !desc +		|| desc->bDescriptorType != USB_DT_ENDPOINT +		|| le16_to_cpu(desc->wMaxPacketSize) == 0) { +		printf("fotg210: bad ep or descriptor\n"); +		return -EINVAL; +	} + +	ep->desc = desc; +	ep->stopped = 0; + +	if (in) +		setbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_IN)); + +	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { +	case USB_ENDPOINT_XFER_CONTROL: +		return -EINVAL; + +	case USB_ENDPOINT_XFER_ISOC: +		setbits_le32(®s->fifocfg, +			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC)); +		break; + +	case USB_ENDPOINT_XFER_BULK: +		setbits_le32(®s->fifocfg, +			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK)); +		break; + +	case USB_ENDPOINT_XFER_INT: +		setbits_le32(®s->fifocfg, +			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR)); +		break; +	} + +	return 0; +} + +static int fotg210_ep_disable(struct usb_ep *_ep) +{ +	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); +	struct fotg210_chip *chip = ep->chip; +	struct fotg210_regs *regs = chip->regs; +	int id = ep_to_fifo(chip, ep->id); + +	ep->desc = NULL; +	ep->stopped = 1; + +	clrbits_le32(®s->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK)); +	clrbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK)); + +	return 0; +} + +static struct usb_request *fotg210_ep_alloc_request( +	struct usb_ep *_ep, gfp_t gfp_flags) +{ +	struct fotg210_request *req = malloc(sizeof(*req)); + +	if (req) { +		memset(req, 0, sizeof(*req)); +		INIT_LIST_HEAD(&req->queue); +	} +	return &req->req; +} + +static void fotg210_ep_free_request( +	struct usb_ep *_ep, struct usb_request *_req) +{ +	struct fotg210_request *req; + +	req = container_of(_req, struct fotg210_request, req); +	free(req); +} + +static int fotg210_ep_queue( +	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ +	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); +	struct fotg210_chip *chip = ep->chip; +	struct fotg210_regs *regs = chip->regs; +	struct fotg210_request *req; + +	req = container_of(_req, struct fotg210_request, req); +	if (!_req || !_req->complete || !_req->buf +		|| !list_empty(&req->queue)) { +		printf("fotg210: invalid request to ep%d\n", ep->id); +		return -EINVAL; +	} + +	if (!chip || chip->state == USB_STATE_SUSPENDED) { +		printf("fotg210: request while chip suspended\n"); +		return -EINVAL; +	} + +	req->req.actual = 0; +	req->req.status = -EINPROGRESS; + +	if (req->req.length == 0) { +		req->req.status = 0; +		if (req->req.complete) +			req->req.complete(&ep->ep, &req->req); +		return 0; +	} + +	if (ep->id == 0) { +		do { +			int len = fotg210_dma(ep, req); +			if (len < ep->ep.maxpacket) +				break; +			if (ep->desc->bEndpointAddress & USB_DIR_IN) +				udelay(100); +		} while (req->req.length > req->req.actual); +	} else { +		if (ep->desc->bEndpointAddress & USB_DIR_IN) { +			do { +				int len = fotg210_dma(ep, req); +				if (len < ep->ep.maxpacket) +					break; +			} while (req->req.length > req->req.actual); +		} else { +			list_add_tail(&req->queue, &ep->queue); +			clrbits_le32(®s->gimr1, +				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); +		} +	} + +	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) { +		if (req->req.complete) +			req->req.complete(&ep->ep, &req->req); +	} + +	return 0; +} + +static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); +	struct fotg210_request *req; + +	/* make sure it's actually queued on this endpoint */ +	list_for_each_entry(req, &ep->queue, queue) { +		if (&req->req == _req) +			break; +	} +	if (&req->req != _req) +		return -EINVAL; + +	/* remove the request */ +	list_del_init(&req->queue); + +	/* update status & invoke complete callback */ +	if (req->req.status == -EINPROGRESS) { +		req->req.status = -ECONNRESET; +		if (req->req.complete) +			req->req.complete(_ep, &req->req); +	} + +	return 0; +} + +static int fotg210_ep_halt(struct usb_ep *_ep, int halt) +{ +	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); +	struct fotg210_chip *chip = ep->chip; +	struct fotg210_regs *regs = chip->regs; +	int ret = -1; + +	debug("fotg210: ep%d halt=%d\n", ep->id, halt); + +	/* Endpoint STALL */ +	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) { +		if (halt) { +			/* wait until all ep fifo empty */ +			fotg210_cxwait(chip, 0xf00); +			/* stall */ +			if (ep->desc->bEndpointAddress & USB_DIR_IN) { +				setbits_le32(®s->iep[ep->id - 1], +					IEP_STALL); +			} else { +				setbits_le32(®s->oep[ep->id - 1], +					OEP_STALL); +			} +		} else { +			if (ep->desc->bEndpointAddress & USB_DIR_IN) { +				clrbits_le32(®s->iep[ep->id - 1], +					IEP_STALL); +			} else { +				clrbits_le32(®s->oep[ep->id - 1], +					OEP_STALL); +			} +		} +		ret = 0; +	} + +	return ret; +} + +/* + * activate/deactivate link with host. + */ +static void pullup(struct fotg210_chip *chip, int is_on) +{ +	struct fotg210_regs *regs = chip->regs; + +	if (is_on) { +		if (!chip->pullup) { +			chip->state = USB_STATE_POWERED; +			chip->pullup = 1; +			/* enable the chip */ +			setbits_le32(®s->dev_ctrl, DEVCTRL_EN); +			/* clear unplug bit (BIT0) */ +			clrbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); +		} +	} else { +		chip->state = USB_STATE_NOTATTACHED; +		chip->pullup = 0; +		chip->addr = 0; +		writel(chip->addr, ®s->dev_addr); +		/* set unplug bit (BIT0) */ +		setbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); +		/* disable the chip */ +		clrbits_le32(®s->dev_ctrl, DEVCTRL_EN); +	} +} + +static int fotg210_pullup(struct usb_gadget *_gadget, int is_on) +{ +	struct fotg210_chip *chip; + +	chip = container_of(_gadget, struct fotg210_chip, gadget); + +	debug("fotg210: pullup=%d\n", is_on); + +	pullup(chip, is_on); + +	return 0; +} + +static int fotg210_get_frame(struct usb_gadget *_gadget) +{ +	struct fotg210_chip *chip; +	struct fotg210_regs *regs; + +	chip = container_of(_gadget, struct fotg210_chip, gadget); +	regs = chip->regs; + +	return SOFFNR_FNR(readl(®s->sof_fnr)); +} + +static struct usb_gadget_ops fotg210_gadget_ops = { +	.get_frame = fotg210_get_frame, +	.pullup = fotg210_pullup, +}; + +static struct usb_ep_ops fotg210_ep_ops = { +	.enable         = fotg210_ep_enable, +	.disable        = fotg210_ep_disable, +	.queue          = fotg210_ep_queue, +	.dequeue        = fotg210_ep_dequeue, +	.set_halt       = fotg210_ep_halt, +	.alloc_request  = fotg210_ep_alloc_request, +	.free_request   = fotg210_ep_free_request, +}; + +static struct fotg210_chip controller = { +	.regs = (void __iomem *)CONFIG_FOTG210_BASE, +	.gadget = { +		.name = "fotg210_udc", +		.ops = &fotg210_gadget_ops, +		.ep0 = &controller.ep[0].ep, +		.speed = USB_SPEED_UNKNOWN, +		.is_dualspeed = 1, +		.is_otg = 0, +		.is_a_peripheral = 0, +		.b_hnp_enable = 0, +		.a_hnp_support = 0, +		.a_alt_hnp_support = 0, +	}, +	.ep[0] = { +		.id = 0, +		.ep = { +			.name  = "ep0", +			.ops   = &fotg210_ep_ops, +		}, +		.desc      = &ep0_desc, +		.chip      = &controller, +		.maxpacket = CFG_EP0_MAX_PACKET_SIZE, +	}, +	.ep[1] = { +		.id = 1, +		.ep = { +			.name  = "ep1", +			.ops   = &fotg210_ep_ops, +		}, +		.chip      = &controller, +		.maxpacket = CFG_EPX_MAX_PACKET_SIZE, +	}, +	.ep[2] = { +		.id = 2, +		.ep = { +			.name  = "ep2", +			.ops   = &fotg210_ep_ops, +		}, +		.chip      = &controller, +		.maxpacket = CFG_EPX_MAX_PACKET_SIZE, +	}, +	.ep[3] = { +		.id = 3, +		.ep = { +			.name  = "ep3", +			.ops   = &fotg210_ep_ops, +		}, +		.chip      = &controller, +		.maxpacket = CFG_EPX_MAX_PACKET_SIZE, +	}, +	.ep[4] = { +		.id = 4, +		.ep = { +			.name  = "ep4", +			.ops   = &fotg210_ep_ops, +		}, +		.chip      = &controller, +		.maxpacket = CFG_EPX_MAX_PACKET_SIZE, +	}, +}; + +int usb_gadget_handle_interrupts(void) +{ +	struct fotg210_chip *chip = &controller; +	struct fotg210_regs *regs = chip->regs; +	uint32_t id, st, isr, gisr; + +	isr  = readl(®s->isr) & (~readl(®s->imr)); +	gisr = readl(®s->gisr) & (~readl(®s->gimr)); +	if (!(isr & ISR_DEV) || !gisr) +		return 0; + +	writel(ISR_DEV, ®s->isr); + +	/* CX interrupts */ +	if (gisr & GISR_GRP0) { +		st = readl(®s->gisr0); +		writel(0, ®s->gisr0); + +		if (st & GISR0_CXERR) +			printf("fotg210: cmd error\n"); + +		if (st & GISR0_CXABORT) +			printf("fotg210: cmd abort\n"); + +		if (st & GISR0_CXSETUP)    /* setup */ +			fotg210_setup(chip); +		else if (st & GISR0_CXEND) /* command finish */ +			setbits_le32(®s->cxfifo, CXFIFO_CXFIN); +	} + +	/* FIFO interrupts */ +	if (gisr & GISR_GRP1) { +		st = readl(®s->gisr1); +		for (id = 0; id < 4; ++id) { +			if (st & GISR1_RX_FIFO(id)) +				fotg210_recv(chip, fifo_to_ep(chip, id, 0)); +		} +	} + +	/* Device Status Interrupts */ +	if (gisr & GISR_GRP2) { +		st = readl(®s->gisr2); +		writel(0, ®s->gisr2); + +		if (st & GISR2_RESET) +			printf("fotg210: reset by host\n"); +		else if (st & GISR2_SUSPEND) +			printf("fotg210: suspend/removed\n"); +		else if (st & GISR2_RESUME) +			printf("fotg210: resume\n"); + +		/* Errors */ +		if (st & GISR2_ISOCERR) +			printf("fotg210: iso error\n"); +		if (st & GISR2_ISOCABT) +			printf("fotg210: iso abort\n"); +		if (st & GISR2_DMAERR) +			printf("fotg210: dma error\n"); +	} + +	return 0; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ +	int i, ret = 0; +	struct fotg210_chip *chip = &controller; + +	if (!driver    || !driver->bind || !driver->setup) { +		puts("fotg210: bad parameter.\n"); +		return -EINVAL; +	} + +	INIT_LIST_HEAD(&chip->gadget.ep_list); +	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) { +		struct fotg210_ep *ep = chip->ep + i; + +		ep->ep.maxpacket = ep->maxpacket; +		INIT_LIST_HEAD(&ep->queue); + +		if (ep->id == 0) { +			ep->stopped = 0; +		} else { +			ep->stopped = 1; +			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list); +		} +	} + +	if (fotg210_reset(chip)) { +		puts("fotg210: reset failed.\n"); +		return -EINVAL; +	} + +	ret = driver->bind(&chip->gadget); +	if (ret) { +		debug("fotg210: driver->bind() returned %d\n", ret); +		return ret; +	} +	chip->driver = driver; + +	return ret; +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ +	struct fotg210_chip *chip = &controller; + +	driver->unbind(&chip->gadget); +	chip->driver = NULL; + +	pullup(chip, 0); + +	return 0; +} diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index cc3f3449c..8a3777b6e 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -125,6 +125,12 @@ static int g_dnl_config_register(struct usb_composite_dev *cdev)  	return usb_add_config(cdev, &config);  } +__weak +int g_dnl_bind_fixup(struct usb_device_descriptor *dev) +{ +	return 0; +} +  static int g_dnl_bind(struct usb_composite_dev *cdev)  {  	struct usb_gadget *gadget = cdev->gadget; @@ -147,6 +153,7 @@ static int g_dnl_bind(struct usb_composite_dev *cdev)  	g_dnl_string_defs[1].id = id;  	device_desc.iProduct = id; +	g_dnl_bind_fixup(&device_desc);  	ret = g_dnl_config_register(cdev);  	if (ret)  		goto error; diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index e5701422f..f038747e6 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -150,6 +150,12 @@  #define gadget_is_mv(g)        0  #endif +#ifdef CONFIG_USB_GADGET_FOTG210 +#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name)) +#else +#define gadget_is_fotg210(g)        0 +#endif +  /*   * CONFIG_USB_GADGET_SX2   * CONFIG_USB_GADGET_AU1X00 @@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)  		return 0x20;  	else if (gadget_is_mv(gadget))  		return 0x21; +	else if (gadget_is_fotg210(gadget)) +		return 0x22;  	return -ENOENT;  } diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 9ce98f076..085503dbe 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -314,7 +314,8 @@ static int pxa25x_ep_enable(struct usb_ep *_ep,  	if (!_ep || !desc || ep->desc || _ep->name == ep0name  			|| desc->bDescriptorType != USB_DT_ENDPOINT  			|| ep->bEndpointAddress != desc->bEndpointAddress -			|| ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { +			|| ep->fifo_size < +			   le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) {  		printf("%s, bad ep or descriptor\n", __func__);  		return -EINVAL;  	} @@ -329,9 +330,9 @@ static int pxa25x_ep_enable(struct usb_ep *_ep,  	/* hardware _could_ do smaller, but driver doesn't */  	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK -				&& le16_to_cpu(desc->wMaxPacketSize) +			&& le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))  						!= BULK_FIFO_SIZE) -			|| !desc->wMaxPacketSize) { +			|| !get_unaligned(&desc->wMaxPacketSize)) {  		printf("%s, bad %s maxpacket\n", __func__, _ep->name);  		return -ERANGE;  	} @@ -345,7 +346,7 @@ static int pxa25x_ep_enable(struct usb_ep *_ep,  	ep->desc = desc;  	ep->stopped = 0;  	ep->pio_irqs = 0; -	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); +	ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));  	/* flush fifo (mostly for OUT buffers) */  	pxa25x_ep_fifo_flush(_ep); @@ -485,7 +486,7 @@ write_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req)  {  	unsigned max; -	max = le16_to_cpu(ep->desc->wMaxPacketSize); +	max = le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize));  	do {  		unsigned count;  		int is_last, is_short; @@ -766,7 +767,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)  	 */  	if (unlikely(ep->bmAttributes == USB_ENDPOINT_XFER_ISOC  			&& req->req.length > -			le16_to_cpu(ep->desc->wMaxPacketSize))) +			le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize))))  		return -EMSGSIZE;  	debug_cond(NOISY, "%s queue req %p, len %d buf %p\n", diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 71cc0f2a0..598923dfc 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -151,7 +151,7 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)  	struct urb *urb = endpoint->rcv_urb;  	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;  	u32 *data32 = (u32 *) urb->buffer; -	unsigned int i, n, is_short ; +	unsigned int i, n;  	usbdbg("read urb on ep %d", ep_num);  #if defined(USBDDBG) && defined(USBDPARANOIA) @@ -165,9 +165,8 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint)  		n = readl(UDCBCN(ep_num)) & 0x3ff;  	else /* zlp */  		n = 0; -	is_short = n != endpoint->rcv_packetSize; -	usbdbg("n %d%s", n, is_short ? "-s" : ""); +	usbdbg("n %d%s", n, n != endpoint->rcv_packetSize ? "-s" : "");  	for (i = 0; i < n; i += 4)  		data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num)); @@ -402,16 +401,13 @@ static void udc_handle_ep(struct usb_endpoint_instance *endpoint)  static void udc_state_changed(void)  { -	int config, interface, alternate;  	writel(readl(UDCCR) | UDCCR_SMAC, UDCCR); -	config = (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S; -	interface = (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S; -	alternate = (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S; -  	usbdbg("New UDC settings are: conf %d - inter %d - alter %d", -		config, interface, alternate); +	       (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S, +	       (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S, +	       (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S);  	usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);  	writel(UDCISR1_IRCC, UDCISR1); diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 87a59704d..98f2a104b 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o  else  COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o  endif +COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o  COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o  COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o  COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c new file mode 100644 index 000000000..86add36ce --- /dev/null +++ b/drivers/usb/host/ehci-faraday.c @@ -0,0 +1,148 @@ +/* + * Faraday USB 2.0 EHCI Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <asm/io.h> +#include <usb.h> +#include <usb/fusbh200.h> +#include <usb/fotg210.h> + +#include "ehci.h" + +#ifndef CONFIG_USB_EHCI_BASE_LIST +#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE } +#endif + +union ehci_faraday_regs { +	struct fusbh200_regs usb; +	struct fotg210_regs  otg; +}; + +static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs) +{ +	return !readl(®s->usb.easstr); +} + +/* + * Create the appropriate control structures to manage + * a new EHCI host controller. + */ +int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr, +		struct ehci_hcor **ret_hcor) +{ +	struct ehci_hccr *hccr; +	struct ehci_hcor *hcor; +	union ehci_faraday_regs *regs; +	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST; + +	if (index < 0 || index >= ARRAY_SIZE(base_list)) +		return -1; +	regs = (void __iomem *)base_list[index]; +	hccr = (struct ehci_hccr *)®s->usb.hccr; +	hcor = (struct ehci_hcor *)®s->usb.hcor; + +	if (ehci_is_fotg2xx(regs)) { +		/* A-device bus reset */ +		/* ... Power off A-device */ +		setbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSDROP); +		/* ... Drop vbus and bus traffic */ +		clrbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSREQ); +		mdelay(1); +		/* ... Power on A-device */ +		clrbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSDROP); +		/* ... Drive vbus and bus traffic */ +		setbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSREQ); +		mdelay(1); +		/* Disable OTG & DEV interrupts, triggered at level-high */ +		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, ®s->otg.imr); +		/* Clear all interrupt status */ +		writel(ISR_HOST | ISR_OTG | ISR_DEV, ®s->otg.isr); +	} else { +		/* Interrupt=level-high */ +		setbits_le32(®s->usb.bmcsr, BMCSR_IRQLH); +		/* VBUS on */ +		clrbits_le32(®s->usb.bmcsr, BMCSR_VBUS_OFF); +		/* Disable all interrupts */ +		writel(0x00, ®s->usb.bmier); +		writel(0x1f, ®s->usb.bmisr); +	} + +	*ret_hccr = hccr; +	*ret_hcor = hcor; + +	return 0; +} + +/* + * Destroy the appropriate control structures corresponding + * the the EHCI host controller. + */ +int ehci_hcd_stop(int index) +{ +	return 0; +} + +/* + * This ehci_set_usbmode() overrides the weak function + * in "ehci-hcd.c". + */ +void ehci_set_usbmode(int index) +{ +	/* nothing needs to be done */ +} + +/* + * This ehci_get_port_speed() overrides the weak function + * in "ehci-hcd.c". + */ +int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) +{ +	int spd, ret = PORTSC_PSPD_HS; +	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10); + +	if (ehci_is_fotg2xx(regs)) +		spd = OTGCSR_SPD(readl(®s->otg.otgcsr)); +	else +		spd = BMCSR_SPD(readl(®s->usb.bmcsr)); + +	switch (spd) { +	case 0:    /* full speed */ +		ret = PORTSC_PSPD_FS; +		break; +	case 1:    /* low  speed */ +		ret = PORTSC_PSPD_LS; +		break; +	case 2:    /* high speed */ +		ret = PORTSC_PSPD_HS; +		break; +	default: +		printf("ehci-faraday: invalid device speed\n"); +		break; +	} + +	return ret; +} + +/* + * This ehci_get_portsc_register() overrides the weak function + * in "ehci-hcd.c". + */ +uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port) +{ +	/* Faraday EHCI has one and only one portsc register */ +	if (port) { +		/* Printing the message would cause a scan failure! */ +		debug("The request port(%d) is not configured\n", port); +		return NULL; +	} + +	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */ +	return (uint32_t *)((uint8_t *)hcor + 0x20); +} diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e0f3e4b6c..706cf0cb7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -589,10 +589,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);  	} else {  		dev->act_len = 0; +#ifndef CONFIG_USB_EHCI_FARADAY  		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",  		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),  		      ehci_readl(&ctrl->hcor->or_portsc[0]),  		      ehci_readl(&ctrl->hcor->or_portsc[1])); +#endif  	}  	free(qtd); @@ -603,6 +605,17 @@ fail:  	return -1;  } +__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port) +{ +	if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { +		/* Printing the message would cause a scan failure! */ +		debug("The request port(%u) is not configured\n", port); +		return NULL; +	} + +	return (uint32_t *)&hcor->or_portsc[port]; +} +  int  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  		 int length, struct devrequest *req) @@ -616,11 +629,6 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  	int port = le16_to_cpu(req->index) & 0xff;  	struct ehci_ctrl *ctrl = dev->controller; -	if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { -		printf("The request port(%d) is not configured\n", port - 1); -		return -1; -	} -	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];  	srclen = 0;  	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", @@ -631,6 +639,19 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  	typeReq = req->request | req->requesttype << 8;  	switch (typeReq) { +	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): +	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): +	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): +		status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1); +		if (!status_reg) +			return -1; +		break; +	default: +		status_reg = NULL; +		break; +	} + +	switch (typeReq) {  	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:  		switch (le16_to_cpu(req->value) >> 8) {  		case USB_DT_DEVICE: @@ -809,21 +830,23 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  		break;  	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):  		reg = ehci_readl(status_reg); +		reg &= ~EHCI_PS_CLEAR;  		switch (le16_to_cpu(req->value)) {  		case USB_PORT_FEAT_ENABLE:  			reg &= ~EHCI_PS_PE;  			break;  		case USB_PORT_FEAT_C_ENABLE: -			reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE; +			reg |= EHCI_PS_PE;  			break;  		case USB_PORT_FEAT_POWER:  			if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) -				reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP); +				reg &= ~EHCI_PS_PP; +			break;  		case USB_PORT_FEAT_C_CONNECTION: -			reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC; +			reg |= EHCI_PS_CSC;  			break;  		case USB_PORT_FEAT_OVER_CURRENT: -			reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; +			reg |= EHCI_PS_OCC;  			break;  		case USB_PORT_FEAT_C_RESET:  			ctrl->portreset &= ~(1 << port); @@ -903,6 +926,9 @@ int usb_lowlevel_init(int index, void **controller)  	qh_list->qh_overlay.qt_token =  			cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED)); +	flush_dcache_range((uint32_t)qh_list, +			   ALIGN_END_ADDR(struct QH, qh_list, 1)); +  	/* Set async. queue head pointer. */  	ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list); @@ -916,6 +942,9 @@ int usb_lowlevel_init(int index, void **controller)  	periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);  	periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); +	flush_dcache_range((uint32_t)periodic, +			   ALIGN_END_ADDR(struct QH, periodic, 1)); +  	/*  	 * Step 2: Setup frame-list: Every microframe, USB tries the same list.  	 *         In particular, device specifications on polling frequency @@ -933,6 +962,10 @@ int usb_lowlevel_init(int index, void **controller)  						| QH_LINK_TYPE_QH;  	} +	flush_dcache_range((uint32_t)ehcic[index].periodic_list, +			   ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list, +					  1024)); +  	/* Set periodic list base address */  	ehci_writel(&ehcic[index].hcor->or_periodiclistbase,  		(uint32_t)ehcic[index].periodic_list); @@ -959,10 +992,13 @@ int usb_lowlevel_init(int index, void **controller)  	cmd |= CMD_RUN;  	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); +#ifndef CONFIG_USB_EHCI_FARADAY  	/* take control over the ports */  	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);  	cmd |= FLAG_CF;  	ehci_writel(&ehcic[index].hcor->or_configflag, cmd); +#endif +  	/* unblock posted write */  	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);  	mdelay(5); @@ -1144,6 +1180,16 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,  		*buf = buffer + i * elementsize;  	} +	flush_dcache_range((uint32_t)buffer, +			   ALIGN_END_ADDR(char, buffer, +					  queuesize * elementsize)); +	flush_dcache_range((uint32_t)result->first, +			   ALIGN_END_ADDR(struct QH, result->first, +					  queuesize)); +	flush_dcache_range((uint32_t)result->tds, +			   ALIGN_END_ADDR(struct qTD, result->tds, +					  queuesize)); +  	if (disable_periodic(ctrl) < 0) {  		debug("FATAL: periodic should never fail, but did");  		goto fail3; @@ -1154,6 +1200,11 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,  	result->last->qh_link = list->qh_link;  	list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH; +	flush_dcache_range((uint32_t)result->last, +			   ALIGN_END_ADDR(struct QH, result->last, 1)); +	flush_dcache_range((uint32_t)list, +			   ALIGN_END_ADDR(struct QH, list, 1)); +  	if (enable_periodic(ctrl) < 0) {  		debug("FATAL: periodic should never fail, but did");  		goto fail3; @@ -1184,6 +1235,8 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)  		return NULL;  	}  	/* still active */ +	invalidate_dcache_range((uint32_t)cur, +				ALIGN_END_ADDR(struct QH, cur, 1));  	if (cur->qh_overlay.qt_token & 0x80) {  		debug("Exit poll_int_queue with no completed intr transfer. "  		      "token is %x\n", cur->qh_overlay.qt_token); @@ -1290,6 +1343,9 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  		return -EINVAL;  	} +	invalidate_dcache_range((uint32_t)buffer, +				ALIGN_END_ADDR(char, buffer, length)); +  	ret = destroy_int_queue(dev, queue);  	if (ret < 0)  		return ret; diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 15d2ec007..c2400328a 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -1,4 +1,5 @@  #include <common.h> +#include <watchdog.h>  #include <asm/errno.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> @@ -164,6 +165,7 @@ static struct musb *gadget;  int usb_gadget_handle_interrupts(void)  { +	WATCHDOG_RESET();  	if (!gadget || !gadget->isr)  		return -EINVAL; diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 60e03a4bf..7bb91e5ab 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -1105,8 +1105,7 @@ int usb_lowlevel_init(int index, void **controller)  	/* Configure all the endpoint FIFO's and start usb controller */  	musbr = musb_cfg.regs; -	musb_configure_ep(&epinfo[0], -			sizeof(epinfo) / sizeof(struct musb_epinfo)); +	musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));  	musb_start();  	/* diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c index e0b4217dc..e8a2ce041 100644 --- a/drivers/usb/musb/musb_udc.c +++ b/drivers/usb/musb/musb_udc.c @@ -894,8 +894,7 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id,  			epinfo[id * 2].epsize = endpoint->rcv_packetSize;  		} -		musb_configure_ep(&epinfo[0], -				  sizeof(epinfo) / sizeof(struct musb_epinfo)); +		musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));  	} else {  		if (debug_level > 0)  			serial_printf("ERROR : %s endpoint request %d " |