summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu/arm_cortexa8/mx51/generic.c52
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/imx_udc.c940
-rw-r--r--include/asm-arm/arch-mx51/mx51.h4
-rw-r--r--include/usb/imx_udc.h420
-rw-r--r--include/usbdevice.h4
6 files changed, 1420 insertions, 1 deletions
diff --git a/cpu/arm_cortexa8/mx51/generic.c b/cpu/arm_cortexa8/mx51/generic.c
index d854988..7013645 100644
--- a/cpu/arm_cortexa8/mx51/generic.c
+++ b/cpu/arm_cortexa8/mx51/generic.c
@@ -928,3 +928,55 @@ int arch_cpu_init(void)
return 0;
}
#endif
+
+void set_usboh3_clk(void)
+{
+ unsigned int reg;
+
+ reg = readl(MXC_CCM_CSCMR1);
+ reg |= 1 << 22;
+ writel(reg, MXC_CCM_CSCMR1);
+ reg = readl(MXC_CCM_CSCDR1);
+ reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
+ reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;
+ reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
+ reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
+
+ writel(reg, MXC_CCM_CSCDR1);
+}
+
+void set_usb_phy1_clk(void)
+{
+ unsigned int reg;
+
+ reg = readl(MXC_CCM_CSCMR1);
+ reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
+ writel(reg, MXC_CCM_CSCMR1);
+}
+
+void enable_usboh3_clk(unsigned char enable)
+{
+ unsigned int reg;
+
+ reg = readl(MXC_CCM_CCGR2);
+ if (enable)
+ reg |= 1 << 14;
+ else
+ reg &= ~(1 << 14);
+ writel(reg, MXC_CCM_CCGR2);
+}
+
+void enable_usb_phy1_clk(unsigned char enable)
+{
+
+ unsigned int reg;
+
+ reg = readl(MXC_CCM_CCGR2);
+
+ if (enable)
+ reg |= 1 << 0;
+ else
+ reg &= ~(1<<0);
+ writel(reg, MXC_CCM_CCGR2);
+}
+
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 2a19b1e..15daa68 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -28,6 +28,7 @@ LIB := $(obj)libusb_gadget.a
ifdef CONFIG_USB_DEVICE
COBJS-y += core.o
COBJS-y += ep0.o
+COBJS-$(CONFIG_MX51_BBG) += imx_udc.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/imx_udc.c b/drivers/usb/gadget/imx_udc.c
new file mode 100644
index 0000000..d180597
--- /dev/null
+++ b/drivers/usb/gadget/imx_udc.c
@@ -0,0 +1,940 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/errno.h>
+#include <usbdevice.h>
+#include <usb/imx_udc.h>
+#include "ep0.h"
+
+#ifdef DEBUG
+#define DBG(x...) printf(x)
+#else
+#define DBG(x...) do {} while (0)
+#endif
+
+#define mdelay(n) udelay((n)*1000)
+
+#define EP_TQ_ITEM_SIZE 4
+
+#define inc_index(x) (x = ((x+1) % EP_TQ_ITEM_SIZE))
+
+#define ep_is_in(e, tx) ((e == 0) ? (mxc_udc.ep0_dir == USB_DIR_IN) : tx)
+
+#define USB_RECIP_MASK 0x03
+#define USB_TYPE_MASK (0x03 << 5)
+
+typedef struct {
+ int epnum;
+ int dir;
+ int max_pkt_size;
+ struct usb_endpoint_instance *epi;
+ struct ep_queue_item *ep_dtd[EP_TQ_ITEM_SIZE];
+ int index; /* to index the free tx tqi */
+ int done; /* to index the complete rx tqi */
+ struct ep_queue_item *tail; /* last item in the dtd chain */
+ struct ep_queue_head *ep_qh;
+} mxc_ep_t;
+
+typedef struct {
+ int max_ep;
+ int ep0_dir;
+ int setaddr;
+ struct ep_queue_head *ep_qh;
+ mxc_ep_t *mxc_ep;
+ u32 qh_dma;
+} mxc_udc_ctrl;
+
+typedef struct usb_device_request setup_packet;
+
+static int usb_highspeed;
+static mxc_udc_ctrl mxc_udc;
+static struct usb_device_instance *udc_device;
+static struct urb *ep0_urb;
+/*
+ * malloc an nocached memory
+ * dmaaddr: phys address
+ * size : memory size
+ * align : alignment for this memroy
+ * return : vir address(NULL when malloc failt)
+*/
+static void *malloc_dma_buffer(u32 *dmaaddr, int size, int align)
+{
+ int msize = (size + align - 1);
+ u32 vir, vir_align;
+
+ vir = (u32)malloc(msize);
+ vir = ioremap_nocache(iomem_to_phys(vir), msize);
+ memset((void *)vir, 0, msize);
+ vir_align = (vir + align - 1) & (~(align - 1));
+ *dmaaddr = (u32)iomem_to_phys(vir_align);
+ DBG("vir addr %x, dma addr %x\n", vir_align, *dmaaddr);
+ return (void *)vir_align;
+}
+
+int is_usb_disconnected()
+{
+ int ret = 0;
+
+ ret = readl(USB_OTGSC) & OTGSC_B_SESSION_VALID ? 0 : 1;
+ return ret;
+}
+
+static int mxc_init_usb_qh(void)
+{
+ int size;
+ memset(&mxc_udc, 0, sizeof(mxc_udc));
+ mxc_udc.max_ep = (readl(USB_DCCPARAMS) & DCCPARAMS_DEN_MASK) * 2;
+ DBG("udc max ep = %d\n", mxc_udc.max_ep);
+ size = mxc_udc.max_ep * sizeof(struct ep_queue_head);
+ mxc_udc.ep_qh = malloc_dma_buffer(&mxc_udc.qh_dma, size, 1024);
+ if (!mxc_udc.ep_qh) {
+ printf("malloc ep qh dma buffer failure\n");
+ return -1;
+ }
+ memset(mxc_udc.ep_qh, 0, size);
+ writel(mxc_udc.qh_dma & 0xfffff800, USB_ENDPOINTLISTADDR);
+
+ return 0;
+}
+
+static int mxc_init_ep_struct(void)
+{
+ int i;
+
+ DBG("init mxc ep\n");
+ mxc_udc.mxc_ep = malloc(mxc_udc.max_ep * sizeof(mxc_ep_t));
+ if (!mxc_udc.mxc_ep) {
+ printf("malloc ep struct failure\n");
+ return -1;
+ }
+ memset((void *)mxc_udc.mxc_ep, 0, sizeof(mxc_ep_t) * mxc_udc.max_ep);
+ for (i = 0; i < mxc_udc.max_ep / 2; i++) {
+ mxc_ep_t *ep;
+ ep = mxc_udc.mxc_ep + i * 2;
+ ep->epnum = i;
+ ep->index = ep->done = 0;
+ ep->dir = USB_RECV; /* data from host to device */
+ ep->ep_qh = &mxc_udc.ep_qh[i * 2];
+
+ ep = mxc_udc.mxc_ep + (i * 2 + 1);
+ ep->epnum = i;
+ ep->index = ep->done = 0;
+ ep->dir = USB_SEND; /* data to host from device */
+ ep->ep_qh = &mxc_udc.ep_qh[(i * 2 + 1)];
+ }
+ return 0;
+}
+
+static int mxc_init_ep_dtd(u8 index)
+{
+ mxc_ep_t *ep;
+ struct ep_queue_item *tqi;
+ u32 dma;
+ int i;
+
+ if (index >= mxc_udc.max_ep)
+ DBG("%s ep %d is not valid\n", __func__, index);
+
+ ep = mxc_udc.mxc_ep + index;
+ tqi = malloc_dma_buffer(&dma,
+ EP_TQ_ITEM_SIZE * sizeof(struct ep_queue_item), 1024);
+ if (tqi == NULL) {
+ printf("%s malloc tq item failure\n", __func__);
+ return -1;
+ }
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ ep->ep_dtd[i] = tqi + i;
+ ep->ep_dtd[i]->item_dma =
+ dma + i * sizeof(struct ep_queue_item);
+ }
+ return -1;
+}
+static void mxc_ep_qh_setup(u8 ep_num, u8 dir, u8 ep_type,
+ u32 max_pkt_len, u32 zlt, u8 mult)
+{
+ struct ep_queue_head *p_qh = mxc_udc.ep_qh + (2 * ep_num + dir);
+ u32 tmp = 0;
+
+ tmp = max_pkt_len << 16;
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ tmp |= (1 << 15);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ tmp |= (mult << 30);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ break;
+ default:
+ DBG("error ep type is %d\n", ep_type);
+ return;
+ }
+ if (zlt)
+ tmp |= (1<<29);
+
+ p_qh->config = tmp;
+}
+
+static void mxc_ep_setup(u8 ep_num, u8 dir, u8 ep_type)
+{
+ u32 epctrl = 0;
+ epctrl = readl(USB_ENDPTCTRL(ep_num));
+ if (dir) {
+ if (ep_num)
+ epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ epctrl |= EPCTRL_TX_ENABLE;
+ epctrl |= ((u32)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT);
+ } else {
+ if (ep_num)
+ epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ epctrl |= EPCTRL_RX_ENABLE;
+ epctrl |= ((u32)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+ writel(epctrl, USB_ENDPTCTRL(ep_num));
+}
+
+static void mxc_tqi_init_page(struct ep_queue_item *tqi)
+{
+ tqi->page0 = tqi->page_dma;
+ tqi->page1 = tqi->page0 + 0x1000;
+ tqi->page2 = tqi->page1 + 0x1000;
+ tqi->page3 = tqi->page2 + 0x1000;
+ tqi->page4 = tqi->page3 + 0x1000;
+}
+static int mxc_malloc_ep0_ptr(mxc_ep_t *ep)
+{
+ int i;
+ struct ep_queue_item *tqi;
+ int max_pkt_size = USB_MAX_CTRL_PAYLOAD;
+
+ ep->max_pkt_size = max_pkt_size;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ tqi = ep->ep_dtd[i];
+ tqi->page_vir = (u32)malloc_dma_buffer(&tqi->page_dma,
+ max_pkt_size, 1024);
+ if ((void *)tqi->page_vir == NULL) {
+ printf("malloc ep's dtd bufer failure, i=%d\n", i);
+ return -1;
+ }
+ mxc_tqi_init_page(tqi);
+ }
+ return 0;
+}
+
+static void ep0_setup(void)
+{
+ mxc_ep_qh_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 0, 0);
+ mxc_ep_qh_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+ USB_MAX_CTRL_PAYLOAD, 0, 0);
+ mxc_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+ mxc_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+ mxc_init_ep_dtd(0 * 2 + USB_RECV);
+ mxc_init_ep_dtd(0 * 2 + USB_SEND);
+ mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_RECV));
+ mxc_malloc_ep0_ptr(mxc_udc.mxc_ep + (USB_SEND));
+}
+
+
+static int mxc_tqi_is_busy(struct ep_queue_item *tqi)
+{
+ /* bit 7 is set by software when send, clear by controller
+ when finish */
+ return tqi->info & (1 << 7);
+}
+
+static int mxc_ep_xfer_is_working(mxc_ep_t *ep, u32 in)
+{
+ /* in: means device -> host */
+ u32 bitmask = 1 << (ep->epnum + in * 16);
+ u32 temp, prime, tstat;
+
+ prime = (bitmask & readl(USB_ENDPTPRIME));
+ if (prime)
+ return 1;
+ do {
+ temp = readl(USB_USBCMD);
+ writel(temp|USB_CMD_ATDTW, USB_USBCMD);
+ tstat = readl(USB_ENDPTSTAT) & bitmask;
+ } while (!readl(USB_USBCMD) & USB_CMD_ATDTW);
+ writel(temp & (~USB_CMD_ATDTW), USB_USBCMD);
+
+ if (tstat)
+ return 1;
+ return 0;
+}
+
+static void mxc_update_qh(mxc_ep_t *ep, struct ep_queue_item *tqi, u32 in)
+{
+ /* in: means device -> host */
+ struct ep_queue_head *qh = ep->ep_qh;
+ u32 bitmask = 1 << (ep->epnum + in * 16);
+ DBG("%s, line %d, epnum=%d, in=%d\n", __func__,
+ __LINE__, ep->epnum, in);
+ qh->next_queue_item = tqi->item_dma;
+ qh->info = 0;
+ writel(bitmask, USB_ENDPTPRIME);
+}
+
+static void _dump_buf(u32 buf, u32 len)
+{
+#ifdef DEBUG
+ char *data = (char *)buf;
+ int i;
+ for (i = 0; i < len; i++)
+ printf("%x ", data[i]);
+ printf("\n");
+#endif
+}
+
+
+static void mxc_udc_queue_update(u8 epnum, u8 *data, u32 len, u32 tx)
+{
+ mxc_ep_t *ep;
+ struct ep_queue_item *tqi, *head, *last;
+ int send = 0;
+ int in;
+
+ head = last = NULL;
+ in = ep_is_in(epnum, tx);
+ ep = mxc_udc.mxc_ep + (epnum * 2 + in);
+ DBG("epnum = %d, in = %d\n", epnum, in);
+ do {
+ tqi = ep->ep_dtd[ep->index];
+ DBG("%s, index = %d, tqi = %p\n", __func__, ep->index, tqi);
+ while (mxc_tqi_is_busy(tqi))
+ ;
+ mxc_tqi_init_page(tqi);
+ DBG("%s, line = %d, len = %d\n", __func__, __LINE__, len);
+ inc_index(ep->index);
+ send = MIN(len, 0x1000);
+ if (data) {
+ memcpy((void *)tqi->page_vir, (void *)data, send);
+ _dump_buf(tqi->page_vir, send);
+ }
+ if (!head)
+ last = head = tqi;
+ else {
+ last->next_item_ptr = tqi->item_dma;
+ last->next_item_vir = tqi;
+ last = tqi;
+ }
+ if (!tx)
+ tqi->reserved[0] = send;
+ /* we set IOS for every dtd */
+ tqi->info = ((send << 16) | (1 << 15) | (1 << 7));
+ data += send;
+ len -= send;
+ } while (len);
+
+ last->next_item_ptr = 0x1; /* end */
+ if (ep->tail) {
+ ep->tail->next_item_ptr = head->item_dma;
+ ep->tail->next_item_vir = head;
+ if (mxc_ep_xfer_is_working(ep, in)) {
+ DBG("ep is working\n");
+ goto out;
+ }
+ }
+ mxc_update_qh(ep, head, in);
+out:
+ ep->tail = last;
+}
+
+static void mxc_udc_txqueue_update(u8 ep, u8 *data, u32 len)
+{
+ mxc_udc_queue_update(ep, data, len, 1);
+}
+
+void mxc_udc_rxqueue_update(u8 ep, u32 len)
+{
+ mxc_udc_queue_update(ep, NULL, len, 0);
+}
+
+static void mxc_ep0_stall(void)
+{
+ u32 temp;
+ temp = readl(USB_ENDPTCTRL(0));
+ temp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+ writel(temp, USB_ENDPTCTRL(0));
+}
+/*
+ * usb function
+ */
+void usb_setup(void)
+{
+ unsigned int temp = 0, portctrl = 0;
+
+ /* Stop and reset the usb controller */
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_CTRL_RESET;
+ writel(temp, USB_USBCMD);
+ while (readl(USB_USBCMD) & USB_CMD_CTRL_RESET)
+ ;
+
+ /* Set the controller as device mode */
+ temp = readl(USB_USBMODE);
+ temp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ writel(temp, USB_USBMODE);
+
+ /* Config PHY interface */
+ portctrl = readl(USB_PORTSC);
+ portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+ portctrl |= PORTSCX_PTW_16BIT;
+ writel(portctrl, USB_PORTSC);
+
+ writel(0xffffffff, USB_ENDPTFLUSH);
+}
+static void mxc_usb_run(void)
+{
+ unsigned int temp = 0;
+
+ /* Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+ | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+ | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ writel(temp, USB_USBINTR);
+
+ /* Set controller to Run */
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+}
+
+static void mxc_usb_stop(void)
+{
+ unsigned int temp = 0;
+
+ writel(temp, USB_USBINTR);
+
+ /* Set controller to Stop */
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+}
+
+static void usb_phy_init(void)
+{
+ u32 temp;
+ /* select 24M clk */
+ temp = readl(USB_PHY1_CTRL);
+ temp &= ~3;
+ temp |= 1;
+ writel(temp, USB_PHY1_CTRL);
+ /* Config PHY interface */
+ temp = readl(USB_PORTSC);
+ temp &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+ temp |= PORTSCX_PTW_16BIT;
+ writel(temp, USB_PORTSC);
+ DBG("Config PHY END\n");
+}
+
+static void usb_set_mode_device(void)
+{
+ u32 temp;
+ /* Do core reset */
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_CTRL_RESET;
+ writel(temp, USB_USBCMD);
+ while (readl(USB_USBCMD) & USB_CMD_CTRL_RESET)
+ ;
+ DBG("DOORE RESET END\n");
+
+ DBG("init core to device mode\n");
+ temp = readl(USB_USBMODE);
+ temp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ temp |= USB_MODE_SETUP_LOCK_OFF;
+ writel(temp, USB_USBMODE);
+ DBG("init core to device mode end\n");
+}
+
+static void usb_init_eps(void)
+{
+ u32 temp;
+
+ temp = readl(USB_ENDPTNAKEN);
+ temp |= 0x10001; /* clear mode bits */
+ writel(temp, USB_ENDPTNAKEN);
+ writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+ writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+ writel(0xffffffff, USB_ENDPTFLUSH);
+ DBG("FLUSH END\n");
+}
+
+static void usb_udc_init(void)
+{
+ DBG("\n************************\n");
+ DBG(" usb init start\n");
+ DBG("\n************************\n");
+
+ usb_phy_init();
+ usb_set_mode_device();
+ mxc_init_usb_qh();
+ usb_init_eps();
+ mxc_init_ep_struct();
+ ep0_setup();
+}
+
+void usb_shutdown(void)
+{
+ u32 temp;
+ /* disable pullup */
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_RUN_STOP;
+ writel(temp, USB_USBCMD);
+ mdelay(2);
+}
+
+static void ch9getstatus(u8 request_type, u16 value, u16 index, u16 length)
+{
+ u16 tmp;
+
+ if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ tmp = 1 << 0; /* self powerd */
+ tmp |= 0 << 1; /* not remote wakeup able */
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+ tmp = 0;
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+ tmp = 0;
+ }
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, (u8 *)&tmp, 2, 0xffffffff);
+}
+static void mxc_udc_read_setup_pkt(setup_packet *s)
+{
+ u32 temp;
+ temp = readl(USB_ENDPTSETUPSTAT);
+ writel(temp, USB_ENDPTSETUPSTAT);
+ DBG("setup stat %x\n", temp);
+ do {
+ temp = readl(USB_USBCMD);
+ temp |= USB_CMD_SUTW;
+ writel(temp, USB_USBCMD);
+ memcpy((void *)s,
+ (void *)mxc_udc.mxc_ep[0].ep_qh->setup_data, 8);
+ } while (!readl(USB_USBCMD) & USB_CMD_SUTW);
+
+ DBG("handle_setup s.type=%x req=%x len=%x\n",
+ s->bmRequestType, s->bRequest, s->wLength);
+ temp = readl(USB_USBCMD);
+ temp &= ~USB_CMD_SUTW;
+ writel(temp, USB_ENDPTSETUPSTAT);
+}
+
+static void mxc_udc_recv_setup(void)
+{
+ setup_packet *s = &ep0_urb->device_request;
+
+ mxc_udc_read_setup_pkt(s);
+ if (s->wLength) {
+ mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
+ USB_DIR_OUT : USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ }
+ if (ep0_recv_setup(ep0_urb)) {
+ mxc_ep0_stall();
+ return;
+ }
+ switch (s->bRequest) {
+ case USB_REQ_GET_STATUS:
+ if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) !=
+ (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9getstatus(s->bmRequestType, s->wValue,
+ s->wIndex, s->wLength);
+ return;
+ case USB_REQ_SET_ADDRESS:
+ if (s->bmRequestType != (USB_DIR_OUT |
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+ break;
+ mxc_udc.setaddr = 1;
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ return;
+ case USB_REQ_SET_CONFIGURATION:
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ {
+ int rc = -1;
+ if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+ (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD))
+ rc = 0;
+ else if ((s->bmRequestType &
+ (USB_RECIP_MASK | USB_TYPE_MASK)) ==
+ (USB_RECIP_DEVICE | USB_TYPE_STANDARD))
+ rc = 0;
+ else
+ break;
+ if (rc == 0) {
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ }
+ return;
+ }
+ default:
+ break;
+ }
+ if (s->wLength) {
+ mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
+ USB_DIR_IN : USB_DIR_OUT;
+ mxc_udc_queue_update(0, ep0_urb->buffer,
+ ep0_urb->actual_length, 0xffffffff);
+ ep0_urb->actual_length = 0;
+ } else {
+ mxc_udc.ep0_dir = USB_DIR_IN;
+ mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
+ }
+}
+static int mxc_udc_tqi_empty(struct ep_queue_item *tqi)
+{
+ int ret;
+
+ ret = tqi->info & (1 << 7);
+ return ret;
+}
+
+static struct usb_endpoint_instance *mxc_get_epi(u8 epnum)
+{
+ 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) == epnum)
+ return &udc_device->bus->endpoint_array[i];
+ }
+ return NULL;
+}
+static u32 _mxc_ep_recv_data(u8 epnum, struct ep_queue_item *tqi)
+{
+ struct usb_endpoint_instance *epi = mxc_get_epi(epnum);
+ struct urb *urb;
+ u32 len = 0;
+
+ if (!epi)
+ return 0;
+
+ urb = epi->rcv_urb;
+ if (urb) {
+ u8 *data = urb->buffer + urb->actual_length;
+ int remain_len = (tqi->info >> 16) & (0xefff);
+ len = tqi->reserved[0] - remain_len;
+ DBG("recv len %d-%d-%d\n", len, tqi->reserved[0], remain_len);
+ memcpy(data, (void *)tqi->page_vir, len);
+ }
+ return len;
+}
+
+static void mxc_udc_ep_recv(u8 epnum)
+{
+ mxc_ep_t *ep = mxc_udc.mxc_ep + (epnum * 2 + USB_RECV);
+ struct ep_queue_item *tqi;
+ while (1) {
+ u32 nbytes;
+ tqi = ep->ep_dtd[ep->done];
+ if (mxc_udc_tqi_empty(tqi))
+ break;
+ nbytes = _mxc_ep_recv_data(epnum, tqi);
+ usbd_rcv_complete(ep->epi, nbytes, 0);
+ inc_index(ep->done);
+ if (ep->done == ep->index)
+ break;
+ }
+}
+static void mxc_udc_handle_xfer_complete(void)
+{
+ int i;
+ u32 bitpos = readl(USB_ENDPTCOMPLETE);
+
+ writel(bitpos, USB_ENDPTCOMPLETE);
+
+ for (i = 0; i < mxc_udc.max_ep; i++) {
+ int epnum = i >> 1;
+ int dir = i % 2;
+ u32 bitmask = 1 << (epnum + 16 * dir);
+ if (!(bitmask & bitpos))
+ continue;
+ DBG("ep %d, dir %d, complete\n", epnum, dir);
+ if (!epnum) {
+ if (mxc_udc.setaddr) {
+ writel(udc_device->address << 25,
+ USB_DEVICEADDR);
+ mxc_udc.setaddr = 0;
+ }
+ continue;
+ }
+ DBG("############### dir = %d ***************\n", dir);
+ if (dir == USB_SEND)
+ continue;
+ mxc_udc_ep_recv(epnum);
+ }
+}
+static void usb_dev_hand_usbint(void)
+{
+ if (readl(USB_ENDPTSETUPSTAT)) {
+ DBG("recv one setup packet\n");
+ mxc_udc_recv_setup();
+ }
+ if (readl(USB_ENDPTCOMPLETE)) {
+ DBG("Dtd complete irq\n");
+ mxc_udc_handle_xfer_complete();
+ }
+}
+
+static void usb_dev_hand_reset(void)
+{
+ u32 temp;
+ temp = readl(USB_DEVICEADDR);
+ temp &= ~0xfe000000;
+ writel(temp, USB_DEVICEADDR);
+ writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
+ writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE);
+ while (readl(USB_ENDPTPRIME))
+ ;
+ writel(0xffffffff, USB_ENDPTFLUSH);
+ DBG("reset-PORTSC=%x\n", readl(USB_PORTSC));
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+}
+
+void usb_dev_hand_pci(void)
+{
+ u32 speed;
+ while (readl(USB_PORTSC) & PORTSCX_PORT_RESET)
+ ;
+ speed = readl(USB_PORTSC) & PORTSCX_PORT_SPEED_MASK;
+ switch (speed) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ usb_highspeed = 2;
+ break;
+ case PORTSCX_PORT_SPEED_FULL:
+ usb_highspeed = 1;
+ break;
+ case PORTSCX_PORT_SPEED_LOW:
+ usb_highspeed = 0;
+ break;
+ default:
+ break;
+ }
+ DBG("portspeed=%d, speed = %x\n", usb_highspeed, speed);
+}
+
+void usb_dev_hand_suspend(void)
+{
+}
+static int ll;
+void mxc_irq_poll(void)
+{
+ unsigned irq_src = readl(USB_USBSTS) & readl(USB_USBINTR);
+ writel(irq_src, USB_USBSTS);
+
+ if (irq_src == 0)
+ return;
+
+ if (irq_src & USB_STS_INT) {
+ ll++;
+ DBG("USB_INT\n");
+ usb_dev_hand_usbint();
+ }
+ if (irq_src & USB_STS_RESET) {
+ printf("USB_RESET\n");
+ usb_dev_hand_reset();
+ }
+ if (irq_src & USB_STS_PORT_CHANGE)
+ usb_dev_hand_pci();
+ if (irq_src & USB_STS_SUSPEND)
+ printf("USB_SUSPEND\n");
+ if (irq_src & USB_STS_ERR)
+ printf("USB_ERR\n");
+}
+
+void mxc_udc_wait_cable_insert(void)
+{
+ u32 temp;
+ int cable_connect = 1;
+
+ do {
+ udelay(50);
+
+ temp = readl(USB_OTGSC);
+ if (temp & (OTGSC_B_SESSION_VALID)) {
+ printf("USB Mini b cable Connected!\n");
+ break;
+ } else if (cable_connect == 1) {
+ printf("wait usb cable into the connector!\n");
+ cable_connect = 0;
+ }
+ } while (1);
+}
+
+/*
+ * mxc_udc_init function
+ */
+int mxc_udc_init(void)
+{
+ set_usboh3_clk();
+ set_usb_phy1_clk();
+ enable_usboh3_clk(1);
+ enable_usb_phy1_clk(1);
+ usb_udc_init();
+
+ return 0;
+}
+
+void mxc_udc_poll(void)
+{
+ mxc_irq_poll();
+}
+
+/*
+ * Functions for gadget APIs
+ */
+int udc_init(void)
+{
+ mxc_udc_init();
+ return 0;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, u32 index,
+ struct usb_endpoint_instance *epi)
+{
+ u8 dir, epnum, zlt, mult;
+ u8 ep_type;
+ u32 max_pkt_size;
+ int ep_addr;
+ mxc_ep_t *ep;
+
+ if (epi) {
+ zlt = 1;
+ mult = 0;
+ ep_addr = epi->endpoint_address;
+ epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+ DBG("setup ep %d\n", epnum);
+ if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ dir = USB_SEND;
+ ep_type = epi->tx_attributes;
+ max_pkt_size = epi->tx_packetSize;
+ } else {
+ dir = USB_RECV;
+ ep_type = epi->rcv_attributes;
+ max_pkt_size = epi->rcv_packetSize;
+ }
+ if (ep_type == USB_ENDPOINT_XFER_ISOC) {
+ mult = (u32)(1 + ((max_pkt_size >> 11) & 0x03));
+ max_pkt_size = max_pkt_size & 0x7ff;
+ DBG("mult = %d\n", mult);
+ }
+ ep = mxc_udc.mxc_ep + (epnum * 2 + dir);
+ ep->epi = epi;
+ if (epnum) {
+ struct ep_queue_item *tqi;
+ int i;
+
+ mxc_ep_qh_setup(epnum, dir, ep_type,
+ max_pkt_size, zlt, mult);
+ mxc_ep_setup(epnum, dir, ep_type);
+ mxc_init_ep_dtd(epnum * 2 + dir);
+
+ /* malloc endpoint's dtd's data buffer*/
+ ep->max_pkt_size = max_pkt_size;
+ for (i = 0; i < EP_TQ_ITEM_SIZE; i++) {
+ tqi = ep->ep_dtd[i];
+ tqi->page_vir = (u32)malloc_dma_buffer(
+ &tqi->page_dma, max_pkt_size, 1024);
+ if ((void *)tqi->page_vir == NULL) {
+ printf("malloc dtd bufer failure\n");
+ return;
+ }
+ mxc_tqi_init_page(tqi);
+ }
+ }
+ }
+}
+
+
+int udc_endpoint_write(struct usb_endpoint_instance *epi)
+{
+ struct urb *urb = epi->tx_urb;
+ int ep_num = epi->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+ u8 *data = (u8 *)urb->buffer + epi->sent;
+ int n = urb->actual_length - epi->sent;
+ mxc_udc_txqueue_update(ep_num, data, n);
+ epi->last = n;
+ epi->sent += n;
+ return 0;
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ udc_device = device;
+ ep0_urb = usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array);
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+ usbd_device_event_irq(device, DEVICE_INIT, 0);
+ usbd_device_event_irq(device, DEVICE_CREATE, 0);
+ udc_enable(device);
+}
+
+void udc_irq(void)
+{
+ mxc_irq_poll();
+}
+
+void udc_connect(void)
+{
+ mxc_usb_run();
+ mxc_udc_wait_cable_insert();
+}
+
+void udc_disconnect(void)
+{
+ mxc_usb_stop();
+}
+
+void udc_set_nak(int epid)
+{
+}
+
+void udc_unset_nak(int epid)
+{
+}
diff --git a/include/asm-arm/arch-mx51/mx51.h b/include/asm-arm/arch-mx51/mx51.h
index d06abac..1f23232 100644
--- a/include/asm-arm/arch-mx51/mx51.h
+++ b/include/asm-arm/arch-mx51/mx51.h
@@ -493,6 +493,10 @@ extern unsigned int mxc_get_clock(enum mxc_clock clk);
extern unsigned int get_board_rev(void);
extern int is_soc_rev(int rev);
extern enum boot_device get_boot_device(void);
+extern void set_usboh3_clk(void);
+extern void set_usb_phy1_clk(void);
+extern void enable_usboh3_clk(unsigned char enable);
+extern void enable_usb_phy1_clk(unsigned char enable);
#endif /* __ASSEMBLER__*/
diff --git a/include/usb/imx_udc.h b/include/usb/imx_udc.h
new file mode 100644
index 0000000..bbc18cb
--- /dev/null
+++ b/include/usb/imx_udc.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _IMX_UDC_H_
+#define _IMX_UDC_H_
+
+#define AIPS1_BASE_ADDR 0x73F00000
+
+#define OTG_BASE_ADDR (AIPS1_BASE_ADDR + 0x00080000)
+
+#define USB_ID (OTG_BASE_ADDR + 0x0000)
+#define USB_HWGENERAL (OTG_BASE_ADDR + 0x0004)
+#define USB_HWHOST (OTG_BASE_ADDR + 0x0008)
+#define USB_HWDEVICE (OTG_BASE_ADDR + 0x000C)
+#define USB_HWTXBUF (OTG_BASE_ADDR + 0x0010)
+#define USB_HWRXBUF (OTG_BASE_ADDR + 0x0014)
+#define USB_SBUSCFG (OTG_BASE_ADDR + 0x0090)
+
+#define USB_CAPLENGTH (OTG_BASE_ADDR + 0x0100) /* 8 bit */
+#define USB_HCIVERSION (OTG_BASE_ADDR + 0x0102) /* 16 bit */
+#define USB_HCSPARAMS (OTG_BASE_ADDR + 0x0104)
+#define USB_HCCPARAMS (OTG_BASE_ADDR + 0x0108)
+#define USB_DCIVERSION (OTG_BASE_ADDR + 0x0120) /* 16 bit */
+#define USB_DCCPARAMS (OTG_BASE_ADDR + 0x0124)
+#define USB_USBCMD (OTG_BASE_ADDR + 0x0140)
+#define USB_USBSTS (OTG_BASE_ADDR + 0x0144)
+#define USB_USBINTR (OTG_BASE_ADDR + 0x0148)
+#define USB_FRINDEX (OTG_BASE_ADDR + 0x014C)
+#define USB_DEVICEADDR (OTG_BASE_ADDR + 0x0154)
+#define USB_ENDPOINTLISTADDR (OTG_BASE_ADDR + 0x0158)
+#define USB_BURSTSIZE (OTG_BASE_ADDR + 0x0160)
+#define USB_TXFILLTUNING (OTG_BASE_ADDR + 0x0164)
+#define USB_ULPI_VIEWPORT (OTG_BASE_ADDR + 0x0170)
+#define USB_ENDPTNAK (OTG_BASE_ADDR + 0x0178)
+#define USB_ENDPTNAKEN (OTG_BASE_ADDR + 0x017C)
+#define USB_PORTSC (OTG_BASE_ADDR + 0x0184)
+#define USB_OTGSC (OTG_BASE_ADDR + 0x01A4)
+#define USB_USBMODE (OTG_BASE_ADDR + 0x01A8)
+#define USB_ENDPTSETUPSTAT (OTG_BASE_ADDR + 0x01AC)
+#define USB_ENDPTPRIME (OTG_BASE_ADDR + 0x01B0)
+#define USB_ENDPTFLUSH (OTG_BASE_ADDR + 0x01B4)
+#define USB_ENDPTSTAT (OTG_BASE_ADDR + 0x01B8)
+#define USB_ENDPTCOMPLETE (OTG_BASE_ADDR + 0x01BC)
+#define USB_ENDPTCTRL(n) (OTG_BASE_ADDR + 0x01C0 + (4 * (n)))
+
+#define USB_PHY1_CTRL (OTG_BASE_ADDR + 0x80C)
+#define USBCMD_RESET 2
+#define USBCMD_ATTACH 1
+
+#define USBMODE_DEVICE 2
+#define USBMODE_HOST 3
+
+struct ep_queue_head {
+ volatile unsigned int config;
+ volatile unsigned int current; /* read-only */
+
+ volatile unsigned int next_queue_item;
+ volatile unsigned int info;
+ volatile unsigned int page0;
+ volatile unsigned int page1;
+ volatile unsigned int page2;
+ volatile unsigned int page3;
+ volatile unsigned int page4;
+ volatile unsigned int reserved_0;
+
+ volatile unsigned char setup_data[8];
+ volatile unsigned int reserved[4];
+};
+
+#define CONFIG_MAX_PKT(n) ((n) << 16)
+#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
+#define CONFIG_IOS (1 << 15) /* IRQ on setup */
+
+struct ep_queue_item {
+ volatile unsigned int next_item_ptr;
+ volatile unsigned int info;
+ volatile unsigned int page0;
+ volatile unsigned int page1;
+ volatile unsigned int page2;
+ volatile unsigned int page3;
+ volatile unsigned int page4;
+ unsigned int item_dma;
+ unsigned int page_vir;
+ unsigned int page_dma;
+ struct ep_queue_item *next_item_vir;
+ volatile unsigned int reserved[5];
+};
+
+#define TERMINATE 1
+
+#define INFO_BYTES(n) ((n) << 16)
+#define INFO_IOC (1 << 15)
+#define INFO_ACTIVE (1 << 7)
+#define INFO_HALTED (1 << 6)
+#define INFO_BUFFER_ERROR (1 << 5)
+#define INFO_TX_ERROR (1 << 3)
+
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC 0x00000080
+#define DCCPARAMS_DEN_MASK 0x0000001f
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_MASKS (0x3fff)
+/* USB CMD Register Bit Masks */
+#define USB_CMD_RUN_STOP (0x00000001)
+#define USB_CMD_CTRL_RESET (0x00000002)
+#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
+#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
+#define USB_CMD_INT_AA_DOORBELL (0x00000040)
+#define USB_CMD_ASP (0x00000300)
+#define USB_CMD_ASYNC_SCH_PARK_EN (0x00000800)
+#define USB_CMD_SUTW (0x00002000)
+#define USB_CMD_ATDTW (0x00004000)
+#define USB_CMD_ITC (0x00FF0000)
+
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024 (0x00000000)
+#define USB_CMD_FRAME_SIZE_512 (0x00000004)
+#define USB_CMD_FRAME_SIZE_256 (0x00000008)
+#define USB_CMD_FRAME_SIZE_128 (0x0000000C)
+#define USB_CMD_FRAME_SIZE_64 (0x00008000)
+#define USB_CMD_FRAME_SIZE_32 (0x00008004)
+#define USB_CMD_FRAME_SIZE_16 (0x00008008)
+#define USB_CMD_FRAME_SIZE_8 (0x0000800C)
+
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00 (0x00000000)
+#define USB_CMD_ASP_01 (0x00000100)
+#define USB_CMD_ASP_10 (0x00000200)
+#define USB_CMD_ASP_11 (0x00000300)
+#define USB_CMD_ASP_BIT_POS (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD (0x00000000)
+#define USB_CMD_ITC_1_MICRO_FRM (0x00010000)
+#define USB_CMD_ITC_2_MICRO_FRM (0x00020000)
+#define USB_CMD_ITC_4_MICRO_FRM (0x00040000)
+#define USB_CMD_ITC_8_MICRO_FRM (0x00080000)
+#define USB_CMD_ITC_16_MICRO_FRM (0x00100000)
+#define USB_CMD_ITC_32_MICRO_FRM (0x00200000)
+#define USB_CMD_ITC_64_MICRO_FRM (0x00400000)
+#define USB_CMD_ITC_BIT_POS (16)
+
+/* USB STS Register Bit Masks */
+#define USB_STS_INT (0x00000001)
+#define USB_STS_ERR (0x00000002)
+#define USB_STS_PORT_CHANGE (0x00000004)
+#define USB_STS_FRM_LST_ROLL (0x00000008)
+#define USB_STS_SYS_ERR (0x00000010)
+#define USB_STS_IAA (0x00000020)
+#define USB_STS_RESET (0x00000040)
+#define USB_STS_SOF (0x00000080)
+#define USB_STS_SUSPEND (0x00000100)
+#define USB_STS_HC_HALTED (0x00001000)
+#define USB_STS_RCL (0x00002000)
+#define USB_STS_PERIODIC_SCHEDULE (0x00004000)
+#define USB_STS_ASYNC_SCHEDULE (0x00008000)
+
+/* USB INTR Register Bit Masks */
+#define USB_INTR_INT_EN (0x00000001)
+#define USB_INTR_ERR_INT_EN (0x00000002)
+#define USB_INTR_PTC_DETECT_EN (0x00000004)
+#define USB_INTR_FRM_LST_ROLL_EN (0x00000008)
+#define USB_INTR_SYS_ERR_EN (0x00000010)
+#define USB_INTR_ASYN_ADV_EN (0x00000020)
+#define USB_INTR_RESET_EN (0x00000040)
+#define USB_INTR_SOF_EN (0x00000080)
+#define USB_INTR_DEVICE_SUSPEND (0x00000100)
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDRESS_MASK (0xFE000000)
+#define USB_DEVICE_ADDRESS_BIT_POS (25)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK (0xfffff800)
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
+#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
+#define PORTSCX_PORT_ENABLE (0x00000004)
+#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
+#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
+#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
+#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
+#define PORTSCX_PORT_SUSPEND (0x00000080)
+#define PORTSCX_PORT_RESET (0x00000100)
+#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
+#define PORTSCX_PORT_POWER (0x00001000)
+#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
+#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
+#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
+#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
+#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
+#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
+#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
+#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
+#define PORTSCX_PORT_WIDTH (0x10000000)
+#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
+#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
+#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
+#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
+#define PORTSCX_LINE_STATUS_BIT_POS (10)
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF (0x00000000)
+#define PORTSCX_PIC_AMBER (0x00004000)
+#define PORTSCX_PIC_GREEN (0x00008000)
+#define PORTSCX_PIC_UNDEF (0x0000C000)
+#define PORTSCX_PIC_BIT_POS (14)
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE (0x00000000)
+#define PORTSCX_PTC_JSTATE (0x00010000)
+#define PORTSCX_PTC_KSTATE (0x00020000)
+#define PORTSCX_PTC_SEQNAK (0x00030000)
+#define PORTSCX_PTC_PACKET (0x00040000)
+#define PORTSCX_PTC_FORCE_EN (0x00050000)
+#define PORTSCX_PTC_BIT_POS (16)
+
+/* bit 27-26 are port speed */
+#define PORTSCX_PORT_SPEED_FULL (0x00000000)
+#define PORTSCX_PORT_SPEED_LOW (0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
+#define PORTSCX_SPEED_BIT_POS (26)
+
+/* OTGSC Register Bit Masks */
+#define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27)
+#define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19)
+#define OTGSC_B_SESSION_VALID (1 << 11)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW (0x10000000)
+#define PORTSCX_PTW_8BIT (0x00000000)
+#define PORTSCX_PTW_16BIT (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define PORTSCX_PTS_UTMI (0x00000000)
+#define PORTSCX_PTS_ULPI (0x80000000)
+#define PORTSCX_PTS_FSLS (0xC0000000)
+#define PORTSCX_PTS_BIT_POS (30)
+
+/* USB MODE Register Bit Masks */
+#define USB_MODE_CTRL_MODE_IDLE (0x00000000)
+#define USB_MODE_CTRL_MODE_DEVICE (0x00000002)
+#define USB_MODE_CTRL_MODE_HOST (0x00000003)
+#define USB_MODE_CTRL_MODE_MASK 0x00000003
+#define USB_MODE_CTRL_MODE_RSV (0x00000001)
+#define USB_MODE_ES 0x00000004 /* (big) Endian Sel */
+#define USB_MODE_SETUP_LOCK_OFF (0x00000008)
+#define USB_MODE_STREAM_DISABLE (0x00000010)
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET (0x00010000)
+#define EPFLUSH_RX_OFFSET (0x00000000)
+
+/* Endpoint Setup Status bit masks */
+#define EP_SETUP_STATUS_MASK (0x0000003F)
+#define EP_SETUP_STATUS_EP0 (0x00000001)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE (0x00800000)
+#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
+#define EPCTRL_TX_TYPE (0x000C0000)
+#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
+#define EPCTRL_TX_EP_STALL (0x00010000)
+#define EPCTRL_RX_ENABLE (0x00000080)
+#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
+#define EPCTRL_RX_TYPE (0x0000000C)
+#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
+#define EPCTRL_RX_EP_STALL (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_EP_TYPE_CONTROL (0)
+#define EPCTRL_EP_TYPE_ISO (1)
+#define EPCTRL_EP_TYPE_BULK (2)
+#define EPCTRL_EP_TYPE_INTERRUPT (3)
+#define EPCTRL_TX_EP_TYPE_SHIFT (18)
+#define EPCTRL_RX_EP_TYPE_SHIFT (2)
+
+/* SNOOPn Register Bit Masks */
+#define SNOOP_ADDRESS_MASK (0xFFFFF000)
+#define SNOOP_SIZE_ZERO (0x00) /* snooping disable */
+#define SNOOP_SIZE_4KB (0x0B) /* 4KB snoop size */
+#define SNOOP_SIZE_8KB (0x0C)
+#define SNOOP_SIZE_16KB (0x0D)
+#define SNOOP_SIZE_32KB (0x0E)
+#define SNOOP_SIZE_64KB (0x0F)
+#define SNOOP_SIZE_128KB (0x10)
+#define SNOOP_SIZE_256KB (0x11)
+#define SNOOP_SIZE_512KB (0x12)
+#define SNOOP_SIZE_1MB (0x13)
+#define SNOOP_SIZE_2MB (0x14)
+#define SNOOP_SIZE_4MB (0x15)
+#define SNOOP_SIZE_8MB (0x16)
+#define SNOOP_SIZE_16MB (0x17)
+#define SNOOP_SIZE_32MB (0x18)
+#define SNOOP_SIZE_64MB (0x19)
+#define SNOOP_SIZE_128MB (0x1A)
+#define SNOOP_SIZE_256MB (0x1B)
+#define SNOOP_SIZE_512MB (0x1C)
+#define SNOOP_SIZE_1GB (0x1D)
+#define SNOOP_SIZE_2GB (0x1E) /* 2GB snoop size */
+
+/* pri_ctrl Register Bit Masks */
+#define PRI_CTRL_PRI_LVL1 (0x0000000C)
+#define PRI_CTRL_PRI_LVL0 (0x00000003)
+
+/* si_ctrl Register Bit Masks */
+#define SI_CTRL_ERR_DISABLE (0x00000010)
+#define SI_CTRL_IDRC_DISABLE (0x00000008)
+#define SI_CTRL_RD_SAFE_EN (0x00000004)
+#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002)
+#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001)
+
+/* control Register Bit Masks */
+#define USB_CTRL_IOENB (0x00000004)
+#define USB_CTRL_ULPI_INT0EN (0x00000001)
+#define USB_CTRL_OTG_WUIR (0x80000000)
+#define USB_CTRL_OTG_WUIE (0x08000000)
+#define USB_CTRL_OTG_VWUE (0x00001000)
+#define USB_CTRL_OTG_IWUE (0x00100000)
+
+
+
+#define INTR_UE (1 << 0)
+#define INTR_UEE (1 << 1)
+#define INTR_PCE (1 << 2)
+#define INTR_SEE (1 << 4)
+#define INTR_URE (1 << 6)
+#define INTR_SRE (1 << 7)
+#define INTR_SLE (1 << 8)
+
+
+/* bits used in all the endpoint status registers */
+#define EPT_TX(n) (1 << ((n) + 16))
+#define EPT_RX(n) (1 << (n))
+
+
+#define CTRL_TXE (1 << 23)
+#define CTRL_TXR (1 << 22)
+#define CTRL_TXI (1 << 21)
+#define CTRL_TXD (1 << 17)
+#define CTRL_TXS (1 << 16)
+#define CTRL_RXE (1 << 7)
+#define CTRL_RXR (1 << 6)
+#define CTRL_RXI (1 << 5)
+#define CTRL_RXD (1 << 1)
+#define CTRL_RXS (1 << 0)
+
+#define CTRL_TXT_CTRL (0 << 18)
+#define CTRL_TXT_ISOCH (1 << 18)
+#define CTRL_TXT_BULK (2 << 18)
+#define CTRL_TXT_INT (3 << 18)
+
+#define CTRL_RXT_CTRL (0 << 2)
+#define CTRL_RXT_ISOCH (1 << 2)
+#define CTRL_RXT_BULK (2 << 2)
+#define CTRL_RXT_INT (3 << 2)
+
+#define USB_RECV 0
+#define USB_SEND 1
+#define USB_MAX_CTRL_PAYLOAD 64
+
+/* UDC device defines */
+#define EP0_MAX_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_OUT_ENDPOINT 0x02
+#define UDC_OUT_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_IN_ENDPOINT 0x03
+#define UDC_IN_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_INT_ENDPOINT 0x01
+#define UDC_INT_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+#define UDC_BULK_PACKET_SIZE USB_MAX_CTRL_PAYLOAD
+
+int udc_init(void);
+
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+
+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);
+int udc_endpoint_write(struct usb_endpoint_instance *epi);
+void udc_irq(void);
+void usb_shutdown(void);
+
+int is_usb_disconnected(void);
+
+#endif
diff --git a/include/usbdevice.h b/include/usbdevice.h
index 206dbbc..82acfb2 100644
--- a/include/usbdevice.h
+++ b/include/usbdevice.h
@@ -467,7 +467,9 @@ typedef struct urb_link {
* function driver to inform it that data has arrived.
*/
-#define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */
+/* in linux we'd malloc this, but in u-boot we prefer static data */
+#define URB_BUF_SIZE 256
+
struct urb {
struct usb_endpoint_instance *endpoint;