diff options
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 312 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-mxs.c | 26 | ||||
| -rw-r--r-- | drivers/usb/host/ehci.h | 60 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-da8xx.c | 48 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hcd.c | 70 | 
6 files changed, 368 insertions, 149 deletions
| diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 6de91640d..bcb4662c4 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -28,6 +28,7 @@ LIB	:= $(obj)libusb_host.o  # ohci  COBJS-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o  COBJS-$(CONFIG_USB_ATMEL) += ohci-at91.o +COBJS-$(CONFIG_USB_OHCI_DA8XX) += ohci-da8xx.o  COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o  COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o  COBJS-$(CONFIG_USB_S3C64XX) += s3c64xx-hcd.o diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2a82a2912..392e28622 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -22,6 +22,7 @@   */  #include <common.h>  #include <asm/byteorder.h> +#include <asm/unaligned.h>  #include <usb.h>  #include <asm/io.h>  #include <malloc.h> @@ -163,7 +164,7 @@ static int ehci_reset(void)  #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH  	cmd = ehci_readl(&hcor->or_txfilltuning); -	cmd &= ~TXFIFO_THRESH(0x3f); +	cmd &= ~TXFIFO_THRESH_MASK;  	cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);  	ehci_writel(&hcor->or_txfilltuning, cmd);  #endif @@ -183,10 +184,10 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)  	flush_dcache_range(addr, ALIGN(addr + sz, ARCH_DMA_MINALIGN));  	idx = 0; -	while (idx < 5) { +	while (idx < QT_BUFFER_CNT) {  		td->qt_buffer[idx] = cpu_to_hc32(addr);  		td->qt_buffer_hi[idx] = 0; -		next = (addr + 4096) & ~4095; +		next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1);  		delta = next - addr;  		if (delta >= sz)  			break; @@ -195,7 +196,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)  		idx++;  	} -	if (idx == 5) { +	if (idx == QT_BUFFER_CNT) {  		printf("out of buffer pointers (%u bytes left)\n", sz);  		return -1;  	} @@ -208,13 +209,14 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		   int length, struct devrequest *req)  {  	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN); -	ALLOC_ALIGN_BUFFER(struct qTD, qtd, 3, USB_DMA_MINALIGN); +	struct qTD *qtd; +	int qtd_count = 0;  	int qtd_counter = 0;  	volatile struct qTD *vtd;  	unsigned long ts;  	uint32_t *tdp; -	uint32_t endpt, token, usbsts; +	uint32_t endpt, maxpacket, token, usbsts;  	uint32_t c, toggle;  	uint32_t cmd;  	int timeout; @@ -229,8 +231,73 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		      le16_to_cpu(req->value), le16_to_cpu(req->value),  		      le16_to_cpu(req->index)); +#define PKT_ALIGN	512 +	/* +	 * The USB transfer is split into qTD transfers. Eeach qTD transfer is +	 * described by a transfer descriptor (the qTD). The qTDs form a linked +	 * list with a queue head (QH). +	 * +	 * Each qTD transfer starts with a new USB packet, i.e. a packet cannot +	 * have its beginning in a qTD transfer and its end in the following +	 * one, so the qTD transfer lengths have to be chosen accordingly. +	 * +	 * Each qTD transfer uses up to QT_BUFFER_CNT data buffers, mapped to +	 * single pages. The first data buffer can start at any offset within a +	 * page (not considering the cache-line alignment issues), while the +	 * following buffers must be page-aligned. There is no alignment +	 * constraint on the size of a qTD transfer. +	 */ +	if (req != NULL) +		/* 1 qTD will be needed for SETUP, and 1 for ACK. */ +		qtd_count += 1 + 1; +	if (length > 0 || req == NULL) { +		/* +		 * Determine the qTD transfer size that will be used for the +		 * data payload (not considering the first qTD transfer, which +		 * may be longer or shorter, and the final one, which may be +		 * shorter). +		 * +		 * In order to keep each packet within a qTD transfer, the qTD +		 * transfer size is aligned to PKT_ALIGN, which is a multiple of +		 * wMaxPacketSize (except in some cases for interrupt transfers, +		 * see comment in submit_int_msg()). +		 * +		 * By default, i.e. if the input buffer is aligned to PKT_ALIGN, +		 * QT_BUFFER_CNT full pages will be used. +		 */ +		int xfr_sz = QT_BUFFER_CNT; +		/* +		 * However, if the input buffer is not aligned to PKT_ALIGN, the +		 * qTD transfer size will be one page shorter, and the first qTD +		 * data buffer of each transfer will be page-unaligned. +		 */ +		if ((uint32_t)buffer & (PKT_ALIGN - 1)) +			xfr_sz--; +		/* Convert the qTD transfer size to bytes. */ +		xfr_sz *= EHCI_PAGE_SIZE; +		/* +		 * Approximate by excess the number of qTDs that will be +		 * required for the data payload. The exact formula is way more +		 * complicated and saves at most 2 qTDs, i.e. a total of 128 +		 * bytes. +		 */ +		qtd_count += 2 + length / xfr_sz; +	} +/* + * Threshold value based on the worst-case total size of the allocated qTDs for + * a mass-storage transfer of 65535 blocks of 512 bytes. + */ +#if CONFIG_SYS_MALLOC_LEN <= 64 + 128 * 1024 +#warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI +#endif +	qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD)); +	if (qtd == NULL) { +		printf("unable to allocate TDs\n"); +		return -1; +	} +  	memset(qh, 0, sizeof(struct QH)); -	memset(qtd, 0, 3 * sizeof(*qtd)); +	memset(qtd, 0, qtd_count * sizeof(*qtd));  	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); @@ -245,20 +312,18 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	 * - qh_overlay.qt_altnext  	 */  	qh->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH); -	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && -	     usb_pipeendpoint(pipe) == 0) ? 1 : 0; -	endpt = (8 << 28) | -	    (c << 27) | -	    (usb_maxpacket(dev, pipe) << 16) | -	    (0 << 15) | -	    (1 << 14) | -	    (usb_pipespeed(pipe) << 12) | -	    (usb_pipeendpoint(pipe) << 8) | -	    (0 << 7) | (usb_pipedevice(pipe) << 0); +	c = usb_pipespeed(pipe) != USB_SPEED_HIGH && !usb_pipeendpoint(pipe); +	maxpacket = usb_maxpacket(dev, pipe); +	endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | +		QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) | +		QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) | +		QH_ENDPT1_EPS(usb_pipespeed(pipe)) | +		QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) | +		QH_ENDPT1_DEVADDR(usb_pipedevice(pipe));  	qh->qh_endpt1 = cpu_to_hc32(endpt); -	endpt = (1 << 30) | -	    (dev->portnr << 23) | -	    (dev->parent->devnum << 16) | (0 << 8) | (0 << 0); +	endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_PORTNUM(dev->portnr) | +		QH_ENDPT2_HUBADDR(dev->parent->devnum) | +		QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0);  	qh->qh_endpt2 = cpu_to_hc32(endpt);  	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); @@ -276,12 +341,13 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		 */  		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);  		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); -		token = (0 << 31) | -		    (sizeof(*req) << 16) | -		    (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0); +		token = QT_TOKEN_DT(0) | QT_TOKEN_TOTALBYTES(sizeof(*req)) | +			QT_TOKEN_IOC(0) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | +			QT_TOKEN_PID(QT_TOKEN_PID_SETUP) | +			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);  		qtd[qtd_counter].qt_token = cpu_to_hc32(token); -		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req)) != 0) { -			printf("unable construct SETUP td\n"); +		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req))) { +			printf("unable to construct SETUP TD\n");  			goto fail;  		}  		/* Update previous qTD! */ @@ -291,31 +357,71 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	}  	if (length > 0 || req == NULL) { -		/* -		 * Setup request qTD (3.5 in ehci-r10.pdf) -		 * -		 *   qt_next ................ 03-00 H -		 *   qt_altnext ............. 07-04 H -		 *   qt_token ............... 0B-08 H -		 * -		 *   [ buffer, buffer_hi ] loaded with "buffer". -		 */ -		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); -		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); -		token = (toggle << 31) | -		    (length << 16) | -		    ((req == NULL ? 1 : 0) << 15) | -		    (0 << 12) | -		    (3 << 10) | -		    ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0); -		qtd[qtd_counter].qt_token = cpu_to_hc32(token); -		if (ehci_td_buffer(&qtd[qtd_counter], buffer, length) != 0) { -			printf("unable construct DATA td\n"); -			goto fail; -		} -		/* Update previous qTD! */ -		*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); -		tdp = &qtd[qtd_counter++].qt_next; +		uint8_t *buf_ptr = buffer; +		int left_length = length; + +		do { +			/* +			 * Determine the size of this qTD transfer. By default, +			 * QT_BUFFER_CNT full pages can be used. +			 */ +			int xfr_bytes = QT_BUFFER_CNT * EHCI_PAGE_SIZE; +			/* +			 * However, if the input buffer is not page-aligned, the +			 * portion of the first page before the buffer start +			 * offset within that page is unusable. +			 */ +			xfr_bytes -= (uint32_t)buf_ptr & (EHCI_PAGE_SIZE - 1); +			/* +			 * In order to keep each packet within a qTD transfer, +			 * align the qTD transfer size to PKT_ALIGN. +			 */ +			xfr_bytes &= ~(PKT_ALIGN - 1); +			/* +			 * This transfer may be shorter than the available qTD +			 * transfer size that has just been computed. +			 */ +			xfr_bytes = min(xfr_bytes, left_length); + +			/* +			 * Setup request qTD (3.5 in ehci-r10.pdf) +			 * +			 *   qt_next ................ 03-00 H +			 *   qt_altnext ............. 07-04 H +			 *   qt_token ............... 0B-08 H +			 * +			 *   [ buffer, buffer_hi ] loaded with "buffer". +			 */ +			qtd[qtd_counter].qt_next = +					cpu_to_hc32(QT_NEXT_TERMINATE); +			qtd[qtd_counter].qt_altnext = +					cpu_to_hc32(QT_NEXT_TERMINATE); +			token = QT_TOKEN_DT(toggle) | +				QT_TOKEN_TOTALBYTES(xfr_bytes) | +				QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) | +				QT_TOKEN_CERR(3) | +				QT_TOKEN_PID(usb_pipein(pipe) ? +					QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) | +				QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); +			qtd[qtd_counter].qt_token = cpu_to_hc32(token); +			if (ehci_td_buffer(&qtd[qtd_counter], buf_ptr, +						xfr_bytes)) { +				printf("unable to construct DATA TD\n"); +				goto fail; +			} +			/* Update previous qTD! */ +			*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); +			tdp = &qtd[qtd_counter++].qt_next; +			/* +			 * Data toggle has to be adjusted since the qTD transfer +			 * size is not always an even multiple of +			 * wMaxPacketSize. +			 */ +			if ((xfr_bytes / maxpacket) & 1) +				toggle ^= 1; +			buf_ptr += xfr_bytes; +			left_length -= xfr_bytes; +		} while (left_length > 0);  	}  	if (req != NULL) { @@ -328,12 +434,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		 */  		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);  		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); -		token = (toggle << 31) | -		    (0 << 16) | -		    (1 << 15) | -		    (0 << 12) | -		    (3 << 10) | -		    ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0); +		token = QT_TOKEN_DT(1) | QT_TOKEN_TOTALBYTES(0) | +			QT_TOKEN_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | +			QT_TOKEN_PID(usb_pipein(pipe) ? +				QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) | +			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);  		qtd[qtd_counter].qt_token = cpu_to_hc32(token);  		/* Update previous qTD! */  		*tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); @@ -346,7 +451,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	flush_dcache_range((uint32_t)qh_list,  		ALIGN_END_ADDR(struct QH, qh_list, 1));  	flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1)); -	flush_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, 3)); +	flush_dcache_range((uint32_t)qtd, +			   ALIGN_END_ADDR(struct qTD, qtd, qtd_count));  	/* Set async. queue head pointer. */  	ehci_writel(&hcor->or_asynclistaddr, (uint32_t)qh_list); @@ -359,10 +465,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  	cmd |= CMD_ASE;  	ehci_writel(&hcor->or_usbcmd, cmd); -	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS, +	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, STS_ASS,  			100 * 1000);  	if (ret < 0) { -		printf("EHCI fail timeout STD_ASS set\n"); +		printf("EHCI fail timeout STS_ASS set\n");  		goto fail;  	} @@ -377,10 +483,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		invalidate_dcache_range((uint32_t)qh,  			ALIGN_END_ADDR(struct QH, qh, 1));  		invalidate_dcache_range((uint32_t)qtd, -			ALIGN_END_ADDR(struct qTD, qtd, 3)); +			ALIGN_END_ADDR(struct qTD, qtd, qtd_count));  		token = hc32_to_cpu(vtd->qt_token); -		if (!(token & 0x80)) +		if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE))  			break;  		WATCHDOG_RESET();  	} while (get_timer(ts) < timeout); @@ -398,50 +504,50 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN));  	/* Check that the TD processing happened */ -	if (token & 0x80) { +	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)  		printf("EHCI timed out on TD - token=%#x\n", token); -	}  	/* Disable async schedule. */  	cmd = ehci_readl(&hcor->or_usbcmd);  	cmd &= ~CMD_ASE;  	ehci_writel(&hcor->or_usbcmd, cmd); -	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0, +	ret = handshake((uint32_t *)&hcor->or_usbsts, STS_ASS, 0,  			100 * 1000);  	if (ret < 0) { -		printf("EHCI fail timeout STD_ASS reset\n"); +		printf("EHCI fail timeout STS_ASS reset\n");  		goto fail;  	}  	token = hc32_to_cpu(qh->qh_overlay.qt_token); -	if (!(token & 0x80)) { +	if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) {  		debug("TOKEN=%#x\n", token); -		switch (token & 0xfc) { +		switch (QT_TOKEN_GET_STATUS(token) & +			~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) {  		case 0: -			toggle = token >> 31; +			toggle = QT_TOKEN_GET_DT(token);  			usb_settoggle(dev, usb_pipeendpoint(pipe),  				       usb_pipeout(pipe), toggle);  			dev->status = 0;  			break; -		case 0x40: +		case QT_TOKEN_STATUS_HALTED:  			dev->status = USB_ST_STALLED;  			break; -		case 0xa0: -		case 0x20: +		case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR: +		case QT_TOKEN_STATUS_DATBUFERR:  			dev->status = USB_ST_BUF_ERR;  			break; -		case 0x50: -		case 0x10: +		case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET: +		case QT_TOKEN_STATUS_BABBLEDET:  			dev->status = USB_ST_BABBLE_DET;  			break;  		default:  			dev->status = USB_ST_CRC_ERR; -			if ((token & 0x40) == 0x40) +			if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_HALTED)  				dev->status |= USB_ST_STALLED;  			break;  		} -		dev->act_len = length - ((token >> 16) & 0x7fff); +		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);  	} else {  		dev->act_len = 0;  		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", @@ -450,9 +556,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,  		      ehci_readl(&hcor->or_portsc[1]));  	} +	free(qtd);  	return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;  fail: +	free(qtd);  	return -1;  } @@ -499,12 +607,14 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  		case USB_DT_DEVICE:  			debug("USB_DT_DEVICE request\n");  			srcptr = &descriptor.device; -			srclen = 0x12; +			srclen = descriptor.device.bLength;  			break;  		case USB_DT_CONFIG:  			debug("USB_DT_CONFIG config\n");  			srcptr = &descriptor.config; -			srclen = 0x19; +			srclen = descriptor.config.bLength + +					descriptor.interface.bLength + +					descriptor.endpoint.bLength;  			break;  		case USB_DT_STRING:  			debug("USB_DT_STRING config\n"); @@ -539,7 +649,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  		case USB_DT_HUB:  			debug("USB_DT_HUB config\n");  			srcptr = &descriptor.hub; -			srclen = 0x8; +			srclen = descriptor.hub.bLength;  			break;  		default:  			debug("unknown value %x\n", le16_to_cpu(req->value)); @@ -577,13 +687,13 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,  			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;  		if (ehci_is_TDI()) { -			switch ((reg >> 26) & 3) { -			case 0: +			switch (PORTSC_PSPD(reg)) { +			case PORTSC_PSPD_FS:  				break; -			case 1: +			case PORTSC_PSPD_LS:  				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;  				break; -			case 2: +			case PORTSC_PSPD_HS:  			default:  				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;  				break; @@ -729,36 +839,40 @@ int usb_lowlevel_init(void)  	uint32_t reg;  	uint32_t cmd; -	if (ehci_hcd_init() != 0) +	if (ehci_hcd_init())  		return -1;  	/* EHCI spec section 4.1 */ -	if (ehci_reset() != 0) +	if (ehci_reset())  		return -1;  #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET) -	if (ehci_hcd_init() != 0) +	if (ehci_hcd_init())  		return -1;  #endif  	/* Set head of reclaim list */  	memset(qh_list, 0, sizeof(*qh_list));  	qh_list->qh_link = cpu_to_hc32((uint32_t)qh_list | QH_LINK_TYPE_QH); -	qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12)); +	qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) | +						QH_ENDPT1_EPS(USB_SPEED_HIGH));  	qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);  	qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);  	qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); -	qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40); +	qh_list->qh_overlay.qt_token = +			cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));  	reg = ehci_readl(&hccr->cr_hcsparams);  	descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);  	printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);  	/* Port Indicators */  	if (HCS_INDICATOR(reg)) -		descriptor.hub.wHubCharacteristics |= 0x80; +		put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) +				| 0x80, &descriptor.hub.wHubCharacteristics);  	/* Port Power Control */  	if (HCS_PPC(reg)) -		descriptor.hub.wHubCharacteristics |= 0x01; +		put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics) +				| 0x01, &descriptor.hub.wHubCharacteristics);  	/* Start the host controller. */  	cmd = ehci_readl(&hcor->or_usbcmd); @@ -808,7 +922,7 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  	}  	if (usb_pipedevice(pipe) == rootdev) { -		if (rootdev == 0) +		if (!rootdev)  			dev->speed = USB_SPEED_HIGH;  		return ehci_submit_root(dev, pipe, buffer, length, setup);  	} @@ -819,8 +933,24 @@ int  submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,  	       int length, int interval)  { -  	debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",  	      dev, pipe, buffer, length, interval); + +	/* +	 * Interrupt transfers requiring several transactions are not supported +	 * because bInterval is ignored. +	 * +	 * Also, ehci_submit_async() relies on wMaxPacketSize being a power of 2 +	 * <= PKT_ALIGN if several qTDs are required, while the USB +	 * specification does not constrain this for interrupt transfers. That +	 * means that ehci_submit_async() would support interrupt transfers +	 * requiring several transactions only as long as the transfer size does +	 * not require more than a single qTD. +	 */ +	if (length > usb_maxpacket(dev, pipe)) { +		printf("%s: Interrupt transfers requiring several transactions " +			"are not supported.\n", __func__); +		return -1; +	}  	return ehci_submit_async(dev, pipe, buffer, length, NULL);  } diff --git a/drivers/usb/host/ehci-mxs.c b/drivers/usb/host/ehci-mxs.c index e1bd37ec8..6e21669d5 100644 --- a/drivers/usb/host/ehci-mxs.c +++ b/drivers/usb/host/ehci-mxs.c @@ -23,7 +23,7 @@  #include <asm/io.h>  #include <asm/arch/regs-common.h>  #include <asm/arch/regs-base.h> -#include <asm/arch/regs-clkctrl.h> +#include <asm/arch/regs-clkctrl-mx28.h>  #include <asm/arch/regs-usb.h>  #include <asm/arch/regs-usbphy.h> @@ -39,8 +39,8 @@  #endif  static struct ehci_mxs { -	struct mx28_usb_regs	*usb_regs; -	struct mx28_usbphy_regs	*phy_regs; +	struct mxs_usb_regs	*usb_regs; +	struct mxs_usbphy_regs	*phy_regs;  } ehci_mxs;  int mxs_ehci_get_port(struct ehci_mxs *mxs_usb, int port) @@ -60,8 +60,8 @@ int mxs_ehci_get_port(struct ehci_mxs *mxs_usb, int port)  		return -1;  	} -	mxs_usb->usb_regs = (struct mx28_usb_regs *)usb_base; -	mxs_usb->phy_regs = (struct mx28_usbphy_regs *)phy_base; +	mxs_usb->usb_regs = (struct mxs_usb_regs *)usb_base; +	mxs_usb->phy_regs = (struct mxs_usbphy_regs *)phy_base;  	return 0;  } @@ -75,10 +75,10 @@ int ehci_hcd_init(void)  	int ret;  	uint32_t usb_base, cap_base; -	struct mx28_register_32 *digctl_ctrl = -		(struct mx28_register_32 *)HW_DIGCTL_CTRL; -	struct mx28_clkctrl_regs *clkctrl_regs = -		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	struct mxs_register_32 *digctl_ctrl = +		(struct mxs_register_32 *)HW_DIGCTL_CTRL; +	struct mxs_clkctrl_regs *clkctrl_regs = +		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;  	ret = mxs_ehci_get_port(&ehci_mxs, CONFIG_EHCI_MXS_PORT);  	if (ret) @@ -119,10 +119,10 @@ int ehci_hcd_stop(void)  {  	int ret;  	uint32_t tmp; -	struct mx28_register_32 *digctl_ctrl = -		(struct mx28_register_32 *)HW_DIGCTL_CTRL; -	struct mx28_clkctrl_regs *clkctrl_regs = -		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	struct mxs_register_32 *digctl_ctrl = +		(struct mxs_register_32 *)HW_DIGCTL_CTRL; +	struct mxs_clkctrl_regs *clkctrl_regs = +		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;  	ret = mxs_ehci_get_port(&ehci_mxs, CONFIG_EHCI_MXS_PORT);  	if (ret) diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index cc00ce428..39acdf965 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -68,7 +68,7 @@ struct ehci_hcor {  #define CMD_RESET	(1 << 1)		/* reset HC not bus */  #define CMD_RUN		(1 << 0)		/* start/stop HC */  	uint32_t or_usbsts; -#define	STD_ASS		(1 << 15) +#define STS_ASS		(1 << 15)  #define STS_HALT	(1 << 12)  	uint32_t or_usbintr;  #define INTR_UE         (1 << 0)                /* USB interrupt enable */ @@ -83,11 +83,16 @@ struct ehci_hcor {  	uint32_t _reserved_0_;  	uint32_t or_burstsize;  	uint32_t or_txfilltuning; +#define TXFIFO_THRESH_MASK		(0x3f << 16)  #define TXFIFO_THRESH(p)		((p & 0x3f) << 16)  	uint32_t _reserved_1_[6];  	uint32_t or_configflag;  #define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */  	uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS]; +#define PORTSC_PSPD(x)		(((x) >> 26) & 0x3) +#define PORTSC_PSPD_FS			0x0 +#define PORTSC_PSPD_LS			0x1 +#define PORTSC_PSPD_HS			0x2  	uint32_t or_systune;  } __attribute__ ((packed, aligned(4))); @@ -171,16 +176,40 @@ struct usb_linux_config_descriptor {  /* Queue Element Transfer Descriptor (qTD). */  struct qTD {  	/* this part defined by EHCI spec */ -	uint32_t qt_next;		/* see EHCI 3.5.1 */ +	uint32_t qt_next;			/* see EHCI 3.5.1 */  #define	QT_NEXT_TERMINATE	1 -	uint32_t qt_altnext;		/* see EHCI 3.5.2 */ -	uint32_t qt_token;		/* see EHCI 3.5.3 */ -	uint32_t qt_buffer[5];		/* see EHCI 3.5.4 */ -	uint32_t qt_buffer_hi[5];	/* Appendix B */ +	uint32_t qt_altnext;			/* see EHCI 3.5.2 */ +	uint32_t qt_token;			/* see EHCI 3.5.3 */ +#define QT_TOKEN_DT(x)		(((x) & 0x1) << 31)	/* Data Toggle */ +#define QT_TOKEN_GET_DT(x)		(((x) >> 31) & 0x1) +#define QT_TOKEN_TOTALBYTES(x)	(((x) & 0x7fff) << 16)	/* Total Bytes to Transfer */ +#define QT_TOKEN_GET_TOTALBYTES(x)	(((x) >> 16) & 0x7fff) +#define QT_TOKEN_IOC(x)		(((x) & 0x1) << 15)	/* Interrupt On Complete */ +#define QT_TOKEN_CPAGE(x)	(((x) & 0x7) << 12)	/* Current Page */ +#define QT_TOKEN_CERR(x)	(((x) & 0x3) << 10)	/* Error Counter */ +#define QT_TOKEN_PID(x)		(((x) & 0x3) << 8)	/* PID Code */ +#define QT_TOKEN_PID_OUT		0x0 +#define QT_TOKEN_PID_IN			0x1 +#define QT_TOKEN_PID_SETUP		0x2 +#define QT_TOKEN_STATUS(x)	(((x) & 0xff) << 0)	/* Status */ +#define QT_TOKEN_GET_STATUS(x)		(((x) >> 0) & 0xff) +#define QT_TOKEN_STATUS_ACTIVE		0x80 +#define QT_TOKEN_STATUS_HALTED		0x40 +#define QT_TOKEN_STATUS_DATBUFERR	0x20 +#define QT_TOKEN_STATUS_BABBLEDET	0x10 +#define QT_TOKEN_STATUS_XACTERR		0x08 +#define QT_TOKEN_STATUS_MISSEDUFRAME	0x04 +#define QT_TOKEN_STATUS_SPLITXSTATE	0x02 +#define QT_TOKEN_STATUS_PERR		0x01 +#define QT_BUFFER_CNT		5 +	uint32_t qt_buffer[QT_BUFFER_CNT];	/* see EHCI 3.5.4 */ +	uint32_t qt_buffer_hi[QT_BUFFER_CNT];	/* Appendix B */  	/* pad struct for 32 byte alignment */  	uint32_t unused[3];  }; +#define EHCI_PAGE_SIZE		4096 +  /* Queue Head (QH). */  struct QH {  	uint32_t qh_link; @@ -190,7 +219,26 @@ struct QH {  #define	QH_LINK_TYPE_SITD	4  #define	QH_LINK_TYPE_FSTN	6  	uint32_t qh_endpt1; +#define QH_ENDPT1_RL(x)		(((x) & 0xf) << 28)	/* NAK Count Reload */ +#define QH_ENDPT1_C(x)		(((x) & 0x1) << 27)	/* Control Endpoint Flag */ +#define QH_ENDPT1_MAXPKTLEN(x)	(((x) & 0x7ff) << 16)	/* Maximum Packet Length */ +#define QH_ENDPT1_H(x)		(((x) & 0x1) << 15)	/* Head of Reclamation List Flag */ +#define QH_ENDPT1_DTC(x)	(((x) & 0x1) << 14)	/* Data Toggle Control */ +#define QH_ENDPT1_DTC_IGNORE_QTD_TD	0x0 +#define QH_ENDPT1_DTC_DT_FROM_QTD	0x1 +#define QH_ENDPT1_EPS(x)	(((x) & 0x3) << 12)	/* Endpoint Speed */ +#define QH_ENDPT1_EPS_FS		0x0 +#define QH_ENDPT1_EPS_LS		0x1 +#define QH_ENDPT1_EPS_HS		0x2 +#define QH_ENDPT1_ENDPT(x)	(((x) & 0xf) << 8)	/* Endpoint Number */ +#define QH_ENDPT1_I(x)		(((x) & 0x1) << 7)	/* Inactivate on Next Transaction */ +#define QH_ENDPT1_DEVADDR(x)	(((x) & 0x7f) << 0)	/* Device Address */  	uint32_t qh_endpt2; +#define QH_ENDPT2_MULT(x)	(((x) & 0x3) << 30)	/* High-Bandwidth Pipe Multiplier */ +#define QH_ENDPT2_PORTNUM(x)	(((x) & 0x7f) << 23)	/* Port Number */ +#define QH_ENDPT2_HUBADDR(x)	(((x) & 0x7f) << 16)	/* Hub Address */ +#define QH_ENDPT2_UFCMASK(x)	(((x) & 0xff) << 8)	/* Split Completion Mask */ +#define QH_ENDPT2_UFSMASK(x)	(((x) & 0xff) << 0)	/* Interrupt Schedule Mask */  	uint32_t qh_curtd;  	struct qTD qh_overlay;  	/* diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c new file mode 100644 index 000000000..f0ccb83f7 --- /dev/null +++ b/drivers/usb/host/ohci-da8xx.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Sughosh Ganu <urwithsughosh@gmail.com> + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <common.h> + +#include <asm/arch/da8xx-usb.h> + +int usb_cpu_init(void) +{ +	/* enable psc for usb2.0 */ +	lpsc_on(DAVINCI_LPSC_USB20); + +	/* enable psc for usb1.0 */ +	lpsc_on(DAVINCI_LPSC_USB11); + +	/* start the on-chip usb phy and its pll */ +	if (usb_phy_on()) +		return 0; + +	return 1; +} + +int usb_cpu_stop(void) +{ +	usb_phy_off(); + +	/* turn off the usb clock and assert the module reset */ +	lpsc_disable(DAVINCI_LPSC_USB11); +	lpsc_disable(DAVINCI_LPSC_USB20); + +	return 0; +} + +int usb_cpu_init_fail(void) +{ +	return usb_cpu_stop(); +} diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index d24f2f131..9f4735167 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1261,19 +1261,11 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,  	int leni = transfer_len;  	int len = 0;  	int stat = 0; -	__u32 datab[4]; -	union { -		void *ptr; -		__u8 *u8; -		__u16 *u16; -		__u32 *u32; -	} databuf;  	__u16 bmRType_bReq;  	__u16 wValue;  	__u16 wIndex;  	__u16 wLength; - -	databuf.u32 = (__u32 *)datab; +	ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32));  #ifdef DEBUG  pkt_print(NULL, dev, pipe, buffer, transfer_len, @@ -1304,20 +1296,20 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,  	*/  	case RH_GET_STATUS: -		databuf.u16[0] = cpu_to_le16(1); +		*(u16 *)databuf = cpu_to_le16(1);  		OK(2);  	case RH_GET_STATUS | RH_INTERFACE: -		databuf.u16[0] = cpu_to_le16(0); +		*(u16 *)databuf = cpu_to_le16(0);  		OK(2);  	case RH_GET_STATUS | RH_ENDPOINT: -		databuf.u16[0] = cpu_to_le16(0); +		*(u16 *)databuf = cpu_to_le16(0);  		OK(2);  	case RH_GET_STATUS | RH_CLASS: -		databuf.u32[0] = cpu_to_le32( +		*(u32 *)databuf = cpu_to_le32(  				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));  		OK(4);  	case RH_GET_STATUS | RH_OTHER | RH_CLASS: -		databuf.u32[0] = cpu_to_le32(RD_RH_PORTSTAT); +		*(u32 *)databuf = cpu_to_le32(RD_RH_PORTSTAT);  		OK(4);  	case RH_CLEAR_FEATURE | RH_ENDPOINT: @@ -1381,14 +1373,14 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,  					min_t(unsigned int,  					sizeof(root_hub_dev_des),  					wLength)); -			databuf.ptr = root_hub_dev_des; OK(len); +			databuf = root_hub_dev_des; OK(len);  		case (0x02): /* configuration descriptor */  			len = min_t(unsigned int,  					leni,  					min_t(unsigned int,  					sizeof(root_hub_config_des),  					wLength)); -			databuf.ptr = root_hub_config_des; OK(len); +			databuf = root_hub_config_des; OK(len);  		case (0x03): /* string descriptors */  			if (wValue == 0x0300) {  				len = min_t(unsigned int, @@ -1396,7 +1388,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,  						min_t(unsigned int,  						sizeof(root_hub_str_index0),  						wLength)); -				databuf.ptr = root_hub_str_index0; +				databuf = root_hub_str_index0;  				OK(len);  			}  			if (wValue == 0x0301) { @@ -1405,7 +1397,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,  						min_t(unsigned int,  						sizeof(root_hub_str_index1),  						wLength)); -				databuf.ptr = root_hub_str_index1; +				databuf = root_hub_str_index1;  				OK(len);  		}  		default: @@ -1417,40 +1409,40 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,  	{  		__u32 temp = roothub_a(&gohci); -		databuf.u8[0] = 9;		/* min length; */ -		databuf.u8[1] = 0x29; -		databuf.u8[2] = temp & RH_A_NDP; +		databuf[0] = 9;		/* min length; */ +		databuf[1] = 0x29; +		databuf[2] = temp & RH_A_NDP;  #ifdef CONFIG_AT91C_PQFP_UHPBUG -		databuf.u8[2] = (databuf.u8[2] == 2) ? 1 : 0; +		databuf[2] = (databuf[2] == 2) ? 1 : 0;  #endif -		databuf.u8[3] = 0; +		databuf[3] = 0;  		if (temp & RH_A_PSM)	/* per-port power switching? */ -			databuf.u8[3] |= 0x1; +			databuf[3] |= 0x1;  		if (temp & RH_A_NOCP)	/* no overcurrent reporting? */ -			databuf.u8[3] |= 0x10; +			databuf[3] |= 0x10;  		else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */ -			databuf.u8[3] |= 0x8; +			databuf[3] |= 0x8; -		/* corresponds to databuf.u8[4-7] */ -		databuf.u8[1] = 0; -		databuf.u8[5] = (temp & RH_A_POTPGT) >> 24; +		databuf[4] = 0; +		databuf[5] = (temp & RH_A_POTPGT) >> 24; +		databuf[6] = 0;  		temp = roothub_b(&gohci); -		databuf.u8[7] = temp & RH_B_DR; -		if (databuf.u8[2] < 7) { -			databuf.u8[8] = 0xff; +		databuf[7] = temp & RH_B_DR; +		if (databuf[2] < 7) { +			databuf[8] = 0xff;  		} else { -			databuf.u8[0] += 2; -			databuf.u8[8] = (temp & RH_B_DR) >> 8; -			databuf.u8[10] = databuf.u8[9] = 0xff; +			databuf[0] += 2; +			databuf[8] = (temp & RH_B_DR) >> 8; +			databuf[10] = databuf[9] = 0xff;  		}  		len = min_t(unsigned int, leni, -			    min_t(unsigned int, databuf.u8[0], wLength)); +			    min_t(unsigned int, databuf[0], wLength));  		OK(len);  	}  	case RH_GET_CONFIGURATION: -		databuf.u8[0] = 0x01; +		databuf[0] = 0x01;  		OK(1);  	case RH_SET_CONFIGURATION: @@ -1469,8 +1461,8 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,  #endif  	len = min_t(int, len, leni); -	if (data != databuf.ptr) -		memcpy(data, databuf.ptr, len); +	if (data != databuf) +		memcpy(data, databuf, len);  	dev->act_len = len;  	dev->status = stat; |