[U-Boot] [PATCH v2] Support for PXA27X UDC.

Signed-off-by: Vivek Kutal vivek.kutal@azingo.com --- drivers/serial/usbtty.h | 4 +- drivers/usb/Makefile | 1 + drivers/usb/usbdcore_pxa27x.c | 712 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 337 +++++++++++++---- include/usbdcore_pxa27x.h | 68 ++++ 5 files changed, 1049 insertions(+), 73 deletions(-) create mode 100644 drivers/usb/usbdcore_pxa27x.c create mode 100644 include/usbdcore_pxa27x.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index ecefde5..5fe872e 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h @@ -27,8 +27,10 @@ #include <usbdcore.h> #if defined(CONFIG_PPC) #include <usbdcore_mpc8xx.h> -#elif defined(CONFIG_ARM) +#elif defined(CONFIG_OMAP1510) #include <usbdcore_omap1510.h> +#elif defined(CONFIG_PXA27X) +#include <usbdcore_pxa27x.h> #endif
#include <version_autogenerated.h> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index b306a65..0a1886a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -47,6 +47,7 @@ COBJS-y += usbdcore_ep0.o COBJS-$(CONFIG_OMAP1510) += usbdcore_omap1510.o COBJS-$(CONFIG_OMAP1610) += usbdcore_omap1510.o COBJS-$(CONFIG_MPC885_FAMILY) += usbdcore_mpc8xx.o +COBJS-$(CONFIG_PXA27X) += usbdcore_pxa27x.o endif
COBJS := $(COBJS-y) diff --git a/drivers/usb/usbdcore_pxa27x.c b/drivers/usb/usbdcore_pxa27x.c new file mode 100644 index 0000000..6dfbf3d --- /dev/null +++ b/drivers/usb/usbdcore_pxa27x.c @@ -0,0 +1,712 @@ +/* + * PXA27x USB device driver for u-boot. + * + * Copyright (C) 2007 Rodolfo Giometti giometti@linux.it + * Copyright (C) 2007 Eurotech S.p.A. info@eurotech.it + * Copyright (C) 2008 Vivek Kutal vivek.kutal@azingo.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + + +#include <common.h> +#include <config.h> +#include <asm/byteorder.h> +#include <usbdcore.h> +#include <usbdcore_ep0.h> +#include <asm/arch/hardware.h> +#include <usbdcore_pxa27x.h> + +#define UDC_MAX_ENDPOINTS 24 /* number of endpoints on this UDC */ + +static struct urb *ep0_urb = NULL; +static struct usb_device_instance *udc_device; +static int ep0state = EP0_IDLE; + +#ifdef USBDDBG +static void udc_dump_buffer(char *name, u8 *buf, int len) +{ + int i, p, flag = 1; + + usbdbg("%s - buf %p, len %d", name, buf, len); + for (i = p = 0; i < len; i++, p++) { + if (p == 0) { + flag = 0; + usbdbg("\t"); + } + + usbdbg("%02x ", buf[i]); + + if (p == 15) { + flag = 1; + usbdbg("\n"); + p = -1; + } + } + if (!flag) + usbdbg("\n"); +} +#else +#define udc_dump_buffer(name, buf, len) /* void */ +#endif + +static inline void udc_ack_int_UDCCR(int mask) +{ + USIR1 = mask | USIR1; +} + +/* + * If the endpoint has an active tx_urb, then the next packet of data from the + * URB is written to the tx FIFO. + * The total amount of data in the urb is given by urb->actual_length. + * The maximum amount of data that can be sent in any one packet is given by + * endpoint->tx_packetSize. + * The number of data bytes from this URB that have already been transmitted + * is given by endpoint->sent. + * endpoint->last is updated by this routine with the number of data bytes + * transmitted in this packet. + */ +static int udc_write_urb(struct usb_endpoint_instance *endpoint) +{ + struct urb *urb = endpoint->tx_urb; + int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + + u32 *addr32 = (u32 *) &UDCDN(ep_num), + *data32 = (u32 *) urb->buffer; + u8 *addr8 = (u8 *) &UDCDN(ep_num), + *data8 = (u8 *) urb->buffer; + unsigned int i, n, w, b, is_short; + int timeout = 2000; /* 2ms */ + + if (!urb || !urb->actual_length) + return -1; + + n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); + if (n <= 0) + return -1; + + usbdbg("write urb on ep %d", ep_num); +#if defined(USBDDBG) && defined(USBDPARANOIA) + usbdbg("urb: buf %p, buf_len %d, actual_len %d", + urb->buffer, urb->buffer_length, urb->actual_length); + usbdbg("endpoint: sent %d, tx_packetSize %d, last %d", + endpoint->sent, endpoint->tx_packetSize, endpoint->last); +#endif + + is_short = n != endpoint->tx_packetSize; + w = n / 4; + b = n % 4; + usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b); + udc_dump_buffer("urb write", data8 + endpoint->sent, n); + /* Prepare for data send */ + + if (ep_num) + UDCCSN(ep_num) = UDCCSR_PC; + + for (i = 0; i < w; i++) + *addr32 = data32[endpoint->sent/4 + i]; + for (i = 0; i < b; i++) + *addr8 = data8[endpoint->sent + w*4 + i]; + + /* Set "Packet Complete" if less data then tx_packetSize */ + if (is_short) + UDCCSN(ep_num) = ep_num ? UDCCSR_SP : UDCCSR0_IPR; + + /* Wait for data sent */ + while (!(UDCCSN(ep_num) & (ep_num ? UDCCSR_PC : UDCCSR0_IPR))) { + if (ep_num) { + if (timeout-- == 0) + return -1; + else + udelay(1); + }; + } + endpoint->last = n; + + if(ep_num) { + usbd_tx_complete(endpoint); + } else { + endpoint->sent += n; + endpoint->last -= n; + } + + if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) { + urb->actual_length = 0; + endpoint->sent = 0; + endpoint->last = 0; + } + + if ((endpoint->sent >= urb->actual_length) && (!ep_num)) { + usbdbg("ep0 IN stage done"); + if(is_short) + ep0state = EP0_IDLE; + else + ep0state = EP0_XFER_COMPLETE; + } + + return 0; +} + +static int udc_read_urb(struct usb_endpoint_instance *endpoint) +{ + struct urb *urb = endpoint->rcv_urb; + int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u32 *addr32 = (u32 *) &UDCDN(ep_num), + *data32 = (u32 *) urb->buffer; + unsigned int i, n, is_short ; + + usbdbg("read urb on ep %d", ep_num); +#if defined(USBDDBG) && defined(USBDPARANOIA) + usbdbg("urb: buf %p, buf_len %d, actual_len %d", + urb->buffer, urb->buffer_length, urb->actual_length); + usbdbg("endpoint: rcv_packetSize %d", + endpoint->rcv_packetSize); +#endif + + if (UDCCSN(ep_num) & UDCCSR_BNE) + n = UDCBCN(ep_num) & 0x3ff; + else /* zlp */ + n = 0; + is_short = n != endpoint->rcv_packetSize; + + usbdbg("n %d%s", n, is_short ? "-s" : ""); + for (i = 0; i < n; i += 4) + data32[urb->actual_length/4 + i/4] = *addr32; + + udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n); + + usbd_rcv_complete(endpoint, n, 0); + + return 0; +} + +static int udc_read_urb_ep0(void) +{ + u32 *addr32 = (u32 *) &UDCDN(0), + *data32 = (u32 *) ep0_urb->buffer; + u8 *addr8 = (u8 *) &UDCDN(0), + *data8 = (u8 *) ep0_urb->buffer; + unsigned int i, n, w, b; + + n = UDCBCR0; + w = n / 4; + b = n % 4; + + for (i = 0; i < w; i++) { + data32[ep0_urb->actual_length/4 + i] = *addr32; + ep0_urb->actual_length += 4; + } + + for (i = 0; i < b; i++ ) { + data8[ep0_urb->actual_length + w*4 + i] = *addr8; + ep0_urb->actual_length++; + } + + UDCCSR0 = UDCCSR0_OPC | UDCCSR0_IPR; + if(ep0_urb->actual_length == ep0_urb->device_request.wLength) + return 1; + return 0; +} + +static void udc_handle_ep0(struct usb_endpoint_instance *endpoint) +{ + u32 udccsr0 = UDCCSR0; + u32 *data = (u32 *) &ep0_urb->device_request; + int i; + + usbdbg("udccsr0 %x", udccsr0); + + /* Clear stall status */ + if (udccsr0 & UDCCSR0_SST) { + usberr("clear stall status"); + UDCCSR0 = UDCCSR0_SST; + ep0state = EP0_IDLE; + } + + /* previous request unfinished? non-error iff back-to-back ... */ + if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE) + ep0state = EP0_IDLE; + + switch (ep0state) { + case EP0_IDLE : + + udccsr0 = UDCCSR0; + /* Start control request? */ + if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) + == (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) { + + /* Read SETUP packet. + * SETUP packet size is 8 bytes (aka 2 words) + */ + usbdbg("try reading SETUP packet"); + for (i = 0; i < 2; i++) { + if ((UDCCSR0 & UDCCSR0_RNE) == 0) { + usberr("setup packet too short (%d)", i); + goto stall; + } + data[i] = UDCDR0; + } + UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA); + if ((UDCCSR0 & UDCCSR0_RNE) != 0) { + usberr("setup packet too long"); + goto stall; + } + + udc_dump_buffer("ep0 setup read", (u8 *) data, 8); + + if(ep0_urb->device_request.wLength == 0) { + + usbdbg("Zero Data control Packet\n"); + + if(ep0_recv_setup(ep0_urb)) { + usberr("Invalid Setup Packet\n"); + udc_dump_buffer("ep0 setup read", (u8 *) data, 8); + goto stall; + } + UDCCSR0 = UDCCSR0_IPR; + ep0state = EP0_IDLE; + } + else { + /* Check direction */ + if ((ep0_urb->device_request.bmRequestType + & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { + ep0state = EP0_OUT_DATA; + ep0_urb->buffer = (u8 *)ep0_urb->buffer_data; + ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data); + ep0_urb->actual_length = 0; + UDCCSR0 = UDCCSR0_IPR; + } + else { + /* The ep0_recv_setup function has already placed our + * response packet data in ep0_urb->buffer and the + * packet length in ep0_urb->actual_length. + */ + if (ep0_recv_setup(ep0_urb)) { +stall: + usberr("Invalid setup packet"); + udc_dump_buffer("ep0 setup read", (u8 *) data, 8); + ep0state= EP0_IDLE; + UDCCSR0 = UDCCSR0_SA|UDCCSR0_OPC | UDCCSR0_FST | UDCCS0_FTF; + return; + } + + endpoint->tx_urb = ep0_urb; + endpoint->sent = 0; + usbdbg("EP0_IN_DATA"); + ep0state = EP0_IN_DATA; + if(udc_write_urb(endpoint) < 0) + goto stall; + + } + } + return; + } + else if ((udccsr0 & (UDCCSR0_OPC |UDCCSR0_SA)) + == (UDCCSR0_OPC|UDCCSR0_SA)) { + usberr("Setup Active but no data. Stalling ....\n"); + goto stall; + } + else { + usbdbg("random early IRQs"); + /* Some random early IRQs: + * - we acked FST + * - IPR cleared + * - OPC got set, without SA (likely status stage) + */ + UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC); + + } + break; + + case EP0_OUT_DATA : + + if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { + if(udc_read_urb_ep0()) { +read_complete: + ep0state = EP0_IDLE; + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next EP0 transaction */ + udc_dump_buffer("ep0 setup read", (u8 *) data, 8); + usberr("can't parse setup packet\n"); + goto stall; + } + } + } + else if(!(udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_IPR)) { + if(ep0_urb->device_request.wLength == ep0_urb->actual_length) + goto read_complete; + usberr("Premature Status\n"); + ep0state = EP0_IDLE; + } + break; + + case EP0_IN_DATA : + /* GET_DESCRIPTOR etc */ + if (udccsr0 & UDCCSR0_OPC) { + UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF; + usberr("ep0in premature status"); + ep0state = EP0_IDLE; + } + else { + /* irq was IPR clearing */ + if(udc_write_urb(endpoint) < 0) { + usberr("ep0_write_error\n"); + goto stall; + } + } + break; + + case EP0_XFER_COMPLETE: + UDCCSR0 = UDCCSR0_IPR; + ep0state = EP0_IDLE; + break; + + default: + usbdbg("Default\n"); + } + USIR0 = USIR0_IR0; +} + +static void udc_handle_ep(struct usb_endpoint_instance *endpoint) +{ + int ep_addr = endpoint->endpoint_address; + int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; + + u32 flags = UDCCSN(ep_num) & (UDCCSR_SST | UDCCSR_TRN); + if (flags) + UDCCSN(ep_num) = flags; + + if (ep_isout) + udc_read_urb(endpoint); + else + udc_write_urb(endpoint); + + UDCCSN(ep_num) = UDCCSR_PC; +} + +static void udc_state_changed(void) +{ + int config, interface, alternate; + + UDCCR |= UDCCR_SMAC; + + config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S; + interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S; + alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S; + + usbdbg("New UDC settings are: conf %d - inter %d - alter %d", + config, interface, alternate); + + usbd_device_event_irq (udc_device, DEVICE_CONFIGURED, 0); + + UDCISR1 = UDCISR1_IRCC; +} + + + +void udc_irq(void) +{ + int handled; + struct usb_endpoint_instance *endpoint; + int ep_num, i; + u32 udcisr0; + + do { + handled = 0; + /* Suspend Interrupt Request */ + if (USIR1 & UDCCR_SUSIR) { + + usbdbg("Suspend\n"); + udc_ack_int_UDCCR(UDCCR_SUSIR); + handled = 1; + ep0state = EP0_IDLE; + } + + /* Resume Interrupt Request */ + if (USIR1 & UDCCR_RESIR) { + udc_ack_int_UDCCR(UDCCR_RESIR); + handled = 1; + usbdbg( "USB resume\n"); + + } + + if (USIR1 & (1<<31) ){ + handled=1; + udc_state_changed(); + } + + /* Reset Interrupt Request */ + if (USIR1 & UDCCR_RSTIR) { + udc_ack_int_UDCCR(UDCCR_RSTIR); + handled = 1; + usbdbg("Reset\n"); + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + } else { + if(USIR0) + usbdbg("UISR0: %x \n",USIR0); + + if (USIR0 & 0x2) USIR0 = 0x2; + + /* Control traffic */ + if (USIR0 & USIR0_IR0) { + handled = 1; + udc_handle_ep0(udc_device->bus->endpoint_array); + USIR0 = USIR0_IR0; + } + + endpoint = udc_device->bus->endpoint_array; + for (i = 0; i < udc_device->bus->max_endpoints; i++) { + ep_num = (endpoint[i].endpoint_address) & USB_ENDPOINT_NUMBER_MASK; + if (!ep_num) + continue; + udcisr0 = UDCISR0; + if (udcisr0 & UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) { + UDCISR0 = UDCISR_INT(ep_num, UDC_INT_PACKETCMP); + udc_handle_ep(&endpoint[i]); + + } + } + + } + + } while (handled); +} + +/* The UDCCR reg contains mask and interrupt status bits, + * so using '|=' isn't safe as it may ack an interrupt. + */ +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_UDE) + +static inline void udc_set_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); +} + +static inline void udc_clear_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); +} + + +static void pio_irq_enable(int ep_num) +{ + if (ep_num < 16) + UDCICR0 |= 3 << (ep_num * 2); + else { + ep_num -= 16; + UDCICR1 |= 3 << (ep_num * 2); + } +} + +/* + * udc_set_nak + * + * Allow upper layers to signal lower layers should not accept more RX data + */ +void udc_set_nak(int ep_num) +{ + /* TODO */ +} + +/* + * udc_unset_nak + * + * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. + * Switch off NAKing on this endpoint to accept more data output from host. + */ +void udc_unset_nak(int ep_num) +{ + /* TODO */ +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ + return udc_write_urb(endpoint); +} + +/* Associate a physical endpoint with endpoint instance */ +void udc_setup_ep(struct usb_device_instance *device, unsigned int id, struct usb_endpoint_instance *endpoint) +{ + int ep_num, ep_addr, ep_isout, ep_type, ep_size; + int config, interface, alternate; + u32 tmp; + + usbdbg("setting up endpoint id %d", id); + + if (!endpoint) { + usberr("endpoint void!"); + return; + } + + ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + if (ep_num >= UDC_MAX_ENDPOINTS) { + usberr("unable to setup ep %d!",ep_num); + return; + } + + pio_irq_enable(ep_num); + if (ep_num == 0) { + /* Done for ep0 */ + return; + } + + config = 1; + interface = 0; + alternate = 0; + + usbdbg("config %d - interface %d - alternate %d", + config, interface, alternate); + + ep_addr = endpoint->endpoint_address; + ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; + ep_type = ep_isout ? endpoint->rcv_attributes : endpoint->tx_attributes; + ep_size = ep_isout ? endpoint->rcv_packetSize : endpoint->tx_packetSize; + + usbdbg("addr %x, num %d, dir %s, type %s, packet size %d", + ep_addr, ep_num, + ep_isout ? "out" : "in", + ep_type == USB_ENDPOINT_XFER_ISOC ? "isoc" : + ep_type == USB_ENDPOINT_XFER_BULK ? "bulk" : + ep_type == USB_ENDPOINT_XFER_INT ? "int" : "???", + ep_size + ); + + /* Configure UDCCRx */ + tmp = 0; + tmp |= (config << UDCCONR_CN_S) & UDCCONR_CN; + tmp |= (interface << UDCCONR_IN_S) & UDCCONR_IN; + tmp |= (alternate << UDCCONR_AISN_S) & UDCCONR_AISN; + tmp |= (ep_num << UDCCONR_EN_S) & UDCCONR_EN; + tmp |= (ep_type << UDCCONR_ET_S) & UDCCONR_ET; + tmp |= ep_isout ? 0 : UDCCONR_ED; + tmp |= (ep_size << UDCCONR_MPS_S ) & UDCCONR_MPS; + tmp |= /* UDCCONR_DE | */ UDCCONR_EE; + + UDCCN(ep_num) = tmp; + + usbdbg("UDCCR%c = %x", 'A' + ep_num-1, UDCCN(ep_num)); + usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, UDCCSN(ep_num)); +} + + + +#define CONFIG_USB_DEV_PULLUP_GPIO 87 + +/* Connect the USB device to the bus */ +void udc_connect(void) +{ + usbdbg("UDC connect"); + + /* Turn on the USB connection by enabling the pullup resistor */ + set_GPIO_mode(CONFIG_USB_DEV_PULLUP_GPIO | GPIO_OUT); + GPSR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO); +} + +/* Disconnect the USB device to the bus */ +void udc_disconnect(void) +{ + usbdbg("UDC disconnect"); + + /* Turn off the USB connection by disabling the pullup resistor */ + GPCR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO); +} + +/* Switch on the UDC */ +void udc_enable(struct usb_device_instance *device) +{ + + ep0state = EP0_IDLE; + CKEN |= CKEN11_USB; + + /* enable endpoint 0, A, B's Packet Complete Interrupt. */ + UDCICR0 = 0x0000003f; + UDCICR1 = 0xa8000000; + + /* clear the interrupt status/control registers */ + UDCISR0 = 0xffffffff; + UDCISR1 = 0xffffffff; + + /* set UDC-enable */ + udc_set_mask_UDCCR( UDCCR_UDE); + + udc_device = device; + if (!ep0_urb) + ep0_urb = usbd_alloc_urb(udc_device,udc_device->bus->endpoint_array); + else + usbinfo("ep0_urb %p already allocated", ep0_urb); + + usbdbg("UDC Enabled\n"); +} + +/* Need to check this again */ +void udc_disable(void) +{ + usbdbg("disable UDC"); + + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + CKEN &= ~CKEN11_USB; + + /* Free ep0 URB */ + if (ep0_urb) { + usbd_dealloc_urb(ep0_urb); + ep0_urb = NULL; + } + + /* Reset device pointer */ + udc_device = NULL; +} + +/* Allow udc code to do any additional startup */ +void udc_startup_events(struct usb_device_instance *device) +{ + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT */ + usbd_device_event_irq(device, DEVICE_INIT, 0); + + /* The DEVICE_CREATE event puts the USB device in the state + * STATE_ATTACHED */ + usbd_device_event_irq(device, DEVICE_CREATE, 0); + + /* Some USB controller driver implementations signal + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. + * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, + * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. + */ + udc_enable(device); +} + +/* Initialize h/w stuff */ +int udc_init(void) +{ + udc_device = NULL; + usbdbg("PXA27x usbd start"); + + /* Disable the UDC */ + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + CKEN &= ~CKEN11_USB; + + /* Disable IRQs: we don't use them */ + UDCICR0 = UDCICR1 = 0; + + return 0; +} diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index e014568..7aeac1e 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -596,56 +596,68 @@ typedef void (*ExcpHndlr) (void) ; /* * USB Device Controller */ -#ifndef CONFIG_CPU_MONAHANS -#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ -#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ -#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ - -#define UDCCR __REG(0x40600000) /* UDC Control Register */ -#define UDCCR_UDE (1 << 0) /* UDC enable */ -#define UDCCR_UDA (1 << 1) /* UDC active */ -#define UDCCR_RSM (1 << 2) /* Device resume */ -#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ -#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ -#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ -#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ -#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ - -#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ -#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ -#define UDCCS0_IPR (1 << 1) /* IN packet ready */ -#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ -#define UDCCS0_SST (1 << 4) /* Sent stall */ -#define UDCCS0_FST (1 << 5) /* Force stall */ -#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ -#define UDCCS0_SA (1 << 7) /* Setup active */ +#ifdef CONFIG_PXA27X + +#define UDCCR __REG(0x40600000) /* UDC Control Register */ +#define UDCCR_UDE (1 << 0) /* UDC enable */ +#define UDCCR_UDA (1 << 1) /* UDC active */ +#define UDCCR_RSM (1 << 2) /* Device resume */ +#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration Error */ +#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active Configuration */ +#define UDCCR_RESIR (1 << 29) /* Resume interrupt request */ +#define UDCCR_SUSIR (1 << 28) /* Suspend interrupt request */ +#define UDCCR_SM (1 << 28) /* Suspend interrupt mask */ +#define UDCCR_RSTIR (1 << 27) /* Reset interrupt request */ +#define UDCCR_REM (1 << 27) /* Reset interrupt mask */ +#define UDCCR_RM (1 << 29) /* resume interrupt mask */ +#define UDCCR_SRM UDCCR_SM|UDCCR_RM +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation Protocol Port Support */ +#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol Support */ +#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol Enable */ +#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ +#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ +#define UDCCR_ACN_S 11 +#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ +#define UDCCR_AIN_S 8 +#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface Setting Number */ +#define UDCCR_AAISN_S 5 + +#define UDCCS0 __REG(0x40600100) /* UDC Endpoint 0 Control/Status Register */ +#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ +#define UDCCS0_IPR (1 << 1) /* IN packet ready */ +#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS0_DRWF (1 << 16) /* Device remote wakeup feature */ +#define UDCCS0_SST (1 << 4) /* Sent stall */ +#define UDCCS0_FST (1 << 5) /* Force stall */ +#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ +#define UDCCS0_SA (1 << 7) /* Setup active */
/* Bulk IN - Endpoint 1,6,11 */ -#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ -#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ -#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */ - -#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ -#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ -#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ -#define UDCCS_BI_SST (1 << 4) /* Sent stall */ -#define UDCCS_BI_FST (1 << 5) /* Force stall */ -#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */ +#define UDCCS1 __REG(0x40600104) /* UDC Endpoint 1 (IN) Control/Status Register */ +#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ +#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */ + +#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ +#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ +#define UDCCS_BI_FTF (1 << 8) /* Flush Tx FIFO */ +#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ +#define UDCCS_BI_SST (1 << 4) /* Sent stall */ +#define UDCCS_BI_FST (1 << 5) /* Force stall */ +#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
/* Bulk OUT - Endpoint 2,7,12 */ -#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ -#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ -#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */ - -#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ -#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ -#define UDCCS_BO_DME (1 << 3) /* DMA enable */ -#define UDCCS_BO_SST (1 << 4) /* Sent stall */ -#define UDCCS_BO_FST (1 << 5) /* Force stall */ -#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ -#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */ +#define UDCCS2 __REG(0x40600108) /* UDC Endpoint 2 (OUT) Control/Status Register */ +#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ +#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */ + +#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ +#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ +#define UDCCS_BO_DME (1 << 3) /* DMA enable */ +#define UDCCS_BO_SST (1 << 4) /* Sent stall */ +#define UDCCS_BO_FST (1 << 5) /* Force stall */ +#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ +#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */
/* Isochronous IN - Endpoint 3,8,13 */ #define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */ @@ -684,16 +696,16 @@ typedef void (*ExcpHndlr) (void) ; #define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ -#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ -#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ +#define UFNRL __REG(0x40600014) /* UDC Frame Number Register Low */ +#define UBCR2 __REG(0x40600208) /* UDC Byte Count Reg 2 */ #define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ #define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ #define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ #define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ #define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ -#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ -#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ -#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ +#define UDDR0 __REG(0x40600300) /* UDC Endpoint 0 Data Register */ +#define UDDR1 __REG(0x40600304) /* UDC Endpoint 1 Data Register */ +#define UDDR2 __REG(0x40600308) /* UDC Endpoint 2 Data Register */ #define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ #define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ #define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ @@ -708,7 +720,7 @@ typedef void (*ExcpHndlr) (void) ; #define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ #define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */
-#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ +#define UICR0 __REG(0x40600004) /* UDC Interrupt Control Register 0 */
#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ #define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ @@ -719,7 +731,7 @@ typedef void (*ExcpHndlr) (void) ; #define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ #define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
-#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ +#define UICR1 __REG(0x40600008) /* UDC Interrupt Control Register 1 */
#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ #define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ @@ -730,18 +742,18 @@ typedef void (*ExcpHndlr) (void) ; #define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ #define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
-#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ +#define USIR0 __REG(0x4060000C) /* UDC Status Interrupt Register 0 */
#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */ -#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */ -#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */ +#define USIR0_IR1 (1 << 2) /* Interrup request ep 1 */ +#define USIR0_IR2 (1 << 4) /* Interrup request ep 2 */ #define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */ #define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */ #define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */ #define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */ #define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */
-#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ +#define USIR1 __REG(0x40600010) /* UDC Status Interrupt Register 1 */
#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */ #define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */ @@ -751,23 +763,204 @@ typedef void (*ExcpHndlr) (void) ; #define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */ #define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */ #define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */ -#endif /* ! CONFIG_CPU_MONAHANS */
-#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
-/* - * USB Client Controller (incomplete) - */ -#define UDCCR __REG(0x40600000) -#define UDCICR0 __REG(0x40600004) -#define UDCCIR0 __REG(0x40600008) -#define UDCISR0 __REG(0x4060000c) -#define UDCSIR1 __REG(0x40600010) -#define UDCFNR __REG(0x40600014) -#define UDCOTGICR __REG(0x40600018) -#define UDCOTGISR __REG(0x4060001c) -#define UP2OCR __REG(0x40600020) -#define UP3OCR __REG(0x40600024) +#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */ +#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */ +#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ +#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ + +#define UDCICR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ +#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ +#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ +#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ + +#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */ +#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */ +#define UDCISR_INT(n,intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCISR1_IRCC (1 << 31) /* IntEn - Configuration Change */ +#define UDCISR1_IRSOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCISR1_IRRU (1 << 29) /* IntEn - Resume */ +#define UDCISR1_IRSU (1 << 28) /* IntEn - Suspend */ +#define UDCISR1_IRRS (1 << 27) /* IntEn - Reset */ + + +#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */ +#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */ +#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ +#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge Interrupt Enable */ +#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge Interrupt Enable */ +#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge Interrupt Enable */ +#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising Edge Interrupt Enable */ +#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge Interrupt Enable */ + +#define UDCCSN(x) __REG2(0x40600100, (x) << 2) +#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ + +#define UDCCSR0_SA (1 << 7) /* Setup Active */ +#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ +#define UDCCSR0_FST (1 << 5) /* Force Stall */ +#define UDCCSR0_SST (1 << 4) /* Sent Stall */ +#define UDCCSR0_DME (1 << 3) /* DMA Enable */ +#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ +#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ +#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ + +#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */ +#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */ +#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */ +#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */ +#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */ +#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */ +#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */ +#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */ +#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */ +#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */ +#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */ +#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */ +#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */ +#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */ +#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */ +#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */ +#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */ +#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */ +#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */ +#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */ +#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */ +#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */ +#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */ + +#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ +#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ +#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ +#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ +#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ +#define UDCCSR_FST (1 << 5) /* Force STALL */ +#define UDCCSR_SST (1 << 4) /* Sent STALL */ +#define UDCCSR_DME (1 << 3) /* DMA Enable */ +#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ +#define UDCCSR_PC (1 << 1) /* Packet Complete */ +#define UDCCSR_FS (1 << 0) /* FIFO needs service */ + +#define UDCBCN(x) __REG2(0x40600200, (x)<<2) +#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */ +#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */ +#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */ +#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */ +#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */ +#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */ +#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */ +#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */ +#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */ +#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */ +#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */ +#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */ +#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */ +#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */ +#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */ +#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */ +#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */ +#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */ +#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */ +#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */ +#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */ +#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */ +#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */ +#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */ + +#define UDCDN(x) __REG2(0x40600300, (x)<<2) +#define PHYS_UDCDN(x) (0x40600300 + ((x)<<2)) +#define PUDCDN(x) (volatile u32 *)(io_p2v(PHYS_UDCDN((x)))) +#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */ +#define UDCDRA __REG(0x40600304) /* Data Register - EPA */ +#define UDCDRB __REG(0x40600308) /* Data Register - EPB */ +#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */ +#define UDCDRD __REG(0x40600310) /* Data Register - EPD */ +#define UDCDRE __REG(0x40600314) /* Data Register - EPE */ +#define UDCDRF __REG(0x40600318) /* Data Register - EPF */ +#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */ +#define UDCDRH __REG(0x40600320) /* Data Register - EPH */ +#define UDCDRI __REG(0x40600324) /* Data Register - EPI */ +#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */ +#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */ +#define UDCDRL __REG(0x40600330) /* Data Register - EPL */ +#define UDCDRM __REG(0x40600334) /* Data Register - EPM */ +#define UDCDRN __REG(0x40600338) /* Data Register - EPN */ +#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */ +#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */ +#define UDCDRR __REG(0x40600344) /* Data Register - EPR */ +#define UDCDRS __REG(0x40600348) /* Data Register - EPS */ +#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */ +#define UDCDRU __REG(0x40600350) /* Data Register - EPU */ +#define UDCDRV __REG(0x40600354) /* Data Register - EPV */ +#define UDCDRW __REG(0x40600358) /* Data Register - EPW */ +#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */ + +#define UDCCN(x) __REG2(0x40600400, (x)<<2) +#define UDCCRA __REG(0x40600404) /* Configuration register EPA */ +#define UDCCRB __REG(0x40600408) /* Configuration register EPB */ +#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */ +#define UDCCRD __REG(0x40600410) /* Configuration register EPD */ +#define UDCCRE __REG(0x40600414) /* Configuration register EPE */ +#define UDCCRF __REG(0x40600418) /* Configuration register EPF */ +#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */ +#define UDCCRH __REG(0x40600420) /* Configuration register EPH */ +#define UDCCRI __REG(0x40600424) /* Configuration register EPI */ +#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */ +#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */ +#define UDCCRL __REG(0x40600430) /* Configuration register EPL */ +#define UDCCRM __REG(0x40600434) /* Configuration register EPM */ +#define UDCCRN __REG(0x40600438) /* Configuration register EPN */ +#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */ +#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */ +#define UDCCRR __REG(0x40600444) /* Configuration register EPR */ +#define UDCCRS __REG(0x40600448) /* Configuration register EPS */ +#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */ +#define UDCCRU __REG(0x40600450) /* Configuration register EPU */ +#define UDCCRV __REG(0x40600454) /* Configuration register EPV */ +#define UDCCRW __REG(0x40600458) /* Configuration register EPW */ +#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */ + +#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ +#define UDCCONR_CN_S (25) +#define UDCCONR_IN (0x07 << 22) /* Interface Number */ +#define UDCCONR_IN_S (22) +#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ +#define UDCCONR_AISN_S (19) +#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ +#define UDCCONR_EN_S (15) +#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ +#define UDCCONR_ET_S (13) +#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ +#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ +#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ +#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ +#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ +#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ +#define UDCCONR_MPS_S (2) +#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ +#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ + + +#define UDC_INT_FIFOERROR (0x2) +#define UDC_INT_PACKETCMP (0x1) +#define UDC_FNR_MASK (0x7ff) +#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST) +#define UDC_BCR_MASK (0x3ff) + + +#endif /* CONFIG_PXA27X */ + +#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
/* * USB Host Controller diff --git a/include/usbdcore_pxa27x.h b/include/usbdcore_pxa27x.h new file mode 100644 index 0000000..81bf3fb --- /dev/null +++ b/include/usbdcore_pxa27x.h @@ -0,0 +1,68 @@ +/* + * PXA27x register declarations and HCD data structures + * + * Copyright (C) 2007 Rodolfo Giometti giometti@linux.it + * Copyright (C) 2007 Eurotech S.p.A. info@eurotech.it + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __USBDCORE_PXA270X_H__ +#define __USBDCORE_PXA270X_H__ + +#include <asm/byteorder.h> + +/* Endpoint 0 states */ +#define EP0_IDLE 0 +#define EP0_IN_DATA 1 +#define EP0_OUT_DATA 2 +#define EP0_XFER_COMPLETE 3 + + +/* Endpoint parameters */ +#define MAX_ENDPOINTS 4 +#define EP_MAX_PACKET_SIZE 64 + +#define EP0_MAX_PACKET_SIZE 16 +#define UDC_OUT_ENDPOINT 0x02 +#define UDC_OUT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_IN_ENDPOINT 0x01 +#define UDC_IN_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_INT_ENDPOINT 0x05 +#define UDC_INT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_BULK_PACKET_SIZE EP_MAX_PACKET_SIZE + +void udc_irq (void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak (int epid); + +/* Higher level functions for abstracting away from specific device */ +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +int udc_init (void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, struct usb_endpoint_instance *endpoint); + +#endif

