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