summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Makefile16
-rw-r--r--drivers/usb/da8xx_usb.c213
-rw-r--r--drivers/usb/da8xx_usb.h73
-rw-r--r--drivers/usb/musbhdrc.c885
-rw-r--r--drivers/usb/musbhdrc.h322
5 files changed, 1502 insertions, 7 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index f8ea167b12..013a78dda9 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -12,7 +12,7 @@
#
# 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
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
@@ -23,7 +23,7 @@
include $(TOPDIR)/config.mk
-LIB := $(obj)libusb.a
+LIB := $(obj)libusb.a
COBJS-y += isp116x-hcd.o
COBJS-y += sl811_usb.o
@@ -32,14 +32,16 @@ COBJS-y += usbdcore.o
COBJS-y += usbdcore_ep0.o
COBJS-y += usbdcore_mpc8xx.o
COBJS-y += usbdcore_omap1510.o
+COBJS-y += da8xx_usb.o
+COBJS-y += musbhdrc.o
-COBJS := $(COBJS-y)
-SRCS := $(COBJS:.o=.c)
-OBJS := $(addprefix $(obj),$(COBJS))
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
-all: $(LIB)
+all: $(LIB)
-$(LIB): $(obj).depend $(OBJS)
+$(LIB): $(obj).depend $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
#########################################################################
diff --git a/drivers/usb/da8xx_usb.c b/drivers/usb/da8xx_usb.c
new file mode 100644
index 0000000000..5dd5f12393
--- /dev/null
+++ b/drivers/usb/da8xx_usb.c
@@ -0,0 +1,213 @@
+/*
+ * TI's DA8xx platform specific usb wrapper functions.
+ *
+ * Copyright (c) 2004 Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named COPYING that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ *
+ * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
+ *
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_DA8XX
+
+#include "da8xx_usb.h"
+
+/* extern functions */
+extern void lpsc_on(unsigned int id);
+
+/* Timeout for DA8xx usb module */
+#define DA8XX_USB_TIMEOUT 0x3FFFF
+
+
+/* This function writes to a 32-bit register of platform usb wrapper */
+inline void pusb_writel( u32 offset , u32 value )
+{
+ *(volatile u32*)(DA8XX_USB0_BASE+offset) = value;
+}
+
+/* This function reads a 32-bit register of platform usb wrapper */
+inline u32 pusb_readl(u32 offset)
+{
+ return(*(volatile u32*)(DA8XX_USB0_BASE+offset));
+}
+
+/* This function writes to a 16-bit register of platform musb core */
+inline void musb_writew(u32 offset, u16 value)
+{
+ *(volatile u16*)(MENTOR_USB0_BASE+offset) = value;
+}
+
+/* This function writes to a 8-bit register of platform musb core */
+inline void musb_writeb(u32 offset, u8 value)
+{
+ *(volatile u8*)(MENTOR_USB0_BASE+offset) = value;
+}
+
+/* This function reads a 16-bit register of platform usb wrapper */
+inline u16 musb_readw(u32 offset)
+{
+ return(*(volatile u16*)(MENTOR_USB0_BASE + offset));
+}
+
+/* This function reads a 8-bit register of platform usb wrapper */
+inline u8 musb_readb(u32 offset)
+{
+ return(*(volatile u8*)(MENTOR_USB0_BASE+offset));
+}
+
+/*
+ * This function enables VBUS by driving the GPIO Bank4 Pin 15 high.
+ */
+static void enable_vbus(void)
+{
+ u32 value;
+
+ /* configure GPIO bank4 pin 15 in output direction */
+ value = *(volatile u32 *)GPIO_BANK4_REG_DIR_ADDR;
+ value &= ~0x8000;
+ *(volatile u32 *)GPIO_BANK4_REG_DIR_ADDR = value;
+
+ /* set GPIO bank4 pin 15 high to drive VBUS */
+ value = *(volatile u32 *)GPIO_BANK4_REG_SET_ADDR;
+ value |= 0x8000;
+ *(volatile u32 *)GPIO_BANK4_REG_SET_ADDR = value;
+}
+
+/*
+ * Enable the usb0 phy. This initialization procedure is explained in
+ * the DA8xx USB user guide document.
+ */
+static u8 phy_on( void )
+{
+ u32 timeout;
+ u8 result = 1;
+
+ /* write access keys */
+ *(volatile u32 *)(KICK0) = 0x83e70b13;
+ *(volatile u32 *)(KICK1) = 0x95a4f1e0;
+
+
+#ifdef CONFIG_USE_PINMUX
+
+ /* set PINMUX[7:4] = 1 */
+ *(volatile u32 *)(PINMUX9) |= ( 1 << 4 );
+ *(volatile u32 *)(PINMUX9) &= 0xFFFFFF7F;
+
+#endif
+
+ /* reset the usb controller */
+ pusb_writel( DA8XX_USB_CTRL_REG , 0x1 );
+ udelay( 5000 );
+
+ /* enable and then disable the usb phy reset */
+ *(volatile u32*)CFGCHIP2 |= 0x00008000;
+ udelay( 5000 );
+ *(volatile u32*)CFGCHIP2 &= 0xFFFF7FFF;
+ udelay( 5000 );
+
+ /* configure phy (refer to da8xx usb user guide use case section) */
+ *(volatile u32*)CFGCHIP2 &= 0xFFFF9FFF;
+ *(volatile u32*)CFGCHIP2 &= 0xFFFFFBFF;
+ *(volatile u32*)CFGCHIP2 &= 0xFFFFFDFF;
+ *(volatile u32*)CFGCHIP2 |= 0x00000100;
+ *(volatile u32*)CFGCHIP2 |= 0x00000020;
+ *(volatile u32*)CFGCHIP2 |= 0x00000010;
+ *(volatile u32*)CFGCHIP2 |= 0x00000002;
+ *(volatile u32*)CFGCHIP2 &= 0xFFFFE7FF;
+ *(volatile u32*)CFGCHIP2 |= 0x00000800;
+
+ *(volatile u32*)CFGCHIP2 &= 0xFFFF9FFF;
+ *(volatile u32*)CFGCHIP2 |= 0x00002000;
+ *(volatile u32*)CFGCHIP2 |= 0x00000040;
+
+ /* wait until the usb phy pll locks */
+ timeout = DA8XX_USB_TIMEOUT;
+ do {
+ timeout--;
+ if (timeout == 0)
+ break;
+ }
+ while(((*(volatile u32*)CFGCHIP2) & 0x00020000) == 0);
+
+ /* disable register access by writing invalid keys */
+ *(volatile u32 *)(0x01C14038) = 0x0;
+ *(volatile u32 *)(0x01C1403C) = 0x0;
+
+ if (timeout == 0)
+ result = 0;
+
+ return(result);
+}
+
+/*
+ * Disable the usb phy
+ */
+static void phy_off(void)
+{
+ /* write access keys */
+ *(volatile u32 *)(KICK0) = 0;
+ *(volatile u32 *)(KICK1) = 0;
+
+ /* powerdown the on-chip PHY and its oscillator */
+ *(volatile u32*)(CFGCHIP2) = 0x8600;
+}
+
+
+/*
+ * This function performs DA8xx platform specific initialization for usb0.
+ */
+int musb_platform_init(void)
+{
+ u32 revision;
+
+ /* enable psc for usb2.0 */
+ lpsc_on(33);
+
+ /* enable usb vbus */
+ enable_vbus();
+
+ /* start the on-chip usb phy and its pll */
+ if (phy_on() == 0)
+ return(-1);
+
+ /* reset the controller */
+ pusb_writel(DA8XX_USB_CTRL_REG, 0x1);
+ udelay(5000);
+
+ /* Returns zero if e.g. not clocked */
+ revision = pusb_readl(DA8XX_USB_VERSION_REG);
+ if (revision == 0)
+ return(-1);
+
+ /* Disable all interrupts */
+ pusb_writel(DA8XX_USB_INT_MASK_SET_REG, 0x01FF1F1F);
+ return(0);
+}
+
+
+/*
+ * This function performs DA8xx platform specific deinitialization for usb0.
+ */
+void musb_platform_deinit(void)
+{
+ /* Turn of the phy */
+ phy_off();
+
+ /* flush any interrupts */
+ pusb_writel(DA8XX_USB_INT_MASK_CLR_REG, DA8XX_USB_USBINT_MASK|DA8XX_USB_TXINT_MASK|DA8XX_USB_RXINT_MASK);
+ pusb_writel(DA8XX_USB_EOI_REG, 0);
+}
+
+#endif /* CONFIG_USB_DA8XX */
+
diff --git a/drivers/usb/da8xx_usb.h b/drivers/usb/da8xx_usb.h
new file mode 100644
index 0000000000..ffc0be39b1
--- /dev/null
+++ b/drivers/usb/da8xx_usb.h
@@ -0,0 +1,73 @@
+/*
+ * TI's DA8xx platform specific usb wrapper functions.
+ *
+ * Copyright (c) 2004 Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named COPYING that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ *
+ * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
+ *
+ */
+
+#ifndef __DA8XX_MUSB_H__
+#define __DA8XX_MUSB_H__
+
+#include "musbhdrc.h"
+
+/* Base address of da8xx usb0 wrapper */
+#define DA8XX_USB0_BASE 0x01E00000
+
+/* Base address of da8xx musb core */
+#define MENTOR_USB0_BASE (DA8XX_USB0_BASE+0x400)
+
+/* For now include usb OTG module registers here */
+#define DA8XX_USB_VERSION_REG 0x00
+#define DA8XX_USB_CTRL_REG 0x04
+#define DA8XX_USB_STAT_REG 0x08
+#define DA8XX_MODE_TGCR_REG 0x10 /* Mode reg RNDIS */
+#define DA8XX_AUTOREQ_REG 0x14
+#define DA8XX_SRP_FIXTIME_REG 0x18 /* SRP Fixtime reg */
+#define DA8XX_TEARDOWN_REG 0x1C /* TearDown Register*/
+#define DA8XX_USB_INT_SOURCE_REG 0x20
+#define DA8XX_USB_INT_SET_REG 0x24
+#define DA8XX_USB_INT_SRC_CLR_REG 0x28
+#define DA8XX_USB_INT_MASK_REG 0x2c
+#define DA8XX_USB_INT_MASK_SET_REG 0x30
+#define DA8XX_USB_INT_MASK_CLR_REG 0x34
+#define DA8XX_USB_INT_SRC_MASKED_REG 0x38
+#define DA8XX_USB_EOI_REG 0x3c
+#define DA8XX_USB_EOI_INTVEC 0x40
+#define DA8XX_GRNDIS_EP1SIZE_REG 0x50
+#define DA8XX_GRNDIS_EP2SIZE_REG 0x54
+#define DA8XX_GRNDIS_EP3SIZE_REG 0x58
+#define DA8XX_GRNDIS_EP4SIZE_REG 0x5C
+
+
+#define DA8XX_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
+#define DA8XX_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
+
+#define DA8XX_USB_USBINT_SHIFT 16
+#define DA8XX_USB_TXINT_SHIFT 0
+#define DA8XX_USB_RXINT_SHIFT 8
+
+#define DA8XX_INTR_DRVVBUS 0x0100
+
+#define DA8XX_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
+#define DA8XX_USB_TXINT_MASK \
+ (DA8XX_USB_TX_ENDPTS_MASK << DA8XX_USB_TXINT_SHIFT)
+#define DA8XX_USB_RXINT_MASK \
+ (DA8XX_USB_RX_ENDPTS_MASK << DA8XX_USB_RXINT_SHIFT)
+
+#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
+ (0x80 + (8*(_bEnd)) + (_bOffset))
+
+#endif /* __DA8XX_MUSB_H__ */
+
diff --git a/drivers/usb/musbhdrc.c b/drivers/usb/musbhdrc.c
new file mode 100644
index 0000000000..ff907f9afe
--- /dev/null
+++ b/drivers/usb/musbhdrc.c
@@ -0,0 +1,885 @@
+/*
+ * Mentor USB Core host controller driver.
+ *
+ * Copyright (c) 2004 Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named COPYING that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ *
+ * Copyright (c) 2003 Wolfgang Denk, wd@denx.de
+ *
+ */
+
+#include <common.h>
+
+/* Include usb hcd code if usb support is included in u-boot */
+#ifdef CONFIG_MUSB
+
+#include <usb.h>
+#include "musbhdrc.h"
+
+/* extern functions */
+extern int musb_platform_init(void);
+extern void musb_platform_deinit(void);
+extern inline void musb_writew(u32 offset, u16 value);
+extern inline void musb_writeb(u32 offset, u8 value);
+extern inline u16 musb_readw(u32 offset);
+extern inline u8 musb_readb(u32 offset);
+
+/* The controller driver polls for changes in the state. This defines a timeout
+ for cases where the states do not change so the appropriate error can be
+ returned. */
+#define MUSB_USB_TIMEOUT 0x3FFFFF
+
+/* This defines the endpoint number used for control transfers */
+#define MUSB_CONTROL_EP 0
+
+/* This defines the endpoint number used for bulk transfer */
+#define MUSB_BULK_EP 1
+
+/* Determine the operating speed of MUSB core */
+#define musb_ishighspeed() \
+ ((musb_readb(MGC_O_HDRC_POWER) & MGC_M_POWER_HSMODE) >> 4)
+
+/* speed negotiated with the connected device */
+static u8 musb_speed;
+
+/*
+ * This function configures all the endpoint FIFOs. Endpoint 1 is used for bulk
+ * transfers and so the fifo size of EP1 Tx and Rx is set to 512 bytes. The
+ * other endpoints 2,3 & 4 are configured for default fifo size of 64 bytes but
+ * these endpoints are not used.
+ */
+void musb_configure_ep(void)
+{
+ /* Select Endpoint 1 for bulk transfer */
+ musb_writeb(MGC_O_HDRC_INDEX, 1);
+
+ /* Configure FIFO for endpoint 1 */
+ musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x06);
+ musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x06);
+ musb_writew(MGC_O_HDRC_TXFIFOADD, 0x08);
+ musb_writew(MGC_O_HDRC_RXFIFOADD, 0x48);
+
+ /* Select Endpoint 2 for bulk transfer */
+ musb_writeb(MGC_O_HDRC_INDEX, 2);
+
+ /* Configure FIFO for endpoint 2 */
+ musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x03);
+ musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x03);
+ musb_writew(MGC_O_HDRC_TXFIFOADD, 0x88);
+ musb_writew(MGC_O_HDRC_RXFIFOADD, 0x90);
+
+ /* Select Endpoint 3 for bulk transfer */
+ musb_writeb(MGC_O_HDRC_INDEX, 3 );
+
+ /* Configure FIFO for endpoint 2 */
+ musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x03);
+ musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x03);
+ musb_writew(MGC_O_HDRC_TXFIFOADD, 0x98);
+ musb_writew(MGC_O_HDRC_RXFIFOADD, 0xA0);
+
+ /* Select Endpoint 3 for bulk transfer */
+ musb_writeb(MGC_O_HDRC_INDEX, 4 );
+
+ /* Configure FIFO for endpoint 2 */
+ musb_writeb(MGC_O_HDRC_TXFIFOSZ, 0x03);
+ musb_writeb(MGC_O_HDRC_RXFIFOSZ, 0x03);
+ musb_writew(MGC_O_HDRC_TXFIFOADD, 0xA8);
+ musb_writew(MGC_O_HDRC_RXFIFOADD, 0xB0);
+}
+
+/*
+ * program the HDRC to start (enable interrupts, dma, etc.)
+ */
+void musb_start( void )
+{
+ u8 devctl;
+
+ /* disable all interrupts */
+ musb_writew(MGC_O_HDRC_INTRTXE, 0x0000);
+ musb_writew(MGC_O_HDRC_INTRRXE, 0x0000);
+ musb_writeb(MGC_O_HDRC_INTRUSBE, 0x00);
+ musb_writeb(MGC_O_HDRC_TESTMODE, 0);
+
+ /* put into basic highspeed mode and start session */
+ musb_writeb(MGC_O_HDRC_POWER, (MGC_M_POWER_HSENAB));
+ devctl = musb_readb(MGC_O_HDRC_DEVCTL);
+ devctl |= MGC_M_DEVCTL_SESSION;
+ musb_writeb(MGC_O_HDRC_DEVCTL, devctl);
+}
+
+/*
+ * This function writes data to endpoint fifo
+ */
+static void write_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ u32 address;
+ u8 *data = (u8*)fifo_data;
+
+ /* select the endpoint index */
+ musb_writeb(MGC_O_HDRC_INDEX, ep);
+ address = MUSB_FIFO_OFFSET(ep)+0x20;
+
+ /* write the data to the fifo */
+ while(length) {
+ musb_writeb(address, *data);
+ data++;
+ length--;
+ }
+}
+
+/*
+ * This function reads data from endpoint fifo
+ */
+static void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ u32 address;
+ u8 *data = (u8*)fifo_data;
+
+ /* select the endpoint index */
+ musb_writeb(MGC_O_HDRC_INDEX, ep);
+ address = MUSB_FIFO_OFFSET(ep)+0x20;
+
+ /* read the data to the fifo */
+ while(length) {
+ *data = musb_readb(address);
+ data++;
+ length--;
+ }
+}
+
+/*
+ * This function performs all intializations required for setting up the
+ * bulk endpoint.
+ */
+static void setup_bulk_ep(u8 bulkep)
+{
+ u16 csr;
+
+ /* select bulk endpoint */
+ musb_writeb(MGC_O_HDRC_INDEX, bulkep);
+
+ /* clear the data toggle bit of bluk endpoint */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = csr | MGC_M_TXCSR_CLRDATATOG;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = csr | MGC_M_RXCSR_CLRDATATOG;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+
+ /* also, flush the Tx and Rx FIFO of endpoint 1 */
+ if ((musb_readb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) & MGC_M_TXCSR_TXPKTRDY) == MGC_M_TXCSR_TXPKTRDY) {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = csr | MGC_M_TXCSR_FLUSHFIFO;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+ }
+
+ if ((musb_readb(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR)) & MGC_M_RXCSR_RXPKTRDY) == MGC_M_RXCSR_RXPKTRDY) {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = csr | MGC_M_RXCSR_FLUSHFIFO;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+ }
+}
+
+/*
+ * This function checks if RxStall has occured on the endpoint. If a RxStall has
+ * occured, the RxStall is cleared and 1 is returned. If RxStall has not occured,
+ * 0 is returned.
+ */
+static u8 check_stall(u8 ep, u8 dir_out)
+{
+ u16 csr;
+
+ /* For endpoint 0 */
+ if (ep == 0) {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ if ((csr & MGC_M_CSR0_H_RXSTALL ) == MGC_M_CSR0_H_RXSTALL) {
+ csr = csr & ~(MGC_M_CSR0_H_RXSTALL|MGC_M_CSR0_H_STATUSPKT|MGC_M_CSR0_RXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+ return(1);
+ }
+ } else { /* For non-ep0 */
+ if (dir_out == 1) { /* is it tx ep */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ if ((csr & MGC_M_TXCSR_H_RXSTALL) == MGC_M_TXCSR_H_RXSTALL) {
+ csr = csr & ~(MGC_M_CSR0_H_RXSTALL|MGC_M_CSR0_H_STATUSPKT|MGC_M_CSR0_RXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+ return(1);
+ }
+ } else { /* is it rx ep */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ if ((csr & MGC_M_RXCSR_H_RXSTALL) == MGC_M_RXCSR_H_RXSTALL) {
+ csr = csr & ~(MGC_M_CSR0_H_RXSTALL|MGC_M_CSR0_H_STATUSPKT|MGC_M_CSR0_RXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+ return(1);
+ }
+ }
+ }
+
+ /* There is no RxStall at the endpoint */
+ return(0);
+}
+
+
+/*
+ * waits until ep0 is ready.
+ */
+static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
+{
+ u32 timeout;
+
+ timeout = MUSB_USB_TIMEOUT;
+ do {
+ /* is there a stall */
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ return( -2 );
+ }
+
+ switch(bit_mask) {
+ case MGC_M_CSR0_TXPKTRDY:
+ /* check if TXPKTRDY bit is cleared */
+ if ((musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)) & MGC_M_CSR0_TXPKTRDY) != MGC_M_CSR0_TXPKTRDY)
+ return(0);
+ break;
+
+ case MGC_M_CSR0_RXPKTRDY:
+ /* check if RXPKTRDY bit is set */
+ if ((musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)) & MGC_M_CSR0_RXPKTRDY) == MGC_M_CSR0_RXPKTRDY)
+ return(0);
+ break;
+
+ case MGC_M_CSR0_H_REQPKT:
+ /* check if the request has been sent */
+ if ((musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0)) & MGC_M_CSR0_H_REQPKT) != MGC_M_CSR0_H_REQPKT)
+ return(0);
+ break;
+ }
+ timeout--;
+ }
+ while(timeout > 0);
+
+ /* timed-out */
+ dev->status = USB_ST_CRC_ERR;
+ return(-1);
+}
+
+/*
+ * This function performs the setup phase of the control transfer
+ */
+static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
+{
+ int result = -1;
+ u16 csr;
+
+ /* write the control request to ep0 fifo */
+ write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void*)setup);
+
+ /* enable transfer of setup packet */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr | (MGC_M_CSR0_TXPKTRDY|MGC_M_CSR0_H_SETUPPKT);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ /* wait until the setup packet is transmitted */
+ result = wait_until_ep0_ready(dev, MGC_M_CSR0_TXPKTRDY);
+ dev->act_len = 0;
+
+ /* control transfer setup phase completes */
+ return(result);
+}
+
+/*
+ * This function handles the control transfer in data phase
+ */
+static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+ u16 csr;
+ u32 rxlen = 0;
+ u32 nextlen = 0;
+ u8 maxpktsize = ( 1 << dev->maxpacketsize ) * 8;
+ u8* rxbuff = (u8*)buffer;
+ u8 rxedlength;
+ int result;
+
+ do {
+ /* Determine the next read length */
+ nextlen = (( len-rxlen) > maxpktsize) ? maxpktsize:(len-rxlen);
+
+ /* Set the ReqPkt bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr | MGC_M_CSR0_H_REQPKT;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ result = wait_until_ep0_ready(dev, MGC_M_CSR0_RXPKTRDY);
+ if (result < 0)
+ return(result);
+
+ /* Actual number of bytes received by usb */
+ rxedlength = musb_readb(MGC_INDEXED_OFFSET(MGC_O_HDRC_COUNT0));
+
+ /* Read the data from the RxFIFO */
+ read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
+
+ /* Clear the RxPktRdy Bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr & (~MGC_M_CSR0_RXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ if (rxedlength != nextlen) {
+ dev->act_len += rxedlength;
+ break;
+ }
+
+ rxlen = rxlen + nextlen;
+ dev->act_len = rxlen;
+ }
+ while(rxlen < len);
+
+ /* done reading the data */
+ return(0);
+}
+
+/*
+ * This function handles the control transfer out data phase
+ */
+static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 maxpktsize = ( 1 << dev->maxpacketsize ) * 8;
+ u8* txbuff = (u8*)buffer;
+ int result;
+
+ do {
+ /* Determine the next write length */
+ nextlen = ((len-txlen) > maxpktsize) ? maxpktsize:(len-txlen);
+
+ /* Load the data to send in FIFO */
+ write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
+
+ /* Set TXPKTRDY bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr | (MGC_M_CSR0_H_DIS_PING|MGC_M_CSR0_TXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ result = wait_until_ep0_ready(dev, MGC_M_CSR0_TXPKTRDY);
+ if ( result < 0 )
+ return(result);
+
+ txlen = txlen + nextlen;
+ dev->act_len = txlen;
+ }
+ while(txlen < len);
+
+ /* done writing the data */
+ return(0);
+}
+
+
+/*
+ * This function handles the control transfer out status phase
+ */
+static int ctrlreq_out_status_phase(struct usb_device *dev)
+{
+ u16 csr;
+ int result;
+
+ /* Set the StatusPkt bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr | (MGC_M_CSR0_H_DIS_PING|MGC_M_CSR0_TXPKTRDY|MGC_M_CSR0_H_STATUSPKT);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ /* Wait until TXPKTRDY bit is cleared */
+ result = wait_until_ep0_ready(dev, MGC_M_CSR0_TXPKTRDY);
+ return(result);
+}
+
+
+/*
+ * This function handles the control transfer in status phase
+ */
+static int ctrlreq_in_status_phase(struct usb_device *dev)
+{
+ u16 csr;
+ int result;
+
+ /* Set the StatusPkt bit and ReqPkt bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr | (MGC_M_CSR0_H_DIS_PING|MGC_M_CSR0_H_REQPKT|MGC_M_CSR0_H_STATUSPKT);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ result = wait_until_ep0_ready(dev, MGC_M_CSR0_H_REQPKT);
+ if (result < 0)
+ return(result);
+
+ /* clear StatusPkt bit and RxPktRdy bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+ csr = csr & (~((MGC_M_CSR0_RXPKTRDY|MGC_M_CSR0_H_STATUSPKT)));
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), csr);
+
+ return(0);
+}
+
+
+/*
+ * determines the speed of the device (High/Full/Slow)
+ */
+static u8 get_dev_speed(struct usb_device *dev)
+{
+ if (dev->high == 1)
+ return(MGC_TYPE_SPEED_HIGH);
+ else
+ if (dev->slow == 1)
+ return(MGC_TYPE_SPEED_LOW);
+ else
+ return(MGC_TYPE_SPEED_FULL);
+}
+
+/*
+ * configure the hub address and the port address.
+ */
+static void config_hub_port(struct usb_device *dev, u8 ep)
+{
+ u8 chid;
+ u8 hub;
+
+ /* Find out the nearest parent which is high speed */
+ while(dev->parent->parent != NULL) {
+ if (get_dev_speed(dev->parent) != MGC_TYPE_SPEED_HIGH)
+ dev = dev->parent;
+ else
+ break;
+ }
+
+ /* determine the port address at that hub */
+ hub = dev->parent->devnum;
+ for (chid = 0; chid < USB_MAXCHILDREN; chid++)
+ if (dev->parent->children[chid] == dev)
+ break;
+
+ /* configure the hub address and the port address */
+ musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_TXHUBADDR), hub );
+ musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_TXHUBPORT), (chid+1) );
+ musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_RXHUBADDR), hub );
+ musb_writeb(MGC_BUSCTL_OFFSET(ep, MGC_O_HDRC_RXHUBPORT), (chid+1) );
+}
+
+/*
+ * do a control transfer
+ */
+int submit_control_msg( struct usb_device *dev , unsigned long pipe , void *buffer ,
+ int len , struct devrequest *setup )
+{
+ int devnum = usb_pipedevice(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ u16 csr;
+ u16 wIntrTxE;
+ u8 devspeed;
+
+ /* select control endpoint */
+ musb_writeb(MGC_O_HDRC_INDEX, MUSB_CONTROL_EP);
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0));
+
+ /* disable interrupt in case we flush */
+ wIntrTxE = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_INTRTXE));
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_INTRTXE), (wIntrTxE & ~(1 << ep)));
+
+ /* endpoint 0: just flush */
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), (csr|MGC_M_CSR0_FLUSHFIFO));
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_CSR0), (csr|MGC_M_CSR0_FLUSHFIFO));
+
+ /* target addr and (for multipoint) hub addr/port */
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_TXFUNCADDR), devnum);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_RXFUNCADDR), devnum);
+
+
+ /* configure the hub address and the port number as required */
+ if (( musb_ishighspeed()) && (dev->parent != NULL)) {
+ devspeed = get_dev_speed(dev);
+ if (devspeed != MGC_TYPE_SPEED_HIGH) {
+ config_hub_port(dev, MUSB_CONTROL_EP);
+ musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TYPE0), devspeed << 6);
+ }
+ } else {
+ musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TYPE0), musb_speed << 6);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_TXHUBADDR), 0);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_TXHUBPORT), 0);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_RXHUBADDR), 0);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_CONTROL_EP, MGC_O_HDRC_RXHUBPORT), 0);
+ }
+
+ /* Control transfer setup phase */
+ if (ctrlreq_setup_phase(dev, setup) < 0)
+ return(-1);
+
+ if ((setup->request == 0x06) || /* GET_DESCRIPTOR */
+ (setup->request == 0x08) || /* GET_CONFIGURATION */
+ (setup->request == 0x0A) || /* GET_INTERFACE */
+ (setup->request == 0x00)) { /* GET_STATUS */
+ /* control transfer in-data-phase */
+ if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
+ return(-1);
+
+ /* control transfer out-status-phase */
+ if (ctrlreq_out_status_phase(dev) < 0)
+ return(-1);
+ } else {
+ if ((setup->request == 0x05) || /* SET_ADDRESS */
+ (setup->request == 0x09) || /* SET_CONFIGURATION */
+ (setup->request == 0x03) || /* SET_FEATURE */
+ (setup->request == 0x03) || /* SET_FEATURE */
+ (setup->request == 0x0B) || /* SET_INTERFACE */
+ (setup->request == 0x01) || /* CLEAR_FEATURE */
+ (setup->request == 0xFF)) { /* USB Mass Stroage Reset */
+
+ /* control transfer in status phase */
+ if (ctrlreq_in_status_phase(dev) < 0)
+ return(-1);
+ } else {
+ if (setup->request == 0x07) { /* SET_DESCRIPTOR */
+ /* control transfer out data phase */
+ if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
+ return(-1);
+
+ /* control transfer in status phase */
+ if ( ctrlreq_in_status_phase(dev) < 0 )
+ return(-1);
+ } else {
+ /* unhandled control transfer */
+ return(-1);
+ }
+ }
+ }
+
+ /* end of control transfer */
+ dev->status = 0;
+ dev->act_len = len;
+ return len;
+}
+
+/*
+ * do a bulk transfer
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len)
+{
+ int dir_out = usb_pipeout(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ int devnum = usb_pipedevice(pipe);
+ u8 type;
+ u16 csr;
+ u32 txLen = 0;
+ u32 nextLen = 0;
+ u8 devspeed;
+ u32 timeout;
+
+ /* select bulk endpoint */
+ musb_writeb(MGC_O_HDRC_INDEX, MUSB_BULK_EP);
+
+ /* write the address of the device */
+ if ( dir_out == 1 )
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_TXFUNCADDR), devnum);
+ else
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_RXFUNCADDR), devnum);
+
+ /* configure the hub address and the port number as required */
+ if ((musb_ishighspeed()) && (dev->parent != NULL)) {
+ devspeed = get_dev_speed(dev);
+ if (devspeed != MGC_TYPE_SPEED_HIGH) {
+ /* MUSB is in high speed and the destination device is full speed device.
+ So configure the hub address and port address registers. */
+ config_hub_port(dev, MUSB_BULK_EP);
+ }
+ } else {
+ if (dir_out == 1) {
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_TXHUBADDR), 0);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_TXHUBPORT), 0);
+ } else {
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_RXHUBADDR), 0);
+ musb_writeb(MGC_BUSCTL_OFFSET(MUSB_BULK_EP, MGC_O_HDRC_RXHUBPORT), 0);
+ }
+ devspeed = musb_speed;
+ }
+
+ if (dir_out == 1) { /* bulk-out transfer */
+ /* Write the old data toggle value */
+ if (usb_gettoggle(dev, ep, dir_out) == 0) {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = MGC_M_TXCSR_CLRDATATOG;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+ } else {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = csr | MGC_M_TXCSR_H_WR_DATATOGGLE;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+
+ csr = csr | (usb_gettoggle(dev, ep, dir_out)<<8);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+ }
+
+ /* Program the TxType register */
+ type = (devspeed << MGC_S_TYPE_SPEED) |
+ (0x2 << MGC_S_TYPE_PROTO) |
+ (ep & 0xF);
+ musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXTYPE), type);
+
+ /* Write maximum packet size to the TxMaxp register */
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXMAXP), dev->epmaxpacketout[ep]);
+
+ while(txLen < len) {
+ nextLen = ((len-txLen) < dev->epmaxpacketout[ep]) ? (len-txLen):dev->epmaxpacketout[ep];
+
+ /* Write the data to the FIFO */
+ write_fifo(1, nextLen, (void*)(((u8*)buffer)+txLen));
+
+ /* Set the TxPktRdy bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = csr | MGC_M_TXCSR_TXPKTRDY;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+
+ /* Wait until the TxPktRdy bit is cleared */
+ timeout = MUSB_USB_TIMEOUT;
+ do {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ if ((csr & MGC_M_TXCSR_H_RXSTALL) == MGC_M_TXCSR_H_RXSTALL) {
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr & (~(MGC_M_TXCSR_H_RXSTALL)));
+
+ /* Keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01);
+
+ dev->status = USB_ST_STALLED;
+ dev->act_len = txLen;
+ return(0);
+ }
+
+ if ((csr & MGC_M_TXCSR_H_ERROR) == MGC_M_TXCSR_H_ERROR) {
+ /* keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01);
+ dev->status = USB_ST_CRC_ERR;
+ dev->act_len = txLen;
+ return(0);
+ }
+
+ /* maintain a timeout */
+ if (timeout-- == 0) {
+ /* keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01);
+ dev->status = USB_ST_CRC_ERR;
+ dev->act_len = txLen;
+
+ /* clear the TxPktRdy bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = csr & (~MGC_M_TXCSR_TXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+ return(0);
+ }
+ }
+ while((csr & MGC_M_TXCSR_TXPKTRDY) == MGC_M_TXCSR_TXPKTRDY);
+
+ txLen = txLen + nextLen;
+ #if 0
+ if ((txLen == len) && (nextLen == dev->epmaxpacketout[ep])) {
+ /* Set the TxPktRdy bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR));
+ csr = csr | MGC_M_TXCSR_TXPKTRDY;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR), csr);
+
+ /* Wait until the TxPktRdy bit is cleared */
+ while(( musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR) & MGC_M_TXCSR_TXPKTRDY)) == MGC_M_TXCSR_TXPKTRDY);
+ }
+ #endif
+ }
+
+ /* Keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_TXCSR)) >> 8) & 0x01);
+ } else { /* bulk-in transfer */
+ /* Write the old data toggle value */
+ if (usb_gettoggle(dev, ep, dir_out) == 0) {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = MGC_M_RXCSR_CLRDATATOG;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+ } else {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = csr | MGC_M_RXCSR_H_WR_DATATOGGLE;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+
+ csr = csr | (usb_gettoggle(dev, ep, dir_out)<<9);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+ }
+
+ /* Program the RxType register */
+ type = (devspeed << MGC_S_TYPE_SPEED) |
+ (0x2 << MGC_S_TYPE_PROTO) |
+ (ep & 0xF);
+ musb_writeb(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXTYPE), type);
+
+ /* Write the maximum packet size to the RxMaxp register */
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXMAXP), dev->epmaxpacketin[ep]);
+
+ while(txLen < len) {
+ nextLen = ((len-txLen) < dev->epmaxpacketin[ep]) ? (len-txLen):dev->epmaxpacketin[ep];
+
+ /* Set the ReqPkt bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = csr | MGC_M_RXCSR_H_REQPKT;
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+
+ /* Wait until the RxPktRdy bit is cleared */
+ timeout = MUSB_USB_TIMEOUT;
+ do {
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ if ((csr & MGC_M_RXCSR_H_RXSTALL) == MGC_M_RXCSR_H_RXSTALL) {
+ /* Keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01);
+
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr & (~(MGC_M_RXCSR_H_RXSTALL)));
+ dev->status = USB_ST_STALLED;
+ dev->act_len = txLen;
+ return(0);
+ }
+
+ if ((csr & MGC_M_RXCSR_H_ERROR) == MGC_M_RXCSR_H_ERROR) {
+ /* Keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01);
+ dev->status = USB_ST_CRC_ERR;
+ dev->act_len = txLen;
+ return(0);
+ }
+
+ if (timeout-- == 0) {
+ /* Keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01);
+ dev->status = USB_ST_CRC_ERR;
+ dev->act_len = txLen;
+
+ /* clear the ReqPkt bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = csr & (~MGC_M_RXCSR_H_REQPKT);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+ return(0);
+ }
+ }
+ while((csr & MGC_M_RXCSR_RXPKTRDY) != MGC_M_RXCSR_RXPKTRDY);
+
+ /* Read the data from the FIFO */
+ read_fifo(1, nextLen, (void*)(((u8*)buffer) + txLen));
+
+ /* Clear the RxPktRdy bit */
+ csr = musb_readw(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR));
+ csr = csr & ~(MGC_M_RXCSR_RXPKTRDY);
+ musb_writew(MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR), csr);
+
+ txLen = txLen + nextLen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ usb_settoggle(dev, ep, dir_out, (musb_readw( MGC_INDEXED_OFFSET(MGC_O_HDRC_RXCSR) ) >> 9) & 0x01);
+ }
+
+ /* bulk transfer is complete */
+ dev->status = 0;
+ dev->act_len = len;
+ return 0;
+}
+
+/*
+ * This function initializes the usb controller module.
+ */
+int usb_lowlevel_init(void)
+{
+ u8 power;
+ u32 timeout;
+
+ if (musb_platform_init() == -1)
+ return(-1);
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musb_configure_ep();
+ musb_start();
+
+ /* Wait until musb is enabled in host mode with a timeout. No hot
+ plug support. So there should be a usb device connected. */
+ timeout = MUSB_USB_TIMEOUT*0x10;
+ do {
+ /* wait until the musb core moves into host mode */
+ if (( musb_readb(MGC_O_HDRC_DEVCTL) & MGC_M_DEVCTL_HM) == MGC_M_DEVCTL_HM)
+ break;
+
+ /* maintain a timeout */
+ timeout--;
+ }
+ while( timeout > 0 );
+
+ /* if musb core is not in host mode, then return */
+ if (timeout == 0)
+ return( -1 );
+
+ /* start usb bus reset */
+ power = musb_readb(MGC_O_HDRC_POWER);
+ power = power | MGC_M_POWER_RESET;
+ musb_writeb(MGC_O_HDRC_POWER, power);
+
+ /* After initiating a usb reset, wait for about 20ms to 30ms */
+ udelay(30000);
+
+ /* stop usb bus reset */
+ power = musb_readb(MGC_O_HDRC_POWER);
+ power = power & (~MGC_M_POWER_RESET);
+ musb_writeb(MGC_O_HDRC_POWER, power);
+
+ /* Determine if the connected device is a high/full/low speed device */
+ if ((musb_readb(MGC_O_HDRC_POWER) & MGC_M_POWER_HSMODE) == MGC_M_POWER_HSMODE) {
+ /* High speed device is connected */
+ musb_speed = MGC_TYPE_SPEED_HIGH;
+ } else {
+ if ((musb_readb(MGC_O_HDRC_DEVCTL) & MGC_M_DEVCTL_FSDEV) == MGC_M_DEVCTL_FSDEV) {
+ /* Full speed device is connected */
+ musb_speed = MGC_TYPE_SPEED_FULL;
+ } else {
+ /* Low speed device is connected */
+ musb_speed = MGC_TYPE_SPEED_LOW;
+ }
+ }
+
+ /* setup the bulk endpoint */
+ setup_bulk_ep(MUSB_BULK_EP);
+
+ /* usb low level intialization is complete */
+ return(0);
+}
+
+/*
+ * This function stops the operation of the davinci usb module.
+ */
+int usb_lowlevel_stop(void)
+{
+ /* Reset the USB module */
+ musb_platform_deinit();
+ musb_writeb(MGC_O_HDRC_DEVCTL, 0);
+
+ /* All done */
+ return 0;
+}
+
+/*
+ * This function supports usb interrupt transfers. Currently, usb interrupt transfers
+ * are not supported.
+ */
+int submit_int_msg( struct usb_device *dev, unsigned long pipe ,
+ void *buffer , int len, int interval )
+{
+ return(-1);
+}
+
+#endif /* CONFIG_MUSB */
+
+
+
diff --git a/drivers/usb/musbhdrc.h b/drivers/usb/musbhdrc.h
new file mode 100644
index 0000000000..fba253e40b
--- /dev/null
+++ b/drivers/usb/musbhdrc.h
@@ -0,0 +1,322 @@
+/******************************************************************
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+/*
+ * HDRC-specific definitions
+ */
+
+#define MGC_MAX_USB_ENDS 4
+
+#define MGC_END0_FIFOSIZE 64 /* this is non-configurable */
+
+/*
+ * MUSBMHDRC Register map
+ */
+
+/* Common USB registers */
+
+#define MGC_O_HDRC_FADDR 0x00 /* 8-bit */
+#define MGC_O_HDRC_POWER 0x01 /* 8-bit */
+
+#define MGC_O_HDRC_INTRTX 0x02 /* 16-bit */
+#define MGC_O_HDRC_INTRRX 0x04
+#define MGC_O_HDRC_INTRTXE 0x06
+#define MGC_O_HDRC_INTRRXE 0x08
+#define MGC_O_HDRC_INTRUSB 0x0A /* 8 bit */
+#define MGC_O_HDRC_INTRUSBE 0x0B /* 8 bit */
+#define MGC_O_HDRC_FRAME 0x0C
+#define MGC_O_HDRC_INDEX 0x0E /* 8 bit */
+#define MGC_O_HDRC_TESTMODE 0x0F /* 8 bit */
+
+/* Get offset for a given FIFO from musb->pRegs */
+#ifdef CONFIG_USB_TUSB6010
+#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
+#else
+#define MUSB_FIFO_OFFSET(epnum) (epnum * 4)
+#endif
+
+/* Additional Control Registers */
+
+#define MGC_O_HDRC_DEVCTL 0x60 /* 8 bit */
+
+/* These are always controlled through the INDEX register */
+#define MGC_O_HDRC_TXFIFOSZ 0x62 /* 8-bit (see masks) */
+#define MGC_O_HDRC_RXFIFOSZ 0x63 /* 8-bit (see masks) */
+#define MGC_O_HDRC_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */
+#define MGC_O_HDRC_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */
+
+// vctrl/vstatus: optional vendor utmi+phy register at 0x68
+#define MGC_O_HDRC_HWVERS 0x6C /* 8 bit */
+
+#define MGC_O_HDRC_EPINFO 0x78 /* 8 bit */
+#define MGC_O_HDRC_RAMINFO 0x79 /* 8 bit */
+#define MGC_O_HDRC_LINKINFO 0x7a /* 8 bit */
+#define MGC_O_HDRC_VPLEN 0x7b /* 8 bit */
+#define MGC_O_HDRC_HS_EOF1 0x7c /* 8 bit */
+#define MGC_O_HDRC_FS_EOF1 0x7d /* 8 bit */
+#define MGC_O_HDRC_LS_EOF1 0x7e /* 8 bit */
+
+/* offsets to endpoint registers */
+#define MGC_O_HDRC_TXMAXP 0x00
+#define MGC_O_HDRC_TXCSR 0x02
+#define MGC_O_HDRC_CSR0 MGC_O_HDRC_TXCSR /* re-used for EP0 */
+#define MGC_O_HDRC_RXMAXP 0x04
+#define MGC_O_HDRC_RXCSR 0x06
+#define MGC_O_HDRC_RXCOUNT 0x08
+#define MGC_O_HDRC_COUNT0 MGC_O_HDRC_RXCOUNT /* re-used for EP0 */
+#define MGC_O_HDRC_TXTYPE 0x0A
+#define MGC_O_HDRC_TYPE0 MGC_O_HDRC_TXTYPE /* re-used for EP0 */
+#define MGC_O_HDRC_TXINTERVAL 0x0B
+#define MGC_O_HDRC_NAKLIMIT0 MGC_O_HDRC_TXINTERVAL /* re-used for EP0 */
+#define MGC_O_HDRC_RXTYPE 0x0C
+#define MGC_O_HDRC_RXINTERVAL 0x0D
+#define MGC_O_HDRC_FIFOSIZE 0x0F
+#define MGC_O_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */
+
+/* offsets to endpoint registers in indexed model (using INDEX register) */
+#define MGC_INDEXED_OFFSET(_bOffset) \
+ (0x10 + (_bOffset))
+
+/* offsets to endpoint registers in flat models */
+#define MGC_FLAT_OFFSET(_bEnd, _bOffset) \
+ (0x100 + (0x10*(_bEnd)) + (_bOffset))
+
+#ifdef CONFIG_USB_TUSB6010
+/* TUSB6010 EP0 configuration register is special */
+#define MGC_TUSB_OFFSET(_bEnd, _bOffset) \
+ (0x10 + _bOffset)
+#include "tusb6010.h" /* needed "only" for TUSB_EP0_CONF */
+#endif
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MGC_O_HDRC_TXFUNCADDR 0x00
+#define MGC_O_HDRC_TXHUBADDR 0x02
+#define MGC_O_HDRC_TXHUBPORT 0x03
+
+#define MGC_O_HDRC_RXFUNCADDR 0x04
+#define MGC_O_HDRC_RXHUBADDR 0x06
+#define MGC_O_HDRC_RXHUBPORT 0x07
+
+#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
+ (0x80 + (8*(_bEnd)) + (_bOffset))
+
+/*
+ * MUSBHDRC Register bit masks
+ */
+
+/* POWER */
+
+#define MGC_M_POWER_ISOUPDATE 0x80
+#define MGC_M_POWER_SOFTCONN 0x40
+#define MGC_M_POWER_HSENAB 0x20
+#define MGC_M_POWER_HSMODE 0x10
+#define MGC_M_POWER_RESET 0x08
+#define MGC_M_POWER_RESUME 0x04
+#define MGC_M_POWER_SUSPENDM 0x02
+#define MGC_M_POWER_ENSUSPEND 0x01
+
+/* INTRUSB */
+#define MGC_M_INTR_SUSPEND 0x01
+#define MGC_M_INTR_RESUME 0x02
+#define MGC_M_INTR_RESET 0x04
+#define MGC_M_INTR_BABBLE 0x04
+#define MGC_M_INTR_SOF 0x08
+#define MGC_M_INTR_CONNECT 0x10
+#define MGC_M_INTR_DISCONNECT 0x20
+#define MGC_M_INTR_SESSREQ 0x40
+#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */
+
+/* DEVCTL */
+#define MGC_M_DEVCTL_BDEVICE 0x80
+#define MGC_M_DEVCTL_FSDEV 0x40
+#define MGC_M_DEVCTL_LSDEV 0x20
+#define MGC_M_DEVCTL_VBUS 0x18
+#define MGC_S_DEVCTL_VBUS 3
+#define MGC_M_DEVCTL_HM 0x04
+#define MGC_M_DEVCTL_HR 0x02
+#define MGC_M_DEVCTL_SESSION 0x01
+
+/* TESTMODE */
+
+#define MGC_M_TEST_FORCE_HOST 0x80
+#define MGC_M_TEST_FIFO_ACCESS 0x40
+#define MGC_M_TEST_FORCE_FS 0x20
+#define MGC_M_TEST_FORCE_HS 0x10
+#define MGC_M_TEST_PACKET 0x08
+#define MGC_M_TEST_K 0x04
+#define MGC_M_TEST_J 0x02
+#define MGC_M_TEST_SE0_NAK 0x01
+
+/* allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MGC_M_FIFOSZ_DPB 0x10
+/* allocation size (8, 16, 32, ... 4096) */
+#define MGC_M_FIFOSZ_SIZE 0x0f
+
+/* CSR0 */
+#define MGC_M_CSR0_FLUSHFIFO 0x0100
+#define MGC_M_CSR0_TXPKTRDY 0x0002
+#define MGC_M_CSR0_RXPKTRDY 0x0001
+
+/* CSR0 in Peripheral mode */
+#define MGC_M_CSR0_P_SVDSETUPEND 0x0080
+#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040
+#define MGC_M_CSR0_P_SENDSTALL 0x0020
+#define MGC_M_CSR0_P_SETUPEND 0x0010
+#define MGC_M_CSR0_P_DATAEND 0x0008
+#define MGC_M_CSR0_P_SENTSTALL 0x0004
+
+/* CSR0 in Host mode */
+#define MGC_M_CSR0_H_DIS_PING 0x0800
+#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */
+#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */
+#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080
+#define MGC_M_CSR0_H_STATUSPKT 0x0040
+#define MGC_M_CSR0_H_REQPKT 0x0020
+#define MGC_M_CSR0_H_ERROR 0x0010
+#define MGC_M_CSR0_H_SETUPPKT 0x0008
+#define MGC_M_CSR0_H_RXSTALL 0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_CSR0_P_WZC_BITS \
+ ( MGC_M_CSR0_P_SENTSTALL )
+#define MGC_M_CSR0_H_WZC_BITS \
+ ( MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_RXSTALL \
+ | MGC_M_CSR0_RXPKTRDY )
+
+
+/* TxType/RxType */
+#define MGC_M_TYPE_SPEED 0xc0
+#define MGC_S_TYPE_SPEED 6
+#define MGC_TYPE_SPEED_HIGH 1
+#define MGC_TYPE_SPEED_FULL 2
+#define MGC_TYPE_SPEED_LOW 3
+#define MGC_M_TYPE_PROTO 0x30 /* implicitly zero for ep0 */
+#define MGC_S_TYPE_PROTO 4
+#define MGC_M_TYPE_REMOTE_END 0xf /* implicitly zero for ep0 */
+
+/* CONFIGDATA */
+
+#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */
+#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */
+#define MGC_M_CONFIGDATA_BIGENDIAN 0x20
+#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
+#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
+#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */
+#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
+#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+
+#define MGC_M_TXCSR_AUTOSET 0x8000
+#define MGC_M_TXCSR_MODE 0x2000
+#define MGC_M_TXCSR_DMAENAB 0x1000
+#define MGC_M_TXCSR_FRCDATATOG 0x0800
+#define MGC_M_TXCSR_DMAMODE 0x0400
+#define MGC_M_TXCSR_CLRDATATOG 0x0040
+#define MGC_M_TXCSR_FLUSHFIFO 0x0008
+#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002
+#define MGC_M_TXCSR_TXPKTRDY 0x0001
+
+/* TXCSR in Peripheral mode */
+
+#define MGC_M_TXCSR_P_ISO 0x4000
+#define MGC_M_TXCSR_P_INCOMPTX 0x0080
+#define MGC_M_TXCSR_P_SENTSTALL 0x0020
+#define MGC_M_TXCSR_P_SENDSTALL 0x0010
+#define MGC_M_TXCSR_P_UNDERRUN 0x0004
+
+/* TXCSR in Host mode */
+
+#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200
+#define MGC_M_TXCSR_H_DATATOGGLE 0x0100
+#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080
+#define MGC_M_TXCSR_H_RXSTALL 0x0020
+#define MGC_M_TXCSR_H_ERROR 0x0004
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_TXCSR_P_WZC_BITS \
+ ( MGC_M_TXCSR_P_INCOMPTX | MGC_M_TXCSR_P_SENTSTALL \
+ | MGC_M_TXCSR_P_UNDERRUN | MGC_M_TXCSR_FIFONOTEMPTY )
+#define MGC_M_TXCSR_H_WZC_BITS \
+ ( MGC_M_TXCSR_H_NAKTIMEOUT | MGC_M_TXCSR_H_RXSTALL \
+ | MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_FIFONOTEMPTY )
+
+
+/* RXCSR in Peripheral and Host mode */
+
+#define MGC_M_RXCSR_AUTOCLEAR 0x8000
+#define MGC_M_RXCSR_DMAENAB 0x2000
+#define MGC_M_RXCSR_DISNYET 0x1000
+#define MGC_M_RXCSR_PID_ERR 0x1000
+#define MGC_M_RXCSR_DMAMODE 0x0800
+#define MGC_M_RXCSR_INCOMPRX 0x0100
+#define MGC_M_RXCSR_CLRDATATOG 0x0080
+#define MGC_M_RXCSR_FLUSHFIFO 0x0010
+#define MGC_M_RXCSR_DATAERROR 0x0008
+#define MGC_M_RXCSR_FIFOFULL 0x0002
+#define MGC_M_RXCSR_RXPKTRDY 0x0001
+
+/* RXCSR in Peripheral mode */
+
+#define MGC_M_RXCSR_P_ISO 0x4000
+#define MGC_M_RXCSR_P_SENTSTALL 0x0040
+#define MGC_M_RXCSR_P_SENDSTALL 0x0020
+#define MGC_M_RXCSR_P_OVERRUN 0x0004
+
+/* RXCSR in Host mode */
+
+#define MGC_M_RXCSR_H_AUTOREQ 0x4000
+#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400
+#define MGC_M_RXCSR_H_DATATOGGLE 0x0200
+#define MGC_M_RXCSR_H_RXSTALL 0x0040
+#define MGC_M_RXCSR_H_REQPKT 0x0020
+#define MGC_M_RXCSR_H_ERROR 0x0004
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MGC_M_RXCSR_P_WZC_BITS \
+ ( MGC_M_RXCSR_P_SENTSTALL | MGC_M_RXCSR_P_OVERRUN \
+ | MGC_M_RXCSR_RXPKTRDY )
+#define MGC_M_RXCSR_H_WZC_BITS \
+ ( MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_H_ERROR \
+ | MGC_M_RXCSR_DATAERROR | MGC_M_RXCSR_RXPKTRDY )
+
+
+/* HUBADDR */
+#define MGC_M_HUBADDR_MULTI_TT 0x80
+
+
+#endif /* __MUSB_HDRC_DEFS_H__ */
+