* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-09-04 20:12 ` [U-Boot] [PATCH 3/8] TWL4030 Add usb PHY support Tom Rix
@ 2009-09-04 20:12 ` Tom Rix
2009-09-05 0:25 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 1 reply; 9+ messages in thread
From: Tom Rix @ 2009-09-04 20:12 UTC (permalink / raw)
To: u-boot
This change adds the usb device support for musb.
Omap3 platform support added at the same level as davinci.
The interface for usbtty to use the musb device support was added.
Verified on omap3 beagle, zoom1 and zoom2.
Signed-off-by: Tom Rix <Tom.Rix@windriver.com>
---
drivers/serial/usbtty.h | 2 +
drivers/usb/musb/Makefile | 2 +
drivers/usb/musb/musb_core.c | 8 +-
drivers/usb/musb/musb_core.h | 40 ++
drivers/usb/musb/musb_debug.h | 240 ++++++++++++
drivers/usb/musb/musb_udc.c | 823 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/musb/omap3.c | 129 +++++++
drivers/usb/musb/omap3.h | 48 +++
include/usb.h | 3 +-
include/usb/musb_udc.h | 54 +++
10 files changed, 1346 insertions(+), 3 deletions(-)
create mode 100644 drivers/usb/musb/musb_debug.h
create mode 100644 drivers/usb/musb/musb_udc.c
create mode 100644 drivers/usb/musb/omap3.c
create mode 100644 drivers/usb/musb/omap3.h
create mode 100644 include/usb/musb_udc.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index f746d63..6b6c4a1 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -29,6 +29,8 @@
#include <usb/mpc8xx_udc.h>
#elif defined(CONFIG_OMAP1510)
#include <usb/omap1510_udc.h>
+#elif defined(CONFIG_MUSB_UDC)
+#include <usb/musb_udc.h>
#elif defined(CONFIG_PXA27X)
#include <usb/pxa27x_udc.h>
#endif
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 09e0a5f..f2ccd9f 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_musb.a
COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o
COBJS-$(CONFIG_USB_DAVINCI) += davinci.o
+COBJS-$(CONFIG_USB_OMAP3) += omap3.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ec57fc8..22f3dba 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -32,7 +32,9 @@ struct musb_regs *musbr;
*/
void musb_start(void)
{
+#if defined(CONFIG_MUSB_HCD)
u8 devctl;
+#endif
/* disable all interrupts */
writew(0, &musbr->intrtxe);
@@ -74,9 +76,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->txfifosz);
writew(fifoaddr >> 3, &musbr->txfifoadd);
+
+ csr = readw(&musbr->txcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->txcsr);
writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
#endif
/* Flush fifo if required */
@@ -87,9 +90,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->rxfifosz);
writew(fifoaddr >> 3, &musbr->rxfifoadd);
+
+ csr = readw(&musbr->rxcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->rxcsr);
writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
#endif
/* Flush fifo if required */
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f9da3f0..15c7f49 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -40,6 +40,36 @@
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+/* EP0 */
+struct musb_ep0_regs {
+ u16 reserved4;
+ u16 csr0;
+ u16 reserved5;
+ u16 reserved6;
+ u16 count0;
+ u8 host_type0;
+ u8 host_naklimit0;
+ u8 reserved7;
+ u8 reserved8;
+ u8 reserved9;
+ u8 configdata;
+};
+
+/* EP 1-15 */
+struct musb_epN_regs {
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+};
+
/* Mentor USB core register overlay structure */
struct musb_regs {
/* common registers */
@@ -97,6 +127,16 @@ struct musb_regs {
u8 rxhubaddr;
u8 rxhubport;
} tar[16];
+ /*
+ * end point registers
+ * ep0 elements are valid when array index is 0
+ * otherwise epN is valid
+ */
+ union musb_ep_regs {
+ struct musb_ep0_regs ep0;
+ struct musb_epN_regs epN;
+ } ep[16];
+
} __attribute__((aligned(32)));
/*
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
new file mode 100644
index 0000000..cd6c29b
--- /dev/null
+++ b/drivers/usb/musb/musb_debug.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.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
+ */
+
+/* Define MUSB_DEBUG before including this file to get debug macros */
+#ifdef MUSB_DEBUG
+
+static inline void MUSB_PRINT_PWR(u8 b)
+{
+ serial_printf("\tpower 0x%2.2x\n", b);
+ if (b & MUSB_POWER_ISOUPDATE)
+ serial_printf("\t\tISOUPDATE\n");
+ if (b & MUSB_POWER_SOFTCONN)
+ serial_printf("\t\tSOFTCONN\n");
+ if (b & MUSB_POWER_HSENAB)
+ serial_printf("\t\tHSENAB\n");
+ if (b & MUSB_POWER_HSMODE)
+ serial_printf("\t\tHSMODE\n");
+ if (b & MUSB_POWER_RESET)
+ serial_printf("\t\tRESET\n");
+ if (b & MUSB_POWER_RESUME)
+ serial_printf("\t\tRESUME\n");
+ if (b & MUSB_POWER_SUSPENDM)
+ serial_printf("\t\tSUSPENDM\n");
+ if (b & MUSB_POWER_ENSUSPEND)
+ serial_printf("\t\tENSUSPEND\n");
+}
+
+static inline void MUSB_PRINT_CSR0(u16 w)
+{
+ serial_printf("\tcsr0 0x%4.4x\n", w);
+ if (w & MUSB_CSR0_FLUSHFIFO)
+ serial_printf("\t\tFLUSHFIFO\n");
+ if (w & MUSB_CSR0_P_SVDSETUPEND)
+ serial_printf("\t\tSERV_SETUPEND\n");
+ if (w & MUSB_CSR0_P_SVDRXPKTRDY)
+ serial_printf("\t\tSERV_RXPKTRDY\n");
+ if (w & MUSB_CSR0_P_SENDSTALL)
+ serial_printf("\t\tSENDSTALL\n");
+ if (w & MUSB_CSR0_P_SETUPEND)
+ serial_printf("\t\tSETUPEND\n");
+ if (w & MUSB_CSR0_P_DATAEND)
+ serial_printf("\t\tDATAEND\n");
+ if (w & MUSB_CSR0_P_SENTSTALL)
+ serial_printf("\t\tSENTSTALL\n");
+ if (w & MUSB_CSR0_TXPKTRDY)
+ serial_printf("\t\tTXPKTRDY\n");
+ if (w & MUSB_CSR0_RXPKTRDY)
+ serial_printf("\t\tRXPKTRDY\n");
+}
+
+static inline void MUSB_PRINT_INTRUSB(u8 b)
+{
+ serial_printf("\tintrusb 0x%2.2x\n", b);
+ if (b & MUSB_INTR_VBUSERROR)
+ serial_printf("\t\tMUSB_INTR_VBUSERROR\n");
+ if (b & MUSB_INTR_SESSREQ)
+ serial_printf("\t\tMUSB_INTR_SESSREQ\n");
+ if (b & MUSB_INTR_DISCONNECT)
+ serial_printf("\t\tMUSB_INTR_DISCONNECT\n");
+ if (b & MUSB_INTR_CONNECT)
+ serial_printf("\t\tMUSB_INTR_CONNECT\n");
+ if (b & MUSB_INTR_SOF)
+ serial_printf("\t\tMUSB_INTR_SOF\n");
+ if (b & MUSB_INTR_BABBLE)
+ serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
+ if (b & MUSB_INTR_RESUME)
+ serial_printf("\t\tMUSB_INTR_RESUME\n");
+ if (b & MUSB_INTR_SUSPEND)
+ serial_printf("\t\tMUSB_INTR_SUSPEND\n");
+}
+
+static inline void MUSB_PRINT_INTRTX(u16 w)
+{
+ serial_printf("\tintrtx 0x%4.4x\n", w);
+}
+
+static inline void MUSB_PRINT_INTRRX(u16 w)
+{
+ serial_printf("\tintrx 0x%4.4x\n", w);
+}
+
+static inline void MUSB_PRINT_DEVCTL(u8 b)
+{
+ serial_printf("\tdevctl 0x%2.2x\n", b);
+ if (b & MUSB_DEVCTL_BDEVICE)
+ serial_printf("\t\tB device\n");
+ else
+ serial_printf("\t\tA device\n");
+ if (b & MUSB_DEVCTL_FSDEV)
+ serial_printf("\t\tFast Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_LSDEV)
+ serial_printf("\t\tSlow Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_HM)
+ serial_printf("\t\tHost mode\n");
+ else
+ serial_printf("\t\tPeripherial mode\n");
+ if (b & MUSB_DEVCTL_HR)
+ serial_printf("\t\tHost request started(B device)\n");
+ else
+ serial_printf("\t\tHost request finished(B device)\n");
+ if (b & MUSB_DEVCTL_BDEVICE) {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(B device)\n");
+ else
+ serial_printf("\t\tEnd of session(B device)\n");
+ } else {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(A device)\n");
+ else
+ serial_printf("\t\tEnd of session(A device)\n");
+ }
+}
+
+static inline void MUSB_PRINT_CONFIG(u8 b)
+{
+ serial_printf("\tconfig 0x%2.2x\n", b);
+ if (b & MUSB_CONFIGDATA_MPRXE)
+ serial_printf("\t\tAuto combine rx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_MPTXE)
+ serial_printf("\t\tAuto split tx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_BIGENDIAN)
+ serial_printf("\t\tBig Endian ordering\n");
+ else
+ serial_printf("\t\tLittle Endian ordering\n");
+ if (b & MUSB_CONFIGDATA_HBRXE)
+ serial_printf("\t\tHigh speed rx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_HBTXE)
+ serial_printf("\t\tHigh speed tx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_DYNFIFO)
+ serial_printf("\t\tDynamic fifo sizing\n");
+ if (b & MUSB_CONFIGDATA_SOFTCONE)
+ serial_printf("\t\tSoft Connect\n");
+ if (b & MUSB_CONFIGDATA_UTMIDW)
+ serial_printf("\t\t16 bit data width\n");
+ else
+ serial_printf("\t\t8 bit data width\n");
+}
+
+static inline void MUSB_PRINT_RXMAXP(u16 w)
+{
+ serial_printf("\trxmaxp 0x%4.4x\n", w);
+}
+
+static inline void MUSB_PRINT_RXCSR(u16 w)
+{
+ serial_printf("\trxcsr 0x%4.4x\n", w);
+ if (w & MUSB_RXCSR_AUTOCLEAR)
+ serial_printf("\t\tautclear\n");
+ if (w & MUSB_RXCSR_DMAENAB)
+ serial_printf("\t\tdma enable\n");
+ if (w & MUSB_RXCSR_DISNYET)
+ serial_printf("\t\tdisable nyet\n");
+ if (w & MUSB_RXCSR_PID_ERR)
+ serial_printf("\t\tpid error\n");
+ if (w & MUSB_RXCSR_DMAMODE)
+ serial_printf("\t\tdma mode should be 0 \n");
+ if (w & MUSB_RXCSR_CLRDATATOG)
+ serial_printf("\t\tclear data\n");
+ if (w & MUSB_RXCSR_FLUSHFIFO)
+ serial_printf("\t\tflush fifo\n");
+ if (w & MUSB_RXCSR_DATAERROR)
+ serial_printf("\t\tdata error\n");
+ if (w & MUSB_RXCSR_FIFOFULL)
+ serial_printf("\t\tfifo full\n");
+ if (w & MUSB_RXCSR_RXPKTRDY)
+ serial_printf("\t\trx packet ready\n");
+ if (w & MUSB_RXCSR_P_ISO)
+ serial_printf("\t\tiso mode\n");
+ else
+ serial_printf("\t\tbulk mode\n");
+ if (w & MUSB_RXCSR_P_SENTSTALL)
+ serial_printf("\t\tsent stall\n");
+ if (w & MUSB_RXCSR_P_SENDSTALL)
+ serial_printf("\t\tsend stall\n");
+ if (w & MUSB_RXCSR_P_OVERRUN)
+ serial_printf("\t\toverrun\n");
+}
+
+static inline void MUSB_PRINT_TXMAXP(u16 w)
+{
+ serial_printf("\ttxmaxp 0x%4.4x\n", w);
+}
+
+static inline void MUSB_PRINT_TXCSR(u16 w)
+{
+ serial_printf("\ttxcsr 0x%4.4x\n", w);
+ if (w & MUSB_TXCSR_TXPKTRDY)
+ serial_printf("\t\ttxpktrdy\n");
+ if (w & MUSB_TXCSR_FIFONOTEMPTY)
+ serial_printf("\t\tfifo not empty\n");
+ if (w & MUSB_TXCSR_FLUSHFIFO)
+ serial_printf("\t\tflush fifo\n");
+ if (w & MUSB_TXCSR_CLRDATATOG)
+ serial_printf("\t\tclear data toggle\n");
+ if (w & MUSB_TXCSR_MODE)
+ serial_printf("\t\tTX mode\n");
+ else
+ serial_printf("\t\tRX mode\n");
+ if (w & MUSB_TXCSR_P_UNDERRUN)
+ serial_printf("\t\tunderrun\n");
+ if (w & MUSB_TXCSR_P_SENTSTALL)
+ serial_printf("\t\tsent stall\n");
+ if (w & MUSB_TXCSR_P_SENDSTALL)
+ serial_printf("\t\tsend stall\n");
+}
+
+#else
+
+/* stubs */
+
+#define MUSB_PRINT_PWR(b)
+#define MUSB_PRINT_CSR0(w)
+#define MUSB_PRINT_INTRUSB(b)
+#define MUSB_PRINT_INTRTX(w)
+#define MUSB_PRINT_INTRRX(w)
+#define MUSB_PRINT_DEVCTL(b)
+#define MUSB_PRINT_CONFIG(b)
+#define MUSB_PRINT_RXMAXP(w)
+#define MUSB_PRINT_RXCSR(w)
+#define MUSB_PRINT_TXMAXP(w)
+#define MUSB_PRINT_TXCSR(w)
+
+#endif /* MUSB_DEBUG */
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
new file mode 100644
index 0000000..3be92f1
--- /dev/null
+++ b/drivers/usb/musb/musb_udc.c
@@ -0,0 +1,823 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is a rewrite of the usb device part of
+ * repository git.omapzoom.org/repo/u-boot.git, branch master,
+ * file cpu/omap3/fastboot.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * -------------------------------------------------------------------------
+ *
+ * The details of connecting the device to the uboot usb device subsystem
+ * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
+ * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 Texas Instruments Incorporated.
+ *
+ * Based on
+ * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
+ * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
+ *
+ * Author: Diego Dompe (diego.dompe at ridgerun.com)
+ * Atin Malaviya (atin.malaviya at gmail.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 <usb/musb_udc.h>
+#include "../gadget/ep0.h"
+#include "musb_core.h"
+#if defined(CONFIG_USB_OMAP3)
+#include "omap3.h"
+#elif defined(CONFIG_USB_DAVINCI)
+#include "davinci.h"
+#endif
+
+/* Define MUSB_DEBUG for debugging */
+/* #define MUSB_DEBUG */
+#include "musb_debug.h"
+
+#define MAX_ENDPOINT 15
+
+#define GET_ENDPOINT(dev,ep) \
+(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
+
+#define SET_EP0_STATE(s) \
+do { \
+ if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
+ if ((s) != ep0_state) { \
+ if ((debug_setup) && (debug_level > 1)) \
+ serial_printf("INFO : Changing state from %s to %s in %s at line %d\n", ep0_state_strings[ep0_state], ep0_state_strings[s], __PRETTY_FUNCTION__, __LINE__); \
+ ep0_state = s; \
+ } \
+ } else { \
+ if (debug_level > 0) \
+ serial_printf("Error at %s %d with setting state %d is invalid\n", __PRETTY_FUNCTION__, __LINE__, s); \
+ } \
+} while (0)
+
+/* static implies these initialized to 0 or NULL */
+static int debug_setup;
+static int debug_level;
+static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
+static enum ep0_state_enum { IDLE = 0, TX, RX, SET_ADDRESS } ep0_state = IDLE;
+static char *ep0_state_strings[4] = {
+ "IDLE",
+ "TX",
+ "RX",
+ "SET_ADDRESS",
+};
+
+static struct urb *ep0_urb;
+struct usb_endpoint_instance *ep0_endpoint;
+static struct usb_device_instance *udc_device;
+static int enabled;
+
+#ifdef MUSB_DEBUG
+static void musb_db_regs(void)
+{
+ u8 b;
+ u16 w;
+
+ b = readb(&musbr->faddr);
+ serial_printf("\tfaddr 0x%2.2x\n", b);
+
+ b = readb(&musbr->power);
+ MUSB_PRINT_PWR(b);
+
+ w = readw(&musbr->ep[0].ep0.csr0);
+ MUSB_PRINT_CSR0(w);
+
+ b = readb(&musbr->devctl);
+ MUSB_PRINT_DEVCTL(b);
+
+ b = readb(&musbr->ep[0].ep0.configdata);
+ MUSB_PRINT_CONFIG(b);
+
+ w = readw(&musbr->frame);
+ serial_printf("\tframe 0x%4.4x\n", w);
+
+ b = readb(&musbr->index);
+ serial_printf("\tindex 0x%2.2x\n", b);
+
+ w = readw(&musbr->ep[1].epN.rxmaxp);
+ MUSB_PRINT_RXMAXP(w);
+
+ w = readw(&musbr->ep[1].epN.rxcsr);
+ MUSB_PRINT_RXCSR(w);
+
+ w = readw(&musbr->ep[1].epN.txmaxp);
+ MUSB_PRINT_TXMAXP(w);
+
+ w = readw(&musbr->ep[1].epN.txcsr);
+ MUSB_PRINT_TXCSR(w);
+}
+#else
+#define musb_db_regs()
+#endif /* DEBUG_MUSB */
+
+static void musb_peri_softconnect(void)
+{
+ u8 power, devctl;
+ u8 intrusb;
+ u16 intrrx, intrtx;
+
+ /* Power off MUSB */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_SOFTCONN;
+ writeb(power, &musbr->power);
+
+ /* Read intr to clear */
+ intrusb = readb(&musbr->intrusb);
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ udelay(2 * 500000); /* 1 sec */
+
+ /* Power on MUSB */
+ power = readb(&musbr->power);
+ power |= MUSB_POWER_SOFTCONN;
+ /*
+ * The usb device interface is usb 1.1
+ * Disable 2.0 high speed by clearring the hsenable bit.
+ */
+ power &= ~MUSB_POWER_HSENAB;
+ writeb(power, &musbr->power);
+
+ /* Check if device is in b-peripheral mode */
+ devctl = readb(&musbr->devctl);
+ if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
+ (devctl & MUSB_DEVCTL_HM)) {
+ serial_printf("ERROR : Unsupport USB mode\n");
+ serial_printf("Check that mini-B USB cable is attached to the device\n");
+ }
+
+ if (debug_setup && (debug_level > 1))
+ musb_db_regs();
+}
+
+static void musb_peri_reset(void)
+{
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
+
+ /* the device address is reset by the event */
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ SET_EP0_STATE(IDLE);
+ if (ep0_endpoint)
+ ep0_endpoint->endpoint_address = 0xff;
+}
+
+static void musb_peri_resume(void)
+{
+ /* noop */
+}
+
+static void musb_peri_ep0_stall(void)
+{
+ u16 csr0;
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SENDSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
+}
+
+static void musb_peri_ep0_ack_req(void)
+{
+ u16 csr0;
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready(void)
+{
+ u16 csr0;
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_TXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_last(void)
+{
+ u16 csr0;
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_DATAEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_set_address(void)
+{
+ writeb(udc_device->address, &musbr->faddr);
+ SET_EP0_STATE(IDLE);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Address set to %d\n", __PRETTY_FUNCTION__, udc_device->address);
+}
+
+static void musb_peri_rx_ack(unsigned int ep)
+{
+ u16 peri_rxcsr;
+ peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+ peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
+}
+
+static void musb_peri_tx_ready(unsigned int ep)
+{
+ u16 peri_txcsr;
+ peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+ peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+}
+
+static void musb_peri_ep0_zero_data_request(int err)
+{
+ musb_peri_ep0_ack_req();
+
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+
+ musb_peri_ep0_last();
+
+ /* USBD state */
+ switch (ep0_urb->device_request.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s received set address\n", __PRETTY_FUNCTION__);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Configured\n", __PRETTY_FUNCTION__);
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ break;
+ }
+
+ /* EP0 state */
+ if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
+ SET_EP0_STATE(SET_ADDRESS);
+ } else {
+ SET_EP0_STATE(IDLE);
+ }
+ }
+}
+
+static void musb_peri_ep0_rx_data_request(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ */
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->rcv_urb = ep0_urb;
+ ep0_urb->actual_length = 0;
+ SET_EP0_STATE(RX);
+}
+
+static void musb_peri_ep0_tx_data_request(int err)
+{
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->tx_urb = ep0_urb;
+ ep0_endpoint->sent = 0;
+ SET_EP0_STATE(TX);
+ }
+}
+
+static void musb_peri_ep0_idle(void)
+{
+ u16 count0;
+ int err;
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ goto end;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+ if (count0 == 0)
+ goto end;
+
+ if (count0 != 8) {
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN : %s SETUP incorrect size %d\n",
+ __PRETTY_FUNCTION__, count0);
+ musb_peri_ep0_stall();
+ goto end;
+ }
+
+ read_fifo(0, count0, &ep0_urb->device_request);
+
+ if (debug_level > 2) {
+ PRINT_USB_DEVICE_REQUEST(&ep0_urb->device_request);
+ }
+
+ if (0 == ep0_urb->device_request.wLength) {
+ err = ep0_recv_setup(ep0_urb);
+
+ /* Zero data request */
+ musb_peri_ep0_zero_data_request(err);
+ } else {
+ /* Is data coming or going ? */
+ u8 reqType = ep0_urb->device_request.bmRequestType;
+ if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
+ err = ep0_recv_setup(ep0_urb);
+ /* Device to host */
+ musb_peri_ep0_tx_data_request(err);
+ } else {
+ /*
+ * Host to device
+ *
+ * The RX routine will call ep0_recv_setup
+ * when the data packet has arrived.
+ */
+ musb_peri_ep0_rx_data_request();
+ }
+ }
+
+end:
+ return;
+}
+
+static void musb_peri_ep0_rx(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ * Pass the data back to driver ep0_recv_setup which
+ * should give the cdc_recv_setup the chance to handle
+ * the rx
+ */
+ u16 csr0;
+ u16 count0;
+
+ if (debug_level > 3) {
+ if (0 != ep0_urb->actual_length) {
+ serial_printf("%s finished ? %d of %d\n",
+ __PRETTY_FUNCTION__,
+ ep0_urb->actual_length,
+ ep0_urb->device_request.wLength);
+ }
+ }
+
+ if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
+ musb_peri_ep0_last();
+ SET_EP0_STATE(IDLE);
+ ep0_recv_setup(ep0_urb);
+ return;
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ return;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+
+ if (count0) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = ep0_endpoint;
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (count0 > remaining_space)
+ length = remaining_space;
+ else
+ length = count0;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(0, length, data);
+
+ musb_peri_ep0_ack_req();
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s no space in rcv buffer\n", __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with endpoint\n", __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s with nothing to do\n", __PRETTY_FUNCTION__);
+ }
+}
+
+static void musb_peri_ep0_tx(void)
+{
+ u16 csr0;
+ int transfer_size = 0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Check for pending tx */
+ if (csr0 & MUSB_CSR0_TXPKTRDY)
+ return;
+
+ /* Check if this is the last packet sent */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length) {
+ SET_EP0_STATE(IDLE);
+ return;
+ }
+
+ transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
+ if (transfer_size > ep0_endpoint->tx_packetSize)
+ transfer_size = ep0_endpoint->tx_packetSize;
+
+ write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
+ ep0_endpoint->sent += transfer_size;
+
+ musb_ep0_tx_ready();
+ if (ep0_endpoint->sent >= ep0_urb->actual_length)
+ musb_peri_ep0_last();
+}
+
+static void musb_peri_ep0(void)
+{
+ u16 csr0;
+
+ if (SET_ADDRESS == ep0_state)
+ musb_peri_ep0_set_address();
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Error conditions */
+ if (MUSB_CSR0_P_SENTSTALL & csr0) {
+ csr0 &= ~MUSB_CSR0_P_SENTSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ }
+ if (MUSB_CSR0_P_SETUPEND & csr0) {
+ csr0 |= MUSB_CSR0_P_SVDSETUPEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN: %s SETUPEND\n", __PRETTY_FUNCTION__);
+ }
+
+ /* Normal states */
+ if (IDLE == ep0_state)
+ musb_peri_ep0_idle();
+
+ if (TX == ep0_state)
+ musb_peri_ep0_tx();
+
+ if (RX == ep0_state)
+ musb_peri_ep0_rx();
+}
+
+static void musb_peri_rx_ep(unsigned int ep)
+{
+ u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
+
+ if (peri_rxcount) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = GET_ENDPOINT(udc_device, ep);
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (peri_rxcount > remaining_space)
+ length = remaining_space;
+ else
+ length = peri_rxcount;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(ep, length, data);
+
+ musb_peri_rx_ack(ep);
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d no space in rcv buffer\n", __PRETTY_FUNCTION__, ep);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d problem with endpoint\n", __PRETTY_FUNCTION__, ep);
+ }
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d with nothing to do\n", __PRETTY_FUNCTION__, ep);
+ }
+}
+
+static void musb_peri_rx(u16 intr)
+{
+ unsigned int ep;
+
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0();
+
+ for (ep = 1; ep < 16; ep++) {
+ if ((1 << ep) & intr)
+ musb_peri_rx_ep(ep);
+ }
+}
+
+static void musb_peri_tx(u16 intr)
+{
+ u8 ep;
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0_tx();
+
+ for (ep = 1; ep < 16; ep++) {
+ if ((1 << ep) & intr) {
+ /* handle tx for this endpoint */
+ }
+ }
+}
+
+void udc_irq(void)
+{
+ /* This is a high freq called function */
+ if (enabled) {
+
+ u8 intrusb;
+ u16 intrrx, intrtx;
+
+ intrusb = readb(&musbr->intrusb);
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ /*
+ * See drivers/usb/gadget/mpc8xx_udc.c for
+ * state diagram going from detached through
+ * configuration.
+ */
+ if (MUSB_INTR_RESUME & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ musb_peri_ep0();
+
+ if (intrrx)
+ musb_peri_rx(intrrx);
+
+ if (intrtx)
+ musb_peri_tx(intrtx);
+
+ if (MUSB_INTR_RESET & intrusb) {
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ }
+
+ if (MUSB_INTR_DISCONNECT & intrusb) {
+ /* cable unplugged from hub/host */
+ usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+ }
+
+ if (MUSB_INTR_SOF & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ if (MUSB_INTR_SUSPEND & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_INACTIVE, 0);
+ }
+ }
+}
+
+void udc_set_nak(int ep_num)
+{
+ /* noop */
+}
+
+void udc_unset_nak(int ep_num)
+{
+ /* noop */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+ int ret = 0;
+
+ /* Transmit only if the hardware is available */
+ if (endpoint->tx_urb && endpoint->state == 0) {
+ unsigned int ep = endpoint->endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK;
+
+ u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+
+ /* Error conditions */
+ if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
+ peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+ }
+
+ if (debug_level > 1) {
+ MUSB_PRINT_TXCSR(peri_txcsr);
+ }
+
+ /* Check if a packet is waiting to be sent */
+ if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
+ u32 length;
+ u8 *data;
+ struct urb *urb = endpoint->tx_urb;
+ unsigned int remaining_packet = urb->actual_length -
+ endpoint->sent;
+
+ if (endpoint->tx_packetSize < remaining_packet)
+ length = endpoint->tx_packetSize;
+ else
+ length = remaining_packet;
+
+ data = (u8 *) urb->buffer;
+ data += endpoint->sent;
+
+ /* common musb fifo function */
+ write_fifo(ep, length, data);
+
+ musb_peri_tx_ready(ep);
+
+ endpoint->last = length;
+ /* usbd_tx_complete will take care of updating 'sent' */
+ usbd_tx_complete(endpoint);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Problem with urb %p or ep state %d\n",
+ __PRETTY_FUNCTION__,
+ endpoint->tx_urb, endpoint->state);
+ }
+
+ return ret;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint)
+{
+ if (0 == id) {
+ /* EP0 */
+ ep0_endpoint = endpoint;
+ ep0_endpoint->endpoint_address = 0xff;
+ ep0_urb = usbd_alloc_urb(device, endpoint);
+ } else if (MAX_ENDPOINT >= id) {
+ int ep_addr;
+
+ /* Check the direction */
+ ep_addr = endpoint->endpoint_address;
+ if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) {
+ /* IN */
+ epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
+ } else {
+ /* OUT */
+ epinfo[id * 2].epsize = endpoint->rcv_packetSize;
+ }
+
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s endpoint request %d exceeds maximum %d\n",
+ __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
+ }
+}
+
+void udc_connect(void)
+{
+ /* noop */
+}
+
+void udc_disconnect(void)
+{
+ /* noop */
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ enabled = 1;
+}
+
+void udc_disable(void)
+{
+ enabled = 0;
+}
+
+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);
+
+ udc_enable(device);
+}
+
+int udc_init(void)
+{
+ int ret;
+ int ep_loop;
+
+ ret = musb_platform_init();
+ if (ret < 0)
+ goto end;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+
+ /* Initialize the endpoints */
+ for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) {
+ epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
+ epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
+ epinfo[ep_loop].epsize = 0;
+ }
+
+ musb_peri_softconnect();
+
+ ret = 0;
+end:
+ return ret;
+}
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
new file mode 100644
index 0000000..3e502e7
--- /dev/null
+++ b/drivers/usb/musb/omap3.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2009 Texas Instruments
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 <twl4030.h>
+#include "omap3.h"
+
+static int platform_needs_initialization = 1;
+
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ OMAP3_USB_TIMEOUT,
+ 0
+};
+
+/*
+ * OMAP3 USB OTG registers.
+ */
+struct omap3_otg_regs {
+ u32 revision;
+ u32 sysconfig;
+ u32 sysstatus;
+ u32 interfsel;
+ u32 simenable;
+ u32 forcestdby;
+};
+
+static struct omap3_otg_regs *otg;
+
+#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000
+#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000
+#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010
+#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008
+#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004
+#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002
+#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001
+
+#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
+
+#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
+
+#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001
+
+
+#ifdef DEBUG_MUSB_OMAP3
+static void musb_db_otg_regs(void)
+{
+ u32 l;
+ l = readl(&otg->revision);
+ serial_printf("OTG_REVISION 0x%x\n", l);
+ l = readl(&otg->sysconfig);
+ serial_printf("OTG_SYSCONFIG 0x%x\n", l);
+ l = readl(&otg->sysstatus);
+ serial_printf("OTG_SYSSTATUS 0x%x\n", l);
+ l = readl(&otg->interfsel);
+ serial_printf("OTG_INTERFSEL 0x%x\n", l);
+ l = readl(&otg->forcestdby);
+ serial_printf("OTG_FORCESTDBY 0x%x\n", l);
+}
+#endif
+
+int musb_platform_init(void)
+{
+ int ret = -1;
+
+ if (platform_needs_initialization) {
+ u32 stdby;
+
+ if (twl4030_usb_ulpi_init()) {
+ serial_printf("ERROR: %s Could not initialize PHY\n",
+ __PRETTY_FUNCTION__);
+ goto end;
+ }
+
+ otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
+
+ /* Set OTG to always be on */
+ writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
+ OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
+
+ /* Set the interface */
+ writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
+
+ /* Clear force standby */
+ stdby = readl(&otg->forcestdby);
+ stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
+ writel(stdby, &otg->forcestdby);
+
+ platform_needs_initialization = 0;
+ }
+
+ ret = platform_needs_initialization;
+end:
+ return ret;
+
+}
+
+void musb_platform_deinit(void)
+{
+ /* noop */
+}
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
new file mode 100644
index 0000000..20fc9d2
--- /dev/null
+++ b/drivers/usb/musb/omap3.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is based on the file drivers/usb/musb/davinci.h
+ *
+ * This is the unique part of its copyright:
+ *
+ * --------------------------------------------------------------------
+ *
+ * Copyright (c) 2008 Texas Instruments
+ * Author: Thomas Abraham t-abraham at ti.com, Texas Instruments
+ *
+ * --------------------------------------------------------------------
+ *
+ * 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 _MUSB_OMAP3_H_
+#define _MUSB_OMAP3_H_
+
+#include "musb_core.h"
+
+/* Base address of MUSB registers */
+#define MENTOR_USB0_BASE (OMAP34XX_CORE_L4_IO_BASE + 0xAB000)
+
+/* Base address of OTG registers */
+#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
+
+/* Timeout for USB module */
+#define OMAP3_USB_TIMEOUT 0x3FFFFFF
+
+int musb_platform_init(void);
+
+#endif /* _MUSB_OMAP3_H */
+
diff --git a/include/usb.h b/include/usb.h
index 378a23b..198d5bb 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -131,7 +131,8 @@ struct usb_device {
#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
- defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
+ defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
+ defined(CONFIG_USB_OMAP3)
int usb_lowlevel_init(void);
int usb_lowlevel_stop(void);
diff --git a/include/usb/musb_udc.h b/include/usb/musb_udc.h
new file mode 100644
index 0000000..ef37dbb
--- /dev/null
+++ b/include/usb/musb_udc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.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
+ */
+#ifndef __MUSB_UDC_H__
+#define __MUSB_UDC_H__
+
+#include <usbdevice.h>
+
+/* UDC level routines */
+void udc_irq(void);
+void udc_set_nak(int ep_num);
+void udc_unset_nak(int ep_num);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint);
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+void udc_startup_events(struct usb_device_instance *device);
+int udc_init(void);
+
+/* usbtty */
+#ifdef CONFIG_USB_TTY
+
+#define EP0_MAX_PACKET_SIZE 64 /* MUSB_EP0_FIFOSIZE */
+#define UDC_INT_ENDPOINT 1
+#define UDC_INT_PACKET_SIZE 64
+#define UDC_OUT_ENDPOINT 2
+#define UDC_OUT_PACKET_SIZE 64
+#define UDC_IN_ENDPOINT 3
+#define UDC_IN_PACKET_SIZE 64
+#define UDC_BULK_PACKET_SIZE 64
+
+#endif /* CONFIG_USB_TTY */
+
+#endif /* __MUSB_UDC_H__ */
+
--
1.6.0.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-09-04 20:12 ` [U-Boot] [PATCH 4/8] OMAP3 Add usb device support Tom Rix
@ 2009-09-05 0:25 ` Jean-Christophe PLAGNIOL-VILLARD
2009-09-06 13:35 ` Tom
0 siblings, 1 reply; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2009-09-05 0:25 UTC (permalink / raw)
To: u-boot
Hi,
please be carefull you have a lot's of ligne which exceed 80 chars
limit
> +
> +/* Define MUSB_DEBUG before including this file to get debug macros */
> +#ifdef MUSB_DEBUG
> +
> +static inline void MUSB_PRINT_PWR(u8 b)
please lowercase
> +{
> + serial_printf("\tpower 0x%2.2x\n", b);
maybe a macro will simplify the code
#define MUSB_FLAGS_PRINT(x, y) \
if (b & MUSB_##x_##y) \
serial_printf("\t\t"#y"\n");
static inline void musb_print_pwr(u8 b)
{
serial_printf("\tpower 0x%2.2x\n", b);
MUSB_FLAGS_PRINT(POWER, ISOUPDATE);
MUSB_FLAGS_PRINT(POWER, SOFTCONN);
MUSB_FLAGS_PRINT(POWER, HSENAB);
MUSB_FLAGS_PRINT(POWER, HSMODE);
MUSB_FLAGS_PRINT(POWER, RESET);
MUSB_FLAGS_PRINT(POWER, RESUME);
MUSB_FLAGS_PRINT(POWER, SUSPENDM);
MUSB_FLAGS_PRINT(POWER, ENSUSPEND);
}
and so on
> +
> +static inline void MUSB_PRINT_CSR0(u16 w)
please lowercase and so on
> +{
> + serial_printf("\tcsr0 0x%4.4x\n", w);
> + if (w & MUSB_CSR0_FLUSHFIFO)
> + serial_printf("\t\tFLUSHFIFO\n");
> + if (w & MUSB_CSR0_P_SVDSETUPEND)
> + serial_printf("\t\tSERV_SETUPEND\n");
> + if (w & MUSB_CSR0_P_SVDRXPKTRDY)
> + serial_printf("\t\tSERV_RXPKTRDY\n");
> + if (w & MUSB_CSR0_P_SENDSTALL)
> + serial_printf("\t\tSENDSTALL\n");
> + if (w & MUSB_CSR0_P_SETUPEND)
> + serial_printf("\t\tSETUPEND\n");
> + if (w & MUSB_CSR0_P_DATAEND)
> + serial_printf("\t\tDATAEND\n");
> + if (w & MUSB_CSR0_P_SENTSTALL)
> + serial_printf("\t\tSENTSTALL\n");
> + if (w & MUSB_CSR0_TXPKTRDY)
> + serial_printf("\t\tTXPKTRDY\n");
> + if (w & MUSB_CSR0_RXPKTRDY)
> + serial_printf("\t\tRXPKTRDY\n");
> +}
> +
> +
> +#define MAX_ENDPOINT 15
maybe we can put it configurable
> +
> +#define GET_ENDPOINT(dev,ep) \
> +(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
> +
> +#define SET_EP0_STATE(s) \
> +do { \
> + if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
> + if ((s) != ep0_state) { \
> + if ((debug_setup) && (debug_level > 1)) \
> + serial_printf("INFO : Changing state from %s to %s in %s at line %d\n", ep0_state_strings[ep0_state], ep0_state_strings[s], __PRETTY_FUNCTION__, __LINE__); \
too long please split
> + ep0_state = s; \
> + } \
> + } else { \
> + if (debug_level > 0) \
> + serial_printf("Error at %s %d with setting state %d is invalid\n", __PRETTY_FUNCTION__, __LINE__, s); \
too long please split
> + } \
> +} while (0)
> +
> +/* static implies these initialized to 0 or NULL */
> +static int debug_setup;
> +static int debug_level;
> +static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
> +static enum ep0_state_enum { IDLE = 0, TX, RX, SET_ADDRESS } ep0_state = IDLE;
this will be better
static enum ep0_state_enum {
IDLE = 0,
TX,
RX,
SET_ADDRESS
} ep0_state = IDLE;
> +static char *ep0_state_strings[4] = {
> + "IDLE",
> + "TX",
> + "RX",
> + "SET_ADDRESS",
> +};
> +
> +static struct urb *ep0_urb;
> +struct usb_endpoint_instance *ep0_endpoint;
> +static struct usb_device_instance *udc_device;
> +static int enabled;
> +
> +#ifdef MUSB_DEBUG
> +static void musb_db_regs(void)
> +{
> + u8 b;
> + u16 w;
> +
> + b = readb(&musbr->faddr);
> + serial_printf("\tfaddr 0x%2.2x\n", b);
> +
> + b = readb(&musbr->power);
> + MUSB_PRINT_PWR(b);
> +
> + w = readw(&musbr->ep[0].ep0.csr0);
> + MUSB_PRINT_CSR0(w);
> +
> + b = readb(&musbr->devctl);
> + MUSB_PRINT_DEVCTL(b);
> +
> + b = readb(&musbr->ep[0].ep0.configdata);
> + MUSB_PRINT_CONFIG(b);
> +
> + w = readw(&musbr->frame);
> + serial_printf("\tframe 0x%4.4x\n", w);
> +
> + b = readb(&musbr->index);
> + serial_printf("\tindex 0x%2.2x\n", b);
> +
> + w = readw(&musbr->ep[1].epN.rxmaxp);
> + MUSB_PRINT_RXMAXP(w);
> +
> + w = readw(&musbr->ep[1].epN.rxcsr);
> + MUSB_PRINT_RXCSR(w);
> +
> + w = readw(&musbr->ep[1].epN.txmaxp);
> + MUSB_PRINT_TXMAXP(w);
> +
> + w = readw(&musbr->ep[1].epN.txcsr);
> + MUSB_PRINT_TXCSR(w);
> +}
> +#else
> +#define musb_db_regs()
> +#endif /* DEBUG_MUSB */
> +
> +static void musb_peri_softconnect(void)
> +{
> + u8 power, devctl;
> + u8 intrusb;
> + u16 intrrx, intrtx;
> +
> + /* Power off MUSB */
> + power = readb(&musbr->power);
> + power &= ~MUSB_POWER_SOFTCONN;
> + writeb(power, &musbr->power);
> +
> + /* Read intr to clear */
> + intrusb = readb(&musbr->intrusb);
> + intrrx = readw(&musbr->intrrx);
> + intrtx = readw(&musbr->intrtx);
> +
> + udelay(2 * 500000); /* 1 sec */
why not udelay(1000 * 1000) as other place?
> +
> + /* Power on MUSB */
> + power = readb(&musbr->power);
> + power |= MUSB_POWER_SOFTCONN;
> + /*
> + * The usb device interface is usb 1.1
> + * Disable 2.0 high speed by clearring the hsenable bit.
> + */
> + power &= ~MUSB_POWER_HSENAB;
> + writeb(power, &musbr->power);
> +
> + /* Check if device is in b-peripheral mode */
> + devctl = readb(&musbr->devctl);
> + if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
> + (devctl & MUSB_DEVCTL_HM)) {
> + serial_printf("ERROR : Unsupport USB mode\n");
> + serial_printf("Check that mini-B USB cable is attached to the device\n");
evenif it's too long it's better for search
> + }
> +
> + if (debug_setup && (debug_level > 1))
> + musb_db_regs();
> +}
> +
> +static void musb_peri_reset(void)
> +{
> + if ((debug_setup) && (debug_level > 1))
> + serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
what do you mean y __PRETTY_FUNCTION__?
> +
> + /* the device address is reset by the event */
> + usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
> + SET_EP0_STATE(IDLE);
> + if (ep0_endpoint)
> + ep0_endpoint->endpoint_address = 0xff;
> +}
> +
> +static void musb_peri_resume(void)
> +{
> + /* noop */
> +}
> +
> +static void musb_peri_ep0_stall(void)
> +{
> + u16 csr0;
please add an empty line
> + csr0 = readw(&musbr->ep[0].ep0.csr0);
> + csr0 |= MUSB_CSR0_P_SENDSTALL;
> + writew(csr0, &musbr->ep[0].ep0.csr0);
> + if ((debug_setup) && (debug_level > 1))
> + serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
> +}
> +
> +static void musb_peri_ep0_ack_req(void)
> +{
> + u16 csr0;
please add an empty line
> + csr0 = readw(&musbr->ep[0].ep0.csr0);
> + csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
> + writew(csr0, &musbr->ep[0].ep0.csr0);
> +}
> +
> +static void musb_ep0_tx_ready(void)
> +{
> + u16 csr0;
please add an empty line
> + csr0 = readw(&musbr->ep[0].ep0.csr0);
> + csr0 |= MUSB_CSR0_TXPKTRDY;
> + writew(csr0, &musbr->ep[0].ep0.csr0);
> +}
> +
> +static void musb_peri_ep0_last(void)
> +{
> + u16 csr0;
please add an empty line
> + csr0 = readw(&musbr->ep[0].ep0.csr0);
> + csr0 |= MUSB_CSR0_P_DATAEND;
> + writew(csr0, &musbr->ep[0].ep0.csr0);
> +}
is it not possible to create a single function which take
MUSB_CSR0_P_DATAEND, MUSB_CSR0_TXPKTRDY, MUSB_CSR0_P_SVDRXPKTRDY,
MUSB_CSR0_P_SENDSTALL etc... as paramter?
> +
> +static void musb_peri_ep0_set_address(void)
> +{
> + writeb(udc_device->address, &musbr->faddr);
> + SET_EP0_STATE(IDLE);
> + usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
> + if ((debug_setup) && (debug_level > 1))
> + serial_printf("INFO : %s Address set to %d\n", __PRETTY_FUNCTION__, udc_device->address);
> +}
> +
> +static void musb_peri_rx_ack(unsigned int ep)
> +{
> + u16 peri_rxcsr;
> + peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
> + peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
> + writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
> +}
> +
> +static void musb_peri_tx_ready(unsigned int ep)
> +{
> + u16 peri_txcsr;
> + peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
> + peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
> + writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
> +}
> +
> +static void musb_peri_ep0_zero_data_request(int err)
> +{
> + musb_peri_ep0_ack_req();
> +
> + if (err) {
> + musb_peri_ep0_stall();
> + SET_EP0_STATE(IDLE);
> + } else {
> +
> + musb_peri_ep0_last();
> +
> + /* USBD state */
> + switch (ep0_urb->device_request.bRequest) {
> + case USB_REQ_SET_ADDRESS:
> + if ((debug_setup) && (debug_level > 1))
> + serial_printf("INFO : %s received set address\n", __PRETTY_FUNCTION__);
maybe you can define a debug macro to reduce the code length
and avoid the if everywhere
> + break;
> +
> + case USB_REQ_SET_CONFIGURATION:
> + if ((debug_setup) && (debug_level > 1))
> + serial_printf("INFO : %s Configured\n", __PRETTY_FUNCTION__);
> + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
> + break;
> + }
> +
> + /* EP0 state */
> + if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
> + SET_EP0_STATE(SET_ADDRESS);
> + } else {
> + SET_EP0_STATE(IDLE);
> + }
> + }
> +}
> +
> +static void musb_peri_ep0_rx_data_request(void)
> +{
> + /*
> + * This is the completion of the data OUT / RX
> + *
> + * Host is sending data to ep0 that is not
> + * part of setup. This comes from the cdc_recv_setup
> + * op that is device specific.
> + *
> + */
> + musb_peri_ep0_ack_req();
> +
> + ep0_endpoint->rcv_urb = ep0_urb;
> + ep0_urb->actual_length = 0;
> + SET_EP0_STATE(RX);
> +}
> +
> +static void musb_peri_ep0_tx_data_request(int err)
> +{
> + if (err) {
> + musb_peri_ep0_stall();
> + SET_EP0_STATE(IDLE);
> + } else {
> + musb_peri_ep0_ack_req();
> +
> + ep0_endpoint->tx_urb = ep0_urb;
> + ep0_endpoint->sent = 0;
> + SET_EP0_STATE(TX);
> + }
> +}
> +
> +static void musb_peri_ep0_idle(void)
> +{
> + u16 count0;
> + int err;
> + u16 csr0;
> +
> + csr0 = readw(&musbr->ep[0].ep0.csr0);
> +
> + if (!(MUSB_CSR0_RXPKTRDY & csr0))
> + goto end;
> +
> + count0 = readw(&musbr->ep[0].ep0.count0);
> + if (count0 == 0)
> + goto end;
> +
> + if (count0 != 8) {
> + if ((debug_setup) && (debug_level > 1))
> + serial_printf("WARN : %s SETUP incorrect size %d\n",
> + __PRETTY_FUNCTION__, count0);
> + musb_peri_ep0_stall();
> + goto end;
> + }
> +
> + read_fifo(0, count0, &ep0_urb->device_request);
> +
> + if (debug_level > 2) {
> + PRINT_USB_DEVICE_REQUEST(&ep0_urb->device_request);
> + }
> +
> + if (0 == ep0_urb->device_request.wLength) {
please invert the test
> + err = ep0_recv_setup(ep0_urb);
> +
> + /* Zero data request */
> + musb_peri_ep0_zero_data_request(err);
> + } else {
> + /* Is data coming or going ? */
> + u8 reqType = ep0_urb->device_request.bmRequestType;
please add an empty line
> + if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
> + err = ep0_recv_setup(ep0_urb);
> + /* Device to host */
> + musb_peri_ep0_tx_data_request(err);
> + } else {
> + /*
> + * Host to device
> + *
> + * The RX routine will call ep0_recv_setup
> + * when the data packet has arrived.
> + */
> + musb_peri_ep0_rx_data_request();
> + }
> + }
> +
> +end:
> + return;
why? will not be usefull to have an error return?
> +}
> +
> +
> diff --git a/include/usb.h b/include/usb.h
> index 378a23b..198d5bb 100644
> --- a/include/usb.h
> +++ b/include/usb.h
> @@ -131,7 +131,8 @@ struct usb_device {
> #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
> defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
> defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
> - defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
> + defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
> + defined(CONFIG_USB_OMAP3)
a simple CONFIG will be better
>
> int usb_lowlevel_init(void);
> int usb_lowlevel_stop(void);
Best Regards,
J.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-09-05 0:25 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2009-09-06 13:35 ` Tom
2009-09-06 13:48 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 1 reply; 9+ messages in thread
From: Tom @ 2009-09-06 13:35 UTC (permalink / raw)
To: u-boot
Jean-Christophe PLAGNIOL-VILLARD wrote:
> Hi,
>
> please be carefull you have a lot's of ligne which exceed 80 chars
> limit
>
>
Yes I saw these from check_patch.
I will try to reduce these.
>> +
>> +/* Define MUSB_DEBUG before including this file to get debug macros */
>> +#ifdef MUSB_DEBUG
>> +
>> +static inline void MUSB_PRINT_PWR(u8 b)
>>
> please lowercase
>
OK
>> +{
>> + serial_printf("\tpower 0x%2.2x\n", b);
>>
> maybe a macro will simplify the code
> #define MUSB_FLAGS_PRINT(x, y) \
> if (b & MUSB_##x_##y) \
> serial_printf("\t\t"#y"\n");
>
> static inline void musb_print_pwr(u8 b)
> {
> serial_printf("\tpower 0x%2.2x\n", b);
> MUSB_FLAGS_PRINT(POWER, ISOUPDATE);
> MUSB_FLAGS_PRINT(POWER, SOFTCONN);
> MUSB_FLAGS_PRINT(POWER, HSENAB);
> MUSB_FLAGS_PRINT(POWER, HSMODE);
> MUSB_FLAGS_PRINT(POWER, RESET);
> MUSB_FLAGS_PRINT(POWER, RESUME);
> MUSB_FLAGS_PRINT(POWER, SUSPENDM);
> MUSB_FLAGS_PRINT(POWER, ENSUSPEND);
> }
> and so on
>
Thanks.
I will give this a try.
>> +
>> +static inline void MUSB_PRINT_CSR0(u16 w)
>>
> please lowercase and so on
>
>> +{
>> + serial_printf("\tcsr0 0x%4.4x\n", w);
>> + if (w & MUSB_CSR0_FLUSHFIFO)
>> + serial_printf("\t\tFLUSHFIFO\n");
>> + if (w & MUSB_CSR0_P_SVDSETUPEND)
>> + serial_printf("\t\tSERV_SETUPEND\n");
>> + if (w & MUSB_CSR0_P_SVDRXPKTRDY)
>> + serial_printf("\t\tSERV_RXPKTRDY\n");
>> + if (w & MUSB_CSR0_P_SENDSTALL)
>> + serial_printf("\t\tSENDSTALL\n");
>> + if (w & MUSB_CSR0_P_SETUPEND)
>> + serial_printf("\t\tSETUPEND\n");
>> + if (w & MUSB_CSR0_P_DATAEND)
>> + serial_printf("\t\tDATAEND\n");
>> + if (w & MUSB_CSR0_P_SENTSTALL)
>> + serial_printf("\t\tSENTSTALL\n");
>> + if (w & MUSB_CSR0_TXPKTRDY)
>> + serial_printf("\t\tTXPKTRDY\n");
>> + if (w & MUSB_CSR0_RXPKTRDY)
>> + serial_printf("\t\tRXPKTRDY\n");
>> +}
>> +
>>
>
>
>> +
>> +#define MAX_ENDPOINT 15
>>
> maybe we can put it configurable
>
mmmm I will see
>> +
>> +#define GET_ENDPOINT(dev,ep) \
>> +(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
>> +
>> +#define SET_EP0_STATE(s) \
>> +do { \
>> + if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
>> + if ((s) != ep0_state) { \
>> + if ((debug_setup) && (debug_level > 1)) \
>> + serial_printf("INFO : Changing state from %s to %s in %s at line %d\n", ep0_state_strings[ep0_state], ep0_state_strings[s], __PRETTY_FUNCTION__, __LINE__); \
>>
> too long please split
>
>> + ep0_state = s; \
>> + } \
>> + } else { \
>> + if (debug_level > 0) \
>> + serial_printf("Error at %s %d with setting state %d is invalid\n", __PRETTY_FUNCTION__, __LINE__, s); \
>>
> too long please split
>
Ok.
>> + } \
>> +} while (0)
>> +
>> +/* static implies these initialized to 0 or NULL */
>> +static int debug_setup;
>> +static int debug_level;
>> +static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
>> +static enum ep0_state_enum { IDLE = 0, TX, RX, SET_ADDRESS } ep0_state = IDLE;
>>
> this will be better
> static enum ep0_state_enum {
> IDLE = 0,
> TX,
> RX,
> SET_ADDRESS
> } ep0_state = IDLE;
>
ok
>> +static char *ep0_state_strings[4] = {
>> + "IDLE",
>> + "TX",
>> + "RX",
>> + "SET_ADDRESS",
>> +};
>> +
>> +static struct urb *ep0_urb;
>> +struct usb_endpoint_instance *ep0_endpoint;
>> +static struct usb_device_instance *udc_device;
>> +static int enabled;
>> +
>> +#ifdef MUSB_DEBUG
>> +static void musb_db_regs(void)
>> +{
>> + u8 b;
>> + u16 w;
>> +
>> + b = readb(&musbr->faddr);
>> + serial_printf("\tfaddr 0x%2.2x\n", b);
>> +
>> + b = readb(&musbr->power);
>> + MUSB_PRINT_PWR(b);
>> +
>> + w = readw(&musbr->ep[0].ep0.csr0);
>> + MUSB_PRINT_CSR0(w);
>> +
>> + b = readb(&musbr->devctl);
>> + MUSB_PRINT_DEVCTL(b);
>> +
>> + b = readb(&musbr->ep[0].ep0.configdata);
>> + MUSB_PRINT_CONFIG(b);
>> +
>> + w = readw(&musbr->frame);
>> + serial_printf("\tframe 0x%4.4x\n", w);
>> +
>> + b = readb(&musbr->index);
>> + serial_printf("\tindex 0x%2.2x\n", b);
>> +
>> + w = readw(&musbr->ep[1].epN.rxmaxp);
>> + MUSB_PRINT_RXMAXP(w);
>> +
>> + w = readw(&musbr->ep[1].epN.rxcsr);
>> + MUSB_PRINT_RXCSR(w);
>> +
>> + w = readw(&musbr->ep[1].epN.txmaxp);
>> + MUSB_PRINT_TXMAXP(w);
>> +
>> + w = readw(&musbr->ep[1].epN.txcsr);
>> + MUSB_PRINT_TXCSR(w);
>> +}
>> +#else
>> +#define musb_db_regs()
>> +#endif /* DEBUG_MUSB */
>> +
>> +static void musb_peri_softconnect(void)
>> +{
>> + u8 power, devctl;
>> + u8 intrusb;
>> + u16 intrrx, intrtx;
>> +
>> + /* Power off MUSB */
>> + power = readb(&musbr->power);
>> + power &= ~MUSB_POWER_SOFTCONN;
>> + writeb(power, &musbr->power);
>> +
>> + /* Read intr to clear */
>> + intrusb = readb(&musbr->intrusb);
>> + intrrx = readw(&musbr->intrrx);
>> + intrtx = readw(&musbr->intrtx);
>> +
>> + udelay(2 * 500000); /* 1 sec */
>>
> why not udelay(1000 * 1000) as other place?
>
cruft begone!
ok. i will clean this up.
>> +
>> + /* Power on MUSB */
>> + power = readb(&musbr->power);
>> + power |= MUSB_POWER_SOFTCONN;
>> + /*
>> + * The usb device interface is usb 1.1
>> + * Disable 2.0 high speed by clearring the hsenable bit.
>> + */
>> + power &= ~MUSB_POWER_HSENAB;
>> + writeb(power, &musbr->power);
>> +
>> + /* Check if device is in b-peripheral mode */
>> + devctl = readb(&musbr->devctl);
>> + if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
>> + (devctl & MUSB_DEVCTL_HM)) {
>> + serial_printf("ERROR : Unsupport USB mode\n");
>> + serial_printf("Check that mini-B USB cable is attached to the device\n");
>>
> evenif it's too long it's better for search
>
>> + }
>> +
>> + if (debug_setup && (debug_level > 1))
>> + musb_db_regs();
>> +}
>> +
>> +static void musb_peri_reset(void)
>> +{
>> + if ((debug_setup) && (debug_level > 1))
>> + serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
>>
> what do you mean y __PRETTY_FUNCTION__?
>
This a gcc compiler macro for printing out the function of the calling
routine. It is useful in the macro's like the state machine changer
to show which function did the change instead of the usual
__LINE__ + __FILE__ + eyeball time. It is a non-standard cpp macro
and would bite us when compiling without gcc. Does u-boot build
with non-gcc ?
>> +
>> + /* the device address is reset by the event */
>> + usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
>> + SET_EP0_STATE(IDLE);
>> + if (ep0_endpoint)
>> + ep0_endpoint->endpoint_address = 0xff;
>> +}
>> +
>> +static void musb_peri_resume(void)
>> +{
>> + /* noop */
>> +}
>> +
>> +static void musb_peri_ep0_stall(void)
>> +{
>> + u16 csr0;
>>
> please add an empty line
>
ok
>> + csr0 = readw(&musbr->ep[0].ep0.csr0);
>> + csr0 |= MUSB_CSR0_P_SENDSTALL;
>> + writew(csr0, &musbr->ep[0].ep0.csr0);
>> + if ((debug_setup) && (debug_level > 1))
>> + serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
>> +}
>> +
>> +static void musb_peri_ep0_ack_req(void)
>> +{
>> + u16 csr0;
>>
> please add an empty line
>
ok,
>> + csr0 = readw(&musbr->ep[0].ep0.csr0);
>> + csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
>> + writew(csr0, &musbr->ep[0].ep0.csr0);
>> +}
>> +
>> +static void musb_ep0_tx_ready(void)
>> +{
>> + u16 csr0;
>>
> please add an empty line
>
ok
>> + csr0 = readw(&musbr->ep[0].ep0.csr0);
>> + csr0 |= MUSB_CSR0_TXPKTRDY;
>> + writew(csr0, &musbr->ep[0].ep0.csr0);
>> +}
>> +
>> +static void musb_peri_ep0_last(void)
>> +{
>> + u16 csr0;
>>
> please add an empty line
>
empty lines for everyone!
>> + csr0 = readw(&musbr->ep[0].ep0.csr0);
>> + csr0 |= MUSB_CSR0_P_DATAEND;
>> + writew(csr0, &musbr->ep[0].ep0.csr0);
>> +}
>>
> is it not possible to create a single function which take
> MUSB_CSR0_P_DATAEND, MUSB_CSR0_TXPKTRDY, MUSB_CSR0_P_SVDRXPKTRDY,
> MUSB_CSR0_P_SENDSTALL etc... as paramter?
>
>> +
>> +static void musb_peri_ep0_set_address(void)
>> +{
>> + writeb(udc_device->address, &musbr->faddr);
>> + SET_EP0_STATE(IDLE);
>> + usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
>> + if ((debug_setup) && (debug_level > 1))
>> + serial_printf("INFO : %s Address set to %d\n", __PRETTY_FUNCTION__, udc_device->address);
>> +}
>> +
>> +static void musb_peri_rx_ack(unsigned int ep)
>> +{
>> + u16 peri_rxcsr;
>> + peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
>> + peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
>> + writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
>> +}
>> +
>> +static void musb_peri_tx_ready(unsigned int ep)
>> +{
>> + u16 peri_txcsr;
>> + peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
>> + peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
>> + writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
>> +}
>> +
>> +static void musb_peri_ep0_zero_data_request(int err)
>> +{
>> + musb_peri_ep0_ack_req();
>> +
>> + if (err) {
>> + musb_peri_ep0_stall();
>> + SET_EP0_STATE(IDLE);
>> + } else {
>> +
>> + musb_peri_ep0_last();
>> +
>> + /* USBD state */
>> + switch (ep0_urb->device_request.bRequest) {
>> + case USB_REQ_SET_ADDRESS:
>> + if ((debug_setup) && (debug_level > 1))
>> + serial_printf("INFO : %s received set address\n", __PRETTY_FUNCTION__);
>>
> maybe you can define a debug macro to reduce the code length
> and avoid the if everywhere
>
ok i will look into it.
>> + break;
>> +
>> + case USB_REQ_SET_CONFIGURATION:
>> + if ((debug_setup) && (debug_level > 1))
>> + serial_printf("INFO : %s Configured\n", __PRETTY_FUNCTION__);
>> + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
>> + break;
>> + }
>> +
>> + /* EP0 state */
>> + if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
>> + SET_EP0_STATE(SET_ADDRESS);
>> + } else {
>> + SET_EP0_STATE(IDLE);
>> + }
>> + }
>> +}
>> +
>> +static void musb_peri_ep0_rx_data_request(void)
>> +{
>> + /*
>> + * This is the completion of the data OUT / RX
>> + *
>> + * Host is sending data to ep0 that is not
>> + * part of setup. This comes from the cdc_recv_setup
>> + * op that is device specific.
>> + *
>> + */
>> + musb_peri_ep0_ack_req();
>> +
>> + ep0_endpoint->rcv_urb = ep0_urb;
>> + ep0_urb->actual_length = 0;
>> + SET_EP0_STATE(RX);
>> +}
>> +
>> +static void musb_peri_ep0_tx_data_request(int err)
>> +{
>> + if (err) {
>> + musb_peri_ep0_stall();
>> + SET_EP0_STATE(IDLE);
>> + } else {
>> + musb_peri_ep0_ack_req();
>> +
>> + ep0_endpoint->tx_urb = ep0_urb;
>> + ep0_endpoint->sent = 0;
>> + SET_EP0_STATE(TX);
>> + }
>> +}
>> +
>> +static void musb_peri_ep0_idle(void)
>> +{
>> + u16 count0;
>> + int err;
>> + u16 csr0;
>> +
>> + csr0 = readw(&musbr->ep[0].ep0.csr0);
>> +
>> + if (!(MUSB_CSR0_RXPKTRDY & csr0))
>> + goto end;
>> +
>> + count0 = readw(&musbr->ep[0].ep0.count0);
>> + if (count0 == 0)
>> + goto end;
>> +
>> + if (count0 != 8) {
>> + if ((debug_setup) && (debug_level > 1))
>> + serial_printf("WARN : %s SETUP incorrect size %d\n",
>> + __PRETTY_FUNCTION__, count0);
>> + musb_peri_ep0_stall();
>> + goto end;
>> + }
>> +
>> + read_fifo(0, count0, &ep0_urb->device_request);
>> +
>> + if (debug_level > 2) {
>> + PRINT_USB_DEVICE_REQUEST(&ep0_urb->device_request);
>> + }
>> +
>> + if (0 == ep0_urb->device_request.wLength) {
>>
> please invert the test
>
ok
>> + err = ep0_recv_setup(ep0_urb);
>> +
>> + /* Zero data request */
>> + musb_peri_ep0_zero_data_request(err);
>> + } else {
>> + /* Is data coming or going ? */
>> + u8 reqType = ep0_urb->device_request.bmRequestType;
>>
> please add an empty line
>
>> + if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
>> + err = ep0_recv_setup(ep0_urb);
>> + /* Device to host */
>> + musb_peri_ep0_tx_data_request(err);
>> + } else {
>> + /*
>> + * Host to device
>> + *
>> + * The RX routine will call ep0_recv_setup
>> + * when the data packet has arrived.
>> + */
>> + musb_peri_ep0_rx_data_request();
>> + }
>> + }
>> +
>> +end:
>> + return;
>>
> why? will not be usefull to have an error return?
>
I am not sure it needs an error.
I will check.
>> +}
>> +
>> +
>> diff --git a/include/usb.h b/include/usb.h
>> index 378a23b..198d5bb 100644
>> --- a/include/usb.h
>> +++ b/include/usb.h
>> @@ -131,7 +131,8 @@ struct usb_device {
>> #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
>> defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
>> defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
>> - defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
>> + defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
>> + defined(CONFIG_USB_OMAP3)
>>
> a simple CONFIG will be better
>
Can this be a follow-on ?
Tom
>>
>> int usb_lowlevel_init(void);
>> int usb_lowlevel_stop(void);
>>
>
> Best Regards,
> J.
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-09-06 13:35 ` Tom
@ 2009-09-06 13:48 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 0 replies; 9+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2009-09-06 13:48 UTC (permalink / raw)
To: u-boot
> >>+ }
> >>+
> >>+ if (debug_setup && (debug_level > 1))
> >>+ musb_db_regs();
> >>+}
> >>+
> >>+static void musb_peri_reset(void)
> >>+{
> >>+ if ((debug_setup) && (debug_level > 1))
> >>+ serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
> >what do you mean y __PRETTY_FUNCTION__?
> This a gcc compiler macro for printing out the function of the calling
> routine. It is useful in the macro's like the state machine changer
> to show which function did the change instead of the usual
> __LINE__ + __FILE__ + eyeball time. It is a non-standard cpp macro
> and would bite us when compiling without gcc. Does u-boot build
> with non-gcc ?
no only gcc but I think it will not be impossible to use an other toolchains
but ok
> >>+
> >>+ /* the device address is reset by the event */
> >>diff --git a/include/usb.h b/include/usb.h
> >>index 378a23b..198d5bb 100644
> >>--- a/include/usb.h
> >>+++ b/include/usb.h
> >>@@ -131,7 +131,8 @@ struct usb_device {
> >> #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
> >> defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
> >> defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
> >>- defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
> >>+ defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
> >>+ defined(CONFIG_USB_OMAP3)
> >a simple CONFIG will be better
> Can this be a follow-on ?
ofcource
Best Regards,
J.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-09-28 16:34 ` [U-Boot] [PATCH 3/8] TWL4030 Add usb PHY support y at windriver.com
@ 2009-09-28 16:34 ` y at windriver.com
0 siblings, 0 replies; 9+ messages in thread
From: y at windriver.com @ 2009-09-28 16:34 UTC (permalink / raw)
To: u-boot
From: Tom Rix <Tom.Rix@windriver.com>
This change adds the usb device support for musb.
Omap3 platform support added at the same level as davinci.
The interface for usbtty to use the musb device support was added.
Verified on omap3 beagle, zoom1 and zoom2.
Signed-off-by: Tom Rix <Tom.Rix@windriver.com>
---
drivers/serial/usbtty.h | 2 +
drivers/usb/musb/Makefile | 2 +
drivers/usb/musb/musb_core.c | 8 +-
drivers/usb/musb/musb_core.h | 40 ++
drivers/usb/musb/musb_debug.h | 205 +++++++++
drivers/usb/musb/musb_udc.c | 963 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/musb/omap3.c | 129 ++++++
drivers/usb/musb/omap3.h | 48 ++
include/usb.h | 3 +-
include/usb/musb_udc.h | 54 +++
10 files changed, 1451 insertions(+), 3 deletions(-)
create mode 100644 drivers/usb/musb/musb_debug.h
create mode 100644 drivers/usb/musb/musb_udc.c
create mode 100644 drivers/usb/musb/omap3.c
create mode 100644 drivers/usb/musb/omap3.h
create mode 100644 include/usb/musb_udc.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index f746d63..6b6c4a1 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -29,6 +29,8 @@
#include <usb/mpc8xx_udc.h>
#elif defined(CONFIG_OMAP1510)
#include <usb/omap1510_udc.h>
+#elif defined(CONFIG_MUSB_UDC)
+#include <usb/musb_udc.h>
#elif defined(CONFIG_PXA27X)
#include <usb/pxa27x_udc.h>
#endif
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 09e0a5f..f2ccd9f 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_musb.a
COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o
COBJS-$(CONFIG_USB_DAVINCI) += davinci.o
+COBJS-$(CONFIG_USB_OMAP3) += omap3.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ec57fc8..22f3dba 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -32,7 +32,9 @@ struct musb_regs *musbr;
*/
void musb_start(void)
{
+#if defined(CONFIG_MUSB_HCD)
u8 devctl;
+#endif
/* disable all interrupts */
writew(0, &musbr->intrtxe);
@@ -74,9 +76,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->txfifosz);
writew(fifoaddr >> 3, &musbr->txfifoadd);
+
+ csr = readw(&musbr->txcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->txcsr);
writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
#endif
/* Flush fifo if required */
@@ -87,9 +90,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->rxfifosz);
writew(fifoaddr >> 3, &musbr->rxfifoadd);
+
+ csr = readw(&musbr->rxcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->rxcsr);
writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
#endif
/* Flush fifo if required */
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f9da3f0..15c7f49 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -40,6 +40,36 @@
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+/* EP0 */
+struct musb_ep0_regs {
+ u16 reserved4;
+ u16 csr0;
+ u16 reserved5;
+ u16 reserved6;
+ u16 count0;
+ u8 host_type0;
+ u8 host_naklimit0;
+ u8 reserved7;
+ u8 reserved8;
+ u8 reserved9;
+ u8 configdata;
+};
+
+/* EP 1-15 */
+struct musb_epN_regs {
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+};
+
/* Mentor USB core register overlay structure */
struct musb_regs {
/* common registers */
@@ -97,6 +127,16 @@ struct musb_regs {
u8 rxhubaddr;
u8 rxhubport;
} tar[16];
+ /*
+ * end point registers
+ * ep0 elements are valid when array index is 0
+ * otherwise epN is valid
+ */
+ union musb_ep_regs {
+ struct musb_ep0_regs ep0;
+ struct musb_epN_regs epN;
+ } ep[16];
+
} __attribute__((aligned(32)));
/*
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
new file mode 100644
index 0000000..62380ff
--- /dev/null
+++ b/drivers/usb/musb/musb_debug.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.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
+ */
+
+/* Define MUSB_DEBUG before including this file to get debug macros */
+#ifdef MUSB_DEBUG
+
+#define MUSB_FLAGS_PRINT(v, x, y) \
+ if (((v) & MUSB_##x##_##y)) \
+ serial_printf("\t\t"#y"\n")
+
+static inline void musb_print_pwr(u8 b)
+{
+ serial_printf("\tpower 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE);
+ MUSB_FLAGS_PRINT(b, POWER, SOFTCONN);
+ MUSB_FLAGS_PRINT(b, POWER, HSENAB);
+ MUSB_FLAGS_PRINT(b, POWER, HSMODE);
+ MUSB_FLAGS_PRINT(b, POWER, RESET);
+ MUSB_FLAGS_PRINT(b, POWER, RESUME);
+ MUSB_FLAGS_PRINT(b, POWER, SUSPENDM);
+ MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND);
+}
+
+static inline void musb_print_csr0(u16 w)
+{
+ serial_printf("\tcsr0 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY);
+}
+
+static inline void musb_print_intrusb(u8 b)
+{
+ serial_printf("\tintrusb 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, INTR, VBUSERROR);
+ MUSB_FLAGS_PRINT(b, INTR, SESSREQ);
+ MUSB_FLAGS_PRINT(b, INTR, DISCONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, CONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, SOF);
+ MUSB_FLAGS_PRINT(b, INTR, RESUME);
+ MUSB_FLAGS_PRINT(b, INTR, SUSPEND);
+
+ if (b & MUSB_INTR_BABBLE)
+ serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
+
+}
+
+static inline void musb_print_intrtx(u16 w)
+{
+ serial_printf("\tintrtx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_intrrx(u16 w)
+{
+ serial_printf("\tintrx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_devctl(u8 b)
+{
+ serial_printf("\tdevctl 0x%2.2x\n", b);
+ if (b & MUSB_DEVCTL_BDEVICE)
+ serial_printf("\t\tB device\n");
+ else
+ serial_printf("\t\tA device\n");
+ if (b & MUSB_DEVCTL_FSDEV)
+ serial_printf("\t\tFast Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_LSDEV)
+ serial_printf("\t\tSlow Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_HM)
+ serial_printf("\t\tHost mode\n");
+ else
+ serial_printf("\t\tPeripherial mode\n");
+ if (b & MUSB_DEVCTL_HR)
+ serial_printf("\t\tHost request started(B device)\n");
+ else
+ serial_printf("\t\tHost request finished(B device)\n");
+ if (b & MUSB_DEVCTL_BDEVICE) {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(B device)\n");
+ else
+ serial_printf("\t\tEnd of session(B device)\n");
+ } else {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(A device)\n");
+ else
+ serial_printf("\t\tEnd of session(A device)\n");
+ }
+}
+
+static inline void musb_print_config(u8 b)
+{
+ serial_printf("\tconfig 0x%2.2x\n", b);
+ if (b & MUSB_CONFIGDATA_MPRXE)
+ serial_printf("\t\tAuto combine rx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_MPTXE)
+ serial_printf("\t\tAuto split tx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_BIGENDIAN)
+ serial_printf("\t\tBig Endian ordering\n");
+ else
+ serial_printf("\t\tLittle Endian ordering\n");
+ if (b & MUSB_CONFIGDATA_HBRXE)
+ serial_printf("\t\tHigh speed rx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_HBTXE)
+ serial_printf("\t\tHigh speed tx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_DYNFIFO)
+ serial_printf("\t\tDynamic fifo sizing\n");
+ if (b & MUSB_CONFIGDATA_SOFTCONE)
+ serial_printf("\t\tSoft Connect\n");
+ if (b & MUSB_CONFIGDATA_UTMIDW)
+ serial_printf("\t\t16 bit data width\n");
+ else
+ serial_printf("\t\t8 bit data width\n");
+}
+
+static inline void musb_print_rxmaxp(u16 w)
+{
+ serial_printf("\trxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_rxcsr(u16 w)
+{
+ serial_printf("\trxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB);
+ MUSB_FLAGS_PRINT(w, RXCSR, DISNYET);
+ MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE);
+ MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR);
+ MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL);
+ MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN);
+
+ if (w & MUSB_RXCSR_P_ISO)
+ serial_printf("\t\tiso mode\n");
+ else
+ serial_printf("\t\tbulk mode\n");
+
+}
+
+static inline void musb_print_txmaxp(u16 w)
+{
+ serial_printf("\ttxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_txcsr(u16 w)
+{
+ serial_printf("\ttxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL);
+
+ if (w & MUSB_TXCSR_MODE)
+ serial_printf("\t\tTX mode\n");
+ else
+ serial_printf("\t\tRX mode\n");
+}
+
+#else
+
+/* stubs */
+
+#define musb_print_pwr(b)
+#define musb_print_csr0(w)
+#define musb_print_intrusb(b)
+#define musb_print_intrtx(w)
+#define musb_print_intrrx(w)
+#define musb_print_devctl(b)
+#define musb_print_config(b)
+#define musb_print_rxmaxp(w)
+#define musb_print_rxcsr(w)
+#define musb_print_txmaxp(w)
+#define musb_print_txcsr(w)
+
+#endif /* MUSB_DEBUG */
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
new file mode 100644
index 0000000..fc43cf4
--- /dev/null
+++ b/drivers/usb/musb/musb_udc.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is a rewrite of the usb device part of
+ * repository git.omapzoom.org/repo/u-boot.git, branch master,
+ * file cpu/omap3/fastboot.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * -------------------------------------------------------------------------
+ *
+ * The details of connecting the device to the uboot usb device subsystem
+ * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
+ * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 Texas Instruments Incorporated.
+ *
+ * Based on
+ * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
+ * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
+ *
+ * Author: Diego Dompe (diego.dompe at ridgerun.com)
+ * Atin Malaviya (atin.malaviya at gmail.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 <usb/musb_udc.h>
+#include "../gadget/ep0.h"
+#include "musb_core.h"
+#if defined(CONFIG_USB_OMAP3)
+#include "omap3.h"
+#elif defined(CONFIG_USB_DAVINCI)
+#include "davinci.h"
+#endif
+
+/* Define MUSB_DEBUG for debugging */
+/* #define MUSB_DEBUG */
+#include "musb_debug.h"
+
+#define MAX_ENDPOINT 15
+
+#define GET_ENDPOINT(dev,ep) \
+(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
+
+#define SET_EP0_STATE(s) \
+do { \
+ if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
+ if ((s) != ep0_state) { \
+ if ((debug_setup) && (debug_level > 1)) \
+ serial_printf("INFO : Changing state " \
+ "from %s to %s in %s at " \
+ "line %d\n", \
+ ep0_state_strings[ep0_state],\
+ ep0_state_strings[s], \
+ __PRETTY_FUNCTION__, \
+ __LINE__); \
+ ep0_state = s; \
+ } \
+ } else { \
+ if (debug_level > 0) \
+ serial_printf("Error at %s %d with setting " \
+ "state %d is invalid\n", \
+ __PRETTY_FUNCTION__, __LINE__, s); \
+ } \
+} while (0)
+
+/* static implies these initialized to 0 or NULL */
+static int debug_setup;
+static int debug_level;
+static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
+static enum ep0_state_enum {
+ IDLE = 0,
+ TX,
+ RX,
+ SET_ADDRESS
+} ep0_state = IDLE;
+static char *ep0_state_strings[4] = {
+ "IDLE",
+ "TX",
+ "RX",
+ "SET_ADDRESS",
+};
+
+static struct urb *ep0_urb;
+struct usb_endpoint_instance *ep0_endpoint;
+static struct usb_device_instance *udc_device;
+static int enabled;
+
+#ifdef MUSB_DEBUG
+static void musb_db_regs(void)
+{
+ u8 b;
+ u16 w;
+
+ b = readb(&musbr->faddr);
+ serial_printf("\tfaddr 0x%2.2x\n", b);
+
+ b = readb(&musbr->power);
+ musb_print_pwr(b);
+
+ w = readw(&musbr->ep[0].ep0.csr0);
+ musb_print_csr0(w);
+
+ b = readb(&musbr->devctl);
+ musb_print_devctl(b);
+
+ b = readb(&musbr->ep[0].ep0.configdata);
+ musb_print_config(b);
+
+ w = readw(&musbr->frame);
+ serial_printf("\tframe 0x%4.4x\n", w);
+
+ b = readb(&musbr->index);
+ serial_printf("\tindex 0x%2.2x\n", b);
+
+ w = readw(&musbr->ep[1].epN.rxmaxp);
+ musb_print_rxmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.rxcsr);
+ musb_print_rxcsr(w);
+
+ w = readw(&musbr->ep[1].epN.txmaxp);
+ musb_print_txmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.txcsr);
+ musb_print_txcsr(w);
+}
+#else
+#define musb_db_regs()
+#endif /* DEBUG_MUSB */
+
+static void musb_peri_softconnect(void)
+{
+ u8 power, devctl;
+ u8 intrusb;
+ u16 intrrx, intrtx;
+
+ /* Power off MUSB */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_SOFTCONN;
+ writeb(power, &musbr->power);
+
+ /* Read intr to clear */
+ intrusb = readb(&musbr->intrusb);
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ udelay(1000 * 1000); /* 1 sec */
+
+ /* Power on MUSB */
+ power = readb(&musbr->power);
+ power |= MUSB_POWER_SOFTCONN;
+ /*
+ * The usb device interface is usb 1.1
+ * Disable 2.0 high speed by clearring the hsenable bit.
+ */
+ power &= ~MUSB_POWER_HSENAB;
+ writeb(power, &musbr->power);
+
+ /* Check if device is in b-peripheral mode */
+ devctl = readb(&musbr->devctl);
+ if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
+ (devctl & MUSB_DEVCTL_HM)) {
+ serial_printf("ERROR : Unsupport USB mode\n");
+ serial_printf("Check that mini-B USB cable is attached "
+ "to the device\n");
+ }
+
+ if (debug_setup && (debug_level > 1))
+ musb_db_regs();
+}
+
+static void musb_peri_reset(void)
+{
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
+
+ if (ep0_endpoint)
+ ep0_endpoint->endpoint_address = 0xff;
+
+ /* Sync sw and hw addresses */
+ writeb(udc_device->address, &musbr->faddr);
+
+ SET_EP0_STATE(IDLE);
+}
+
+static void musb_peri_resume(void)
+{
+ /* noop */
+}
+
+static void musb_peri_ep0_stall(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SENDSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
+}
+
+static void musb_peri_ep0_ack_req(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_TXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready_and_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_DATAEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_set_address(void)
+{
+ u8 faddr;
+ writeb(udc_device->address, &musbr->faddr);
+
+ /* Verify */
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address == faddr) {
+ SET_EP0_STATE(IDLE);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Address set to %d\n",
+ __PRETTY_FUNCTION__, udc_device->address);
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Address missmatch "
+ "sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ }
+}
+
+static void musb_peri_rx_ack(unsigned int ep)
+{
+ u16 peri_rxcsr;
+
+ peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+ peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
+}
+
+static void musb_peri_tx_ready(unsigned int ep)
+{
+ u16 peri_txcsr;
+
+ peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+ peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+}
+
+static void musb_peri_ep0_zero_data_request(int err)
+{
+ musb_peri_ep0_ack_req();
+
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+
+ musb_peri_ep0_last();
+
+ /* USBD state */
+ switch (ep0_urb->device_request.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s received set "
+ "address\n", __PRETTY_FUNCTION__);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Configured\n",
+ __PRETTY_FUNCTION__);
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ break;
+ }
+
+ /* EP0 state */
+ if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
+ SET_EP0_STATE(SET_ADDRESS);
+ } else {
+ SET_EP0_STATE(IDLE);
+ }
+ }
+}
+
+static void musb_peri_ep0_rx_data_request(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ */
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->rcv_urb = ep0_urb;
+ ep0_urb->actual_length = 0;
+ SET_EP0_STATE(RX);
+}
+
+static void musb_peri_ep0_tx_data_request(int err)
+{
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->tx_urb = ep0_urb;
+ ep0_endpoint->sent = 0;
+ SET_EP0_STATE(TX);
+ }
+}
+
+static void musb_peri_ep0_idle(void)
+{
+ u16 count0;
+ int err;
+ u16 csr0;
+
+ /*
+ * Verify addresses
+ * A lot of confusion can be caused if the address
+ * in software, udc layer, does not agree with the
+ * hardware. Since the setting of the hardware address
+ * must be set after the set address request, the
+ * usb state machine is out of sync for a few frame.
+ * It is a good idea to run this check when changes
+ * are made to the state machine.
+ */
+ if ((debug_level > 0) &&
+ (ep0_state != SET_ADDRESS)) {
+ u8 faddr;
+
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address != faddr) {
+ serial_printf("ERROR : %s addresses do not"
+ "match sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ udelay(1000 * 1000);
+ hang();
+ }
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ goto end;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+ if (count0 == 0)
+ goto end;
+
+ if (count0 != 8) {
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN : %s SETUP incorrect size %d\n",
+ __PRETTY_FUNCTION__, count0);
+ musb_peri_ep0_stall();
+ goto end;
+ }
+
+ read_fifo(0, count0, &ep0_urb->device_request);
+
+ if (debug_level > 2)
+ print_usb_device_request(&ep0_urb->device_request);
+
+ if (ep0_urb->device_request.wLength == 0) {
+ err = ep0_recv_setup(ep0_urb);
+
+ /* Zero data request */
+ musb_peri_ep0_zero_data_request(err);
+ } else {
+ /* Is data coming or going ? */
+ u8 reqType = ep0_urb->device_request.bmRequestType;
+
+ if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
+ err = ep0_recv_setup(ep0_urb);
+ /* Device to host */
+ musb_peri_ep0_tx_data_request(err);
+ } else {
+ /*
+ * Host to device
+ *
+ * The RX routine will call ep0_recv_setup
+ * when the data packet has arrived.
+ */
+ musb_peri_ep0_rx_data_request();
+ }
+ }
+
+end:
+ return;
+}
+
+static void musb_peri_ep0_rx(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ * Pass the data back to driver ep0_recv_setup which
+ * should give the cdc_recv_setup the chance to handle
+ * the rx
+ */
+ u16 csr0;
+ u16 count0;
+
+ if (debug_level > 3) {
+ if (0 != ep0_urb->actual_length) {
+ serial_printf("%s finished ? %d of %d\n",
+ __PRETTY_FUNCTION__,
+ ep0_urb->actual_length,
+ ep0_urb->device_request.wLength);
+ }
+ }
+
+ if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
+ musb_peri_ep0_last();
+ SET_EP0_STATE(IDLE);
+ ep0_recv_setup(ep0_urb);
+ return;
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ return;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+
+ if (count0) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = ep0_endpoint;
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (count0 > remaining_space)
+ length = remaining_space;
+ else
+ length = count0;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(0, length, data);
+
+ musb_peri_ep0_ack_req();
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s no space in "
+ "rcv buffer\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s with nothing to do\n",
+ __PRETTY_FUNCTION__);
+ }
+}
+
+static void musb_peri_ep0_tx(void)
+{
+ u16 csr0;
+ int transfer_size = 0;
+ unsigned int p, pm;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Check for pending tx */
+ if (csr0 & MUSB_CSR0_TXPKTRDY)
+ goto end;
+
+ /* Check if this is the last packet sent */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length) {
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
+ /* Is the transfer size negative ? */
+ if (transfer_size <= 0) {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with the"
+ " transfer size %d\n",
+ __PRETTY_FUNCTION__,
+ transfer_size);
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ /* Truncate large transfers to the fifo size */
+ if (transfer_size > ep0_endpoint->tx_packetSize)
+ transfer_size = ep0_endpoint->tx_packetSize;
+
+ write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
+ ep0_endpoint->sent += transfer_size;
+
+ /* Done or more to send ? */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length)
+ musb_ep0_tx_ready_and_last();
+ else
+ musb_ep0_tx_ready();
+
+ /* Wait a bit */
+ pm = 10;
+ for (p = 0; p < pm; p++) {
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(csr0 & MUSB_CSR0_TXPKTRDY))
+ break;
+
+ /* Double the delay. */
+ udelay(1 << pm);
+ }
+
+ if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
+ SET_EP0_STATE(IDLE);
+
+end:
+ return;
+}
+
+static void musb_peri_ep0(void)
+{
+ u16 csr0;
+
+ if (SET_ADDRESS == ep0_state)
+ return;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Error conditions */
+ if (MUSB_CSR0_P_SENTSTALL & csr0) {
+ csr0 &= ~MUSB_CSR0_P_SENTSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ }
+ if (MUSB_CSR0_P_SETUPEND & csr0) {
+ csr0 |= MUSB_CSR0_P_SVDSETUPEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN: %s SETUPEND\n",
+ __PRETTY_FUNCTION__);
+ }
+
+ /* Normal states */
+ if (IDLE == ep0_state)
+ musb_peri_ep0_idle();
+
+ if (TX == ep0_state)
+ musb_peri_ep0_tx();
+
+ if (RX == ep0_state)
+ musb_peri_ep0_rx();
+}
+
+static void musb_peri_rx_ep(unsigned int ep)
+{
+ u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
+
+ if (peri_rxcount) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = GET_ENDPOINT(udc_device, ep);
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (peri_rxcount > remaining_space)
+ length = remaining_space;
+ else
+ length = peri_rxcount;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(ep, length, data);
+
+ musb_peri_rx_ack(ep);
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d no space "
+ "in rcv buffer\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d with nothing to do\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+}
+
+static void musb_peri_rx(u16 intr)
+{
+ unsigned int ep;
+
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0();
+
+ for (ep = 1; ep < 16; ep++) {
+ if ((1 << ep) & intr)
+ musb_peri_rx_ep(ep);
+ }
+}
+
+static void musb_peri_tx(u16 intr)
+{
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0_tx();
+
+ /*
+ * Use this in the future when handling epN tx
+ *
+ * u8 ep;
+ *
+ * for (ep = 1; ep < 16; ep++) {
+ * if ((1 << ep) & intr) {
+ * / * handle tx for this endpoint * /
+ * }
+ * }
+ */
+}
+
+void udc_irq(void)
+{
+ /* This is a high freq called function */
+ if (enabled) {
+ u8 intrusb;
+
+ intrusb = readb(&musbr->intrusb);
+
+ /*
+ * See drivers/usb/gadget/mpc8xx_udc.c for
+ * state diagram going from detached through
+ * configuration.
+ */
+ if (MUSB_INTR_RESUME & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ musb_peri_ep0();
+
+ if (MUSB_INTR_RESET & intrusb) {
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ }
+
+ if (MUSB_INTR_DISCONNECT & intrusb) {
+ /* cable unplugged from hub/host */
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+ }
+
+ if (MUSB_INTR_SOF & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ if (MUSB_INTR_SUSPEND & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_INACTIVE, 0);
+ }
+
+ if (ep0_state != SET_ADDRESS) {
+ u16 intrrx, intrtx;
+
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ if (intrrx)
+ musb_peri_rx(intrrx);
+
+ if (intrtx)
+ musb_peri_tx(intrtx);
+ } else {
+ if (MUSB_INTR_SOF & intrusb) {
+ u8 faddr;
+ faddr = readb(&musbr->faddr);
+ /*
+ * Setting of the address can fail.
+ * Normally it succeeds the second time.
+ */
+ if (udc_device->address != faddr)
+ musb_peri_ep0_set_address();
+ }
+ }
+ }
+}
+
+void udc_set_nak(int ep_num)
+{
+ /* noop */
+}
+
+void udc_unset_nak(int ep_num)
+{
+ /* noop */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+ int ret = 0;
+
+ /* Transmit only if the hardware is available */
+ if (endpoint->tx_urb && endpoint->state == 0) {
+ unsigned int ep = endpoint->endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK;
+
+ u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+
+ /* Error conditions */
+ if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
+ peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+ }
+
+ if (debug_level > 1)
+ musb_print_txcsr(peri_txcsr);
+
+ /* Check if a packet is waiting to be sent */
+ if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
+ u32 length;
+ u8 *data;
+ struct urb *urb = endpoint->tx_urb;
+ unsigned int remaining_packet = urb->actual_length -
+ endpoint->sent;
+
+ if (endpoint->tx_packetSize < remaining_packet)
+ length = endpoint->tx_packetSize;
+ else
+ length = remaining_packet;
+
+ data = (u8 *) urb->buffer;
+ data += endpoint->sent;
+
+ /* common musb fifo function */
+ write_fifo(ep, length, data);
+
+ musb_peri_tx_ready(ep);
+
+ endpoint->last = length;
+ /* usbd_tx_complete will take care of updating 'sent' */
+ usbd_tx_complete(endpoint);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Problem with urb %p "
+ "or ep state %d\n",
+ __PRETTY_FUNCTION__,
+ endpoint->tx_urb, endpoint->state);
+ }
+
+ return ret;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint)
+{
+ if (0 == id) {
+ /* EP0 */
+ ep0_endpoint = endpoint;
+ ep0_endpoint->endpoint_address = 0xff;
+ ep0_urb = usbd_alloc_urb(device, endpoint);
+ } else if (MAX_ENDPOINT >= id) {
+ int ep_addr;
+
+ /* Check the direction */
+ ep_addr = endpoint->endpoint_address;
+ if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) {
+ /* IN */
+ epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
+ } else {
+ /* OUT */
+ epinfo[id * 2].epsize = endpoint->rcv_packetSize;
+ }
+
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s endpoint request %d "
+ "exceeds maximum %d\n",
+ __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
+ }
+}
+
+void udc_connect(void)
+{
+ /* noop */
+}
+
+void udc_disconnect(void)
+{
+ /* noop */
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ enabled = 1;
+}
+
+void udc_disable(void)
+{
+ enabled = 0;
+}
+
+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);
+
+ /* Resets the address to 0 */
+ usbd_device_event_irq(device, DEVICE_RESET, 0);
+
+ udc_enable(device);
+}
+
+int udc_init(void)
+{
+ int ret;
+ int ep_loop;
+
+ ret = musb_platform_init();
+ if (ret < 0)
+ goto end;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+
+ /* Initialize the endpoints */
+ for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) {
+ epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
+ epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
+ epinfo[ep_loop].epsize = 0;
+ }
+
+ musb_peri_softconnect();
+
+ ret = 0;
+end:
+
+ return ret;
+}
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
new file mode 100644
index 0000000..3e502e7
--- /dev/null
+++ b/drivers/usb/musb/omap3.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2009 Texas Instruments
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 <twl4030.h>
+#include "omap3.h"
+
+static int platform_needs_initialization = 1;
+
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ OMAP3_USB_TIMEOUT,
+ 0
+};
+
+/*
+ * OMAP3 USB OTG registers.
+ */
+struct omap3_otg_regs {
+ u32 revision;
+ u32 sysconfig;
+ u32 sysstatus;
+ u32 interfsel;
+ u32 simenable;
+ u32 forcestdby;
+};
+
+static struct omap3_otg_regs *otg;
+
+#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000
+#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000
+#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010
+#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008
+#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004
+#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002
+#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001
+
+#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
+
+#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
+
+#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001
+
+
+#ifdef DEBUG_MUSB_OMAP3
+static void musb_db_otg_regs(void)
+{
+ u32 l;
+ l = readl(&otg->revision);
+ serial_printf("OTG_REVISION 0x%x\n", l);
+ l = readl(&otg->sysconfig);
+ serial_printf("OTG_SYSCONFIG 0x%x\n", l);
+ l = readl(&otg->sysstatus);
+ serial_printf("OTG_SYSSTATUS 0x%x\n", l);
+ l = readl(&otg->interfsel);
+ serial_printf("OTG_INTERFSEL 0x%x\n", l);
+ l = readl(&otg->forcestdby);
+ serial_printf("OTG_FORCESTDBY 0x%x\n", l);
+}
+#endif
+
+int musb_platform_init(void)
+{
+ int ret = -1;
+
+ if (platform_needs_initialization) {
+ u32 stdby;
+
+ if (twl4030_usb_ulpi_init()) {
+ serial_printf("ERROR: %s Could not initialize PHY\n",
+ __PRETTY_FUNCTION__);
+ goto end;
+ }
+
+ otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
+
+ /* Set OTG to always be on */
+ writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
+ OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
+
+ /* Set the interface */
+ writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
+
+ /* Clear force standby */
+ stdby = readl(&otg->forcestdby);
+ stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
+ writel(stdby, &otg->forcestdby);
+
+ platform_needs_initialization = 0;
+ }
+
+ ret = platform_needs_initialization;
+end:
+ return ret;
+
+}
+
+void musb_platform_deinit(void)
+{
+ /* noop */
+}
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
new file mode 100644
index 0000000..20fc9d2
--- /dev/null
+++ b/drivers/usb/musb/omap3.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is based on the file drivers/usb/musb/davinci.h
+ *
+ * This is the unique part of its copyright:
+ *
+ * --------------------------------------------------------------------
+ *
+ * Copyright (c) 2008 Texas Instruments
+ * Author: Thomas Abraham t-abraham at ti.com, Texas Instruments
+ *
+ * --------------------------------------------------------------------
+ *
+ * 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 _MUSB_OMAP3_H_
+#define _MUSB_OMAP3_H_
+
+#include "musb_core.h"
+
+/* Base address of MUSB registers */
+#define MENTOR_USB0_BASE (OMAP34XX_CORE_L4_IO_BASE + 0xAB000)
+
+/* Base address of OTG registers */
+#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
+
+/* Timeout for USB module */
+#define OMAP3_USB_TIMEOUT 0x3FFFFFF
+
+int musb_platform_init(void);
+
+#endif /* _MUSB_OMAP3_H */
+
diff --git a/include/usb.h b/include/usb.h
index 378a23b..198d5bb 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -131,7 +131,8 @@ struct usb_device {
#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
- defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
+ defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
+ defined(CONFIG_USB_OMAP3)
int usb_lowlevel_init(void);
int usb_lowlevel_stop(void);
diff --git a/include/usb/musb_udc.h b/include/usb/musb_udc.h
new file mode 100644
index 0000000..ef37dbb
--- /dev/null
+++ b/include/usb/musb_udc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.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
+ */
+#ifndef __MUSB_UDC_H__
+#define __MUSB_UDC_H__
+
+#include <usbdevice.h>
+
+/* UDC level routines */
+void udc_irq(void);
+void udc_set_nak(int ep_num);
+void udc_unset_nak(int ep_num);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint);
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+void udc_startup_events(struct usb_device_instance *device);
+int udc_init(void);
+
+/* usbtty */
+#ifdef CONFIG_USB_TTY
+
+#define EP0_MAX_PACKET_SIZE 64 /* MUSB_EP0_FIFOSIZE */
+#define UDC_INT_ENDPOINT 1
+#define UDC_INT_PACKET_SIZE 64
+#define UDC_OUT_ENDPOINT 2
+#define UDC_OUT_PACKET_SIZE 64
+#define UDC_IN_ENDPOINT 3
+#define UDC_IN_PACKET_SIZE 64
+#define UDC_BULK_PACKET_SIZE 64
+
+#endif /* CONFIG_USB_TTY */
+
+#endif /* __MUSB_UDC_H__ */
+
--
1.6.0.6
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-09-28 16:37 ` [U-Boot] [PATCH 3/8] TWL4030 Add usb PHY support Tom Rix
@ 2009-09-28 16:37 ` Tom Rix
0 siblings, 0 replies; 9+ messages in thread
From: Tom Rix @ 2009-09-28 16:37 UTC (permalink / raw)
To: u-boot
This change adds the usb device support for musb.
Omap3 platform support added at the same level as davinci.
The interface for usbtty to use the musb device support was added.
Verified on omap3 beagle, zoom1 and zoom2.
Signed-off-by: Tom Rix <Tom.Rix@windriver.com>
---
drivers/serial/usbtty.h | 2 +
drivers/usb/musb/Makefile | 2 +
drivers/usb/musb/musb_core.c | 8 +-
drivers/usb/musb/musb_core.h | 40 ++
drivers/usb/musb/musb_debug.h | 205 +++++++++
drivers/usb/musb/musb_udc.c | 963 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/musb/omap3.c | 129 ++++++
drivers/usb/musb/omap3.h | 48 ++
include/usb.h | 3 +-
include/usb/musb_udc.h | 54 +++
10 files changed, 1451 insertions(+), 3 deletions(-)
create mode 100644 drivers/usb/musb/musb_debug.h
create mode 100644 drivers/usb/musb/musb_udc.c
create mode 100644 drivers/usb/musb/omap3.c
create mode 100644 drivers/usb/musb/omap3.h
create mode 100644 include/usb/musb_udc.h
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index f746d63..6b6c4a1 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -29,6 +29,8 @@
#include <usb/mpc8xx_udc.h>
#elif defined(CONFIG_OMAP1510)
#include <usb/omap1510_udc.h>
+#elif defined(CONFIG_MUSB_UDC)
+#include <usb/musb_udc.h>
#elif defined(CONFIG_PXA27X)
#include <usb/pxa27x_udc.h>
#endif
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 09e0a5f..f2ccd9f 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_musb.a
COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o
COBJS-$(CONFIG_USB_DAVINCI) += davinci.o
+COBJS-$(CONFIG_USB_OMAP3) += omap3.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ec57fc8..22f3dba 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -32,7 +32,9 @@ struct musb_regs *musbr;
*/
void musb_start(void)
{
+#if defined(CONFIG_MUSB_HCD)
u8 devctl;
+#endif
/* disable all interrupts */
writew(0, &musbr->intrtxe);
@@ -74,9 +76,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->txfifosz);
writew(fifoaddr >> 3, &musbr->txfifoadd);
+
+ csr = readw(&musbr->txcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->txcsr);
writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
#endif
/* Flush fifo if required */
@@ -87,9 +90,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
/* Configure fifo size and fifo base address */
writeb(idx, &musbr->rxfifosz);
writew(fifoaddr >> 3, &musbr->rxfifoadd);
+
+ csr = readw(&musbr->rxcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->rxcsr);
writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
#endif
/* Flush fifo if required */
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f9da3f0..15c7f49 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -40,6 +40,36 @@
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+/* EP0 */
+struct musb_ep0_regs {
+ u16 reserved4;
+ u16 csr0;
+ u16 reserved5;
+ u16 reserved6;
+ u16 count0;
+ u8 host_type0;
+ u8 host_naklimit0;
+ u8 reserved7;
+ u8 reserved8;
+ u8 reserved9;
+ u8 configdata;
+};
+
+/* EP 1-15 */
+struct musb_epN_regs {
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+};
+
/* Mentor USB core register overlay structure */
struct musb_regs {
/* common registers */
@@ -97,6 +127,16 @@ struct musb_regs {
u8 rxhubaddr;
u8 rxhubport;
} tar[16];
+ /*
+ * end point registers
+ * ep0 elements are valid when array index is 0
+ * otherwise epN is valid
+ */
+ union musb_ep_regs {
+ struct musb_ep0_regs ep0;
+ struct musb_epN_regs epN;
+ } ep[16];
+
} __attribute__((aligned(32)));
/*
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
new file mode 100644
index 0000000..62380ff
--- /dev/null
+++ b/drivers/usb/musb/musb_debug.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.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
+ */
+
+/* Define MUSB_DEBUG before including this file to get debug macros */
+#ifdef MUSB_DEBUG
+
+#define MUSB_FLAGS_PRINT(v, x, y) \
+ if (((v) & MUSB_##x##_##y)) \
+ serial_printf("\t\t"#y"\n")
+
+static inline void musb_print_pwr(u8 b)
+{
+ serial_printf("\tpower 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE);
+ MUSB_FLAGS_PRINT(b, POWER, SOFTCONN);
+ MUSB_FLAGS_PRINT(b, POWER, HSENAB);
+ MUSB_FLAGS_PRINT(b, POWER, HSMODE);
+ MUSB_FLAGS_PRINT(b, POWER, RESET);
+ MUSB_FLAGS_PRINT(b, POWER, RESUME);
+ MUSB_FLAGS_PRINT(b, POWER, SUSPENDM);
+ MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND);
+}
+
+static inline void musb_print_csr0(u16 w)
+{
+ serial_printf("\tcsr0 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY);
+}
+
+static inline void musb_print_intrusb(u8 b)
+{
+ serial_printf("\tintrusb 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, INTR, VBUSERROR);
+ MUSB_FLAGS_PRINT(b, INTR, SESSREQ);
+ MUSB_FLAGS_PRINT(b, INTR, DISCONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, CONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, SOF);
+ MUSB_FLAGS_PRINT(b, INTR, RESUME);
+ MUSB_FLAGS_PRINT(b, INTR, SUSPEND);
+
+ if (b & MUSB_INTR_BABBLE)
+ serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
+
+}
+
+static inline void musb_print_intrtx(u16 w)
+{
+ serial_printf("\tintrtx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_intrrx(u16 w)
+{
+ serial_printf("\tintrx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_devctl(u8 b)
+{
+ serial_printf("\tdevctl 0x%2.2x\n", b);
+ if (b & MUSB_DEVCTL_BDEVICE)
+ serial_printf("\t\tB device\n");
+ else
+ serial_printf("\t\tA device\n");
+ if (b & MUSB_DEVCTL_FSDEV)
+ serial_printf("\t\tFast Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_LSDEV)
+ serial_printf("\t\tSlow Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_HM)
+ serial_printf("\t\tHost mode\n");
+ else
+ serial_printf("\t\tPeripherial mode\n");
+ if (b & MUSB_DEVCTL_HR)
+ serial_printf("\t\tHost request started(B device)\n");
+ else
+ serial_printf("\t\tHost request finished(B device)\n");
+ if (b & MUSB_DEVCTL_BDEVICE) {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(B device)\n");
+ else
+ serial_printf("\t\tEnd of session(B device)\n");
+ } else {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(A device)\n");
+ else
+ serial_printf("\t\tEnd of session(A device)\n");
+ }
+}
+
+static inline void musb_print_config(u8 b)
+{
+ serial_printf("\tconfig 0x%2.2x\n", b);
+ if (b & MUSB_CONFIGDATA_MPRXE)
+ serial_printf("\t\tAuto combine rx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_MPTXE)
+ serial_printf("\t\tAuto split tx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_BIGENDIAN)
+ serial_printf("\t\tBig Endian ordering\n");
+ else
+ serial_printf("\t\tLittle Endian ordering\n");
+ if (b & MUSB_CONFIGDATA_HBRXE)
+ serial_printf("\t\tHigh speed rx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_HBTXE)
+ serial_printf("\t\tHigh speed tx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_DYNFIFO)
+ serial_printf("\t\tDynamic fifo sizing\n");
+ if (b & MUSB_CONFIGDATA_SOFTCONE)
+ serial_printf("\t\tSoft Connect\n");
+ if (b & MUSB_CONFIGDATA_UTMIDW)
+ serial_printf("\t\t16 bit data width\n");
+ else
+ serial_printf("\t\t8 bit data width\n");
+}
+
+static inline void musb_print_rxmaxp(u16 w)
+{
+ serial_printf("\trxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_rxcsr(u16 w)
+{
+ serial_printf("\trxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB);
+ MUSB_FLAGS_PRINT(w, RXCSR, DISNYET);
+ MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE);
+ MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR);
+ MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL);
+ MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN);
+
+ if (w & MUSB_RXCSR_P_ISO)
+ serial_printf("\t\tiso mode\n");
+ else
+ serial_printf("\t\tbulk mode\n");
+
+}
+
+static inline void musb_print_txmaxp(u16 w)
+{
+ serial_printf("\ttxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_txcsr(u16 w)
+{
+ serial_printf("\ttxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL);
+
+ if (w & MUSB_TXCSR_MODE)
+ serial_printf("\t\tTX mode\n");
+ else
+ serial_printf("\t\tRX mode\n");
+}
+
+#else
+
+/* stubs */
+
+#define musb_print_pwr(b)
+#define musb_print_csr0(w)
+#define musb_print_intrusb(b)
+#define musb_print_intrtx(w)
+#define musb_print_intrrx(w)
+#define musb_print_devctl(b)
+#define musb_print_config(b)
+#define musb_print_rxmaxp(w)
+#define musb_print_rxcsr(w)
+#define musb_print_txmaxp(w)
+#define musb_print_txcsr(w)
+
+#endif /* MUSB_DEBUG */
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
new file mode 100644
index 0000000..fc43cf4
--- /dev/null
+++ b/drivers/usb/musb/musb_udc.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is a rewrite of the usb device part of
+ * repository git.omapzoom.org/repo/u-boot.git, branch master,
+ * file cpu/omap3/fastboot.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * -------------------------------------------------------------------------
+ *
+ * The details of connecting the device to the uboot usb device subsystem
+ * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
+ * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 Texas Instruments Incorporated.
+ *
+ * Based on
+ * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
+ * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
+ *
+ * Author: Diego Dompe (diego.dompe at ridgerun.com)
+ * Atin Malaviya (atin.malaviya at gmail.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 <usb/musb_udc.h>
+#include "../gadget/ep0.h"
+#include "musb_core.h"
+#if defined(CONFIG_USB_OMAP3)
+#include "omap3.h"
+#elif defined(CONFIG_USB_DAVINCI)
+#include "davinci.h"
+#endif
+
+/* Define MUSB_DEBUG for debugging */
+/* #define MUSB_DEBUG */
+#include "musb_debug.h"
+
+#define MAX_ENDPOINT 15
+
+#define GET_ENDPOINT(dev,ep) \
+(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
+
+#define SET_EP0_STATE(s) \
+do { \
+ if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
+ if ((s) != ep0_state) { \
+ if ((debug_setup) && (debug_level > 1)) \
+ serial_printf("INFO : Changing state " \
+ "from %s to %s in %s at " \
+ "line %d\n", \
+ ep0_state_strings[ep0_state],\
+ ep0_state_strings[s], \
+ __PRETTY_FUNCTION__, \
+ __LINE__); \
+ ep0_state = s; \
+ } \
+ } else { \
+ if (debug_level > 0) \
+ serial_printf("Error at %s %d with setting " \
+ "state %d is invalid\n", \
+ __PRETTY_FUNCTION__, __LINE__, s); \
+ } \
+} while (0)
+
+/* static implies these initialized to 0 or NULL */
+static int debug_setup;
+static int debug_level;
+static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
+static enum ep0_state_enum {
+ IDLE = 0,
+ TX,
+ RX,
+ SET_ADDRESS
+} ep0_state = IDLE;
+static char *ep0_state_strings[4] = {
+ "IDLE",
+ "TX",
+ "RX",
+ "SET_ADDRESS",
+};
+
+static struct urb *ep0_urb;
+struct usb_endpoint_instance *ep0_endpoint;
+static struct usb_device_instance *udc_device;
+static int enabled;
+
+#ifdef MUSB_DEBUG
+static void musb_db_regs(void)
+{
+ u8 b;
+ u16 w;
+
+ b = readb(&musbr->faddr);
+ serial_printf("\tfaddr 0x%2.2x\n", b);
+
+ b = readb(&musbr->power);
+ musb_print_pwr(b);
+
+ w = readw(&musbr->ep[0].ep0.csr0);
+ musb_print_csr0(w);
+
+ b = readb(&musbr->devctl);
+ musb_print_devctl(b);
+
+ b = readb(&musbr->ep[0].ep0.configdata);
+ musb_print_config(b);
+
+ w = readw(&musbr->frame);
+ serial_printf("\tframe 0x%4.4x\n", w);
+
+ b = readb(&musbr->index);
+ serial_printf("\tindex 0x%2.2x\n", b);
+
+ w = readw(&musbr->ep[1].epN.rxmaxp);
+ musb_print_rxmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.rxcsr);
+ musb_print_rxcsr(w);
+
+ w = readw(&musbr->ep[1].epN.txmaxp);
+ musb_print_txmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.txcsr);
+ musb_print_txcsr(w);
+}
+#else
+#define musb_db_regs()
+#endif /* DEBUG_MUSB */
+
+static void musb_peri_softconnect(void)
+{
+ u8 power, devctl;
+ u8 intrusb;
+ u16 intrrx, intrtx;
+
+ /* Power off MUSB */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_SOFTCONN;
+ writeb(power, &musbr->power);
+
+ /* Read intr to clear */
+ intrusb = readb(&musbr->intrusb);
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ udelay(1000 * 1000); /* 1 sec */
+
+ /* Power on MUSB */
+ power = readb(&musbr->power);
+ power |= MUSB_POWER_SOFTCONN;
+ /*
+ * The usb device interface is usb 1.1
+ * Disable 2.0 high speed by clearring the hsenable bit.
+ */
+ power &= ~MUSB_POWER_HSENAB;
+ writeb(power, &musbr->power);
+
+ /* Check if device is in b-peripheral mode */
+ devctl = readb(&musbr->devctl);
+ if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
+ (devctl & MUSB_DEVCTL_HM)) {
+ serial_printf("ERROR : Unsupport USB mode\n");
+ serial_printf("Check that mini-B USB cable is attached "
+ "to the device\n");
+ }
+
+ if (debug_setup && (debug_level > 1))
+ musb_db_regs();
+}
+
+static void musb_peri_reset(void)
+{
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
+
+ if (ep0_endpoint)
+ ep0_endpoint->endpoint_address = 0xff;
+
+ /* Sync sw and hw addresses */
+ writeb(udc_device->address, &musbr->faddr);
+
+ SET_EP0_STATE(IDLE);
+}
+
+static void musb_peri_resume(void)
+{
+ /* noop */
+}
+
+static void musb_peri_ep0_stall(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SENDSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
+}
+
+static void musb_peri_ep0_ack_req(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_TXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready_and_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_DATAEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_set_address(void)
+{
+ u8 faddr;
+ writeb(udc_device->address, &musbr->faddr);
+
+ /* Verify */
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address == faddr) {
+ SET_EP0_STATE(IDLE);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Address set to %d\n",
+ __PRETTY_FUNCTION__, udc_device->address);
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Address missmatch "
+ "sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ }
+}
+
+static void musb_peri_rx_ack(unsigned int ep)
+{
+ u16 peri_rxcsr;
+
+ peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+ peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
+}
+
+static void musb_peri_tx_ready(unsigned int ep)
+{
+ u16 peri_txcsr;
+
+ peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+ peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+}
+
+static void musb_peri_ep0_zero_data_request(int err)
+{
+ musb_peri_ep0_ack_req();
+
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+
+ musb_peri_ep0_last();
+
+ /* USBD state */
+ switch (ep0_urb->device_request.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s received set "
+ "address\n", __PRETTY_FUNCTION__);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Configured\n",
+ __PRETTY_FUNCTION__);
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ break;
+ }
+
+ /* EP0 state */
+ if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
+ SET_EP0_STATE(SET_ADDRESS);
+ } else {
+ SET_EP0_STATE(IDLE);
+ }
+ }
+}
+
+static void musb_peri_ep0_rx_data_request(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ */
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->rcv_urb = ep0_urb;
+ ep0_urb->actual_length = 0;
+ SET_EP0_STATE(RX);
+}
+
+static void musb_peri_ep0_tx_data_request(int err)
+{
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->tx_urb = ep0_urb;
+ ep0_endpoint->sent = 0;
+ SET_EP0_STATE(TX);
+ }
+}
+
+static void musb_peri_ep0_idle(void)
+{
+ u16 count0;
+ int err;
+ u16 csr0;
+
+ /*
+ * Verify addresses
+ * A lot of confusion can be caused if the address
+ * in software, udc layer, does not agree with the
+ * hardware. Since the setting of the hardware address
+ * must be set after the set address request, the
+ * usb state machine is out of sync for a few frame.
+ * It is a good idea to run this check when changes
+ * are made to the state machine.
+ */
+ if ((debug_level > 0) &&
+ (ep0_state != SET_ADDRESS)) {
+ u8 faddr;
+
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address != faddr) {
+ serial_printf("ERROR : %s addresses do not"
+ "match sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ udelay(1000 * 1000);
+ hang();
+ }
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ goto end;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+ if (count0 == 0)
+ goto end;
+
+ if (count0 != 8) {
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN : %s SETUP incorrect size %d\n",
+ __PRETTY_FUNCTION__, count0);
+ musb_peri_ep0_stall();
+ goto end;
+ }
+
+ read_fifo(0, count0, &ep0_urb->device_request);
+
+ if (debug_level > 2)
+ print_usb_device_request(&ep0_urb->device_request);
+
+ if (ep0_urb->device_request.wLength == 0) {
+ err = ep0_recv_setup(ep0_urb);
+
+ /* Zero data request */
+ musb_peri_ep0_zero_data_request(err);
+ } else {
+ /* Is data coming or going ? */
+ u8 reqType = ep0_urb->device_request.bmRequestType;
+
+ if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
+ err = ep0_recv_setup(ep0_urb);
+ /* Device to host */
+ musb_peri_ep0_tx_data_request(err);
+ } else {
+ /*
+ * Host to device
+ *
+ * The RX routine will call ep0_recv_setup
+ * when the data packet has arrived.
+ */
+ musb_peri_ep0_rx_data_request();
+ }
+ }
+
+end:
+ return;
+}
+
+static void musb_peri_ep0_rx(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ * Pass the data back to driver ep0_recv_setup which
+ * should give the cdc_recv_setup the chance to handle
+ * the rx
+ */
+ u16 csr0;
+ u16 count0;
+
+ if (debug_level > 3) {
+ if (0 != ep0_urb->actual_length) {
+ serial_printf("%s finished ? %d of %d\n",
+ __PRETTY_FUNCTION__,
+ ep0_urb->actual_length,
+ ep0_urb->device_request.wLength);
+ }
+ }
+
+ if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
+ musb_peri_ep0_last();
+ SET_EP0_STATE(IDLE);
+ ep0_recv_setup(ep0_urb);
+ return;
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ return;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+
+ if (count0) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = ep0_endpoint;
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (count0 > remaining_space)
+ length = remaining_space;
+ else
+ length = count0;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(0, length, data);
+
+ musb_peri_ep0_ack_req();
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s no space in "
+ "rcv buffer\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s with nothing to do\n",
+ __PRETTY_FUNCTION__);
+ }
+}
+
+static void musb_peri_ep0_tx(void)
+{
+ u16 csr0;
+ int transfer_size = 0;
+ unsigned int p, pm;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Check for pending tx */
+ if (csr0 & MUSB_CSR0_TXPKTRDY)
+ goto end;
+
+ /* Check if this is the last packet sent */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length) {
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
+ /* Is the transfer size negative ? */
+ if (transfer_size <= 0) {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with the"
+ " transfer size %d\n",
+ __PRETTY_FUNCTION__,
+ transfer_size);
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ /* Truncate large transfers to the fifo size */
+ if (transfer_size > ep0_endpoint->tx_packetSize)
+ transfer_size = ep0_endpoint->tx_packetSize;
+
+ write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
+ ep0_endpoint->sent += transfer_size;
+
+ /* Done or more to send ? */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length)
+ musb_ep0_tx_ready_and_last();
+ else
+ musb_ep0_tx_ready();
+
+ /* Wait a bit */
+ pm = 10;
+ for (p = 0; p < pm; p++) {
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(csr0 & MUSB_CSR0_TXPKTRDY))
+ break;
+
+ /* Double the delay. */
+ udelay(1 << pm);
+ }
+
+ if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
+ SET_EP0_STATE(IDLE);
+
+end:
+ return;
+}
+
+static void musb_peri_ep0(void)
+{
+ u16 csr0;
+
+ if (SET_ADDRESS == ep0_state)
+ return;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Error conditions */
+ if (MUSB_CSR0_P_SENTSTALL & csr0) {
+ csr0 &= ~MUSB_CSR0_P_SENTSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ }
+ if (MUSB_CSR0_P_SETUPEND & csr0) {
+ csr0 |= MUSB_CSR0_P_SVDSETUPEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN: %s SETUPEND\n",
+ __PRETTY_FUNCTION__);
+ }
+
+ /* Normal states */
+ if (IDLE == ep0_state)
+ musb_peri_ep0_idle();
+
+ if (TX == ep0_state)
+ musb_peri_ep0_tx();
+
+ if (RX == ep0_state)
+ musb_peri_ep0_rx();
+}
+
+static void musb_peri_rx_ep(unsigned int ep)
+{
+ u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
+
+ if (peri_rxcount) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = GET_ENDPOINT(udc_device, ep);
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (peri_rxcount > remaining_space)
+ length = remaining_space;
+ else
+ length = peri_rxcount;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(ep, length, data);
+
+ musb_peri_rx_ack(ep);
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d no space "
+ "in rcv buffer\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d with nothing to do\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+}
+
+static void musb_peri_rx(u16 intr)
+{
+ unsigned int ep;
+
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0();
+
+ for (ep = 1; ep < 16; ep++) {
+ if ((1 << ep) & intr)
+ musb_peri_rx_ep(ep);
+ }
+}
+
+static void musb_peri_tx(u16 intr)
+{
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0_tx();
+
+ /*
+ * Use this in the future when handling epN tx
+ *
+ * u8 ep;
+ *
+ * for (ep = 1; ep < 16; ep++) {
+ * if ((1 << ep) & intr) {
+ * / * handle tx for this endpoint * /
+ * }
+ * }
+ */
+}
+
+void udc_irq(void)
+{
+ /* This is a high freq called function */
+ if (enabled) {
+ u8 intrusb;
+
+ intrusb = readb(&musbr->intrusb);
+
+ /*
+ * See drivers/usb/gadget/mpc8xx_udc.c for
+ * state diagram going from detached through
+ * configuration.
+ */
+ if (MUSB_INTR_RESUME & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ musb_peri_ep0();
+
+ if (MUSB_INTR_RESET & intrusb) {
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ }
+
+ if (MUSB_INTR_DISCONNECT & intrusb) {
+ /* cable unplugged from hub/host */
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+ }
+
+ if (MUSB_INTR_SOF & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ if (MUSB_INTR_SUSPEND & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_INACTIVE, 0);
+ }
+
+ if (ep0_state != SET_ADDRESS) {
+ u16 intrrx, intrtx;
+
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ if (intrrx)
+ musb_peri_rx(intrrx);
+
+ if (intrtx)
+ musb_peri_tx(intrtx);
+ } else {
+ if (MUSB_INTR_SOF & intrusb) {
+ u8 faddr;
+ faddr = readb(&musbr->faddr);
+ /*
+ * Setting of the address can fail.
+ * Normally it succeeds the second time.
+ */
+ if (udc_device->address != faddr)
+ musb_peri_ep0_set_address();
+ }
+ }
+ }
+}
+
+void udc_set_nak(int ep_num)
+{
+ /* noop */
+}
+
+void udc_unset_nak(int ep_num)
+{
+ /* noop */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+ int ret = 0;
+
+ /* Transmit only if the hardware is available */
+ if (endpoint->tx_urb && endpoint->state == 0) {
+ unsigned int ep = endpoint->endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK;
+
+ u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+
+ /* Error conditions */
+ if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
+ peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+ }
+
+ if (debug_level > 1)
+ musb_print_txcsr(peri_txcsr);
+
+ /* Check if a packet is waiting to be sent */
+ if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
+ u32 length;
+ u8 *data;
+ struct urb *urb = endpoint->tx_urb;
+ unsigned int remaining_packet = urb->actual_length -
+ endpoint->sent;
+
+ if (endpoint->tx_packetSize < remaining_packet)
+ length = endpoint->tx_packetSize;
+ else
+ length = remaining_packet;
+
+ data = (u8 *) urb->buffer;
+ data += endpoint->sent;
+
+ /* common musb fifo function */
+ write_fifo(ep, length, data);
+
+ musb_peri_tx_ready(ep);
+
+ endpoint->last = length;
+ /* usbd_tx_complete will take care of updating 'sent' */
+ usbd_tx_complete(endpoint);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Problem with urb %p "
+ "or ep state %d\n",
+ __PRETTY_FUNCTION__,
+ endpoint->tx_urb, endpoint->state);
+ }
+
+ return ret;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint)
+{
+ if (0 == id) {
+ /* EP0 */
+ ep0_endpoint = endpoint;
+ ep0_endpoint->endpoint_address = 0xff;
+ ep0_urb = usbd_alloc_urb(device, endpoint);
+ } else if (MAX_ENDPOINT >= id) {
+ int ep_addr;
+
+ /* Check the direction */
+ ep_addr = endpoint->endpoint_address;
+ if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) {
+ /* IN */
+ epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
+ } else {
+ /* OUT */
+ epinfo[id * 2].epsize = endpoint->rcv_packetSize;
+ }
+
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s endpoint request %d "
+ "exceeds maximum %d\n",
+ __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
+ }
+}
+
+void udc_connect(void)
+{
+ /* noop */
+}
+
+void udc_disconnect(void)
+{
+ /* noop */
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ enabled = 1;
+}
+
+void udc_disable(void)
+{
+ enabled = 0;
+}
+
+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);
+
+ /* Resets the address to 0 */
+ usbd_device_event_irq(device, DEVICE_RESET, 0);
+
+ udc_enable(device);
+}
+
+int udc_init(void)
+{
+ int ret;
+ int ep_loop;
+
+ ret = musb_platform_init();
+ if (ret < 0)
+ goto end;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+
+ /* Initialize the endpoints */
+ for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) {
+ epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
+ epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
+ epinfo[ep_loop].epsize = 0;
+ }
+
+ musb_peri_softconnect();
+
+ ret = 0;
+end:
+
+ return ret;
+}
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
new file mode 100644
index 0000000..3e502e7
--- /dev/null
+++ b/drivers/usb/musb/omap3.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2009 Texas Instruments
+ *
+ * ------------------------------------------------------------------------
+ *
+ * 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 <twl4030.h>
+#include "omap3.h"
+
+static int platform_needs_initialization = 1;
+
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ OMAP3_USB_TIMEOUT,
+ 0
+};
+
+/*
+ * OMAP3 USB OTG registers.
+ */
+struct omap3_otg_regs {
+ u32 revision;
+ u32 sysconfig;
+ u32 sysstatus;
+ u32 interfsel;
+ u32 simenable;
+ u32 forcestdby;
+};
+
+static struct omap3_otg_regs *otg;
+
+#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000
+#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000
+#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010
+#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008
+#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004
+#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002
+#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001
+
+#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
+
+#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
+
+#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001
+
+
+#ifdef DEBUG_MUSB_OMAP3
+static void musb_db_otg_regs(void)
+{
+ u32 l;
+ l = readl(&otg->revision);
+ serial_printf("OTG_REVISION 0x%x\n", l);
+ l = readl(&otg->sysconfig);
+ serial_printf("OTG_SYSCONFIG 0x%x\n", l);
+ l = readl(&otg->sysstatus);
+ serial_printf("OTG_SYSSTATUS 0x%x\n", l);
+ l = readl(&otg->interfsel);
+ serial_printf("OTG_INTERFSEL 0x%x\n", l);
+ l = readl(&otg->forcestdby);
+ serial_printf("OTG_FORCESTDBY 0x%x\n", l);
+}
+#endif
+
+int musb_platform_init(void)
+{
+ int ret = -1;
+
+ if (platform_needs_initialization) {
+ u32 stdby;
+
+ if (twl4030_usb_ulpi_init()) {
+ serial_printf("ERROR: %s Could not initialize PHY\n",
+ __PRETTY_FUNCTION__);
+ goto end;
+ }
+
+ otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
+
+ /* Set OTG to always be on */
+ writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
+ OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
+
+ /* Set the interface */
+ writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
+
+ /* Clear force standby */
+ stdby = readl(&otg->forcestdby);
+ stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
+ writel(stdby, &otg->forcestdby);
+
+ platform_needs_initialization = 0;
+ }
+
+ ret = platform_needs_initialization;
+end:
+ return ret;
+
+}
+
+void musb_platform_deinit(void)
+{
+ /* noop */
+}
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
new file mode 100644
index 0000000..20fc9d2
--- /dev/null
+++ b/drivers/usb/musb/omap3.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is based on the file drivers/usb/musb/davinci.h
+ *
+ * This is the unique part of its copyright:
+ *
+ * --------------------------------------------------------------------
+ *
+ * Copyright (c) 2008 Texas Instruments
+ * Author: Thomas Abraham t-abraham at ti.com, Texas Instruments
+ *
+ * --------------------------------------------------------------------
+ *
+ * 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 _MUSB_OMAP3_H_
+#define _MUSB_OMAP3_H_
+
+#include "musb_core.h"
+
+/* Base address of MUSB registers */
+#define MENTOR_USB0_BASE (OMAP34XX_CORE_L4_IO_BASE + 0xAB000)
+
+/* Base address of OTG registers */
+#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
+
+/* Timeout for USB module */
+#define OMAP3_USB_TIMEOUT 0x3FFFFFF
+
+int musb_platform_init(void);
+
+#endif /* _MUSB_OMAP3_H */
+
diff --git a/include/usb.h b/include/usb.h
index 378a23b..198d5bb 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -131,7 +131,8 @@ struct usb_device {
#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
- defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
+ defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
+ defined(CONFIG_USB_OMAP3)
int usb_lowlevel_init(void);
int usb_lowlevel_stop(void);
diff --git a/include/usb/musb_udc.h b/include/usb/musb_udc.h
new file mode 100644
index 0000000..ef37dbb
--- /dev/null
+++ b/include/usb/musb_udc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.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
+ */
+#ifndef __MUSB_UDC_H__
+#define __MUSB_UDC_H__
+
+#include <usbdevice.h>
+
+/* UDC level routines */
+void udc_irq(void);
+void udc_set_nak(int ep_num);
+void udc_unset_nak(int ep_num);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint);
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+void udc_startup_events(struct usb_device_instance *device);
+int udc_init(void);
+
+/* usbtty */
+#ifdef CONFIG_USB_TTY
+
+#define EP0_MAX_PACKET_SIZE 64 /* MUSB_EP0_FIFOSIZE */
+#define UDC_INT_ENDPOINT 1
+#define UDC_INT_PACKET_SIZE 64
+#define UDC_OUT_ENDPOINT 2
+#define UDC_OUT_PACKET_SIZE 64
+#define UDC_IN_ENDPOINT 3
+#define UDC_IN_PACKET_SIZE 64
+#define UDC_BULK_PACKET_SIZE 64
+
+#endif /* CONFIG_USB_TTY */
+
+#endif /* __MUSB_UDC_H__ */
+
--
1.6.0.6
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
@ 2009-10-27 5:18 Gupta, Ajay Kumar
2009-10-27 14:04 ` Tom
0 siblings, 1 reply; 9+ messages in thread
From: Gupta, Ajay Kumar @ 2009-10-27 5:18 UTC (permalink / raw)
To: u-boot
Tom,
> From: Tom Rix <Tom.Rix <at> windriver.com>
> Subject: [PATCH 4/8] OMAP3 Add usb device support
> Newsgroups: gmane.comp.boot-loaders.u-boot
> Date: 2009-09-28 16:37:25 GMT (4 weeks, 12 hours and 29 minutes ago)
> This change adds the usb device support for musb.
>
> Omap3 platform support added at the same level as davinci.
>
> The interface for usbtty to use the musb device support was added.
>
> Verified on omap3 beagle, zoom1 and zoom2.
>
> Signed-off-by: Tom Rix <Tom.Rix <at> windriver.com>
> ---
> drivers/serial/usbtty.h?????? |??? 2 +
> drivers/usb/musb/Makefile???? |??? 2 +
> drivers/usb/musb/musb_core.c? |??? 8 +-
> drivers/usb/musb/musb_core.h? |?? 40 ++
> drivers/usb/musb/musb_debug.h |? 205 +++++++++
> drivers/usb/musb/musb_udc.c?? |? 963
> +++++++++++++++++++++++++++++++++++++++++
> drivers/usb/musb/omap3.c????? |? 129 ++++++
> drivers/usb/musb/omap3.h????? |?? 48 ++
> include/usb.h???????????????? |??? 3 +-
> include/usb/musb_udc.h??????? |?? 54 +++
> 10 files changed, 1451 insertions(+), 3 deletions(-)
> create mode 100644 drivers/usb/musb/musb_debug.h
> create mode 100644 drivers/usb/musb/musb_udc.c
> create mode 100644 drivers/usb/musb/omap3.c
> create mode 100644 drivers/usb/musb/omap3.h
> create mode 100644 include/usb/musb_udc.h
>
<snip>
..
..
> +int musb_platform_init(void)
> +{
> +?????? int ret = -1;
> +
> +?????? if (platform_needs_initialization) {
> +????????????? u32 stdby;
> +
> +????????????? if (twl4030_usb_ulpi_init()) {
> +????????????????????? serial_printf("ERROR: %s Could not initialize
> PHY\n",
> +????????????????????????????? __PRETTY_FUNCTION__);
> +????????????????????? goto end;
> +????????????? }
OMAP3EVM uses ISP1504 phy and so twl4030 related init is not required.
Can we move this within #ifdef like,
#ifndef CONFIG_OMAP3_EVM
+ if (twl4030_usb_ulpi_init()) {
...
...
#endif
-Ajay
> +
> +????????????? otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
> +
> +????????????? /* Set OTG to always be on */
> +????????????? writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
> +????????????? ?????? OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
> +
> +????????????? /* Set the interface */
> +????????????? writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
> +
> +????????????? /* Clear force standby */
> +????????????? stdby = readl(&otg->forcestdby);
> +????????????? stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
> +????????????? writel(stdby, &otg->forcestdby);
> +
> +????????????? platform_needs_initialization = 0;
> +?????? }
> +
> +?????? ret = platform_needs_initialization;
> +end:
> +?????? return ret;
> +
> +}
> +
> +
> +/* UDC level routines */
> +void udc_irq(void);
> +void udc_set_nak(int ep_num);
> +void udc_unset_nak(int ep_num);
> +int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
> +void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
> +????????????? ? struct usb_endpoint_instance *endpoint);
> +void udc_connect(void);
> +void udc_disconnect(void);
> +void udc_enable(struct usb_device_instance *device);
> +void udc_disable(void);
> +void udc_startup_events(struct usb_device_instance *device);
> +int udc_init(void);
> +
> +/* usbtty */
> +#ifdef CONFIG_USB_TTY
> +
> +#define EP0_MAX_PACKET_SIZE?? 64 /* MUSB_EP0_FIFOSIZE */
> +#define UDC_INT_ENDPOINT????? 1
> +#define UDC_INT_PACKET_SIZE?? 64
> +#define UDC_OUT_ENDPOINT????? 2
> +#define UDC_OUT_PACKET_SIZE?? 64
> +#define UDC_IN_ENDPOINT????????????? 3
> +#define UDC_IN_PACKET_SIZE??? 64
> +#define UDC_BULK_PACKET_SIZE? 64
> +
> +#endif /* CONFIG_USB_TTY */
> +
> +#endif /* __MUSB_UDC_H__ */
> +
> --
> 1.6.0.6
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-10-27 5:18 [U-Boot] [PATCH 4/8] OMAP3 Add usb device support Gupta, Ajay Kumar
@ 2009-10-27 14:04 ` Tom
2009-10-28 8:46 ` Gupta, Ajay Kumar
0 siblings, 1 reply; 9+ messages in thread
From: Tom @ 2009-10-27 14:04 UTC (permalink / raw)
To: u-boot
Gupta, Ajay Kumar wrote:
> Tom,
>
>> From: Tom Rix <Tom.Rix <at> windriver.com>
>> Subject: [PATCH 4/8] OMAP3 Add usb device support
>> Newsgroups: gmane.comp.boot-loaders.u-boot
>> Date: 2009-09-28 16:37:25 GMT (4 weeks, 12 hours and 29 minutes ago)
>> This change adds the usb device support for musb.
>>
>> Omap3 platform support added at the same level as davinci.
>>
>> The interface for usbtty to use the musb device support was added.
>>
>> Verified on omap3 beagle, zoom1 and zoom2.
>>
>> Signed-off-by: Tom Rix <Tom.Rix <at> windriver.com>
>> ---
>> drivers/serial/usbtty.h | 2 +
>> drivers/usb/musb/Makefile | 2 +
>> drivers/usb/musb/musb_core.c | 8 +-
>> drivers/usb/musb/musb_core.h | 40 ++
>> drivers/usb/musb/musb_debug.h | 205 +++++++++
>> drivers/usb/musb/musb_udc.c | 963
>> +++++++++++++++++++++++++++++++++++++++++
>> drivers/usb/musb/omap3.c | 129 ++++++
>> drivers/usb/musb/omap3.h | 48 ++
>> include/usb.h | 3 +-
>> include/usb/musb_udc.h | 54 +++
>> 10 files changed, 1451 insertions(+), 3 deletions(-)
>> create mode 100644 drivers/usb/musb/musb_debug.h
>> create mode 100644 drivers/usb/musb/musb_udc.c
>> create mode 100644 drivers/usb/musb/omap3.c
>> create mode 100644 drivers/usb/musb/omap3.h
>> create mode 100644 include/usb/musb_udc.h
>>
>
> <snip>
> ..
> ..
>
>> +int musb_platform_init(void)
>> +{
>> + int ret = -1;
>> +
>> + if (platform_needs_initialization) {
>> + u32 stdby;
>> +
>> + if (twl4030_usb_ulpi_init()) {
>> + serial_printf("ERROR: %s Could not initialize
>> PHY\n",
>> + __PRETTY_FUNCTION__);
>> + goto end;
>> + }
>
> OMAP3EVM uses ISP1504 phy and so twl4030 related init is not required.
> Can we move this within #ifdef like,
>
> #ifndef CONFIG_OMAP3_EVM
> + if (twl4030_usb_ulpi_init()) {
> ...
> ...
> #endif
>
>
> -Ajay
I will include this in the next revision.
Will the omap3_evm need to add its own PHY initialization
code ?
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH 4/8] OMAP3 Add usb device support
2009-10-27 14:04 ` Tom
@ 2009-10-28 8:46 ` Gupta, Ajay Kumar
0 siblings, 0 replies; 9+ messages in thread
From: Gupta, Ajay Kumar @ 2009-10-28 8:46 UTC (permalink / raw)
To: u-boot
Tom,
> >
> > OMAP3EVM uses ISP1504 phy and so twl4030 related init is not required.
> > Can we move this within #ifdef like,
> >
> > #ifndef CONFIG_OMAP3_EVM
> > + if (twl4030_usb_ulpi_init()) {
> > ...
> > ...
> > #endif
> >
> >
> > -Ajay
>
> I will include this in the next revision.
Thanks.
> Will the omap3_evm need to add its own PHY initialization
> code ?
omap3_evm doesn't need any phy initialization code. In kernel driver
also it uses nop (no-operation) transceiver.
-Ajay
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-10-28 8:46 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-27 5:18 [U-Boot] [PATCH 4/8] OMAP3 Add usb device support Gupta, Ajay Kumar
2009-10-27 14:04 ` Tom
2009-10-28 8:46 ` Gupta, Ajay Kumar
-- strict thread matches above, loose matches on Subject: below --
2009-09-28 16:37 [U-Boot] V2 of OMAP3 USB device Support Tom Rix
2009-09-28 16:37 ` [U-Boot] [PATCH 1/8] USB Consolidate descriptor definitions Tom Rix
2009-09-28 16:37 ` [U-Boot] [PATCH 2/8] USB add macros for debugging usb device setup Tom Rix
2009-09-28 16:37 ` [U-Boot] [PATCH 3/8] TWL4030 Add usb PHY support Tom Rix
2009-09-28 16:37 ` [U-Boot] [PATCH 4/8] OMAP3 Add usb device support Tom Rix
2009-09-28 16:34 [U-Boot] V2 of OMAP3 USB device Support y at windriver.com
2009-09-28 16:34 ` [U-Boot] [PATCH 1/8] USB Consolidate descriptor definitions y at windriver.com
2009-09-28 16:34 ` [U-Boot] [PATCH 2/8] USB add macros for debugging usb device setup y at windriver.com
2009-09-28 16:34 ` [U-Boot] [PATCH 3/8] TWL4030 Add usb PHY support y at windriver.com
2009-09-28 16:34 ` [U-Boot] [PATCH 4/8] OMAP3 Add usb device support y at windriver.com
2009-09-04 20:12 [U-Boot] [PATCH 1/8] USB Consolidate descriptor definitions Tom Rix
2009-09-04 20:12 ` [U-Boot] [PATCH 2/8] USB add macros for debugging usb device setup Tom Rix
2009-09-04 20:12 ` [U-Boot] [PATCH 3/8] TWL4030 Add usb PHY support Tom Rix
2009-09-04 20:12 ` [U-Boot] [PATCH 4/8] OMAP3 Add usb device support Tom Rix
2009-09-05 0:25 ` Jean-Christophe PLAGNIOL-VILLARD
2009-09-06 13:35 ` Tom
2009-09-06 13:48 ` Jean-Christophe PLAGNIOL-VILLARD
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox