📄 uboot-s3c2410_udc.patch
字号:
USB Device Controller Driver for Samsung S3C2410 SoCIndex: u-boot/drivers/usb/Makefile===================================================================--- u-boot.orig/drivers/usb/Makefile+++ u-boot/drivers/usb/Makefile@@ -32,6 +32,7 @@ COBJS-y += usbdcore_ep0.o COBJS-y += usbdcore_mpc8xx.o COBJS-y += usbdcore_omap1510.o+COBJS-y += usbdcore_s3c2410.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c)Index: u-boot/drivers/usb/usbdcore_s3c2410.c===================================================================--- /dev/null+++ u-boot/drivers/usb/usbdcore_s3c2410.c@@ -0,0 +1,751 @@+/* S3C2410 USB Device Controller Driver for u-boot+ *+ * (C) Copyright 2007 by OpenMoko, Inc.+ * Author: Harald Welte <laforge@openmoko.org>+ *+ * based on Linux' s3c2410_udc.c, which is+ * Copyright (C) 2004-2006 Herbert P枚tzl - Arnaud Patard+ *+ * 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 <config.h>++#if defined(CONFIG_S3C2410) && defined(CONFIG_USB_DEVICE)++#include <common.h>++/* we can't use the regular debug macros since the console might be+ * set to usbtty, which would cause deadlocks! */+#ifdef DEBUG+#undef debug+#undef debugX+#define debug(fmt,args...) serial_printf (fmt ,##args)+#define debugX(level,fmt,args...) if (DEBUG>=level) serial_printf(fmt,##args)+#endif++DECLARE_GLOBAL_DATA_PTR;++#include <asm/io.h>+#include <s3c2410.h>++#include "usbdcore.h"+#include "usbdcore_s3c2410.h"+#include "usbdcore_ep0.h"+#include <usb_cdc_acm.h>++static void debug_urb_buffer(char *prefix, struct usb_endpoint_instance *ep)+{+#ifdef DEBUG+ int num;+ static char buf[128];++ if (!ep->tx_urb) {+ serial_printf("no tx_urb\n");+ return;+ }++ num = MIN(ep->tx_urb->actual_length - ep->sent, ep->tx_packetSize);++ memset(buf, 0, sizeof(buf));+ strncpy(buf, ep->tx_urb->buffer + ep->sent, num);++ serial_printf("%s(%d:%s)\n", prefix, num, buf);+#endif+}+++enum ep0_state {+ EP0_IDLE,+ EP0_IN_DATA_PHASE,+ EP0_OUT_DATA_PHASE,+ EP0_END_XFER,+ EP0_STALL,+};++static struct urb *ep0_urb = NULL;++static struct usb_device_instance *udc_device; /* Used in interrupt handler */++static inline int fifo_count_out(void)+{+ int tmp;++ tmp = inl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;+ tmp |= inl(S3C2410_UDC_OUT_FIFO_CNT1_REG);++ return tmp & 0xffff;+}++static const unsigned long ep_fifo_reg[S3C2410_UDC_NUM_ENDPOINTS] = {+ S3C2410_UDC_EP0_FIFO_REG,+ S3C2410_UDC_EP1_FIFO_REG,+ S3C2410_UDC_EP2_FIFO_REG,+ S3C2410_UDC_EP3_FIFO_REG,+ S3C2410_UDC_EP4_FIFO_REG,+};++static int s3c2410_write_noniso_tx_fifo(struct usb_endpoint_instance *endpoint)+{+ struct urb *urb = endpoint->tx_urb;+ unsigned int last, i;+ unsigned int ep = endpoint->endpoint_address & 0x7f;+ unsigned long fifo_reg = ep_fifo_reg[ep];++ /* WARNING: don't ever put serial debug printf's in non-error codepaths+ * here, it is called from the time critical EP0 codepath ! */++ if (!urb || ep >= S3C2410_UDC_NUM_ENDPOINTS) {+ serial_printf("no urb or wrong endpoint\n");+ return -1;+ }++ S3C2410_UDC_SETIX(ep);+ if ((last = MIN(urb->actual_length - endpoint->sent,+ endpoint->tx_packetSize))) {+ u8 *cp = urb->buffer + endpoint->sent;++ for (i = 0; i < last; i++)+ outb(*(cp+i), fifo_reg);+ }+ endpoint->last = last;++ if (endpoint->sent + last < urb->actual_length) {+ /* not all data has been transmitted so far */+ return 0;+ }++ if (last == endpoint->tx_packetSize) {+ /* we need to send one more packet (ZLP) */+ return 0;+ }++ return 1;+}+++static void s3c2410_deconfigure_device (void)+{+ /* FIXME: Implement this */+}++static void s3c2410_configure_device (struct usb_device_instance *device)+{+ S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();+ S3C24X0_CLOCK_POWER * const cpower = S3C24X0_GetBase_CLOCK_POWER();++ /* disable EP0-4 SUBD interrupts ? */+ outl(0x00, S3C2410_UDC_USB_INT_EN_REG);++ /* UPLL already configured by board-level init code */++ /* configure USB pads to device mode */+ gpio->MISCCR &= ~(S3C2410_MISCCR_USBHOST|S3C2410_MISCCR_USBSUSPND1);++ /* don't disable USB clock */+ cpower->CLKSLOW &= ~S3C2410_CLKSLOW_UCLK_OFF;++ /* clear interrupt registers */+ inl(S3C2410_UDC_EP_INT_REG);+ inl(S3C2410_UDC_USB_INT_REG);+ outl(0xff, S3C2410_UDC_EP_INT_REG);+ outl(0xff, S3C2410_UDC_USB_INT_REG);++ /* enable USB interrupts for RESET and SUSPEND/RESUME */+ outl(S3C2410_UDC_USBINT_RESET|S3C2410_UDC_USBINT_SUSPEND,+ S3C2410_UDC_USB_INT_EN_REG);+}++static void udc_set_address(unsigned char address)+{+ address |= 0x80; /* ADDR_UPDATE bit */+ outl(address, S3C2410_UDC_FUNC_ADDR_REG);+}++extern struct usb_device_descriptor device_descriptor;++static void s3c2410_udc_ep0(void)+{+ u_int8_t ep0csr;+ struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array;++ S3C2410_UDC_SETIX(0);+ ep0csr = inl(S3C2410_UDC_IN_CSR1_REG);++ /* clear stall status */+ if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {+ serial_printf("Clearing SENT_STALL\n");+ clear_ep0_sst();+ if (ep0csr & S3C2410_UDC_EP0_CSR_SOPKTRDY)+ clear_ep0_opr();+ ep0->state = EP0_IDLE;+ return;+ }++ /* clear setup end */+ if (ep0csr & S3C2410_UDC_EP0_CSR_SE+ /* && ep0->state != EP0_IDLE */) {+ serial_printf("Clearing SETUP_END\n");+ clear_ep0_se();+#if 1+ if (ep0csr & S3C2410_UDC_EP0_CSR_SOPKTRDY) {+ /* Flush FIFO */+ while (inl(S3C2410_UDC_OUT_FIFO_CNT1_REG))+ inl(S3C2410_UDC_EP0_FIFO_REG);+ clear_ep0_opr();+ }+#endif+ ep0->state = EP0_IDLE;+ return;+ }++ /* Don't ever put [serial] debugging in non-error codepaths here, it+ * will violate the tight timing constraints of this USB Device+ * controller (and lead to bus enumeration failures) */++ switch (ep0->state) {+ int i, fifo_count;+ unsigned char *datap;+ case EP0_IDLE:+ if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))+ break;++ datap = (unsigned char *) &ep0_urb->device_request;+ /* host->device packet has been received */++ /* pull it out of the fifo */+ fifo_count = fifo_count_out();+ for (i = 0; i < fifo_count; i++) {+ *datap = (unsigned char)inl(S3C2410_UDC_EP0_FIFO_REG);+ datap++;+ }+ if (fifo_count != 8) {+ debug("STRANGE FIFO COUNT: %u bytes\n", fifo_count);+ set_ep0_ss();+ return;+ }++ if (ep0_urb->device_request.wLength == 0) {+ if (ep0_recv_setup(ep0_urb)) {+ /* Not a setup packet, stall next EP0 transaction */+ debug("can't parse setup packet1\n");+ set_ep0_ss();+ set_ep0_de_out();+ ep0->state = EP0_IDLE;+ return;+ }+ /* There are some requests with which we need to deal+ * manually here */+ switch (ep0_urb->device_request.bRequest) {+ case USB_REQ_SET_CONFIGURATION:+ if (!ep0_urb->device_request.wValue)+ usbd_device_event_irq(udc_device,+ DEVICE_DE_CONFIGURED, 0);+ else+ usbd_device_event_irq(udc_device,+ DEVICE_CONFIGURED, 0);+ break;+ case USB_REQ_SET_ADDRESS:+ udc_set_address(udc_device->address);+ usbd_device_event_irq(udc_device,+ DEVICE_ADDRESS_ASSIGNED, 0);+ break;+ default:+ break;+ }+ set_ep0_de_out();+ ep0->state = EP0_IDLE;+ } else {+ if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)+ == USB_REQ_HOST2DEVICE) {+ clear_ep0_opr();+ ep0->state = EP0_OUT_DATA_PHASE;+ ep0_urb->buffer = ep0_urb->buffer_data;+ ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data);+ ep0_urb->actual_length = 0;+ } else {+ ep0->state = EP0_IN_DATA_PHASE;++ if (ep0_recv_setup(ep0_urb)) {+ /* Not a setup packet, stall next EP0 transaction */+ debug("can't parse setup packet2\n");+ set_ep0_ss();+ //set_ep0_de_out();+ ep0->state = EP0_IDLE;+ return;+ }+ clear_ep0_opr();+ ep0->tx_urb = ep0_urb;+ ep0->sent = ep0->last = 0;++ if (s3c2410_write_noniso_tx_fifo(ep0)) {+ ep0->state = EP0_IDLE;+ set_ep0_de_in();+ } else+ set_ep0_ipr();+ }+ }+ break;+ case EP0_IN_DATA_PHASE:+ if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY)) {+ ep0->sent += ep0->last;++ if (s3c2410_write_noniso_tx_fifo(ep0)) {+ ep0->state = EP0_IDLE;+ set_ep0_de_in();+ } else+ set_ep0_ipr();+ }+ break;+ case EP0_OUT_DATA_PHASE:+ if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {+ u32 urb_avail = ep0_urb->buffer_length - ep0_urb->actual_length;+ u_int8_t *cp = ep0_urb->buffer + ep0_urb->actual_length;+ int i, fifo_count;++ fifo_count = fifo_count_out();+ if (fifo_count < urb_avail)+ urb_avail = fifo_count;++ for (i = 0; i < urb_avail; i++)+ *cp++ = inl(S3C2410_UDC_EP0_FIFO_REG);++ ep0_urb->actual_length += urb_avail;++ if (fifo_count < ep0->rcv_packetSize ||+ ep0_urb->actual_length >= ep0_urb->device_request.wLength) {+ ep0->state = EP0_IDLE;+ if (ep0_recv_setup(ep0_urb)) {+ /* Not a setup packet, stall next EP0 transaction */+ debug("can't parse setup packet3\n");+ set_ep0_ss();+ //set_ep0_de_out();+ return;+ }+ set_ep0_de_out();+ } else+ clear_ep0_opr();+ }+ break;+ case EP0_END_XFER:+ ep0->state = EP0_IDLE;+ break;+ case EP0_STALL:+ //set_ep0_ss;+ ep0->state = EP0_IDLE;+ break;+ }+}+++static void s3c2410_udc_epn(int ep)+{+ struct usb_endpoint_instance *endpoint;+ struct urb *urb;+ u32 ep_csr1;++ if (ep >= S3C2410_UDC_NUM_ENDPOINTS)+ return;++ endpoint = &udc_device->bus->endpoint_array[ep];++ S3C2410_UDC_SETIX(ep);++ if (endpoint->endpoint_address & USB_DIR_IN) {+ /* IN transfer (device to host) */+ ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG);+ debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1);++ urb = endpoint->tx_urb;+ if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {+ /* Stall handshake */+ debug("stall\n");+ outl(0x00, S3C2410_UDC_IN_CSR1_REG);+ return;+ }+ if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && urb &&+ urb->actual_length) {++ debug("completing previously send data ");+ usbd_tx_complete(endpoint);++ /* push pending data into FIFO */+ if ((endpoint->last == endpoint->tx_packetSize) &&+ (urb->actual_length - endpoint->sent - endpoint->last == 0)) {+ endpoint->sent += endpoint->last;+ /* Write 0 bytes of data (ZLP) */+ debug("ZLP ");+ outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);+ } else {+ /* write actual data to fifo */+ debug_urb_buffer("TX_DATA", endpoint);+ s3c2410_write_noniso_tx_fifo(endpoint);+ outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);+ }+ }+ debug("\n");+ } else {+ /* OUT transfer (host to device) */+ ep_csr1 = inl(S3C2410_UDC_OUT_CSR1_REG);+ debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1);++ urb = endpoint->rcv_urb;+ if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {+ /* Stall handshake */+ outl(0x00, S3C2410_UDC_IN_CSR1_REG);+ return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -