diff options
-rwxr-xr-x[-rw-r--r--] | drivers/usb/Makefile | 2 | ||||
-rwxr-xr-x | drivers/usb/da8xx_usb.c | 214 | ||||
-rwxr-xr-x | drivers/usb/da8xx_usb.h | 73 | ||||
-rwxr-xr-x | drivers/usb/musbhdrc.c | 885 | ||||
-rwxr-xr-x | drivers/usb/musbhdrc.h | 322 | ||||
-rw-r--r-- | include/asm-arm/arch-da8xx/hardware.h | 8 | ||||
-rw-r--r-- | include/configs/da830_evm.h | 14 | ||||
-rw-r--r-- | include/configs/da850_evm.h | 15 | ||||
-rw-r--r-- | include/usb.h | 4 |
9 files changed, 1536 insertions, 1 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 856f51a75f1..ad2329c9576 100644..100755 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -33,6 +33,8 @@ COBJS-$(CONFIG_USB_OHCI_NEW) += usb_ohci.o COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o COBJS-$(CONFIG_USB_SL811HS) += sl811_usb.o +COBJS-$(CONFIG_USB_DA8XX) += da8xx_usb.o +COBJS-$(CONFIG_MUSB) += musbhdrc.o # device ifdef CONFIG_USB_DEVICE diff --git a/drivers/usb/da8xx_usb.c b/drivers/usb/da8xx_usb.c new file mode 100755 index 00000000000..6e46d436b0b --- /dev/null +++ b/drivers/usb/da8xx_usb.c @@ -0,0 +1,214 @@ +/* + * 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; +#if 0 + /* write access keys */ + *(volatile u32 *)(KICK0) = 0x83e70b13; + *(volatile u32 *)(KICK1) = 0x95a4f1e0; +#endif + +#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); +#if 0 + /* disable register access by writing invalid keys */ + *(volatile u32 *)(0x01C14038) = 0x0; + *(volatile u32 *)(0x01C1403C) = 0x0; +#endif + if (timeout == 0) + result = 0; + + return(result); +} + +/* + * Disable the usb phy + */ +static void phy_off(void) +{ +#if 0 + /* write access keys */ + *(volatile u32 *)(KICK0) = 0; + *(volatile u32 *)(KICK1) = 0; +#endif + /* 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 100755 index 00000000000..ffc0be39b18 --- /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 100755 index 00000000000..ff907f9afe3 --- /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 100755 index 00000000000..fba253e40b1 --- /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__ */ + diff --git a/include/asm-arm/arch-da8xx/hardware.h b/include/asm-arm/arch-da8xx/hardware.h index 3574971a507..d0709f15a61 100644 --- a/include/asm-arm/arch-da8xx/hardware.h +++ b/include/asm-arm/arch-da8xx/hardware.h @@ -196,6 +196,7 @@ #define PINMUX19 (DAVINCI_BOOTCFG_BASE + 0x16c) #define SUSPSRC (DAVINCI_BOOTCFG_BASE + 0x170) #define CFGCHIP0 (DAVINCI_BOOTCFG_BASE + 0x17c) +#define CFGCHIP2 (DAVINCI_BOOTCFG_BASE + 0x184) #define CFGCHIP3 (DAVINCI_BOOTCFG_BASE + 0x188) /* Interrupt controller */ @@ -203,6 +204,13 @@ #define INTC_HINT_EN (DAVINCI_INTC_BASE + 0x1500) #define INTC_EN_CLR0 (DAVINCI_INTC_BASE + 0x380) +/* GPIO */ +#define GPIO_BANK4_ADDR 0x01E26000 +#define GPIO_BANK4_REG_DIR_ADDR ( GPIO_BANK4_ADDR + 0x60 ) +#define GPIO_BANK4_REG_OPDATA_ADDR ( GPIO_BANK4_ADDR + 0x64 ) +#define GPIO_BANK4_REG_SET_ADDR ( GPIO_BANK4_ADDR + 0x68 ) +#define GPIO_BANK4_REG_CLR_ADDR ( GPIO_BANK4_ADDR + 0x6C ) + #ifndef __ASSEMBLY__ diff --git a/include/configs/da830_evm.h b/include/configs/da830_evm.h index 3ca92cbe655..24a36ffa66e 100644 --- a/include/configs/da830_evm.h +++ b/include/configs/da830_evm.h @@ -170,6 +170,13 @@ #define CONFIG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED #endif +/*==============================*/ +/* USB configuration */ +/*==============================*/ +#define CONFIG_MUSB /* Generic MUSB controller */ +#define CONFIG_USB_DA8XX /* Platform hookup to MUSB controller */ +#define CONFIG_USB_STORAGE /* MSC class support */ + /*==============================*/ /* U-Boot general configuration */ @@ -250,4 +257,11 @@ #undef CONFIG_CMD_ENV #endif +#ifdef CONFIG_USB_DA8XX +#define CONFIG_CMD_USB /* inclue support for usb */ +#define CONFIG_CMD_STORAGE /* inclue support for usb */ +#define CONFIG_CMD_FAT /* inclue support for FAT/storage*/ +#define CONFIG_DOS_PARTITION /* inclue support for FAT/storage*/ +#endif + #endif /* __CONFIG_H */ diff --git a/include/configs/da850_evm.h b/include/configs/da850_evm.h index ce7820a725c..4de2e139f48 100644 --- a/include/configs/da850_evm.h +++ b/include/configs/da850_evm.h @@ -160,6 +160,13 @@ /*==============================*/ +/* USB configuration */ +/*==============================*/ +#define CONFIG_MUSB /* Generic MUSB controller */ +#define CONFIG_USB_DA8XX /* Platform hookup to MUSB controller */ +#define CONFIG_USB_STORAGE /* MSC class support */ + +/*==============================*/ /* U-Boot general configuration */ /*==============================*/ /* No IRQ/FIQ in U-Boot */ @@ -238,4 +245,12 @@ #undef CONFIG_CMD_ENV #endif +#ifdef CONFIG_USB_DA8XX +#define CONFIG_CMD_USB /* inclue support for usb */ +#define CONFIG_CMD_STORAGE /* inclue support for usb */ +#define CONFIG_CMD_FAT /* inclue support for FAT/storage*/ +#define CONFIG_DOS_PARTITION /* inclue support for FAT/storage*/ +#endif + + #endif /* __CONFIG_H */ diff --git a/include/usb.h b/include/usb.h index 510df95d628..bc1c14a09dd 100644 --- a/include/usb.h +++ b/include/usb.h @@ -139,6 +139,7 @@ enum { struct usb_device { int devnum; /* Device number on USB bus */ int slow; /* Slow device? */ + int high; /* High Speed */ char mf[32]; /* manufacturer */ char prod[32]; /* product */ char serial[32]; /* serial number */ @@ -181,7 +182,8 @@ struct usb_device { #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \ defined(CONFIG_USB_OHCI_NEW) || defined(CONFIG_USB_SL811HS) || \ - defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_R8A66597_HCD) + defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_R8A66597_HCD) || \ + defined(CONFIG_MUSB) int usb_lowlevel_init(void); int usb_lowlevel_stop(void); |