12721551aSVipin KUMAR /* 22721551aSVipin KUMAR * Based on drivers/usb/gadget/omap1510_udc.c 32721551aSVipin KUMAR * TI OMAP1510 USB bus interface driver 42721551aSVipin KUMAR * 52721551aSVipin KUMAR * (C) Copyright 2009 62721551aSVipin KUMAR * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. 72721551aSVipin KUMAR * 82721551aSVipin KUMAR * See file CREDITS for list of people who contributed to this 92721551aSVipin KUMAR * project. 102721551aSVipin KUMAR * 112721551aSVipin KUMAR * This program is free software; you can redistribute it and/or 122721551aSVipin KUMAR * modify it under the terms of the GNU General Public License as 132721551aSVipin KUMAR * published by the Free Software Foundation; either version 2 of 142721551aSVipin KUMAR * the License, or (at your option) any later version. 152721551aSVipin KUMAR * 162721551aSVipin KUMAR * This program is distributed in the hope that it will be useful, 172721551aSVipin KUMAR * but WITHOUT ANY WARRANTY; without even the implied warranty of 182721551aSVipin KUMAR * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 192721551aSVipin KUMAR * GNU General Public License for more details. 202721551aSVipin KUMAR * 212721551aSVipin KUMAR * You should have received a copy of the GNU General Public License 222721551aSVipin KUMAR * along with this program; if not, write to the Free Software 232721551aSVipin KUMAR * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 242721551aSVipin KUMAR * MA 02111-1307 USA 252721551aSVipin KUMAR */ 262721551aSVipin KUMAR 272721551aSVipin KUMAR #include <common.h> 282721551aSVipin KUMAR #include <asm/io.h> 292721551aSVipin KUMAR 302721551aSVipin KUMAR #include <usbdevice.h> 312721551aSVipin KUMAR #include "ep0.h" 322721551aSVipin KUMAR #include <usb/designware_udc.h> 332721551aSVipin KUMAR #include <asm/arch/hardware.h> 342721551aSVipin KUMAR 352721551aSVipin KUMAR #define UDC_INIT_MDELAY 80 /* Device settle delay */ 362721551aSVipin KUMAR 372721551aSVipin KUMAR /* Some kind of debugging output... */ 382721551aSVipin KUMAR #ifndef DEBUG_DWUSBTTY 392721551aSVipin KUMAR #define UDCDBG(str) 402721551aSVipin KUMAR #define UDCDBGA(fmt, args...) 412721551aSVipin KUMAR #else 422721551aSVipin KUMAR #define UDCDBG(str) serial_printf(str "\n") 432721551aSVipin KUMAR #define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) 442721551aSVipin KUMAR #endif 452721551aSVipin KUMAR 462721551aSVipin KUMAR static struct urb *ep0_urb; 472721551aSVipin KUMAR static struct usb_device_instance *udc_device; 482721551aSVipin KUMAR 492721551aSVipin KUMAR static struct plug_regs *const plug_regs_p = 502721551aSVipin KUMAR (struct plug_regs * const)CONFIG_SYS_PLUG_BASE; 512721551aSVipin KUMAR static struct udc_regs *const udc_regs_p = 522721551aSVipin KUMAR (struct udc_regs * const)CONFIG_SYS_USBD_BASE; 532721551aSVipin KUMAR static struct udc_endp_regs *const outep_regs_p = 542721551aSVipin KUMAR &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0]; 552721551aSVipin KUMAR static struct udc_endp_regs *const inep_regs_p = 562721551aSVipin KUMAR &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0]; 572721551aSVipin KUMAR 582721551aSVipin KUMAR /* 592721551aSVipin KUMAR * udc_state_transition - Write the next packet to TxFIFO. 602721551aSVipin KUMAR * @initial: Initial state. 612721551aSVipin KUMAR * @final: Final state. 622721551aSVipin KUMAR * 632721551aSVipin KUMAR * Helper function to implement device state changes. The device states and 642721551aSVipin KUMAR * the events that transition between them are: 652721551aSVipin KUMAR * 662721551aSVipin KUMAR * STATE_ATTACHED 672721551aSVipin KUMAR * || /\ 682721551aSVipin KUMAR * \/ || 692721551aSVipin KUMAR * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET 702721551aSVipin KUMAR * || /\ 712721551aSVipin KUMAR * \/ || 722721551aSVipin KUMAR * STATE_POWERED 732721551aSVipin KUMAR * || /\ 742721551aSVipin KUMAR * \/ || 752721551aSVipin KUMAR * DEVICE_RESET DEVICE_POWER_INTERRUPTION 762721551aSVipin KUMAR * || /\ 772721551aSVipin KUMAR * \/ || 782721551aSVipin KUMAR * STATE_DEFAULT 792721551aSVipin KUMAR * || /\ 802721551aSVipin KUMAR * \/ || 812721551aSVipin KUMAR * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET 822721551aSVipin KUMAR * || /\ 832721551aSVipin KUMAR * \/ || 842721551aSVipin KUMAR * STATE_ADDRESSED 852721551aSVipin KUMAR * || /\ 862721551aSVipin KUMAR * \/ || 872721551aSVipin KUMAR * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED 882721551aSVipin KUMAR * || /\ 892721551aSVipin KUMAR * \/ || 902721551aSVipin KUMAR * STATE_CONFIGURED 912721551aSVipin KUMAR * 922721551aSVipin KUMAR * udc_state_transition transitions up (in the direction from STATE_ATTACHED 932721551aSVipin KUMAR * to STATE_CONFIGURED) from the specified initial state to the specified final 942721551aSVipin KUMAR * state, passing through each intermediate state on the way. If the initial 952721551aSVipin KUMAR * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then 962721551aSVipin KUMAR * no state transitions will take place. 972721551aSVipin KUMAR * 982721551aSVipin KUMAR * udc_state_transition also transitions down (in the direction from 992721551aSVipin KUMAR * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the 1002721551aSVipin KUMAR * specified final state, passing through each intermediate state on the way. 1012721551aSVipin KUMAR * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final 1022721551aSVipin KUMAR * state, then no state transitions will take place. 1032721551aSVipin KUMAR * 1042721551aSVipin KUMAR * This function must only be called with interrupts disabled. 1052721551aSVipin KUMAR */ 1062721551aSVipin KUMAR static void udc_state_transition(usb_device_state_t initial, 1072721551aSVipin KUMAR usb_device_state_t final) 1082721551aSVipin KUMAR { 1092721551aSVipin KUMAR if (initial < final) { 1102721551aSVipin KUMAR switch (initial) { 1112721551aSVipin KUMAR case STATE_ATTACHED: 1122721551aSVipin KUMAR usbd_device_event_irq(udc_device, 1132721551aSVipin KUMAR DEVICE_HUB_CONFIGURED, 0); 1142721551aSVipin KUMAR if (final == STATE_POWERED) 1152721551aSVipin KUMAR break; 1162721551aSVipin KUMAR case STATE_POWERED: 1172721551aSVipin KUMAR usbd_device_event_irq(udc_device, DEVICE_RESET, 0); 1182721551aSVipin KUMAR if (final == STATE_DEFAULT) 1192721551aSVipin KUMAR break; 1202721551aSVipin KUMAR case STATE_DEFAULT: 1212721551aSVipin KUMAR usbd_device_event_irq(udc_device, 1222721551aSVipin KUMAR DEVICE_ADDRESS_ASSIGNED, 0); 1232721551aSVipin KUMAR if (final == STATE_ADDRESSED) 1242721551aSVipin KUMAR break; 1252721551aSVipin KUMAR case STATE_ADDRESSED: 1262721551aSVipin KUMAR usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); 1272721551aSVipin KUMAR case STATE_CONFIGURED: 1282721551aSVipin KUMAR break; 1292721551aSVipin KUMAR default: 1302721551aSVipin KUMAR break; 1312721551aSVipin KUMAR } 1322721551aSVipin KUMAR } else if (initial > final) { 1332721551aSVipin KUMAR switch (initial) { 1342721551aSVipin KUMAR case STATE_CONFIGURED: 1352721551aSVipin KUMAR usbd_device_event_irq(udc_device, 1362721551aSVipin KUMAR DEVICE_DE_CONFIGURED, 0); 1372721551aSVipin KUMAR if (final == STATE_ADDRESSED) 1382721551aSVipin KUMAR break; 1392721551aSVipin KUMAR case STATE_ADDRESSED: 1402721551aSVipin KUMAR usbd_device_event_irq(udc_device, DEVICE_RESET, 0); 1412721551aSVipin KUMAR if (final == STATE_DEFAULT) 1422721551aSVipin KUMAR break; 1432721551aSVipin KUMAR case STATE_DEFAULT: 1442721551aSVipin KUMAR usbd_device_event_irq(udc_device, 1452721551aSVipin KUMAR DEVICE_POWER_INTERRUPTION, 0); 1462721551aSVipin KUMAR if (final == STATE_POWERED) 1472721551aSVipin KUMAR break; 1482721551aSVipin KUMAR case STATE_POWERED: 1492721551aSVipin KUMAR usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); 1502721551aSVipin KUMAR case STATE_ATTACHED: 1512721551aSVipin KUMAR break; 1522721551aSVipin KUMAR default: 1532721551aSVipin KUMAR break; 1542721551aSVipin KUMAR } 1552721551aSVipin KUMAR } 1562721551aSVipin KUMAR } 1572721551aSVipin KUMAR 1582721551aSVipin KUMAR /* Stall endpoint */ 1592721551aSVipin KUMAR static void udc_stall_ep(u32 ep_num) 1602721551aSVipin KUMAR { 1612721551aSVipin KUMAR writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, 1622721551aSVipin KUMAR &inep_regs_p[ep_num].endp_cntl); 1632721551aSVipin KUMAR 1642721551aSVipin KUMAR writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, 1652721551aSVipin KUMAR &outep_regs_p[ep_num].endp_cntl); 1662721551aSVipin KUMAR } 1672721551aSVipin KUMAR 1682721551aSVipin KUMAR static void *get_fifo(int ep_num, int in) 1692721551aSVipin KUMAR { 1702721551aSVipin KUMAR u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE; 1712721551aSVipin KUMAR 1722721551aSVipin KUMAR switch (ep_num) { 1732721551aSVipin KUMAR case UDC_EP3: 1742721551aSVipin KUMAR fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn); 1752721551aSVipin KUMAR /* break intentionally left out */ 1762721551aSVipin KUMAR 1772721551aSVipin KUMAR case UDC_EP1: 1782721551aSVipin KUMAR fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn); 1792721551aSVipin KUMAR /* break intentionally left out */ 1802721551aSVipin KUMAR 1812721551aSVipin KUMAR case UDC_EP0: 1822721551aSVipin KUMAR default: 1832721551aSVipin KUMAR if (in) { 1842721551aSVipin KUMAR fifo_ptr += 1852721551aSVipin KUMAR readl(&outep_regs_p[2].endp_maxpacksize) >> 16; 1862721551aSVipin KUMAR /* break intentionally left out */ 1872721551aSVipin KUMAR } else { 1882721551aSVipin KUMAR break; 1892721551aSVipin KUMAR } 1902721551aSVipin KUMAR 1912721551aSVipin KUMAR case UDC_EP2: 1922721551aSVipin KUMAR fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16; 1932721551aSVipin KUMAR /* break intentionally left out */ 1942721551aSVipin KUMAR } 1952721551aSVipin KUMAR 1962721551aSVipin KUMAR return (void *)fifo_ptr; 1972721551aSVipin KUMAR } 1982721551aSVipin KUMAR 1992721551aSVipin KUMAR static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len) 2002721551aSVipin KUMAR { 2012721551aSVipin KUMAR u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0); 2022721551aSVipin KUMAR u32 i, nw, nb; 2032721551aSVipin KUMAR u32 *wrdp; 2042721551aSVipin KUMAR u8 *bytp; 205*f50dcd60SShiraz Hashim u32 tmp[128]; 2062721551aSVipin KUMAR 2072721551aSVipin KUMAR if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY) 2082721551aSVipin KUMAR return -1; 2092721551aSVipin KUMAR 2102721551aSVipin KUMAR nw = len / sizeof(u32); 2112721551aSVipin KUMAR nb = len % sizeof(u32); 2122721551aSVipin KUMAR 213*f50dcd60SShiraz Hashim /* use tmp buf if bufp is not word aligned */ 214*f50dcd60SShiraz Hashim if ((int)bufp & 0x3) 215*f50dcd60SShiraz Hashim wrdp = (u32 *)&tmp[0]; 216*f50dcd60SShiraz Hashim else 2172721551aSVipin KUMAR wrdp = (u32 *)bufp; 218*f50dcd60SShiraz Hashim 2192721551aSVipin KUMAR for (i = 0; i < nw; i++) { 2202721551aSVipin KUMAR writel(readl(fifo_ptr), wrdp); 2212721551aSVipin KUMAR wrdp++; 2222721551aSVipin KUMAR } 2232721551aSVipin KUMAR 2242721551aSVipin KUMAR bytp = (u8 *)wrdp; 2252721551aSVipin KUMAR for (i = 0; i < nb; i++) { 2262721551aSVipin KUMAR writeb(readb(fifo_ptr), bytp); 2272721551aSVipin KUMAR fifo_ptr++; 2282721551aSVipin KUMAR bytp++; 2292721551aSVipin KUMAR } 2302721551aSVipin KUMAR readl(&outep_regs_p[epNum].write_done); 2312721551aSVipin KUMAR 232*f50dcd60SShiraz Hashim /* copy back tmp buffer to bufp if bufp is not word aligned */ 233*f50dcd60SShiraz Hashim if ((int)bufp & 0x3) 234*f50dcd60SShiraz Hashim memcpy(bufp, tmp, len); 235*f50dcd60SShiraz Hashim 2362721551aSVipin KUMAR return 0; 2372721551aSVipin KUMAR } 2382721551aSVipin KUMAR 2392721551aSVipin KUMAR static void usbputpcktofifo(int epNum, u8 *bufp, u32 len) 2402721551aSVipin KUMAR { 2412721551aSVipin KUMAR u32 i, nw, nb; 2422721551aSVipin KUMAR u32 *wrdp; 2432721551aSVipin KUMAR u8 *bytp; 2442721551aSVipin KUMAR u8 *fifo_ptr = get_fifo(epNum, 1); 2452721551aSVipin KUMAR 2462721551aSVipin KUMAR nw = len / sizeof(int); 2472721551aSVipin KUMAR nb = len % sizeof(int); 2482721551aSVipin KUMAR wrdp = (u32 *)bufp; 2492721551aSVipin KUMAR for (i = 0; i < nw; i++) { 2502721551aSVipin KUMAR writel(*wrdp, fifo_ptr); 2512721551aSVipin KUMAR wrdp++; 2522721551aSVipin KUMAR } 2532721551aSVipin KUMAR 2542721551aSVipin KUMAR bytp = (u8 *)wrdp; 2552721551aSVipin KUMAR for (i = 0; i < nb; i++) { 2562721551aSVipin KUMAR writeb(*bytp, fifo_ptr); 2572721551aSVipin KUMAR fifo_ptr++; 2582721551aSVipin KUMAR bytp++; 2592721551aSVipin KUMAR } 2602721551aSVipin KUMAR } 2612721551aSVipin KUMAR 2622721551aSVipin KUMAR /* 2632721551aSVipin KUMAR * dw_write_noniso_tx_fifo - Write the next packet to TxFIFO. 2642721551aSVipin KUMAR * @endpoint: Endpoint pointer. 2652721551aSVipin KUMAR * 2662721551aSVipin KUMAR * If the endpoint has an active tx_urb, then the next packet of data from the 2672721551aSVipin KUMAR * URB is written to the tx FIFO. The total amount of data in the urb is given 2682721551aSVipin KUMAR * by urb->actual_length. The maximum amount of data that can be sent in any 2692721551aSVipin KUMAR * one packet is given by endpoint->tx_packetSize. The number of data bytes 2702721551aSVipin KUMAR * from this URB that have already been transmitted is given by endpoint->sent. 2712721551aSVipin KUMAR * endpoint->last is updated by this routine with the number of data bytes 2722721551aSVipin KUMAR * transmitted in this packet. 2732721551aSVipin KUMAR * 2742721551aSVipin KUMAR */ 2752721551aSVipin KUMAR static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance 2762721551aSVipin KUMAR *endpoint) 2772721551aSVipin KUMAR { 2782721551aSVipin KUMAR struct urb *urb = endpoint->tx_urb; 2792721551aSVipin KUMAR int align; 2802721551aSVipin KUMAR 2812721551aSVipin KUMAR if (urb) { 2822721551aSVipin KUMAR u32 last; 2832721551aSVipin KUMAR 2842721551aSVipin KUMAR UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d", 2852721551aSVipin KUMAR urb->buffer, urb->buffer_length, urb->actual_length); 2862721551aSVipin KUMAR 2872721551aSVipin KUMAR last = MIN(urb->actual_length - endpoint->sent, 2882721551aSVipin KUMAR endpoint->tx_packetSize); 2892721551aSVipin KUMAR 2902721551aSVipin KUMAR if (last) { 2912721551aSVipin KUMAR u8 *cp = urb->buffer + endpoint->sent; 2922721551aSVipin KUMAR 2932721551aSVipin KUMAR /* 2942721551aSVipin KUMAR * This ensures that USBD packet fifo is accessed 2952721551aSVipin KUMAR * - through word aligned pointer or 2962721551aSVipin KUMAR * - through non word aligned pointer but only 2972721551aSVipin KUMAR * with a max length to make the next packet 2982721551aSVipin KUMAR * word aligned 2992721551aSVipin KUMAR */ 3002721551aSVipin KUMAR 3012721551aSVipin KUMAR align = ((ulong)cp % sizeof(int)); 3022721551aSVipin KUMAR if (align) 3032721551aSVipin KUMAR last = MIN(last, sizeof(int) - align); 3042721551aSVipin KUMAR 3052721551aSVipin KUMAR UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d", 3062721551aSVipin KUMAR endpoint->sent, endpoint->tx_packetSize, last); 3072721551aSVipin KUMAR 3082721551aSVipin KUMAR usbputpcktofifo(endpoint->endpoint_address & 3092721551aSVipin KUMAR USB_ENDPOINT_NUMBER_MASK, cp, last); 3102721551aSVipin KUMAR } 3112721551aSVipin KUMAR endpoint->last = last; 3122721551aSVipin KUMAR } 3132721551aSVipin KUMAR } 3142721551aSVipin KUMAR 3152721551aSVipin KUMAR /* 3162721551aSVipin KUMAR * Handle SETUP USB interrupt. 3172721551aSVipin KUMAR * This function implements TRM Figure 14-14. 3182721551aSVipin KUMAR */ 3192721551aSVipin KUMAR static void dw_udc_setup(struct usb_endpoint_instance *endpoint) 3202721551aSVipin KUMAR { 3212721551aSVipin KUMAR u8 *datap = (u8 *)&ep0_urb->device_request; 3222721551aSVipin KUMAR int ep_addr = endpoint->endpoint_address; 3232721551aSVipin KUMAR 3242721551aSVipin KUMAR UDCDBG("-> Entering device setup"); 3252721551aSVipin KUMAR usbgetpckfromfifo(ep_addr, datap, 8); 3262721551aSVipin KUMAR 3272721551aSVipin KUMAR /* Try to process setup packet */ 3282721551aSVipin KUMAR if (ep0_recv_setup(ep0_urb)) { 3292721551aSVipin KUMAR /* Not a setup packet, stall next EP0 transaction */ 3302721551aSVipin KUMAR udc_stall_ep(0); 3312721551aSVipin KUMAR UDCDBG("can't parse setup packet, still waiting for setup"); 3322721551aSVipin KUMAR return; 3332721551aSVipin KUMAR } 3342721551aSVipin KUMAR 3352721551aSVipin KUMAR /* Check direction */ 3362721551aSVipin KUMAR if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) 3372721551aSVipin KUMAR == USB_REQ_HOST2DEVICE) { 3382721551aSVipin KUMAR UDCDBG("control write on EP0"); 3392721551aSVipin KUMAR if (le16_to_cpu(ep0_urb->device_request.wLength)) { 3402721551aSVipin KUMAR /* Stall this request */ 3412721551aSVipin KUMAR UDCDBG("Stalling unsupported EP0 control write data " 3422721551aSVipin KUMAR "stage."); 3432721551aSVipin KUMAR udc_stall_ep(0); 3442721551aSVipin KUMAR } 3452721551aSVipin KUMAR } else { 3462721551aSVipin KUMAR 3472721551aSVipin KUMAR UDCDBG("control read on EP0"); 3482721551aSVipin KUMAR /* 3492721551aSVipin KUMAR * The ep0_recv_setup function has already placed our response 3502721551aSVipin KUMAR * packet data in ep0_urb->buffer and the packet length in 3512721551aSVipin KUMAR * ep0_urb->actual_length. 3522721551aSVipin KUMAR */ 3532721551aSVipin KUMAR endpoint->tx_urb = ep0_urb; 3542721551aSVipin KUMAR endpoint->sent = 0; 3552721551aSVipin KUMAR /* 3562721551aSVipin KUMAR * Write packet data to the FIFO. dw_write_noniso_tx_fifo 3572721551aSVipin KUMAR * will update endpoint->last with the number of bytes written 3582721551aSVipin KUMAR * to the FIFO. 3592721551aSVipin KUMAR */ 3602721551aSVipin KUMAR dw_write_noniso_tx_fifo(endpoint); 3612721551aSVipin KUMAR 3622721551aSVipin KUMAR writel(0x0, &inep_regs_p[ep_addr].write_done); 3632721551aSVipin KUMAR } 3642721551aSVipin KUMAR 3652721551aSVipin KUMAR udc_unset_nak(endpoint->endpoint_address); 3662721551aSVipin KUMAR 3672721551aSVipin KUMAR UDCDBG("<- Leaving device setup"); 3682721551aSVipin KUMAR } 3692721551aSVipin KUMAR 3702721551aSVipin KUMAR /* 3712721551aSVipin KUMAR * Handle endpoint 0 RX interrupt 3722721551aSVipin KUMAR */ 3732721551aSVipin KUMAR static void dw_udc_ep0_rx(struct usb_endpoint_instance *endpoint) 3742721551aSVipin KUMAR { 3752721551aSVipin KUMAR u8 dummy[64]; 3762721551aSVipin KUMAR 3772721551aSVipin KUMAR UDCDBG("RX on EP0"); 3782721551aSVipin KUMAR 3792721551aSVipin KUMAR /* Check direction */ 3802721551aSVipin KUMAR if ((ep0_urb->device_request.bmRequestType 3812721551aSVipin KUMAR & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { 3822721551aSVipin KUMAR /* 3832721551aSVipin KUMAR * This rx interrupt must be for a control write data 3842721551aSVipin KUMAR * stage packet. 3852721551aSVipin KUMAR * 3862721551aSVipin KUMAR * We don't support control write data stages. 3872721551aSVipin KUMAR * We should never end up here. 3882721551aSVipin KUMAR */ 3892721551aSVipin KUMAR 3902721551aSVipin KUMAR UDCDBG("Stalling unexpected EP0 control write " 3912721551aSVipin KUMAR "data stage packet"); 3922721551aSVipin KUMAR udc_stall_ep(0); 3932721551aSVipin KUMAR } else { 3942721551aSVipin KUMAR /* 3952721551aSVipin KUMAR * This rx interrupt must be for a control read status 3962721551aSVipin KUMAR * stage packet. 3972721551aSVipin KUMAR */ 3982721551aSVipin KUMAR UDCDBG("ACK on EP0 control read status stage packet"); 3992721551aSVipin KUMAR u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff; 4002721551aSVipin KUMAR usbgetpckfromfifo(0, dummy, len); 4012721551aSVipin KUMAR } 4022721551aSVipin KUMAR } 4032721551aSVipin KUMAR 4042721551aSVipin KUMAR /* 4052721551aSVipin KUMAR * Handle endpoint 0 TX interrupt 4062721551aSVipin KUMAR */ 4072721551aSVipin KUMAR static void dw_udc_ep0_tx(struct usb_endpoint_instance *endpoint) 4082721551aSVipin KUMAR { 4092721551aSVipin KUMAR struct usb_device_request *request = &ep0_urb->device_request; 4102721551aSVipin KUMAR int ep_addr; 4112721551aSVipin KUMAR 4122721551aSVipin KUMAR UDCDBG("TX on EP0"); 4132721551aSVipin KUMAR 4142721551aSVipin KUMAR /* Check direction */ 4152721551aSVipin KUMAR if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == 4162721551aSVipin KUMAR USB_REQ_HOST2DEVICE) { 4172721551aSVipin KUMAR /* 4182721551aSVipin KUMAR * This tx interrupt must be for a control write status 4192721551aSVipin KUMAR * stage packet. 4202721551aSVipin KUMAR */ 4212721551aSVipin KUMAR UDCDBG("ACK on EP0 control write status stage packet"); 4222721551aSVipin KUMAR } else { 4232721551aSVipin KUMAR /* 4242721551aSVipin KUMAR * This tx interrupt must be for a control read data 4252721551aSVipin KUMAR * stage packet. 4262721551aSVipin KUMAR */ 4272721551aSVipin KUMAR int wLength = le16_to_cpu(request->wLength); 4282721551aSVipin KUMAR 4292721551aSVipin KUMAR /* 4302721551aSVipin KUMAR * Update our count of bytes sent so far in this 4312721551aSVipin KUMAR * transfer. 4322721551aSVipin KUMAR */ 4332721551aSVipin KUMAR endpoint->sent += endpoint->last; 4342721551aSVipin KUMAR 4352721551aSVipin KUMAR /* 4362721551aSVipin KUMAR * We are finished with this transfer if we have sent 4372721551aSVipin KUMAR * all of the bytes in our tx urb (urb->actual_length) 4382721551aSVipin KUMAR * unless we need a zero-length terminating packet. We 4392721551aSVipin KUMAR * need a zero-length terminating packet if we returned 4402721551aSVipin KUMAR * fewer bytes than were requested (wLength) by the host, 4412721551aSVipin KUMAR * and the number of bytes we returned is an exact 4422721551aSVipin KUMAR * multiple of the packet size endpoint->tx_packetSize. 4432721551aSVipin KUMAR */ 4442721551aSVipin KUMAR if ((endpoint->sent == ep0_urb->actual_length) && 4452721551aSVipin KUMAR ((ep0_urb->actual_length == wLength) || 4462721551aSVipin KUMAR (endpoint->last != endpoint->tx_packetSize))) { 4472721551aSVipin KUMAR /* Done with control read data stage. */ 4482721551aSVipin KUMAR UDCDBG("control read data stage complete"); 4492721551aSVipin KUMAR } else { 4502721551aSVipin KUMAR /* 4512721551aSVipin KUMAR * We still have another packet of data to send 4522721551aSVipin KUMAR * in this control read data stage or else we 4532721551aSVipin KUMAR * need a zero-length terminating packet. 4542721551aSVipin KUMAR */ 4552721551aSVipin KUMAR UDCDBG("ACK control read data stage packet"); 4562721551aSVipin KUMAR dw_write_noniso_tx_fifo(endpoint); 4572721551aSVipin KUMAR 4582721551aSVipin KUMAR ep_addr = endpoint->endpoint_address; 4592721551aSVipin KUMAR writel(0x0, &inep_regs_p[ep_addr].write_done); 4602721551aSVipin KUMAR } 4612721551aSVipin KUMAR } 4622721551aSVipin KUMAR } 4632721551aSVipin KUMAR 4642721551aSVipin KUMAR static struct usb_endpoint_instance *dw_find_ep(int ep) 4652721551aSVipin KUMAR { 4662721551aSVipin KUMAR int i; 4672721551aSVipin KUMAR 4682721551aSVipin KUMAR for (i = 0; i < udc_device->bus->max_endpoints; i++) { 4692721551aSVipin KUMAR if ((udc_device->bus->endpoint_array[i].endpoint_address & 4702721551aSVipin KUMAR USB_ENDPOINT_NUMBER_MASK) == ep) 4712721551aSVipin KUMAR return &udc_device->bus->endpoint_array[i]; 4722721551aSVipin KUMAR } 4732721551aSVipin KUMAR return NULL; 4742721551aSVipin KUMAR } 4752721551aSVipin KUMAR 4762721551aSVipin KUMAR /* 4772721551aSVipin KUMAR * Handle RX transaction on non-ISO endpoint. 4782721551aSVipin KUMAR * The ep argument is a physical endpoint number for a non-ISO IN endpoint 4792721551aSVipin KUMAR * in the range 1 to 15. 4802721551aSVipin KUMAR */ 4812721551aSVipin KUMAR static void dw_udc_epn_rx(int ep) 4822721551aSVipin KUMAR { 4832721551aSVipin KUMAR int nbytes = 0; 4842721551aSVipin KUMAR struct urb *urb; 4852721551aSVipin KUMAR struct usb_endpoint_instance *endpoint = dw_find_ep(ep); 4862721551aSVipin KUMAR 4872721551aSVipin KUMAR if (endpoint) { 4882721551aSVipin KUMAR urb = endpoint->rcv_urb; 4892721551aSVipin KUMAR 4902721551aSVipin KUMAR if (urb) { 4912721551aSVipin KUMAR u8 *cp = urb->buffer + urb->actual_length; 4922721551aSVipin KUMAR 4932721551aSVipin KUMAR nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) & 4942721551aSVipin KUMAR 0xfff; 4952721551aSVipin KUMAR usbgetpckfromfifo(ep, cp, nbytes); 4962721551aSVipin KUMAR usbd_rcv_complete(endpoint, nbytes, 0); 4972721551aSVipin KUMAR } 4982721551aSVipin KUMAR } 4992721551aSVipin KUMAR } 5002721551aSVipin KUMAR 5012721551aSVipin KUMAR /* 5022721551aSVipin KUMAR * Handle TX transaction on non-ISO endpoint. 5032721551aSVipin KUMAR * The ep argument is a physical endpoint number for a non-ISO IN endpoint 5042721551aSVipin KUMAR * in the range 16 to 30. 5052721551aSVipin KUMAR */ 5062721551aSVipin KUMAR static void dw_udc_epn_tx(int ep) 5072721551aSVipin KUMAR { 5082721551aSVipin KUMAR struct usb_endpoint_instance *endpoint = dw_find_ep(ep); 5092721551aSVipin KUMAR 510dc3e7739SVipin KUMAR if (!endpoint) 511dc3e7739SVipin KUMAR return; 512dc3e7739SVipin KUMAR 5132721551aSVipin KUMAR /* 5142721551aSVipin KUMAR * We need to transmit a terminating zero-length packet now if 5152721551aSVipin KUMAR * we have sent all of the data in this URB and the transfer 5162721551aSVipin KUMAR * size was an exact multiple of the packet size. 5172721551aSVipin KUMAR */ 518dc3e7739SVipin KUMAR if (endpoint->tx_urb && 519dc3e7739SVipin KUMAR (endpoint->last == endpoint->tx_packetSize) && 520dc3e7739SVipin KUMAR (endpoint->tx_urb->actual_length - endpoint->sent - 521dc3e7739SVipin KUMAR endpoint->last == 0)) { 5222721551aSVipin KUMAR /* handle zero length packet here */ 5232721551aSVipin KUMAR writel(0x0, &inep_regs_p[ep].write_done); 524dc3e7739SVipin KUMAR 5252721551aSVipin KUMAR } 526dc3e7739SVipin KUMAR 527dc3e7739SVipin KUMAR if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { 5282721551aSVipin KUMAR /* retire the data that was just sent */ 5292721551aSVipin KUMAR usbd_tx_complete(endpoint); 5302721551aSVipin KUMAR /* 5312721551aSVipin KUMAR * Check to see if we have more data ready to transmit 5322721551aSVipin KUMAR * now. 5332721551aSVipin KUMAR */ 5342721551aSVipin KUMAR if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { 5352721551aSVipin KUMAR /* write data to FIFO */ 5362721551aSVipin KUMAR dw_write_noniso_tx_fifo(endpoint); 5372721551aSVipin KUMAR writel(0x0, &inep_regs_p[ep].write_done); 5382721551aSVipin KUMAR 5392721551aSVipin KUMAR } else if (endpoint->tx_urb 5402721551aSVipin KUMAR && (endpoint->tx_urb->actual_length == 0)) { 5412721551aSVipin KUMAR /* udc_set_nak(ep); */ 5422721551aSVipin KUMAR } 5432721551aSVipin KUMAR } 5442721551aSVipin KUMAR } 5452721551aSVipin KUMAR 5462721551aSVipin KUMAR /* 5472721551aSVipin KUMAR * Start of public functions. 5482721551aSVipin KUMAR */ 5492721551aSVipin KUMAR 5502721551aSVipin KUMAR /* Called to start packet transmission. */ 5512721551aSVipin KUMAR int udc_endpoint_write(struct usb_endpoint_instance *endpoint) 5522721551aSVipin KUMAR { 5532721551aSVipin KUMAR udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK); 5542721551aSVipin KUMAR return 0; 5552721551aSVipin KUMAR } 5562721551aSVipin KUMAR 5572721551aSVipin KUMAR /* Start to initialize h/w stuff */ 5582721551aSVipin KUMAR int udc_init(void) 5592721551aSVipin KUMAR { 5602721551aSVipin KUMAR int i; 5612721551aSVipin KUMAR u32 plug_st; 5622721551aSVipin KUMAR 5632721551aSVipin KUMAR udc_device = NULL; 5642721551aSVipin KUMAR 5652721551aSVipin KUMAR UDCDBG("starting"); 5662721551aSVipin KUMAR 5672721551aSVipin KUMAR readl(&plug_regs_p->plug_pending); 5682721551aSVipin KUMAR 5692721551aSVipin KUMAR for (i = 0; i < UDC_INIT_MDELAY; i++) 5702721551aSVipin KUMAR udelay(1000); 5712721551aSVipin KUMAR 5722721551aSVipin KUMAR plug_st = readl(&plug_regs_p->plug_state); 5732721551aSVipin KUMAR writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state); 5742721551aSVipin KUMAR 5752721551aSVipin KUMAR writel(~0x0, &udc_regs_p->endp_int); 5762721551aSVipin KUMAR writel(~0x0, &udc_regs_p->dev_int_mask); 5772721551aSVipin KUMAR writel(~0x0, &udc_regs_p->endp_int_mask); 5782721551aSVipin KUMAR 57923b0e694SVipin KUMAR #ifndef CONFIG_USBD_HS 5802721551aSVipin KUMAR writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | 5812721551aSVipin KUMAR DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); 58223b0e694SVipin KUMAR #else 58323b0e694SVipin KUMAR writel(DEV_CONF_HS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | 58423b0e694SVipin KUMAR DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); 58523b0e694SVipin KUMAR #endif 5862721551aSVipin KUMAR 587dc3e7739SVipin KUMAR writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl); 5882721551aSVipin KUMAR 5892721551aSVipin KUMAR /* Clear all interrupts pending */ 5902721551aSVipin KUMAR writel(DEV_INT_MSK, &udc_regs_p->dev_int); 5912721551aSVipin KUMAR 5922721551aSVipin KUMAR return 0; 5932721551aSVipin KUMAR } 5942721551aSVipin KUMAR 59523b0e694SVipin KUMAR int is_usbd_high_speed(void) 59623b0e694SVipin KUMAR { 59723b0e694SVipin KUMAR return (readl(&udc_regs_p->dev_stat) & DEV_STAT_ENUM) ? 0 : 1; 59823b0e694SVipin KUMAR } 59923b0e694SVipin KUMAR 6002721551aSVipin KUMAR /* 6012721551aSVipin KUMAR * udc_setup_ep - setup endpoint 6022721551aSVipin KUMAR * Associate a physical endpoint with endpoint_instance 6032721551aSVipin KUMAR */ 6042721551aSVipin KUMAR void udc_setup_ep(struct usb_device_instance *device, 6052721551aSVipin KUMAR u32 ep, struct usb_endpoint_instance *endpoint) 6062721551aSVipin KUMAR { 6072721551aSVipin KUMAR UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address); 6082721551aSVipin KUMAR int ep_addr; 6092721551aSVipin KUMAR int ep_num, ep_type; 6102721551aSVipin KUMAR int packet_size; 6112721551aSVipin KUMAR int buffer_size; 6122721551aSVipin KUMAR int attributes; 6132721551aSVipin KUMAR char *tt; 6142721551aSVipin KUMAR u32 endp_intmask; 6152721551aSVipin KUMAR 616dc3e7739SVipin KUMAR if ((ep != 0) && (udc_device->device_state < STATE_ADDRESSED)) 617dc3e7739SVipin KUMAR return; 618dc3e7739SVipin KUMAR 6192721551aSVipin KUMAR tt = getenv("usbtty"); 6202721551aSVipin KUMAR if (!tt) 6212721551aSVipin KUMAR tt = "generic"; 6222721551aSVipin KUMAR 6232721551aSVipin KUMAR ep_addr = endpoint->endpoint_address; 6242721551aSVipin KUMAR ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; 6252721551aSVipin KUMAR 6262721551aSVipin KUMAR if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { 6272721551aSVipin KUMAR /* IN endpoint */ 6282721551aSVipin KUMAR packet_size = endpoint->tx_packetSize; 6292721551aSVipin KUMAR buffer_size = packet_size * 2; 6302721551aSVipin KUMAR attributes = endpoint->tx_attributes; 6312721551aSVipin KUMAR } else { 6322721551aSVipin KUMAR /* OUT endpoint */ 6332721551aSVipin KUMAR packet_size = endpoint->rcv_packetSize; 6342721551aSVipin KUMAR buffer_size = packet_size * 2; 6352721551aSVipin KUMAR attributes = endpoint->rcv_attributes; 6362721551aSVipin KUMAR } 6372721551aSVipin KUMAR 6382721551aSVipin KUMAR switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { 6392721551aSVipin KUMAR case USB_ENDPOINT_XFER_CONTROL: 6402721551aSVipin KUMAR ep_type = ENDP_EPTYPE_CNTL; 6412721551aSVipin KUMAR break; 6422721551aSVipin KUMAR case USB_ENDPOINT_XFER_BULK: 6432721551aSVipin KUMAR default: 6442721551aSVipin KUMAR ep_type = ENDP_EPTYPE_BULK; 6452721551aSVipin KUMAR break; 6462721551aSVipin KUMAR case USB_ENDPOINT_XFER_INT: 6472721551aSVipin KUMAR ep_type = ENDP_EPTYPE_INT; 6482721551aSVipin KUMAR break; 6492721551aSVipin KUMAR case USB_ENDPOINT_XFER_ISOC: 6502721551aSVipin KUMAR ep_type = ENDP_EPTYPE_ISO; 6512721551aSVipin KUMAR break; 6522721551aSVipin KUMAR } 6532721551aSVipin KUMAR 6542721551aSVipin KUMAR struct udc_endp_regs *out_p = &outep_regs_p[ep_num]; 6552721551aSVipin KUMAR struct udc_endp_regs *in_p = &inep_regs_p[ep_num]; 6562721551aSVipin KUMAR 6572721551aSVipin KUMAR if (!ep_addr) { 6582721551aSVipin KUMAR /* Setup endpoint 0 */ 6592721551aSVipin KUMAR buffer_size = packet_size; 6602721551aSVipin KUMAR 6612721551aSVipin KUMAR writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK, 6622721551aSVipin KUMAR &in_p->endp_cntl); 6632721551aSVipin KUMAR 6642721551aSVipin KUMAR writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK, 6652721551aSVipin KUMAR &out_p->endp_cntl); 6662721551aSVipin KUMAR 6672721551aSVipin KUMAR writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl); 6682721551aSVipin KUMAR 6692721551aSVipin KUMAR writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); 6702721551aSVipin KUMAR 6712721551aSVipin KUMAR writel(packet_size, &in_p->endp_maxpacksize); 6722721551aSVipin KUMAR 6732721551aSVipin KUMAR writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl); 6742721551aSVipin KUMAR 6752721551aSVipin KUMAR writel(packet_size | ((buffer_size / sizeof(int)) << 16), 6762721551aSVipin KUMAR &out_p->endp_maxpacksize); 6772721551aSVipin KUMAR 6782721551aSVipin KUMAR } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { 6792721551aSVipin KUMAR /* Setup the IN endpoint */ 6802721551aSVipin KUMAR writel(0x0, &in_p->endp_status); 6812721551aSVipin KUMAR writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl); 6822721551aSVipin KUMAR writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); 6832721551aSVipin KUMAR writel(packet_size, &in_p->endp_maxpacksize); 6842721551aSVipin KUMAR 6852721551aSVipin KUMAR if (!strcmp(tt, "cdc_acm")) { 6862721551aSVipin KUMAR if (ep_type == ENDP_EPTYPE_INT) { 6872721551aSVipin KUMAR /* Conf no. 1 Interface no. 0 */ 6882721551aSVipin KUMAR writel((packet_size << 19) | 6892721551aSVipin KUMAR ENDP_EPDIR_IN | (1 << 7) | 6902721551aSVipin KUMAR (0 << 11) | (ep_type << 5) | ep_num, 6912721551aSVipin KUMAR &udc_regs_p->udc_endp_reg[ep_num]); 6922721551aSVipin KUMAR } else { 6932721551aSVipin KUMAR /* Conf no. 1 Interface no. 1 */ 6942721551aSVipin KUMAR writel((packet_size << 19) | 6952721551aSVipin KUMAR ENDP_EPDIR_IN | (1 << 7) | 6962721551aSVipin KUMAR (1 << 11) | (ep_type << 5) | ep_num, 6972721551aSVipin KUMAR &udc_regs_p->udc_endp_reg[ep_num]); 6982721551aSVipin KUMAR } 6992721551aSVipin KUMAR } else { 7002721551aSVipin KUMAR /* Conf no. 1 Interface no. 0 */ 7012721551aSVipin KUMAR writel((packet_size << 19) | 7022721551aSVipin KUMAR ENDP_EPDIR_IN | (1 << 7) | 7032721551aSVipin KUMAR (0 << 11) | (ep_type << 5) | ep_num, 7042721551aSVipin KUMAR &udc_regs_p->udc_endp_reg[ep_num]); 7052721551aSVipin KUMAR } 7062721551aSVipin KUMAR 7072721551aSVipin KUMAR } else { 7082721551aSVipin KUMAR /* Setup the OUT endpoint */ 7092721551aSVipin KUMAR writel(0x0, &out_p->endp_status); 7102721551aSVipin KUMAR writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl); 7112721551aSVipin KUMAR writel(packet_size | ((buffer_size / sizeof(int)) << 16), 7122721551aSVipin KUMAR &out_p->endp_maxpacksize); 7132721551aSVipin KUMAR 7142721551aSVipin KUMAR if (!strcmp(tt, "cdc_acm")) { 7152721551aSVipin KUMAR writel((packet_size << 19) | 7162721551aSVipin KUMAR ENDP_EPDIR_OUT | (1 << 7) | 7172721551aSVipin KUMAR (1 << 11) | (ep_type << 5) | ep_num, 7182721551aSVipin KUMAR &udc_regs_p->udc_endp_reg[ep_num]); 7192721551aSVipin KUMAR } else { 7202721551aSVipin KUMAR writel((packet_size << 19) | 7212721551aSVipin KUMAR ENDP_EPDIR_OUT | (1 << 7) | 7222721551aSVipin KUMAR (0 << 11) | (ep_type << 5) | ep_num, 7232721551aSVipin KUMAR &udc_regs_p->udc_endp_reg[ep_num]); 7242721551aSVipin KUMAR } 7252721551aSVipin KUMAR 7262721551aSVipin KUMAR } 7272721551aSVipin KUMAR 7282721551aSVipin KUMAR endp_intmask = readl(&udc_regs_p->endp_int_mask); 7292721551aSVipin KUMAR endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num); 7302721551aSVipin KUMAR writel(endp_intmask, &udc_regs_p->endp_int_mask); 7312721551aSVipin KUMAR } 7322721551aSVipin KUMAR 7332721551aSVipin KUMAR /* Turn on the USB connection by enabling the pullup resistor */ 7342721551aSVipin KUMAR void udc_connect(void) 7352721551aSVipin KUMAR { 736dc3e7739SVipin KUMAR u32 plug_st, dev_cntl; 737dc3e7739SVipin KUMAR 738dc3e7739SVipin KUMAR dev_cntl = readl(&udc_regs_p->dev_cntl); 739dc3e7739SVipin KUMAR dev_cntl |= DEV_CNTL_SOFTDISCONNECT; 740dc3e7739SVipin KUMAR writel(dev_cntl, &udc_regs_p->dev_cntl); 741dc3e7739SVipin KUMAR 742dc3e7739SVipin KUMAR udelay(1000); 743dc3e7739SVipin KUMAR 744dc3e7739SVipin KUMAR dev_cntl = readl(&udc_regs_p->dev_cntl); 745dc3e7739SVipin KUMAR dev_cntl &= ~DEV_CNTL_SOFTDISCONNECT; 746dc3e7739SVipin KUMAR writel(dev_cntl, &udc_regs_p->dev_cntl); 7472721551aSVipin KUMAR 7482721551aSVipin KUMAR plug_st = readl(&plug_regs_p->plug_state); 7492721551aSVipin KUMAR plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); 7502721551aSVipin KUMAR writel(plug_st, &plug_regs_p->plug_state); 7512721551aSVipin KUMAR } 7522721551aSVipin KUMAR 7532721551aSVipin KUMAR /* Turn off the USB connection by disabling the pullup resistor */ 7542721551aSVipin KUMAR void udc_disconnect(void) 7552721551aSVipin KUMAR { 7562721551aSVipin KUMAR u32 plug_st; 7572721551aSVipin KUMAR 758dc3e7739SVipin KUMAR writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl); 759dc3e7739SVipin KUMAR 7602721551aSVipin KUMAR plug_st = readl(&plug_regs_p->plug_state); 7612721551aSVipin KUMAR plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); 7622721551aSVipin KUMAR writel(plug_st, &plug_regs_p->plug_state); 7632721551aSVipin KUMAR } 7642721551aSVipin KUMAR 7652721551aSVipin KUMAR /* Switch on the UDC */ 7662721551aSVipin KUMAR void udc_enable(struct usb_device_instance *device) 7672721551aSVipin KUMAR { 7682721551aSVipin KUMAR UDCDBGA("enable device %p, status %d", device, device->status); 7692721551aSVipin KUMAR 7702721551aSVipin KUMAR /* Save the device structure pointer */ 7712721551aSVipin KUMAR udc_device = device; 7722721551aSVipin KUMAR 7732721551aSVipin KUMAR /* Setup ep0 urb */ 7742721551aSVipin KUMAR if (!ep0_urb) { 7752721551aSVipin KUMAR ep0_urb = 7762721551aSVipin KUMAR usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array); 7772721551aSVipin KUMAR } else { 7782721551aSVipin KUMAR serial_printf("udc_enable: ep0_urb already allocated %p\n", 7792721551aSVipin KUMAR ep0_urb); 7802721551aSVipin KUMAR } 7812721551aSVipin KUMAR 7822721551aSVipin KUMAR writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); 7832721551aSVipin KUMAR } 7842721551aSVipin KUMAR 7852721551aSVipin KUMAR /** 7862721551aSVipin KUMAR * udc_startup - allow udc code to do any additional startup 7872721551aSVipin KUMAR */ 7882721551aSVipin KUMAR void udc_startup_events(struct usb_device_instance *device) 7892721551aSVipin KUMAR { 7902721551aSVipin KUMAR /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ 7912721551aSVipin KUMAR usbd_device_event_irq(device, DEVICE_INIT, 0); 7922721551aSVipin KUMAR 7932721551aSVipin KUMAR /* 7942721551aSVipin KUMAR * The DEVICE_CREATE event puts the USB device in the state 7952721551aSVipin KUMAR * STATE_ATTACHED. 7962721551aSVipin KUMAR */ 7972721551aSVipin KUMAR usbd_device_event_irq(device, DEVICE_CREATE, 0); 7982721551aSVipin KUMAR 7992721551aSVipin KUMAR /* 8002721551aSVipin KUMAR * Some USB controller driver implementations signal 8012721551aSVipin KUMAR * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. 8022721551aSVipin KUMAR * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, 8032721551aSVipin KUMAR * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. 8042721551aSVipin KUMAR * The DW USB client controller has the capability to detect when the 8052721551aSVipin KUMAR * USB cable is connected to a powered USB bus, so we will defer the 8062721551aSVipin KUMAR * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later. 8072721551aSVipin KUMAR */ 8082721551aSVipin KUMAR 8092721551aSVipin KUMAR udc_enable(device); 8102721551aSVipin KUMAR } 8112721551aSVipin KUMAR 8122721551aSVipin KUMAR /* 8132721551aSVipin KUMAR * Plug detection interrupt handling 8142721551aSVipin KUMAR */ 8154df4f3c9SAmit Virdi static void dw_udc_plug_irq(void) 8162721551aSVipin KUMAR { 8172721551aSVipin KUMAR if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) { 8182721551aSVipin KUMAR /* 8192721551aSVipin KUMAR * USB cable attached 8202721551aSVipin KUMAR * Turn off PHY reset bit (PLUG detect). 8212721551aSVipin KUMAR * Switch PHY opmode to normal operation (PLUG detect). 8222721551aSVipin KUMAR */ 8232721551aSVipin KUMAR udc_connect(); 8242721551aSVipin KUMAR writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); 8252721551aSVipin KUMAR 8262721551aSVipin KUMAR UDCDBG("device attached and powered"); 8272721551aSVipin KUMAR udc_state_transition(udc_device->device_state, STATE_POWERED); 8282721551aSVipin KUMAR } else { 8292721551aSVipin KUMAR writel(~0x0, &udc_regs_p->dev_int_mask); 8302721551aSVipin KUMAR 8312721551aSVipin KUMAR UDCDBG("device detached or unpowered"); 8322721551aSVipin KUMAR udc_state_transition(udc_device->device_state, STATE_ATTACHED); 8332721551aSVipin KUMAR } 8342721551aSVipin KUMAR } 8352721551aSVipin KUMAR 8362721551aSVipin KUMAR /* 8372721551aSVipin KUMAR * Device interrupt handling 8382721551aSVipin KUMAR */ 8394df4f3c9SAmit Virdi static void dw_udc_dev_irq(void) 8402721551aSVipin KUMAR { 8412721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) { 8422721551aSVipin KUMAR writel(~0x0, &udc_regs_p->endp_int_mask); 8432721551aSVipin KUMAR 8442721551aSVipin KUMAR writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH, 8452721551aSVipin KUMAR &inep_regs_p[0].endp_cntl); 8462721551aSVipin KUMAR 8472721551aSVipin KUMAR writel(DEV_INT_USBRESET, &udc_regs_p->dev_int); 8482721551aSVipin KUMAR 849dc3e7739SVipin KUMAR /* 850dc3e7739SVipin KUMAR * This endpoint0 specific register can be programmed only 851dc3e7739SVipin KUMAR * after the phy clock is initialized 852dc3e7739SVipin KUMAR */ 853dc3e7739SVipin KUMAR writel((EP0_MAX_PACKET_SIZE << 19) | ENDP_EPTYPE_CNTL, 854dc3e7739SVipin KUMAR &udc_regs_p->udc_endp_reg[0]); 855dc3e7739SVipin KUMAR 8562721551aSVipin KUMAR UDCDBG("device reset in progess"); 8572721551aSVipin KUMAR udc_state_transition(udc_device->device_state, STATE_DEFAULT); 8582721551aSVipin KUMAR } 8592721551aSVipin KUMAR 8602721551aSVipin KUMAR /* Device Enumeration completed */ 8612721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) { 8622721551aSVipin KUMAR writel(DEV_INT_ENUM, &udc_regs_p->dev_int); 8632721551aSVipin KUMAR 8642721551aSVipin KUMAR /* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */ 8652721551aSVipin KUMAR writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001, 8662721551aSVipin KUMAR &udc_regs_p->endp_int_mask); 8672721551aSVipin KUMAR 8682721551aSVipin KUMAR UDCDBG("default -> addressed"); 8692721551aSVipin KUMAR udc_state_transition(udc_device->device_state, STATE_ADDRESSED); 8702721551aSVipin KUMAR } 8712721551aSVipin KUMAR 8722721551aSVipin KUMAR /* The USB will be in SUSPEND in 3 ms */ 8732721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) { 8742721551aSVipin KUMAR writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int); 8752721551aSVipin KUMAR 8762721551aSVipin KUMAR UDCDBG("entering inactive state"); 8772721551aSVipin KUMAR /* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */ 8782721551aSVipin KUMAR } 8792721551aSVipin KUMAR 8802721551aSVipin KUMAR /* SetConfiguration command received */ 8812721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) { 8822721551aSVipin KUMAR writel(DEV_INT_SETCFG, &udc_regs_p->dev_int); 8832721551aSVipin KUMAR 8842721551aSVipin KUMAR UDCDBG("entering configured state"); 8852721551aSVipin KUMAR udc_state_transition(udc_device->device_state, 8862721551aSVipin KUMAR STATE_CONFIGURED); 8872721551aSVipin KUMAR } 8882721551aSVipin KUMAR 8892721551aSVipin KUMAR /* SetInterface command received */ 8902721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF) 8912721551aSVipin KUMAR writel(DEV_INT_SETINTF, &udc_regs_p->dev_int); 8922721551aSVipin KUMAR 8932721551aSVipin KUMAR /* USB Suspend detected on cable */ 8942721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) { 8952721551aSVipin KUMAR writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int); 8962721551aSVipin KUMAR 8972721551aSVipin KUMAR UDCDBG("entering suspended state"); 8982721551aSVipin KUMAR usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); 8992721551aSVipin KUMAR } 9002721551aSVipin KUMAR 9012721551aSVipin KUMAR /* USB Start-Of-Frame detected on cable */ 9022721551aSVipin KUMAR if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF) 9032721551aSVipin KUMAR writel(DEV_INT_SOF, &udc_regs_p->dev_int); 9042721551aSVipin KUMAR } 9052721551aSVipin KUMAR 9062721551aSVipin KUMAR /* 9072721551aSVipin KUMAR * Endpoint interrupt handling 9082721551aSVipin KUMAR */ 9094df4f3c9SAmit Virdi static void dw_udc_endpoint_irq(void) 9102721551aSVipin KUMAR { 9112721551aSVipin KUMAR while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) { 9122721551aSVipin KUMAR 9132721551aSVipin KUMAR writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int); 9142721551aSVipin KUMAR 9152721551aSVipin KUMAR if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK) 9162721551aSVipin KUMAR == ENDP_STATUS_OUT_SETUP) { 9172721551aSVipin KUMAR dw_udc_setup(udc_device->bus->endpoint_array + 0); 9182721551aSVipin KUMAR writel(ENDP_STATUS_OUT_SETUP, 9192721551aSVipin KUMAR &outep_regs_p[0].endp_status); 9202721551aSVipin KUMAR 9212721551aSVipin KUMAR } else if ((readl(&outep_regs_p[0].endp_status) & 9222721551aSVipin KUMAR ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { 9232721551aSVipin KUMAR dw_udc_ep0_rx(udc_device->bus->endpoint_array + 0); 9242721551aSVipin KUMAR writel(ENDP_STATUS_OUT_DATA, 9252721551aSVipin KUMAR &outep_regs_p[0].endp_status); 9262721551aSVipin KUMAR 9272721551aSVipin KUMAR } else if ((readl(&outep_regs_p[0].endp_status) & 9282721551aSVipin KUMAR ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { 9292721551aSVipin KUMAR /* NONE received */ 9302721551aSVipin KUMAR } 9312721551aSVipin KUMAR 9322721551aSVipin KUMAR writel(0x0, &outep_regs_p[0].endp_status); 9332721551aSVipin KUMAR } 9342721551aSVipin KUMAR 9352721551aSVipin KUMAR if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) { 9362721551aSVipin KUMAR dw_udc_ep0_tx(udc_device->bus->endpoint_array + 0); 9372721551aSVipin KUMAR 9382721551aSVipin KUMAR writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status); 9392721551aSVipin KUMAR writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int); 9402721551aSVipin KUMAR } 9412721551aSVipin KUMAR 942dc3e7739SVipin KUMAR if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) { 9432721551aSVipin KUMAR u32 epnum = 0; 9442721551aSVipin KUMAR u32 ep_int = readl(&udc_regs_p->endp_int) & 9452721551aSVipin KUMAR ENDP_INT_NONISOOUT_MSK; 9462721551aSVipin KUMAR 9472721551aSVipin KUMAR ep_int >>= 16; 9482721551aSVipin KUMAR while (0x0 == (ep_int & 0x1)) { 9492721551aSVipin KUMAR ep_int >>= 1; 9502721551aSVipin KUMAR epnum++; 9512721551aSVipin KUMAR } 9522721551aSVipin KUMAR 9532721551aSVipin KUMAR writel((1 << 16) << epnum, &udc_regs_p->endp_int); 9542721551aSVipin KUMAR 9552721551aSVipin KUMAR if ((readl(&outep_regs_p[epnum].endp_status) & 9562721551aSVipin KUMAR ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { 9572721551aSVipin KUMAR 9582721551aSVipin KUMAR dw_udc_epn_rx(epnum); 9592721551aSVipin KUMAR writel(ENDP_STATUS_OUT_DATA, 9602721551aSVipin KUMAR &outep_regs_p[epnum].endp_status); 9612721551aSVipin KUMAR } else if ((readl(&outep_regs_p[epnum].endp_status) & 9622721551aSVipin KUMAR ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { 9632721551aSVipin KUMAR writel(0x0, &outep_regs_p[epnum].endp_status); 9642721551aSVipin KUMAR } 9652721551aSVipin KUMAR } 9662721551aSVipin KUMAR 9672721551aSVipin KUMAR if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) { 9682721551aSVipin KUMAR u32 epnum = 0; 9692721551aSVipin KUMAR u32 ep_int = readl(&udc_regs_p->endp_int) & 9702721551aSVipin KUMAR ENDP_INT_NONISOIN_MSK; 9712721551aSVipin KUMAR 9722721551aSVipin KUMAR while (0x0 == (ep_int & 0x1)) { 9732721551aSVipin KUMAR ep_int >>= 1; 9742721551aSVipin KUMAR epnum++; 9752721551aSVipin KUMAR } 9762721551aSVipin KUMAR 9772721551aSVipin KUMAR if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) { 9782721551aSVipin KUMAR writel(ENDP_STATUS_IN, 9792721551aSVipin KUMAR &outep_regs_p[epnum].endp_status); 9802721551aSVipin KUMAR dw_udc_epn_tx(epnum); 9812721551aSVipin KUMAR 9822721551aSVipin KUMAR writel(ENDP_STATUS_IN, 9832721551aSVipin KUMAR &outep_regs_p[epnum].endp_status); 9842721551aSVipin KUMAR } 9852721551aSVipin KUMAR 9862721551aSVipin KUMAR writel((1 << epnum), &udc_regs_p->endp_int); 9872721551aSVipin KUMAR } 9882721551aSVipin KUMAR } 9892721551aSVipin KUMAR 9902721551aSVipin KUMAR /* 9912721551aSVipin KUMAR * UDC interrupts 9922721551aSVipin KUMAR */ 9932721551aSVipin KUMAR void udc_irq(void) 9942721551aSVipin KUMAR { 9952721551aSVipin KUMAR /* 9962721551aSVipin KUMAR * Loop while we have interrupts. 9972721551aSVipin KUMAR * If we don't do this, the input chain 9982721551aSVipin KUMAR * polling delay is likely to miss 9992721551aSVipin KUMAR * host requests. 10002721551aSVipin KUMAR */ 10012721551aSVipin KUMAR while (readl(&plug_regs_p->plug_pending)) 10022721551aSVipin KUMAR dw_udc_plug_irq(); 10032721551aSVipin KUMAR 10042721551aSVipin KUMAR while (readl(&udc_regs_p->dev_int)) 10052721551aSVipin KUMAR dw_udc_dev_irq(); 10062721551aSVipin KUMAR 10072721551aSVipin KUMAR if (readl(&udc_regs_p->endp_int)) 10082721551aSVipin KUMAR dw_udc_endpoint_irq(); 10092721551aSVipin KUMAR } 10102721551aSVipin KUMAR 10112721551aSVipin KUMAR /* Flow control */ 10122721551aSVipin KUMAR void udc_set_nak(int epid) 10132721551aSVipin KUMAR { 10142721551aSVipin KUMAR writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, 10152721551aSVipin KUMAR &inep_regs_p[epid].endp_cntl); 10162721551aSVipin KUMAR 10172721551aSVipin KUMAR writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, 10182721551aSVipin KUMAR &outep_regs_p[epid].endp_cntl); 10192721551aSVipin KUMAR } 10202721551aSVipin KUMAR 10212721551aSVipin KUMAR void udc_unset_nak(int epid) 10222721551aSVipin KUMAR { 10232721551aSVipin KUMAR u32 val; 10242721551aSVipin KUMAR 10252721551aSVipin KUMAR val = readl(&inep_regs_p[epid].endp_cntl); 10262721551aSVipin KUMAR val &= ~ENDP_CNTL_SNAK; 10272721551aSVipin KUMAR val |= ENDP_CNTL_CNAK; 10282721551aSVipin KUMAR writel(val, &inep_regs_p[epid].endp_cntl); 10292721551aSVipin KUMAR 10302721551aSVipin KUMAR val = readl(&outep_regs_p[epid].endp_cntl); 10312721551aSVipin KUMAR val &= ~ENDP_CNTL_SNAK; 10322721551aSVipin KUMAR val |= ENDP_CNTL_CNAK; 10332721551aSVipin KUMAR writel(val, &outep_regs_p[epid].endp_cntl); 10342721551aSVipin KUMAR } 1035