Patchwork [U-Boot,V2] USB:gadget:designware USB OTG implementation

login
register
mail settings
Submitter Amit Virdi
Date April 3, 2012, 2:20 p.m.
Message ID <27065c311969ab4ce9d10fba7921ed9f47970d6e.1333462753.git.amit.virdi@st.com>
Download mbox | patch
Permalink /patch/150451/
State Superseded
Delegated to: Marek Vasut
Headers show

Comments

Amit Virdi - April 3, 2012, 2:20 p.m.
From: Pratyush Anand <pratyush.anand@st.com>

Driver for designware otg device only implements device functionality
and is meant to be used with usbtty interface.
This driver will work mainly for Control and Bulk endpoints. Periodic
transfer has not been verified using these drivers.

Signed-off-by: Pratyush Anand <pratyush.anand@st.com>
Signed-off-by: Amit Virdi <amit.virdi@st.com>
---
 drivers/serial/usbtty.h             |    2 +
 drivers/usb/gadget/Makefile         |    1 +
 drivers/usb/gadget/designware_otg.c |  990 +++++++++++++++++++++++++++++++++++
 include/usb/designware_otg.h        |  523 ++++++++++++++++++
 4 files changed, 1516 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/gadget/designware_otg.c
 create mode 100644 include/usb/designware_otg.h
Marek Vasut - April 4, 2012, 8:23 a.m.
Dear Amit Virdi,

