SPEAr SoCs contain a synopsys usb device controller.
USB Device IP can work in 2 modes
- DMA mode
- Slave mode

The driver adds support only for slave mode operation of usb
device IP. This driver is used along with standard USBTTY
driver to obtain a tty interface over USB on the host

Signed-off-by: Vipin <[email protected]>
---
  drivers/serial/usbtty.h      |    2 +
  drivers/usb/gadget/Makefile  |    1 +
  drivers/usb/gadget/spr_udc.c | 1002 ++++++++++++++++++++++++++++++++++++++++++
  include/usb/spr_udc.h        |  227 ++++++++++
  4 files changed, 1232 insertions(+), 0 deletions(-)
  mode change 100644 => 100755 drivers/serial/usbtty.h
  mode change 100644 => 100755 drivers/usb/gadget/Makefile
  create mode 100755 drivers/usb/gadget/spr_udc.c
  create mode 100755 include/usb/spr_udc.h

<snip>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <usbdevice.h>
+#include "ep0.h"
+#include <usb/spr_udc.h>
+#include <asm/arch/spr_misc.h>
+
+#define UDC_INIT_MDELAY                     80 /* Device settle delay */
ws
Some space before the '80'
+
+/* Some kind of debugging output... */
+#ifndef DEBUG_SPRUSBTTY
+#define UDCDBG(str)
+#define UDCDBGA(fmt, args...)
+#else
+#define UDCDBG(str) serial_printf(str "\n")
+#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args)
+#endif
+
+static struct urb *ep0_urb;
+static struct usb_device_instance *udc_device;
+
+static struct plug_regs *const plug_regs_p =
+    (struct plug_regs * const)CONFIG_SYS_PLUG_BASE;
+static struct udc_regs *const udc_regs_p =
+    (struct udc_regs * const)CONFIG_SYS_USBD_BASE;
+static struct udc_endp_regs *const outep_regs_p =
+    &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0];
+static struct udc_endp_regs *const inep_regs_p =
+    &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0];
+
Similar to other CONFIG_* register bases,
It may be better to move/rename the CONFIG_SYS_PLUG_BASE to
an asm/arch header file.


+/*
+ * udc_state_transition - Write the next packet to TxFIFO.

<snip>

  *
+ * This function must only be called with interrupts disabled.
+ */
+static void udc_state_transition(usb_device_state_t initial,
+                                usb_device_state_t final)
+{
+       if (initial < final) {
+               switch (initial) {
+               case STATE_ATTACHED:
+                       usbd_device_event_irq(udc_device,
+                                             DEVICE_HUB_CONFIGURED, 0);
+                       if (final == STATE_POWERED)
+                               break;
+               case STATE_POWERED:
+                       usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+                       if (final == STATE_DEFAULT)
+                               break;
+               case STATE_DEFAULT:
+                       usbd_device_event_irq(udc_device,
+                                             DEVICE_ADDRESS_ASSIGNED, 0);
+                       if (final == STATE_ADDRESSED)
+                               break;
+               case STATE_ADDRESSED:
+                       usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+               case STATE_CONFIGURED:
+                       break;
+               default:
+                       break;
+               }
+       } else if (initial > final) {
+               switch (initial) {
+               case STATE_CONFIGURED:
+                       usbd_device_event_irq(udc_device,
+                                             DEVICE_DE_CONFIGURED, 0);
+                       if (final == STATE_ADDRESSED)
+                               break;
+               case STATE_ADDRESSED:
+                       usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+                       if (final == STATE_DEFAULT)
+                               break;
+               case STATE_DEFAULT:
+                       usbd_device_event_irq(udc_device,
+                                             DEVICE_POWER_INTERRUPTION, 0);
+                       if (final == STATE_POWERED)
+                               break;
+               case STATE_POWERED:
+                       usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+               case STATE_ATTACHED:
+                       break;
+               default:
+                       break;
+               }
+       }
No panicing if the state transition is the default ?
+}
+

<snip>

+static void *get_fifo(int ep_num, int in)
+{
+       u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE;
+
+       switch (ep_num) {
+       case 3:
+               fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn);
+               /* break intentionally left out */
+
+       case 1:
+               fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn);
+               /* break intentionally left out */
+
These EP's should be the #defined UDC_*_ENDPOINT