Hello Vivek,
2009/2/23 Vivek Kutal vivek.kutal@azingo.com:
Signed-off-by: Vivek Kutal vivek.kutal@azingo.com
Missing proper description of this patch.
drivers/serial/usbtty.h | 4 +- drivers/usb/Makefile | 1 + drivers/usb/usbdcore_pxa27x.c | 712 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 337 +++++++++++++---- include/usbdcore_pxa27x.h | 68 ++++ 5 files changed, 1049 insertions(+), 73 deletions(-) create mode 100644 drivers/usb/usbdcore_pxa27x.c create mode 100644 include/usbdcore_pxa27x.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index ecefde5..5fe872e 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h
I get 46 errors and 101 warnings while running linux/checkpatch.pl on this patch. Please clean up and resubmit.
Kind Regards,
Remy

Hi Remy, There are around ~70 warnings generated for pxa-regs.h for having more than 80 chars in a line, I have taken all the macro definitions from the linux kernel source code should I fix those warnings too ? Also pxa-regs.h already has many line with more than 80 chars.
-- Thanks Vivek Kutal

Hello Vivek,
2009/3/6 Vivek Kutal vivek.kutal@azingo.com:
Hi Remy, There are around ~70 warnings generated for pxa-regs.h for having more than 80 chars in a line, I have taken all the macro definitions from the linux kernel source code should I fix those warnings too ? Also pxa-regs.h already has many line with more than 80 chars.
Thanks for asking. If you look here: http://www.denx.de/wiki/U-Boot/CodingStyle, you will see that source files originating from different projects (for example the MTD subsystem or the hush shell code from the BusyBox project) may, after careful consideration, be exempted from these rules. For such files, the original coding style may be kept to ease subsequent migration to newer versions of those sources. Maybe you should also read this: http://www.denx.de/wiki/U-Boot/Patches
Kind regards,
Remy