> From: Pratyush Anand <pratyush.anand@st.com>
> 
> Driver for designware otg device only implements device functionality
> and is meant to be used with usbtty interface.
> This driver will work mainly for Control and Bulk endpoints. Periodic
> transfer has not been verified using these drivers.
> 
> Signed-off-by: Pratyush Anand <pratyush.anand@st.com>
> Signed-off-by: Amit Virdi <amit.virdi@st.com>
> ---
>  drivers/serial/usbtty.h             |    2 +
>  drivers/usb/gadget/Makefile         |    1 +
>  drivers/usb/gadget/designware_otg.c |  990
> +++++++++++++++++++++++++++++++++++ include/usb/designware_otg.h        | 
> 523 ++++++++++++++++++
>  4 files changed, 1516 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/usb/gadget/designware_otg.c
>  create mode 100644 include/usb/designware_otg.h
> 
> diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
> index eb670da..bd3bcbc 100644
> --- a/drivers/serial/usbtty.h
> +++ b/drivers/serial/usbtty.h
> @@ -35,6 +35,8 @@
>  #include <usb/pxa27x_udc.h>
>  #elif defined(CONFIG_DW_UDC)
>  #include <usb/designware_udc.h>
> +#elif defined(CONFIG_DW_OTG)
> +#include <usb/designware_otg.h>
>  #endif
> 
>  #include <version.h>
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index 87d1918..ede367e 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -40,6 +40,7 @@ ifdef CONFIG_USB_DEVICE
>  COBJS-y += core.o
>  COBJS-y += ep0.o
>  COBJS-$(CONFIG_DW_UDC) += designware_udc.o
> +COBJS-$(CONFIG_DW_OTG) += designware_otg.o
>  COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o
>  COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o
>  COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
> diff --git a/drivers/usb/gadget/designware_otg.c
> b/drivers/usb/gadget/designware_otg.c new file mode 100644
> index 0000000..5af6940
> --- /dev/null
> +++ b/drivers/usb/gadget/designware_otg.c
> @@ -0,0 +1,990 @@
> +/*
> + * Based on drivers/usb/gadget/designware_otg.c
> + * Synopsys DW OTG Device bus interface driver
> + *
> + * (C) Copyright 2011
> + * Pratyush Anand, ST Micoelectronics, pratyush.anand@st.com.
> + *
> + * (C) Copyright 2012
> + * Amit Virdi, ST Micoelectronics, amit.virdi@st.com.
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <usbdevice.h>
> +#include <watchdog.h>
> +#include "ep0.h"
> +#include <usb/designware_otg.h>
> +#include <asm/arch/hardware.h>
> +
> +#define UDC_INIT_MDELAY		80	/* Device settle delay */
> +
> +static struct urb *ep0_urb;
> +static struct usb_device_instance *udc_device;
> +
> +static struct device_if	device_if_mem;
> +static struct device_if	*dev_if = &device_if_mem;
> +
> +#if defined(CONFIG_USBD_HS)
> +#define CONFIG_USBD_SERIAL_BULK_PKTSIZE	UDC_BULK_HS_PACKET_SIZE
> +#endif
> +
> +void udc_set_nak(int epid)
> +{
> +	setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, SNAK);
> +	setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, SNAK);
> +}
> +
> +void udc_unset_nak(int epid)
> +{
> +	setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, CNAK);
> +	setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, CNAK);
> +}
> +
> +static void udc_set_stall(int epid, int dir)
> +{
> +	if (dir)
> +		setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, SSTALL);
> +	else
> +		setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, SSTALL);
> +}
> +
> +/*
> + * This function enables EP0 OUT to receive SETUP packets and configures
> EP0 + * IN for transmitting packets. It is normally called when the
> "Enumeration + * Done" interrupt occurs.
> + */
> +static void dwc_otg_ep0_activate(void)
> +{
> +	struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[0];
> +	struct device_out_ep_regs *out_ep_regs = dev_if->out_ep_regs[0];
> +
> +	/* Read the Device Status and Endpoint 0 Control registers */
> +	clrsetbits_le32(&in_ep_regs->diepctl, MPSMSK0, DWC_DEP0CTL_MPS_64);
> +
> +	/* Enable OUT EP for receive */
> +	setbits_le32(&out_ep_regs->doepctl, EPENA);
> +}
> +
> +static struct usb_endpoint_instance *dw_find_ep(int ep)
> +{
> +	int i;
> +
> +	for (i = 0; i < udc_device->bus->max_endpoints; i++) {
> +		if ((udc_device->bus->endpoint_array[i].endpoint_address &
> +					USB_ENDPOINT_NUMBER_MASK) == ep)
> +			return &udc_device->bus->endpoint_array[i];
> +	}
> +	return NULL;
> +}
> +
> +/*
> + * This function reads a packet from the Rx FIFO into the destination
> buffer. + * To read SETUP data use dwc_otg_read_setup_packet.
> + */
> +static void dwc_otg_read_packet(struct dwc_ep *ep, u16 bytes)
> +{
> +	u32 i;
> +	int word_count = (bytes + 3) / 4;
> +	u32 *fifo = dev_if->data_fifo[0];
> +	u32 *data_buff = (u32 *) ep->xfer_buff;
> +	u32 unaligned;
> +	/*
> +	 * This requires reading data from the FIFO into a u32 temp buffer,
> +	 * then moving it into the data buffer.
> +	 */
> +	if ((bytes < 4) && (bytes > 0)) {
> +		unaligned = readl(fifo);
> +		memcpy(data_buff, &unaligned, bytes);
> +	} else {
> +		for (i = 0; i < word_count; i++, data_buff++)
> +			*data_buff = readl(fifo);

Thinking of this, will this really handle unaligned access of length for example 
5 ?

> +	}
> +}
> +
> +/* Handle RX transaction on non-ISO endpoint. */
> +static void dw_udc_epn_rx(struct dwc_ep *ep, int bcnt)
> +{
> +	struct urb *urb;
> +	struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
> +
> +	if (endpoint) {

if (!endpoint)
 return;

... code ...

> +		urb = endpoint->rcv_urb;
> +
> +		if (urb) {
> +			ep->xfer_buff = urb->buffer + urb->actual_length;
> +			dwc_otg_read_packet(ep, bcnt);
> +			usbd_rcv_complete(endpoint, bcnt, 0);
> +		}
> +	}
> +}
> +
> +/*
> + * This function writes a packet into the Tx FIFO associated with the EP.
> + * The buffer is padded to DWORD on a per packet basis in
> + * slave/dma mode if the MPS is not DWORD aligned. The last packet, if
> + * short, is also padded to a multiple of DWORD.
> + *
> + * ep->xfer_buff always starts DWORD aligned in memory and is a
> + * multiple of DWORD in length
> + *
> + * ep->xfer_len can be any number of bytes
> + *
> + * FIFO access is DWORD
> + */
> +static void dwc_otg_ep_write_packet(struct dwc_ep *ep)
> +{
> +	u32 i;
> +	u32 dword_count;
> +	u32 *fifo;
> +	u32 *data_buff = (u32 *) ep->xfer_buff;
> +	u32 temp, unaligned;
> +	u32 timeout = 1; /* 1ms as the timeout */
> +	ulong start;
> +	struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[ep->num];
> +	struct core_global_regs *core_global_regs = dev_if->core_global_regs;
> +
> +	/*
> +	 * Find the DWORD length, padded by extra bytes as neccessary if MPS
> +	 * is not a multiple of DWORD
> +	 */
> +	dword_count = (ep->xfer_len + 3) / 4;
> +	fifo = dev_if->data_fifo[ep->num];
> +
> +	/* program pkt count */
> +	temp = ep->xfer_len;
> +	temp |= (1 << PKTCNT_SHIFT);
> +	writel(temp, &in_ep_regs->dieptsiz);
> +
> +	/* enable EP*/

missing space before ending comment

> +	setbits_le32(&in_ep_regs->diepctl, EPENA | CNAK);
> +
> +	/* clear TX Fifo Empty intr*/
> +	writel(NPTXFEMPTY, &core_global_regs->gintsts);
> +
> +	setbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
> +
> +	start = get_timer(0);
> +	while (!(readl(&core_global_regs->gintsts) & NPTXFEMPTY)) {
> +		if (get_timer(start) > timeout) {
> +			printf("%s: NPTXFEMPTY: TimeOUT\n", __func__);
> +			WATCHDOG_RESET();
> +		}
> +	}
> +
> +	/* write to fifo */
> +	if ((ep->xfer_len < 4) && (ep->xfer_len > 0)) {
> +		memcpy(&unaligned, data_buff, ep->xfer_len);
> +		*fifo = unaligned;
> +	} else {
> +		for (i = 0; i < dword_count; i++, data_buff++)
> +			*fifo = *data_buff;

DTTO, will this handle unaligned xfer of size > 4 properly ?

> +	}
> +
> +	writel(NPTXFEMPTY, &core_global_regs->gintsts);
> +
> +	/* check for transfer completion*/
> +	start = get_timer(0);
> +	while (!(readl(&in_ep_regs->diepint) & XFERCOMPL)) {
> +		if (get_timer(start) > timeout) {
> +			printf("%s: XFERCOMPLE: TimeOUT\n", __func__);
> +			WATCHDOG_RESET();
> +		}
> +	}
> +
> +	writel(XFERCOMPL, &in_ep_regs->diepint);
> +	clrbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
> +}
> +
> +/* Handle TX transaction on non-ISO endpoint. */
> +static void dw_udc_epn_tx(struct dwc_ep *ep)
> +{
> +	struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
> +	struct urb *urb = endpoint->tx_urb;
> +	int align;
> +
> +	if (!endpoint)
> +		return;
> +
> +	/*
> +	 * We need to transmit a terminating zero-length packet now if
> +	 * we have sent all of the data in this URB and the transfer
> +	 * size was an exact multiple of the packet size.
> +	 */
> +	if (urb && (endpoint->last == endpoint->tx_packetSize) &&
> +			(urb->actual_length - endpoint->sent -
> +			 endpoint->last == 0)) {
> +		/* handle zero length packet here */
> +		ep->xfer_len = 0;
> +		dwc_otg_ep_write_packet(ep);
> +	}
> +
> +	if (urb && urb->actual_length) {
> +		/* retire the data that was just sent */
> +		usbd_tx_complete(endpoint);
> +		/*
> +		 * Check to see if we have more data ready to transmit
> +		 * now.
> +		 */
> +		if (urb && urb->actual_length) {
> +			/* write data to FIFO */
> +			ep->xfer_len = MIN(urb->actual_length - endpoint->sent,
> +					endpoint->tx_packetSize);
> +
> +			if (ep->xfer_len) {
> +				ep->xfer_buff = urb->buffer + endpoint->sent;
> +
> +				/*
> +				 * This ensures that USBD packet fifo is
> +				 * accessed through word aligned pointer or
> +				 * through non word aligned pointer but only
> +				 * with a max length to make the next packet
> +				 * word aligned
> +				 */
> +
> +				align = ((ulong)ep->xfer_buff % sizeof(int));
> +				if (align)
> +					ep->xfer_len = MIN(ep->xfer_len,
> +							sizeof(int)-align);
> +
> +				dwc_otg_ep_write_packet(ep);
> +			}
> +			endpoint->last = ep->xfer_len;
> +
> +		}
> +	}
> +}
> +
> +/* This function returns pointer to out ep struct with number num */
> +static struct dwc_ep *get_out_ep(u32 num)
> +{
> +	u32 i;
> +	int num_out_eps = MAX_EPS_CHANNELS;
> +	struct dwc_pcd *pcd = &dev_if->pcd;
> +
> +	if (num == 0)
> +		return &pcd->ep0;
> +
> +	for (i = 0; i < num_out_eps; ++i) {

i++ ... ++i has no meaning here (not even a compiler hint).

> +		if (pcd->out_ep[i].num == num)
> +			return &pcd->out_ep[i];
> +	}
> +
> +	return 0;
> +}
> +
> +/* This function returns pointer to in ep struct with number num */
> +static struct dwc_ep *get_in_ep(u32 num)
> +{
> +	u32 i;
> +	int num_out_eps = MAX_EPS_CHANNELS;
> +	struct dwc_pcd *pcd = &dev_if->pcd;
> +
> +	if (num == 0)
> +		return &pcd->ep0;
> +
> +	for (i = 0; i < num_out_eps; ++i) {
> +		if (pcd->in_ep[i].num == num)
> +			return &pcd->in_ep[i];
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * This function reads the 8 bytes of the setup packet from the Rx FIFO
> into the + * destination buffer. It is called from the Rx Status Queue
> Level (RxStsQLvl) + * interrupt routine when a SETUP packet has been
> received in Slave mode. + */
> +static void dwc_otg_read_setup_packet(u32 *dest)
> +{
> +	dest[0] = readl(dev_if->data_fifo[0]);
> +	dest[1] = readl(dev_if->data_fifo[0]);
> +}
> +
> +/*
> + * This function handles the Rx Status Queue Level Interrupt, which
> + * indicates that there is a least one packet in the Rx FIFO. The
> + * packets are moved from the FIFO to memory, where they will be
> + * processed when the Endpoint Interrupt Register indicates Transfer
> + * Complete or SETUP Phase Done.
> + *
> + * Repeat the following until the Rx Status Queue is empty:
> + *	 -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
> + *		info
> + *	 -# If Receive FIFO is empty then skip to step Clear the interrupt
> + *		and exit
> + *	 -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
> + *		SETUP data to the buffer
> + *	 -# If OUT Data Packet call dwc_otg_read_packet to copy the data
> + *		to the destination buffer
> + */

Otherwise, I think you did a pretty decent job, one more round and I'm queueing 
this ;-)
Amit Virdi - April 9, 2012, 8:38 a.m.
Dear Marek,

[...]

>> +static void dwc_otg_read_packet(struct dwc_ep *ep, u16 bytes)
>> +{
>> +     u32 i;
>> +     int word_count = (bytes + 3) / 4;
>> +     u32 *fifo = dev_if->data_fifo[0];
>> +     u32 *data_buff = (u32 *) ep->xfer_buff;
>> +     u32 unaligned;
>> +     /*
>> +      * This requires reading data from the FIFO into a u32 temp buffer,
>> +      * then moving it into the data buffer.
>> +      */
>> +     if ((bytes<  4)&&  (bytes>  0)) {
>> +             unaligned = readl(fifo);
>> +             memcpy(data_buff,&unaligned, bytes);
>> +     } else {
>> +             for (i = 0; i<  word_count; i++, data_buff++)
>> +                     *data_buff = readl(fifo);
>
> Thinking of this, will this really handle unaligned access of length for example
> 5 ?
>

If data_buff is unaligned, there will be a problem!

>> +     }
>> +}
>> +
>> +/* Handle RX transaction on non-ISO endpoint. */
>> +static void dw_udc_epn_rx(struct dwc_ep *ep, int bcnt)
>> +{
>> +     struct urb *urb;
>> +     struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
>> +
>> +     if (endpoint) {
>
> if (!endpoint)
>   return;
>
> ... code ...
>

Ok.


>> +             urb = endpoint->rcv_urb;
>> +
>> +             if (urb) {
>> +                     ep->xfer_buff = urb->buffer + urb->actual_length;
>> +                     dwc_otg_read_packet(ep, bcnt);
>> +                     usbd_rcv_complete(endpoint, bcnt, 0);
>> +             }
>> +     }
>> +}

[...]

>> +     /* program pkt count */
>> +     temp = ep->xfer_len;
>> +     temp |= (1<<  PKTCNT_SHIFT);
>> +     writel(temp,&in_ep_regs->dieptsiz);
>> +
>> +     /* enable EP*/
>
> missing space before ending comment
>

Ok, 'll correct.

>> +     setbits_le32(&in_ep_regs->diepctl, EPENA | CNAK);
>> +
>> +     /* clear TX Fifo Empty intr*/
>> +     writel(NPTXFEMPTY,&core_global_regs->gintsts);
>> +
>> +     setbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
>> +
>> +     start = get_timer(0);
>> +     while (!(readl(&core_global_regs->gintsts)&  NPTXFEMPTY)) {
>> +             if (get_timer(start)>  timeout) {
>> +                     printf("%s: NPTXFEMPTY: TimeOUT\n", __func__);
>> +                     WATCHDOG_RESET();
>> +             }
>> +     }
>> +
>> +     /* write to fifo */
>> +     if ((ep->xfer_len<  4)&&  (ep->xfer_len>  0)) {
>> +             memcpy(&unaligned, data_buff, ep->xfer_len);
>> +             *fifo = unaligned;
>> +     } else {
>> +             for (i = 0; i<  dword_count; i++, data_buff++)
>> +                     *fifo = *data_buff;
>
> DTTO, will this handle unaligned xfer of size>  4 properly ?
>

Again, this part needs to be made more generic. I'll amend it in V3.

>> +     }
>> +
>> +     writel(NPTXFEMPTY,&core_global_regs->gintsts);
>> +

[...]

>> +/* This function returns pointer to out ep struct with number num */
>> +static struct dwc_ep *get_out_ep(u32 num)
>> +{
>> +     u32 i;
>> +     int num_out_eps = MAX_EPS_CHANNELS;
>> +     struct dwc_pcd *pcd =&dev_if->pcd;
>> +
>> +     if (num == 0)
>> +             return&pcd->ep0;
>> +
>> +     for (i = 0; i<  num_out_eps; ++i) {
>
> i++ ... ++i has no meaning here (not even a compiler hint).
>

Ok, 'll amend

>> +             if (pcd->out_ep[i].num == num)
>> +                     return&pcd->out_ep[i];
>> +     }
>> +
>> +     return 0;
>> +}
>> +

[...]

>> + *           to the destination buffer
>> + */
>
> Otherwise, I think you did a pretty decent job, one more round and I'm queueing
> this ;-)
>
> .

:)

Sorry for my delayed response.

Best Regards
Amit Virdi
Marek Vasut - April 9, 2012, 8:49 a.m.
Dear Amit Virdi,