+       case 0:
+       default:
+               if (in) {
+                       fifo_ptr +=
+                           readl(&outep_regs_p[2].endp_maxpacksize) >> 16;
+                       /* break intentionally left out */
+               } else {
+                       break;
+               }
+
+       case 2:
+               fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16;
+               /* break intentionally left out */
+       }
+
+       return (void *)fifo_ptr;
+}
+
+static short usbgetpckfromfifo(int epNum, u8 *bufp, u32 len)
+{
+       u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0);
+       u32 i, nw, nb;
+       u32 *wrdp;
+       u8 *bytp;
+
+       if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY)
+               return -1;
+
+       nw = len / sizeof(u32);
+       nb = len % sizeof(u32);
+
+       wrdp = (u32 *)bufp;
Does this work when bufp is unaligned ?
+       for (i = 0; i < nw; i++) {
+               writel(readl(fifo_ptr), wrdp);
+               wrdp++;
+       }
+
+       bytp = (u8 *)wrdp;
+       for (i = 0; i < nb; i++) {
+               writeb(readb(fifo_ptr), bytp);
+               fifo_ptr++;
+               bytp++;
+       }
+       readl(&outep_regs_p[epNum].write_done);
+
+       return 0;
The status of this function is never checked.
Choosing 'short' is also unusual.
Maybe this should be an int
+}
+
+static void usbputpcktofifo(int epNum, u8 *bufp, u32 len)
+{
+       u32 i, nw, nb;
+       u32 *wrdp;
+       u8 *bytp;
+       u8 *fifo_ptr = get_fifo(epNum, 1);
+
+       nw = len / sizeof(int);
+       nb = len % sizeof(int);
+       wrdp = (u32 *)bufp;
+       for (i = 0; i < nw; i++) {
+               writel(*wrdp, fifo_ptr);
+               wrdp++;
+       }
+
+       bytp = (u8 *)wrdp;
+       for (i = 0; i < nb; i++) {
+               writeb(*bytp, fifo_ptr);
+               fifo_ptr++;
+               bytp++;
+       }
+}

<snip>

+/*
+ * Handle TX transaction on non-ISO endpoint.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 16 to 30.
+ */
+static void spear_udc_epn_tx(int ep)
+{
+       struct usb_endpoint_instance *endpoint = spear_find_ep(ep);

This can return NULL
check if (endpoint)

+
+       /*
+        * We need to transmit a terminating zero-length packet now if
+        * we have sent all of the data in this URB and the transfer
+        * size was an exact multiple of the packet size.
+        */
+       if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
+               if (endpoint->last == endpoint->tx_packetSize) {
+                       /* handle zero length packet here */
+                       writel(0x0, &inep_regs_p[ep].write_done);
+               }
+               /* retire the data that was just sent */
+               usbd_tx_complete(endpoint);
+               /*
+                * Check to see if we have more data ready to transmit
+                * now.
+                */
+               if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
+                       /* write data to FIFO */
+                       spear_write_noniso_tx_fifo(endpoint);
+                       writel(0x0, &inep_regs_p[ep].write_done);
+
+               } else if (endpoint->tx_urb
+                          && (endpoint->tx_urb->actual_length == 0)) {
+                       /* udc_set_nak(ep); */
+               }
+       }
+}

<snip>
+       writel(val, &outep_regs_p[epid].endp_cntl);
+}
+
+/*******************************************************************
+ * SLAVE MODE ::
+ * Routines to acces RX/TX FIFOs directly.
+ *******************************************************************/
ws
change to proper multi-line comment.