This Patch adds Support for PXA27X UDC.
Signed-off-by: Vivek Kutal vivek.kutal@azingo.com --- Resending after code cleanup.
drivers/serial/usbtty.h | 4 +- drivers/usb/Makefile | 1 + drivers/usb/usbdcore_pxa27x.c | 719 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 296 ++++++++++++--- include/usbdcore_pxa27x.h | 69 ++++ 5 files changed, 1035 insertions(+), 54 deletions(-) create mode 100644 drivers/usb/usbdcore_pxa27x.c create mode 100644 include/usbdcore_pxa27x.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index ecefde5..5fe872e 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h @@ -27,8 +27,10 @@ #include <usbdcore.h> #if defined(CONFIG_PPC) #include <usbdcore_mpc8xx.h> -#elif defined(CONFIG_ARM) +#elif defined(CONFIG_OMAP1510) #include <usbdcore_omap1510.h> +#elif defined(CONFIG_PXA27X) +#include <usbdcore_pxa27x.h> #endif
#include <version_autogenerated.h> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index b306a65..0a1886a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -47,6 +47,7 @@ COBJS-y += usbdcore_ep0.o COBJS-$(CONFIG_OMAP1510) += usbdcore_omap1510.o COBJS-$(CONFIG_OMAP1610) += usbdcore_omap1510.o COBJS-$(CONFIG_MPC885_FAMILY) += usbdcore_mpc8xx.o +COBJS-$(CONFIG_PXA27X) += usbdcore_pxa27x.o endif
COBJS := $(COBJS-y) diff --git a/drivers/usb/usbdcore_pxa27x.c b/drivers/usb/usbdcore_pxa27x.c new file mode 100644 index 0000000..9674452 --- /dev/null +++ b/drivers/usb/usbdcore_pxa27x.c @@ -0,0 +1,719 @@ +/* + * PXA27x USB device driver for u-boot. + * + * Copyright (C) 2007 Rodolfo Giometti giometti@linux.it + * Copyright (C) 2007 Eurotech S.p.A. info@eurotech.it + * Copyright (C) 2008 Vivek Kutal vivek.kutal@azingo.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + + +#include <common.h> +#include <config.h> +#include <asm/byteorder.h> +#include <usbdcore.h> +#include <usbdcore_ep0.h> +#include <asm/arch/hardware.h> +#include <usbdcore_pxa27x.h> + +/* number of endpoints on this UDC */ +#define UDC_MAX_ENDPOINTS 24 + +static struct urb *ep0_urb; +static struct usb_device_instance *udc_device; +static int ep0state = EP0_IDLE; + +#ifdef USBDDBG +static void udc_dump_buffer(char *name, u8 *buf, int len) +{ + int i, p, flag = 1; + + usbdbg("%s - buf %p, len %d", name, buf, len); + for (i = p = 0; i < len; i++, p++) { + if (p == 0) { + flag = 0; + usbdbg("\t"); + } + + usbdbg("%02x ", buf[i]); + + if (p == 15) { + flag = 1; + usbdbg("\n"); + p = -1; + } + } + if (!flag) + usbdbg("\n"); +} +#else +#define udc_dump_buffer(name, buf, len) /* void */ +#endif + +static inline void udc_ack_int_UDCCR(int mask) +{ + USIR1 = mask | USIR1; +} + +/* + * If the endpoint has an active tx_urb, then the next packet of data from the + * URB is written to the tx FIFO. + * The total amount of data in the urb is given by urb->actual_length. + * The maximum amount of data that can be sent in any one packet is given by + * endpoint->tx_packetSize. + * The number of data bytes from this URB that have already been transmitted + * is given by endpoint->sent. + * endpoint->last is updated by this routine with the number of data bytes + * transmitted in this packet. + */ +static int udc_write_urb(struct usb_endpoint_instance *endpoint) +{ + struct urb *urb = endpoint->tx_urb; + int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + + u32 *addr32 = (u32 *) &UDCDN(ep_num), + *data32 = (u32 *) urb->buffer; + u8 *addr8 = (u8 *) &UDCDN(ep_num), + *data8 = (u8 *) urb->buffer; + unsigned int i, n, w, b, is_short; + int timeout = 2000; /* 2ms */ + + if (!urb || !urb->actual_length) + return -1; + + n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); + if (n <= 0) + return -1; + + usbdbg("write urb on ep %d", ep_num); +#if defined(USBDDBG) && defined(USBDPARANOIA) + usbdbg("urb: buf %p, buf_len %d, actual_len %d", + urb->buffer, urb->buffer_length, urb->actual_length); + usbdbg("endpoint: sent %d, tx_packetSize %d, last %d", + endpoint->sent, endpoint->tx_packetSize, endpoint->last); +#endif + + is_short = n != endpoint->tx_packetSize; + w = n / 4; + b = n % 4; + usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b); + udc_dump_buffer("urb write", data8 + endpoint->sent, n); + + /* Prepare for data send */ + if (ep_num) + UDCCSN(ep_num) = UDCCSR_PC; + + for (i = 0; i < w; i++) + *addr32 = data32[endpoint->sent/4 + i]; + for (i = 0; i < b; i++) + *addr8 = data8[endpoint->sent + w*4 + i]; + + /* Set "Packet Complete" if less data then tx_packetSize */ + if (is_short) + UDCCSN(ep_num) = ep_num ? UDCCSR_SP : UDCCSR0_IPR; + + /* Wait for data sent */ + while (!(UDCCSN(ep_num) & (ep_num ? UDCCSR_PC : UDCCSR0_IPR))) { + if (ep_num) { + if (timeout-- == 0) + return -1; + else + udelay(1); + }; + } + endpoint->last = n; + + if (ep_num) { + usbd_tx_complete(endpoint); + } else { + endpoint->sent += n; + endpoint->last -= n; + } + + if ((endpoint->tx_urb->actual_length - endpoint->sent) <= 0) { + urb->actual_length = 0; + endpoint->sent = 0; + endpoint->last = 0; + } + + if ((endpoint->sent >= urb->actual_length) && (!ep_num)) { + usbdbg("ep0 IN stage done"); + if (is_short) + ep0state = EP0_IDLE; + else + ep0state = EP0_XFER_COMPLETE; + } + + return 0; +} + +static int udc_read_urb(struct usb_endpoint_instance *endpoint) +{ + struct urb *urb = endpoint->rcv_urb; + int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u32 *addr32 = (u32 *) &UDCDN(ep_num), + *data32 = (u32 *) urb->buffer; + unsigned int i, n, is_short ; + + usbdbg("read urb on ep %d", ep_num); +#if defined(USBDDBG) && defined(USBDPARANOIA) + usbdbg("urb: buf %p, buf_len %d, actual_len %d", + urb->buffer, urb->buffer_length, urb->actual_length); + usbdbg("endpoint: rcv_packetSize %d", + endpoint->rcv_packetSize); +#endif + + if (UDCCSN(ep_num) & UDCCSR_BNE) + n = UDCBCN(ep_num) & 0x3ff; + else /* zlp */ + n = 0; + is_short = n != endpoint->rcv_packetSize; + + usbdbg("n %d%s", n, is_short ? "-s" : ""); + for (i = 0; i < n; i += 4) + data32[urb->actual_length/4 + i/4] = *addr32; + + udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n); + + usbd_rcv_complete(endpoint, n, 0); + + return 0; +} + +static int udc_read_urb_ep0(void) +{ + u32 *addr32 = (u32 *) &UDCDN(0); + u32 *data32 = (u32 *) ep0_urb->buffer; + u8 *addr8 = (u8 *) &UDCDN(0); + u8 *data8 = (u8 *) ep0_urb->buffer; + unsigned int i, n, w, b; + + n = UDCBCR0; + w = n / 4; + b = n % 4; + + for (i = 0; i < w; i++) { + data32[ep0_urb->actual_length/4 + i] = *addr32; + ep0_urb->actual_length += 4; + } + + for (i = 0; i < b; i++) { + data8[ep0_urb->actual_length + w*4 + i] = *addr8; + ep0_urb->actual_length++; + } + + UDCCSR0 = UDCCSR0_OPC | UDCCSR0_IPR; + if (ep0_urb->actual_length == ep0_urb->device_request.wLength) + return 1; + return 0; +} + +static void udc_handle_ep0(struct usb_endpoint_instance *endpoint) +{ + u32 udccsr0 = UDCCSR0; + u32 *data = (u32 *) &ep0_urb->device_request; + int i; + + usbdbg("udccsr0 %x", udccsr0); + + /* Clear stall status */ + if (udccsr0 & UDCCSR0_SST) { + usberr("clear stall status"); + UDCCSR0 = UDCCSR0_SST; + ep0state = EP0_IDLE; + } + + /* previous request unfinished? non-error iff back-to-back ... */ + if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE) + ep0state = EP0_IDLE; + + switch (ep0state) { + + case EP0_IDLE: + + udccsr0 = UDCCSR0; + /* Start control request? */ + if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) + == (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) { + + /* Read SETUP packet. + * SETUP packet size is 8 bytes (aka 2 words) + */ + usbdbg("try reading SETUP packet"); + for (i = 0; i < 2; i++) { + if ((UDCCSR0 & UDCCSR0_RNE) == 0) { + usberr("setup packet too short:%d", i); + goto stall; + } + data[i] = UDCDR0; + } + + UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA); + if ((UDCCSR0 & UDCCSR0_RNE) != 0) { + usberr("setup packet too long"); + goto stall; + } + + udc_dump_buffer("ep0 setup read", (u8 *) data, 8); + + if (ep0_urb->device_request.wLength == 0) { + usbdbg("Zero Data control Packet\n"); + if (ep0_recv_setup(ep0_urb)) { + usberr("Invalid Setup Packet\n"); + udc_dump_buffer("ep0 setup read", + (u8 *)data, 8); + goto stall; + } + UDCCSR0 = UDCCSR0_IPR; + ep0state = EP0_IDLE; + } else { + /* Check direction */ + if (ep0_urb->device_request.bmRequestType & + USB_REQ_DIRECTION_MASK == USB_REQ_HOST2DEVICE) { + ep0state = EP0_OUT_DATA; + ep0_urb->buffer = + (u8 *)ep0_urb->buffer_data; + ep0_urb->buffer_length = + sizeof(ep0_urb->buffer_data); + ep0_urb->actual_length = 0; + UDCCSR0 = UDCCSR0_IPR; + } else { + /* The ep0_recv_setup function has + * already placed our response packet + * data in ep0_urb->buffer and the + * packet length in + * ep0_urb->actual_length. + */ + if (ep0_recv_setup(ep0_urb)) { +stall: + usberr("Invalid setup packet"); + udc_dump_buffer("ep0 setup read" + , (u8 *) data, 8); + ep0state = EP0_IDLE; + + UDCCSR0 = UDCCSR0_SA | + UDCCSR0_OPC | UDCCSR0_FST | + UDCCS0_FTF; + + return; + } + + endpoint->tx_urb = ep0_urb; + endpoint->sent = 0; + usbdbg("EP0_IN_DATA"); + ep0state = EP0_IN_DATA; + if (udc_write_urb(endpoint) < 0) + goto stall; + + } + } + return; + } else if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA)) + == (UDCCSR0_OPC|UDCCSR0_SA)) { + usberr("Setup Active but no data. Stalling ....\n"); + goto stall; + } else { + usbdbg("random early IRQs"); + /* Some random early IRQs: + * - we acked FST + * - IPR cleared + * - OPC got set, without SA (likely status stage) + */ + UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC); + } + break; + + case EP0_OUT_DATA: + + if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { + if (udc_read_urb_ep0()) { +read_complete: + ep0state = EP0_IDLE; + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next + * EP0 transaction + */ + udc_dump_buffer("ep0 setup read", + (u8 *) data, 8); + usberr("can't parse setup packet\n"); + goto stall; + } + } + } else if (!(udccsr0 & UDCCSR0_OPC) && + !(udccsr0 & UDCCSR0_IPR)) { + if (ep0_urb->device_request.wLength == + ep0_urb->actual_length) + goto read_complete; + + usberr("Premature Status\n"); + ep0state = EP0_IDLE; + } + break; + + case EP0_IN_DATA: + /* GET_DESCRIPTOR etc */ + if (udccsr0 & UDCCSR0_OPC) { + UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF; + usberr("ep0in premature status"); + ep0state = EP0_IDLE; + } else { + /* irq was IPR clearing */ + if (udc_write_urb(endpoint) < 0) { + usberr("ep0_write_error\n"); + goto stall; + } + } + break; + + case EP0_XFER_COMPLETE: + UDCCSR0 = UDCCSR0_IPR; + ep0state = EP0_IDLE; + break; + + default: + usbdbg("Default\n"); + } + USIR0 = USIR0_IR0; +} + +static void udc_handle_ep(struct usb_endpoint_instance *endpoint) +{ + int ep_addr = endpoint->endpoint_address; + int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; + + u32 flags = UDCCSN(ep_num) & (UDCCSR_SST | UDCCSR_TRN); + if (flags) + UDCCSN(ep_num) = flags; + + if (ep_isout) + udc_read_urb(endpoint); + else + udc_write_urb(endpoint); + + UDCCSN(ep_num) = UDCCSR_PC; +} + +static void udc_state_changed(void) +{ + int config, interface, alternate; + + UDCCR |= UDCCR_SMAC; + + config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S; + interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S; + alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S; + + usbdbg("New UDC settings are: conf %d - inter %d - alter %d", + config, interface, alternate); + + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); + UDCISR1 = UDCISR1_IRCC; +} + +void udc_irq(void) +{ + int handled; + struct usb_endpoint_instance *endpoint; + int ep_num, i; + u32 udcisr0; + + do { + handled = 0; + /* Suspend Interrupt Request */ + if (USIR1 & UDCCR_SUSIR) { + usbdbg("Suspend\n"); + udc_ack_int_UDCCR(UDCCR_SUSIR); + handled = 1; + ep0state = EP0_IDLE; + } + + /* Resume Interrupt Request */ + if (USIR1 & UDCCR_RESIR) { + udc_ack_int_UDCCR(UDCCR_RESIR); + handled = 1; + usbdbg("USB resume\n"); + } + + if (USIR1 & (1<<31)) { + handled = 1; + udc_state_changed(); + } + + /* Reset Interrupt Request */ + if (USIR1 & UDCCR_RSTIR) { + udc_ack_int_UDCCR(UDCCR_RSTIR); + handled = 1; + usbdbg("Reset\n"); + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + } else { + if (USIR0) + usbdbg("UISR0: %x \n", USIR0); + + if (USIR0 & 0x2) + USIR0 = 0x2; + + /* Control traffic */ + if (USIR0 & USIR0_IR0) { + handled = 1; + udc_handle_ep0(udc_device->bus->endpoint_array); + USIR0 = USIR0_IR0; + } + + endpoint = udc_device->bus->endpoint_array; + for (i = 0; i < udc_device->bus->max_endpoints; i++) { + ep_num = (endpoint[i].endpoint_address) & + USB_ENDPOINT_NUMBER_MASK; + if (!ep_num) + continue; + udcisr0 = UDCISR0; + if (udcisr0 & + UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) { + UDCISR0 = UDCISR_INT(ep_num, + UDC_INT_PACKETCMP); + udc_handle_ep(&endpoint[i]); + } + } + } + + } while (handled); +} + +/* The UDCCR reg contains mask and interrupt status bits, + * so using '|=' isn't safe as it may ack an interrupt. + */ +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_UDE) + +static inline void udc_set_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); +} + +static inline void udc_clear_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); +} + +static void pio_irq_enable(int ep_num) +{ + if (ep_num < 16) + UDCICR0 |= 3 << (ep_num * 2); + else { + ep_num -= 16; + UDCICR1 |= 3 << (ep_num * 2); + } +} + +/* + * udc_set_nak + * + * Allow upper layers to signal lower layers should not accept more RX data + */ +void udc_set_nak(int ep_num) +{ + /* TODO */ +} + +/* + * udc_unset_nak + * + * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. + * Switch off NAKing on this endpoint to accept more data output from host. + */ +void udc_unset_nak(int ep_num) +{ + /* TODO */ +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ + return udc_write_urb(endpoint); +} + +/* Associate a physical endpoint with endpoint instance */ +void udc_setup_ep(struct usb_device_instance *device, unsigned int id, + struct usb_endpoint_instance *endpoint) +{ + int ep_num, ep_addr, ep_isout, ep_type, ep_size; + int config, interface, alternate; + u32 tmp; + + usbdbg("setting up endpoint id %d", id); + + if (!endpoint) { + usberr("endpoint void!"); + return; + } + + ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + if (ep_num >= UDC_MAX_ENDPOINTS) { + usberr("unable to setup ep %d!", ep_num); + return; + } + + pio_irq_enable(ep_num); + if (ep_num == 0) { + /* Done for ep0 */ + return; + } + + config = 1; + interface = 0; + alternate = 0; + + usbdbg("config %d - interface %d - alternate %d", + config, interface, alternate); + + ep_addr = endpoint->endpoint_address; + ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; + ep_type = ep_isout ? endpoint->rcv_attributes : endpoint->tx_attributes; + ep_size = ep_isout ? endpoint->rcv_packetSize : endpoint->tx_packetSize; + + usbdbg("addr %x, num %d, dir %s, type %s, packet size %d", + ep_addr, ep_num, + ep_isout ? "out" : "in", + ep_type == USB_ENDPOINT_XFER_ISOC ? "isoc" : + ep_type == USB_ENDPOINT_XFER_BULK ? "bulk" : + ep_type == USB_ENDPOINT_XFER_INT ? "int" : "???", + ep_size + ); + + /* Configure UDCCRx */ + tmp = 0; + tmp |= (config << UDCCONR_CN_S) & UDCCONR_CN; + tmp |= (interface << UDCCONR_IN_S) & UDCCONR_IN; + tmp |= (alternate << UDCCONR_AISN_S) & UDCCONR_AISN; + tmp |= (ep_num << UDCCONR_EN_S) & UDCCONR_EN; + tmp |= (ep_type << UDCCONR_ET_S) & UDCCONR_ET; + tmp |= ep_isout ? 0 : UDCCONR_ED; + tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS; + tmp |= UDCCONR_EE; + + UDCCN(ep_num) = tmp; + + usbdbg("UDCCR%c = %x", 'A' + ep_num-1, UDCCN(ep_num)); + usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, UDCCSN(ep_num)); +} + +#define CONFIG_USB_DEV_PULLUP_GPIO 87 + +/* Connect the USB device to the bus */ +void udc_connect(void) +{ + usbdbg("UDC connect"); + + /* Turn on the USB connection by enabling the pullup resistor */ + set_GPIO_mode(CONFIG_USB_DEV_PULLUP_GPIO | GPIO_OUT); + GPSR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO); +} + +/* Disconnect the USB device to the bus */ +void udc_disconnect(void) +{ + usbdbg("UDC disconnect"); + + /* Turn off the USB connection by disabling the pullup resistor */ + GPCR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO); +} + +/* Switch on the UDC */ +void udc_enable(struct usb_device_instance *device) +{ + + ep0state = EP0_IDLE; + CKEN |= CKEN11_USB; + + /* enable endpoint 0, A, B's Packet Complete Interrupt. */ + UDCICR0 = 0x0000003f; + UDCICR1 = 0xa8000000; + + /* clear the interrupt status/control registers */ + UDCISR0 = 0xffffffff; + UDCISR1 = 0xffffffff; + + /* set UDC-enable */ + udc_set_mask_UDCCR(UDCCR_UDE); + + udc_device = device; + if (!ep0_urb) + ep0_urb = usbd_alloc_urb(udc_device, + udc_device->bus->endpoint_array); + else + usbinfo("ep0_urb %p already allocated", ep0_urb); + + usbdbg("UDC Enabled\n"); +} + +/* Need to check this again */ +void udc_disable(void) +{ + usbdbg("disable UDC"); + + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + CKEN &= ~CKEN11_USB; + + /* Free ep0 URB */ + if (ep0_urb) { + usbd_dealloc_urb(ep0_urb); + ep0_urb = NULL; + } + + /* Reset device pointer */ + udc_device = NULL; +} + +/* Allow udc code to do any additional startup */ +void udc_startup_events(struct usb_device_instance *device) +{ + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT */ + usbd_device_event_irq(device, DEVICE_INIT, 0); + + /* The DEVICE_CREATE event puts the USB device in the state + * STATE_ATTACHED */ + usbd_device_event_irq(device, DEVICE_CREATE, 0); + + /* Some USB controller driver implementations signal + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. + * DEVICE_HUB_CONFIGURED causes a transition to the state + * STATE_POWERED, and DEVICE_RESET causes a transition to + * the state STATE_DEFAULT. + */ + udc_enable(device); +} + +/* Initialize h/w stuff */ +int udc_init(void) +{ + udc_device = NULL; + usbdbg("PXA27x usbd start"); + + /* Disable the UDC */ + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + CKEN &= ~CKEN11_USB; + + /* Disable IRQs: we don't use them */ + UDCICR0 = UDCICR1 = 0; + + return 0; +} diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index e014568..a8d30e2 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -596,46 +596,58 @@ typedef void (*ExcpHndlr) (void) ; /* * USB Device Controller */ -#ifndef CONFIG_CPU_MONAHANS -#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ -#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ -#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ - -#define UDCCR __REG(0x40600000) /* UDC Control Register */ -#define UDCCR_UDE (1 << 0) /* UDC enable */ -#define UDCCR_UDA (1 << 1) /* UDC active */ -#define UDCCR_RSM (1 << 2) /* Device resume */ -#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ -#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ -#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ -#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ -#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ - -#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ -#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ -#define UDCCS0_IPR (1 << 1) /* IN packet ready */ -#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ -#define UDCCS0_SST (1 << 4) /* Sent stall */ -#define UDCCS0_FST (1 << 5) /* Force stall */ -#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ -#define UDCCS0_SA (1 << 7) /* Setup active */ +#ifdef CONFIG_PXA27X + +#define UDCCR __REG(0x40600000) /* UDC Control Register */ +#define UDCCR_UDE (1 << 0) /* UDC enable */ +#define UDCCR_UDA (1 << 1) /* UDC active */ +#define UDCCR_RSM (1 << 2) /* Device resume */ +#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration Error */ +#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active Configuration */ +#define UDCCR_RESIR (1 << 29) /* Resume interrupt request */ +#define UDCCR_SUSIR (1 << 28) /* Suspend interrupt request */ +#define UDCCR_SM (1 << 28) /* Suspend interrupt mask */ +#define UDCCR_RSTIR (1 << 27) /* Reset interrupt request */ +#define UDCCR_REM (1 << 27) /* Reset interrupt mask */ +#define UDCCR_RM (1 << 29) /* resume interrupt mask */ +#define UDCCR_SRM (UDCCR_SM|UDCCR_RM) +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation Protocol Port Support */ +#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol Support */ +#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol Enable */ +#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ +#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ +#define UDCCR_ACN_S 11 +#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ +#define UDCCR_AIN_S 8 +#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface Setting Number */ +#define UDCCR_AAISN_S 5 + +#define UDCCS0 __REG(0x40600100) /* UDC Endpoint 0 Control/Status Register */ +#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ +#define UDCCS0_IPR (1 << 1) /* IN packet ready */ +#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS0_DRWF (1 << 16) /* Device remote wakeup feature */ +#define UDCCS0_SST (1 << 4) /* Sent stall */ +#define UDCCS0_FST (1 << 5) /* Force stall */ +#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ +#define UDCCS0_SA (1 << 7) /* Setup active */
/* Bulk IN - Endpoint 1,6,11 */ -#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ +#define UDCCS1 __REG(0x40600104) /* UDC Endpoint 1 (IN) Control/Status Register */ #define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ #define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */
#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ #define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ -#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS_BI_FTF (1 << 8) /* Flush Tx FIFO */ #define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ #define UDCCS_BI_SST (1 << 4) /* Sent stall */ #define UDCCS_BI_FST (1 << 5) /* Force stall */ #define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
/* Bulk OUT - Endpoint 2,7,12 */ -#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ +#define UDCCS2 __REG(0x40600108) /* UDC Endpoint 2 (OUT) Control/Status Register */ #define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ #define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */
@@ -684,16 +696,16 @@ typedef void (*ExcpHndlr) (void) ; #define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ -#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ -#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ +#define UFNRL __REG(0x40600014) /* UDC Frame Number Register Low */ +#define UBCR2 __REG(0x40600208) /* UDC Byte Count Reg 2 */ #define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ #define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ #define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ #define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ #define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ -#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ -#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ -#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ +#define UDDR0 __REG(0x40600300) /* UDC Endpoint 0 Data Register */ +#define UDDR1 __REG(0x40600304) /* UDC Endpoint 1 Data Register */ +#define UDDR2 __REG(0x40600308) /* UDC Endpoint 2 Data Register */ #define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ #define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ #define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ @@ -708,7 +720,7 @@ typedef void (*ExcpHndlr) (void) ; #define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ #define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */
-#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ +#define UICR0 __REG(0x40600004) /* UDC Interrupt Control Register 0 */
#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ #define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ @@ -719,7 +731,7 @@ typedef void (*ExcpHndlr) (void) ; #define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ #define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
-#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ +#define UICR1 __REG(0x40600008) /* UDC Interrupt Control Register 1 */
#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ #define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ @@ -730,18 +742,18 @@ typedef void (*ExcpHndlr) (void) ; #define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ #define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
-#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ +#define USIR0 __REG(0x4060000C) /* UDC Status Interrupt Register 0 */
#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */ -#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */ -#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */ +#define USIR0_IR1 (1 << 2) /* Interrup request ep 1 */ +#define USIR0_IR2 (1 << 4) /* Interrup request ep 2 */ #define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */ #define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */ #define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */ #define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */ #define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */
-#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ +#define USIR1 __REG(0x40600010) /* UDC Status Interrupt Register 1 */
#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */ #define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */ @@ -751,23 +763,201 @@ typedef void (*ExcpHndlr) (void) ; #define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */ #define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */ #define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */ -#endif /* ! CONFIG_CPU_MONAHANS */
-#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
-/* - * USB Client Controller (incomplete) - */ -#define UDCCR __REG(0x40600000) -#define UDCICR0 __REG(0x40600004) -#define UDCCIR0 __REG(0x40600008) -#define UDCISR0 __REG(0x4060000c) -#define UDCSIR1 __REG(0x40600010) -#define UDCFNR __REG(0x40600014) -#define UDCOTGICR __REG(0x40600018) -#define UDCOTGISR __REG(0x4060001c) -#define UP2OCR __REG(0x40600020) -#define UP3OCR __REG(0x40600024) +#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */ +#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */ +#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ +#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ + +#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ +#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ +#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ +#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ + +#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */ +#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */ +#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCISR1_IRCC (1 << 31) /* IntEn - Configuration Change */ +#define UDCISR1_IRSOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCISR1_IRRU (1 << 29) /* IntEn - Resume */ +#define UDCISR1_IRSU (1 << 28) /* IntEn - Suspend */ +#define UDCISR1_IRRS (1 << 27) /* IntEn - Reset */ + + +#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */ +#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */ +#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ +#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge Interrupt Enable */ +#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge Interrupt Enable */ +#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge Interrupt Enable */ +#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising Edge Interrupt Enable */ +#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge Interrupt Enable */ + +#define UDCCSN(x) __REG2(0x40600100, (x) << 2) +#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ + +#define UDCCSR0_SA (1 << 7) /* Setup Active */ +#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ +#define UDCCSR0_FST (1 << 5) /* Force Stall */ +#define UDCCSR0_SST (1 << 4) /* Sent Stall */ +#define UDCCSR0_DME (1 << 3) /* DMA Enable */ +#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ +#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ +#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ + +#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */ +#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */ +#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */ +#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */ +#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */ +#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */ +#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */ +#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */ +#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */ +#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */ +#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */ +#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */ +#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */ +#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */ +#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */ +#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */ +#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */ +#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */ +#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */ +#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */ +#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */ +#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */ +#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */ + +#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ +#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ +#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ +#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ +#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ +#define UDCCSR_FST (1 << 5) /* Force STALL */ +#define UDCCSR_SST (1 << 4) /* Sent STALL */ +#define UDCCSR_DME (1 << 3) /* DMA Enable */ +#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ +#define UDCCSR_PC (1 << 1) /* Packet Complete */ +#define UDCCSR_FS (1 << 0) /* FIFO needs service */ + +#define UDCBCN(x) __REG2(0x40600200, (x)<<2) +#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */ +#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */ +#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */ +#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */ +#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */ +#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */ +#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */ +#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */ +#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */ +#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */ +#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */ +#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */ +#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */ +#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */ +#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */ +#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */ +#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */ +#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */ +#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */ +#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */ +#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */ +#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */ +#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */ +#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */ + +#define UDCDN(x) __REG2(0x40600300, (x)<<2) +#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */ +#define UDCDRA __REG(0x40600304) /* Data Register - EPA */ +#define UDCDRB __REG(0x40600308) /* Data Register - EPB */ +#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */ +#define UDCDRD __REG(0x40600310) /* Data Register - EPD */ +#define UDCDRE __REG(0x40600314) /* Data Register - EPE */ +#define UDCDRF __REG(0x40600318) /* Data Register - EPF */ +#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */ +#define UDCDRH __REG(0x40600320) /* Data Register - EPH */ +#define UDCDRI __REG(0x40600324) /* Data Register - EPI */ +#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */ +#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */ +#define UDCDRL __REG(0x40600330) /* Data Register - EPL */ +#define UDCDRM __REG(0x40600334) /* Data Register - EPM */ +#define UDCDRN __REG(0x40600338) /* Data Register - EPN */ +#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */ +#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */ +#define UDCDRR __REG(0x40600344) /* Data Register - EPR */ +#define UDCDRS __REG(0x40600348) /* Data Register - EPS */ +#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */ +#define UDCDRU __REG(0x40600350) /* Data Register - EPU */ +#define UDCDRV __REG(0x40600354) /* Data Register - EPV */ +#define UDCDRW __REG(0x40600358) /* Data Register - EPW */ +#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */ + +#define UDCCN(x) __REG2(0x40600400, (x)<<2) +#define UDCCRA __REG(0x40600404) /* Configuration register EPA */ +#define UDCCRB __REG(0x40600408) /* Configuration register EPB */ +#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */ +#define UDCCRD __REG(0x40600410) /* Configuration register EPD */ +#define UDCCRE __REG(0x40600414) /* Configuration register EPE */ +#define UDCCRF __REG(0x40600418) /* Configuration register EPF */ +#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */ +#define UDCCRH __REG(0x40600420) /* Configuration register EPH */ +#define UDCCRI __REG(0x40600424) /* Configuration register EPI */ +#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */ +#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */ +#define UDCCRL __REG(0x40600430) /* Configuration register EPL */ +#define UDCCRM __REG(0x40600434) /* Configuration register EPM */ +#define UDCCRN __REG(0x40600438) /* Configuration register EPN */ +#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */ +#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */ +#define UDCCRR __REG(0x40600444) /* Configuration register EPR */ +#define UDCCRS __REG(0x40600448) /* Configuration register EPS */ +#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */ +#define UDCCRU __REG(0x40600450) /* Configuration register EPU */ +#define UDCCRV __REG(0x40600454) /* Configuration register EPV */ +#define UDCCRW __REG(0x40600458) /* Configuration register EPW */ +#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */ + +#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ +#define UDCCONR_CN_S (25) +#define UDCCONR_IN (0x07 << 22) /* Interface Number */ +#define UDCCONR_IN_S (22) +#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ +#define UDCCONR_AISN_S (19) +#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ +#define UDCCONR_EN_S (15) +#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ +#define UDCCONR_ET_S (13) +#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ +#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ +#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ +#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ +#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ +#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ +#define UDCCONR_MPS_S (2) +#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ +#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ + + +#define UDC_INT_FIFOERROR (0x2) +#define UDC_INT_PACKETCMP (0x1) +#define UDC_FNR_MASK (0x7ff) +#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST) +#define UDC_BCR_MASK (0x3ff) + +#endif /* CONFIG_PXA27X */ + +#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
/* * USB Host Controller diff --git a/include/usbdcore_pxa27x.h b/include/usbdcore_pxa27x.h new file mode 100644 index 0000000..e6d8121 --- /dev/null +++ b/include/usbdcore_pxa27x.h @@ -0,0 +1,69 @@ +/* + * PXA27x register declarations and HCD data structures + * + * Copyright (C) 2007 Rodolfo Giometti giometti@linux.it + * Copyright (C) 2007 Eurotech S.p.A. info@eurotech.it + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __USBDCORE_PXA270X_H__ +#define __USBDCORE_PXA270X_H__ + +#include <asm/byteorder.h> + +/* Endpoint 0 states */ +#define EP0_IDLE 0 +#define EP0_IN_DATA 1 +#define EP0_OUT_DATA 2 +#define EP0_XFER_COMPLETE 3 + + +/* Endpoint parameters */ +#define MAX_ENDPOINTS 4 +#define EP_MAX_PACKET_SIZE 64 + +#define EP0_MAX_PACKET_SIZE 16 +#define UDC_OUT_ENDPOINT 0x02 +#define UDC_OUT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_IN_ENDPOINT 0x01 +#define UDC_IN_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_INT_ENDPOINT 0x05 +#define UDC_INT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_BULK_PACKET_SIZE EP_MAX_PACKET_SIZE + +void udc_irq(void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak(int epid); + +/* Higher level functions for abstracting away from specific device */ +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +int udc_init(void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, + unsigned int ep, struct usb_endpoint_instance *endpoint); + +#endif