> Dear Marek,
> 
> [...]
> 
> >> +static void dwc_otg_read_packet(struct dwc_ep *ep, u16 bytes)
> >> +{
> >> +     u32 i;
> >> +     int word_count = (bytes + 3) / 4;
> >> +     u32 *fifo = dev_if->data_fifo[0];
> >> +     u32 *data_buff = (u32 *) ep->xfer_buff;
> >> +     u32 unaligned;
> >> +     /*
> >> +      * This requires reading data from the FIFO into a u32 temp
> >> buffer, +      * then moving it into the data buffer.
> >> +      */
> >> +     if ((bytes<  4)&&  (bytes>  0)) {
> >> +             unaligned = readl(fifo);
> >> +             memcpy(data_buff,&unaligned, bytes);
> >> +     } else {
> >> +             for (i = 0; i<  word_count; i++, data_buff++)
> >> +                     *data_buff = readl(fifo);
> > 
> > Thinking of this, will this really handle unaligned access of length for
> > example 5 ?
> 
> If data_buff is unaligned, there will be a problem!
> 
> >> +     }
> >> +}
> >> +
> >> +/* Handle RX transaction on non-ISO endpoint. */
> >> +static void dw_udc_epn_rx(struct dwc_ep *ep, int bcnt)
> >> +{
> >> +     struct urb *urb;
> >> +     struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
> >> +
> >> +     if (endpoint) {
> > 
> > if (!endpoint)
> > 
> >   return;
> > 
> > ... code ...
> 
> Ok.
> 
> >> +             urb = endpoint->rcv_urb;
> >> +
> >> +             if (urb) {
> >> +                     ep->xfer_buff = urb->buffer + urb->actual_length;
> >> +                     dwc_otg_read_packet(ep, bcnt);
> >> +                     usbd_rcv_complete(endpoint, bcnt, 0);
> >> +             }
> >> +     }
> >> +}
> 
> [...]
> 
> >> +     /* program pkt count */
> >> +     temp = ep->xfer_len;
> >> +     temp |= (1<<  PKTCNT_SHIFT);
> >> +     writel(temp,&in_ep_regs->dieptsiz);
> >> +
> >> +     /* enable EP*/
> > 
> > missing space before ending comment
> 
> Ok, 'll correct.
> 
> >> +     setbits_le32(&in_ep_regs->diepctl, EPENA | CNAK);
> >> +
> >> +     /* clear TX Fifo Empty intr*/
> >> +     writel(NPTXFEMPTY,&core_global_regs->gintsts);
> >> +
> >> +     setbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
> >> +
> >> +     start = get_timer(0);
> >> +     while (!(readl(&core_global_regs->gintsts)&  NPTXFEMPTY)) {
> >> +             if (get_timer(start)>  timeout) {
> >> +                     printf("%s: NPTXFEMPTY: TimeOUT\n", __func__);
> >> +                     WATCHDOG_RESET();
> >> +             }
> >> +     }
> >> +
> >> +     /* write to fifo */
> >> +     if ((ep->xfer_len<  4)&&  (ep->xfer_len>  0)) {
> >> +             memcpy(&unaligned, data_buff, ep->xfer_len);
> >> +             *fifo = unaligned;
> >> +     } else {
> >> +             for (i = 0; i<  dword_count; i++, data_buff++)
> >> +                     *fifo = *data_buff;
> > 
> > DTTO, will this handle unaligned xfer of size>  4 properly ?
> 
> Again, this part needs to be made more generic. I'll amend it in V3.
> 
> >> +     }
> >> +
> >> +     writel(NPTXFEMPTY,&core_global_regs->gintsts);
> >> +
> 
> [...]
> 
> >> +/* This function returns pointer to out ep struct with number num */
> >> +static struct dwc_ep *get_out_ep(u32 num)
> >> +{
> >> +     u32 i;
> >> +     int num_out_eps = MAX_EPS_CHANNELS;
> >> +     struct dwc_pcd *pcd =&dev_if->pcd;
> >> +
> >> +     if (num == 0)
> >> +             return&pcd->ep0;
> >> +
> >> +     for (i = 0; i<  num_out_eps; ++i) {
> > 
> > i++ ... ++i has no meaning here (not even a compiler hint).
> 
> Ok, 'll amend
> 
> >> +             if (pcd->out_ep[i].num == num)
> >> +                     return&pcd->out_ep[i];
> >> +     }
> >> +
> >> +     return 0;
> >> +}
> >> +
> 
> [...]
> 
> >> + *           to the destination buffer
> >> + */
> > 
> > Otherwise, I think you did a pretty decent job, one more round and I'm
> > queueing this ;-)
> > 
> > .
> :
> :)
> 
> Sorry for my delayed response.

Don't worry about it :)

> 
> Best Regards
> Amit Virdi
Marek Vasut - Oct. 16, 2012, 6:24 a.m.
Dear Amit Virdi,

[...]

Did we get any further with this patch please?

Best regards,
Marek Vasut
Amit Virdi - Oct. 16, 2012, 6:33 a.m.
Dear Marek,

On 10/16/2012 11:54 AM, Marek Vasut wrote:
> Dear Amit Virdi,
>
> [...]
>
> Did we get any further with this patch please?
>

Vipin shall send V3 on this soon.

Regards
Amit Virdi
Marek Vasut - Oct. 16, 2012, 6:35 a.m.
Dear Amit Virdi,

> Dear Marek,
> 
> On 10/16/2012 11:54 AM, Marek Vasut wrote:
> > Dear Amit Virdi,
> > 
> > [...]
> > 
> > Did we get any further with this patch please?
> 
> Vipin shall send V3 on this soon.

Thanks!

Best regards,
Marek Vasut

Patch

diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index eb670da..bd3bcbc 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -35,6 +35,8 @@ 
 #include <usb/pxa27x_udc.h>
 #elif defined(CONFIG_DW_UDC)
 #include <usb/designware_udc.h>
+#elif defined(CONFIG_DW_OTG)
+#include <usb/designware_otg.h>
 #endif
 
 #include <version.h>
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 87d1918..ede367e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -40,6 +40,7 @@  ifdef CONFIG_USB_DEVICE
 COBJS-y += core.o
 COBJS-y += ep0.o
 COBJS-$(CONFIG_DW_UDC) += designware_udc.o
+COBJS-$(CONFIG_DW_OTG) += designware_otg.o
 COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o
 COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o
 COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