diff --git a/include/usb/spr_udc.h b/include/usb/spr_udc.h
new file mode 100755
index 0000000..191c439
--- /dev/null
+++ b/include/usb/spr_udc.h
@@ -0,0 +1,227 @@
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, [email protected].
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 __SPR_UDC_H
+#define __SPR_UDC_H
+
+/*****************************************************************************
+ * Defines for  USBD
+ *
+ * The udc_ahb controller has three AHB slaves:
+ *
+ * 1.  THe UDC registers
+ * 2.  The plug detect
+ * 3.  The RX/TX FIFO
+ *****************************************************************************/
ws
change to proper multi-line comment
+
+#define MAX_ENDPOINTS          16
+
+struct udc_endp_regs {
+       u32 endp_cntl;
+       u32 endp_status;
+       u32 endp_bsorfn;
+       u32 endp_maxpacksize;
+       u32 reserved_1;
+       u32 endp_desc_point;
+       u32 reserved_2;
+       u32 write_done;
+};
+
+/* Endpoint Control Register definitions */
+
+#define  ENDP_CNTL_STALL               0x00000001
+#define  ENDP_CNTL_FLUSH               0x00000002
+#define  ENDP_CNTL_SNOOP               0x00000004
+#define  ENDP_CNTL_POLL                        0x00000008
+#define  ENDP_CNTL_CONTROL             0x00000000
+#define  ENDP_CNTL_ISO                 0x00000010
+#define  ENDP_CNTL_BULK                        0x00000020
+#define  ENDP_CNTL_INT                 0x00000030
+#define  ENDP_CNTL_NAK                 0x00000040
+#define  ENDP_CNTL_SNAK                        0x00000080
+#define  ENDP_CNTL_CNAK                        0x00000100
+#define  ENDP_CNTL_RRDY                        0x00000200
+
+/* Endpoint Satus Register definitions */
+
+#define  ENDP_STATUS_PIDMSK            0x0000000f
+#define  ENDP_STATUS_OUTMSK            0x00000030
+#define  ENDP_STATUS_OUT_NONE          0x00000000
+#define  ENDP_STATUS_OUT_DATA          0x00000010
+#define  ENDP_STATUS_OUT_SETUP         0x00000020
+#define  ENDP_STATUS_IN                        0x00000040
+#define  ENDP_STATUS_BUFFNAV           0x00000080
+#define  ENDP_STATUS_FATERR            0x00000100
+#define  ENDP_STATUS_HOSTBUSERR                0x00000200
+#define  ENDP_STATUS_TDC               0x00000400
+#define  ENDP_STATUS_RXPKTMSK          0x003ff800
+
+struct udc_regs {
+       struct udc_endp_regs in_regs[MAX_ENDPOINTS];
+       struct udc_endp_regs out_regs[MAX_ENDPOINTS];
+       u32 dev_conf;
+       u32 dev_cntl;
+       u32 dev_stat;
+       u32 dev_int;
+       u32 dev_int_mask;
+       u32 endp_int;
+       u32 endp_int_mask;
+       u32 reserved_3[0x39];
+       u32 reserved_4;         /* offset 0x500 */
+       u32 udc_endp_reg[MAX_ENDPOINTS];
+};
+
+/* Device Configuration Register definitions */
+
+#define  DEV_CONF_HS_SPEED             0x00000000
+#define  DEV_CONF_LS_SPEED             0x00000002
+#define  DEV_CONF_FS_SPEED             0x00000003
+#define  DEV_CONF_REMWAKEUP            0x00000004
+#define  DEV_CONF_SELFPOW              0x00000008
+#define  DEV_CONF_SYNCFRAME            0x00000010
+#define  DEV_CONF_PHYINT_8             0x00000020
+#define  DEV_CONF_PHYINT_16            0x00000000
+#define  DEV_CONF_UTMI_BIDIR           0x00000040
+#define  DEV_CONF_STATUS_STALL         0x00000080
+
+/* Device Control Register definitions */
+
+#define  DEV_CNTL_RESUME               0x00000001
+#define  DEV_CNTL_TFFLUSH              0x00000002
+#define  DEV_CNTL_RXDMAEN              0x00000004
+#define  DEV_CNTL_TXDMAEN              0x00000008
+#define  DEV_CNTL_DESCRUPD             0x00000010
+#define  DEV_CNTL_BIGEND               0x00000020
+#define  DEV_CNTL_BUFFILL              0x00000040
+#define  DEV_CNTL_TSHLDEN              0x00000080
+#define  DEV_CNTL_BURSTEN              0x00000100
+#define  DEV_CNTL_DMAMODE              0x00000200
+#define  DEV_CNTL_SOFTDISCONNECT       0x00000400
+#define  DEV_CNTL_SCALEDOWN            0x00000800
+#define  DEV_CNTL_BURSTLENU            0x00010000
+#define  DEV_CNTL_BURSTLENMSK          0x00ff0000
+#define  DEV_CNTL_TSHLDLENU            0x01000000
+#define  DEV_CNTL_TSHLDLENMSK          0xff000000
+
+/* Device Status Register definitions */
+
+#define  DEV_STAT_CFG                  0x0000000f
+#define  DEV_STAT_INTF                 0x000000f0
+#define  DEV_STAT_ALT                  0x00000f00
+#define  DEV_STAT_SUSP                 0x00001000
+#define  DEV_STAT_ENUM                 0x00006000
+#define  DEV_STAT_ENUM_SPEED_HS                0x00000000
+#define  DEV_STAT_ENUM_SPEED_FS                0x00002000
+#define  DEV_STAT_ENUM_SPEED_LS                0x00004000
+#define  DEV_STAT_RXFIFO_EMPTY         0x00008000
+#define  DEV_STAT_PHY_ERR              0x00010000
+#define  DEV_STAT_TS                   0xf0000000
+
+/* Device Interrupt Register definitions */
+
+#define  DEV_INT_MSK                   0x0000007f
+#define  DEV_INT_SETCFG                        0x00000001
+#define  DEV_INT_SETINTF               0x00000002
+#define  DEV_INT_INACTIVE              0x00000004
+#define  DEV_INT_USBRESET              0x00000008
+#define  DEV_INT_SUSPUSB               0x00000010
+#define  DEV_INT_SOF                   0x00000020
+#define  DEV_INT_ENUM                  0x00000040
+
+/* Endpoint Interrupt Register definitions */
+
+#define  ENDP0_INT_CTRLIN              0x00000001
+#define  ENDP1_INT_BULKIN              0x00000002
+#define  ENDP_INT_NONISOIN_MSK         0x0000AAAA
+#define  ENDP2_INT_BULKIN              0x00000004
+#define  ENDP0_INT_CTRLOUT             0x00010000
+#define  ENDP1_INT_BULKOUT             0x00020000
+#define  ENDP2_INT_BULKOUT             0x00040000
+#define  ENDP_INT_NONISOOUT_MSK                0x55540000
+
+/* Endpoint Register definitions */
+#define  ENDP_EPDIR_OUT                        0x00000000
+#define  ENDP_EPDIR_IN                 0x00000010
+#define  ENDP_EPTYPE_CNTL              0x0
+#define  ENDP_EPTYPE_ISO               0x1
+#define  ENDP_EPTYPE_BULK              0x2
+#define  ENDP_EPTYPE_INT               0x3
+
+/*
+ * Defines for Plug Detect
+ */
+
+struct plug_regs {
+       u32 plug_state;
+       u32 plug_pending;
+};
+
+/* Plug State Register definitions */
+#define  PLUG_STATUS_EN                        0x1
+#define  PLUG_STATUS_ATTACHED          0x2
+#define  PLUG_STATUS_PHY_RESET         0x4
+#define  PLUG_STATUS_PHY_MODE          0x8
+
+/*
+ * Defines for UDC FIFO (Slave Mode)
+ */
+struct udcfifo_regs {
+       u32 *fifo_p;
+};
+
+/*
+ * USBTTY definitions
+ */
+#define  EP0_MAX_PACKET_SIZE        64
+#define  UDC_INT_ENDPOINT           1
+#define  UDC_INT_PACKET_SIZE        64
+#define  UDC_OUT_ENDPOINT           2
+#define  UDC_BULK_PACKET_SIZE       64
+#define  UDC_IN_ENDPOINT            3
+#define  UDC_OUT_PACKET_SIZE        64
+#define  UDC_IN_PACKET_SIZE         64

ws
change leading spaces to tabs
+
+/*
+ * Function declarations
+ */
+
+void udc_irq(void);
+
+void udc_set_nak(int epid);
+void udc_unset_nak(int epid);
+
+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);
ws
could remove the extra empty line
+
+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);

Tom
_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to