1 USB Device Controller Driver for Samsung S3C2410 SoC
3 Index: u-boot/drivers/Makefile
4 ===================================================================
5 --- u-boot.orig/drivers/Makefile
6 +++ u-boot/drivers/Makefile
8 status_led.o sym53c8xx.o systemace.o ahci.o \
9 ti_pci1410a.o tigon3.o tsec.o \
10 tsi108_eth.o tsi108_i2c.o tsi108_pci.o \
11 - usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \
12 + usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbdcore_s3c2410.o usbtty.o \
13 videomodes.o w83c553f.o \
16 Index: u-boot/drivers/usbdcore_s3c2410.c
17 ===================================================================
19 +++ u-boot/drivers/usbdcore_s3c2410.c
21 +/* S3C2410 USB Device Controller Driver for u-boot
23 + * (C) Copyright 2007 by Openmoko, Inc.
24 + * Author: Harald Welte <laforge@openmoko.org>
26 + * based on Linux' s3c2410_udc.c, which is
27 + * Copyright (C) 2004-2006 Herbert Pƶtzl - Arnaud Patard
29 + * This program is free software; you can redistribute it and/or modify
30 + * it under the terms of the GNU General Public License as published by
31 + * the Free Software Foundation; either version 2 of the License, or
32 + * (at your option) any later version.
34 + * This program is distributed in the hope that it will be useful,
35 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 + * GNU General Public License for more details.
39 + * You should have received a copy of the GNU General Public License
40 + * along with this program; if not, write to the Free Software
41 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
47 +#if defined(CONFIG_S3C2410) && defined(CONFIG_USB_DEVICE)
51 +/* we can't use the regular debug macros since the console might be
52 + * set to usbtty, which would cause deadlocks! */
56 +#define debug(fmt,args...) serial_printf (fmt ,##args)
57 +#define debugX(level,fmt,args...) if (DEBUG>=level) serial_printf(fmt,##args)
60 +DECLARE_GLOBAL_DATA_PTR;
65 +#include "usbdcore.h"
66 +#include "usbdcore_s3c2410.h"
67 +#include "usbdcore_ep0.h"
68 +#include <usb_cdc_acm.h>
78 +static struct urb *ep0_urb = NULL;
80 +static struct usb_device_instance *udc_device; /* Used in interrupt handler */
82 +static inline int fifo_count_out(void)
86 + tmp = inl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
87 + tmp |= inl(S3C2410_UDC_OUT_FIFO_CNT1_REG);
89 + return tmp & 0xffff;
92 +static const unsigned long ep_fifo_reg[S3C2410_UDC_NUM_ENDPOINTS] = {
93 + S3C2410_UDC_EP0_FIFO_REG,
94 + S3C2410_UDC_EP1_FIFO_REG,
95 + S3C2410_UDC_EP2_FIFO_REG,
96 + S3C2410_UDC_EP3_FIFO_REG,
97 + S3C2410_UDC_EP4_FIFO_REG,
100 +static int s3c2410_write_noniso_tx_fifo(struct usb_endpoint_instance *endpoint)
102 + struct urb *urb = endpoint->tx_urb;
103 + unsigned int last, i;
104 + unsigned int ep = endpoint->endpoint_address & 0x7f;
105 + unsigned long fifo_reg = ep_fifo_reg[ep];
107 + /* WARNING: don't ever put serial debug printf's in non-error codepaths
108 + * here, it is called from the time critical EP0 codepath ! */
110 + if (!urb || ep >= S3C2410_UDC_NUM_ENDPOINTS) {
111 + serial_printf("no urb or wrong endpoint\n");
115 + S3C2410_UDC_SETIX(ep);
116 + if ((last = MIN(urb->actual_length - endpoint->sent,
117 + endpoint->tx_packetSize))) {
118 + u8 *cp = urb->buffer + endpoint->sent;
120 + for (i = 0; i < last; i++)
121 + outb(*(cp+i), fifo_reg);
123 + endpoint->last = last;
125 + if (endpoint->sent + last < urb->actual_length) {
126 + /* not all data has been transmitted so far */
130 + if (last == endpoint->tx_packetSize) {
131 + /* we need to send one more packet (ZLP) */
139 +static void s3c2410_deconfigure_device (void)
141 + /* FIXME: Implement this */
144 +static void s3c2410_configure_device (struct usb_device_instance *device)
146 + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
147 + S3C24X0_CLOCK_POWER * const cpower = S3C24X0_GetBase_CLOCK_POWER();
149 + /* disable EP0-4 SUBD interrupts ? */
150 + outl(0x00, S3C2410_UDC_USB_INT_EN_REG);
152 + /* UPLL already configured by board-level init code */
154 + /* configure USB pads to device mode */
155 + gpio->MISCCR &= ~(S3C2410_MISCCR_USBHOST|S3C2410_MISCCR_USBSUSPND1);
157 + /* don't disable USB clock */
158 + cpower->CLKSLOW &= ~S3C2410_CLKSLOW_UCLK_OFF;
160 + /* clear interrupt registers */
161 + inl(S3C2410_UDC_EP_INT_REG);
162 + inl(S3C2410_UDC_USB_INT_REG);
163 + outl(0xff, S3C2410_UDC_EP_INT_REG);
164 + outl(0xff, S3C2410_UDC_USB_INT_REG);
166 + /* enable USB interrupts for RESET and SUSPEND/RESUME */
167 + outl(S3C2410_UDC_USBINT_RESET|S3C2410_UDC_USBINT_SUSPEND,
168 + S3C2410_UDC_USB_INT_EN_REG);
171 +static void udc_set_address(unsigned char address)
173 + address |= 0x80; /* ADDR_UPDATE bit */
174 + outl(address, S3C2410_UDC_FUNC_ADDR_REG);
177 +extern struct usb_device_descriptor device_descriptor;
179 +static void s3c2410_udc_ep0(void)
182 + struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array;
184 + S3C2410_UDC_SETIX(0);
185 + ep0csr = inl(S3C2410_UDC_IN_CSR1_REG);
187 + /* clear stall status */
188 + if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
189 + serial_printf("Clearing SENT_STALL\n");
191 + if (ep0csr & S3C2410_UDC_EP0_CSR_SOPKTRDY)
193 + ep0->state = EP0_IDLE;
197 + /* clear setup end */
198 + if (ep0csr & S3C2410_UDC_EP0_CSR_SE
199 + /* && ep0->state != EP0_IDLE */) {
200 + serial_printf("Clearing SETUP_END\n");
203 + if (ep0csr & S3C2410_UDC_EP0_CSR_SOPKTRDY) {
205 + while (inl(S3C2410_UDC_OUT_FIFO_CNT1_REG))
206 + inl(S3C2410_UDC_EP0_FIFO_REG);
210 + ep0->state = EP0_IDLE;
214 + /* Don't ever put [serial] debugging in non-error codepaths here, it
215 + * will violate the tight timing constraints of this USB Device
216 + * controller (and lead to bus enumeration failures) */
218 + switch (ep0->state) {
220 + unsigned char *datap;
222 + if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))
225 + datap = (unsigned char *) &ep0_urb->device_request;
226 + /* host->device packet has been received */
228 + /* pull it out of the fifo */
229 + fifo_count = fifo_count_out();
230 + for (i = 0; i < fifo_count; i++) {
231 + *datap = (unsigned char)inl(S3C2410_UDC_EP0_FIFO_REG);
234 + if (fifo_count != 8) {
235 + debug("STRANGE FIFO COUNT: %u bytes\n", fifo_count);
240 + if (ep0_urb->device_request.wLength == 0) {
241 + if (ep0_recv_setup(ep0_urb)) {
242 + /* Not a setup packet, stall next EP0 transaction */
243 + debug("can't parse setup packet1\n");
246 + ep0->state = EP0_IDLE;
249 + /* There are some requests with which we need to deal
251 + switch (ep0_urb->device_request.bRequest) {
252 + case USB_REQ_SET_CONFIGURATION:
253 + if (!ep0_urb->device_request.wValue)
254 + usbd_device_event_irq(udc_device,
255 + DEVICE_DE_CONFIGURED, 0);
257 + usbd_device_event_irq(udc_device,
258 + DEVICE_CONFIGURED, 0);
260 + case USB_REQ_SET_ADDRESS:
261 + udc_set_address(udc_device->address);
262 + usbd_device_event_irq(udc_device,
263 + DEVICE_ADDRESS_ASSIGNED, 0);
269 + ep0->state = EP0_IDLE;
271 + if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
272 + == USB_REQ_HOST2DEVICE) {
274 + ep0->state = EP0_OUT_DATA_PHASE;
275 + ep0_urb->buffer = ep0_urb->buffer_data;
276 + ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data);
277 + ep0_urb->actual_length = 0;
279 + ep0->state = EP0_IN_DATA_PHASE;
281 + if (ep0_recv_setup(ep0_urb)) {
282 + /* Not a setup packet, stall next EP0 transaction */
283 + debug("can't parse setup packet2\n");
285 + //set_ep0_de_out();
286 + ep0->state = EP0_IDLE;
290 + ep0->tx_urb = ep0_urb;
291 + ep0->sent = ep0->last = 0;
293 + if (s3c2410_write_noniso_tx_fifo(ep0)) {
294 + ep0->state = EP0_IDLE;
301 + case EP0_IN_DATA_PHASE:
302 + if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY)) {
303 + ep0->sent += ep0->last;
305 + if (s3c2410_write_noniso_tx_fifo(ep0)) {
306 + ep0->state = EP0_IDLE;
312 + case EP0_OUT_DATA_PHASE:
313 + if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {
314 + u32 urb_avail = ep0_urb->buffer_length - ep0_urb->actual_length;
315 + u_int8_t *cp = ep0_urb->buffer + ep0_urb->actual_length;
318 + fifo_count = fifo_count_out();
319 + if (fifo_count < urb_avail)
320 + urb_avail = fifo_count;
322 + for (i = 0; i < urb_avail; i++)
323 + *cp++ = inl(S3C2410_UDC_EP0_FIFO_REG);
325 + ep0_urb->actual_length += urb_avail;
327 + if (fifo_count < ep0->rcv_packetSize ||
328 + ep0_urb->actual_length >= ep0_urb->device_request.wLength) {
329 + ep0->state = EP0_IDLE;
330 + if (ep0_recv_setup(ep0_urb)) {
331 + /* Not a setup packet, stall next EP0 transaction */
332 + debug("can't parse setup packet3\n");
334 + //set_ep0_de_out();
343 + ep0->state = EP0_IDLE;
347 + ep0->state = EP0_IDLE;
353 +static void s3c2410_udc_epn(int ep)
355 + struct usb_endpoint_instance *endpoint;
359 + if (ep >= S3C2410_UDC_NUM_ENDPOINTS)
362 + endpoint = &udc_device->bus->endpoint_array[ep];
364 + S3C2410_UDC_SETIX(ep);
366 + if (endpoint->endpoint_address & USB_DIR_IN) {
367 + /* IN transfer (device to host) */
368 + ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG);
369 + debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1);
371 + urb = endpoint->tx_urb;
372 + if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {
373 + /* Stall handshake */
375 + outl(0x00, S3C2410_UDC_IN_CSR1_REG);
378 + if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && urb &&
379 + urb->actual_length) {
381 + debug("completing previously send data ");
382 + usbd_tx_complete(endpoint);
384 + /* push pending data into FIFO */
385 + if ((endpoint->last == endpoint->tx_packetSize) &&
386 + (urb->actual_length - endpoint->sent - endpoint->last == 0)) {
387 + endpoint->sent += endpoint->last;
388 + /* Write 0 bytes of data (ZLP) */
390 + outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);
392 + /* write actual data to fifo */
394 + s3c2410_write_noniso_tx_fifo(endpoint);
395 + outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);
400 + /* OUT transfer (host to device) */
401 + ep_csr1 = inl(S3C2410_UDC_OUT_CSR1_REG);
402 + debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1);
404 + urb = endpoint->rcv_urb;
405 + if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {
406 + /* Stall handshake */
407 + outl(0x00, S3C2410_UDC_IN_CSR1_REG);
410 + if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && urb) {
411 + /* Read pending data from fifo */
412 + u32 fifo_count = fifo_count_out();
414 + u32 i, urb_avail = urb->buffer_length - urb->actual_length;
415 + u8 *cp = urb->buffer + urb->actual_length;
417 + if (fifo_count < endpoint->rcv_packetSize)
420 + debug("fifo_count=%u is_last=%, urb_avail=%u)\n",
421 + fifo_count, is_last, urb_avail);
423 + if (fifo_count < urb_avail)
424 + urb_avail = fifo_count;
426 + for (i = 0; i < urb_avail; i++)
427 + *cp++ = inb(ep_fifo_reg[ep]);
430 + outl(ep_csr1 & ~S3C2410_UDC_OCSR1_PKTRDY,
431 + S3C2410_UDC_OUT_CSR1_REG);
433 + usbd_rcv_complete(endpoint, urb_avail, 0);
437 + urb = endpoint->rcv_urb;
441 +-------------------------------------------------------------------------------
444 +/* this is just an empty wrapper for usbtty who assumes polling operation */
449 +/* Handle general USB interrupts and dispatch according to type.
450 + * This function implements TRM Figure 14-13.
452 +void s3c2410_udc_irq(void)
454 + struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array;
455 + u_int32_t save_idx = inl(S3C2410_UDC_INDEX_REG);
457 + /* read interrupt sources */
458 + u_int32_t usb_status = inl(S3C2410_UDC_USB_INT_REG);
459 + u_int32_t usbd_status = inl(S3C2410_UDC_EP_INT_REG);
461 + //debug("< IRQ usbs=0x%02x, usbds=0x%02x start >", usb_status, usbd_status);
463 + /* clear interrupts */
464 + outl(usb_status, S3C2410_UDC_USB_INT_REG);
466 + if (usb_status & S3C2410_UDC_USBINT_RESET) {
467 + //serial_putc('R');
468 + debug("RESET pwr=0x%x\n", inl(S3C2410_UDC_PWR_REG));
469 + udc_setup_ep(udc_device, 0, ep0);
470 + outl(S3C2410_UDC_EP0_CSR_SSE|S3C2410_UDC_EP0_CSR_SOPKTRDY, S3C2410_UDC_EP0_CSR_REG);
471 + ep0->state = EP0_IDLE;
472 + usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
475 + if (usb_status & S3C2410_UDC_USBINT_RESUME) {
477 + usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0);
480 + if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
481 + debug("SUSPEND\n");
482 + usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0);
485 + /* Endpoint Interrupts */
489 + if (usbd_status & S3C2410_UDC_INT_EP0) {
490 + outl(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
494 + for (i = 1; i < 5; i++) {
495 + u_int32_t tmp = 1 << i;
497 + if (usbd_status & tmp) {
498 + /* FIXME: Handle EP X */
499 + outl(tmp, S3C2410_UDC_EP_INT_REG);
500 + s3c2410_udc_epn(i);
504 + S3C2410_UDC_SETIX(save_idx);
508 +-------------------------------------------------------------------------------
513 + * Start of public functions.
516 +/* Called to start packet transmission. */
517 +void udc_endpoint_write (struct usb_endpoint_instance *endpoint)
519 + unsigned short epnum =
520 + endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
522 + debug("Entering for ep %x ", epnum);
524 + if (endpoint->tx_urb) {
526 + debug("We have an URB, transmitting\n");
528 + s3c2410_write_noniso_tx_fifo(endpoint);
530 + S3C2410_UDC_SETIX(epnum);
532 + ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG);
533 + outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);
538 +/* Start to initialize h/w stuff */
541 + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
542 + S3C24X0_INTERRUPT * irq = S3C24X0_GetBase_INTERRUPT();
546 + /* Set and check clock control.
547 + * We might ought to be using the clock control API to do
548 + * this instead of fiddling with the clock registers directly
551 + clk_power->CLKCON |= (1 << 7);
553 + /* Print banner with device revision */
554 + printf("USB: S3C2410 USB Deviced\n");
557 + * At this point, device is ready for configuration...
559 + outl(0x00, S3C2410_UDC_EP_INT_EN_REG);
560 + outl(0x00, S3C2410_UDC_USB_INT_EN_REG);
562 + irq->INTMSK &= ~BIT_USBD;
568 + * udc_setup_ep - setup endpoint
570 + * Associate a physical endpoint with endpoint_instance
572 +int udc_setup_ep (struct usb_device_instance *device,
573 + unsigned int ep, struct usb_endpoint_instance *endpoint)
575 + int ep_addr = endpoint->endpoint_address;
580 + S3C2410_UDC_SETIX(ep);
583 + if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
585 + outl(S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT,
586 + S3C2410_UDC_IN_CSR1_REG);
587 + outl(S3C2410_UDC_ICSR2_MODEIN, S3C2410_UDC_IN_CSR2_REG);
588 + packet_size = endpoint->tx_packetSize;
589 + attributes = endpoint->tx_attributes;
592 + outl(S3C2410_UDC_ICSR1_CLRDT, S3C2410_UDC_IN_CSR1_REG);
593 + outl(0, S3C2410_UDC_IN_CSR2_REG);
594 + outl(S3C2410_UDC_OCSR1_FFLUSH|S3C2410_UDC_OCSR1_CLRDT,
595 + S3C2410_UDC_OUT_CSR1_REG);
596 + outl(0, S3C2410_UDC_OUT_CSR2_REG);
597 + packet_size = endpoint->rcv_packetSize;
598 + attributes = endpoint->rcv_attributes;
601 + packet_size = endpoint->tx_packetSize;
603 + switch (packet_size) {
605 + maxp = S3C2410_UDC_MAXP_8;
608 + maxp = S3C2410_UDC_MAXP_16;
611 + maxp = S3C2410_UDC_MAXP_32;
614 + maxp = S3C2410_UDC_MAXP_64;
617 + debug("invalid packet size %u\n", packet_size);
621 + debug("setting up endpoint %u addr %x packet_size %u maxp %u\n", ep,
622 + endpoint->endpoint_address, packet_size, maxp);
624 + /* Set maximum packet size */
625 + writel(maxp, S3C2410_UDC_MAXP_REG);
630 +/* ************************************************************************** */
633 + * udc_connected - is the USB cable connected
635 + * Return non-zero if cable is connected.
638 +int udc_connected (void)
640 + return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
644 +/* Turn on the USB connection by enabling the pullup resistor */
645 +void udc_connect (void)
647 + debug("connect, enable Pullup\n");
648 + S3C24X0_INTERRUPT * irq = S3C24X0_GetBase_INTERRUPT();
650 + udc_ctrl(UDC_CTRL_PULLUP_ENABLE, 0);
652 + udc_ctrl(UDC_CTRL_PULLUP_ENABLE, 1);
654 + irq->INTMSK &= ~BIT_USBD;
657 +/* Turn off the USB connection by disabling the pullup resistor */
658 +void udc_disconnect (void)
660 + debug("disconnect, disable Pullup\n");
661 + S3C24X0_INTERRUPT * irq = S3C24X0_GetBase_INTERRUPT();
663 + udc_ctrl(UDC_CTRL_PULLUP_ENABLE, 0);
665 + /* Disable interrupt (we don't want to get interrupts while the kernel
666 + * is relocating itself */
667 + irq->INTMSK |= BIT_USBD;
670 +/* Switch on the UDC */
671 +void udc_enable (struct usb_device_instance *device)
673 + debug("enable device %p, status %d\n", device, device->status);
675 + /* Save the device structure pointer */
676 + udc_device = device;
678 + /* Setup ep0 urb */
680 + ep0_urb = usbd_alloc_urb(udc_device,
681 + udc_device->bus->endpoint_array);
683 + serial_printf("udc_enable: ep0_urb already allocated %p\n",
686 + s3c2410_configure_device(device);
689 +/* Switch off the UDC */
690 +void udc_disable (void)
692 + debug("disable UDC\n");
694 + s3c2410_deconfigure_device();
698 + /*usbd_dealloc_urb(ep0_urb); */
702 + /* Reset device pointer.
703 + * We ought to do this here to balance the initialization of udc_device
704 + * in udc_enable, but some of our other exported functions get called
705 + * by the bus interface driver after udc_disable, so we have to hang on
706 + * to the device pointer to avoid a null pointer dereference. */
707 + /* udc_device = NULL; */
711 + * udc_startup - allow udc code to do any additional startup
713 +void udc_startup_events (struct usb_device_instance *device)
715 + /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
716 + usbd_device_event_irq (device, DEVICE_INIT, 0);
718 + /* The DEVICE_CREATE event puts the USB device in the state
721 + usbd_device_event_irq (device, DEVICE_CREATE, 0);
723 + /* Some USB controller driver implementations signal
724 + * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
725 + * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
726 + * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
727 + * The OMAP USB client controller has the capability to detect when the
728 + * USB cable is connected to a powered USB bus via the ATT bit in the
729 + * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and
730 + * DEVICE_RESET events until later.
733 + /* The GTA01 can detect usb device attachment, but we just assume being
734 + * attached for now (go to STATE_POWERED) */
735 + usbd_device_event_irq (device, DEVICE_HUB_CONFIGURED, 0);
737 + udc_enable (device);
740 +void udc_set_nak(int epid)
742 + /* FIXME: implement this */
745 +void udc_unset_nak(int epid)
747 + /* FIXME: implement this */
750 +#endif /* CONFIG_S3C2410 && CONFIG_USB_DEVICE */
751 Index: u-boot/drivers/usbdcore_s3c2410.h
752 ===================================================================
754 +++ u-boot/drivers/usbdcore_s3c2410.h
756 +/* linux/include/asm/arch-s3c2410/regs-udc.h
758 + * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
760 + * This include file is free software; you can redistribute it and/or
761 + * modify it under the terms of the GNU General Public License as
762 + * published by the Free Software Foundation; either version 2 of
763 + * the License, or (at your option) any later version.
766 + * 01-08-2004 Initial creation
767 + * 12-09-2004 Cleanup for submission
768 + * 24-10-2004 Fixed S3C2410_UDC_MAXP_REG definition
769 + * 10-03-2005 Changed S3C2410_VA to S3C24XX_VA
770 + * 10-01-2007 Modify for u-boot
773 +#ifndef __ASM_ARCH_REGS_UDC_H
774 +#define __ASM_ARCH_REGS_UDC_H
776 +#define S3C2410_UDC_REG_BASE_PHYS 0x52000000
777 +#define S3C2410_UDC_NUM_ENDPOINTS 5
779 +#define S3C2410_USBDREG(x) (x + S3C2410_UDC_REG_BASE_PHYS)
781 +#define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140)
782 +#define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144)
783 +#define S3C2410_UDC_EP_INT_REG S3C2410_USBDREG(0x0148)
785 +#define S3C2410_UDC_USB_INT_REG S3C2410_USBDREG(0x0158)
786 +#define S3C2410_UDC_EP_INT_EN_REG S3C2410_USBDREG(0x015c)
788 +#define S3C2410_UDC_USB_INT_EN_REG S3C2410_USBDREG(0x016c)
790 +#define S3C2410_UDC_FRAME_NUM1_REG S3C2410_USBDREG(0x0170)
791 +#define S3C2410_UDC_FRAME_NUM2_REG S3C2410_USBDREG(0x0174)
793 +#define S3C2410_UDC_EP0_FIFO_REG S3C2410_USBDREG(0x01c0)
794 +#define S3C2410_UDC_EP1_FIFO_REG S3C2410_USBDREG(0x01c4)
795 +#define S3C2410_UDC_EP2_FIFO_REG S3C2410_USBDREG(0x01c8)
796 +#define S3C2410_UDC_EP3_FIFO_REG S3C2410_USBDREG(0x01cc)
797 +#define S3C2410_UDC_EP4_FIFO_REG S3C2410_USBDREG(0x01d0)
799 +#define S3C2410_UDC_EP1_DMA_CON S3C2410_USBDREG(0x0200)
800 +#define S3C2410_UDC_EP1_DMA_UNIT S3C2410_USBDREG(0x0204)
801 +#define S3C2410_UDC_EP1_DMA_FIFO S3C2410_USBDREG(0x0208)
802 +#define S3C2410_UDC_EP1_DMA_TTC_L S3C2410_USBDREG(0x020c)
803 +#define S3C2410_UDC_EP1_DMA_TTC_M S3C2410_USBDREG(0x0210)
804 +#define S3C2410_UDC_EP1_DMA_TTC_H S3C2410_USBDREG(0x0214)
806 +#define S3C2410_UDC_EP2_DMA_CON S3C2410_USBDREG(0x0218)
807 +#define S3C2410_UDC_EP2_DMA_UNIT S3C2410_USBDREG(0x021c)
808 +#define S3C2410_UDC_EP2_DMA_FIFO S3C2410_USBDREG(0x0220)
809 +#define S3C2410_UDC_EP2_DMA_TTC_L S3C2410_USBDREG(0x0224)
810 +#define S3C2410_UDC_EP2_DMA_TTC_M S3C2410_USBDREG(0x0228)
811 +#define S3C2410_UDC_EP2_DMA_TTC_H S3C2410_USBDREG(0x022c)
813 +#define S3C2410_UDC_EP3_DMA_CON S3C2410_USBDREG(0x0240)
814 +#define S3C2410_UDC_EP3_DMA_UNIT S3C2410_USBDREG(0x0244)
815 +#define S3C2410_UDC_EP3_DMA_FIFO S3C2410_USBDREG(0x0248)
816 +#define S3C2410_UDC_EP3_DMA_TTC_L S3C2410_USBDREG(0x024c)
817 +#define S3C2410_UDC_EP3_DMA_TTC_M S3C2410_USBDREG(0x0250)
818 +#define S3C2410_UDC_EP3_DMA_TTC_H S3C2410_USBDREG(0x0254)
820 +#define S3C2410_UDC_EP4_DMA_CON S3C2410_USBDREG(0x0258)
821 +#define S3C2410_UDC_EP4_DMA_UNIT S3C2410_USBDREG(0x025c)
822 +#define S3C2410_UDC_EP4_DMA_FIFO S3C2410_USBDREG(0x0260)
823 +#define S3C2410_UDC_EP4_DMA_TTC_L S3C2410_USBDREG(0x0264)
824 +#define S3C2410_UDC_EP4_DMA_TTC_M S3C2410_USBDREG(0x0268)
825 +#define S3C2410_UDC_EP4_DMA_TTC_H S3C2410_USBDREG(0x026c)
827 +#define S3C2410_UDC_INDEX_REG S3C2410_USBDREG(0x0178)
829 +/* indexed registers */
831 +#define S3C2410_UDC_MAXP_REG S3C2410_USBDREG(0x0180)
833 +#define S3C2410_UDC_EP0_CSR_REG S3C2410_USBDREG(0x0184)
835 +#define S3C2410_UDC_IN_CSR1_REG S3C2410_USBDREG(0x0184)
836 +#define S3C2410_UDC_IN_CSR2_REG S3C2410_USBDREG(0x0188)
838 +#define S3C2410_UDC_OUT_CSR1_REG S3C2410_USBDREG(0x0190)
839 +#define S3C2410_UDC_OUT_CSR2_REG S3C2410_USBDREG(0x0194)
840 +#define S3C2410_UDC_OUT_FIFO_CNT1_REG S3C2410_USBDREG(0x0198)
841 +#define S3C2410_UDC_OUT_FIFO_CNT2_REG S3C2410_USBDREG(0x019c)
845 +#define S3C2410_UDC_PWR_ISOUP (1<<7) // R/W
846 +#define S3C2410_UDC_PWR_RESET (1<<3) // R
847 +#define S3C2410_UDC_PWR_RESUME (1<<2) // R/W
848 +#define S3C2410_UDC_PWR_SUSPEND (1<<1) // R
849 +#define S3C2410_UDC_PWR_ENSUSPEND (1<<0) // R/W
851 +#define S3C2410_UDC_PWR_DEFAULT 0x00
853 +#define S3C2410_UDC_INT_EP4 (1<<4) // R/W (clear only)
854 +#define S3C2410_UDC_INT_EP3 (1<<3) // R/W (clear only)
855 +#define S3C2410_UDC_INT_EP2 (1<<2) // R/W (clear only)
856 +#define S3C2410_UDC_INT_EP1 (1<<1) // R/W (clear only)
857 +#define S3C2410_UDC_INT_EP0 (1<<0) // R/W (clear only)
859 +#define S3C2410_UDC_USBINT_RESET (1<<2) // R/W (clear only)
860 +#define S3C2410_UDC_USBINT_RESUME (1<<1) // R/W (clear only)
861 +#define S3C2410_UDC_USBINT_SUSPEND (1<<0) // R/W (clear only)
863 +#define S3C2410_UDC_INTE_EP4 (1<<4) // R/W
864 +#define S3C2410_UDC_INTE_EP3 (1<<3) // R/W
865 +#define S3C2410_UDC_INTE_EP2 (1<<2) // R/W
866 +#define S3C2410_UDC_INTE_EP1 (1<<1) // R/W
867 +#define S3C2410_UDC_INTE_EP0 (1<<0) // R/W
869 +#define S3C2410_UDC_USBINTE_RESET (1<<2) // R/W
870 +#define S3C2410_UDC_USBINTE_SUSPEND (1<<0) // R/W
873 +#define S3C2410_UDC_INDEX_EP0 (0x00)
874 +#define S3C2410_UDC_INDEX_EP1 (0x01) // ??
875 +#define S3C2410_UDC_INDEX_EP2 (0x02) // ??
876 +#define S3C2410_UDC_INDEX_EP3 (0x03) // ??
877 +#define S3C2410_UDC_INDEX_EP4 (0x04) // ??
879 +#define S3C2410_UDC_ICSR1_CLRDT (1<<6) // R/W
880 +#define S3C2410_UDC_ICSR1_SENTSTL (1<<5) // R/W (clear only)
881 +#define S3C2410_UDC_ICSR1_SENDSTL (1<<4) // R/W
882 +#define S3C2410_UDC_ICSR1_FFLUSH (1<<3) // W (set only)
883 +#define S3C2410_UDC_ICSR1_UNDRUN (1<<2) // R/W (clear only)
884 +#define S3C2410_UDC_ICSR1_PKTRDY (1<<0) // R/W (set only)
886 +#define S3C2410_UDC_ICSR2_AUTOSET (1<<7) // R/W
887 +#define S3C2410_UDC_ICSR2_ISO (1<<6) // R/W
888 +#define S3C2410_UDC_ICSR2_MODEIN (1<<5) // R/W
889 +#define S3C2410_UDC_ICSR2_DMAIEN (1<<4) // R/W
891 +#define S3C2410_UDC_OCSR1_CLRDT (1<<7) // R/W
892 +#define S3C2410_UDC_OCSR1_SENTSTL (1<<6) // R/W (clear only)
893 +#define S3C2410_UDC_OCSR1_SENDSTL (1<<5) // R/W
894 +#define S3C2410_UDC_OCSR1_FFLUSH (1<<4) // R/W
895 +#define S3C2410_UDC_OCSR1_DERROR (1<<3) // R
896 +#define S3C2410_UDC_OCSR1_OVRRUN (1<<2) // R/W (clear only)
897 +#define S3C2410_UDC_OCSR1_PKTRDY (1<<0) // R/W (clear only)
899 +#define S3C2410_UDC_OCSR2_AUTOCLR (1<<7) // R/W
900 +#define S3C2410_UDC_OCSR2_ISO (1<<6) // R/W
901 +#define S3C2410_UDC_OCSR2_DMAIEN (1<<5) // R/W
903 +#define S3C2410_UDC_SETIX(X) writel(X, S3C2410_UDC_INDEX_REG)
905 +#define S3C2410_UDC_EP0_CSR_OPKRDY (1<<0)
906 +#define S3C2410_UDC_EP0_CSR_IPKRDY (1<<1)
907 +#define S3C2410_UDC_EP0_CSR_SENTSTL (1<<2)
908 +#define S3C2410_UDC_EP0_CSR_DE (1<<3)
909 +#define S3C2410_UDC_EP0_CSR_SE (1<<4)
910 +#define S3C2410_UDC_EP0_CSR_SENDSTL (1<<5)
911 +#define S3C2410_UDC_EP0_CSR_SOPKTRDY (1<<6)
912 +#define S3C2410_UDC_EP0_CSR_SSE (1<<7)
914 +#define S3C2410_UDC_MAXP_8 (1<<0)
915 +#define S3C2410_UDC_MAXP_16 (1<<1)
916 +#define S3C2410_UDC_MAXP_32 (1<<2)
917 +#define S3C2410_UDC_MAXP_64 (1<<3)
919 +/****************** MACROS ******************/
920 +#define BIT_MASK 0xFF
923 +#define maskl(v,m,a) \
924 + writel((readl(a) & ~(m))|((v)&(m)), (a))
926 +#define maskl(v,m,a) do { \
927 + unsigned long foo = readl(a); \
928 + unsigned long bar = (foo & ~(m)) | ((v)&(m)); \
929 + serial_printf("0x%08x:0x%x->0x%x\n", (a), foo, bar); \
930 + writel(bar, (a)); \
934 +#define clear_ep0_sst() do { \
935 + S3C2410_UDC_SETIX(0); \
936 + writel(0x00, S3C2410_UDC_EP0_CSR_REG); \
939 +#define clear_ep0_se() do { \
940 + S3C2410_UDC_SETIX(0); \
941 + maskl(S3C2410_UDC_EP0_CSR_SSE, \
942 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
945 +#define clear_ep0_opr() do { \
946 + S3C2410_UDC_SETIX(0); \
947 + maskl(S3C2410_UDC_EP0_CSR_SOPKTRDY, \
948 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
951 +#define set_ep0_ipr() do { \
952 + S3C2410_UDC_SETIX(0); \
953 + maskl(S3C2410_UDC_EP0_CSR_IPKRDY, \
954 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
957 +#define set_ep0_de() do { \
958 + S3C2410_UDC_SETIX(0); \
959 + maskl(S3C2410_UDC_EP0_CSR_DE, \
960 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
963 +#define set_ep0_ss() do { \
964 + S3C2410_UDC_SETIX(0); \
965 + maskl(S3C2410_UDC_EP0_CSR_SENDSTL, \
966 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
969 +#define set_ep0_de_out() do { \
970 + S3C2410_UDC_SETIX(0); \
971 + maskl((S3C2410_UDC_EP0_CSR_SOPKTRDY \
972 + | S3C2410_UDC_EP0_CSR_DE), \
973 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
976 +#define set_ep0_sse_out() do { \
977 + S3C2410_UDC_SETIX(0); \
978 + maskl((S3C2410_UDC_EP0_CSR_SOPKTRDY \
979 + | S3C2410_UDC_EP0_CSR_SSE), \
980 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
983 +#define set_ep0_de_in() do { \
984 + S3C2410_UDC_SETIX(0); \
985 + maskl((S3C2410_UDC_EP0_CSR_IPKRDY \
986 + | S3C2410_UDC_EP0_CSR_DE), \
987 + BIT_MASK, S3C2410_UDC_EP0_CSR_REG); \
993 +#define clear_stall_ep1_out(base) do { \
994 + S3C2410_UDC_SETIX(base,EP1); \
995 + orl(0,base+S3C2410_UDC_OUT_CSR1_REG); \
999 +#define clear_stall_ep2_out(base) do { \
1000 + S3C2410_UDC_SETIX(base,EP2); \
1001 + orl(0, base+S3C2410_UDC_OUT_CSR1_REG); \
1005 +#define clear_stall_ep3_out(base) do { \
1006 + S3C2410_UDC_SETIX(base,EP3); \
1007 + orl(0,base+S3C2410_UDC_OUT_CSR1_REG); \
1011 +#define clear_stall_ep4_out(base) do { \
1012 + S3C2410_UDC_SETIX(base,EP4); \
1013 + orl(0, base+S3C2410_UDC_OUT_CSR1_REG); \
1018 +/* S3C2410 Endpoint parameters */
1019 +#define EP0_MAX_PACKET_SIZE 16
1020 +#define UDC_OUT_ENDPOINT 2
1021 +#define UDC_OUT_PACKET_SIZE 64
1022 +#define UDC_IN_ENDPOINT 1
1023 +#define UDC_IN_PACKET_SIZE 64
1024 +#define UDC_INT_ENDPOINT 5
1025 +#define UDC_INT_PACKET_SIZE 16
1026 +#define UDC_BULK_PACKET_SIZE 16
1029 Index: u-boot/drivers/usbdcore_ep0.c
1030 ===================================================================
1031 --- u-boot.orig/drivers/usbdcore_ep0.c
1032 +++ u-boot/drivers/usbdcore_ep0.c
1037 -#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
1038 +#if defined(CONFIG_USB_DEVICE)
1039 #include "usbdcore.h"
1042 @@ -187,9 +187,13 @@
1043 if (!urb || !urb->buffer || !urb->buffer_length
1044 || (urb->buffer_length < 255)) {
1045 dbg_ep0 (2, "invalid urb %p", urb);
1046 + serial_printf("invalid urb %p", urb);
1050 + /* re-initialize the ep0 buffer pointer */
1051 + urb->buffer = (u8 *) urb->buffer_data;
1054 urb->actual_length = 0;
1056 @@ -206,17 +210,8 @@
1057 usbd_device_device_descriptor (device, port))) {
1060 - /* copy descriptor for this device */
1061 - copy_config (urb, device_descriptor,
1062 - sizeof (struct usb_device_descriptor),
1065 - /* correct the correct control endpoint 0 max packet size into the descriptor */
1066 - device_descriptor =
1067 - (struct usb_device_descriptor *) urb->buffer;
1068 - device_descriptor->bMaxPacketSize0 =
1069 - urb->device->bus->maxpacketsize;
1071 + urb->buffer = device_descriptor;
1072 + urb->actual_length = MIN(sizeof(*device_descriptor), max);
1074 /*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
1076 @@ -250,11 +245,9 @@
1080 - copy_config (urb, configuration_descriptor,
1082 - usb_configuration_descriptor),
1085 + urb->buffer = configuration_descriptor;
1086 + urb->actual_length =
1087 + MIN(le16_to_cpu(configuration_descriptor->wTotalLength), max);
1092 dbg_ep0 (0, "entering ep0_recv_setup()");
1093 if (!urb || !urb->device) {
1094 dbg_ep0 (3, "invalid URB %p", urb);
1095 + serial_printf("invalid URB %p", urb);
1100 return device->cdc_recv_setup(request, urb);
1101 dbg_ep0 (1, "non standard request: %x",
1102 request->bmRequestType & USB_REQ_TYPE_MASK);
1103 + serial_printf("non standard request: %x", request->bmRequestType & USB_REQ_TYPE_MASK);
1104 return -1; /* Stall here */
1108 dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
1109 USBD_DEVICE_REQUESTS (request->bRequest),
1110 usbd_device_states[device->device_state]);
1111 + serial_printf("request %s not allowed in UNKNOWN state: %s", USBD_DEVICE_REQUESTS (request->bRequest), usbd_device_states[device->device_state]);
1117 /*dbg_ep0(2, "address: %d %d %d", */
1118 /* request->wValue, le16_to_cpu(request->wValue), device->address); */
1120 - serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
1121 + //serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
1122 + //udc_set_address(device->address);
1125 case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */
1126 Index: u-boot/include/configs/neo1973_gta01.h
1127 ===================================================================
1128 --- u-boot.orig/include/configs/neo1973_gta01.h
1129 +++ u-boot/include/configs/neo1973_gta01.h
1130 @@ -173,6 +173,16 @@
1131 #define CONFIG_USB_OHCI 1
1134 +#define CONFIG_USB_DEVICE 1
1135 +#define CONFIG_USB_TTY 1
1136 +#define CFG_CONSOLE_IS_IN_ENV 1
1137 +#define CONFIG_USBD_VENDORID 0x1457 /* Linux/NetChip */
1138 +#define CONFIG_USBD_PRODUCTID_GSERIAL 0x5120 /* gserial */
1139 +#define CONFIG_USBD_PRODUCTID_CDCACM 0x5119 /* CDC ACM */
1140 +#define CONFIG_USBD_MANUFACTURER "Openmoko, Inc"
1141 +#define CONFIG_USBD_PRODUCT_NAME "Neo1973 Bootloader " U_BOOT_VERSION
1142 +#define CONFIG_EXTRA_ENV_SETTINGS "usbtty=cdc_acm\0"
1144 /*-----------------------------------------------------------------------
1145 * Physical Memory Map
1147 Index: u-boot/cpu/arm920t/s3c24x0/interrupts.c
1148 ===================================================================
1149 --- u-boot.orig/cpu/arm920t/s3c24x0/interrupts.c
1150 +++ u-boot/cpu/arm920t/s3c24x0/interrupts.c
1151 @@ -222,6 +222,13 @@
1152 S3C24X0_INTERRUPT * irq = S3C24X0_GetBase_INTERRUPT();
1153 u_int32_t intpnd = irq->INTPND;
1155 +#ifdef CONFIG_USB_DEVICE
1156 + if (intpnd & BIT_USBD) {
1157 + s3c2410_udc_irq();
1158 + irq->SRCPND = BIT_USBD;
1159 + irq->INTPND = BIT_USBD;
1161 +#endif /* USB_DEVICE */
1163 #endif /* USE_IRQ */
1165 Index: u-boot/drivers/usbtty.h
1166 ===================================================================
1167 --- u-boot.orig/drivers/usbtty.h
1168 +++ u-boot/drivers/usbtty.h
1170 #include "usbdcore_mpc8xx.h"
1171 #elif defined(CONFIG_OMAP1510)
1172 #include "usbdcore_omap1510.h"
1173 +#elif defined(CONFIG_S3C2410)
1174 +#include "usbdcore_s3c2410.h"
1178 Index: u-boot/board/neo1973/common/cmd_neo1973.c
1179 ===================================================================
1180 --- u-boot.orig/board/neo1973/common/cmd_neo1973.c
1181 +++ u-boot/board/neo1973/common/cmd_neo1973.c
1183 neo1973_vibrator(1);
1185 neo1973_vibrator(0);
1186 + } else if (!strcmp(argv[1], "udc")) {
1189 + if (!strcmp(argv[2], "udc")) {
1192 + if (!strcmp(argv[3], "on"))
1200 printf("Usage:\n%s\n", cmdtp->usage);
1202 "neo1973 charger off - disable charging\n"
1203 "neo1973 backlight (on|off) - switch backlight on or off\n"
1204 "neo1973 vibrator (on|off) - switch vibrator on or off\n"
1205 + "neo1973 udc pullup (on|off) - switch pull-up on or off\n"
1207 #endif /* CFG_CMD_BDI */
1208 Index: u-boot/board/neo1973/gta01/Makefile
1209 ===================================================================
1210 --- u-boot.orig/board/neo1973/gta01/Makefile
1211 +++ u-boot/board/neo1973/gta01/Makefile
1216 -OBJS := gta01.o pcf50606.o ../common/cmd_neo1973.o ../common/jbt6k74.o
1217 +OBJS := gta01.o pcf50606.o ../common/cmd_neo1973.o ../common/jbt6k74.o ../common/udc.o
1218 SOBJS := ../common/lowlevel_init.o
1220 $(LIB): $(OBJS) $(SOBJS)
1221 Index: u-boot/board/neo1973/common/udc.c
1222 ===================================================================
1224 +++ u-boot/board/neo1973/common/udc.c
1227 +#include <common.h>
1228 +#include <usbdcore.h>
1229 +#include <s3c2410.h>
1231 +void udc_ctrl(enum usbd_event event, int param)
1233 + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
1236 + case UDC_CTRL_PULLUP_ENABLE:
1237 +#if defined(CONFIG_ARCH_GTA01_v4) || defined(CONFIG_ARCH_GTA01B_v2) || \
1238 + defined(CONFIG_ARCH_GTA01B_v3) || defined(CONFIG_ARCH_GTA01B_v4)
1240 + gpio->GPBDAT |= (1 << 9);
1242 + gpio->GPBDAT &= ~(1 << 9);
1249 Index: u-boot/include/usbdcore.h
1250 ===================================================================
1251 --- u-boot.orig/include/usbdcore.h
1252 +++ u-boot/include/usbdcore.h
1253 @@ -671,4 +671,10 @@
1254 void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad);
1255 void usbd_tx_complete (struct usb_endpoint_instance *endpoint);
1258 + UDC_CTRL_PULLUP_ENABLE,
1261 +void udc_ctrl(enum usbd_event event, int param);