diff --git a/drivers/usb/gadget/designware_otg.c b/drivers/usb/gadget/designware_otg.c
new file mode 100644
index 0000000..5af6940
--- /dev/null
+++ b/drivers/usb/gadget/designware_otg.c
@@ -0,0 +1,990 @@ 
+/*
+ * Based on drivers/usb/gadget/designware_otg.c
+ * Synopsys DW OTG Device bus interface driver
+ *
+ * (C) Copyright 2011
+ * Pratyush Anand, ST Micoelectronics, pratyush.anand@st.com.
+ *
+ * (C) Copyright 2012
+ * Amit Virdi, ST Micoelectronics, amit.virdi@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usbdevice.h>
+#include <watchdog.h>
+#include "ep0.h"
+#include <usb/designware_otg.h>
+#include <asm/arch/hardware.h>
+
+#define UDC_INIT_MDELAY		80	/* Device settle delay */
+
+static struct urb *ep0_urb;
+static struct usb_device_instance *udc_device;
+
+static struct device_if	device_if_mem;
+static struct device_if	*dev_if = &device_if_mem;
+
+#if defined(CONFIG_USBD_HS)
+#define CONFIG_USBD_SERIAL_BULK_PKTSIZE	UDC_BULK_HS_PACKET_SIZE
+#endif
+
+void udc_set_nak(int epid)
+{
+	setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, SNAK);
+	setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, SNAK);
+}
+
+void udc_unset_nak(int epid)
+{
+	setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, CNAK);
+	setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, CNAK);
+}
+
+static void udc_set_stall(int epid, int dir)
+{
+	if (dir)
+		setbits_le32(&dev_if->in_ep_regs[epid]->diepctl, SSTALL);
+	else
+		setbits_le32(&dev_if->out_ep_regs[epid]->doepctl, SSTALL);
+}
+
+/*
+ * This function enables EP0 OUT to receive SETUP packets and configures EP0
+ * IN for transmitting packets. It is normally called when the "Enumeration
+ * Done" interrupt occurs.
+ */
+static void dwc_otg_ep0_activate(void)
+{
+	struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[0];
+	struct device_out_ep_regs *out_ep_regs = dev_if->out_ep_regs[0];
+
+	/* Read the Device Status and Endpoint 0 Control registers */
+	clrsetbits_le32(&in_ep_regs->diepctl, MPSMSK0, DWC_DEP0CTL_MPS_64);
+
+	/* Enable OUT EP for receive */
+	setbits_le32(&out_ep_regs->doepctl, EPENA);
+}
+
+static struct usb_endpoint_instance *dw_find_ep(int ep)
+{
+	int i;
+
+	for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+		if ((udc_device->bus->endpoint_array[i].endpoint_address &
+					USB_ENDPOINT_NUMBER_MASK) == ep)
+			return &udc_device->bus->endpoint_array[i];
+	}
+	return NULL;
+}
+
+/*
+ * This function reads a packet from the Rx FIFO into the destination buffer.
+ * To read SETUP data use dwc_otg_read_setup_packet.
+ */
+static void dwc_otg_read_packet(struct dwc_ep *ep, u16 bytes)
+{
+	u32 i;
+	int word_count = (bytes + 3) / 4;
+	u32 *fifo = dev_if->data_fifo[0];
+	u32 *data_buff = (u32 *) ep->xfer_buff;
+	u32 unaligned;
+	/*
+	 * This requires reading data from the FIFO into a u32 temp buffer,
+	 * then moving it into the data buffer.
+	 */
+	if ((bytes < 4) && (bytes > 0)) {
+		unaligned = readl(fifo);
+		memcpy(data_buff, &unaligned, bytes);
+	} else {
+		for (i = 0; i < word_count; i++, data_buff++)
+			*data_buff = readl(fifo);
+	}
+}
+
+/* Handle RX transaction on non-ISO endpoint. */
+static void dw_udc_epn_rx(struct dwc_ep *ep, int bcnt)
+{
+	struct urb *urb;
+	struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
+
+	if (endpoint) {
+		urb = endpoint->rcv_urb;
+
+		if (urb) {
+			ep->xfer_buff = urb->buffer + urb->actual_length;
+			dwc_otg_read_packet(ep, bcnt);
+			usbd_rcv_complete(endpoint, bcnt, 0);
+		}
+	}
+}
+
+/*
+ * This function writes a packet into the Tx FIFO associated with the EP.
+ * The buffer is padded to DWORD on a per packet basis in
+ * slave/dma mode if the MPS is not DWORD aligned. The last packet, if
+ * short, is also padded to a multiple of DWORD.
+ *
+ * ep->xfer_buff always starts DWORD aligned in memory and is a
+ * multiple of DWORD in length
+ *
+ * ep->xfer_len can be any number of bytes
+ *
+ * FIFO access is DWORD
+ */
+static void dwc_otg_ep_write_packet(struct dwc_ep *ep)
+{
+	u32 i;
+	u32 dword_count;
+	u32 *fifo;
+	u32 *data_buff = (u32 *) ep->xfer_buff;
+	u32 temp, unaligned;
+	u32 timeout = 1; /* 1ms as the timeout */
+	ulong start;
+	struct device_in_ep_regs *in_ep_regs = dev_if->in_ep_regs[ep->num];
+	struct core_global_regs *core_global_regs = dev_if->core_global_regs;
+
+	/*
+	 * Find the DWORD length, padded by extra bytes as neccessary if MPS
+	 * is not a multiple of DWORD
+	 */
+	dword_count = (ep->xfer_len + 3) / 4;
+	fifo = dev_if->data_fifo[ep->num];
+
+	/* program pkt count */
+	temp = ep->xfer_len;
+	temp |= (1 << PKTCNT_SHIFT);
+	writel(temp, &in_ep_regs->dieptsiz);
+
+	/* enable EP*/
+	setbits_le32(&in_ep_regs->diepctl, EPENA | CNAK);
+
+	/* clear TX Fifo Empty intr*/
+	writel(NPTXFEMPTY, &core_global_regs->gintsts);
+
+	setbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
+
+	start = get_timer(0);
+	while (!(readl(&core_global_regs->gintsts) & NPTXFEMPTY)) {
+		if (get_timer(start) > timeout) {
+			printf("%s: NPTXFEMPTY: TimeOUT\n", __func__);
+			WATCHDOG_RESET();
+		}
+	}
+
+	/* write to fifo */
+	if ((ep->xfer_len < 4) && (ep->xfer_len > 0)) {
+		memcpy(&unaligned, data_buff, ep->xfer_len);
+		*fifo = unaligned;
+	} else {
+		for (i = 0; i < dword_count; i++, data_buff++)
+			*fifo = *data_buff;
+	}
+
+	writel(NPTXFEMPTY, &core_global_regs->gintsts);
+
+	/* check for transfer completion*/
+	start = get_timer(0);
+	while (!(readl(&in_ep_regs->diepint) & XFERCOMPL)) {
+		if (get_timer(start) > timeout) {
+			printf("%s: XFERCOMPLE: TimeOUT\n", __func__);
+			WATCHDOG_RESET();
+		}
+	}
+
+	writel(XFERCOMPL, &in_ep_regs->diepint);
+	clrbits_le32(&core_global_regs->gintmsk, NPTXFEMPTY);
+}
+
+/* Handle TX transaction on non-ISO endpoint. */
+static void dw_udc_epn_tx(struct dwc_ep *ep)
+{
+	struct usb_endpoint_instance *endpoint = dw_find_ep(ep->num);
+	struct urb *urb = endpoint->tx_urb;
+	int align;
+
+	if (!endpoint)
+		return;
+
+	/*
+	 * We need to transmit a terminating zero-length packet now if
+	 * we have sent all of the data in this URB and the transfer
+	 * size was an exact multiple of the packet size.
+	 */
+	if (urb && (endpoint->last == endpoint->tx_packetSize) &&
+			(urb->actual_length - endpoint->sent -
+			 endpoint->last == 0)) {
+		/* handle zero length packet here */
+		ep->xfer_len = 0;
+		dwc_otg_ep_write_packet(ep);
+	}
+
+	if (urb && urb->actual_length) {
+		/* retire the data that was just sent */
+		usbd_tx_complete(endpoint);
+		/*
+		 * Check to see if we have more data ready to transmit
+		 * now.
+		 */
+		if (urb && urb->actual_length) {
+			/* write data to FIFO */
+			ep->xfer_len = MIN(urb->actual_length - endpoint->sent,
+					endpoint->tx_packetSize);
+
+			if (ep->xfer_len) {
+				ep->xfer_buff = urb->buffer + endpoint->sent;
+
+				/*
+				 * This ensures that USBD packet fifo is
+				 * accessed through word aligned pointer or
+				 * through non word aligned pointer but only
+				 * with a max length to make the next packet
+				 * word aligned
+				 */
+
+				align = ((ulong)ep->xfer_buff % sizeof(int));
+				if (align)
+					ep->xfer_len = MIN(ep->xfer_len,
+							sizeof(int)-align);
+
+				dwc_otg_ep_write_packet(ep);
+			}
+			endpoint->last = ep->xfer_len;
+
+		}
+	}
+}
+
+/* This function returns pointer to out ep struct with number num */
+static struct dwc_ep *get_out_ep(u32 num)
+{
+	u32 i;
+	int num_out_eps = MAX_EPS_CHANNELS;
+	struct dwc_pcd *pcd = &dev_if->pcd;
+
+	if (num == 0)
+		return &pcd->ep0;
+
+	for (i = 0; i < num_out_eps; ++i) {
+		if (pcd->out_ep[i].num == num)
+			return &pcd->out_ep[i];
+	}
+
+	return 0;
+}
+
+/* This function returns pointer to in ep struct with number num */
+static struct dwc_ep *get_in_ep(u32 num)
+{
+	u32 i;
+	int num_out_eps = MAX_EPS_CHANNELS;
+	struct dwc_pcd *pcd = &dev_if->pcd;
+
+	if (num == 0)
+		return &pcd->ep0;
+
+	for (i = 0; i < num_out_eps; ++i) {
+		if (pcd->in_ep[i].num == num)
+			return &pcd->in_ep[i];
+	}
+
+	return 0;
+}
+
+/*
+ * This function reads the 8 bytes of the setup packet from the Rx FIFO into the
+ * destination buffer. It is called from the Rx Status Queue Level (RxStsQLvl)
+ * interrupt routine when a SETUP packet has been received in Slave mode.
+ */
+static void dwc_otg_read_setup_packet(u32 *dest)
+{
+	dest[0] = readl(dev_if->data_fifo[0]);
+	dest[1] = readl(dev_if->data_fifo[0]);
+}
+
+/*
+ * This function handles the Rx Status Queue Level Interrupt, which
+ * indicates that there is a least one packet in the Rx FIFO. The
+ * packets are moved from the FIFO to memory, where they will be
+ * processed when the Endpoint Interrupt Register indicates Transfer
+ * Complete or SETUP Phase Done.
+ *
+ * Repeat the following until the Rx Status Queue is empty:
+ *	 -# Read the Receive Status Pop Register (GRXSTSP) to get Packet
+ *		info
+ *	 -# If Receive FIFO is empty then skip to step Clear the interrupt
+ *		and exit
+ *	 -# If SETUP Packet call dwc_otg_read_setup_packet to copy the
+ *		SETUP data to the buffer
+ *	 -# If OUT Data Packet call dwc_otg_read_packet to copy the data
+ *		to the destination buffer
+ */
+static int dwc_otg_pcd_handle_rx_status_q_level_intr(void)
+{
+	struct core_global_regs *global_regs = dev_if->core_global_regs;
+	struct dwc_pcd *pcd = &dev_if->pcd;
+	u32	status;
+	struct dwc_ep *ep;
+	u32	bcnt;
+
+	/* Disable the Rx Status Queue Level interrupt */
+	clrbits_le32(&global_regs->gintmsk, RXSTSQLVL);
+
+	/* Get the Status from the top of the FIFO */
+	status = readl(&global_regs->grxstsp);
+	/* Get pointer to EP structure */
+	ep = get_out_ep((status & EPNUMMSK) >> EPNUM_SHIFT);
+	bcnt = (status & BCNTMSK) >> BCNT_SHIFT;
+
+	switch ((status & PKTSTSMSK) >> PKTSTS_SHIFT) {
+	case DWC_DSTS_GOUT_NAK:
+		break;
+	case DWC_STS_DATA_UPDT:
+		if (bcnt)
+			dw_udc_epn_rx(ep, bcnt);
+		break;
+	case DWC_STS_XFER_COMP:
+		break;
+	case DWC_DSTS_SETUP_COMP:
+		break;
+	case DWC_DSTS_SETUP_UPDT:
+		dwc_otg_read_setup_packet((u32 *)pcd->req);
+		break;
+	default:
+		break;
+	}
+
+	/* Enable the Rx Status Queue Level interrupt */
+	setbits_le32(&global_regs->gintmsk, RXSTSQLVL);
+
+	/* Clear interrupt */
+	setbits_le32(&global_regs->gintsts, RXSTSQLVL);
+
+	return 1;
+}
+
+/*
+ * This function starts the Zero-Length Packet for the IN status phase
+ * of a 2 stage control transfer.
+ */
+static void do_setup_in_status_phase(struct device_if *dev_if)
+{
+	struct device_out_ep_regs *out_regs =
+		dev_if->out_ep_regs[0];
+
+	setbits_le32(&out_regs->doeptsiz, PKTCNT_SHIFT);
+
+	setbits_le32(&out_regs->doepctl, CNAK | EPENA);
+}
+
+/*
+ * This function handles EP0 Control transfers.
+ *
+ * The state of the control tranfers are tracked in ep0state
+ *
+ * A flag set indicates that it is not the first packet, so do not
+ * process setup data now. it has alreday been processed, just send the
+ * next data packet
+ */
+static void handle_ep0(int in_flag)
+{
+	struct dwc_pcd *pcd = &dev_if->pcd;
+	struct dwc_ep *ep0 = &pcd->ep0;
+	struct usb_device_request *ctrl = pcd->req;
+
+	/* handle inepint, only when more than 64 bytes to transfer*/
+	if (in_flag & !ep0_urb->actual_length)
+		return;
+
+	if (!ep0_urb->actual_length) {
+		if (ep0_recv_setup(ep0_urb)) {
+			udc_set_stall(0, ctrl->bmRequestType & USB_DIR_IN);
+			return;
+		}
+		ep0->xfer_buff = (u8 *)ep0_urb->buffer;
+	} else
+		ep0->xfer_buff += EP0_MAX_PACKET_SIZE;
+
+	if (ep0_urb->actual_length <= EP0_MAX_PACKET_SIZE) {
+		ep0->xfer_len = ep0_urb->actual_length;
+		ep0_urb->actual_length = 0;
+	} else {
+		ep0->xfer_len = EP0_MAX_PACKET_SIZE;
+		ep0_urb->actual_length -= EP0_MAX_PACKET_SIZE;
+	}
+
+	if (ctrl->bmRequestType & USB_DIR_IN) {
+		dwc_otg_ep_write_packet(ep0);
+		if (!ep0_urb->actual_length)
+			do_setup_in_status_phase(dev_if);
+	} else {
+		if (!ctrl->wLength)
+			dwc_otg_ep_write_packet(ep0);
+		else
+			udc_set_stall(0, ctrl->bmRequestType & USB_DIR_OUT);
+	}
+}
+
+/*
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the OUT endpoint interrupt bits.
+ */
+static u32 dwc_otg_read_dev_all_out_ep_intr(void)
+{
+	u32 v;
+
+	v = readl(&dev_if->dev_global_regs->daint) &
+		readl(&dev_if->dev_global_regs->daintmsk);
+	return v >> 16;
+}
+
+/*
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the IN endpoint interrupt bits.
+ */
+static u32 dwc_otg_read_dev_all_in_ep_intr(void)
+{
+	u32 v;
+
+	v = readl(&dev_if->dev_global_regs->daint) &
+		readl(&dev_if->dev_global_regs->daintmsk);
+	return v & 0xffff;
+}
+
+/* This function returns the Device OUT EP Interrupt register */
+static u32 dwc_otg_read_doep_intr(struct dwc_ep *ep)
+{
+	u32 v;
+
+	v = readl(&dev_if->out_ep_regs[ep->num]->doepint) &
+		readl(&dev_if->dev_global_regs->doepmsk);
+	return v;
+}
+
+/*This function returns the Device IN EP Interrupt register */
+static u32 dwc_otg_read_diep_intr(struct dwc_ep *ep)
+{
+	u32 v;
+
+	v = readl(&dev_if->in_ep_regs[ep->num]->diepint) &
+		readl(&dev_if->dev_global_regs->diepmsk);
+	return v;
+}
+
+/*
+ * This function configures EPO to receive SETUP packets.
+ *
+ * Program the following fields in the endpoint specific registers for Control
+ * OUT EP 0, in order to receive a setup packet:
+ *
+ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back setup packets)
+ *
+ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back to back setup
+ * packets)
+ *
+ * In DMA mode, DOEPDMA0 Register with a memory address to store any setup
+ * packets received
+ */
+static void ep0_out_start(void)
+{
+	u32 temp;
+
+	/* program transfer size*/
+	temp = 8 * 3;
+	/* program packet count*/
+	temp |= PKTCNT;
+	/* program setup packet count */
+	temp |= (3 << SUPCNT_SHIFT);
+	writel(temp, &dev_if->out_ep_regs[0]->doeptsiz);
+}
+
+/* should be called after set address is received */
+void udc_set_address_controller(u32 address)
+{
+	u32 dcfg;
+
+	dcfg = readl(&dev_if->dev_global_regs->dcfg);
+	dcfg &= ~DEVADDRMSK;
+	dcfg |= address << DEVADDR_SHIFT;
+	writel(dcfg, &dev_if->dev_global_regs->dcfg);
+
+	usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+}
+
+/* should be called after set configuration is received */
+static void dwc_otg_bulk_out_activate(void)
+{
+	struct device_out_ep_regs *out_regs =
+		dev_if->out_ep_regs[UDC_OUT_ENDPOINT];
+	struct device_global_regs *dev_global_regs
+		= dev_if->dev_global_regs;
+
+	setbits_le32(&dev_global_regs->daintmsk,
+			(UDC_OUT_ENDPOINT + DAINTMASK_OUT_SHIFT));
+
+	setbits_le32(&out_regs->doeptsiz,
+			CONFIG_USBD_SERIAL_BULK_PKTSIZE | PKTCNT_SHIFT);
+
+	clrsetbits_le32(&out_regs->doepctl, DOEPCTL_MPSMSK | EPTYPEMSK,
+			CONFIG_USBD_SERIAL_BULK_PKTSIZE | CNAK | EPENA |
+			USBACTEP | DATA0PID | (EPTYPE_BULK << EPTYPE_SHIFT));
+}
+
+/* should be called after set configuration is received */
+static void dwc_otg_bulk_in_activate(void)
+{
+	struct device_in_ep_regs *in_regs =
+		dev_if->in_ep_regs[UDC_IN_ENDPOINT];
+	struct device_global_regs *dev_global_regs
+		= dev_if->dev_global_regs;
+
+	setbits_le32(&dev_global_regs->daintmsk,
+			(UDC_IN_ENDPOINT + DAINTMASK_IN_SHIFT));
+
+	clrsetbits_le32(&in_regs->diepctl,
+			DIEPCTL_MPSMSK | EPTYPEMSK,
+			CONFIG_USBD_SERIAL_BULK_PKTSIZE | USBACTEP | DATA0PID |
+			(EPTYPE_BULK << EPTYPE_SHIFT));
+}
+
+static void dwc_otg_int_in_activate(void)
+{
+	struct device_in_ep_regs *in_regs =
+		dev_if->in_ep_regs[UDC_INT_ENDPOINT];
+	struct device_global_regs *dev_global_regs
+		= dev_if->dev_global_regs;
+
+	setbits_le32(&dev_global_regs->daintmsk,
+			(UDC_INT_ENDPOINT + DAINTMASK_IN_SHIFT));
+
+	clrsetbits_le32(&in_regs->diepctl,
+			DIEPCTL_MPSMSK | EPTYPEMSK,
+			UDC_INT_PACKET_SIZE | USBACTEP | DATA0PID |
+			(EPTYPE_INT << EPTYPE_SHIFT));
+}
+
+/* should be called after set configuration is received */
+void udc_set_configuration_controller(u32 config)
+{
+	dwc_otg_bulk_out_activate();
+	dwc_otg_bulk_in_activate();
+	dwc_otg_int_in_activate();
+	usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+}
+
+/* should be called to receive next packet */
+static void dwc_otg_bulk_out_enable(void)
+{
+	struct device_out_ep_regs *out_regs =
+		dev_if->out_ep_regs[UDC_OUT_ENDPOINT];
+
+	setbits_le32(&out_regs->doeptsiz, PKTCNT_SHIFT |
+			CONFIG_USBD_SERIAL_BULK_PKTSIZE);
+	setbits_le32(&out_regs->doepctl, CNAK | EPENA);
+}
+
+/* This interrupt indicates that an OUT EP has a pending Interrupt. */
+
+static int dwc_otg_pcd_handle_out_ep_intr(void)
+{
+	u32 ep_intr;
+	u32 doepint;
+	u32 epnum = 0;
+	struct dwc_ep *ep;
+	struct device_out_ep_regs **out_ep_regs
+		= dev_if->out_ep_regs;
+
+	/* Read in the device interrupt bits */
+	ep_intr = dwc_otg_read_dev_all_out_ep_intr();
+	while (ep_intr) {
+		if (ep_intr & 0x1) {
+			ep = get_out_ep(epnum);
+			doepint = dwc_otg_read_doep_intr(ep);
+
+			/* Transfer complete */
+			if (doepint & XFERCOMPL) {
+				/* Clear xfercompl */
+				writel(XFERCOMPL, &out_ep_regs[epnum]->doepint);
+				if (!epnum)
+					ep0_out_start();
+				else if (epnum == UDC_OUT_ENDPOINT)
+					dwc_otg_bulk_out_enable();
+			}
+			/* Setup Phase Done (control EPs) */
+			if (doepint & SETUP) {
+				writel(SETUP, &out_ep_regs[epnum]->doepint);
+				handle_ep0(0);
+			}
+		}
+		epnum++;
+		ep_intr >>= 1;
+	}
+	return 1;
+}
+
+/* This interrupt indicates that an IN EP has a pending Interrupt. */
+
+static int dwc_otg_pcd_handle_in_ep_intr(void)
+{
+	u32 ep_intr;
+	u32 diepint;
+	u32 epnum = 0;
+	struct dwc_ep *ep;
+	struct device_in_ep_regs **in_ep_regs
+		= dev_if->in_ep_regs;
+
+	/* Read in the device interrupt bits */
+	ep_intr = dwc_otg_read_dev_all_in_ep_intr();
+	while (ep_intr) {
+		if (!(ep_intr & 0x1))
+			continue;
+		ep = get_in_ep(epnum);
+		diepint = dwc_otg_read_diep_intr(ep);
+
+		/* IN token received when txfifo empty */
+		if (diepint & INTKNTXFEMP) {
+			/* Clear xfercompl */
+			writel(INTKNTXFEMP,
+					&in_ep_regs[epnum]->diepint);
+			if (!epnum)
+				handle_ep0(1);
+			else if (epnum == UDC_IN_ENDPOINT)
+				dw_udc_epn_tx(ep);
+		}
+		epnum++;
+		ep_intr >>= 1;
+	}
+	return 1;
+}
+
+static void dwc_otg_flush_tx_fifo(const int num)
+{
+	struct core_global_regs *global_regs = dev_if->core_global_regs;
+	u32 val = 0;
+	u32 timeout = 10; /* 10ms timeout */
+	ulong start = 0;
+
+	clrsetbits_le32(&global_regs->grstctl, TXFNUM,
+			TXFFLSH | (num << TXFNUM_SHIFT));
+
+	start = get_timer(0);
+	while (val & TXFFLSH) {
+		if (get_timer(start) > timeout)
+			WATCHDOG_RESET();
+
+		val = readl(&global_regs->grstctl);
+	}
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+static void dwc_otg_flush_rx_fifo(void)
+{
+	struct core_global_regs *global_regs = dev_if->core_global_regs;
+	int timeout = 10; /* 10 ms timeout */
+	u32 val = 0;
+	ulong start;
+
+	setbits_le32(&global_regs->grstctl, RXFFLSH);
+
+	start = get_timer(0);
+	while (val & RXFFLSH) {
+		if (get_timer(start) > timeout)
+			WATCHDOG_RESET();
+
+		val = readl(&global_regs->grstctl);
+	}
+
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/*
+ * This interrupt occurs when a USB Reset is detected. When the USB Reset
+ * Interrupt occurs the device state is set to DEFAULT and the EP0 state is set
+ * to IDLE.
+ *
+ */
+static int dwc_otg_pcd_handle_usb_reset_intr(void)
+{
+	u32 temp;
+	u32 i;
+	struct device_out_ep_regs **out_ep_regs
+		= dev_if->out_ep_regs;
+	struct device_global_regs *dev_global_regs
+		= dev_if->dev_global_regs;
+	struct core_global_regs *core_global_regs
+		= dev_if->core_global_regs;
+	/* Set NAK for all OUT EPs */
+	for (i = 0; i < MAX_EPS_CHANNELS; i++)
+		setbits_le32(&out_ep_regs[i]->doepctl, SNAK);
+
+	/* Flush the NP Tx FIFO */
+	dwc_otg_flush_tx_fifo(DWC_GRSTCTL_TXFNUM_ALL);
+	dwc_otg_flush_rx_fifo();
+	setbits_le32(&dev_global_regs->daintmsk, DAINTMASK_IN_SHIFT |
+			DAINTMASK_OUT_SHIFT);
+
+	setbits_le32(&dev_global_regs->doepmsk, SETUPMSK | XFERCOMPLMSK |
+			AHBERRMSK | EPDISABLEDMSK);
+
+	writel(INTKNTXFEMP, &dev_global_regs->diepmsk);
+
+	setbits_le32(&core_global_regs->gintmsk, GOUTNAKEFF);
+
+	/* program fifo size for ep0 */
+	writel(DWC_OTG_RX_FIFO_SIZE, &core_global_regs->grxfsiz);
+
+	temp = readl(&dev_if->in_ep_regs[0]->diepctl);
+	temp &= 0xFFC3FFFF; /* TxFNumBF = 0, bits 25:22 */
+	writel(temp, &dev_if->in_ep_regs[0]->diepctl);
+
+	temp = readl(&core_global_regs->gnptxfsiz);
+
+	writel((DWC_OTG_RX_FIFO_SIZE | DWC_OTG_NPTX_FIFO_SIZE << 16),
+			&core_global_regs->gnptxfsiz);
+
+	/* Reset Device Address */
+	clrbits_le32(&dev_global_regs->dcfg, DEVADDRMSK);
+
+	/* setup EP0 to receive SETUP packets */
+	ep0_out_start();
+
+	/* Clear interrupt */
+	writel(USBRESET, &core_global_regs->gintsts);
+
+	usbd_device_event_irq(udc_device, DEVICE_HUB_CONFIGURED, 0);
+
+	return 1;
+}
+
+/*
+ * Read the device status register and set the device speed in the
+ * data structure.
+ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate.
+ */
+static int dwc_otg_pcd_handle_enum_done_intr(void)
+{
+	struct core_global_regs *global_regs = dev_if->core_global_regs;
+
+	dwc_otg_ep0_activate();
+
+	clrsetbits_le32(&global_regs->gusbcfg, USBTRDTIMMSK, PHYIF_16BIT |
+			(USBTRDTIM_MAC_IF_8BIT_UTMI << USBTRDTIM_SHIFT));
+
+	/* Clear interrupt */
+	writel(ENUMDONE, &global_regs->gintsts);
+	usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+
+	return 1;
+}
+
+static u32 dwc_otg_read_core_intr(void)
+{
+	return readl(&dev_if->core_global_regs->gintsts) &
+		readl(&dev_if->core_global_regs->gintmsk);
+}
+
+static void dwc_otg_init(const void *reg_base)
+{
+	struct dwc_pcd *pcd = &dev_if->pcd;
+	u32 offset;
+	u32 i;
+
+	dev_if->core_global_regs = (struct core_global_regs *) reg_base;
+	dev_if->dev_global_regs = (struct device_global_regs *) ((u32)reg_base +
+			DWC_DEV_GLOBAL_REG_OFFSET);
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		offset = i * DWC_EP_REG_OFFSET;
+
+		dev_if->in_ep_regs[i] = (struct device_in_ep_regs *)
+			((u32)reg_base + DWC_DEV_IN_EP_REG_OFFSET + offset);
+
+		dev_if->out_ep_regs[i] = (struct device_out_ep_regs *)
+			((u32)reg_base + DWC_DEV_OUT_EP_REG_OFFSET + offset);
+	}
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		dev_if->data_fifo[i] =
+			(u32 *) ((u32)reg_base + DWC_OTG_DATA_FIFO_OFFSET +
+					(i * DWC_OTG_DATA_FIFO_SIZE));
+	}
+
+	dev_if->speed = 0;	/* unknown */
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		pcd->in_ep[i].num = i;
+		pcd->out_ep[i].num = i;
+	}
+}
+
+/*
+ * This function initializes the DWC_otg controller registers and prepares the
+ * core for device mode
+ */
+static void dwc_otg_core_init(void)
+{
+	struct core_global_regs *global_regs = dev_if->core_global_regs;
+
+	/* Step 1: Program the GAHBCFG Register. */
+	setbits_le32(&global_regs->gahbcfg, DWC_NPTXEMPTYLVL_EMPTY |
+			DWC_PTXEMPTYLVL_EMPTY);
+
+	/* Step 2: write usbcfg regs*/
+	setbits_le32 (&global_regs->gusbcfg, SRPCAP | HNPCAP);
+
+	/* step3: write int_msk reg*/
+	setbits_le32(&global_regs->gintmsk, USBRESET | ENUMDONE | RXSTSQLVL |
+			OUTEPINTR | INEPINTR);
+}
+
+/* Switch on the UDC */
+static void usbotg_init(void)
+{
+	udc_device = NULL;
+	dwc_otg_init((void *)CONFIG_SYS_USBD_BASE);
+
+	/* Initialize the DWC_otg core.	*/
+	dwc_otg_core_init();
+
+}
+
+void udc_irq(void)
+{
+	u32 status;
+
+	status = dwc_otg_read_core_intr();
+	while (status) {
+		if (status & USBRESET)
+			dwc_otg_pcd_handle_usb_reset_intr();
+		if (status & ENUMDONE)
+			dwc_otg_pcd_handle_enum_done_intr();
+		if (status & RXSTSQLVL)
+			dwc_otg_pcd_handle_rx_status_q_level_intr();
+		if (status & OUTEPINTR)
+			dwc_otg_pcd_handle_out_ep_intr();
+		if (status & INEPINTR)
+			dwc_otg_pcd_handle_in_ep_intr();
+		status = dwc_otg_read_core_intr();
+	}
+
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+	udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK);
+	return 0;
+}
+
+static void udc_enable(struct usb_device_instance *device)
+{
+	struct dwc_pcd *pcd = &dev_if->pcd;
+
+	/* Save the device structure pointer */
+	udc_device = device;
+
+	/* Setup ep0 urb */
+	if (!ep0_urb) {
+		ep0_urb =
+			usbd_alloc_urb(udc_device,
+					udc_device->bus->endpoint_array);
+		pcd->req =
+			(struct usb_device_request *)&ep0_urb->device_request;
+		pcd->ep0.xfer_buff = (u8 *)ep0_urb->buffer;
+	} else {
+		printf("udc_enable: ep0_urb already allocated %p\n",
+				ep0_urb);
+	}
+}
+
+void udc_connect(void)
+{
+	struct device_global_regs *dev_regs = dev_if->dev_global_regs;
+
+	/* remove soft disconnect */
+	clrbits_le32(&dev_regs->dctl, SFTDISCON);
+}
+
+void udc_disconnect(void)
+{
+	struct device_global_regs *dev_regs = dev_if->dev_global_regs;
+
+	/* soft disconnect */
+	setbits_le32(&dev_regs->dctl, SFTDISCON);
+
+	udelay(150);
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+	usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+	/*
+	 * The DEVICE_CREATE event puts the USB device in the state
+	 * STATE_ATTACHED.
+	 */
+	usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+	/*
+	 * Some USB controller driver implementations signal
+	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+	 * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
+	 * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
+	 * The DW USB client controller has the capability to detect when the
+	 * USB cable is connected to a powered USB bus, so we will defer the
+	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later.
+	 */
+
+	udc_enable(device);
+
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+		struct usb_endpoint_instance *endpoint)
+{
+	/*
+	 * Nothing to do here. Hob of this function has laready been
+	 * done during init.
+	 */
+}
+
+int is_usbd_high_speed(void)
+{
+	struct device_global_regs *dev_regs = dev_if->dev_global_regs;
+	u32 dsts;
+
+	dsts = readl(&dev_regs->dsts);
+	dsts &= ENUMSPDMSK;
+	if (dsts == DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ)
+		return 1;
+	else
+		return 0;
+}
+
+int udc_init(void)
+{
+	phy_init();
+	udc_disconnect();
+	usbotg_init();
+	return 0;
+}
diff --git a/include/usb/designware_otg.h b/include/usb/designware_otg.h
new file mode 100644
index 0000000..053a324
--- /dev/null
+++ b/include/usb/designware_otg.h
@@ -0,0 +1,523 @@ 
+/*
+ * (C) Copyright 2011
+ * Pratyush Anand, ST Micoelectronics, pratyush.anand@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __DW_OTG_H
+#define __DW_OTG_H
+
+#include "usbdevice.h"
+/* USBTTY definitions */
+#define  EP0_MAX_PACKET_SIZE		64
+#define  UDC_INT_ENDPOINT		1
+#define  UDC_INT_PACKET_SIZE		64
+#define  UDC_OUT_ENDPOINT		2
+#define  UDC_BULK_PACKET_SIZE		512
+#if defined(CONFIG_USBD_HS)
+#define  UDC_BULK_HS_PACKET_SIZE	512
+#endif
+#define  UDC_IN_ENDPOINT		3
+#define  UDC_OUT_PACKET_SIZE		64
+#define  UDC_IN_PACKET_SIZE		64
+
+/* UDC endpoint definitions */
+#define  UDC_EP0			0
+#define  UDC_EP1			1
+#define  UDC_EP2			2
+#define  UDC_EP3			3
+
+#define CMD_SIZE	12
+/* OTG Register Definitions */
+
+/*
+ * The application interfaces with the HS OTG core by reading from and
+ * writing to the Control and Status Register (CSR) space through the
+ * AHB Slave interface. These registers are 32 bits wide, and the
+ * addresses are 32-bit-block aligned.
+ * CSRs are classified as follows:
+ * - Core Global Registers
+ * - Device Mode Registers
+ * - Device Global Registers
+ * - Device Endpoint Specific Registers
+ * - Host Mode Registers
+ * - Host Global Registers
+ * - Host Port CSRs
+ * - Host Channel Specific Registers
+ *
+ * Only the Core Global registers can be accessed in both Device and
+ * Host modes. When the HS OTG core is operating in one mode, either
+ * Device or Host, the application must not access registers from the
+ * other mode. When the core switches from one mode to another, the
+ * registers in the new mode of operation must be reprogrammed as they
+ * would be after a power-on reset.
+ */
+
+/*
+ * DWC_otg Core registers. The core_global_regs structure defines the
+ * size and relative field offsets for the Core Global registers.
+ */
+struct core_global_regs {
+	/* OTG Control and Status Register.		Offset: 000h */
+	u32 gotgctl;
+	/* OTG Interrupt Register.			Offset: 004h */
+	u32 gotgint;
+	/* Core AHB Configuration Register.		Offset: 008h */
+	u32 gahbcfg;
+
+#define DWC_GLBINTRMASK				0x0001
+#define DWC_DMAENABLE				0x0020
+#define DWC_NPTXEMPTYLVL_EMPTY			0x0080
+#define DWC_NPTXEMPTYLVL_HALFEMPTY		0x0000
+#define DWC_PTXEMPTYLVL_EMPTY			0x0100
+#define DWC_PTXEMPTYLVL_HALFEMPTY		0x0000
+
+	/* Core USB Configuration Register.		Offset: 00Ch */
+	u32 gusbcfg;
+#define PHYIF_16BIT				(1 << 3)
+#define SRPCAP					(1 << 8)
+#define HNPCAP					(1 << 9)
+#define TERM_SEL_DL_PULSE			(1 << 22)
+#define USBTRDTIM_SHIFT				10
+#define USBTRDTIMMSK				(0xF << USBTRDTIM_SHIFT)
+#define USBTRDTIM_MAC_IF_8BIT_UTMI		0x9
+#define USBTRDTIM_MAC_IF_16BIT_UTMI		0x5
+	/* Core Reset Register.				Offset: 010h */
+	u32 grstctl;
+#define DWC_GRSTCTL_TXFNUM_ALL			0x10
+#define CSFTRST					(1 << 0)
+#define INTKNQFLSH				(1 << 3)
+#define RXFFLSH					(1 << 4)
+#define	TXFFLSH					(1 << 5)
+#define TXFNUM_SHIFT				6
+#define TXFNUM					(0x1F << TXFNUM_SHIFT)
+#define AHBIDLE					((u32)1 << 31)
+	/* Core Interrupt Register.			Offset: 014h */
+	u32 gintsts;
+#define RXSTSQLVL				(1 << 4)
+#define NPTXFEMPTY				(1 << 5)
+#define GOUTNAKEFF				(1 << 7)
+#define USBRESET				(1 << 12)
+#define ENUMDONE				(1 << 13)
+#define INEPINTR				(1 << 18)
+#define OUTEPINTR				(1 << 19)
+	/* Core Interrupt Mask Register.		Offset: 018h */
+	u32 gintmsk;
+	/*
+	 * Receive Status Queue Read Register
+	 * (Read Only)					Offset: 01Ch
+	 */
+	u32 grxstsr;
+	/*
+	 * Receive Status Queue Read & POP Register
+	 * (Read Only)					Offset: 020h
+	 */
+	u32 grxstsp;
+#define DWC_STS_DATA_UPDT		0x2 /* OUT Data Packet */
+#define DWC_STS_XFER_COMP		0x3 /* OUT Data Transfer Complete */
+#define DWC_DSTS_GOUT_NAK		0x1 /* Global OUT NAK */
+#define DWC_DSTS_SETUP_COMP		0x4 /* Setup Phase Complete */
+#define DWC_DSTS_SETUP_UPDT		0x6 /* SETUP Packet */
+#define EPNUM_SHIFT					0
+#define EPNUMMSK					(0xF << EPNUM_SHIFT)
+#define BCNT_SHIFT					4
+#define BCNTMSK						(0x7FF << BCNT_SHIFT)
+#define PKTSTS_SHIFT					17
+#define PKTSTSMSK					(0xF << PKTSTS_SHIFT)
+	/* Receive FIFO Size Register.			Offset: 024h */
+	u32 grxfsiz;
+#define dwc_param_dev_rx_fifo_size_default		1064
+	/* Non Periodic Transmit FIFO Size Register.	Offset: 028h */
+	u32 gnptxfsiz;
+#define dwc_param_dev_nperio_tx_fifo_size_default	1024
+#define DWC_OTG_RX_FIFO_SIZE		0x200
+#define DWC_OTG_NPTX_FIFO_SIZE		0x200
+	/*
+	 * Non Periodic Transmit FIFO/Queue Status Register
+	 * (Read Only).					Offset: 02Ch
+	 */
+	u32 gnptxsts;
+#define NPTXQSPCAVAIL_SHIFT			16
+#define NPTXQSPCAVAILMSK			(0xFF << NPTXQSPCAVAIL_SHIFT)
+#define NPTXFSPCAVAIL_SHIFT			0
+#define NPTXFSPCAVAILMSK			(0xFFFF << NPTXFSPCAVAIL_SHIFT)
+	/* I2C Access Register.				Offset: 030h */
+	u32 gi2cctl;
+	/* PHY Vendor Control Register.			Offset: 034h */
+	u32 gpvndctl;
+	/* General Purpose Input/Output Register.	Offset: 038h */
+	u32 ggpio;
+	/* User ID Register.				Offset: 03Ch */
+	u32 guid;
+	/* Synopsys ID Register (Read Only).		Offset: 040h */
+	u32 gsnpsid;
+	/* User HW Config1 Register (Read Only).	Offset: 044h */
+	u32 ghwcfg1;
+	/* User HW Config2 Register (Read Only).	Offset: 048h */
+
+	u32 ghwcfg2;
+#define DWC_SLAVE_ONLY_ARCH			0
+#define DWC_EXT_DMA_ARCH			1
+#define DWC_INT_DMA_ARCH			2
+
+#define DWC_MODE_HNP_SRP_CAPABLE		0
+#define DWC_MODE_SRP_ONLY_CAPABLE		1
+#define DWC_MODE_NO_HNP_SRP_CAPABLE		2
+#define DWC_MODE_SRP_CAPABLE_DEVICE		3
+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE		4
+#define DWC_MODE_SRP_CAPABLE_HOST		5
+#define DWC_MODE_NO_SRP_CAPABLE_HOST		6
+#define DYNAMIC_FIFO				(1 << 19)
+#define	NUM_DEV_EP_SHIFT	10
+#define	NUM_DEV_EP	(0xF << NUM_DEV_EP_SHIFT)
+#define HSPHYTYPE_SHIFT				6
+#define HSPHYTYPEMSK				(3 << HSPHYTYPE_SHIFT)
+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED		0
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI			1
+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI			2
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI		3
+#define TKNQDEPTH_SHIFT					26
+#define TKNQDEPTHMSK				(0x1F << TKNQDEPTH_SHIFT)
+
+	/* User HW Config3 Register (Read Only).	Offset: 04Ch */
+	u32 ghwcfg3;
+#define	DFIFO_DEPTH_SHIFT	16
+#define DFIFO_DEPTH	((u32)0xFFFF << DFIFO_DEPTH_SHIFT)
+	/* User HW Config4 Register (Read Only).	Offset: 050h */
+	u32 ghwcfg4;
+#define NUM_DEV_PERIO_IN_EP_SHIFT	0
+#define NUM_DEV_PERIO_IN_EP (0xF << NUM_DEV_PERIO_IN_EP_SHIFT)
+#define DED_FIFO_EN	(1 << 25)
+#define NUM_IN_EPS_SHIFT	26
+#define NUM_IN_EPS	(0xF << NUM_IN_EPS_SHIFT)
+#define UTMI_PHY_DATA_WIDTH_SHIFT	14
+#define UTMI_PHY_DATA_WIDTH	(0x3 << UTMI_PHY_DATA_WIDTH_SHIFT)
+	/* Reserved					Offset: 054h-0FFh */
+	u32 reserved[43];
+	/* Host Periodic Transmit FIFO Size Register.	Offset: 100h */
+	u32 hptxfsiz;
+
+	/*
+	 * Device Periodic Transmit FIFO#n Register, if dedicated fifos are
+	 * disabled. Otherwise Device Transmit FIFO#n Register.
+	 *
+	 * Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15)
+	 */
+	u32 dptxfsiz_dieptxf[15];
+#define dwc_param_dev_tx_fifo_size_default	256
+#define dwc_param_dev_perio_tx_fifo_size_default	256
+};
+
+/*
+ * Device Global Registers. Offsets 800h-BFFh
+ *
+ * The following structures define the size and relative field offsets for the
+ * Device Mode Registers.
+ *
+ * These registers are visible only in Device mode and must not be accessed in
+ * Host mode, as the results are unknown.
+ */
+struct device_global_regs {		/* CONFIG_DWC_OTG_REG_LE */
+	/* Device Configuration Register.			Offset: 800h */
+	u32 dcfg;
+#define DWC_DCFG_FRAME_INTERVAL_80		0
+#define DWC_DCFG_FRAME_INTERVAL_85		1
+#define DWC_DCFG_FRAME_INTERVAL_90		2
+#define DWC_DCFG_FRAME_INTERVAL_95		3
+#define DWC_DCFG_FRAME_INTERVAL_MASK		3
+#define	PERFRINT_SHIFT				11
+#define DEVSPDMSK				(0x3 << 0)
+#define DEVADDR_SHIFT				4
+#define DEVADDRMSK				(0x7F << DEVADDR_SHIFT)
+#define NZSTSOUTHSHK				(1 << 2)
+	/* Device Control Register.				Offset: 804h */
+	u32 dctl;
+#define RMTWKUPSIG	(1 << 0)
+#define SFTDISCON	(1 << 1)
+#define CGNPINNAK	(1 << 7)
+	/* Device Status Register (Read Only).			Offset: 808h */
+	u32 dsts;
+#define ENUMSPD_SHIFT				1
+#define ENUMSPDMSK				(3 << ENUMSPD_SHIFT)
+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ		0
+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ		1
+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ			2
+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ			3
+	/* Reserved.						Offset: 80Ch */
+	u32 unused;
+	/* Device IN Endpoint Common Interrupt Mask Register.	Offset: 810h */
+	u32 diepmsk;
+#define TIMEOUTMSK				(1 << 3)
+#define INTKNTXFEMP				(1 << 4)
+#define INTKNEPMISMSK				(1 << 5)
+#define INEPNAKEFFMSK				(1 << 6)
+#define TXFIFOUNDRN				(1 << 8)
+	/* Device OUT Endpoint Common Interrupt Mask Register.	Offset: 814h */
+	u32 doepmsk;
+#define XFERCOMPLMSK				(1 << 0)
+#define EPDISABLEDMSK				(1 << 1)
+#define AHBERRMSK				(1 << 2)
+#define SETUPMSK				(1 << 3)
+#define INTKNTXFEMPMSK				(1 << 4)
+	/* Device All Endpoints Interrupt Register.		Offset: 818h */
+	u32 daint;
+	/* Device All Endpoints Interrupt Mask Register.	Offset: 81Ch */
+	u32 daintmsk;
+#define DAINTMASK_IN_SHIFT	0
+#define DAINTMASK_OUT_SHIFT	16
+	/* Device IN Token Queue Read Register-1 (Read Only).	Offset: 820h */
+	u32 dtknqr1;
+#define EPTK0_5_SHIFT				8
+#define EPTK0_5MSK				((u32)0xFFFFFF << EPTK0_5_SHIFT)
+#define INTKNWPTR_SHIFT				0
+#define INTKNWPTRMSK				((u32)0x1F << INTKNWPTR_SHIFT)
+	/* Device IN Token Queue Read Register-2 (Read Only).	Offset: 824h */
+	u32 dtknqr2;
+	/* Device VBUS discharge Register.			Offset: 828h */
+	u32 dvbusdis;
+	/* Device VBUS Pulse Register.				Offset: 82Ch */
+	u32 dvbuspulse;
+	/* Device IN Token Queue Read Register-3 (Read Only).	Offset: 830h */
+	u32 dtknqr3_dthrctl;
+	/* Device IN Token Queue Read Register-4 (Read Only).	Offset: 834h */
+	u32 dtknqr4_fifoemptymsk;
+};
+/*
+ * Device Logical IN Endpoint-Specific Registers. Offsets 900h-AFCh
+ *
+ * There will be one set of endpoint registers per logical endpoint implemented.
+ *
+ * These registers are visible only in Device mode and must not be accessed in
+ * Host mode, as the results are unknown.
+ */
+struct device_in_ep_regs {
+	/*
+	 * Device IN Endpoint Control Register.
+	 * Offset:900h + (ep_num * 20h) + 00h
+	 */
+	u32 diepctl;
+#define	EPENA				((u32)1 << 31)
+#define EPDIS				(1 << 30)
+#define	SNAK				(1 << 27)
+#define	CNAK				(1 << 26)
+#define	SSTALL				(1 << 21)
+#define MPS_SHIFT			0
+#define MPSMSK0				(3 << MPS_SHIFT)
+#define DWC_DEP0CTL_MPS_64			0
+#define DWC_DEP0CTL_MPS_32			1
+#define DWC_DEP0CTL_MPS_16			2
+#define DWC_DEP0CTL_MPS_8			3
+#define DIEPCTL_MPSMSK				(0x7FF << MPS_SHIFT)
+	/* Reserved. Offset:900h + (ep_num * 20h) + 04h */
+	u32 reserved04;
+	/*
+	 * Device IN Endpoint Interrupt Register.
+	 * Offset:900h + (ep_num * 20h) + 08h
+	 */
+	u32 diepint;
+#define TXFEMP				(1 << 7)
+#define INTKNTXFEMP			(1 << 4)
+#define XFERCOMPL			(1 << 0)
+	/* Reserved. Offset:900h + (ep_num * 20h) + 0Ch */
+	u32 reserved0C;
+	/* Device IN Endpoint Transfer Size Register.
+	 * Offset:900h + (ep_num * 20h) + 10h
+	 */
+	u32 dieptsiz;
+#define PKTCNT_SHIFT	19
+	/*
+	 * Device IN Endpoint DMA Address Register.
+	 * Offset:900h + (ep_num * 20h) + 14h
+	 */
+	u32 diepdma;
+	/* Reserved.
+	 * Offset:900h + (ep_num * 20h) + 18h - 900h + (ep_num * 20h) + 1Ch
+	 */
+	u32 dtxfsts;
+	/*
+	 * Reserved.
+	 * Offset:900h + (ep_num * 20h) + 1Ch - 900h + (ep_num * 20h) + 1Ch
+	 */
+	u32 reserved18;
+};
+
+/*
+ * Device Logical OUT Endpoint-Specific Registers. Offsets: B00h-CFCh
+ *
+ * There will be one set of endpoint registers per logical endpoint implemented.
+ *
+ * These registers are visible only in Device mode and must not be accessed in
+ * Host mode, as the results are unknown.
+ */
+struct device_out_ep_regs {
+	/*
+	 * Device OUT Endpoint Control Register.
+	 * Offset:B00h + (ep_num * 20h) + 00h
+	 */
+	u32 doepctl;
+#define DOEPCTL_MPSMSK		0x7FF
+#define USBACTEP		(1 << 15)
+#define EPTYPE_SHIFT		18
+#define EPTYPEMSK		(0x3 << EPTYPE_SHIFT)
+#define EPTYPE_BULK		0x2
+#define EPTYPE_INT		0x3
+#define DATA0PID		(1 << 28)
+#define DATA1PID		(1 << 29)
+#define DPIDMSK			(1 << 16)
+	/*
+	 * Device OUT Endpoint Frame number Register.
+	 * Offset: B00h + (ep_num * 20h) + 04h
+	 */
+	u32 doepfn;
+	/*
+	 * Device OUT Endpoint Interrupt Register.
+	 * Offset:B00h + (ep_num * 20h) + 08h
+	 */
+	u32 doepint;
+#define XFERCOMPL			(1 << 0)
+#define EPDISBLD			(1 << 1)
+#define AHBERR				(1 << 2)
+#define SETUP				(1 << 3)
+	/* Reserved. Offset:B00h + (ep_num * 20h) + 0Ch */
+	u32 reserved0C;
+	/*
+	 * Device OUT Endpoint Transfer Size Register.
+	 * Offset: B00h + (ep_num * 20h) + 10h
+	 */
+	u32 doeptsiz;
+#define XFERSIZE_SHIFT			0
+#define XFERSIZEMSK			0x3F
+#define PKTCNT_SHIFT			19
+#define PKTCNT				(3 << 19)
+#define SUPCNT_SHIFT			29
+#define SUPCNTMSK			(3 << SUPCNT_SHIFT)
+	/*
+	 * Device OUT Endpoint DMA Address Register.
+	 * Offset:B00h + (ep_num * 20h) + 14h
+	 */
+	u32 doepdma;
+	/*
+	 * Reserved.
+	 * Offset:B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch
+	 */
+	u32 unused[2];
+};
+#define MAX_EPS_CHANNELS 4
+
+/*
+ * The dwc_ep structure represents the state of a single endpoint when acting in
+ * device mode. It contains the data items needed for an endpoint to be
+ * activated and transfer packets.
+ */
+struct dwc_ep {
+	/* EP number used for register address lookup */
+	u8	 num;
+	/* EP direction 0 = OUT */
+#if 0
+	u8 is_in;
+#endif
+	/* pointer to the transfer buffer */
+	u8 *xfer_buff;
+	/* Number of bytes to transfer */
+	u32 xfer_len;
+};
+
+/*
+ * DWC_otg PCD Structure.
+ * This structure encapsulates the data for the dwc_otg PCD.
+ */
+struct dwc_pcd {
+#if 0
+	/* USB gadget */
+	/* Current configuration */
+	u8	configuration;
+	/* Current interface */
+	u8	interface;
+	/* Current alternate settinng */
+	u8	alternate;
+	/* Current Address */
+	u16 address;
+	/* device state */
+/*	usb_device_state_t device_state; */	/* current USB Device state */
+	/*
+	 * SETUP packet for EP0. This structure is allocated as a DMA buffer on
+	 * PCD initialization with enough space for up to 3 setup packets.
+	 */
+#endif
+	struct usb_device_request *req;
+	/* Array of EPs. */
+	struct dwc_ep ep0;
+	/* Array of IN EPs. */
+	struct dwc_ep in_ep[MAX_EPS_CHANNELS];
+	/* Array of OUT EPs. */
+	struct dwc_ep out_ep[MAX_EPS_CHANNELS];
+};
+
+/*
+ * The device_if structure contains information needed to manage the DWC_otg
+ * controller acting in device mode. It represents the programming view of the
+ * device-specific aspects of the controller.
+ */
+struct device_if {
+	struct core_global_regs *core_global_regs;
+	/* Common configuration information */
+
+	/* Device Global Registers starting at offset 800h */
+	struct device_global_regs *dev_global_regs;
+#define DWC_DEV_GLOBAL_REG_OFFSET		0x800
+
+	/* Device Logical IN Endpoint-Specific Registers 900h-AFCh */
+	struct device_in_ep_regs *in_ep_regs[MAX_EPS_CHANNELS];
+#define DWC_DEV_IN_EP_REG_OFFSET		0x900
+#define DWC_EP_REG_OFFSET			0x20
+
+	/* Device Logical OUT Endpoint-Specific Registers B00h-CFCh */
+	struct device_out_ep_regs *out_ep_regs[MAX_EPS_CHANNELS];
+#define DWC_DEV_OUT_EP_REG_OFFSET		0xB00
+
+	/* Push/pop addresses for endpoints or host channels.*/
+	u32 *data_fifo[MAX_EPS_CHANNELS];
+#define DWC_OTG_DATA_FIFO_OFFSET		0x1000
+#define DWC_OTG_DATA_FIFO_SIZE			0x1000
+
+	struct dwc_pcd pcd;
+	int speed;
+};
+
+
+/* Function declarations */
+
+void phy_init(void);
+void udc_irq(void);
+
+void udc_set_nak(int epid);
+void udc_unset_nak(int epid);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+int udc_init(void);
+/* void udc_enable(struct usb_device_instance *device);*/
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_startup_events(struct usb_device_instance *device);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+		  struct usb_endpoint_instance *endpoint);
+void udc_set_configuration_controller(u32);
+void udc_set_address_controller(u32);
+
+#endif /* __DW_UDC_H */