From: Vipin KUMAR Date: Tue, 6 Mar 2012 23:39:37 +0000 (+0000) Subject: USB:gadget:designware USB device controller (UDC) implementation X-Git-Tag: v2012.04-rc1~42 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=2721551a11e64ac639547211dae027eea476af4c;p=u-boot USB:gadget:designware USB device controller (UDC) implementation The earlier usb device controller driver was specific to spear platforms. This patch implements the usb device controller driver as a generic controller which can be reused by other platforms using this peripheral. Signed-off-by: Vipin Kumar Signed-off-by: Amit Virdi Acked-by: Marek Vasut --- diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index e449cd717d..60347d7884 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h @@ -33,8 +33,8 @@ #include #elif defined(CONFIG_CPU_PXA27X) #include -#elif defined(CONFIG_SPEAR3XX) || defined(CONFIG_SPEAR600) -#include +#elif defined(CONFIG_DW_UDC) +#include #endif #include diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 64b091f4a1..87d1918cb9 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -39,11 +39,11 @@ else ifdef CONFIG_USB_DEVICE COBJS-y += core.o COBJS-y += ep0.o +COBJS-$(CONFIG_DW_UDC) += designware_udc.o COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o COBJS-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o -COBJS-$(CONFIG_SPEARUDC) += spr_udc.o endif endif diff --git a/drivers/usb/gadget/designware_udc.c b/drivers/usb/gadget/designware_udc.c new file mode 100644 index 0000000000..aee44aa064 --- /dev/null +++ b/drivers/usb/gadget/designware_udc.c @@ -0,0 +1,997 @@ +/* + * Based on drivers/usb/gadget/omap1510_udc.c + * TI OMAP1510 USB bus interface driver + * + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@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 +#include + +#include +#include "ep0.h" +#include +#include + +#define UDC_INIT_MDELAY 80 /* Device settle delay */ + +/* Some kind of debugging output... */ +#ifndef DEBUG_DWUSBTTY +#define UDCDBG(str) +#define UDCDBGA(fmt, args...) +#else +#define UDCDBG(str) serial_printf(str "\n") +#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) +#endif + +static struct urb *ep0_urb; +static struct usb_device_instance *udc_device; + +static struct plug_regs *const plug_regs_p = + (struct plug_regs * const)CONFIG_SYS_PLUG_BASE; +static struct udc_regs *const udc_regs_p = + (struct udc_regs * const)CONFIG_SYS_USBD_BASE; +static struct udc_endp_regs *const outep_regs_p = + &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0]; +static struct udc_endp_regs *const inep_regs_p = + &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0]; + +/* + * udc_state_transition - Write the next packet to TxFIFO. + * @initial: Initial state. + * @final: Final state. + * + * Helper function to implement device state changes. The device states and + * the events that transition between them are: + * + * STATE_ATTACHED + * || /\ + * \/ || + * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET + * || /\ + * \/ || + * STATE_POWERED + * || /\ + * \/ || + * DEVICE_RESET DEVICE_POWER_INTERRUPTION + * || /\ + * \/ || + * STATE_DEFAULT + * || /\ + * \/ || + * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET + * || /\ + * \/ || + * STATE_ADDRESSED + * || /\ + * \/ || + * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED + * || /\ + * \/ || + * STATE_CONFIGURED + * + * udc_state_transition transitions up (in the direction from STATE_ATTACHED + * to STATE_CONFIGURED) from the specified initial state to the specified final + * state, passing through each intermediate state on the way. If the initial + * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then + * no state transitions will take place. + * + * udc_state_transition also transitions down (in the direction from + * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the + * specified final state, passing through each intermediate state on the way. + * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final + * state, then no state transitions will take place. + * + * This function must only be called with interrupts disabled. + */ +static void udc_state_transition(usb_device_state_t initial, + usb_device_state_t final) +{ + if (initial < final) { + switch (initial) { + case STATE_ATTACHED: + usbd_device_event_irq(udc_device, + DEVICE_HUB_CONFIGURED, 0); + if (final == STATE_POWERED) + break; + case STATE_POWERED: + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + if (final == STATE_DEFAULT) + break; + case STATE_DEFAULT: + usbd_device_event_irq(udc_device, + DEVICE_ADDRESS_ASSIGNED, 0); + if (final == STATE_ADDRESSED) + break; + case STATE_ADDRESSED: + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); + case STATE_CONFIGURED: + break; + default: + break; + } + } else if (initial > final) { + switch (initial) { + case STATE_CONFIGURED: + usbd_device_event_irq(udc_device, + DEVICE_DE_CONFIGURED, 0); + if (final == STATE_ADDRESSED) + break; + case STATE_ADDRESSED: + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + if (final == STATE_DEFAULT) + break; + case STATE_DEFAULT: + usbd_device_event_irq(udc_device, + DEVICE_POWER_INTERRUPTION, 0); + if (final == STATE_POWERED) + break; + case STATE_POWERED: + usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); + case STATE_ATTACHED: + break; + default: + break; + } + } +} + +/* Stall endpoint */ +static void udc_stall_ep(u32 ep_num) +{ + writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, + &inep_regs_p[ep_num].endp_cntl); + + writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, + &outep_regs_p[ep_num].endp_cntl); +} + +static void *get_fifo(int ep_num, int in) +{ + u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE; + + switch (ep_num) { + case UDC_EP3: + fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn); + /* break intentionally left out */ + + case UDC_EP1: + fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn); + /* break intentionally left out */ + + case UDC_EP0: + default: + if (in) { + fifo_ptr += + readl(&outep_regs_p[2].endp_maxpacksize) >> 16; + /* break intentionally left out */ + } else { + break; + } + + case UDC_EP2: + fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16; + /* break intentionally left out */ + } + + return (void *)fifo_ptr; +} + +static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len) +{ + u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0); + u32 i, nw, nb; + u32 *wrdp; + u8 *bytp; + + if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY) + return -1; + + nw = len / sizeof(u32); + nb = len % sizeof(u32); + + wrdp = (u32 *)bufp; + for (i = 0; i < nw; i++) { + writel(readl(fifo_ptr), wrdp); + wrdp++; + } + + bytp = (u8 *)wrdp; + for (i = 0; i < nb; i++) { + writeb(readb(fifo_ptr), bytp); + fifo_ptr++; + bytp++; + } + readl(&outep_regs_p[epNum].write_done); + + return 0; +} + +static void usbputpcktofifo(int epNum, u8 *bufp, u32 len) +{ + u32 i, nw, nb; + u32 *wrdp; + u8 *bytp; + u8 *fifo_ptr = get_fifo(epNum, 1); + + nw = len / sizeof(int); + nb = len % sizeof(int); + wrdp = (u32 *)bufp; + for (i = 0; i < nw; i++) { + writel(*wrdp, fifo_ptr); + wrdp++; + } + + bytp = (u8 *)wrdp; + for (i = 0; i < nb; i++) { + writeb(*bytp, fifo_ptr); + fifo_ptr++; + bytp++; + } +} + +/* + * dw_write_noniso_tx_fifo - Write the next packet to TxFIFO. + * @endpoint: Endpoint pointer. + * + * If the endpoint has an active tx_urb, then the next packet of data from the + * URB is written to the tx FIFO. The total amount of data in the urb is given + * by urb->actual_length. The maximum amount of data that can be sent in any + * one packet is given by endpoint->tx_packetSize. The number of data bytes + * from this URB that have already been transmitted is given by endpoint->sent. + * endpoint->last is updated by this routine with the number of data bytes + * transmitted in this packet. + * + */ +static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance + *endpoint) +{ + struct urb *urb = endpoint->tx_urb; + int align; + + if (urb) { + u32 last; + + UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d", + urb->buffer, urb->buffer_length, urb->actual_length); + + last = MIN(urb->actual_length - endpoint->sent, + endpoint->tx_packetSize); + + if (last) { + u8 *cp = 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)cp % sizeof(int)); + if (align) + last = MIN(last, sizeof(int) - align); + + UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d", + endpoint->sent, endpoint->tx_packetSize, last); + + usbputpcktofifo(endpoint->endpoint_address & + USB_ENDPOINT_NUMBER_MASK, cp, last); + } + endpoint->last = last; + } +} + +/* + * Handle SETUP USB interrupt. + * This function implements TRM Figure 14-14. + */ +static void dw_udc_setup(struct usb_endpoint_instance *endpoint) +{ + u8 *datap = (u8 *)&ep0_urb->device_request; + int ep_addr = endpoint->endpoint_address; + + UDCDBG("-> Entering device setup"); + usbgetpckfromfifo(ep_addr, datap, 8); + + /* Try to process setup packet */ + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next EP0 transaction */ + udc_stall_ep(0); + UDCDBG("can't parse setup packet, still waiting for setup"); + return; + } + + /* Check direction */ + if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) + == USB_REQ_HOST2DEVICE) { + UDCDBG("control write on EP0"); + if (le16_to_cpu(ep0_urb->device_request.wLength)) { + /* Stall this request */ + UDCDBG("Stalling unsupported EP0 control write data " + "stage."); + udc_stall_ep(0); + } + } else { + + UDCDBG("control read on EP0"); + /* + * The ep0_recv_setup function has already placed our response + * packet data in ep0_urb->buffer and the packet length in + * ep0_urb->actual_length. + */ + endpoint->tx_urb = ep0_urb; + endpoint->sent = 0; + /* + * Write packet data to the FIFO. dw_write_noniso_tx_fifo + * will update endpoint->last with the number of bytes written + * to the FIFO. + */ + dw_write_noniso_tx_fifo(endpoint); + + writel(0x0, &inep_regs_p[ep_addr].write_done); + } + + udc_unset_nak(endpoint->endpoint_address); + + UDCDBG("<- Leaving device setup"); +} + +/* + * Handle endpoint 0 RX interrupt + */ +static void dw_udc_ep0_rx(struct usb_endpoint_instance *endpoint) +{ + u8 dummy[64]; + + UDCDBG("RX on EP0"); + + /* Check direction */ + if ((ep0_urb->device_request.bmRequestType + & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { + /* + * This rx interrupt must be for a control write data + * stage packet. + * + * We don't support control write data stages. + * We should never end up here. + */ + + UDCDBG("Stalling unexpected EP0 control write " + "data stage packet"); + udc_stall_ep(0); + } else { + /* + * This rx interrupt must be for a control read status + * stage packet. + */ + UDCDBG("ACK on EP0 control read status stage packet"); + u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff; + usbgetpckfromfifo(0, dummy, len); + } +} + +/* + * Handle endpoint 0 TX interrupt + */ +static void dw_udc_ep0_tx(struct usb_endpoint_instance *endpoint) +{ + struct usb_device_request *request = &ep0_urb->device_request; + int ep_addr; + + UDCDBG("TX on EP0"); + + /* Check direction */ + if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == + USB_REQ_HOST2DEVICE) { + /* + * This tx interrupt must be for a control write status + * stage packet. + */ + UDCDBG("ACK on EP0 control write status stage packet"); + } else { + /* + * This tx interrupt must be for a control read data + * stage packet. + */ + int wLength = le16_to_cpu(request->wLength); + + /* + * Update our count of bytes sent so far in this + * transfer. + */ + endpoint->sent += endpoint->last; + + /* + * We are finished with this transfer if we have sent + * all of the bytes in our tx urb (urb->actual_length) + * unless we need a zero-length terminating packet. We + * need a zero-length terminating packet if we returned + * fewer bytes than were requested (wLength) by the host, + * and the number of bytes we returned is an exact + * multiple of the packet size endpoint->tx_packetSize. + */ + if ((endpoint->sent == ep0_urb->actual_length) && + ((ep0_urb->actual_length == wLength) || + (endpoint->last != endpoint->tx_packetSize))) { + /* Done with control read data stage. */ + UDCDBG("control read data stage complete"); + } else { + /* + * We still have another packet of data to send + * in this control read data stage or else we + * need a zero-length terminating packet. + */ + UDCDBG("ACK control read data stage packet"); + dw_write_noniso_tx_fifo(endpoint); + + ep_addr = endpoint->endpoint_address; + writel(0x0, &inep_regs_p[ep_addr].write_done); + } + } +} + +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; +} + +/* + * Handle RX transaction on non-ISO endpoint. + * The ep argument is a physical endpoint number for a non-ISO IN endpoint + * in the range 1 to 15. + */ +static void dw_udc_epn_rx(int ep) +{ + int nbytes = 0; + struct urb *urb; + struct usb_endpoint_instance *endpoint = dw_find_ep(ep); + + if (endpoint) { + urb = endpoint->rcv_urb; + + if (urb) { + u8 *cp = urb->buffer + urb->actual_length; + + nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) & + 0xfff; + usbgetpckfromfifo(ep, cp, nbytes); + usbd_rcv_complete(endpoint, nbytes, 0); + } + } +} + +/* + * Handle TX transaction on non-ISO endpoint. + * The ep argument is a physical endpoint number for a non-ISO IN endpoint + * in the range 16 to 30. + */ +static void dw_udc_epn_tx(int ep) +{ + struct usb_endpoint_instance *endpoint = dw_find_ep(ep); + + /* + * 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 (endpoint && endpoint->tx_urb && endpoint->tx_urb->actual_length) { + if (endpoint->last == endpoint->tx_packetSize) { + /* handle zero length packet here */ + writel(0x0, &inep_regs_p[ep].write_done); + } + /* retire the data that was just sent */ + usbd_tx_complete(endpoint); + /* + * Check to see if we have more data ready to transmit + * now. + */ + if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { + /* write data to FIFO */ + dw_write_noniso_tx_fifo(endpoint); + writel(0x0, &inep_regs_p[ep].write_done); + + } else if (endpoint->tx_urb + && (endpoint->tx_urb->actual_length == 0)) { + /* udc_set_nak(ep); */ + } + } +} + +/* + * Start of public functions. + */ + +/* Called to start packet transmission. */ +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ + udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK); + return 0; +} + +/* Start to initialize h/w stuff */ +int udc_init(void) +{ + int i; + u32 plug_st; + + udc_device = NULL; + + UDCDBG("starting"); + + readl(&plug_regs_p->plug_pending); + + udc_disconnect(); + + for (i = 0; i < UDC_INIT_MDELAY; i++) + udelay(1000); + + plug_st = readl(&plug_regs_p->plug_state); + writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state); + + writel(~0x0, &udc_regs_p->endp_int); + writel(~0x0, &udc_regs_p->dev_int_mask); + writel(~0x0, &udc_regs_p->endp_int_mask); + + writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | + /* Dev_Conf_SYNCFRAME | */ + DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); + + writel(0x0, &udc_regs_p->dev_cntl); + + /* Clear all interrupts pending */ + writel(DEV_INT_MSK, &udc_regs_p->dev_int); + + return 0; +} + +/* + * udc_setup_ep - setup endpoint + * Associate a physical endpoint with endpoint_instance + */ +void udc_setup_ep(struct usb_device_instance *device, + u32 ep, struct usb_endpoint_instance *endpoint) +{ + UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address); + int ep_addr; + int ep_num, ep_type; + int packet_size; + int buffer_size; + int attributes; + char *tt; + u32 endp_intmask; + + tt = getenv("usbtty"); + if (!tt) + tt = "generic"; + + ep_addr = endpoint->endpoint_address; + ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* IN endpoint */ + packet_size = endpoint->tx_packetSize; + buffer_size = packet_size * 2; + attributes = endpoint->tx_attributes; + } else { + /* OUT endpoint */ + packet_size = endpoint->rcv_packetSize; + buffer_size = packet_size * 2; + attributes = endpoint->rcv_attributes; + } + + switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + ep_type = ENDP_EPTYPE_CNTL; + break; + case USB_ENDPOINT_XFER_BULK: + default: + ep_type = ENDP_EPTYPE_BULK; + break; + case USB_ENDPOINT_XFER_INT: + ep_type = ENDP_EPTYPE_INT; + break; + case USB_ENDPOINT_XFER_ISOC: + ep_type = ENDP_EPTYPE_ISO; + break; + } + + struct udc_endp_regs *out_p = &outep_regs_p[ep_num]; + struct udc_endp_regs *in_p = &inep_regs_p[ep_num]; + + if (!ep_addr) { + /* Setup endpoint 0 */ + buffer_size = packet_size; + + writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK, + &in_p->endp_cntl); + + writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK, + &out_p->endp_cntl); + + writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl); + + writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); + + writel(packet_size, &in_p->endp_maxpacksize); + + writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl); + + writel(packet_size | ((buffer_size / sizeof(int)) << 16), + &out_p->endp_maxpacksize); + + writel((packet_size << 19) | ENDP_EPTYPE_CNTL, + &udc_regs_p->udc_endp_reg[ep_num]); + + } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + /* Setup the IN endpoint */ + writel(0x0, &in_p->endp_status); + writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl); + writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); + writel(packet_size, &in_p->endp_maxpacksize); + + if (!strcmp(tt, "cdc_acm")) { + if (ep_type == ENDP_EPTYPE_INT) { + /* Conf no. 1 Interface no. 0 */ + writel((packet_size << 19) | + ENDP_EPDIR_IN | (1 << 7) | + (0 << 11) | (ep_type << 5) | ep_num, + &udc_regs_p->udc_endp_reg[ep_num]); + } else { + /* Conf no. 1 Interface no. 1 */ + writel((packet_size << 19) | + ENDP_EPDIR_IN | (1 << 7) | + (1 << 11) | (ep_type << 5) | ep_num, + &udc_regs_p->udc_endp_reg[ep_num]); + } + } else { + /* Conf no. 1 Interface no. 0 */ + writel((packet_size << 19) | + ENDP_EPDIR_IN | (1 << 7) | + (0 << 11) | (ep_type << 5) | ep_num, + &udc_regs_p->udc_endp_reg[ep_num]); + } + + } else { + /* Setup the OUT endpoint */ + writel(0x0, &out_p->endp_status); + writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl); + writel(packet_size | ((buffer_size / sizeof(int)) << 16), + &out_p->endp_maxpacksize); + + if (!strcmp(tt, "cdc_acm")) { + writel((packet_size << 19) | + ENDP_EPDIR_OUT | (1 << 7) | + (1 << 11) | (ep_type << 5) | ep_num, + &udc_regs_p->udc_endp_reg[ep_num]); + } else { + writel((packet_size << 19) | + ENDP_EPDIR_OUT | (1 << 7) | + (0 << 11) | (ep_type << 5) | ep_num, + &udc_regs_p->udc_endp_reg[ep_num]); + } + + } + + endp_intmask = readl(&udc_regs_p->endp_int_mask); + endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num); + writel(endp_intmask, &udc_regs_p->endp_int_mask); +} + +/* Turn on the USB connection by enabling the pullup resistor */ +void udc_connect(void) +{ + u32 plug_st; + + plug_st = readl(&plug_regs_p->plug_state); + plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); + writel(plug_st, &plug_regs_p->plug_state); +} + +/* Turn off the USB connection by disabling the pullup resistor */ +void udc_disconnect(void) +{ + u32 plug_st; + + plug_st = readl(&plug_regs_p->plug_state); + plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); + writel(plug_st, &plug_regs_p->plug_state); +} + +/* Switch on the UDC */ +void udc_enable(struct usb_device_instance *device) +{ + UDCDBGA("enable device %p, status %d", device, device->status); + + /* 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); + } else { + serial_printf("udc_enable: ep0_urb already allocated %p\n", + ep0_urb); + } + + writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); +} + +/** + * udc_startup - allow udc code to do any additional startup + */ +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); +} + +/* + * Plug detection interrupt handling + */ +void dw_udc_plug_irq(void) +{ + if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) { + /* + * USB cable attached + * Turn off PHY reset bit (PLUG detect). + * Switch PHY opmode to normal operation (PLUG detect). + */ + udc_connect(); + writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); + + UDCDBG("device attached and powered"); + udc_state_transition(udc_device->device_state, STATE_POWERED); + } else { + /* + * USB cable detached + * Reset the PHY and switch the mode. + */ + udc_disconnect(); + writel(~0x0, &udc_regs_p->dev_int_mask); + + UDCDBG("device detached or unpowered"); + udc_state_transition(udc_device->device_state, STATE_ATTACHED); + } +} + +/* + * Device interrupt handling + */ +void dw_udc_dev_irq(void) +{ + if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) { + writel(~0x0, &udc_regs_p->endp_int_mask); + + udc_connect(); + + writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH, + &inep_regs_p[0].endp_cntl); + + writel(DEV_INT_USBRESET, &udc_regs_p->dev_int); + + UDCDBG("device reset in progess"); + udc_state_transition(udc_device->device_state, STATE_DEFAULT); + } + + /* Device Enumeration completed */ + if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) { + writel(DEV_INT_ENUM, &udc_regs_p->dev_int); + + /* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */ + writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001, + &udc_regs_p->endp_int_mask); + + UDCDBG("default -> addressed"); + udc_state_transition(udc_device->device_state, STATE_ADDRESSED); + } + + /* The USB will be in SUSPEND in 3 ms */ + if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) { + writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int); + + UDCDBG("entering inactive state"); + /* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */ + } + + /* SetConfiguration command received */ + if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) { + writel(DEV_INT_SETCFG, &udc_regs_p->dev_int); + + UDCDBG("entering configured state"); + udc_state_transition(udc_device->device_state, + STATE_CONFIGURED); + } + + /* SetInterface command received */ + if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF) + writel(DEV_INT_SETINTF, &udc_regs_p->dev_int); + + /* USB Suspend detected on cable */ + if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) { + writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int); + + UDCDBG("entering suspended state"); + usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); + } + + /* USB Start-Of-Frame detected on cable */ + if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF) + writel(DEV_INT_SOF, &udc_regs_p->dev_int); +} + +/* + * Endpoint interrupt handling + */ +void dw_udc_endpoint_irq(void) +{ + while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) { + + writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int); + + if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK) + == ENDP_STATUS_OUT_SETUP) { + dw_udc_setup(udc_device->bus->endpoint_array + 0); + writel(ENDP_STATUS_OUT_SETUP, + &outep_regs_p[0].endp_status); + + } else if ((readl(&outep_regs_p[0].endp_status) & + ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { + dw_udc_ep0_rx(udc_device->bus->endpoint_array + 0); + writel(ENDP_STATUS_OUT_DATA, + &outep_regs_p[0].endp_status); + + } else if ((readl(&outep_regs_p[0].endp_status) & + ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { + /* NONE received */ + } + + writel(0x0, &outep_regs_p[0].endp_status); + } + + if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) { + dw_udc_ep0_tx(udc_device->bus->endpoint_array + 0); + + writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status); + writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int); + } + + while (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) { + u32 epnum = 0; + u32 ep_int = readl(&udc_regs_p->endp_int) & + ENDP_INT_NONISOOUT_MSK; + + ep_int >>= 16; + while (0x0 == (ep_int & 0x1)) { + ep_int >>= 1; + epnum++; + } + + writel((1 << 16) << epnum, &udc_regs_p->endp_int); + + if ((readl(&outep_regs_p[epnum].endp_status) & + ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { + + dw_udc_epn_rx(epnum); + writel(ENDP_STATUS_OUT_DATA, + &outep_regs_p[epnum].endp_status); + } else if ((readl(&outep_regs_p[epnum].endp_status) & + ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { + writel(0x0, &outep_regs_p[epnum].endp_status); + } + } + + if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) { + u32 epnum = 0; + u32 ep_int = readl(&udc_regs_p->endp_int) & + ENDP_INT_NONISOIN_MSK; + + while (0x0 == (ep_int & 0x1)) { + ep_int >>= 1; + epnum++; + } + + if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) { + writel(ENDP_STATUS_IN, + &outep_regs_p[epnum].endp_status); + dw_udc_epn_tx(epnum); + + writel(ENDP_STATUS_IN, + &outep_regs_p[epnum].endp_status); + } + + writel((1 << epnum), &udc_regs_p->endp_int); + } +} + +/* + * UDC interrupts + */ +void udc_irq(void) +{ + /* + * Loop while we have interrupts. + * If we don't do this, the input chain + * polling delay is likely to miss + * host requests. + */ + while (readl(&plug_regs_p->plug_pending)) + dw_udc_plug_irq(); + + while (readl(&udc_regs_p->dev_int)) + dw_udc_dev_irq(); + + if (readl(&udc_regs_p->endp_int)) + dw_udc_endpoint_irq(); +} + +/* Flow control */ +void udc_set_nak(int epid) +{ + writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, + &inep_regs_p[epid].endp_cntl); + + writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, + &outep_regs_p[epid].endp_cntl); +} + +void udc_unset_nak(int epid) +{ + u32 val; + + val = readl(&inep_regs_p[epid].endp_cntl); + val &= ~ENDP_CNTL_SNAK; + val |= ENDP_CNTL_CNAK; + writel(val, &inep_regs_p[epid].endp_cntl); + + val = readl(&outep_regs_p[epid].endp_cntl); + val &= ~ENDP_CNTL_SNAK; + val |= ENDP_CNTL_CNAK; + writel(val, &outep_regs_p[epid].endp_cntl); +} diff --git a/drivers/usb/gadget/spr_udc.c b/drivers/usb/gadget/spr_udc.c deleted file mode 100644 index f2b06d68e2..0000000000 --- a/drivers/usb/gadget/spr_udc.c +++ /dev/null @@ -1,998 +0,0 @@ -/* - * Based on drivers/usb/gadget/omap1510_udc.c - * TI OMAP1510 USB bus interface driver - * - * (C) Copyright 2009 - * Vipin Kumar, ST Micoelectronics, vipin.kumar@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 -#include - -#include -#include "ep0.h" -#include -#include -#include - -#define UDC_INIT_MDELAY 80 /* Device settle delay */ - -/* Some kind of debugging output... */ -#ifndef DEBUG_SPRUSBTTY -#define UDCDBG(str) -#define UDCDBGA(fmt, args...) -#else -#define UDCDBG(str) serial_printf(str "\n") -#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) -#endif - -static struct urb *ep0_urb; -static struct usb_device_instance *udc_device; - -static struct plug_regs *const plug_regs_p = - (struct plug_regs * const)CONFIG_SYS_PLUG_BASE; -static struct udc_regs *const udc_regs_p = - (struct udc_regs * const)CONFIG_SYS_USBD_BASE; -static struct udc_endp_regs *const outep_regs_p = - &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0]; -static struct udc_endp_regs *const inep_regs_p = - &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0]; - -/* - * udc_state_transition - Write the next packet to TxFIFO. - * @initial: Initial state. - * @final: Final state. - * - * Helper function to implement device state changes. The device states and - * the events that transition between them are: - * - * STATE_ATTACHED - * || /\ - * \/ || - * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET - * || /\ - * \/ || - * STATE_POWERED - * || /\ - * \/ || - * DEVICE_RESET DEVICE_POWER_INTERRUPTION - * || /\ - * \/ || - * STATE_DEFAULT - * || /\ - * \/ || - * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET - * || /\ - * \/ || - * STATE_ADDRESSED - * || /\ - * \/ || - * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED - * || /\ - * \/ || - * STATE_CONFIGURED - * - * udc_state_transition transitions up (in the direction from STATE_ATTACHED - * to STATE_CONFIGURED) from the specified initial state to the specified final - * state, passing through each intermediate state on the way. If the initial - * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then - * no state transitions will take place. - * - * udc_state_transition also transitions down (in the direction from - * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the - * specified final state, passing through each intermediate state on the way. - * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final - * state, then no state transitions will take place. - * - * This function must only be called with interrupts disabled. - */ -static void udc_state_transition(usb_device_state_t initial, - usb_device_state_t final) -{ - if (initial < final) { - switch (initial) { - case STATE_ATTACHED: - usbd_device_event_irq(udc_device, - DEVICE_HUB_CONFIGURED, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq(udc_device, - DEVICE_ADDRESS_ASSIGNED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); - case STATE_CONFIGURED: - break; - default: - break; - } - } else if (initial > final) { - switch (initial) { - case STATE_CONFIGURED: - usbd_device_event_irq(udc_device, - DEVICE_DE_CONFIGURED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq(udc_device, - DEVICE_POWER_INTERRUPTION, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); - case STATE_ATTACHED: - break; - default: - break; - } - } -} - -/* Stall endpoint */ -static void udc_stall_ep(u32 ep_num) -{ - writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, - &inep_regs_p[ep_num].endp_cntl); - - writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, - &outep_regs_p[ep_num].endp_cntl); -} - -static void *get_fifo(int ep_num, int in) -{ - u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE; - - switch (ep_num) { - case UDC_EP3: - fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn); - /* break intentionally left out */ - - case UDC_EP1: - fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn); - /* break intentionally left out */ - - case UDC_EP0: - default: - if (in) { - fifo_ptr += - readl(&outep_regs_p[2].endp_maxpacksize) >> 16; - /* break intentionally left out */ - } else { - break; - } - - case UDC_EP2: - fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16; - /* break intentionally left out */ - } - - return (void *)fifo_ptr; -} - -static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len) -{ - u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0); - u32 i, nw, nb; - u32 *wrdp; - u8 *bytp; - - if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY) - return -1; - - nw = len / sizeof(u32); - nb = len % sizeof(u32); - - wrdp = (u32 *)bufp; - for (i = 0; i < nw; i++) { - writel(readl(fifo_ptr), wrdp); - wrdp++; - } - - bytp = (u8 *)wrdp; - for (i = 0; i < nb; i++) { - writeb(readb(fifo_ptr), bytp); - fifo_ptr++; - bytp++; - } - readl(&outep_regs_p[epNum].write_done); - - return 0; -} - -static void usbputpcktofifo(int epNum, u8 *bufp, u32 len) -{ - u32 i, nw, nb; - u32 *wrdp; - u8 *bytp; - u8 *fifo_ptr = get_fifo(epNum, 1); - - nw = len / sizeof(int); - nb = len % sizeof(int); - wrdp = (u32 *)bufp; - for (i = 0; i < nw; i++) { - writel(*wrdp, fifo_ptr); - wrdp++; - } - - bytp = (u8 *)wrdp; - for (i = 0; i < nb; i++) { - writeb(*bytp, fifo_ptr); - fifo_ptr++; - bytp++; - } -} - -/* - * spear_write_noniso_tx_fifo - Write the next packet to TxFIFO. - * @endpoint: Endpoint pointer. - * - * If the endpoint has an active tx_urb, then the next packet of data from the - * URB is written to the tx FIFO. The total amount of data in the urb is given - * by urb->actual_length. The maximum amount of data that can be sent in any - * one packet is given by endpoint->tx_packetSize. The number of data bytes - * from this URB that have already been transmitted is given by endpoint->sent. - * endpoint->last is updated by this routine with the number of data bytes - * transmitted in this packet. - * - */ -static void spear_write_noniso_tx_fifo(struct usb_endpoint_instance - *endpoint) -{ - struct urb *urb = endpoint->tx_urb; - int align; - - if (urb) { - u32 last; - - UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d", - urb->buffer, urb->buffer_length, urb->actual_length); - - last = MIN(urb->actual_length - endpoint->sent, - endpoint->tx_packetSize); - - if (last) { - u8 *cp = 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)cp % sizeof(int)); - if (align) - last = MIN(last, sizeof(int) - align); - - UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d", - endpoint->sent, endpoint->tx_packetSize, last); - - usbputpcktofifo(endpoint->endpoint_address & - USB_ENDPOINT_NUMBER_MASK, cp, last); - } - endpoint->last = last; - } -} - -/* - * Handle SETUP USB interrupt. - * This function implements TRM Figure 14-14. - */ -static void spear_udc_setup(struct usb_endpoint_instance *endpoint) -{ - u8 *datap = (u8 *)&ep0_urb->device_request; - int ep_addr = endpoint->endpoint_address; - - UDCDBG("-> Entering device setup"); - usbgetpckfromfifo(ep_addr, datap, 8); - - /* Try to process setup packet */ - if (ep0_recv_setup(ep0_urb)) { - /* Not a setup packet, stall next EP0 transaction */ - udc_stall_ep(0); - UDCDBG("can't parse setup packet, still waiting for setup"); - return; - } - - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) - == USB_REQ_HOST2DEVICE) { - UDCDBG("control write on EP0"); - if (le16_to_cpu(ep0_urb->device_request.wLength)) { - /* Stall this request */ - UDCDBG("Stalling unsupported EP0 control write data " - "stage."); - udc_stall_ep(0); - } - } else { - - UDCDBG("control read on EP0"); - /* - * The ep0_recv_setup function has already placed our response - * packet data in ep0_urb->buffer and the packet length in - * ep0_urb->actual_length. - */ - endpoint->tx_urb = ep0_urb; - endpoint->sent = 0; - /* - * Write packet data to the FIFO. spear_write_noniso_tx_fifo - * will update endpoint->last with the number of bytes written - * to the FIFO. - */ - spear_write_noniso_tx_fifo(endpoint); - - writel(0x0, &inep_regs_p[ep_addr].write_done); - } - - udc_unset_nak(endpoint->endpoint_address); - - UDCDBG("<- Leaving device setup"); -} - -/* - * Handle endpoint 0 RX interrupt - */ -static void spear_udc_ep0_rx(struct usb_endpoint_instance *endpoint) -{ - u8 dummy[64]; - - UDCDBG("RX on EP0"); - - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType - & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { - /* - * This rx interrupt must be for a control write data - * stage packet. - * - * We don't support control write data stages. - * We should never end up here. - */ - - UDCDBG("Stalling unexpected EP0 control write " - "data stage packet"); - udc_stall_ep(0); - } else { - /* - * This rx interrupt must be for a control read status - * stage packet. - */ - UDCDBG("ACK on EP0 control read status stage packet"); - u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff; - usbgetpckfromfifo(0, dummy, len); - } -} - -/* - * Handle endpoint 0 TX interrupt - */ -static void spear_udc_ep0_tx(struct usb_endpoint_instance *endpoint) -{ - struct usb_device_request *request = &ep0_urb->device_request; - int ep_addr; - - UDCDBG("TX on EP0"); - - /* Check direction */ - if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == - USB_REQ_HOST2DEVICE) { - /* - * This tx interrupt must be for a control write status - * stage packet. - */ - UDCDBG("ACK on EP0 control write status stage packet"); - } else { - /* - * This tx interrupt must be for a control read data - * stage packet. - */ - int wLength = le16_to_cpu(request->wLength); - - /* - * Update our count of bytes sent so far in this - * transfer. - */ - endpoint->sent += endpoint->last; - - /* - * We are finished with this transfer if we have sent - * all of the bytes in our tx urb (urb->actual_length) - * unless we need a zero-length terminating packet. We - * need a zero-length terminating packet if we returned - * fewer bytes than were requested (wLength) by the host, - * and the number of bytes we returned is an exact - * multiple of the packet size endpoint->tx_packetSize. - */ - if ((endpoint->sent == ep0_urb->actual_length) && - ((ep0_urb->actual_length == wLength) || - (endpoint->last != endpoint->tx_packetSize))) { - /* Done with control read data stage. */ - UDCDBG("control read data stage complete"); - } else { - /* - * We still have another packet of data to send - * in this control read data stage or else we - * need a zero-length terminating packet. - */ - UDCDBG("ACK control read data stage packet"); - spear_write_noniso_tx_fifo(endpoint); - - ep_addr = endpoint->endpoint_address; - writel(0x0, &inep_regs_p[ep_addr].write_done); - } - } -} - -static struct usb_endpoint_instance *spear_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; -} - -/* - * Handle RX transaction on non-ISO endpoint. - * The ep argument is a physical endpoint number for a non-ISO IN endpoint - * in the range 1 to 15. - */ -static void spear_udc_epn_rx(int ep) -{ - int nbytes = 0; - struct urb *urb; - struct usb_endpoint_instance *endpoint = spear_find_ep(ep); - - if (endpoint) { - urb = endpoint->rcv_urb; - - if (urb) { - u8 *cp = urb->buffer + urb->actual_length; - - nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) & - 0xfff; - usbgetpckfromfifo(ep, cp, nbytes); - usbd_rcv_complete(endpoint, nbytes, 0); - } - } -} - -/* - * Handle TX transaction on non-ISO endpoint. - * The ep argument is a physical endpoint number for a non-ISO IN endpoint - * in the range 16 to 30. - */ -static void spear_udc_epn_tx(int ep) -{ - struct usb_endpoint_instance *endpoint = spear_find_ep(ep); - - /* - * 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 (endpoint && endpoint->tx_urb && endpoint->tx_urb->actual_length) { - if (endpoint->last == endpoint->tx_packetSize) { - /* handle zero length packet here */ - writel(0x0, &inep_regs_p[ep].write_done); - } - /* retire the data that was just sent */ - usbd_tx_complete(endpoint); - /* - * Check to see if we have more data ready to transmit - * now. - */ - if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { - /* write data to FIFO */ - spear_write_noniso_tx_fifo(endpoint); - writel(0x0, &inep_regs_p[ep].write_done); - - } else if (endpoint->tx_urb - && (endpoint->tx_urb->actual_length == 0)) { - /* udc_set_nak(ep); */ - } - } -} - -/* - * Start of public functions. - */ - -/* Called to start packet transmission. */ -int udc_endpoint_write(struct usb_endpoint_instance *endpoint) -{ - udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK); - return 0; -} - -/* Start to initialize h/w stuff */ -int udc_init(void) -{ - int i; - u32 plug_st; - - udc_device = NULL; - - UDCDBG("starting"); - - readl(&plug_regs_p->plug_pending); - - udc_disconnect(); - - for (i = 0; i < UDC_INIT_MDELAY; i++) - udelay(1000); - - plug_st = readl(&plug_regs_p->plug_state); - writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state); - - writel(~0x0, &udc_regs_p->endp_int); - writel(~0x0, &udc_regs_p->dev_int_mask); - writel(~0x0, &udc_regs_p->endp_int_mask); - - writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | - /* Dev_Conf_SYNCFRAME | */ - DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); - - writel(0x0, &udc_regs_p->dev_cntl); - - /* Clear all interrupts pending */ - writel(DEV_INT_MSK, &udc_regs_p->dev_int); - - return 0; -} - -/* - * udc_setup_ep - setup endpoint - * Associate a physical endpoint with endpoint_instance - */ -void udc_setup_ep(struct usb_device_instance *device, - u32 ep, struct usb_endpoint_instance *endpoint) -{ - UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address); - int ep_addr; - int ep_num, ep_type; - int packet_size; - int buffer_size; - int attributes; - char *tt; - u32 endp_intmask; - - tt = getenv("usbtty"); - if (!tt) - tt = "generic"; - - ep_addr = endpoint->endpoint_address; - ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - - if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* IN endpoint */ - packet_size = endpoint->tx_packetSize; - buffer_size = packet_size * 2; - attributes = endpoint->tx_attributes; - } else { - /* OUT endpoint */ - packet_size = endpoint->rcv_packetSize; - buffer_size = packet_size * 2; - attributes = endpoint->rcv_attributes; - } - - switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_CONTROL: - ep_type = ENDP_EPTYPE_CNTL; - break; - case USB_ENDPOINT_XFER_BULK: - default: - ep_type = ENDP_EPTYPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep_type = ENDP_EPTYPE_INT; - break; - case USB_ENDPOINT_XFER_ISOC: - ep_type = ENDP_EPTYPE_ISO; - break; - } - - struct udc_endp_regs *out_p = &outep_regs_p[ep_num]; - struct udc_endp_regs *in_p = &inep_regs_p[ep_num]; - - if (!ep_addr) { - /* Setup endpoint 0 */ - buffer_size = packet_size; - - writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK, - &in_p->endp_cntl); - - writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK, - &out_p->endp_cntl); - - writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl); - - writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); - - writel(packet_size, &in_p->endp_maxpacksize); - - writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl); - - writel(packet_size | ((buffer_size / sizeof(int)) << 16), - &out_p->endp_maxpacksize); - - writel((packet_size << 19) | ENDP_EPTYPE_CNTL, - &udc_regs_p->udc_endp_reg[ep_num]); - - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* Setup the IN endpoint */ - writel(0x0, &in_p->endp_status); - writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl); - writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); - writel(packet_size, &in_p->endp_maxpacksize); - - if (!strcmp(tt, "cdc_acm")) { - if (ep_type == ENDP_EPTYPE_INT) { - /* Conf no. 1 Interface no. 0 */ - writel((packet_size << 19) | - ENDP_EPDIR_IN | (1 << 7) | - (0 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } else { - /* Conf no. 1 Interface no. 1 */ - writel((packet_size << 19) | - ENDP_EPDIR_IN | (1 << 7) | - (1 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } - } else { - /* Conf no. 1 Interface no. 0 */ - writel((packet_size << 19) | - ENDP_EPDIR_IN | (1 << 7) | - (0 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } - - } else { - /* Setup the OUT endpoint */ - writel(0x0, &out_p->endp_status); - writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl); - writel(packet_size | ((buffer_size / sizeof(int)) << 16), - &out_p->endp_maxpacksize); - - if (!strcmp(tt, "cdc_acm")) { - writel((packet_size << 19) | - ENDP_EPDIR_OUT | (1 << 7) | - (1 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } else { - writel((packet_size << 19) | - ENDP_EPDIR_OUT | (1 << 7) | - (0 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } - - } - - endp_intmask = readl(&udc_regs_p->endp_int_mask); - endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num); - writel(endp_intmask, &udc_regs_p->endp_int_mask); -} - -/* Turn on the USB connection by enabling the pullup resistor */ -void udc_connect(void) -{ - u32 plug_st; - - plug_st = readl(&plug_regs_p->plug_state); - plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); - writel(plug_st, &plug_regs_p->plug_state); -} - -/* Turn off the USB connection by disabling the pullup resistor */ -void udc_disconnect(void) -{ - u32 plug_st; - - plug_st = readl(&plug_regs_p->plug_state); - plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); - writel(plug_st, &plug_regs_p->plug_state); -} - -/* Switch on the UDC */ -void udc_enable(struct usb_device_instance *device) -{ - UDCDBGA("enable device %p, status %d", device, device->status); - - /* 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); - } else { - serial_printf("udc_enable: ep0_urb already allocated %p\n", - ep0_urb); - } - - writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); -} - -/** - * udc_startup - allow udc code to do any additional startup - */ -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 SPEAr 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); -} - -/* - * Plug detection interrupt handling - */ -void spear_udc_plug_irq(void) -{ - if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) { - /* - * USB cable attached - * Turn off PHY reset bit (PLUG detect). - * Switch PHY opmode to normal operation (PLUG detect). - */ - udc_connect(); - writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); - - UDCDBG("device attached and powered"); - udc_state_transition(udc_device->device_state, STATE_POWERED); - } else { - /* - * USB cable detached - * Reset the PHY and switch the mode. - */ - udc_disconnect(); - writel(~0x0, &udc_regs_p->dev_int_mask); - - UDCDBG("device detached or unpowered"); - udc_state_transition(udc_device->device_state, STATE_ATTACHED); - } -} - -/* - * Device interrupt handling - */ -void spear_udc_dev_irq(void) -{ - if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) { - writel(~0x0, &udc_regs_p->endp_int_mask); - - udc_connect(); - - writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH, - &inep_regs_p[0].endp_cntl); - - writel(DEV_INT_USBRESET, &udc_regs_p->dev_int); - - UDCDBG("device reset in progess"); - udc_state_transition(udc_device->device_state, STATE_DEFAULT); - } - - /* Device Enumeration completed */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) { - writel(DEV_INT_ENUM, &udc_regs_p->dev_int); - - /* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */ - writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001, - &udc_regs_p->endp_int_mask); - - UDCDBG("default -> addressed"); - udc_state_transition(udc_device->device_state, STATE_ADDRESSED); - } - - /* The USB will be in SUSPEND in 3 ms */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) { - writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int); - - UDCDBG("entering inactive state"); - /* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */ - } - - /* SetConfiguration command received */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) { - writel(DEV_INT_SETCFG, &udc_regs_p->dev_int); - - UDCDBG("entering configured state"); - udc_state_transition(udc_device->device_state, - STATE_CONFIGURED); - } - - /* SetInterface command received */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF) - writel(DEV_INT_SETINTF, &udc_regs_p->dev_int); - - /* USB Suspend detected on cable */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) { - writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int); - - UDCDBG("entering suspended state"); - usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); - } - - /* USB Start-Of-Frame detected on cable */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF) - writel(DEV_INT_SOF, &udc_regs_p->dev_int); -} - -/* - * Endpoint interrupt handling - */ -void spear_udc_endpoint_irq(void) -{ - while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) { - - writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int); - - if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK) - == ENDP_STATUS_OUT_SETUP) { - spear_udc_setup(udc_device->bus->endpoint_array + 0); - writel(ENDP_STATUS_OUT_SETUP, - &outep_regs_p[0].endp_status); - - } else if ((readl(&outep_regs_p[0].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { - spear_udc_ep0_rx(udc_device->bus->endpoint_array + 0); - writel(ENDP_STATUS_OUT_DATA, - &outep_regs_p[0].endp_status); - - } else if ((readl(&outep_regs_p[0].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { - /* NONE received */ - } - - writel(0x0, &outep_regs_p[0].endp_status); - } - - if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) { - spear_udc_ep0_tx(udc_device->bus->endpoint_array + 0); - - writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status); - writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int); - } - - while (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) { - u32 epnum = 0; - u32 ep_int = readl(&udc_regs_p->endp_int) & - ENDP_INT_NONISOOUT_MSK; - - ep_int >>= 16; - while (0x0 == (ep_int & 0x1)) { - ep_int >>= 1; - epnum++; - } - - writel((1 << 16) << epnum, &udc_regs_p->endp_int); - - if ((readl(&outep_regs_p[epnum].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { - - spear_udc_epn_rx(epnum); - writel(ENDP_STATUS_OUT_DATA, - &outep_regs_p[epnum].endp_status); - } else if ((readl(&outep_regs_p[epnum].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { - writel(0x0, &outep_regs_p[epnum].endp_status); - } - } - - if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) { - u32 epnum = 0; - u32 ep_int = readl(&udc_regs_p->endp_int) & - ENDP_INT_NONISOIN_MSK; - - while (0x0 == (ep_int & 0x1)) { - ep_int >>= 1; - epnum++; - } - - if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) { - writel(ENDP_STATUS_IN, - &outep_regs_p[epnum].endp_status); - spear_udc_epn_tx(epnum); - - writel(ENDP_STATUS_IN, - &outep_regs_p[epnum].endp_status); - } - - writel((1 << epnum), &udc_regs_p->endp_int); - } -} - -/* - * UDC interrupts - */ -void udc_irq(void) -{ - /* - * Loop while we have interrupts. - * If we don't do this, the input chain - * polling delay is likely to miss - * host requests. - */ - while (readl(&plug_regs_p->plug_pending)) - spear_udc_plug_irq(); - - while (readl(&udc_regs_p->dev_int)) - spear_udc_dev_irq(); - - if (readl(&udc_regs_p->endp_int)) - spear_udc_endpoint_irq(); -} - -/* Flow control */ -void udc_set_nak(int epid) -{ - writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, - &inep_regs_p[epid].endp_cntl); - - writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, - &outep_regs_p[epid].endp_cntl); -} - -void udc_unset_nak(int epid) -{ - u32 val; - - val = readl(&inep_regs_p[epid].endp_cntl); - val &= ~ENDP_CNTL_SNAK; - val |= ENDP_CNTL_CNAK; - writel(val, &inep_regs_p[epid].endp_cntl); - - val = readl(&outep_regs_p[epid].endp_cntl); - val &= ~ENDP_CNTL_SNAK; - val |= ENDP_CNTL_CNAK; - writel(val, &outep_regs_p[epid].endp_cntl); -} diff --git a/include/configs/spear-common.h b/include/configs/spear-common.h index 55d19b5ce3..5fef8cce80 100644 --- a/include/configs/spear-common.h +++ b/include/configs/spear-common.h @@ -28,14 +28,16 @@ */ /* USBD driver configuration */ -#define CONFIG_SPEARUDC +#define CONFIG_DW_UDC #define CONFIG_USB_DEVICE #define CONFIG_USB_TTY #define CONFIG_USBD_PRODUCT_NAME "SPEAr SoC" #define CONFIG_USBD_MANUFACTURER "ST Microelectronics" +#if defined(CONFIG_USB_TTY) #define CONFIG_EXTRA_ENV_USBTTY "usbtty=cdc_acm\0" +#endif /* I2C driver configuration */ #define CONFIG_HARD_I2C diff --git a/include/usb/designware_udc.h b/include/usb/designware_udc.h new file mode 100644 index 0000000000..ae98e8c2c2 --- /dev/null +++ b/include/usb/designware_udc.h @@ -0,0 +1,230 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@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_UDC_H +#define __DW_UDC_H + +/* + * Defines for USBD + * + * The udc_ahb controller has three AHB slaves: + * + * 1. THe UDC registers + * 2. The plug detect + * 3. The RX/TX FIFO + */ + +#define MAX_ENDPOINTS 16 + +struct udc_endp_regs { + u32 endp_cntl; + u32 endp_status; + u32 endp_bsorfn; + u32 endp_maxpacksize; + u32 reserved_1; + u32 endp_desc_point; + u32 reserved_2; + u32 write_done; +}; + +/* Endpoint Control Register definitions */ + +#define ENDP_CNTL_STALL 0x00000001 +#define ENDP_CNTL_FLUSH 0x00000002 +#define ENDP_CNTL_SNOOP 0x00000004 +#define ENDP_CNTL_POLL 0x00000008 +#define ENDP_CNTL_CONTROL 0x00000000 +#define ENDP_CNTL_ISO 0x00000010 +#define ENDP_CNTL_BULK 0x00000020 +#define ENDP_CNTL_INT 0x00000030 +#define ENDP_CNTL_NAK 0x00000040 +#define ENDP_CNTL_SNAK 0x00000080 +#define ENDP_CNTL_CNAK 0x00000100 +#define ENDP_CNTL_RRDY 0x00000200 + +/* Endpoint Satus Register definitions */ + +#define ENDP_STATUS_PIDMSK 0x0000000f +#define ENDP_STATUS_OUTMSK 0x00000030 +#define ENDP_STATUS_OUT_NONE 0x00000000 +#define ENDP_STATUS_OUT_DATA 0x00000010 +#define ENDP_STATUS_OUT_SETUP 0x00000020 +#define ENDP_STATUS_IN 0x00000040 +#define ENDP_STATUS_BUFFNAV 0x00000080 +#define ENDP_STATUS_FATERR 0x00000100 +#define ENDP_STATUS_HOSTBUSERR 0x00000200 +#define ENDP_STATUS_TDC 0x00000400 +#define ENDP_STATUS_RXPKTMSK 0x003ff800 + +struct udc_regs { + struct udc_endp_regs in_regs[MAX_ENDPOINTS]; + struct udc_endp_regs out_regs[MAX_ENDPOINTS]; + u32 dev_conf; + u32 dev_cntl; + u32 dev_stat; + u32 dev_int; + u32 dev_int_mask; + u32 endp_int; + u32 endp_int_mask; + u32 reserved_3[0x39]; + u32 reserved_4; /* offset 0x500 */ + u32 udc_endp_reg[MAX_ENDPOINTS]; +}; + +/* Device Configuration Register definitions */ + +#define DEV_CONF_HS_SPEED 0x00000000 +#define DEV_CONF_LS_SPEED 0x00000002 +#define DEV_CONF_FS_SPEED 0x00000003 +#define DEV_CONF_REMWAKEUP 0x00000004 +#define DEV_CONF_SELFPOW 0x00000008 +#define DEV_CONF_SYNCFRAME 0x00000010 +#define DEV_CONF_PHYINT_8 0x00000020 +#define DEV_CONF_PHYINT_16 0x00000000 +#define DEV_CONF_UTMI_BIDIR 0x00000040 +#define DEV_CONF_STATUS_STALL 0x00000080 + +/* Device Control Register definitions */ + +#define DEV_CNTL_RESUME 0x00000001 +#define DEV_CNTL_TFFLUSH 0x00000002 +#define DEV_CNTL_RXDMAEN 0x00000004 +#define DEV_CNTL_TXDMAEN 0x00000008 +#define DEV_CNTL_DESCRUPD 0x00000010 +#define DEV_CNTL_BIGEND 0x00000020 +#define DEV_CNTL_BUFFILL 0x00000040 +#define DEV_CNTL_TSHLDEN 0x00000080 +#define DEV_CNTL_BURSTEN 0x00000100 +#define DEV_CNTL_DMAMODE 0x00000200 +#define DEV_CNTL_SOFTDISCONNECT 0x00000400 +#define DEV_CNTL_SCALEDOWN 0x00000800 +#define DEV_CNTL_BURSTLENU 0x00010000 +#define DEV_CNTL_BURSTLENMSK 0x00ff0000 +#define DEV_CNTL_TSHLDLENU 0x01000000 +#define DEV_CNTL_TSHLDLENMSK 0xff000000 + +/* Device Status Register definitions */ + +#define DEV_STAT_CFG 0x0000000f +#define DEV_STAT_INTF 0x000000f0 +#define DEV_STAT_ALT 0x00000f00 +#define DEV_STAT_SUSP 0x00001000 +#define DEV_STAT_ENUM 0x00006000 +#define DEV_STAT_ENUM_SPEED_HS 0x00000000 +#define DEV_STAT_ENUM_SPEED_FS 0x00002000 +#define DEV_STAT_ENUM_SPEED_LS 0x00004000 +#define DEV_STAT_RXFIFO_EMPTY 0x00008000 +#define DEV_STAT_PHY_ERR 0x00010000 +#define DEV_STAT_TS 0xf0000000 + +/* Device Interrupt Register definitions */ + +#define DEV_INT_MSK 0x0000007f +#define DEV_INT_SETCFG 0x00000001 +#define DEV_INT_SETINTF 0x00000002 +#define DEV_INT_INACTIVE 0x00000004 +#define DEV_INT_USBRESET 0x00000008 +#define DEV_INT_SUSPUSB 0x00000010 +#define DEV_INT_SOF 0x00000020 +#define DEV_INT_ENUM 0x00000040 + +/* Endpoint Interrupt Register definitions */ + +#define ENDP0_INT_CTRLIN 0x00000001 +#define ENDP1_INT_BULKIN 0x00000002 +#define ENDP_INT_NONISOIN_MSK 0x0000AAAA +#define ENDP2_INT_BULKIN 0x00000004 +#define ENDP0_INT_CTRLOUT 0x00010000 +#define ENDP1_INT_BULKOUT 0x00020000 +#define ENDP2_INT_BULKOUT 0x00040000 +#define ENDP_INT_NONISOOUT_MSK 0x55540000 + +/* Endpoint Register definitions */ +#define ENDP_EPDIR_OUT 0x00000000 +#define ENDP_EPDIR_IN 0x00000010 +#define ENDP_EPTYPE_CNTL 0x0 +#define ENDP_EPTYPE_ISO 0x1 +#define ENDP_EPTYPE_BULK 0x2 +#define ENDP_EPTYPE_INT 0x3 + +/* + * Defines for Plug Detect + */ + +struct plug_regs { + u32 plug_state; + u32 plug_pending; +}; + +/* Plug State Register definitions */ +#define PLUG_STATUS_EN 0x1 +#define PLUG_STATUS_ATTACHED 0x2 +#define PLUG_STATUS_PHY_RESET 0x4 +#define PLUG_STATUS_PHY_MODE 0x8 + +/* + * Defines for UDC FIFO (Slave Mode) + */ +struct udcfifo_regs { + u32 *fifo_p; +}; + +/* + * 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 64 +#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 + +/* + * Function declarations + */ + +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_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); + +#endif /* __DW_UDC_H */ diff --git a/include/usb/spr_udc.h b/include/usb/spr_udc.h deleted file mode 100644 index 2c332d5999..0000000000 --- a/include/usb/spr_udc.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * (C) Copyright 2009 - * Vipin Kumar, ST Micoelectronics, vipin.kumar@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 __SPR_UDC_H -#define __SPR_UDC_H - -/* - * Defines for USBD - * - * The udc_ahb controller has three AHB slaves: - * - * 1. THe UDC registers - * 2. The plug detect - * 3. The RX/TX FIFO - */ - -#define MAX_ENDPOINTS 16 - -struct udc_endp_regs { - u32 endp_cntl; - u32 endp_status; - u32 endp_bsorfn; - u32 endp_maxpacksize; - u32 reserved_1; - u32 endp_desc_point; - u32 reserved_2; - u32 write_done; -}; - -/* Endpoint Control Register definitions */ - -#define ENDP_CNTL_STALL 0x00000001 -#define ENDP_CNTL_FLUSH 0x00000002 -#define ENDP_CNTL_SNOOP 0x00000004 -#define ENDP_CNTL_POLL 0x00000008 -#define ENDP_CNTL_CONTROL 0x00000000 -#define ENDP_CNTL_ISO 0x00000010 -#define ENDP_CNTL_BULK 0x00000020 -#define ENDP_CNTL_INT 0x00000030 -#define ENDP_CNTL_NAK 0x00000040 -#define ENDP_CNTL_SNAK 0x00000080 -#define ENDP_CNTL_CNAK 0x00000100 -#define ENDP_CNTL_RRDY 0x00000200 - -/* Endpoint Satus Register definitions */ - -#define ENDP_STATUS_PIDMSK 0x0000000f -#define ENDP_STATUS_OUTMSK 0x00000030 -#define ENDP_STATUS_OUT_NONE 0x00000000 -#define ENDP_STATUS_OUT_DATA 0x00000010 -#define ENDP_STATUS_OUT_SETUP 0x00000020 -#define ENDP_STATUS_IN 0x00000040 -#define ENDP_STATUS_BUFFNAV 0x00000080 -#define ENDP_STATUS_FATERR 0x00000100 -#define ENDP_STATUS_HOSTBUSERR 0x00000200 -#define ENDP_STATUS_TDC 0x00000400 -#define ENDP_STATUS_RXPKTMSK 0x003ff800 - -struct udc_regs { - struct udc_endp_regs in_regs[MAX_ENDPOINTS]; - struct udc_endp_regs out_regs[MAX_ENDPOINTS]; - u32 dev_conf; - u32 dev_cntl; - u32 dev_stat; - u32 dev_int; - u32 dev_int_mask; - u32 endp_int; - u32 endp_int_mask; - u32 reserved_3[0x39]; - u32 reserved_4; /* offset 0x500 */ - u32 udc_endp_reg[MAX_ENDPOINTS]; -}; - -/* Device Configuration Register definitions */ - -#define DEV_CONF_HS_SPEED 0x00000000 -#define DEV_CONF_LS_SPEED 0x00000002 -#define DEV_CONF_FS_SPEED 0x00000003 -#define DEV_CONF_REMWAKEUP 0x00000004 -#define DEV_CONF_SELFPOW 0x00000008 -#define DEV_CONF_SYNCFRAME 0x00000010 -#define DEV_CONF_PHYINT_8 0x00000020 -#define DEV_CONF_PHYINT_16 0x00000000 -#define DEV_CONF_UTMI_BIDIR 0x00000040 -#define DEV_CONF_STATUS_STALL 0x00000080 - -/* Device Control Register definitions */ - -#define DEV_CNTL_RESUME 0x00000001 -#define DEV_CNTL_TFFLUSH 0x00000002 -#define DEV_CNTL_RXDMAEN 0x00000004 -#define DEV_CNTL_TXDMAEN 0x00000008 -#define DEV_CNTL_DESCRUPD 0x00000010 -#define DEV_CNTL_BIGEND 0x00000020 -#define DEV_CNTL_BUFFILL 0x00000040 -#define DEV_CNTL_TSHLDEN 0x00000080 -#define DEV_CNTL_BURSTEN 0x00000100 -#define DEV_CNTL_DMAMODE 0x00000200 -#define DEV_CNTL_SOFTDISCONNECT 0x00000400 -#define DEV_CNTL_SCALEDOWN 0x00000800 -#define DEV_CNTL_BURSTLENU 0x00010000 -#define DEV_CNTL_BURSTLENMSK 0x00ff0000 -#define DEV_CNTL_TSHLDLENU 0x01000000 -#define DEV_CNTL_TSHLDLENMSK 0xff000000 - -/* Device Status Register definitions */ - -#define DEV_STAT_CFG 0x0000000f -#define DEV_STAT_INTF 0x000000f0 -#define DEV_STAT_ALT 0x00000f00 -#define DEV_STAT_SUSP 0x00001000 -#define DEV_STAT_ENUM 0x00006000 -#define DEV_STAT_ENUM_SPEED_HS 0x00000000 -#define DEV_STAT_ENUM_SPEED_FS 0x00002000 -#define DEV_STAT_ENUM_SPEED_LS 0x00004000 -#define DEV_STAT_RXFIFO_EMPTY 0x00008000 -#define DEV_STAT_PHY_ERR 0x00010000 -#define DEV_STAT_TS 0xf0000000 - -/* Device Interrupt Register definitions */ - -#define DEV_INT_MSK 0x0000007f -#define DEV_INT_SETCFG 0x00000001 -#define DEV_INT_SETINTF 0x00000002 -#define DEV_INT_INACTIVE 0x00000004 -#define DEV_INT_USBRESET 0x00000008 -#define DEV_INT_SUSPUSB 0x00000010 -#define DEV_INT_SOF 0x00000020 -#define DEV_INT_ENUM 0x00000040 - -/* Endpoint Interrupt Register definitions */ - -#define ENDP0_INT_CTRLIN 0x00000001 -#define ENDP1_INT_BULKIN 0x00000002 -#define ENDP_INT_NONISOIN_MSK 0x0000AAAA -#define ENDP2_INT_BULKIN 0x00000004 -#define ENDP0_INT_CTRLOUT 0x00010000 -#define ENDP1_INT_BULKOUT 0x00020000 -#define ENDP2_INT_BULKOUT 0x00040000 -#define ENDP_INT_NONISOOUT_MSK 0x55540000 - -/* Endpoint Register definitions */ -#define ENDP_EPDIR_OUT 0x00000000 -#define ENDP_EPDIR_IN 0x00000010 -#define ENDP_EPTYPE_CNTL 0x0 -#define ENDP_EPTYPE_ISO 0x1 -#define ENDP_EPTYPE_BULK 0x2 -#define ENDP_EPTYPE_INT 0x3 - -/* - * Defines for Plug Detect - */ - -struct plug_regs { - u32 plug_state; - u32 plug_pending; -}; - -/* Plug State Register definitions */ -#define PLUG_STATUS_EN 0x1 -#define PLUG_STATUS_ATTACHED 0x2 -#define PLUG_STATUS_PHY_RESET 0x4 -#define PLUG_STATUS_PHY_MODE 0x8 - -/* - * Defines for UDC FIFO (Slave Mode) - */ -struct udcfifo_regs { - u32 *fifo_p; -}; - -/* - * 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 64 -#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 - -/* - * Function declarations - */ - -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_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); - -#endif /* __SPR_UDC_H */