On Mon, 9 Mar 2009 18:38:47 +0530 Vivek Kutal vivek.kutal@azingo.com wrote:
+#ifdef USBDDBG +static void udc_dump_buffer(char *name, u8 *buf, int len) +{
- int i, p, flag = 1;
- usbdbg("%s - buf %p, len %d", name, buf, len);
- for (i = p = 0; i < len; i++, p++) {
if (p == 0) {
flag = 0;
usbdbg("\t");
}
usbdbg("%02x ", buf[i]);
if (p == 15) {
flag = 1;
usbdbg("\n");
p = -1;
}
- }
- if (!flag)
usbdbg("\n");
+} +#else +#define udc_dump_buffer(name, buf, len) /* void */ +#endif
can we not reinvent the wheel here and use lib_generic/display_options.c's print_buffer()?
+static int udc_write_urb(struct usb_endpoint_instance *endpoint) +{
- struct urb *urb = endpoint->tx_urb;
- int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
no blank line here please.
- u32 *addr32 = (u32 *) &UDCDN(ep_num),
*data32 = (u32 *) urb->buffer;
- u8 *addr8 = (u8 *) &UDCDN(ep_num),
*data8 = (u8 *) urb->buffer;
alignment (or give data* their own entire line).
/* Check direction */
if (ep0_urb->device_request.bmRequestType &
USB_REQ_DIRECTION_MASK == USB_REQ_HOST2DEVICE) {
alignment. Might need to add parens for clarity.
Kim

This Patch adds Support for PXA27X UDC.
Signed-off-by: Vivek Kutal vivek.kutal@azingo.com --- Resinding after doing the changes suggested by Kim.
drivers/serial/usbtty.h | 4 +- drivers/usb/Makefile | 1 + drivers/usb/usbdcore_pxa27x.c | 702 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 296 ++++++++++++--- include/usbdcore_pxa27x.h | 69 ++++ 5 files changed, 1018 insertions(+), 54 deletions(-) create mode 100644 drivers/usb/usbdcore_pxa27x.c create mode 100644 include/usbdcore_pxa27x.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h index ecefde5..5fe872e 100644 --- a/drivers/serial/usbtty.h +++ b/drivers/serial/usbtty.h @@ -27,8 +27,10 @@ #include <usbdcore.h> #if defined(CONFIG_PPC) #include <usbdcore_mpc8xx.h> -#elif defined(CONFIG_ARM) +#elif defined(CONFIG_OMAP1510) #include <usbdcore_omap1510.h> +#elif defined(CONFIG_PXA27X) +#include <usbdcore_pxa27x.h> #endif
#include <version_autogenerated.h> diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index b306a65..0a1886a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -47,6 +47,7 @@ COBJS-y += usbdcore_ep0.o COBJS-$(CONFIG_OMAP1510) += usbdcore_omap1510.o COBJS-$(CONFIG_OMAP1610) += usbdcore_omap1510.o COBJS-$(CONFIG_MPC885_FAMILY) += usbdcore_mpc8xx.o +COBJS-$(CONFIG_PXA27X) += usbdcore_pxa27x.o endif
COBJS := $(COBJS-y) diff --git a/drivers/usb/usbdcore_pxa27x.c b/drivers/usb/usbdcore_pxa27x.c new file mode 100644 index 0000000..8b893f7 --- /dev/null +++ b/drivers/usb/usbdcore_pxa27x.c @@ -0,0 +1,702 @@ +/* + * PXA27x USB device driver for u-boot. + * + * Copyright (C) 2007 Rodolfo Giometti giometti@linux.it + * Copyright (C) 2007 Eurotech S.p.A. info@eurotech.it + * Copyright (C) 2008 Vivek Kutal vivek.kutal@azingo.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + + +#include <common.h> +#include <config.h> +#include <asm/byteorder.h> +#include <usbdcore.h> +#include <usbdcore_ep0.h> +#include <asm/arch/hardware.h> +#include <usbdcore_pxa27x.h> + +/* number of endpoints on this UDC */ +#define UDC_MAX_ENDPOINTS 24 + +static struct urb *ep0_urb; +static struct usb_device_instance *udc_device; +static int ep0state = EP0_IDLE; + +#ifdef USBDDBG +static void udc_dump_buffer(char *name, u8 *buf, int len) +{ + usbdbg("%s - buf %p, len %d", name, buf, len); + print_buffer(0, buf, 1, len, 0); +} +#else +#define udc_dump_buffer(name, buf, len) /* void */ +#endif + +static inline void udc_ack_int_UDCCR(int mask) +{ + USIR1 = mask | USIR1; +} + +/* + * If the endpoint has an active tx_urb, then the next packet of data from the + * URB is written to the tx FIFO. + * The total amount of data in the urb is given by urb->actual_length. + * The maximum amount of data that can be sent in any one packet is given by + * endpoint->tx_packetSize. + * The number of data bytes from this URB that have already been transmitted + * is given by endpoint->sent. + * endpoint->last is updated by this routine with the number of data bytes + * transmitted in this packet. + */ +static int udc_write_urb(struct usb_endpoint_instance *endpoint) +{ + struct urb *urb = endpoint->tx_urb; + int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u32 *addr32 = (u32 *) &UDCDN(ep_num); + u32 *data32 = (u32 *) urb->buffer; + u8 *addr8 = (u8 *) &UDCDN(ep_num); + u8 *data8 = (u8 *) urb->buffer; + unsigned int i, n, w, b, is_short; + int timeout = 2000; /* 2ms */ + + if (!urb || !urb->actual_length) + return -1; + + n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); + if (n <= 0) + return -1; + + usbdbg("write urb on ep %d", ep_num); +#if defined(USBDDBG) && defined(USBDPARANOIA) + usbdbg("urb: buf %p, buf_len %d, actual_len %d", + urb->buffer, urb->buffer_length, urb->actual_length); + usbdbg("endpoint: sent %d, tx_packetSize %d, last %d", + endpoint->sent, endpoint->tx_packetSize, endpoint->last); +#endif + + is_short = n != endpoint->tx_packetSize; + w = n / 4; + b = n % 4; + usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b); + udc_dump_buffer("urb write", data8 + endpoint->sent, n); + + /* Prepare for data send */ + if (ep_num) + UDCCSN(ep_num) = UDCCSR_PC; + + for (i = 0; i < w; i++) + *addr32 = data32[endpoint->sent/4 + i]; + for (i = 0; i < b; i++) + *addr8 = data8[endpoint->sent + w*4 + i]; + + /* Set "Packet Complete" if less data then tx_packetSize */ + if (is_short) + UDCCSN(ep_num) = ep_num ? UDCCSR_SP : UDCCSR0_IPR; + + /* Wait for data sent */ + while (!(UDCCSN(ep_num) & (ep_num ? UDCCSR_PC : UDCCSR0_IPR))) { + if (ep_num) { + if (timeout-- == 0) + return -1; + else + udelay(1); + }; + } + endpoint->last = n; + + if (ep_num) { + usbd_tx_complete(endpoint); + } else { + endpoint->sent += n; + endpoint->last -= n; + } + + if ((endpoint->tx_urb->actual_length - endpoint->sent) <= 0) { + urb->actual_length = 0; + endpoint->sent = 0; + endpoint->last = 0; + } + + if ((endpoint->sent >= urb->actual_length) && (!ep_num)) { + usbdbg("ep0 IN stage done"); + if (is_short) + ep0state = EP0_IDLE; + else + ep0state = EP0_XFER_COMPLETE; + } + + return 0; +} + +static int udc_read_urb(struct usb_endpoint_instance *endpoint) +{ + struct urb *urb = endpoint->rcv_urb; + int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + u32 *addr32 = (u32 *) &UDCDN(ep_num); + u32 *data32 = (u32 *) urb->buffer; + unsigned int i, n, is_short ; + + usbdbg("read urb on ep %d", ep_num); +#if defined(USBDDBG) && defined(USBDPARANOIA) + usbdbg("urb: buf %p, buf_len %d, actual_len %d", + urb->buffer, urb->buffer_length, urb->actual_length); + usbdbg("endpoint: rcv_packetSize %d", + endpoint->rcv_packetSize); +#endif + + if (UDCCSN(ep_num) & UDCCSR_BNE) + n = UDCBCN(ep_num) & 0x3ff; + else /* zlp */ + n = 0; + is_short = n != endpoint->rcv_packetSize; + + usbdbg("n %d%s", n, is_short ? "-s" : ""); + for (i = 0; i < n; i += 4) + data32[urb->actual_length/4 + i/4] = *addr32; + + udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n); + usbd_rcv_complete(endpoint, n, 0); + + return 0; +} + +static int udc_read_urb_ep0(void) +{ + u32 *addr32 = (u32 *) &UDCDN(0); + u32 *data32 = (u32 *) ep0_urb->buffer; + u8 *addr8 = (u8 *) &UDCDN(0); + u8 *data8 = (u8 *) ep0_urb->buffer; + unsigned int i, n, w, b; + + n = UDCBCR0; + w = n / 4; + b = n % 4; + + for (i = 0; i < w; i++) { + data32[ep0_urb->actual_length/4 + i] = *addr32; + ep0_urb->actual_length += 4; + } + + for (i = 0; i < b; i++) { + data8[ep0_urb->actual_length + w*4 + i] = *addr8; + ep0_urb->actual_length++; + } + + UDCCSR0 = UDCCSR0_OPC | UDCCSR0_IPR; + if (ep0_urb->actual_length == ep0_urb->device_request.wLength) + return 1; + + return 0; +} + +static void udc_handle_ep0(struct usb_endpoint_instance *endpoint) +{ + u32 udccsr0 = UDCCSR0; + u32 *data = (u32 *) &ep0_urb->device_request; + int i; + + usbdbg("udccsr0 %x", udccsr0); + + /* Clear stall status */ + if (udccsr0 & UDCCSR0_SST) { + usberr("clear stall status"); + UDCCSR0 = UDCCSR0_SST; + ep0state = EP0_IDLE; + } + + /* previous request unfinished? non-error iff back-to-back ... */ + if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE) + ep0state = EP0_IDLE; + + switch (ep0state) { + + case EP0_IDLE: + + udccsr0 = UDCCSR0; + /* Start control request? */ + if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) + == (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) { + + /* Read SETUP packet. + * SETUP packet size is 8 bytes (aka 2 words) + */ + usbdbg("try reading SETUP packet"); + for (i = 0; i < 2; i++) { + if ((UDCCSR0 & UDCCSR0_RNE) == 0) { + usberr("setup packet too short:%d", i); + goto stall; + } + data[i] = UDCDR0; + } + + UDCCSR0 |= (UDCCSR0_OPC | UDCCSR0_SA); + if ((UDCCSR0 & UDCCSR0_RNE) != 0) { + usberr("setup packet too long"); + goto stall; + } + + udc_dump_buffer("ep0 setup read", (u8 *) data, 8); + + if (ep0_urb->device_request.wLength == 0) { + usbdbg("Zero Data control Packet\n"); + if (ep0_recv_setup(ep0_urb)) { + usberr("Invalid Setup Packet\n"); + udc_dump_buffer("ep0 setup read", + (u8 *)data, 8); + goto stall; + } + UDCCSR0 = UDCCSR0_IPR; + ep0state = EP0_IDLE; + } else { + /* Check direction */ + if ((ep0_urb->device_request.bmRequestType & + USB_REQ_DIRECTION_MASK) + == USB_REQ_HOST2DEVICE) { + ep0state = EP0_OUT_DATA; + ep0_urb->buffer = + (u8 *)ep0_urb->buffer_data; + ep0_urb->buffer_length = + sizeof(ep0_urb->buffer_data); + ep0_urb->actual_length = 0; + UDCCSR0 = UDCCSR0_IPR; + } else { + /* The ep0_recv_setup function has + * already placed our response packet + * data in ep0_urb->buffer and the + * packet length in + * ep0_urb->actual_length. + */ + if (ep0_recv_setup(ep0_urb)) { +stall: + usberr("Invalid setup packet"); + udc_dump_buffer("ep0 setup read" + , (u8 *) data, 8); + ep0state = EP0_IDLE; + + UDCCSR0 = UDCCSR0_SA | + UDCCSR0_OPC | UDCCSR0_FST | + UDCCS0_FTF; + + return; + } + + endpoint->tx_urb = ep0_urb; + endpoint->sent = 0; + usbdbg("EP0_IN_DATA"); + ep0state = EP0_IN_DATA; + if (udc_write_urb(endpoint) < 0) + goto stall; + + } + } + return; + } else if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA)) + == (UDCCSR0_OPC|UDCCSR0_SA)) { + usberr("Setup Active but no data. Stalling ....\n"); + goto stall; + } else { + usbdbg("random early IRQs"); + /* Some random early IRQs: + * - we acked FST + * - IPR cleared + * - OPC got set, without SA (likely status stage) + */ + UDCCSR0 = udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC); + } + break; + + case EP0_OUT_DATA: + + if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { + if (udc_read_urb_ep0()) { +read_complete: + ep0state = EP0_IDLE; + if (ep0_recv_setup(ep0_urb)) { + /* Not a setup packet, stall next + * EP0 transaction + */ + udc_dump_buffer("ep0 setup read", + (u8 *) data, 8); + usberr("can't parse setup packet\n"); + goto stall; + } + } + } else if (!(udccsr0 & UDCCSR0_OPC) && + !(udccsr0 & UDCCSR0_IPR)) { + if (ep0_urb->device_request.wLength == + ep0_urb->actual_length) + goto read_complete; + + usberr("Premature Status\n"); + ep0state = EP0_IDLE; + } + break; + + case EP0_IN_DATA: + /* GET_DESCRIPTOR etc */ + if (udccsr0 & UDCCSR0_OPC) { + UDCCSR0 = UDCCSR0_OPC | UDCCSR0_FTF; + usberr("ep0in premature status"); + ep0state = EP0_IDLE; + } else { + /* irq was IPR clearing */ + if (udc_write_urb(endpoint) < 0) { + usberr("ep0_write_error\n"); + goto stall; + } + } + break; + + case EP0_XFER_COMPLETE: + UDCCSR0 = UDCCSR0_IPR; + ep0state = EP0_IDLE; + break; + + default: + usbdbg("Default\n"); + } + USIR0 = USIR0_IR0; +} + +static void udc_handle_ep(struct usb_endpoint_instance *endpoint) +{ + int ep_addr = endpoint->endpoint_address; + int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; + + u32 flags = UDCCSN(ep_num) & (UDCCSR_SST | UDCCSR_TRN); + if (flags) + UDCCSN(ep_num) = flags; + + if (ep_isout) + udc_read_urb(endpoint); + else + udc_write_urb(endpoint); + + UDCCSN(ep_num) = UDCCSR_PC; +} + +static void udc_state_changed(void) +{ + int config, interface, alternate; + + UDCCR |= UDCCR_SMAC; + + config = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S; + interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S; + alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S; + + usbdbg("New UDC settings are: conf %d - inter %d - alter %d", + config, interface, alternate); + + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); + UDCISR1 = UDCISR1_IRCC; +} + +void udc_irq(void) +{ + int handled; + struct usb_endpoint_instance *endpoint; + int ep_num, i; + u32 udcisr0; + + do { + handled = 0; + /* Suspend Interrupt Request */ + if (USIR1 & UDCCR_SUSIR) { + usbdbg("Suspend\n"); + udc_ack_int_UDCCR(UDCCR_SUSIR); + handled = 1; + ep0state = EP0_IDLE; + } + + /* Resume Interrupt Request */ + if (USIR1 & UDCCR_RESIR) { + udc_ack_int_UDCCR(UDCCR_RESIR); + handled = 1; + usbdbg("USB resume\n"); + } + + if (USIR1 & (1<<31)) { + handled = 1; + udc_state_changed(); + } + + /* Reset Interrupt Request */ + if (USIR1 & UDCCR_RSTIR) { + udc_ack_int_UDCCR(UDCCR_RSTIR); + handled = 1; + usbdbg("Reset\n"); + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + } else { + if (USIR0) + usbdbg("UISR0: %x \n", USIR0); + + if (USIR0 & 0x2) + USIR0 = 0x2; + + /* Control traffic */ + if (USIR0 & USIR0_IR0) { + handled = 1; + udc_handle_ep0(udc_device->bus->endpoint_array); + USIR0 = USIR0_IR0; + } + + endpoint = udc_device->bus->endpoint_array; + for (i = 0; i < udc_device->bus->max_endpoints; i++) { + ep_num = (endpoint[i].endpoint_address) & + USB_ENDPOINT_NUMBER_MASK; + if (!ep_num) + continue; + udcisr0 = UDCISR0; + if (udcisr0 & + UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) { + UDCISR0 = UDCISR_INT(ep_num, + UDC_INT_PACKETCMP); + udc_handle_ep(&endpoint[i]); + } + } + } + + } while (handled); +} + +/* The UDCCR reg contains mask and interrupt status bits, + * so using '|=' isn't safe as it may ack an interrupt. + */ +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_UDE) + +static inline void udc_set_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); +} + +static inline void udc_clear_mask_UDCCR(int mask) +{ + UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); +} + +static void pio_irq_enable(int ep_num) +{ + if (ep_num < 16) + UDCICR0 |= 3 << (ep_num * 2); + else { + ep_num -= 16; + UDCICR1 |= 3 << (ep_num * 2); + } +} + +/* + * udc_set_nak + * + * Allow upper layers to signal lower layers should not accept more RX data + */ +void udc_set_nak(int ep_num) +{ + /* TODO */ +} + +/* + * udc_unset_nak + * + * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. + * Switch off NAKing on this endpoint to accept more data output from host. + */ +void udc_unset_nak(int ep_num) +{ + /* TODO */ +} + +int udc_endpoint_write(struct usb_endpoint_instance *endpoint) +{ + return udc_write_urb(endpoint); +} + +/* Associate a physical endpoint with endpoint instance */ +void udc_setup_ep(struct usb_device_instance *device, unsigned int id, + struct usb_endpoint_instance *endpoint) +{ + int ep_num, ep_addr, ep_isout, ep_type, ep_size; + int config, interface, alternate; + u32 tmp; + + usbdbg("setting up endpoint id %d", id); + + if (!endpoint) { + usberr("endpoint void!"); + return; + } + + ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; + if (ep_num >= UDC_MAX_ENDPOINTS) { + usberr("unable to setup ep %d!", ep_num); + return; + } + + pio_irq_enable(ep_num); + if (ep_num == 0) { + /* Done for ep0 */ + return; + } + + config = 1; + interface = 0; + alternate = 0; + + usbdbg("config %d - interface %d - alternate %d", + config, interface, alternate); + + ep_addr = endpoint->endpoint_address; + ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; + ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; + ep_type = ep_isout ? endpoint->rcv_attributes : endpoint->tx_attributes; + ep_size = ep_isout ? endpoint->rcv_packetSize : endpoint->tx_packetSize; + + usbdbg("addr %x, num %d, dir %s, type %s, packet size %d", + ep_addr, ep_num, + ep_isout ? "out" : "in", + ep_type == USB_ENDPOINT_XFER_ISOC ? "isoc" : + ep_type == USB_ENDPOINT_XFER_BULK ? "bulk" : + ep_type == USB_ENDPOINT_XFER_INT ? "int" : "???", + ep_size + ); + + /* Configure UDCCRx */ + tmp = 0; + tmp |= (config << UDCCONR_CN_S) & UDCCONR_CN; + tmp |= (interface << UDCCONR_IN_S) & UDCCONR_IN; + tmp |= (alternate << UDCCONR_AISN_S) & UDCCONR_AISN; + tmp |= (ep_num << UDCCONR_EN_S) & UDCCONR_EN; + tmp |= (ep_type << UDCCONR_ET_S) & UDCCONR_ET; + tmp |= ep_isout ? 0 : UDCCONR_ED; + tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS; + tmp |= UDCCONR_EE; + + UDCCN(ep_num) = tmp; + + usbdbg("UDCCR%c = %x", 'A' + ep_num-1, UDCCN(ep_num)); + usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, UDCCSN(ep_num)); +} + +#define CONFIG_USB_DEV_PULLUP_GPIO 87 + +/* Connect the USB device to the bus */ +void udc_connect(void) +{ + usbdbg("UDC connect"); + + /* Turn on the USB connection by enabling the pullup resistor */ + set_GPIO_mode(CONFIG_USB_DEV_PULLUP_GPIO | GPIO_OUT); + GPSR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO); +} + +/* Disconnect the USB device to the bus */ +void udc_disconnect(void) +{ + usbdbg("UDC disconnect"); + + /* Turn off the USB connection by disabling the pullup resistor */ + GPCR(CONFIG_USB_DEV_PULLUP_GPIO) = GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO); +} + +/* Switch on the UDC */ +void udc_enable(struct usb_device_instance *device) +{ + + ep0state = EP0_IDLE; + CKEN |= CKEN11_USB; + + /* enable endpoint 0, A, B's Packet Complete Interrupt. */ + UDCICR0 = 0x0000003f; + UDCICR1 = 0xa8000000; + + /* clear the interrupt status/control registers */ + UDCISR0 = 0xffffffff; + UDCISR1 = 0xffffffff; + + /* set UDC-enable */ + udc_set_mask_UDCCR(UDCCR_UDE); + + udc_device = device; + if (!ep0_urb) + ep0_urb = usbd_alloc_urb(udc_device, + udc_device->bus->endpoint_array); + else + usbinfo("ep0_urb %p already allocated", ep0_urb); + + usbdbg("UDC Enabled\n"); +} + +/* Need to check this again */ +void udc_disable(void) +{ + usbdbg("disable UDC"); + + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + CKEN &= ~CKEN11_USB; + + /* Free ep0 URB */ + if (ep0_urb) { + usbd_dealloc_urb(ep0_urb); + ep0_urb = NULL; + } + + /* Reset device pointer */ + udc_device = NULL; +} + +/* Allow udc code to do any additional startup */ +void udc_startup_events(struct usb_device_instance *device) +{ + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT */ + usbd_device_event_irq(device, DEVICE_INIT, 0); + + /* The DEVICE_CREATE event puts the USB device in the state + * STATE_ATTACHED */ + usbd_device_event_irq(device, DEVICE_CREATE, 0); + + /* Some USB controller driver implementations signal + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. + * DEVICE_HUB_CONFIGURED causes a transition to the state + * STATE_POWERED, and DEVICE_RESET causes a transition to + * the state STATE_DEFAULT. + */ + udc_enable(device); +} + +/* Initialize h/w stuff */ +int udc_init(void) +{ + udc_device = NULL; + usbdbg("PXA27x usbd start"); + + /* Disable the UDC */ + udc_clear_mask_UDCCR(UDCCR_UDE); + + /* Disable clock for USB device */ + CKEN &= ~CKEN11_USB; + + /* Disable IRQs: we don't use them */ + UDCICR0 = UDCICR1 = 0; + + return 0; +} diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index e014568..a8d30e2 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -596,46 +596,58 @@ typedef void (*ExcpHndlr) (void) ; /* * USB Device Controller */ -#ifndef CONFIG_CPU_MONAHANS -#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ -#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ -#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ - -#define UDCCR __REG(0x40600000) /* UDC Control Register */ -#define UDCCR_UDE (1 << 0) /* UDC enable */ -#define UDCCR_UDA (1 << 1) /* UDC active */ -#define UDCCR_RSM (1 << 2) /* Device resume */ -#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ -#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ -#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ -#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ -#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ - -#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ -#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ -#define UDCCS0_IPR (1 << 1) /* IN packet ready */ -#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ -#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ -#define UDCCS0_SST (1 << 4) /* Sent stall */ -#define UDCCS0_FST (1 << 5) /* Force stall */ -#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ -#define UDCCS0_SA (1 << 7) /* Setup active */ +#ifdef CONFIG_PXA27X + +#define UDCCR __REG(0x40600000) /* UDC Control Register */ +#define UDCCR_UDE (1 << 0) /* UDC enable */ +#define UDCCR_UDA (1 << 1) /* UDC active */ +#define UDCCR_RSM (1 << 2) /* Device resume */ +#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration Error */ +#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active Configuration */ +#define UDCCR_RESIR (1 << 29) /* Resume interrupt request */ +#define UDCCR_SUSIR (1 << 28) /* Suspend interrupt request */ +#define UDCCR_SM (1 << 28) /* Suspend interrupt mask */ +#define UDCCR_RSTIR (1 << 27) /* Reset interrupt request */ +#define UDCCR_REM (1 << 27) /* Reset interrupt mask */ +#define UDCCR_RM (1 << 29) /* resume interrupt mask */ +#define UDCCR_SRM (UDCCR_SM|UDCCR_RM) +#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ +#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation Protocol Port Support */ +#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol Support */ +#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol Enable */ +#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ +#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ +#define UDCCR_ACN_S 11 +#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ +#define UDCCR_AIN_S 8 +#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface Setting Number */ +#define UDCCR_AAISN_S 5 + +#define UDCCS0 __REG(0x40600100) /* UDC Endpoint 0 Control/Status Register */ +#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ +#define UDCCS0_IPR (1 << 1) /* IN packet ready */ +#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS0_DRWF (1 << 16) /* Device remote wakeup feature */ +#define UDCCS0_SST (1 << 4) /* Sent stall */ +#define UDCCS0_FST (1 << 5) /* Force stall */ +#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ +#define UDCCS0_SA (1 << 7) /* Setup active */
/* Bulk IN - Endpoint 1,6,11 */ -#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ +#define UDCCS1 __REG(0x40600104) /* UDC Endpoint 1 (IN) Control/Status Register */ #define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ #define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */
#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ #define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ -#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ +#define UDCCS_BI_FTF (1 << 8) /* Flush Tx FIFO */ #define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ #define UDCCS_BI_SST (1 << 4) /* Sent stall */ #define UDCCS_BI_FST (1 << 5) /* Force stall */ #define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
/* Bulk OUT - Endpoint 2,7,12 */ -#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ +#define UDCCS2 __REG(0x40600108) /* UDC Endpoint 2 (OUT) Control/Status Register */ #define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ #define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */
@@ -684,16 +696,16 @@ typedef void (*ExcpHndlr) (void) ; #define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ -#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ -#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ +#define UFNRL __REG(0x40600014) /* UDC Frame Number Register Low */ +#define UBCR2 __REG(0x40600208) /* UDC Byte Count Reg 2 */ #define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ #define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ #define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ #define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ #define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ -#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ -#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ -#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ +#define UDDR0 __REG(0x40600300) /* UDC Endpoint 0 Data Register */ +#define UDDR1 __REG(0x40600304) /* UDC Endpoint 1 Data Register */ +#define UDDR2 __REG(0x40600308) /* UDC Endpoint 2 Data Register */ #define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ #define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ #define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ @@ -708,7 +720,7 @@ typedef void (*ExcpHndlr) (void) ; #define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ #define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */
-#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ +#define UICR0 __REG(0x40600004) /* UDC Interrupt Control Register 0 */
#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ #define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ @@ -719,7 +731,7 @@ typedef void (*ExcpHndlr) (void) ; #define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ #define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
-#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ +#define UICR1 __REG(0x40600008) /* UDC Interrupt Control Register 1 */
#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ #define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ @@ -730,18 +742,18 @@ typedef void (*ExcpHndlr) (void) ; #define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ #define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
-#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ +#define USIR0 __REG(0x4060000C) /* UDC Status Interrupt Register 0 */
#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */ -#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */ -#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */ +#define USIR0_IR1 (1 << 2) /* Interrup request ep 1 */ +#define USIR0_IR2 (1 << 4) /* Interrup request ep 2 */ #define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */ #define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */ #define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */ #define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */ #define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */
-#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ +#define USIR1 __REG(0x40600010) /* UDC Status Interrupt Register 1 */
#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */ #define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */ @@ -751,23 +763,201 @@ typedef void (*ExcpHndlr) (void) ; #define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */ #define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */ #define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */ -#endif /* ! CONFIG_CPU_MONAHANS */
-#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
-/* - * USB Client Controller (incomplete) - */ -#define UDCCR __REG(0x40600000) -#define UDCICR0 __REG(0x40600004) -#define UDCCIR0 __REG(0x40600008) -#define UDCISR0 __REG(0x4060000c) -#define UDCSIR1 __REG(0x40600010) -#define UDCFNR __REG(0x40600014) -#define UDCOTGICR __REG(0x40600018) -#define UDCOTGISR __REG(0x4060001c) -#define UP2OCR __REG(0x40600020) -#define UP3OCR __REG(0x40600024) +#define UDCICR0 __REG(0x40600004) /* UDC Interrupt Control Register0 */ +#define UDCICR1 __REG(0x40600008) /* UDC Interrupt Control Register1 */ +#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ +#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ + +#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ +#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ +#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ +#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ + +#define UDCISR0 __REG(0x4060000C) /* UDC Interrupt Status Register 0 */ +#define UDCISR1 __REG(0x40600010) /* UDC Interrupt Status Register 1 */ +#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) +#define UDCISR1_IRCC (1 << 31) /* IntEn - Configuration Change */ +#define UDCISR1_IRSOF (1 << 30) /* IntEn - Start of Frame */ +#define UDCISR1_IRRU (1 << 29) /* IntEn - Resume */ +#define UDCISR1_IRSU (1 << 28) /* IntEn - Suspend */ +#define UDCISR1_IRRS (1 << 27) /* IntEn - Reset */ + + +#define UDCFNR __REG(0x40600014) /* UDC Frame Number Register */ +#define UDCOTGICR __REG(0x40600018) /* UDC On-The-Go interrupt control */ +#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ +#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge Interrupt Enable */ +#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge Interrupt Enable */ +#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge Interrupt Enable */ +#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising Edge Interrupt Enable */ +#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling Edge Interrupt Enable */ +#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge Interrupt Enable */ +#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge Interrupt Enable */ + +#define UDCCSN(x) __REG2(0x40600100, (x) << 2) +#define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ + +#define UDCCSR0_SA (1 << 7) /* Setup Active */ +#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */ +#define UDCCSR0_FST (1 << 5) /* Force Stall */ +#define UDCCSR0_SST (1 << 4) /* Sent Stall */ +#define UDCCSR0_DME (1 << 3) /* DMA Enable */ +#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ +#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ +#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ + +#define UDCCSRA __REG(0x40600104) /* UDC Control/Status register - Endpoint A */ +#define UDCCSRB __REG(0x40600108) /* UDC Control/Status register - Endpoint B */ +#define UDCCSRC __REG(0x4060010C) /* UDC Control/Status register - Endpoint C */ +#define UDCCSRD __REG(0x40600110) /* UDC Control/Status register - Endpoint D */ +#define UDCCSRE __REG(0x40600114) /* UDC Control/Status register - Endpoint E */ +#define UDCCSRF __REG(0x40600118) /* UDC Control/Status register - Endpoint F */ +#define UDCCSRG __REG(0x4060011C) /* UDC Control/Status register - Endpoint G */ +#define UDCCSRH __REG(0x40600120) /* UDC Control/Status register - Endpoint H */ +#define UDCCSRI __REG(0x40600124) /* UDC Control/Status register - Endpoint I */ +#define UDCCSRJ __REG(0x40600128) /* UDC Control/Status register - Endpoint J */ +#define UDCCSRK __REG(0x4060012C) /* UDC Control/Status register - Endpoint K */ +#define UDCCSRL __REG(0x40600130) /* UDC Control/Status register - Endpoint L */ +#define UDCCSRM __REG(0x40600134) /* UDC Control/Status register - Endpoint M */ +#define UDCCSRN __REG(0x40600138) /* UDC Control/Status register - Endpoint N */ +#define UDCCSRP __REG(0x4060013C) /* UDC Control/Status register - Endpoint P */ +#define UDCCSRQ __REG(0x40600140) /* UDC Control/Status register - Endpoint Q */ +#define UDCCSRR __REG(0x40600144) /* UDC Control/Status register - Endpoint R */ +#define UDCCSRS __REG(0x40600148) /* UDC Control/Status register - Endpoint S */ +#define UDCCSRT __REG(0x4060014C) /* UDC Control/Status register - Endpoint T */ +#define UDCCSRU __REG(0x40600150) /* UDC Control/Status register - Endpoint U */ +#define UDCCSRV __REG(0x40600154) /* UDC Control/Status register - Endpoint V */ +#define UDCCSRW __REG(0x40600158) /* UDC Control/Status register - Endpoint W */ +#define UDCCSRX __REG(0x4060015C) /* UDC Control/Status register - Endpoint X */ + +#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ +#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ +#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ +#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ +#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ +#define UDCCSR_FST (1 << 5) /* Force STALL */ +#define UDCCSR_SST (1 << 4) /* Sent STALL */ +#define UDCCSR_DME (1 << 3) /* DMA Enable */ +#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ +#define UDCCSR_PC (1 << 1) /* Packet Complete */ +#define UDCCSR_FS (1 << 0) /* FIFO needs service */ + +#define UDCBCN(x) __REG2(0x40600200, (x)<<2) +#define UDCBCR0 __REG(0x40600200) /* Byte Count Register - EP0 */ +#define UDCBCRA __REG(0x40600204) /* Byte Count Register - EPA */ +#define UDCBCRB __REG(0x40600208) /* Byte Count Register - EPB */ +#define UDCBCRC __REG(0x4060020C) /* Byte Count Register - EPC */ +#define UDCBCRD __REG(0x40600210) /* Byte Count Register - EPD */ +#define UDCBCRE __REG(0x40600214) /* Byte Count Register - EPE */ +#define UDCBCRF __REG(0x40600218) /* Byte Count Register - EPF */ +#define UDCBCRG __REG(0x4060021C) /* Byte Count Register - EPG */ +#define UDCBCRH __REG(0x40600220) /* Byte Count Register - EPH */ +#define UDCBCRI __REG(0x40600224) /* Byte Count Register - EPI */ +#define UDCBCRJ __REG(0x40600228) /* Byte Count Register - EPJ */ +#define UDCBCRK __REG(0x4060022C) /* Byte Count Register - EPK */ +#define UDCBCRL __REG(0x40600230) /* Byte Count Register - EPL */ +#define UDCBCRM __REG(0x40600234) /* Byte Count Register - EPM */ +#define UDCBCRN __REG(0x40600238) /* Byte Count Register - EPN */ +#define UDCBCRP __REG(0x4060023C) /* Byte Count Register - EPP */ +#define UDCBCRQ __REG(0x40600240) /* Byte Count Register - EPQ */ +#define UDCBCRR __REG(0x40600244) /* Byte Count Register - EPR */ +#define UDCBCRS __REG(0x40600248) /* Byte Count Register - EPS */ +#define UDCBCRT __REG(0x4060024C) /* Byte Count Register - EPT */ +#define UDCBCRU __REG(0x40600250) /* Byte Count Register - EPU */ +#define UDCBCRV __REG(0x40600254) /* Byte Count Register - EPV */ +#define UDCBCRW __REG(0x40600258) /* Byte Count Register - EPW */ +#define UDCBCRX __REG(0x4060025C) /* Byte Count Register - EPX */ + +#define UDCDN(x) __REG2(0x40600300, (x)<<2) +#define UDCDR0 __REG(0x40600300) /* Data Register - EP0 */ +#define UDCDRA __REG(0x40600304) /* Data Register - EPA */ +#define UDCDRB __REG(0x40600308) /* Data Register - EPB */ +#define UDCDRC __REG(0x4060030C) /* Data Register - EPC */ +#define UDCDRD __REG(0x40600310) /* Data Register - EPD */ +#define UDCDRE __REG(0x40600314) /* Data Register - EPE */ +#define UDCDRF __REG(0x40600318) /* Data Register - EPF */ +#define UDCDRG __REG(0x4060031C) /* Data Register - EPG */ +#define UDCDRH __REG(0x40600320) /* Data Register - EPH */ +#define UDCDRI __REG(0x40600324) /* Data Register - EPI */ +#define UDCDRJ __REG(0x40600328) /* Data Register - EPJ */ +#define UDCDRK __REG(0x4060032C) /* Data Register - EPK */ +#define UDCDRL __REG(0x40600330) /* Data Register - EPL */ +#define UDCDRM __REG(0x40600334) /* Data Register - EPM */ +#define UDCDRN __REG(0x40600338) /* Data Register - EPN */ +#define UDCDRP __REG(0x4060033C) /* Data Register - EPP */ +#define UDCDRQ __REG(0x40600340) /* Data Register - EPQ */ +#define UDCDRR __REG(0x40600344) /* Data Register - EPR */ +#define UDCDRS __REG(0x40600348) /* Data Register - EPS */ +#define UDCDRT __REG(0x4060034C) /* Data Register - EPT */ +#define UDCDRU __REG(0x40600350) /* Data Register - EPU */ +#define UDCDRV __REG(0x40600354) /* Data Register - EPV */ +#define UDCDRW __REG(0x40600358) /* Data Register - EPW */ +#define UDCDRX __REG(0x4060035C) /* Data Register - EPX */ + +#define UDCCN(x) __REG2(0x40600400, (x)<<2) +#define UDCCRA __REG(0x40600404) /* Configuration register EPA */ +#define UDCCRB __REG(0x40600408) /* Configuration register EPB */ +#define UDCCRC __REG(0x4060040C) /* Configuration register EPC */ +#define UDCCRD __REG(0x40600410) /* Configuration register EPD */ +#define UDCCRE __REG(0x40600414) /* Configuration register EPE */ +#define UDCCRF __REG(0x40600418) /* Configuration register EPF */ +#define UDCCRG __REG(0x4060041C) /* Configuration register EPG */ +#define UDCCRH __REG(0x40600420) /* Configuration register EPH */ +#define UDCCRI __REG(0x40600424) /* Configuration register EPI */ +#define UDCCRJ __REG(0x40600428) /* Configuration register EPJ */ +#define UDCCRK __REG(0x4060042C) /* Configuration register EPK */ +#define UDCCRL __REG(0x40600430) /* Configuration register EPL */ +#define UDCCRM __REG(0x40600434) /* Configuration register EPM */ +#define UDCCRN __REG(0x40600438) /* Configuration register EPN */ +#define UDCCRP __REG(0x4060043C) /* Configuration register EPP */ +#define UDCCRQ __REG(0x40600440) /* Configuration register EPQ */ +#define UDCCRR __REG(0x40600444) /* Configuration register EPR */ +#define UDCCRS __REG(0x40600448) /* Configuration register EPS */ +#define UDCCRT __REG(0x4060044C) /* Configuration register EPT */ +#define UDCCRU __REG(0x40600450) /* Configuration register EPU */ +#define UDCCRV __REG(0x40600454) /* Configuration register EPV */ +#define UDCCRW __REG(0x40600458) /* Configuration register EPW */ +#define UDCCRX __REG(0x4060045C) /* Configuration register EPX */ + +#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ +#define UDCCONR_CN_S (25) +#define UDCCONR_IN (0x07 << 22) /* Interface Number */ +#define UDCCONR_IN_S (22) +#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ +#define UDCCONR_AISN_S (19) +#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ +#define UDCCONR_EN_S (15) +#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ +#define UDCCONR_ET_S (13) +#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ +#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ +#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ +#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ +#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ +#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ +#define UDCCONR_MPS_S (2) +#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ +#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ + + +#define UDC_INT_FIFOERROR (0x2) +#define UDC_INT_PACKETCMP (0x1) +#define UDC_FNR_MASK (0x7ff) +#define UDCCSR_WR_MASK (UDCCSR_DME|UDCCSR_FST) +#define UDC_BCR_MASK (0x3ff) + +#endif /* CONFIG_PXA27X */ + +#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
/* * USB Host Controller diff --git a/include/usbdcore_pxa27x.h b/include/usbdcore_pxa27x.h new file mode 100644 index 0000000..e6d8121 --- /dev/null +++ b/include/usbdcore_pxa27x.h @@ -0,0 +1,69 @@ +/* + * PXA27x register declarations and HCD data structures + * + * Copyright (C) 2007 Rodolfo Giometti giometti@linux.it + * Copyright (C) 2007 Eurotech S.p.A. info@eurotech.it + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + + +#ifndef __USBDCORE_PXA270X_H__ +#define __USBDCORE_PXA270X_H__ + +#include <asm/byteorder.h> + +/* Endpoint 0 states */ +#define EP0_IDLE 0 +#define EP0_IN_DATA 1 +#define EP0_OUT_DATA 2 +#define EP0_XFER_COMPLETE 3 + + +/* Endpoint parameters */ +#define MAX_ENDPOINTS 4 +#define EP_MAX_PACKET_SIZE 64 + +#define EP0_MAX_PACKET_SIZE 16 +#define UDC_OUT_ENDPOINT 0x02 +#define UDC_OUT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_IN_ENDPOINT 0x01 +#define UDC_IN_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_INT_ENDPOINT 0x05 +#define UDC_INT_PACKET_SIZE EP_MAX_PACKET_SIZE +#define UDC_BULK_PACKET_SIZE EP_MAX_PACKET_SIZE + +void udc_irq(void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak(int epid); + +/* Higher level functions for abstracting away from specific device */ +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); + +int udc_init(void); + +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); + +void udc_connect(void); +void udc_disconnect(void); + +void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, + unsigned int ep, struct usb_endpoint_instance *endpoint); + +#endif

Dear Jean-Christophe & Remy,
In message 1236684053-21368-1-git-send-email-vivek.kutal@azingo.com Vivek Kutal wrote:
This Patch adds Support for PXA27X UDC.
Signed-off-by: Vivek Kutal vivek.kutal@azingo.com
Resinding after doing the changes suggested by Kim.
drivers/serial/usbtty.h | 4 +- drivers/usb/Makefile | 1 + drivers/usb/usbdcore_pxa27x.c | 702 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 296 ++++++++++++--- include/usbdcore_pxa27x.h | 69 ++++ 5 files changed, 1018 insertions(+), 54 deletions(-) create mode 100644 drivers/usb/usbdcore_pxa27x.c create mode 100644 include/usbdcore_pxa27x.h
Is this going to go through the USB or through the PXA tree?

On 23:28 Fri 03 Apr , Wolfgang Denk wrote:
Dear Jean-Christophe & Remy,
In message 1236684053-21368-1-git-send-email-vivek.kutal@azingo.com Vivek Kutal wrote:
This Patch adds Support for PXA27X UDC.
Signed-off-by: Vivek Kutal vivek.kutal@azingo.com
Resinding after doing the changes suggested by Kim.
drivers/serial/usbtty.h | 4 +- drivers/usb/Makefile | 1 + drivers/usb/usbdcore_pxa27x.c | 702 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 296 ++++++++++++--- include/usbdcore_pxa27x.h | 69 ++++ 5 files changed, 1018 insertions(+), 54 deletions(-) create mode 100644 drivers/usb/usbdcore_pxa27x.c create mode 100644 include/usbdcore_pxa27x.h
Is this going to go through the USB or through the PXA tree?
USB I guess But the patch will need to rebase due to the last usb dev
Best Regards, J.

Hello Vivek,
2009/3/10 Vivek Kutal vivek.kutal@azingo.com:
This Patch adds Support for PXA27X UDC.
Signed-off-by: Vivek Kutal vivek.kutal@azingo.com
Resinding after doing the changes suggested by Kim.
Applied to U-boot usb. Thanks.
Remy
participants (5)
-
Jean-Christophe PLAGNIOL-VILLARD
-
Kim Phillips
-
Remy Bohmer
-
Vivek Kutal
-
Wolfgang Denk