diff options
author | Sammy He <r62914@freescale.com> | 2010-11-17 00:39:08 +0800 |
---|---|---|
committer | Sammy He <r62914@freescale.com> | 2010-11-18 00:57:49 +0800 |
commit | 7496154e2fdc3efccd5d5b8acf160082f1b95c2d (patch) | |
tree | 0522cedde956e6c6d8aed4e1def5a9940eafb10e | |
parent | 5c13c889739565b7a0409048ef4ac3eaedf3ff09 (diff) | |
download | u-boot-imx-7496154e2fdc3efccd5d5b8acf160082f1b95c2d.zip u-boot-imx-7496154e2fdc3efccd5d5b8acf160082f1b95c2d.tar.gz u-boot-imx-7496154e2fdc3efccd5d5b8acf160082f1b95c2d.tar.bz2 |
ENGR00133551-1 Add freescale usb udc support for i.mx51 platform.
Add imx_udc for usb gadget on i.mx51 platform.
Signed-off-by: Hu Hui <b29976@freescale.com>
Signed-off-by: Sammy He <r62914@freescale.com>
-rw-r--r-- | cpu/arm_cortexa8/mx51/generic.c | 52 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/imx_udc.c | 940 | ||||
-rw-r--r-- | include/asm-arm/arch-mx51/mx51.h | 4 | ||||
-rw-r--r-- | include/usb/imx_udc.h | 420 | ||||
-rw-r--r-- | include/usbdevice.h | 4 |
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; |