Merge branch 'master' of git://git.denx.de/u-boot-usb
diff --git a/board/davinci/dvevm/dvevm.c b/board/davinci/dvevm/dvevm.c
index abf60b3..bf36f73 100644
--- a/board/davinci/dvevm/dvevm.c
+++ b/board/davinci/dvevm/dvevm.c
@@ -52,6 +52,7 @@
lpsc_on(DAVINCI_LPSC_UART0);
lpsc_on(DAVINCI_LPSC_TIMER1);
lpsc_on(DAVINCI_LPSC_GPIO);
+ lpsc_on(DAVINCI_LPSC_USB);
#if !defined(CONFIG_SYS_USE_DSPLINK)
/* Powerup the DSP */
@@ -101,3 +102,26 @@
return(0);
}
+
+#ifdef CONFIG_USB_DAVINCI
+
+/* IO Expander I2C address and USB VBUS enable mask */
+#define IOEXP_I2C_ADDR 0x3A
+#define IOEXP_VBUSEN_MASK 1
+
+/*
+ * This function enables USB VBUS by writting to IO expander using I2C.
+ * Note that the I2C is already initialized at this stage. This
+ * function is used by davinci specific USB wrapper code.
+ */
+void enable_vbus(void)
+{
+ uchar data; /* IO Expander data to enable VBUS */
+
+ /* Write to IO expander to enable VBUS */
+ i2c_read(IOEXP_I2C_ADDR, 0, 0, &data, 1);
+ data &= ~IOEXP_VBUSEN_MASK;
+ i2c_write(IOEXP_I2C_ADDR, 0, 0, &data, 1);
+}
+#endif
+
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index 423a29f..a18e16e 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -264,6 +264,16 @@
printf("\n");
}
+static inline char *portspeed(int speed)
+{
+ if (speed == USB_SPEED_HIGH)
+ return "480 Mb/s";
+ else if (speed == USB_SPEED_LOW)
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+
/* shows the device tree recursively */
void usb_show_tree_graph(struct usb_device *dev, char *pre)
{
@@ -310,7 +320,7 @@
pre[index] = 0;
printf(" %s (%s, %dmA)\n", usb_get_class_desc(
dev->config.if_desc[0].bInterfaceClass),
- dev->slow ? "1.5MBit/s" : "12MBit/s",
+ portspeed(dev->speed),
dev->config.MaxPower * 2);
if (strlen(dev->mf) || strlen(dev->prod) || strlen(dev->serial))
printf(" %s %s %s %s\n", pre, dev->mf, dev->prod, dev->serial);
diff --git a/common/usb.c b/common/usb.c
index ee18152..87fca70 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -681,7 +681,7 @@
err = usb_string_sub(dev, 0, 0, tbuf);
if (err < 0) {
USB_PRINTF("error getting string descriptor 0 " \
- "(error=%x)\n", dev->status);
+ "(error=%lx)\n", dev->status);
return -1;
} else if (tbuf[0] < 4) {
USB_PRINTF("string descriptor 0 too short\n");
@@ -939,8 +939,10 @@
dev_index = 0;
/* device 0 is always present (root hub, so let it analyze) */
dev = usb_alloc_new_device();
- usb_new_device(dev);
- printf("%d USB Device(s) found\n", dev_index);
+ if (usb_new_device(dev))
+ printf("No USB Device found\n");
+ else
+ printf("%d USB Device(s) found\n", dev_index);
/* insert "driver" if possible */
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();
@@ -1041,6 +1043,16 @@
#define MAX_TRIES 5
+static inline char *portspeed(int portstatus)
+{
+ if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
+ return "480 Mb/s";
+ else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
+ return "1.5 Mb/s";
+ else
+ return "12 Mb/s";
+}
+
static int hub_port_reset(struct usb_device *dev, int port,
unsigned short *portstat)
{
@@ -1061,10 +1073,11 @@
}
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
+
USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
portstatus, portchange,
- portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? \
- "Low Speed" : "High Speed");
+ portspeed(portstatus));
+
USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \
" USB_PORT_STAT_ENABLE %d\n",
(portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0,
@@ -1109,9 +1122,7 @@
portstatus = le16_to_cpu(portsts.wPortStatus);
portchange = le16_to_cpu(portsts.wPortChange);
USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
- portstatus, portchange,
- portstatus&(1 << USB_PORT_FEAT_LOWSPEED) ? \
- "Low Speed" : "High Speed");
+ portstatus, portchange, portspeed(portstatus));
/* Clear the connection change status */
usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -1136,7 +1147,13 @@
/* Allocate a new device struct for it */
usb = usb_alloc_new_device();
- usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
+
+ if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ usb->speed = USB_SPEED_HIGH;
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ usb->speed = USB_SPEED_LOW;
+ else
+ usb->speed = USB_SPEED_FULL;
dev->children[port] = usb;
usb->parent = dev;
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 89e6ee7..e0d006c 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -183,6 +183,7 @@
usb_kbd_dev.puts = NULL;
usb_kbd_dev.getc = usb_kbd_getc;
usb_kbd_dev.tstc = usb_kbd_testc;
+ usb_kbd_dev.priv = (void *)dev;
error = device_register (&usb_kbd_dev);
if(error==0) {
/* check if this is the standard input device */
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 94f659f..51f0789 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -45,8 +45,6 @@
* New Note:
* Support for USB Mass Storage Devices (BBB) has been added. It has
* only been tested with USB memory sticks.
- * Nota bene: if you are using the BBB support with a little-endian
- * CPU then you MUST define LITTLEENDIAN in the configuration file!
*/
@@ -63,9 +61,9 @@
#undef BBB_XPORT_TRACE
#ifdef USB_STOR_DEBUG
-#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args)
+#define USB_STOR_PRINTF(fmt, args...) printf(fmt , ##args)
#else
-#define USB_STOR_PRINTF(fmt,args...)
+#define USB_STOR_PRINTF(fmt, args...)
#endif
#include <scsi.h>
@@ -110,7 +108,7 @@
__u8 CBWCDB[CBWCDBLENGTH];
} umass_bbb_cbw_t;
#define UMASS_BBB_CBW_SIZE 31
-static __u32 CBWTag = 0;
+static __u32 CBWTag;
/* Command Status Wrapper */
typedef struct {
@@ -126,34 +124,35 @@
#define UMASS_BBB_CSW_SIZE 13
#define USB_MAX_STOR_DEV 5
-static int usb_max_devs = 0; /* number of highest available usb device */
+static int usb_max_devs; /* number of highest available usb device */
static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
struct us_data;
-typedef int (*trans_cmnd)(ccb*, struct us_data*);
-typedef int (*trans_reset)(struct us_data*);
+typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
+typedef int (*trans_reset)(struct us_data *data);
struct us_data {
- struct usb_device *pusb_dev; /* this usb_device */
- unsigned int flags; /* from filter initially */
- unsigned char ifnum; /* interface number */
- unsigned char ep_in; /* in endpoint */
- unsigned char ep_out; /* out ....... */
- unsigned char ep_int; /* interrupt . */
- unsigned char subclass; /* as in overview */
- unsigned char protocol; /* .............. */
- unsigned char attention_done; /* force attn on first cmd */
- unsigned short ip_data; /* interrupt data */
- int action; /* what to do */
- int ip_wanted; /* needed */
- int *irq_handle; /* for USB int requests */
- unsigned int irqpipe; /* pipe for release_irq */
- unsigned char irqmaxp; /* max packed for irq Pipe */
- unsigned char irqinterval; /* Intervall for IRQ Pipe */
- ccb *srb; /* current srb */
- trans_reset transport_reset; /* reset routine */
- trans_cmnd transport; /* transport routine */
+ struct usb_device *pusb_dev; /* this usb_device */
+
+ unsigned int flags; /* from filter initially */
+ unsigned char ifnum; /* interface number */
+ unsigned char ep_in; /* in endpoint */
+ unsigned char ep_out; /* out ....... */
+ unsigned char ep_int; /* interrupt . */
+ unsigned char subclass; /* as in overview */
+ unsigned char protocol; /* .............. */
+ unsigned char attention_done; /* force attn on first cmd */
+ unsigned short ip_data; /* interrupt data */
+ int action; /* what to do */
+ int ip_wanted; /* needed */
+ int *irq_handle; /* for USB int requests */
+ unsigned int irqpipe; /* pipe for release_irq */
+ unsigned char irqmaxp; /* max packed for irq Pipe */
+ unsigned char irqinterval; /* Intervall for IRQ Pipe */
+ ccb *srb; /* current srb */
+ trans_reset transport_reset; /* reset routine */
+ trans_cmnd transport; /* transport routine */
};
static struct us_data usb_stor[USB_MAX_STOR_DEV];
@@ -163,10 +162,12 @@
#define USB_STOR_TRANSPORT_FAILED -1
#define USB_STOR_TRANSPORT_ERROR -2
-
-int usb_stor_get_info(struct usb_device *dev, struct us_data *us, block_dev_desc_t *dev_desc);
-int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss);
-unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, void *buffer);
+int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
+ block_dev_desc_t *dev_desc);
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
+ struct us_data *ss);
+unsigned long usb_stor_read(int device, unsigned long blknr,
+ unsigned long blkcnt, void *buffer);
struct usb_device * usb_get_dev_index(int index);
void uhci_show_temp_int_td(void);
@@ -181,7 +182,7 @@
printf(".");
}
-/*********************************************************************************
+/*******************************************************************************
* show info on storage devices; 'usb start/init' must be invoked earlier
* as we only retrieve structures populated during devices initialization
*/
@@ -191,7 +192,7 @@
if (usb_max_devs > 0) {
for (i = 0; i < usb_max_devs; i++) {
- printf (" Device %d: ", i);
+ printf(" Device %d: ", i);
dev_print(&usb_dev_desc[i]);
}
return 0;
@@ -201,7 +202,7 @@
return 1;
}
-/*********************************************************************************
+/*******************************************************************************
* scan the usb and reports device info
* to the user if mode = 1
* returns current device or -1 if no
@@ -214,67 +215,69 @@
/* GJ */
memset(usb_stor_buf, 0, sizeof(usb_stor_buf));
- if(mode==1) {
+ if (mode == 1)
printf(" scanning bus for storage devices... ");
- }
+
usb_disable_asynch(1); /* asynch transfer not allowed */
- for(i=0;i<USB_MAX_STOR_DEV;i++) {
- memset(&usb_dev_desc[i],0,sizeof(block_dev_desc_t));
- usb_dev_desc[i].target=0xff;
- usb_dev_desc[i].if_type=IF_TYPE_USB;
- usb_dev_desc[i].dev=i;
- usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
- usb_dev_desc[i].block_read=usb_stor_read;
+ for (i = 0; i < USB_MAX_STOR_DEV; i++) {
+ memset(&usb_dev_desc[i], 0, sizeof(block_dev_desc_t));
+ usb_dev_desc[i].target = 0xff;
+ usb_dev_desc[i].if_type = IF_TYPE_USB;
+ usb_dev_desc[i].dev = i;
+ usb_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+ usb_dev_desc[i].block_read = usb_stor_read;
}
- usb_max_devs=0;
- for(i=0;i<USB_MAX_DEVICE;i++) {
- dev=usb_get_dev_index(i); /* get device */
- USB_STOR_PRINTF("i=%d\n",i);
- if(dev==NULL) {
+ usb_max_devs = 0;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i); /* get device */
+ USB_STOR_PRINTF("i=%d\n", i);
+ if (dev == NULL)
break; /* no more devices avaiable */
- }
- if(usb_storage_probe(dev,0,&usb_stor[usb_max_devs])) { /* ok, it is a storage devices */
- /* get info and fill it in */
- if(usb_stor_get_info(dev, &usb_stor[usb_max_devs], &usb_dev_desc[usb_max_devs]))
+
+ if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
+ /* ok, it is a storage devices
+ * get info and fill it in
+ */
+ if (usb_stor_get_info(dev, &usb_stor[usb_max_devs],
+ &usb_dev_desc[usb_max_devs]))
usb_max_devs++;
- } /* if storage device */
- if(usb_max_devs==USB_MAX_STOR_DEV) {
- printf("max USB Storage Device reached: %d stopping\n",usb_max_devs);
+ }
+ /* if storage device */
+ if (usb_max_devs == USB_MAX_STOR_DEV) {
+ printf("max USB Storage Device reached: %d stopping\n",
+ usb_max_devs);
break;
}
} /* for */
usb_disable_asynch(0); /* asynch transfer allowed */
printf("%d Storage Device(s) found\n", usb_max_devs);
- if(usb_max_devs>0)
+ if (usb_max_devs > 0)
return 0;
- else
- return-1;
+ return -1;
}
static int usb_stor_irq(struct usb_device *dev)
{
struct us_data *us;
- us=(struct us_data *)dev->privptr;
+ us = (struct us_data *)dev->privptr;
- if(us->ip_wanted) {
- us->ip_wanted=0;
- }
+ if (us->ip_wanted)
+ us->ip_wanted = 0;
return 0;
}
#ifdef USB_STOR_DEBUG
-static void usb_show_srb(ccb * pccb)
+static void usb_show_srb(ccb *pccb)
{
int i;
- printf("SRB: len %d datalen 0x%lX\n ",pccb->cmdlen,pccb->datalen);
- for(i=0;i<12;i++) {
- printf("%02X ",pccb->cmd[i]);
- }
+ printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
+ for (i = 0; i < 12; i++)
+ printf("%02X ", pccb->cmd[i]);
printf("\n");
}
@@ -322,11 +325,14 @@
USB_STOR_PRINTF("Bulk xfer 0x%x(%d) try #%d\n",
(unsigned int)buf, this_xfer, 11 - maxtry);
result = usb_bulk_msg(us->pusb_dev, pipe, buf,
- this_xfer, &partial, USB_CNTL_TIMEOUT*5);
+ this_xfer, &partial,
+ USB_CNTL_TIMEOUT * 5);
USB_STOR_PRINTF("bulk_msg returned %d xferred %d/%d\n",
result, partial, this_xfer);
- if(us->pusb_dev->status!=0) {
- /* if we stall, we need to clear it before we go on */
+ if (us->pusb_dev->status != 0) {
+ /* if we stall, we need to clear it before
+ * we go on
+ */
#ifdef USB_STOR_DEBUG
display_int_status(us->pusb_dev->status);
#endif
@@ -334,9 +340,9 @@
USB_STOR_PRINTF("stalled ->clearing endpoint halt for pipe 0x%x\n", pipe);
stat = us->pusb_dev->status;
usb_clear_halt(us->pusb_dev, pipe);
- us->pusb_dev->status=stat;
- if(this_xfer == partial) {
- USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n",us->pusb_dev->status);
+ us->pusb_dev->status = stat;
+ if (this_xfer == partial) {
+ USB_STOR_PRINTF("bulk transferred with error %X, but data ok\n", us->pusb_dev->status);
return 0;
}
else
@@ -346,12 +352,15 @@
USB_STOR_PRINTF("Device NAKed bulk_msg\n");
return result;
}
- if(this_xfer == partial) {
- USB_STOR_PRINTF("bulk transferred with error %d, but data ok\n",us->pusb_dev->status);
+ USB_STOR_PRINTF("bulk transferred with error");
+ if (this_xfer == partial) {
+ USB_STOR_PRINTF(" %d, but data ok\n",
+ us->pusb_dev->status);
return 0;
}
/* if our try counter reaches 0, bail out */
- USB_STOR_PRINTF("bulk transferred with error %d, data %d\n",us->pusb_dev->status,partial);
+ USB_STOR_PRINTF(" %d, data %d\n",
+ us->pusb_dev->status, partial);
if (!maxtry--)
return result;
}
@@ -359,7 +368,7 @@
this_xfer -= partial;
buf += partial;
/* continue until this transfer is done */
- } while ( this_xfer );
+ } while (this_xfer);
}
/* if we get here, we're done and successful */
@@ -386,29 +395,33 @@
* This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
*/
USB_STOR_PRINTF("BBB_reset\n");
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT*5);
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ US_BBB_RESET,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT * 5);
- if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED))
- {
+ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
USB_STOR_PRINTF("RESET:stall\n");
return -1;
}
/* long wait for reset */
wait_ms(150);
- USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n",result,us->pusb_dev->status);
+ USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n", result,
+ us->pusb_dev->status);
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
result = usb_clear_halt(us->pusb_dev, pipe);
/* long wait for reset */
wait_ms(150);
- USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",result,us->pusb_dev->status);
+ USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",
+ result, us->pusb_dev->status);
/* long wait for reset */
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
result = usb_clear_halt(us->pusb_dev, pipe);
wait_ms(150);
- USB_STOR_PRINTF("BBB_reset result %d: status %X clearing OUT endpoint\n",result,us->pusb_dev->status);
+ USB_STOR_PRINTF("BBB_reset result %d: status %X"
+ " clearing OUT endpoint\n", result,
+ us->pusb_dev->status);
USB_STOR_PRINTF("BBB_reset done\n");
return 0;
}
@@ -423,16 +436,20 @@
int result;
USB_STOR_PRINTF("CB_reset\n");
- memset(cmd, 0xFF, sizeof(cmd));
+ memset(cmd, 0xff, sizeof(cmd));
cmd[0] = SCSI_SEND_DIAG;
cmd[1] = 4;
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, us->ifnum, cmd, sizeof(cmd), USB_CNTL_TIMEOUT*5);
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, cmd, sizeof(cmd),
+ USB_CNTL_TIMEOUT * 5);
/* long wait for reset */
wait_ms(1500);
- USB_STOR_PRINTF("CB_reset result %d: status %X clearing endpoint halt\n",result,us->pusb_dev->status);
+ USB_STOR_PRINTF("CB_reset result %d: status %X"
+ " clearing endpoint halt\n", result,
+ us->pusb_dev->status);
usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
@@ -455,9 +472,11 @@
dir_in = US_DIRECTION(srb->cmd[0]);
#ifdef BBB_COMDAT_TRACE
- printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata);
+ printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n",
+ dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
+ srb->pdata);
if (srb->cmdlen) {
- for(result = 0;result < srb->cmdlen;result++)
+ for (result = 0; result < srb->cmdlen; result++)
printf("cmd[%d] %#x ", result, srb->cmd[result]);
printf("\n");
}
@@ -474,13 +493,14 @@
cbw.dCBWSignature = cpu_to_le32(CBWSIGNATURE);
cbw.dCBWTag = cpu_to_le32(CBWTag++);
cbw.dCBWDataTransferLength = cpu_to_le32(srb->datalen);
- cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT);
+ cbw.bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
cbw.bCBWLUN = srb->lun;
cbw.bCDBLength = srb->cmdlen;
/* copy the command data into the CBW command data buffer */
/* DST SRC LEN!!! */
memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen);
- result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5);
+ result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE,
+ &actlen, USB_CNTL_TIMEOUT * 5);
if (result < 0)
USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n");
return result;
@@ -492,46 +512,61 @@
int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
{
int result = 0;
- int dir_in,retry;
+ int dir_in, retry;
unsigned int pipe;
unsigned long status;
- retry=5;
- dir_in=US_DIRECTION(srb->cmd[0]);
+ retry = 5;
+ dir_in = US_DIRECTION(srb->cmd[0]);
- if(dir_in)
- pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
- else
- pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out);
- while(retry--) {
- USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry);
+ if (dir_in)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ while (retry--) {
+ USB_STOR_PRINTF("CBI gets a command: Try %d\n", 5 - retry);
#ifdef USB_STOR_DEBUG
usb_show_srb(srb);
#endif
/* let's send the command via the control pipe */
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
- US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev , 0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum,
- srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5);
- USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status);
+ srb->cmd, srb->cmdlen,
+ USB_CNTL_TIMEOUT * 5);
+ USB_STOR_PRINTF("CB_transport: control msg returned %d,"
+ " status %X\n", result, us->pusb_dev->status);
/* check the return code for the command */
if (result < 0) {
- if(us->pusb_dev->status & USB_ST_STALLED) {
- status=us->pusb_dev->status;
- USB_STOR_PRINTF(" stall during command found, clear pipe\n");
- usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0));
- us->pusb_dev->status=status;
+ if (us->pusb_dev->status & USB_ST_STALLED) {
+ status = us->pusb_dev->status;
+ USB_STOR_PRINTF(" stall during command found,"
+ " clear pipe\n");
+ usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev, 0));
+ us->pusb_dev->status = status;
}
- USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status);
+ USB_STOR_PRINTF(" error during command %02X"
+ " Stat = %X\n", srb->cmd[0],
+ us->pusb_dev->status);
return result;
}
/* transfer the data payload for this command, if one exists*/
- USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen);
+ USB_STOR_PRINTF("CB_transport: control msg returned %d,"
+ " direction is %s to go 0x%lx\n", result,
+ dir_in ? "IN" : "OUT", srb->datalen);
if (srb->datalen) {
- result = us_one_transfer(us, pipe, (char *)srb->pdata,srb->datalen);
- USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len);
- if(!(us->pusb_dev->status & USB_ST_NAK_REC))
+ result = us_one_transfer(us, pipe, (char *)srb->pdata,
+ srb->datalen);
+ USB_STOR_PRINTF("CBI attempted to transfer data,"
+ " result is %d status %lX, len %d\n",
+ result, us->pusb_dev->status,
+ us->pusb_dev->act_len);
+ if (!(us->pusb_dev->status & USB_ST_NAK_REC))
break;
} /* if (srb->datalen) */
else
@@ -543,21 +578,21 @@
}
-int usb_stor_CBI_get_status (ccb * srb, struct us_data *us)
+int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
{
int timeout;
us->ip_wanted = 1;
- submit_int_msg (us->pusb_dev, us->irqpipe,
+ submit_int_msg(us->pusb_dev, us->irqpipe,
(void *) &us->ip_data, us->irqmaxp, us->irqinterval);
timeout = 1000;
while (timeout--) {
if ((volatile int *) us->ip_wanted == 0)
break;
- wait_ms (10);
+ wait_ms(10);
}
if (us->ip_wanted) {
- printf (" Did not get interrupt on CBI\n");
+ printf(" Did not get interrupt on CBI\n");
us->ip_wanted = 0;
return USB_STOR_TRANSPORT_ERROR;
}
@@ -596,9 +631,9 @@
int result;
/* ENDPOINT_HALT = 0, so set value to 0 */
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
- 0, endpt, 0, 0, USB_CNTL_TIMEOUT*5);
+ 0, endpt, 0, 0, USB_CNTL_TIMEOUT * 5);
return result;
}
@@ -638,12 +673,14 @@
pipe = pipein;
else
pipe = pipeout;
- result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5);
+ result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
+ &data_actlen, USB_CNTL_TIMEOUT * 5);
/* special handling of STALL in DATA phase */
- if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
+ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
USB_STOR_PRINTF("DATA:stall\n");
/* clear the STALL on the endpoint */
- result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out);
+ result = usb_stor_BBB_clear_endpt_stall(us,
+ dir_in ? us->ep_in : us->ep_out);
if (result >= 0)
/* continue on to STATUS phase */
goto st;
@@ -660,15 +697,16 @@
printf("\n");
#endif
/* STATUS phase + error handling */
- st:
+st:
retry = 0;
- again:
+again:
USB_STOR_PRINTF("STATUS phase\n");
result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE,
&actlen, USB_CNTL_TIMEOUT*5);
/* special handling of STALL in STATUS phase */
- if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) {
+ if ((result < 0) && (retry < 1) &&
+ (us->pusb_dev->status & USB_ST_STALLED)) {
USB_STOR_PRINTF("STATUS:stall\n");
/* clear the STALL on the endpoint */
result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
@@ -722,32 +760,33 @@
int usb_stor_CB_transport(ccb *srb, struct us_data *us)
{
- int result,status;
+ int result, status;
ccb *psrb;
ccb reqsrb;
- int retry,notready;
+ int retry, notready;
psrb = &reqsrb;
- status=USB_STOR_TRANSPORT_GOOD;
- retry=0;
- notready=0;
+ status = USB_STOR_TRANSPORT_GOOD;
+ retry = 0;
+ notready = 0;
/* issue the command */
do_retry:
- result=usb_stor_CB_comdat(srb,us);
- USB_STOR_PRINTF("command / Data returned %d, status %X\n",result,us->pusb_dev->status);
+ result = usb_stor_CB_comdat(srb, us);
+ USB_STOR_PRINTF("command / Data returned %d, status %X\n",
+ result, us->pusb_dev->status);
/* if this is an CBI Protocol, get IRQ */
- if(us->protocol==US_PR_CBI) {
- status=usb_stor_CBI_get_status(srb,us);
+ if (us->protocol == US_PR_CBI) {
+ status = usb_stor_CBI_get_status(srb, us);
/* if the status is error, report it */
- if(status==USB_STOR_TRANSPORT_ERROR) {
+ if (status == USB_STOR_TRANSPORT_ERROR) {
USB_STOR_PRINTF(" USB CBI Command Error\n");
return status;
}
- srb->sense_buf[12]=(unsigned char)(us->ip_data>>8);
- srb->sense_buf[13]=(unsigned char)(us->ip_data&0xff);
- if(!us->ip_data) {
- /* if the status is good, report it */
- if(status==USB_STOR_TRANSPORT_GOOD) {
+ srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
+ srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
+ if (!us->ip_data) {
+ /* if the status is good, report it */
+ if (status == USB_STOR_TRANSPORT_GOOD) {
USB_STOR_PRINTF(" USB CBI Command Good\n");
return status;
}
@@ -755,51 +794,62 @@
}
/* do we have to issue an auto request? */
/* HERE we have to check the result */
- if((result<0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
- USB_STOR_PRINTF("ERROR %X\n",us->pusb_dev->status);
+ if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF("ERROR %X\n", us->pusb_dev->status);
us->transport_reset(us);
return USB_STOR_TRANSPORT_ERROR;
}
- if((us->protocol==US_PR_CBI) &&
- ((srb->cmd[0]==SCSI_REQ_SENSE) ||
- (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */
+ if ((us->protocol == US_PR_CBI) &&
+ ((srb->cmd[0] == SCSI_REQ_SENSE) ||
+ (srb->cmd[0] == SCSI_INQUIRY))) {
+ /* do not issue an autorequest after request sense */
USB_STOR_PRINTF("No auto request and good\n");
return USB_STOR_TRANSPORT_GOOD;
}
/* issue an request_sense */
- memset(&psrb->cmd[0],0,12);
- psrb->cmd[0]=SCSI_REQ_SENSE;
- psrb->cmd[1]=srb->lun<<5;
- psrb->cmd[4]=18;
- psrb->datalen=18;
+ memset(&psrb->cmd[0], 0, 12);
+ psrb->cmd[0] = SCSI_REQ_SENSE;
+ psrb->cmd[1] = srb->lun << 5;
+ psrb->cmd[4] = 18;
+ psrb->datalen = 18;
psrb->pdata = &srb->sense_buf[0];
- psrb->cmdlen=12;
+ psrb->cmdlen = 12;
/* issue the command */
- result=usb_stor_CB_comdat(psrb,us);
- USB_STOR_PRINTF("auto request returned %d\n",result);
+ result = usb_stor_CB_comdat(psrb, us);
+ USB_STOR_PRINTF("auto request returned %d\n", result);
/* if this is an CBI Protocol, get IRQ */
- if(us->protocol==US_PR_CBI) {
- status=usb_stor_CBI_get_status(psrb,us);
- }
- if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) {
- USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status);
+ if (us->protocol == US_PR_CBI)
+ status = usb_stor_CBI_get_status(psrb, us);
+
+ if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
+ USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",
+ us->pusb_dev->status);
return USB_STOR_TRANSPORT_ERROR;
}
- USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ USB_STOR_PRINTF("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ srb->sense_buf[0], srb->sense_buf[2],
+ srb->sense_buf[12], srb->sense_buf[13]);
/* Check the auto request result */
- if((srb->sense_buf[2]==0) &&
- (srb->sense_buf[12]==0) &&
- (srb->sense_buf[13]==0)) /* ok, no sense */
+ if ((srb->sense_buf[2] == 0) &&
+ (srb->sense_buf[12] == 0) &&
+ (srb->sense_buf[13] == 0)) {
+ /* ok, no sense */
return USB_STOR_TRANSPORT_GOOD;
+ }
+
/* Check the auto request result */
- switch(srb->sense_buf[2]) {
- case 0x01: /* Recovered Error */
+ switch (srb->sense_buf[2]) {
+ case 0x01:
+ /* Recovered Error */
return USB_STOR_TRANSPORT_GOOD;
break;
- case 0x02: /* Not Ready */
- if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
- printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n",
- srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ case 0x02:
+ /* Not Ready */
+ if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
+ " 0x%02X (NOT READY)\n", srb->cmd[0],
+ srb->sense_buf[0], srb->sense_buf[2],
+ srb->sense_buf[12], srb->sense_buf[13]);
return USB_STOR_TRANSPORT_FAILED;
} else {
wait_ms(100);
@@ -807,113 +857,116 @@
}
break;
default:
- if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
- printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
- srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
+ printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
+ " 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
+ srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
return USB_STOR_TRANSPORT_FAILED;
- } else {
+ } else
goto do_retry;
- }
break;
}
return USB_STOR_TRANSPORT_FAILED;
}
-static int usb_inquiry(ccb *srb,struct us_data *ss)
+static int usb_inquiry(ccb *srb, struct us_data *ss)
{
- int retry,i;
- retry=5;
+ int retry, i;
+ retry = 5;
do {
- memset(&srb->cmd[0],0,12);
- srb->cmd[0]=SCSI_INQUIRY;
- srb->cmd[1]=srb->lun<<5;
- srb->cmd[4]=36;
- srb->datalen=36;
- srb->cmdlen=12;
- i=ss->transport(srb,ss);
- USB_STOR_PRINTF("inquiry returns %d\n",i);
- if(i==0)
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_INQUIRY;
+ srb->cmd[1] = srb->lun<<5;
+ srb->cmd[4] = 36;
+ srb->datalen = 36;
+ srb->cmdlen = 12;
+ i = ss->transport(srb, ss);
+ USB_STOR_PRINTF("inquiry returns %d\n", i);
+ if (i == 0)
break;
- } while(retry--);
+ } while (retry--);
- if(!retry) {
+ if (!retry) {
printf("error in inquiry\n");
return -1;
}
return 0;
}
-static int usb_request_sense(ccb *srb,struct us_data *ss)
+static int usb_request_sense(ccb *srb, struct us_data *ss)
{
char *ptr;
- ptr=(char *)srb->pdata;
- memset(&srb->cmd[0],0,12);
- srb->cmd[0]=SCSI_REQ_SENSE;
- srb->cmd[1]=srb->lun<<5;
- srb->cmd[4]=18;
- srb->datalen=18;
+ ptr = (char *)srb->pdata;
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_REQ_SENSE;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[4] = 18;
+ srb->datalen = 18;
srb->pdata = &srb->sense_buf[0];
- srb->cmdlen=12;
- ss->transport(srb,ss);
- USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
- srb->pdata=(uchar *)ptr;
+ srb->cmdlen = 12;
+ ss->transport(srb, ss);
+ USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",
+ srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ srb->pdata = (uchar *)ptr;
return 0;
}
-static int usb_test_unit_ready(ccb *srb,struct us_data *ss)
+static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
{
int retries = 10;
do {
- memset(&srb->cmd[0],0,12);
- srb->cmd[0]=SCSI_TST_U_RDY;
- srb->cmd[1]=srb->lun<<5;
- srb->datalen=0;
- srb->cmdlen=12;
- if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_TST_U_RDY;
+ srb->cmd[1] = srb->lun << 5;
+ srb->datalen = 0;
+ srb->cmdlen = 12;
+ if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
return 0;
- }
- usb_request_sense (srb, ss);
- wait_ms (100);
- } while(retries--);
+ usb_request_sense(srb, ss);
+ wait_ms(100);
+ } while (retries--);
return -1;
}
-static int usb_read_capacity(ccb *srb,struct us_data *ss)
+static int usb_read_capacity(ccb *srb, struct us_data *ss)
{
int retry;
- retry = 3; /* retries */
+ /* XXX retries */
+ retry = 3;
do {
- memset(&srb->cmd[0],0,12);
- srb->cmd[0]=SCSI_RD_CAPAC;
- srb->cmd[1]=srb->lun<<5;
- srb->datalen=8;
- srb->cmdlen=12;
- if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) {
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_RD_CAPAC;
+ srb->cmd[1] = srb->lun << 5;
+ srb->datalen = 8;
+ srb->cmdlen = 12;
+ if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
return 0;
- }
- } while(retry--);
+ } while (retry--);
return -1;
}
-static int usb_read_10(ccb *srb,struct us_data *ss, unsigned long start, unsigned short blocks)
+static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start,
+ unsigned short blocks)
{
- memset(&srb->cmd[0],0,12);
- srb->cmd[0]=SCSI_READ10;
- srb->cmd[1]=srb->lun<<5;
- srb->cmd[2]=((unsigned char) (start>>24))&0xff;
- srb->cmd[3]=((unsigned char) (start>>16))&0xff;
- srb->cmd[4]=((unsigned char) (start>>8))&0xff;
- srb->cmd[5]=((unsigned char) (start))&0xff;
- srb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
- srb->cmd[8]=(unsigned char) blocks & 0xff;
- srb->cmdlen=12;
- USB_STOR_PRINTF("read10: start %lx blocks %x\n",start,blocks);
- return ss->transport(srb,ss);
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_READ10;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
+ srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
+ srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
+ srb->cmd[5] = ((unsigned char) (start)) & 0xff;
+ srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
+ srb->cmd[8] = (unsigned char) blocks & 0xff;
+ srb->cmdlen = 12;
+ USB_STOR_PRINTF("read10: start %lx blocks %x\n", start, blocks);
+ return ss->transport(srb, ss);
}
@@ -933,85 +986,94 @@
const unsigned char max_vendor_len = 40;
const unsigned char max_product_len = 20;
if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
- strncpy ((char *)vendor, "SMSC", max_vendor_len);
- strncpy ((char *)product, "Flash Media Cntrller", max_product_len);
+ strncpy((char *)vendor, "SMSC", max_vendor_len);
+ strncpy((char *)product, "Flash Media Cntrller",
+ max_product_len);
}
}
#endif /* CONFIG_USB_BIN_FIXUP */
#define USB_MAX_READ_BLK 20
-unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcnt, void *buffer)
+unsigned long usb_stor_read(int device, unsigned long blknr,
+ unsigned long blkcnt, void *buffer)
{
- unsigned long start,blks, buf_addr;
+ unsigned long start, blks, buf_addr;
unsigned short smallblks;
struct usb_device *dev;
- int retry,i;
+ int retry, i;
ccb *srb = &usb_ccb;
if (blkcnt == 0)
return 0;
device &= 0xff;
- /* Setup device
- */
- USB_STOR_PRINTF("\nusb_read: dev %d \n",device);
- dev=NULL;
- for(i=0;i<USB_MAX_DEVICE;i++) {
- dev=usb_get_dev_index(i);
- if(dev==NULL) {
+ /* Setup device */
+ USB_STOR_PRINTF("\nusb_read: dev %d \n", device);
+ dev = NULL;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i);
+ if (dev == NULL)
return 0;
- }
- if(dev->devnum==usb_dev_desc[device].target)
+ if (dev->devnum == usb_dev_desc[device].target)
break;
}
usb_disable_asynch(1); /* asynch transfer not allowed */
- srb->lun=usb_dev_desc[device].lun;
- buf_addr=(unsigned long)buffer;
- start=blknr;
- blks=blkcnt;
- if(usb_test_unit_ready(srb,(struct us_data *)dev->privptr)) {
- printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",
- srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]);
+ srb->lun = usb_dev_desc[device].lun;
+ buf_addr = (unsigned long)buffer;
+ start = blknr;
+ blks = blkcnt;
+ if (usb_test_unit_ready(srb, (struct us_data *)dev->privptr)) {
+ printf("Device NOT ready\n Request Sense returned %02X %02X"
+ " %02X\n", srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
return 0;
}
- USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks, buf_addr);
+
+ USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx"
+ " buffer %lx\n", device, start, blks, buf_addr);
+
do {
- retry=2;
- srb->pdata=(unsigned char *)buf_addr;
- if(blks>USB_MAX_READ_BLK) {
- smallblks=USB_MAX_READ_BLK;
- } else {
- smallblks=(unsigned short) blks;
- }
+ /* XXX need some comment here */
+ retry = 2;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (blks > USB_MAX_READ_BLK)
+ smallblks = USB_MAX_READ_BLK;
+ else
+ smallblks = (unsigned short) blks;
retry_it:
- if(smallblks==USB_MAX_READ_BLK)
+ if (smallblks == USB_MAX_READ_BLK)
usb_show_progress();
- srb->datalen=usb_dev_desc[device].blksz * smallblks;
- srb->pdata=(unsigned char *)buf_addr;
- if(usb_read_10(srb,(struct us_data *)dev->privptr, start, smallblks)) {
+ srb->datalen = usb_dev_desc[device].blksz * smallblks;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (usb_read_10(srb, (struct us_data *)dev->privptr, start,
+ smallblks)) {
USB_STOR_PRINTF("Read ERROR\n");
- usb_request_sense(srb,(struct us_data *)dev->privptr);
- if(retry--)
+ usb_request_sense(srb, (struct us_data *)dev->privptr);
+ if (retry--)
goto retry_it;
- blkcnt-=blks;
+ blkcnt -= blks;
break;
}
- start+=smallblks;
- blks-=smallblks;
- buf_addr+=srb->datalen;
- } while(blks!=0);
- USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
+ start += smallblks;
+ blks -= smallblks;
+ buf_addr += srb->datalen;
+ } while (blks != 0);
+
+ USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",
+ start, smallblks, buf_addr);
+
usb_disable_asynch(0); /* asynch transfer allowed */
- if(blkcnt>=USB_MAX_READ_BLK)
+ if (blkcnt >= USB_MAX_READ_BLK)
printf("\n");
- return(blkcnt);
+ return blkcnt;
}
/* Probe to see if a new device is actually a Storage device */
-int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data *ss)
+int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
+ struct us_data *ss)
{
struct usb_interface_descriptor *iface;
int i;
@@ -1025,8 +1087,11 @@
#if 0
/* this is the place to patch some storage devices */
- USB_STOR_PRINTF("iVendor %X iProduct %X\n",dev->descriptor.idVendor,dev->descriptor.idProduct);
- if ((dev->descriptor.idVendor) == 0x066b && (dev->descriptor.idProduct) == 0x0103) {
+ USB_STOR_PRINTF("iVendor %X iProduct %X\n", dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+
+ if ((dev->descriptor.idVendor) == 0x066b &&
+ (dev->descriptor.idProduct) == 0x0103) {
USB_STOR_PRINTF("patched for E-USB\n");
protocol = US_PR_CB;
subclass = US_SC_UFI; /* an assumption */
@@ -1095,19 +1160,20 @@
*/
for (i = 0; i < iface->bNumEndpoints; i++) {
/* is it an BULK endpoint? */
- if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK) {
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
ss->ep_in = iface->ep_desc[i].bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
else
- ss->ep_out = iface->ep_desc[i].bEndpointAddress &
+ ss->ep_out =
+ iface->ep_desc[i].bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
}
/* is it an interrupt endpoint? */
- if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT) {
+ if ((iface->ep_desc[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
ss->ep_int = iface->ep_desc[i].bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ss->irqinterval = iface->ep_desc[i].bInterval;
@@ -1130,26 +1196,28 @@
*/
if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
ss->subclass != US_SC_8070) {
- printf("Sorry, protocol %d not yet supported.\n",ss->subclass);
+ printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
return 0;
}
- if(ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe */
- /* set up the IRQ pipe and handler */
-
+ if (ss->ep_int) {
+ /* we had found an interrupt endpoint, prepare irq pipe
+ * set up the IRQ pipe and handler
+ */
ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
- dev->irq_handle=usb_stor_irq;
+ dev->irq_handle = usb_stor_irq;
}
- dev->privptr=(void *)ss;
+ dev->privptr = (void *)ss;
return 1;
}
-int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t *dev_desc)
+int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
+ block_dev_desc_t *dev_desc)
{
- unsigned char perq,modi;
+ unsigned char perq, modi;
unsigned long cap[2];
- unsigned long *capacity,*blksz;
+ unsigned long *capacity, *blksz;
ccb *pccb = &usb_ccb;
/* for some reasons a couple of devices would not survive this reset */
@@ -1157,7 +1225,6 @@
/* Sony USM256E */
(dev->descriptor.idVendor == 0x054c &&
dev->descriptor.idProduct == 0x019e)
-
||
/* USB007 Mini-USB2 Flash Drive */
(dev->descriptor.idVendor == 0x066f &&
@@ -1166,6 +1233,13 @@
/* SanDisk Corporation Cruzer Micro 20044318410546613953 */
(dev->descriptor.idVendor == 0x0781 &&
dev->descriptor.idProduct == 0x5151)
+ ||
+ /*
+ * SanDisk Corporation U3 Cruzer Micro 1/4GB
+ * Flash Drive 000016244373FFB4
+ */
+ (dev->descriptor.idVendor == 0x0781 &&
+ dev->descriptor.idProduct == 0x5406)
)
USB_STOR_PRINTF("usb_stor_get_info: skipping RESET..\n");
else
@@ -1175,17 +1249,20 @@
dev_desc->target = dev->devnum;
pccb->lun = dev_desc->lun;
- USB_STOR_PRINTF(" address %d\n",dev_desc->target);
+ USB_STOR_PRINTF(" address %d\n", dev_desc->target);
- if(usb_inquiry(pccb,ss))
+ if (usb_inquiry(pccb, ss))
return -1;
perq = usb_stor_buf[0];
modi = usb_stor_buf[1];
- if((perq & 0x1f) == 0x1f) {
- return 0; /* skip unknown devices */
+
+ if ((perq & 0x1f) == 0x1f) {
+ /* skip unknown devices */
+ return 0;
}
- if((modi&0x80) == 0x80) {/* drive is removable */
+ if ((modi&0x80) == 0x80) {
+ /* drive is removable */
dev_desc->removable = 1;
}
memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
@@ -1195,29 +1272,34 @@
dev_desc->product[16] = 0;
dev_desc->revision[4] = 0;
#ifdef CONFIG_USB_BIN_FIXUP
- usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor, (uchar *)dev_desc->product);
+ usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
+ (uchar *)dev_desc->product);
#endif /* CONFIG_USB_BIN_FIXUP */
- USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]);
- if(usb_test_unit_ready(pccb,ss)) {
- printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]);
- if(dev_desc->removable == 1) {
+ USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
+ usb_stor_buf[3]);
+ if (usb_test_unit_ready(pccb, ss)) {
+ printf("Device NOT ready\n"
+ " Request Sense returned %02X %02X %02X\n",
+ pccb->sense_buf[2], pccb->sense_buf[12],
+ pccb->sense_buf[13]);
+ if (dev_desc->removable == 1) {
dev_desc->type = perq;
return 1;
}
- else
- return 0;
+ return 0;
}
pccb->pdata = (unsigned char *)&cap[0];
- memset(pccb->pdata,0,8);
- if(usb_read_capacity(pccb,ss) != 0) {
+ memset(pccb->pdata, 0, 8);
+ if (usb_read_capacity(pccb, ss) != 0) {
printf("READ_CAP ERROR\n");
cap[0] = 2880;
cap[1] = 0x200;
}
- USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]);
+ USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n", cap[0],
+ cap[1]);
#if 0
- if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */
- cap[0]>>=16;
+ if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
+ cap[0] >>= 16;
#endif
cap[0] = cpu_to_be32(cap[0]);
cap[1] = cpu_to_be32(cap[1]);
@@ -1226,15 +1308,16 @@
cap[0] += 1;
capacity = &cap[0];
blksz = &cap[1];
- USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz);
+ USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",
+ *capacity, *blksz);
dev_desc->lba = *capacity;
dev_desc->blksz = *blksz;
dev_desc->type = perq;
- USB_STOR_PRINTF(" address %d\n",dev_desc->target);
- USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
+ USB_STOR_PRINTF(" address %d\n", dev_desc->target);
+ USB_STOR_PRINTF("partype: %d\n", dev_desc->part_type);
init_part(dev_desc);
- USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
+ USB_STOR_PRINTF("partype: %d\n", dev_desc->part_type);
return 1;
}
diff --git a/cpu/arm920t/s3c24x0/usb_ohci.c b/cpu/arm920t/s3c24x0/usb_ohci.c
index 641f270..9cbd477 100644
--- a/cpu/arm920t/s3c24x0/usb_ohci.c
+++ b/cpu/arm920t/s3c24x0/usb_ohci.c
@@ -29,9 +29,7 @@
*/
/*
* IMPORTANT NOTES
- * 1 - you MUST define LITTLEENDIAN in the configuration file for the
- * board or this driver will NOT work!
- * 2 - this driver is intended for use with USB Mass Storage Devices
+ * 1 - this driver is intended for use with USB Mass Storage Devices
* (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
*/
diff --git a/cpu/mips/au1x00_usb_ohci.c b/cpu/mips/au1x00_usb_ohci.c
index 17489da..ea02efb 100644
--- a/cpu/mips/au1x00_usb_ohci.c
+++ b/cpu/mips/au1x00_usb_ohci.c
@@ -27,9 +27,7 @@
*/
/*
* IMPORTANT NOTES
- * 1 - you MUST define LITTLEENDIAN in the configuration file for the
- * board or this driver will NOT work!
- * 2 - this driver is intended for use with USB Mass Storage Devices
+ * 1 - this driver is intended for use with USB Mass Storage Devices
* (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
*/
@@ -56,7 +54,7 @@
#define USBH_ENABLE_CE (1<<3)
#define USBH_ENABLE_RD (1<<4)
-#ifdef LITTLEENDIAN
+#ifdef __LITTLE_ENDIAN
#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
#else
#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 856f51a..b306a65 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,11 +28,18 @@
# core
COBJS-y += usbdcore.o
COBJS-$(CONFIG_USB_OHCI_NEW) += usb_ohci.o
+COBJS-$(CONFIG_USB_EHCI) += usb_ehci_core.o
# host
COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
COBJS-$(CONFIG_USB_SL811HS) += sl811_usb.o
+COBJS-$(CONFIG_USB_EHCI_FSL) += usb_ehci_fsl.o
+COBJS-$(CONFIG_USB_EHCI_PCI) += usb_ehci_pci.o
+COBJS-$(CONFIG_USB_EHCI_IXP4XX) += usb_ehci_ixp.o
+COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_USB_DAVINCI) += davinci_usb.o
+COBJS-$(CONFIG_USB_EHCI_VCT) += usb_ehci_vct.o
# device
ifdef CONFIG_USB_DEVICE
diff --git a/drivers/usb/davinci_usb.c b/drivers/usb/davinci_usb.c
new file mode 100644
index 0000000..e66f660
--- /dev/null
+++ b/drivers/usb/davinci_usb.c
@@ -0,0 +1,106 @@
+/*
+ * TI's Davinci platform specific USB wrapper functions.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include "davinci_usb.h"
+
+/* MUSB platform configuration */
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ DAVINCI_USB_TIMEOUT,
+ 0
+};
+
+/* MUSB module register overlay */
+struct davinci_usb_regs *dregs;
+
+/*
+ * Enable the USB phy
+ */
+static u8 phy_on(void)
+{
+ u32 timeout;
+
+ /* Wait until the USB phy is turned on */
+ writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN, USBPHY_CTL_PADDR);
+ timeout = musb_cfg.timeout;
+ while (timeout--)
+ if (readl(USBPHY_CTL_PADDR) & USBPHY_PHYCLKGD)
+ return 1;
+
+ /* USB phy was not turned on */
+ return 0;
+}
+
+/*
+ * Disable the USB phy
+ */
+static void phy_off(void)
+{
+ /* powerdown the on-chip PHY and its oscillator */
+ writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, USBPHY_CTL_PADDR);
+}
+
+/*
+ * This function performs Davinci platform specific initialization for usb0.
+ */
+int musb_platform_init(void)
+{
+ u32 revision;
+
+ /* enable USB VBUS */
+ enable_vbus();
+
+ /* start the on-chip USB phy and its pll */
+ if (!phy_on())
+ return -1;
+
+ /* reset the controller */
+ dregs = (struct davinci_usb_regs *)DAVINCI_USB0_BASE;
+ writel(1, &dregs->ctrlr);
+ udelay(5000);
+
+ /* Returns zero if e.g. not clocked */
+ revision = readl(&dregs->version);
+ if (!revision)
+ return -1;
+
+ /* Disable all interrupts */
+ writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_RXINT_MASK |
+ DAVINCI_USB_TXINT_MASK , &dregs->intmsksetr);
+ return 0;
+}
+
+/*
+ * This function performs Davinci platform specific deinitialization for usb0.
+ */
+void musb_platform_deinit(void)
+{
+ /* Turn of the phy */
+ phy_off();
+
+ /* flush any interrupts */
+ writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK |
+ DAVINCI_USB_RXINT_MASK , &dregs->intclrr);
+}
diff --git a/drivers/usb/davinci_usb.h b/drivers/usb/davinci_usb.h
new file mode 100644
index 0000000..d270861
--- /dev/null
+++ b/drivers/usb/davinci_usb.h
@@ -0,0 +1,87 @@
+/*
+ * TI's Davinci platform specific USB wrapper functions.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#ifndef __DAVINCI_USB_H__
+#define __DAVINCI_USB_H__
+
+#include <asm/arch/hardware.h>
+#include "musb_core.h"
+
+/* Base address of DAVINCI usb0 wrapper */
+#define DAVINCI_USB0_BASE 0x01C64000
+
+/* Base address of DAVINCI musb core */
+#define MENTOR_USB0_BASE (DAVINCI_USB0_BASE+0x400)
+
+/*
+ * Davinci platform USB wrapper register overlay. Note: Only the required
+ * registers are included in this structure. It can be expanded as required.
+ */
+struct davinci_usb_regs {
+ u32 version;
+ u32 ctrlr;
+ u32 reserved[0x20];
+ u32 intclrr;
+ u32 intmskr;
+ u32 intmsksetr;
+};
+
+#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
+#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
+#define DAVINCI_USB_USBINT_SHIFT 16
+#define DAVINCI_USB_TXINT_SHIFT 0
+#define DAVINCI_USB_RXINT_SHIFT 8
+#define DAVINCI_INTR_DRVVBUS 0x0100
+
+#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
+#define DAVINCI_USB_TXINT_MASK \
+ (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
+#define DAVINCI_USB_RXINT_MASK \
+ (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
+#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
+ (0x80 + (8*(_bEnd)) + (_bOffset))
+
+/* Integrated highspeed/otg PHY */
+#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
+#define USBPHY_PHYCLKGD (1 << 8)
+#define USBPHY_SESNDEN (1 << 7) /* v(sess_end) comparator */
+#define USBPHY_VBDTCTEN (1 << 6) /* v(bus) comparator */
+#define USBPHY_PHYPLLON (1 << 4) /* override pll suspend */
+#define USBPHY_CLKO1SEL (1 << 3)
+#define USBPHY_OSCPDWN (1 << 2)
+#define USBPHY_PHYPDWN (1 << 0)
+
+/* Timeout for Davinci USB module */
+#define DAVINCI_USB_TIMEOUT 0x3FFFFFF
+
+/* IO Expander I2C address and VBUS enable mask */
+#define IOEXP_I2C_ADDR 0x3A
+#define IOEXP_VBUSEN_MASK 1
+
+/* extern functions */
+extern void lpsc_on(unsigned int id);
+extern int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len);
+extern int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len);
+extern void enable_vbus(void);
+#endif /* __DAVINCI_USB_H__ */
+
diff --git a/drivers/usb/musb_core.c b/drivers/usb/musb_core.c
new file mode 100644
index 0000000..ec57fc8
--- /dev/null
+++ b/drivers/usb/musb_core.c
@@ -0,0 +1,141 @@
+/*
+ * Mentor USB OTG Core functionality common for both Host and Device
+ * functionality.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+
+#include "musb_core.h"
+struct musb_regs *musbr;
+
+/*
+ * program the mentor core to start (enable interrupts, dma, etc.)
+ */
+void musb_start(void)
+{
+ u8 devctl;
+
+ /* disable all interrupts */
+ writew(0, &musbr->intrtxe);
+ writew(0, &musbr->intrrxe);
+ writeb(0, &musbr->intrusbe);
+ writeb(0, &musbr->testmode);
+
+ /* put into basic highspeed mode and start session */
+ writeb(MUSB_POWER_HSENAB, &musbr->power);
+#if defined(CONFIG_MUSB_HCD)
+ devctl = readb(&musbr->devctl);
+ writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
+#endif
+}
+
+/*
+ * This function configures the endpoint configuration. The musb hcd or musb
+ * device implementation can use this function to configure the endpoints
+ * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
+ * should not be more than the available FIFO size.
+ *
+ * epinfo - Pointer to EP configuration table
+ * cnt - Number of entries in the EP conf table.
+ */
+void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
+{
+ u16 csr;
+ u16 fifoaddr = 64; /* First 64 bytes of FIFO reserved for EP0 */
+ u32 fifosize;
+ u8 idx;
+
+ while (cnt--) {
+ /* prepare fifosize to write to register */
+ fifosize = epinfo->epsize >> 3;
+ idx = ffs(fifosize) - 1;
+
+ writeb(epinfo->epnum, &musbr->index);
+ if (epinfo->epdir) {
+ /* Configure fifo size and fifo base address */
+ writeb(idx, &musbr->txfifosz);
+ writew(fifoaddr >> 3, &musbr->txfifoadd);
+#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 */
+ if (csr & MUSB_TXCSR_TXPKTRDY)
+ writew(csr | MUSB_TXCSR_FLUSHFIFO,
+ &musbr->txcsr);
+ } else {
+ /* Configure fifo size and fifo base address */
+ writeb(idx, &musbr->rxfifosz);
+ writew(fifoaddr >> 3, &musbr->rxfifoadd);
+#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 */
+ if (csr & MUSB_RXCSR_RXPKTRDY)
+ writew(csr | MUSB_RXCSR_FLUSHFIFO,
+ &musbr->rxcsr);
+ }
+ fifoaddr += epinfo->epsize;
+ epinfo++;
+ }
+}
+
+/*
+ * This function writes data to endpoint fifo
+ *
+ * ep - endpoint number
+ * length - number of bytes to write to FIFO
+ * fifo_data - Pointer to data buffer that contains the data to write
+ */
+void write_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ u8 *data = (u8 *)fifo_data;
+
+ /* select the endpoint index */
+ writeb(ep, &musbr->index);
+
+ /* write the data to the fifo */
+ while (length--)
+ writeb(*data++, &musbr->fifox[ep]);
+}
+
+/*
+ * This function reads data from endpoint fifo
+ *
+ * ep - endpoint number
+ * length - number of bytes to read from FIFO
+ * fifo_data - pointer to data buffer into which data is read
+ */
+void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ u8 *data = (u8 *)fifo_data;
+
+ /* select the endpoint index */
+ writeb(ep, &musbr->index);
+
+ /* read the data to the fifo */
+ while (length--)
+ *data++ = readb(&musbr->fifox[ep]);
+}
diff --git a/drivers/usb/musb_core.h b/drivers/usb/musb_core.h
new file mode 100644
index 0000000..9f5ebe7
--- /dev/null
+++ b/drivers/usb/musb_core.h
@@ -0,0 +1,317 @@
+/******************************************************************
+ * Copyright 2008 Mentor Graphics Corporation
+ * Copyright (C) 2008 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+#include <usb.h>
+#include <usb_defs.h>
+#include <asm/io.h>
+
+#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+
+/* Mentor USB core register overlay structure */
+struct musb_regs {
+ /* common registers */
+ u8 faddr;
+ u8 power;
+ u16 intrtx;
+ u16 intrrx;
+ u16 intrtxe;
+ u16 intrrxe;
+ u8 intrusb;
+ u8 intrusbe;
+ u16 frame;
+ u8 index;
+ u8 testmode;
+ /* indexed registers */
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+ /* fifo */
+ u32 fifox[16];
+ /* OTG, dynamic FIFO, version & vendor registers */
+ u8 devctl;
+ u8 reserved1;
+ u8 txfifosz;
+ u8 rxfifosz;
+ u16 txfifoadd;
+ u16 rxfifoadd;
+ u32 vcontrol;
+ u16 hwvers;
+ u16 reserved2[5];
+ u8 epinfo;
+ u8 raminfo;
+ u8 linkinfo;
+ u8 vplen;
+ u8 hseof1;
+ u8 fseof1;
+ u8 lseof1;
+ u8 reserved3;
+ /* target address registers */
+ struct musb_tar_regs {
+ u8 txfuncaddr;
+ u8 reserved0;
+ u8 txhubaddr;
+ u8 txhubport;
+ u8 rxfuncaddr;
+ u8 reserved1;
+ u8 rxhubaddr;
+ u8 rxhubport;
+ } tar[16];
+} __attribute((aligned(32)));
+
+/*
+ * MUSB Register bits
+ */
+
+/* POWER */
+#define MUSB_POWER_ISOUPDATE 0x80
+#define MUSB_POWER_SOFTCONN 0x40
+#define MUSB_POWER_HSENAB 0x20
+#define MUSB_POWER_HSMODE 0x10
+#define MUSB_POWER_RESET 0x08
+#define MUSB_POWER_RESUME 0x04
+#define MUSB_POWER_SUSPENDM 0x02
+#define MUSB_POWER_ENSUSPEND 0x01
+#define MUSB_POWER_HSMODE_SHIFT 4
+
+/* INTRUSB */
+#define MUSB_INTR_SUSPEND 0x01
+#define MUSB_INTR_RESUME 0x02
+#define MUSB_INTR_RESET 0x04
+#define MUSB_INTR_BABBLE 0x04
+#define MUSB_INTR_SOF 0x08
+#define MUSB_INTR_CONNECT 0x10
+#define MUSB_INTR_DISCONNECT 0x20
+#define MUSB_INTR_SESSREQ 0x40
+#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
+
+/* DEVCTL */
+#define MUSB_DEVCTL_BDEVICE 0x80
+#define MUSB_DEVCTL_FSDEV 0x40
+#define MUSB_DEVCTL_LSDEV 0x20
+#define MUSB_DEVCTL_VBUS 0x18
+#define MUSB_DEVCTL_VBUS_SHIFT 3
+#define MUSB_DEVCTL_HM 0x04
+#define MUSB_DEVCTL_HR 0x02
+#define MUSB_DEVCTL_SESSION 0x01
+
+/* TESTMODE */
+#define MUSB_TEST_FORCE_HOST 0x80
+#define MUSB_TEST_FIFO_ACCESS 0x40
+#define MUSB_TEST_FORCE_FS 0x20
+#define MUSB_TEST_FORCE_HS 0x10
+#define MUSB_TEST_PACKET 0x08
+#define MUSB_TEST_K 0x04
+#define MUSB_TEST_J 0x02
+#define MUSB_TEST_SE0_NAK 0x01
+
+/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MUSB_FIFOSZ_DPB 0x10
+/* Allocation size (8, 16, 32, ... 4096) */
+#define MUSB_FIFOSZ_SIZE 0x0f
+
+/* CSR0 */
+#define MUSB_CSR0_FLUSHFIFO 0x0100
+#define MUSB_CSR0_TXPKTRDY 0x0002
+#define MUSB_CSR0_RXPKTRDY 0x0001
+
+/* CSR0 in Peripheral mode */
+#define MUSB_CSR0_P_SVDSETUPEND 0x0080
+#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
+#define MUSB_CSR0_P_SENDSTALL 0x0020
+#define MUSB_CSR0_P_SETUPEND 0x0010
+#define MUSB_CSR0_P_DATAEND 0x0008
+#define MUSB_CSR0_P_SENTSTALL 0x0004
+
+/* CSR0 in Host mode */
+#define MUSB_CSR0_H_DIS_PING 0x0800
+#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
+#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
+#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
+#define MUSB_CSR0_H_STATUSPKT 0x0040
+#define MUSB_CSR0_H_REQPKT 0x0020
+#define MUSB_CSR0_H_ERROR 0x0010
+#define MUSB_CSR0_H_SETUPPKT 0x0008
+#define MUSB_CSR0_H_RXSTALL 0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_CSR0_P_WZC_BITS \
+ (MUSB_CSR0_P_SENTSTALL)
+#define MUSB_CSR0_H_WZC_BITS \
+ (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
+ | MUSB_CSR0_RXPKTRDY)
+
+/* TxType/RxType */
+#define MUSB_TYPE_SPEED 0xc0
+#define MUSB_TYPE_SPEED_SHIFT 6
+#define MUSB_TYPE_SPEED_HIGH 1
+#define MUSB_TYPE_SPEED_FULL 2
+#define MUSB_TYPE_SPEED_LOW 3
+#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_SHIFT 4
+#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_BULK 2
+#define MUSB_TYPE_PROTO_INTR 3
+
+/* CONFIGDATA */
+#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
+#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
+#define MUSB_CONFIGDATA_BIGENDIAN 0x20
+#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
+#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
+#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
+#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
+#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+#define MUSB_TXCSR_AUTOSET 0x8000
+#define MUSB_TXCSR_MODE 0x2000
+#define MUSB_TXCSR_DMAENAB 0x1000
+#define MUSB_TXCSR_FRCDATATOG 0x0800
+#define MUSB_TXCSR_DMAMODE 0x0400
+#define MUSB_TXCSR_CLRDATATOG 0x0040
+#define MUSB_TXCSR_FLUSHFIFO 0x0008
+#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
+#define MUSB_TXCSR_TXPKTRDY 0x0001
+
+/* TXCSR in Peripheral mode */
+#define MUSB_TXCSR_P_ISO 0x4000
+#define MUSB_TXCSR_P_INCOMPTX 0x0080
+#define MUSB_TXCSR_P_SENTSTALL 0x0020
+#define MUSB_TXCSR_P_SENDSTALL 0x0010
+#define MUSB_TXCSR_P_UNDERRUN 0x0004
+
+/* TXCSR in Host mode */
+#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
+#define MUSB_TXCSR_H_DATATOGGLE 0x0100
+#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
+#define MUSB_TXCSR_H_RXSTALL 0x0020
+#define MUSB_TXCSR_H_ERROR 0x0004
+#define MUSB_TXCSR_H_DATATOGGLE_SHIFT 8
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_TXCSR_P_WZC_BITS \
+ (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
+ | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
+#define MUSB_TXCSR_H_WZC_BITS \
+ (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+ | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
+
+/* RXCSR in Peripheral and Host mode */
+#define MUSB_RXCSR_AUTOCLEAR 0x8000
+#define MUSB_RXCSR_DMAENAB 0x2000
+#define MUSB_RXCSR_DISNYET 0x1000
+#define MUSB_RXCSR_PID_ERR 0x1000
+#define MUSB_RXCSR_DMAMODE 0x0800
+#define MUSB_RXCSR_INCOMPRX 0x0100
+#define MUSB_RXCSR_CLRDATATOG 0x0080
+#define MUSB_RXCSR_FLUSHFIFO 0x0010
+#define MUSB_RXCSR_DATAERROR 0x0008
+#define MUSB_RXCSR_FIFOFULL 0x0002
+#define MUSB_RXCSR_RXPKTRDY 0x0001
+
+/* RXCSR in Peripheral mode */
+#define MUSB_RXCSR_P_ISO 0x4000
+#define MUSB_RXCSR_P_SENTSTALL 0x0040
+#define MUSB_RXCSR_P_SENDSTALL 0x0020
+#define MUSB_RXCSR_P_OVERRUN 0x0004
+
+/* RXCSR in Host mode */
+#define MUSB_RXCSR_H_AUTOREQ 0x4000
+#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
+#define MUSB_RXCSR_H_DATATOGGLE 0x0200
+#define MUSB_RXCSR_H_RXSTALL 0x0040
+#define MUSB_RXCSR_H_REQPKT 0x0020
+#define MUSB_RXCSR_H_ERROR 0x0004
+#define MUSB_S_RXCSR_H_DATATOGGLE 9
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_RXCSR_P_WZC_BITS \
+ (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
+ | MUSB_RXCSR_RXPKTRDY)
+#define MUSB_RXCSR_H_WZC_BITS \
+ (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
+ | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
+
+/* HUBADDR */
+#define MUSB_HUBADDR_MULTI_TT 0x80
+
+/* Endpoint configuration information. Note: The value of endpoint fifo size
+ * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other
+ * values are not supported
+ */
+struct musb_epinfo {
+ u8 epnum; /* endpoint number */
+ u8 epdir; /* endpoint direction */
+ u16 epsize; /* endpoint FIFO size */
+};
+
+/*
+ * Platform specific MUSB configuration. Any platform using the musb
+ * functionality should create one instance of this structure in the
+ * platform specific file.
+ */
+struct musb_config {
+ struct musb_regs *regs;
+ u32 timeout;
+ u8 musb_speed;
+};
+
+/* externally defined data */
+extern struct musb_config musb_cfg;
+extern struct musb_regs *musbr;
+
+/* exported functions */
+extern void musb_start(void);
+extern void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt);
+extern void write_fifo(u8 ep, u32 length, void *fifo_data);
+extern void read_fifo(u8 ep, u32 length, void *fifo_data);
+
+/* extern functions */
+extern inline void musb_writew(u32 offset, u16 value);
+extern inline void musb_writeb(u32 offset, u8 value);
+extern inline u16 musb_readw(u32 offset);
+extern inline u8 musb_readb(u32 offset);
+
+#endif /* __MUSB_HDRC_DEFS_H__ */
+
diff --git a/drivers/usb/musb_hcd.c b/drivers/usb/musb_hcd.c
new file mode 100644
index 0000000..352a0d4
--- /dev/null
+++ b/drivers/usb/musb_hcd.c
@@ -0,0 +1,792 @@
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include "musb_hcd.h"
+
+/* MSC control transfers */
+#define USB_MSC_BBB_RESET 0xFF
+#define USB_MSC_BBB_GET_MAX_LUN 0xFE
+
+/* Endpoint configuration information */
+static struct musb_epinfo epinfo[3] = {
+ {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
+ {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */
+ {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */
+};
+
+/*
+ * This function writes the data toggle value.
+ */
+static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
+{
+ u16 toggle = usb_gettoggle(dev, ep, dir_out);
+ u16 csr;
+
+ if (dir_out) {
+ if (!toggle)
+ writew(MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
+ else {
+ csr = readw(&musbr->txcsr);
+ csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
+ writew(csr, &musbr->txcsr);
+ csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
+ writew(csr, &musbr->txcsr);
+ }
+ } else {
+ if (!toggle)
+ writew(MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
+ else {
+ csr = readw(&musbr->rxcsr);
+ csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
+ writew(csr, &musbr->rxcsr);
+ csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
+ writew(csr, &musbr->rxcsr);
+ }
+ }
+}
+
+/*
+ * This function checks if RxStall has occured on the endpoint. If a RxStall
+ * has occured, the RxStall is cleared and 1 is returned. If RxStall has
+ * not occured, 0 is returned.
+ */
+static u8 check_stall(u8 ep, u8 dir_out)
+{
+ u16 csr;
+
+ /* For endpoint 0 */
+ if (!ep) {
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_CSR0_H_RXSTALL) {
+ csr &= ~MUSB_CSR0_H_RXSTALL;
+ writew(csr, &musbr->txcsr);
+ return 1;
+ }
+ } else { /* For non-ep0 */
+ if (dir_out) { /* is it tx ep */
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_TXCSR_H_RXSTALL) {
+ csr &= ~MUSB_TXCSR_H_RXSTALL;
+ writew(csr, &musbr->txcsr);
+ return 1;
+ }
+ } else { /* is it rx ep */
+ csr = readw(&musbr->rxcsr);
+ if (csr & MUSB_RXCSR_H_RXSTALL) {
+ csr &= ~MUSB_RXCSR_H_RXSTALL;
+ writew(csr, &musbr->rxcsr);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
+ * error and -2 for stall.
+ */
+static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
+{
+ u16 csr;
+ int result = 1;
+
+ while (result > 0) {
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_CSR0_H_ERROR) {
+ csr &= ~MUSB_CSR0_H_ERROR;
+ writew(csr, &musbr->txcsr);
+ dev->status = USB_ST_CRC_ERR;
+ result = -1;
+ break;
+ }
+
+ switch (bit_mask) {
+ case MUSB_CSR0_TXPKTRDY:
+ if (!(csr & MUSB_CSR0_TXPKTRDY)) {
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ result = -2;
+ } else
+ result = 0;
+ }
+ break;
+
+ case MUSB_CSR0_RXPKTRDY:
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ result = -2;
+ } else
+ if (csr & MUSB_CSR0_RXPKTRDY)
+ result = 0;
+ break;
+
+ case MUSB_CSR0_H_REQPKT:
+ if (!(csr & MUSB_CSR0_H_REQPKT)) {
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ result = -2;
+ } else
+ result = 0;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static u8 wait_until_txep_ready(struct usb_device *dev, u8 ep)
+{
+ u16 csr;
+
+ do {
+ if (check_stall(ep, 1)) {
+ dev->status = USB_ST_STALLED;
+ return 0;
+ }
+
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_TXCSR_H_ERROR) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+ } while (csr & MUSB_TXCSR_TXPKTRDY);
+ return 1;
+}
+
+/*
+ * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static u8 wait_until_rxep_ready(struct usb_device *dev, u8 ep)
+{
+ u16 csr;
+
+ do {
+ if (check_stall(ep, 0)) {
+ dev->status = USB_ST_STALLED;
+ return 0;
+ }
+
+ csr = readw(&musbr->rxcsr);
+ if (csr & MUSB_RXCSR_H_ERROR) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+ } while (!(csr & MUSB_RXCSR_RXPKTRDY));
+ return 1;
+}
+
+/*
+ * This function performs the setup phase of the control transfer
+ */
+static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
+{
+ int result;
+ u16 csr;
+
+ /* write the control request to ep0 fifo */
+ write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
+
+ /* enable transfer of setup packet */
+ csr = readw(&musbr->txcsr);
+ csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
+ writew(csr, &musbr->txcsr);
+
+ /* wait until the setup packet is transmitted */
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+ dev->act_len = 0;
+ return result;
+}
+
+/*
+ * This function handles the control transfer in data phase
+ */
+static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+ u16 csr;
+ u32 rxlen = 0;
+ u32 nextlen = 0;
+ u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
+ u8 *rxbuff = (u8 *)buffer;
+ u8 rxedlength;
+ int result;
+
+ while (rxlen < len) {
+ /* Determine the next read length */
+ nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
+
+ /* Set the ReqPkt bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
+ if (result < 0)
+ return result;
+
+ /* Actual number of bytes received by usb */
+ rxedlength = readb(&musbr->rxcount);
+
+ /* Read the data from the RxFIFO */
+ read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
+
+ /* Clear the RxPktRdy Bit */
+ csr = readw(&musbr->txcsr);
+ csr &= ~MUSB_CSR0_RXPKTRDY;
+ writew(csr, &musbr->txcsr);
+
+ /* short packet? */
+ if (rxedlength != nextlen) {
+ dev->act_len += rxedlength;
+ break;
+ }
+ rxlen += nextlen;
+ dev->act_len = rxlen;
+ }
+ return 0;
+}
+
+/*
+ * This function handles the control transfer out data phase
+ */
+static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
+ u8 *txbuff = (u8 *)buffer;
+ int result = 0;
+
+ while (txlen < len) {
+ /* Determine the next write length */
+ nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
+
+ /* Load the data to send in FIFO */
+ write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
+
+ /* Set TXPKTRDY bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY,
+ &musbr->txcsr);
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+ if (result < 0)
+ break;
+
+ txlen += nextlen;
+ dev->act_len = txlen;
+ }
+ return result;
+}
+
+/*
+ * This function handles the control transfer out status phase
+ */
+static int ctrlreq_out_status_phase(struct usb_device *dev)
+{
+ u16 csr;
+ int result;
+
+ /* Set the StatusPkt bit */
+ csr = readw(&musbr->txcsr);
+ csr |= (MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY |
+ MUSB_CSR0_H_STATUSPKT);
+ writew(csr, &musbr->txcsr);
+
+ /* Wait until TXPKTRDY bit is cleared */
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+ return result;
+}
+
+/*
+ * This function handles the control transfer in status phase
+ */
+static int ctrlreq_in_status_phase(struct usb_device *dev)
+{
+ u16 csr;
+ int result;
+
+ /* Set the StatusPkt bit and ReqPkt bit */
+ csr = MUSB_CSR0_H_DIS_PING | MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
+ writew(csr, &musbr->txcsr);
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
+
+ /* clear StatusPkt bit and RxPktRdy bit */
+ csr = readw(&musbr->txcsr);
+ csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
+ writew(csr, &musbr->txcsr);
+ return result;
+}
+
+/*
+ * determines the speed of the device (High/Full/Slow)
+ */
+static u8 get_dev_speed(struct usb_device *dev)
+{
+ return (dev->speed & USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
+ ((dev->speed & USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
+ MUSB_TYPE_SPEED_FULL);
+}
+
+/*
+ * configure the hub address and the port address.
+ */
+static void config_hub_port(struct usb_device *dev, u8 ep)
+{
+ u8 chid;
+ u8 hub;
+
+ /* Find out the nearest parent which is high speed */
+ while (dev->parent->parent != NULL)
+ if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH)
+ dev = dev->parent;
+ else
+ break;
+
+ /* determine the port address at that hub */
+ hub = dev->parent->devnum;
+ for (chid = 0; chid < USB_MAXCHILDREN; chid++)
+ if (dev->parent->children[chid] == dev)
+ break;
+
+ /* configure the hub address and the port address */
+ writeb(hub, &musbr->tar[ep].txhubaddr);
+ writeb((chid + 1), &musbr->tar[ep].txhubport);
+ writeb(hub, &musbr->tar[ep].rxhubaddr);
+ writeb((chid + 1), &musbr->tar[ep].rxhubport);
+}
+
+/*
+ * do a control transfer
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, struct devrequest *setup)
+{
+ int devnum = usb_pipedevice(pipe);
+ u16 csr;
+ u8 devspeed;
+
+ /* select control endpoint */
+ writeb(MUSB_CONTROL_EP, &musbr->index);
+ csr = readw(&musbr->txcsr);
+
+ /* target addr and (for multipoint) hub addr/port */
+ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
+ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
+
+ /* configure the hub address and the port number as required */
+ devspeed = get_dev_speed(dev);
+ if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+ (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+ config_hub_port(dev, MUSB_CONTROL_EP);
+ writeb(devspeed << 6, &musbr->txtype);
+ } else {
+ writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
+ }
+
+ /* Control transfer setup phase */
+ if (ctrlreq_setup_phase(dev, setup) < 0)
+ return 0;
+
+ switch (setup->request) {
+ case USB_REQ_GET_DESCRIPTOR:
+ case USB_REQ_GET_CONFIGURATION:
+ case USB_REQ_GET_INTERFACE:
+ case USB_REQ_GET_STATUS:
+ case USB_MSC_BBB_GET_MAX_LUN:
+ /* control transfer in-data-phase */
+ if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
+ return 0;
+ /* control transfer out-status-phase */
+ if (ctrlreq_out_status_phase(dev) < 0)
+ return 0;
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ case USB_REQ_SET_CONFIGURATION:
+ case USB_REQ_SET_FEATURE:
+ case USB_REQ_SET_INTERFACE:
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_MSC_BBB_RESET:
+ /* control transfer in status phase */
+ if (ctrlreq_in_status_phase(dev) < 0)
+ return 0;
+ break;
+
+ case USB_REQ_SET_DESCRIPTOR:
+ /* control transfer out data phase */
+ if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
+ return 0;
+ /* control transfer in status phase */
+ if (ctrlreq_in_status_phase(dev) < 0)
+ return 0;
+ break;
+
+ default:
+ /* unhandled control transfer */
+ return -1;
+ }
+
+ dev->status = 0;
+ dev->act_len = len;
+ return len;
+}
+
+/*
+ * do a bulk transfer
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int len)
+{
+ int dir_out = usb_pipeout(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ int devnum = usb_pipedevice(pipe);
+ u8 type;
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 devspeed;
+
+ /* select bulk endpoint */
+ writeb(MUSB_BULK_EP, &musbr->index);
+
+ /* write the address of the device */
+ if (dir_out)
+ writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
+ else
+ writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
+
+ /* configure the hub address and the port number as required */
+ devspeed = get_dev_speed(dev);
+ if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+ (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+ /*
+ * MUSB is in high speed and the destination device is full
+ * speed device. So configure the hub address and port
+ * address registers.
+ */
+ config_hub_port(dev, MUSB_BULK_EP);
+ } else {
+ if (dir_out) {
+ writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
+ writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
+ } else {
+ writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
+ writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
+ }
+ devspeed = musb_cfg.musb_speed;
+ }
+
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+
+ if (dir_out) { /* bulk-out transfer */
+ /* Program the TxType register */
+ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+ (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+ (ep & MUSB_TYPE_REMOTE_END);
+ writeb(type, &musbr->txtype);
+
+ /* Write maximum packet size to the TxMaxp register */
+ writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
+ while (txlen < len) {
+ nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
+ (len-txlen) : dev->epmaxpacketout[ep];
+
+ /* Write the data to the FIFO */
+ write_fifo(MUSB_BULK_EP, nextlen,
+ (void *)(((u8 *)buffer) + txlen));
+
+ /* Set the TxPktRdy bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
+
+ /* Wait until the TxPktRdy bit is cleared */
+ if (!wait_until_txep_ready(dev, MUSB_BULK_EP)) {
+ readw(&musbr->txcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+ dev->act_len = txlen;
+ return 0;
+ }
+ txlen += nextlen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ csr = readw(&musbr->txcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+ } else { /* bulk-in transfer */
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+
+ /* Program the RxType register */
+ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+ (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+ (ep & MUSB_TYPE_REMOTE_END);
+ writeb(type, &musbr->rxtype);
+
+ /* Write the maximum packet size to the RxMaxp register */
+ writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+ while (txlen < len) {
+ nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+ (len-txlen) : dev->epmaxpacketin[ep];
+
+ /* Set the ReqPkt bit */
+ writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+ /* Wait until the RxPktRdy bit is set */
+ if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) {
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ dev->act_len = txlen;
+ return 0;
+ }
+
+ /* Read the data from the FIFO */
+ read_fifo(MUSB_BULK_EP, nextlen,
+ (void *)(((u8 *)buffer) + txlen));
+
+ /* Clear the RxPktRdy bit */
+ csr = readw(&musbr->rxcsr);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ txlen += nextlen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ }
+
+ /* bulk transfer is complete */
+ dev->status = 0;
+ dev->act_len = len;
+ return 0;
+}
+
+/*
+ * This function initializes the usb controller module.
+ */
+int usb_lowlevel_init(void)
+{
+ u8 power;
+ u32 timeout;
+
+ if (musb_platform_init() == -1)
+ return -1;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ musb_start();
+
+ /*
+ * Wait until musb is enabled in host mode with a timeout. There
+ * should be a usb device connected.
+ */
+ timeout = musb_cfg.timeout;
+ while (timeout--)
+ if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
+ break;
+
+ /* if musb core is not in host mode, then return */
+ if (!timeout)
+ return -1;
+
+ /* start usb bus reset */
+ power = readb(&musbr->power);
+ writeb(power | MUSB_POWER_RESET, &musbr->power);
+
+ /* After initiating a usb reset, wait for about 20ms to 30ms */
+ udelay(30000);
+
+ /* stop usb bus reset */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_RESET;
+ writeb(power, &musbr->power);
+
+ /* Determine if the connected device is a high/full/low speed device */
+ musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
+ MUSB_TYPE_SPEED_HIGH :
+ ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
+ MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
+ return 0;
+}
+
+/*
+ * This function stops the operation of the davinci usb module.
+ */
+int usb_lowlevel_stop(void)
+{
+ /* Reset the USB module */
+ musb_platform_deinit();
+ writeb(0, &musbr->devctl);
+ return 0;
+}
+
+/*
+ * This function supports usb interrupt transfers. Currently, usb interrupt
+ * transfers are not supported.
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int len, int interval)
+{
+ int dir_out = usb_pipeout(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ int devnum = usb_pipedevice(pipe);
+ u8 type;
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 devspeed;
+
+ /* select interrupt endpoint */
+ writeb(MUSB_INTR_EP, &musbr->index);
+
+ /* write the address of the device */
+ if (dir_out)
+ writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
+ else
+ writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
+
+ /* configure the hub address and the port number as required */
+ devspeed = get_dev_speed(dev);
+ if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+ (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+ /*
+ * MUSB is in high speed and the destination device is full
+ * speed device. So configure the hub address and port
+ * address registers.
+ */
+ config_hub_port(dev, MUSB_INTR_EP);
+ } else {
+ if (dir_out) {
+ writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
+ writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
+ } else {
+ writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
+ writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
+ }
+ devspeed = musb_cfg.musb_speed;
+ }
+
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+
+ if (!dir_out) { /* intrrupt-in transfer */
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+ writeb(interval, &musbr->rxinterval);
+
+ /* Program the RxType register */
+ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+ (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
+ (ep & MUSB_TYPE_REMOTE_END);
+ writeb(type, &musbr->rxtype);
+
+ /* Write the maximum packet size to the RxMaxp register */
+ writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+
+ while (txlen < len) {
+ nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+ (len-txlen) : dev->epmaxpacketin[ep];
+
+ /* Set the ReqPkt bit */
+ writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+ /* Wait until the RxPktRdy bit is set */
+ if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) {
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ dev->act_len = txlen;
+ return 0;
+ }
+
+ /* Read the data from the FIFO */
+ read_fifo(MUSB_INTR_EP, nextlen,
+ (void *)(((u8 *)buffer) + txlen));
+
+ /* Clear the RxPktRdy bit */
+ csr = readw(&musbr->rxcsr);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ txlen += nextlen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ }
+
+ /* interrupt transfer is complete */
+ dev->irq_status = 0;
+ dev->irq_act_len = len;
+ dev->irq_handle(dev);
+ dev->status = 0;
+ dev->act_len = len;
+ return 0;
+}
+
+
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+/*
+ * This function polls for USB keyboard data.
+ */
+void usb_event_poll()
+{
+ device_t *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_interface_descriptor *iface;
+ struct usb_endpoint_descriptor *ep;
+ int pipe;
+ int maxp;
+
+ /* Get the pointer to USB Keyboard device pointer */
+ dev = device_get_by_name("usbkbd");
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ iface = &usb_kbd_dev->config.if_desc[0];
+ ep = &iface->ep_desc[0];
+ pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+ /* Submit a interrupt transfer request */
+ maxp = usb_maxpacket(usb_kbd_dev, pipe);
+ usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
+ maxp > 8 ? 8 : maxp, ep->bInterval);
+}
+#endif /* CONFIG_SYS_USB_EVENT_POLL */
diff --git a/drivers/usb/musb_hcd.h b/drivers/usb/musb_hcd.h
new file mode 100644
index 0000000..bb83311
--- /dev/null
+++ b/drivers/usb/musb_hcd.h
@@ -0,0 +1,51 @@
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#ifndef __MUSB_HCD_H__
+#define __MUSB_HCD_H__
+
+#include "musb_core.h"
+#ifdef CONFIG_USB_KEYBOARD
+#include <devices.h>
+extern unsigned char new[];
+#endif
+
+/* This defines the endpoint number used for control transfers */
+#define MUSB_CONTROL_EP 0
+
+/* This defines the endpoint number used for bulk transfer */
+#define MUSB_BULK_EP 1
+
+/* This defines the endpoint number used for interrupt transfer */
+#define MUSB_INTR_EP 2
+
+/* Determine the operating speed of MUSB core */
+#define musb_ishighspeed() \
+ ((readb(&musbr->power) & MUSB_POWER_HSMODE) \
+ >> MUSB_POWER_HSMODE_SHIFT)
+
+/* extern functions */
+extern int musb_platform_init(void);
+extern void musb_platform_deinit(void);
+
+#endif /* __MUSB_HCD_H__ */
diff --git a/drivers/usb/usb_ehci.h b/drivers/usb/usb_ehci.h
new file mode 100644
index 0000000..b3c1d5d
--- /dev/null
+++ b/drivers/usb/usb_ehci.h
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ * All rights reserved.
+ *
+ * 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 version 2 of
+ * the License.
+ *
+ * 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 USB_EHCI_H
+#define USB_EHCI_H
+
+#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
+#endif
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+ ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
+
+#define DeviceOutRequest \
+ ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
+
+#define InterfaceRequest \
+ ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+#define EndpointRequest \
+ ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+#define EndpointOutRequest \
+ ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+/*
+ * Register Space.
+ */
+struct ehci_hccr {
+ uint32_t cr_capbase;
+#define HC_LENGTH(p) (((p) >> 0) & 0x00ff)
+#define HC_VERSION(p) (((p) >> 16) & 0xffff)
+ uint32_t cr_hcsparams;
+#define HCS_PPC(p) ((p) & (1 << 4))
+#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */
+#define HCS_N_PORTS(p) (((p) >> 0) & 0xf)
+ uint32_t cr_hccparams;
+ uint8_t cr_hcsp_portrt[8];
+} __attribute__ ((packed));
+
+struct ehci_hcor {
+ uint32_t or_usbcmd;
+#define CMD_PARK (1 << 11) /* enable "park" */
+#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */
+#define CMD_ASE (1 << 5) /* async schedule enable */
+#define CMD_LRESET (1 << 7) /* partial reset */
+#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */
+#define CMD_PSE (1 << 4) /* periodic schedule enable */
+#define CMD_RESET (1 << 1) /* reset HC not bus */
+#define CMD_RUN (1 << 0) /* start/stop HC */
+ uint32_t or_usbsts;
+#define STD_ASS (1 << 15)
+#define STS_HALT (1 << 12)
+ uint32_t or_usbintr;
+ uint32_t or_frindex;
+ uint32_t or_ctrldssegment;
+ uint32_t or_periodiclistbase;
+ uint32_t or_asynclistaddr;
+ uint32_t _reserved_[9];
+ uint32_t or_configflag;
+#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
+ uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
+ uint32_t or_systune;
+} __attribute__ ((packed));
+
+#define USBMODE 0x68 /* USB Device mode */
+#define USBMODE_SDIS (1 << 3) /* Stream disable */
+#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */
+#define USBMODE_CM_HC (3 << 0) /* host controller mode */
+#define USBMODE_CM_IDLE (0 << 0) /* idle state */
+
+/* Interface descriptor */
+struct usb_linux_interface_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned char bInterfaceNumber;
+ unsigned char bAlternateSetting;
+ unsigned char bNumEndpoints;
+ unsigned char bInterfaceClass;
+ unsigned char bInterfaceSubClass;
+ unsigned char bInterfaceProtocol;
+ unsigned char iInterface;
+} __attribute__ ((packed));
+
+/* Configuration descriptor information.. */
+struct usb_linux_config_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short wTotalLength;
+ unsigned char bNumInterfaces;
+ unsigned char bConfigurationValue;
+ unsigned char iConfiguration;
+ unsigned char bmAttributes;
+ unsigned char MaxPower;
+} __attribute__ ((packed));
+
+#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
+#define ehci_readl(x) (*((volatile u32 *)(x)))
+#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b))
+#else
+#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x))))
+#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \
+ cpu_to_le32(((volatile u32)b)))
+#endif
+
+#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
+#define hc32_to_cpu(x) be32_to_cpu((x))
+#define cpu_to_hc32(x) cpu_to_be32((x))
+#else
+#define hc32_to_cpu(x) le32_to_cpu((x))
+#define cpu_to_hc32(x) cpu_to_le32((x))
+#endif
+
+#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */
+#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */
+#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */
+#define EHCI_PS_PO (1 << 13) /* RW port owner */
+#define EHCI_PS_PP (1 << 12) /* RW,RO port power */
+#define EHCI_PS_LS (3 << 10) /* RO line status */
+#define EHCI_PS_PR (1 << 8) /* RW port reset */
+#define EHCI_PS_SUSP (1 << 7) /* RW suspend */
+#define EHCI_PS_FPR (1 << 6) /* RW force port resume */
+#define EHCI_PS_OCC (1 << 5) /* RWC over current change */
+#define EHCI_PS_OCA (1 << 4) /* RO over current active */
+#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */
+#define EHCI_PS_PE (1 << 2) /* RW port enable */
+#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */
+#define EHCI_PS_CS (1 << 0) /* RO connect status */
+#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
+
+#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10))
+
+/*
+ * Schedule Interface Space.
+ *
+ * IMPORTANT: Software must ensure that no interface data structure
+ * reachable by the EHCI host controller spans a 4K page boundary!
+ *
+ * Periodic transfers (i.e. isochronous and interrupt transfers) are
+ * not supported.
+ */
+
+/* Queue Element Transfer Descriptor (qTD). */
+struct qTD {
+ uint32_t qt_next;
+#define QT_NEXT_TERMINATE 1
+ uint32_t qt_altnext;
+ uint32_t qt_token;
+ uint32_t qt_buffer[5];
+};
+
+/* Queue Head (QH). */
+struct QH {
+ uint32_t qh_link;
+#define QH_LINK_TERMINATE 1
+#define QH_LINK_TYPE_ITD 0
+#define QH_LINK_TYPE_QH 2
+#define QH_LINK_TYPE_SITD 4
+#define QH_LINK_TYPE_FSTN 6
+ uint32_t qh_endpt1;
+ uint32_t qh_endpt2;
+ uint32_t qh_curtd;
+ struct qTD qh_overlay;
+ /*
+ * Add dummy fill value to make the size of this struct
+ * aligned to 32 bytes
+ */
+ uint8_t fill[16];
+};
+
+/* Low level init functions */
+int ehci_hcd_init(void);
+int ehci_hcd_stop(void);
+
+#endif /* USB_EHCI_H */
diff --git a/drivers/usb/usb_ehci_core.c b/drivers/usb/usb_ehci_core.c
new file mode 100644
index 0000000..813f64a
--- /dev/null
+++ b/drivers/usb/usb_ehci_core.c
@@ -0,0 +1,880 @@
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Excito Elektronik i Skåne AB
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * All rights reserved.
+ *
+ * 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 version 2 of
+ * the License.
+ *
+ * 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 <asm/byteorder.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include "usb_ehci.h"
+
+int rootdev;
+struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
+volatile struct ehci_hcor *hcor;
+
+static uint16_t portreset;
+static struct QH qh_list __attribute__((aligned(32)));
+
+static struct descriptor {
+ struct usb_hub_descriptor hub;
+ struct usb_device_descriptor device;
+ struct usb_linux_config_descriptor config;
+ struct usb_linux_interface_descriptor interface;
+ struct usb_endpoint_descriptor endpoint;
+} __attribute__ ((packed)) descriptor = {
+ {
+ 0x8, /* bDescLength */
+ 0x29, /* bDescriptorType: hub descriptor */
+ 2, /* bNrPorts -- runtime modified */
+ 0, /* wHubCharacteristics */
+ 0xff, /* bPwrOn2PwrGood */
+ 0, /* bHubCntrCurrent */
+ {}, /* Device removable */
+ {} /* at most 7 ports! XXX */
+ },
+ {
+ 0x12, /* bLength */
+ 1, /* bDescriptorType: UDESC_DEVICE */
+ 0x0002, /* bcdUSB: v2.0 */
+ 9, /* bDeviceClass: UDCLASS_HUB */
+ 0, /* bDeviceSubClass: UDSUBCLASS_HUB */
+ 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
+ 64, /* bMaxPacketSize: 64 bytes */
+ 0x0000, /* idVendor */
+ 0x0000, /* idProduct */
+ 0x0001, /* bcdDevice */
+ 1, /* iManufacturer */
+ 2, /* iProduct */
+ 0, /* iSerialNumber */
+ 1 /* bNumConfigurations: 1 */
+ },
+ {
+ 0x9,
+ 2, /* bDescriptorType: UDESC_CONFIG */
+ cpu_to_le16(0x19),
+ 1, /* bNumInterface */
+ 1, /* bConfigurationValue */
+ 0, /* iConfiguration */
+ 0x40, /* bmAttributes: UC_SELF_POWER */
+ 0 /* bMaxPower */
+ },
+ {
+ 0x9, /* bLength */
+ 4, /* bDescriptorType: UDESC_INTERFACE */
+ 0, /* bInterfaceNumber */
+ 0, /* bAlternateSetting */
+ 1, /* bNumEndpoints */
+ 9, /* bInterfaceClass: UICLASS_HUB */
+ 0, /* bInterfaceSubClass: UISUBCLASS_HUB */
+ 0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */
+ 0 /* iInterface */
+ },
+ {
+ 0x7, /* bLength */
+ 5, /* bDescriptorType: UDESC_ENDPOINT */
+ 0x81, /* bEndpointAddress:
+ * UE_DIR_IN | EHCI_INTR_ENDPT
+ */
+ 3, /* bmAttributes: UE_INTERRUPT */
+ 8, 0, /* wMaxPacketSize */
+ 255 /* bInterval */
+ },
+};
+
+#if defined(CONFIG_EHCI_IS_TDI)
+#define ehci_is_TDI() (1)
+#else
+#define ehci_is_TDI() (0)
+#endif
+
+#if defined(CONFIG_EHCI_DCACHE)
+/*
+ * Routines to handle (flush/invalidate) the dcache for the QH and qTD
+ * structures and data buffers. This is needed on platforms using this
+ * EHCI support with dcache enabled.
+ */
+static void flush_invalidate(u32 addr, int size, int flush)
+{
+ if (flush)
+ flush_dcache_range(addr, addr + size);
+ else
+ invalidate_dcache_range(addr, addr + size);
+}
+
+static void cache_qtd(struct qTD *qtd, int flush)
+{
+ u32 *ptr = (u32 *)qtd->qt_buffer[0];
+ int len = (qtd->qt_token & 0x7fff0000) >> 16;
+
+ flush_invalidate((u32)qtd, sizeof(struct qTD), flush);
+ if (ptr && len)
+ flush_invalidate((u32)ptr, len, flush);
+}
+
+
+static inline struct QH *qh_addr(struct QH *qh)
+{
+ return (struct QH *)((u32)qh & 0xffffffe0);
+}
+
+static void cache_qh(struct QH *qh, int flush)
+{
+ struct qTD *qtd;
+ struct qTD *next;
+ static struct qTD *first_qtd;
+
+ /*
+ * Walk the QH list and flush/invalidate all entries
+ */
+ while (1) {
+ flush_invalidate((u32)qh_addr(qh), sizeof(struct QH), flush);
+ if ((u32)qh & QH_LINK_TYPE_QH)
+ break;
+ qh = qh_addr(qh);
+ qh = (struct QH *)qh->qh_link;
+ }
+ qh = qh_addr(qh);
+
+ /*
+ * Save first qTD pointer, needed for invalidating pass on this QH
+ */
+ if (flush)
+ first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay &
+ 0xffffffe0);
+ else
+ qtd = first_qtd;
+
+ /*
+ * Walk the qTD list and flush/invalidate all entries
+ */
+ while (1) {
+ if (qtd == NULL)
+ break;
+ cache_qtd(qtd, flush);
+ next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0);
+ if (next == qtd)
+ break;
+ qtd = next;
+ }
+}
+
+static inline void ehci_flush_dcache(struct QH *qh)
+{
+ cache_qh(qh, 1);
+}
+
+static inline void ehci_invalidate_dcache(struct QH *qh)
+{
+ cache_qh(qh, 0);
+}
+#else /* CONFIG_EHCI_DCACHE */
+/*
+ *
+ */
+static inline void ehci_flush_dcache(struct QH *qh)
+{
+}
+
+static inline void ehci_invalidate_dcache(struct QH *qh)
+{
+}
+#endif /* CONFIG_EHCI_DCACHE */
+
+static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
+{
+ uint32_t result;
+ do {
+ result = ehci_readl(ptr);
+ if (result == ~(uint32_t)0)
+ return -1;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -1;
+}
+
+static void ehci_free(void *p, size_t sz)
+{
+
+}
+
+static int ehci_reset(void)
+{
+ uint32_t cmd;
+ uint32_t tmp;
+ uint32_t *reg_ptr;
+ int ret = 0;
+
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ cmd |= CMD_RESET;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+ ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
+ if (ret < 0) {
+ printf("EHCI fail to reset\n");
+ goto out;
+ }
+
+ if (ehci_is_TDI()) {
+ reg_ptr = (uint32_t *)((u8 *)hcor + USBMODE);
+ tmp = ehci_readl(reg_ptr);
+ tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+ tmp |= USBMODE_BE;
+#endif
+ ehci_writel(reg_ptr, tmp);
+ }
+out:
+ return ret;
+}
+
+static void *ehci_alloc(size_t sz, size_t align)
+{
+ static struct QH qh __attribute__((aligned(32)));
+ static struct qTD td[3] __attribute__((aligned (32)));
+ static int ntds;
+ void *p;
+
+ switch (sz) {
+ case sizeof(struct QH):
+ p = &qh;
+ ntds = 0;
+ break;
+ case sizeof(struct qTD):
+ if (ntds == 3) {
+ debug("out of TDs\n");
+ return NULL;
+ }
+ p = &td[ntds];
+ ntds++;
+ break;
+ default:
+ debug("unknown allocation size\n");
+ return NULL;
+ }
+
+ memset(p, sz, 0);
+ return p;
+}
+
+static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
+{
+ uint32_t addr, delta, next;
+ int idx;
+
+ addr = (uint32_t) buf;
+ idx = 0;
+ while (idx < 5) {
+ td->qt_buffer[idx] = cpu_to_hc32(addr);
+ next = (addr + 4096) & ~4095;
+ delta = next - addr;
+ if (delta >= sz)
+ break;
+ sz -= delta;
+ addr = next;
+ idx++;
+ }
+
+ if (idx == 5) {
+ debug("out of buffer pointers (%u bytes left)\n", sz);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *req)
+{
+ struct QH *qh;
+ struct qTD *td;
+ volatile struct qTD *vtd;
+ unsigned long ts;
+ uint32_t *tdp;
+ uint32_t endpt, token, usbsts;
+ uint32_t c, toggle;
+ uint32_t cmd;
+ int ret = 0;
+
+ debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
+ buffer, length, req);
+ if (req != NULL)
+ debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
+ req->request, req->request,
+ req->requesttype, req->requesttype,
+ le16_to_cpu(req->value), le16_to_cpu(req->value),
+ le16_to_cpu(req->index));
+
+ qh = ehci_alloc(sizeof(struct QH), 32);
+ if (qh == NULL) {
+ debug("unable to allocate QH\n");
+ return -1;
+ }
+ qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
+ c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
+ usb_pipeendpoint(pipe) == 0) ? 1 : 0;
+ endpt = (8 << 28) |
+ (c << 27) |
+ (usb_maxpacket(dev, pipe) << 16) |
+ (0 << 15) |
+ (1 << 14) |
+ (usb_pipespeed(pipe) << 12) |
+ (usb_pipeendpoint(pipe) << 8) |
+ (0 << 7) | (usb_pipedevice(pipe) << 0);
+ qh->qh_endpt1 = cpu_to_hc32(endpt);
+ endpt = (1 << 30) |
+ (dev->portnr << 23) |
+ (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
+ qh->qh_endpt2 = cpu_to_hc32(endpt);
+ qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+
+ td = NULL;
+ tdp = &qh->qh_overlay.qt_next;
+
+ toggle =
+ usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+ if (req != NULL) {
+ td = ehci_alloc(sizeof(struct qTD), 32);
+ if (td == NULL) {
+ debug("unable to allocate SETUP td\n");
+ goto fail;
+ }
+ td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ token = (0 << 31) |
+ (sizeof(*req) << 16) |
+ (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
+ td->qt_token = cpu_to_hc32(token);
+ if (ehci_td_buffer(td, req, sizeof(*req)) != 0) {
+ debug("unable construct SETUP td\n");
+ ehci_free(td, sizeof(*td));
+ goto fail;
+ }
+ *tdp = cpu_to_hc32((uint32_t) td);
+ tdp = &td->qt_next;
+ toggle = 1;
+ }
+
+ if (length > 0 || req == NULL) {
+ td = ehci_alloc(sizeof(struct qTD), 32);
+ if (td == NULL) {
+ debug("unable to allocate DATA td\n");
+ goto fail;
+ }
+ td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ token = (toggle << 31) |
+ (length << 16) |
+ ((req == NULL ? 1 : 0) << 15) |
+ (0 << 12) |
+ (3 << 10) |
+ ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
+ td->qt_token = cpu_to_hc32(token);
+ if (ehci_td_buffer(td, buffer, length) != 0) {
+ debug("unable construct DATA td\n");
+ ehci_free(td, sizeof(*td));
+ goto fail;
+ }
+ *tdp = cpu_to_hc32((uint32_t) td);
+ tdp = &td->qt_next;
+ }
+
+ if (req != NULL) {
+ td = ehci_alloc(sizeof(struct qTD), 32);
+ if (td == NULL) {
+ debug("unable to allocate ACK td\n");
+ goto fail;
+ }
+ td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ token = (toggle << 31) |
+ (0 << 16) |
+ (1 << 15) |
+ (0 << 12) |
+ (3 << 10) |
+ ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
+ td->qt_token = cpu_to_hc32(token);
+ *tdp = cpu_to_hc32((uint32_t) td);
+ tdp = &td->qt_next;
+ }
+
+ qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
+
+ /* Flush dcache */
+ ehci_flush_dcache(&qh_list);
+
+ usbsts = ehci_readl(&hcor->or_usbsts);
+ ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
+
+ /* Enable async. schedule. */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ cmd |= CMD_ASE;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+
+ ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
+ 100 * 1000);
+ if (ret < 0) {
+ printf("EHCI fail timeout STD_ASS set\n");
+ goto fail;
+ }
+
+ /* Wait for TDs to be processed. */
+ ts = get_timer(0);
+ vtd = td;
+ do {
+ /* Invalidate dcache */
+ ehci_invalidate_dcache(&qh_list);
+ token = hc32_to_cpu(vtd->qt_token);
+ if (!(token & 0x80))
+ break;
+ } while (get_timer(ts) < CONFIG_SYS_HZ);
+
+ /* Disable async schedule. */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ cmd &= ~CMD_ASE;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+
+ ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+ 100 * 1000);
+ if (ret < 0) {
+ printf("EHCI fail timeout STD_ASS reset\n");
+ goto fail;
+ }
+
+ qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
+
+ token = hc32_to_cpu(qh->qh_overlay.qt_token);
+ if (!(token & 0x80)) {
+ debug("TOKEN=%#x\n", token);
+ switch (token & 0xfc) {
+ case 0:
+ toggle = token >> 31;
+ usb_settoggle(dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), toggle);
+ dev->status = 0;
+ break;
+ case 0x40:
+ dev->status = USB_ST_STALLED;
+ break;
+ case 0xa0:
+ case 0x20:
+ dev->status = USB_ST_BUF_ERR;
+ break;
+ case 0x50:
+ case 0x10:
+ dev->status = USB_ST_BABBLE_DET;
+ break;
+ default:
+ dev->status = USB_ST_CRC_ERR;
+ break;
+ }
+ dev->act_len = length - ((token >> 16) & 0x7fff);
+ } else {
+ dev->act_len = 0;
+ debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
+ dev->devnum, ehci_readl(&hcor->or_usbsts),
+ ehci_readl(&hcor->or_portsc[0]),
+ ehci_readl(&hcor->or_portsc[1]));
+ }
+
+ return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
+
+fail:
+ td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
+ while (td != (void *)QT_NEXT_TERMINATE) {
+ qh->qh_overlay.qt_next = td->qt_next;
+ ehci_free(td, sizeof(*td));
+ td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
+ }
+ ehci_free(qh, sizeof(*qh));
+ return -1;
+}
+
+static inline int min3(int a, int b, int c)
+{
+
+ if (b < a)
+ a = b;
+ if (c < a)
+ a = c;
+ return a;
+}
+
+int
+ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *req)
+{
+ uint8_t tmpbuf[4];
+ u16 typeReq;
+ void *srcptr = NULL;
+ int len, srclen;
+ uint32_t reg;
+ uint32_t *status_reg;
+
+ if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+ printf("The request port(%d) is not configured\n",
+ le16_to_cpu(req->index) - 1);
+ return -1;
+ }
+ status_reg = (uint32_t *)&hcor->or_portsc[
+ le16_to_cpu(req->index) - 1];
+ srclen = 0;
+
+ debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
+ req->request, req->request,
+ req->requesttype, req->requesttype,
+ le16_to_cpu(req->value), le16_to_cpu(req->index));
+
+ typeReq = req->request << 8 | req->requesttype;
+
+ switch (le16_to_cpu(typeReq)) {
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ switch (le16_to_cpu(req->value) >> 8) {
+ case USB_DT_DEVICE:
+ debug("USB_DT_DEVICE request\n");
+ srcptr = &descriptor.device;
+ srclen = 0x12;
+ break;
+ case USB_DT_CONFIG:
+ debug("USB_DT_CONFIG config\n");
+ srcptr = &descriptor.config;
+ srclen = 0x19;
+ break;
+ case USB_DT_STRING:
+ debug("USB_DT_STRING config\n");
+ switch (le16_to_cpu(req->value) & 0xff) {
+ case 0: /* Language */
+ srcptr = "\4\3\1\0";
+ srclen = 4;
+ break;
+ case 1: /* Vendor */
+ srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
+ srclen = 14;
+ break;
+ case 2: /* Product */
+ srcptr = "\52\3E\0H\0C\0I\0 "
+ "\0H\0o\0s\0t\0 "
+ "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
+ srclen = 42;
+ break;
+ default:
+ debug("unknown value DT_STRING %x\n",
+ le16_to_cpu(req->value));
+ goto unknown;
+ }
+ break;
+ default:
+ debug("unknown value %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ break;
+ case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
+ switch (le16_to_cpu(req->value) >> 8) {
+ case USB_DT_HUB:
+ debug("USB_DT_HUB config\n");
+ srcptr = &descriptor.hub;
+ srclen = 0x8;
+ break;
+ default:
+ debug("unknown value %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ break;
+ case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
+ debug("USB_REQ_SET_ADDRESS\n");
+ rootdev = le16_to_cpu(req->value);
+ break;
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ debug("USB_REQ_SET_CONFIGURATION\n");
+ /* Nothing to do */
+ break;
+ case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
+ tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */
+ tmpbuf[1] = 0;
+ srcptr = tmpbuf;
+ srclen = 2;
+ break;
+ case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+ memset(tmpbuf, 0, 4);
+ reg = ehci_readl(status_reg);
+ if (reg & EHCI_PS_CS)
+ tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
+ if (reg & EHCI_PS_PE)
+ tmpbuf[0] |= USB_PORT_STAT_ENABLE;
+ if (reg & EHCI_PS_SUSP)
+ tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
+ if (reg & EHCI_PS_OCA)
+ tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
+ if (reg & EHCI_PS_PR &&
+ (portreset & (1 << le16_to_cpu(req->index)))) {
+ int ret;
+ /* force reset to complete */
+ reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
+ ehci_writel(status_reg, reg);
+ ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
+ if (!ret)
+ tmpbuf[0] |= USB_PORT_STAT_RESET;
+ else
+ printf("port(%d) reset error\n",
+ le16_to_cpu(req->index) - 1);
+ }
+ if (reg & EHCI_PS_PP)
+ tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
+
+ if (ehci_is_TDI()) {
+ switch ((reg >> 26) & 3) {
+ case 0:
+ break;
+ case 1:
+ tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
+ break;
+ case 2:
+ default:
+ tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+ break;
+ }
+ } else {
+ tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+ }
+
+ if (reg & EHCI_PS_CSC)
+ tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
+ if (reg & EHCI_PS_PEC)
+ tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
+ if (reg & EHCI_PS_OCC)
+ tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
+ if (portreset & (1 << le16_to_cpu(req->index)))
+ tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+
+ srcptr = tmpbuf;
+ srclen = 4;
+ break;
+ case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+ reg = ehci_readl(status_reg);
+ reg &= ~EHCI_PS_CLEAR;
+ switch (le16_to_cpu(req->value)) {
+ case USB_PORT_FEAT_ENABLE:
+ reg |= EHCI_PS_PE;
+ ehci_writel(status_reg, reg);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) {
+ reg |= EHCI_PS_PP;
+ ehci_writel(status_reg, reg);
+ }
+ break;
+ case USB_PORT_FEAT_RESET:
+ if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
+ !ehci_is_TDI() &&
+ EHCI_PS_IS_LOWSPEED(reg)) {
+ /* Low speed device, give up ownership. */
+ debug("port %d low speed --> companion\n",
+ req->index - 1);
+ reg |= EHCI_PS_PO;
+ ehci_writel(status_reg, reg);
+ break;
+ } else {
+ reg |= EHCI_PS_PR;
+ reg &= ~EHCI_PS_PE;
+ ehci_writel(status_reg, reg);
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 specification say 50 ms resets on
+ * root
+ */
+ wait_ms(50);
+ portreset |= 1 << le16_to_cpu(req->index);
+ }
+ break;
+ default:
+ debug("unknown feature %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ /* unblock posted writes */
+ ehci_readl(&hcor->or_usbcmd);
+ break;
+ case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+ reg = ehci_readl(status_reg);
+ switch (le16_to_cpu(req->value)) {
+ case USB_PORT_FEAT_ENABLE:
+ reg &= ~EHCI_PS_PE;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams)))
+ reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
+ case USB_PORT_FEAT_C_CONNECTION:
+ reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
+ break;
+ case USB_PORT_FEAT_OVER_CURRENT:
+ reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ portreset &= ~(1 << le16_to_cpu(req->index));
+ break;
+ default:
+ debug("unknown feature %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ ehci_writel(status_reg, reg);
+ /* unblock posted write */
+ ehci_readl(&hcor->or_usbcmd);
+ break;
+ default:
+ debug("Unknown request\n");
+ goto unknown;
+ }
+
+ wait_ms(1);
+ len = min3(srclen, le16_to_cpu(req->length), length);
+ if (srcptr != NULL && len > 0)
+ memcpy(buffer, srcptr, len);
+ else
+ debug("Len is 0\n");
+
+ dev->act_len = len;
+ dev->status = 0;
+ return 0;
+
+unknown:
+ debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n",
+ req->requesttype, req->request, le16_to_cpu(req->value),
+ le16_to_cpu(req->index), le16_to_cpu(req->length));
+
+ dev->act_len = 0;
+ dev->status = USB_ST_STALLED;
+ return -1;
+}
+
+int usb_lowlevel_stop(void)
+{
+ return ehci_hcd_stop();
+}
+
+int usb_lowlevel_init(void)
+{
+ uint32_t reg;
+ uint32_t cmd;
+
+ if (ehci_hcd_init() != 0)
+ return -1;
+
+ /* EHCI spec section 4.1 */
+ if (ehci_reset() != 0)
+ return -1;
+
+#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
+ if (ehci_hcd_init() != 0)
+ return -1;
+#endif
+
+ /* Set head of reclaim list */
+ memset(&qh_list, 0, sizeof(qh_list));
+ qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
+ qh_list.qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
+ qh_list.qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh_list.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh_list.qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh_list.qh_overlay.qt_token = cpu_to_hc32(0x40);
+
+ /* Set async. queue head pointer. */
+ ehci_writel(&hcor->or_asynclistaddr, (uint32_t)&qh_list);
+
+ reg = ehci_readl(&hccr->cr_hcsparams);
+ descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
+ printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
+ /* Port Indicators */
+ if (HCS_INDICATOR(reg))
+ descriptor.hub.wHubCharacteristics |= 0x80;
+ /* Port Power Control */
+ if (HCS_PPC(reg))
+ descriptor.hub.wHubCharacteristics |= 0x01;
+
+ /* Start the host controller. */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ /* Philips, Intel, and maybe others need CMD_RUN before the
+ * root hub will detect new devices (why?); NEC doesn't */
+ cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+ cmd |= CMD_RUN;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+
+ /* take control over the ports */
+ cmd = ehci_readl(&hcor->or_configflag);
+ cmd |= FLAG_CF;
+ ehci_writel(&hcor->or_configflag, cmd);
+ /* unblock posted write */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ wait_ms(5);
+ reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
+ printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
+
+ rootdev = 0;
+
+ return 0;
+}
+
+int
+submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length)
+{
+
+ if (usb_pipetype(pipe) != PIPE_BULK) {
+ debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
+ return -1;
+ }
+ return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+int
+submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *setup)
+{
+
+ if (usb_pipetype(pipe) != PIPE_CONTROL) {
+ debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
+ return -1;
+ }
+
+ if (usb_pipedevice(pipe) == rootdev) {
+ if (rootdev == 0)
+ dev->speed = USB_SPEED_HIGH;
+ return ehci_submit_root(dev, pipe, buffer, length, setup);
+ }
+ return ehci_submit_async(dev, pipe, buffer, length, setup);
+}
+
+int
+submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, int interval)
+{
+
+ debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
+ dev, pipe, buffer, length, interval);
+ return -1;
+}
diff --git a/drivers/usb/usb_ehci_core.h b/drivers/usb/usb_ehci_core.h
new file mode 100644
index 0000000..39e5c5e
--- /dev/null
+++ b/drivers/usb/usb_ehci_core.h
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Excito Elektronik i Skåne AB
+ * All rights reserved.
+ *
+ * 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 version 2 of
+ * the License.
+ *
+ * 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 USB_EHCI_CORE_H
+#define USB_EHCI_CORE_H
+
+extern int rootdev;
+extern struct ehci_hccr *hccr;
+extern volatile struct ehci_hcor *hcor;
+
+#endif
diff --git a/drivers/usb/usb_ehci_fsl.c b/drivers/usb/usb_ehci_fsl.c
new file mode 100644
index 0000000..81d5d21
--- /dev/null
+++ b/drivers/usb/usb_ehci_fsl.c
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
+ *
+ * Author: Tor Krill tor@excito.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 <pci.h>
+#include <usb.h>
+#include <mpc83xx.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "usb_ehci.h"
+#include "usb_ehci_fsl.h"
+#include "usb_ehci_core.h"
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ *
+ * Excerpts from linux ehci fsl driver.
+ */
+int ehci_hcd_init(void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ uint32_t addr, temp;
+
+ addr = (uint32_t)&(im->usb[0]);
+ hccr = (struct ehci_hccr *)(addr + FSL_SKIP_PCI);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr +
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ /* Configure clock */
+ clrsetbits_be32(&(im->clk.sccr), MPC83XX_SCCR_USB_MASK,
+ MPC83XX_SCCR_USB_DRCM_11);
+
+ /* Confgure interface. */
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp
+ | REFSEL_16MHZ | UTMI_PHY_EN);
+
+ /* Wait for clock to stabilize */
+ do {
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ udelay(1000);
+ } while (!(temp & PHY_CLK_VALID));
+
+ /* Set to Host mode */
+ temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
+ out_le32((void *)(addr + FSL_SOC_USB_USBMODE), temp | CM_HOST);
+
+ out_be32((void *)(addr + FSL_SOC_USB_SNOOP1), SNOOP_SIZE_2GB);
+ out_be32((void *)(addr + FSL_SOC_USB_SNOOP2),
+ 0x80000000 | SNOOP_SIZE_2GB);
+
+ /* Init phy */
+ /* TODO: handle different phys? */
+ out_le32(&(hcor->or_portsc[0]), PORT_PTS_UTMI);
+
+ /* Enable interface. */
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
+
+ out_be32((void *)(addr + FSL_SOC_USB_PRICTRL), 0x0000000c);
+ out_be32((void *)(addr + FSL_SOC_USB_AGECNTTHRSH), 0x00000040);
+ out_be32((void *)(addr + FSL_SOC_USB_SICTRL), 0x00000001);
+
+ /* Enable interface. */
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
+
+ temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
diff --git a/drivers/usb/usb_ehci_fsl.h b/drivers/usb/usb_ehci_fsl.h
new file mode 100644
index 0000000..c429af1
--- /dev/null
+++ b/drivers/usb/usb_ehci_fsl.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2005 freescale semiconductor
+ * Copyright (c) 2005 MontaVista Software
+ * Copyright (c) 2008 Excito Elektronik i Sk=E5ne AB
+ *
+ * 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 _EHCI_FSL_H
+#define _EHCI_FSL_H
+
+/* Global offsets */
+#define FSL_SKIP_PCI 0x100
+
+/* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ULPIVP 0x170
+#define FSL_SOC_USB_PORTSC1 0x184
+#define PORT_PTS_MSK (3 << 30)
+#define PORT_PTS_UTMI (0 << 30)
+#define PORT_PTS_ULPI (2 << 30)
+#define PORT_PTS_SERIAL (3 << 30)
+#define PORT_PTS_PTW (1 << 28)
+
+/* USBMODE Register bits */
+#define CM_IDLE (0 << 0)
+#define CM_RESERVED (1 << 0)
+#define CM_DEVICE (2 << 0)
+#define CM_HOST (3 << 0)
+#define USBMODE_RESERVED_2 (0 << 2)
+#define SLOM (1 << 3)
+#define SDIS (1 << 4)
+
+/* CONTROL Register bits */
+#define ULPI_INT_EN (1 << 0)
+#define WU_INT_EN (1 << 1)
+#define USB_EN (1 << 2)
+#define LSF_EN (1 << 3)
+#define KEEP_OTG_ON (1 << 4)
+#define OTG_PORT (1 << 5)
+#define REFSEL_12MHZ (0 << 6)
+#define REFSEL_16MHZ (1 << 6)
+#define REFSEL_48MHZ (2 << 6)
+#define PLL_RESET (1 << 8)
+#define UTMI_PHY_EN (1 << 9)
+#define PHY_CLK_SEL_UTMI (0 << 10)
+#define PHY_CLK_SEL_ULPI (1 << 10)
+#define CLKIN_SEL_USB_CLK (0 << 11)
+#define CLKIN_SEL_USB_CLK2 (1 << 11)
+#define CLKIN_SEL_SYS_CLK (2 << 11)
+#define CLKIN_SEL_SYS_CLK2 (3 << 11)
+#define RESERVED_18 (0 << 13)
+#define RESERVED_17 (0 << 14)
+#define RESERVED_16 (0 << 15)
+#define WU_INT (1 << 16)
+#define PHY_CLK_VALID (1 << 17)
+
+#define FSL_SOC_USB_PORTSC2 0x188
+#define FSL_SOC_USB_USBMODE 0x1a8
+#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
+#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
+#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
+#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
+#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
+#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
+#define SNOOP_SIZE_2GB 0x1e
+
+/* System Clock Control Register */
+#define MPC83XX_SCCR_USB_MASK 0x00f00000
+#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
+#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
+#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
+
+#endif /* _EHCI_FSL_H */
diff --git a/drivers/usb/usb_ehci_ixp.c b/drivers/usb/usb_ehci_ixp.c
new file mode 100644
index 0000000..25c18c1
--- /dev/null
+++ b/drivers/usb/usb_ehci_ixp.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * Author: Michael Trimarchi <trimarchimichael@yahoo.it>
+ * This code is based on ehci freescale driver
+ *
+ * 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.h>
+#include "usb_ehci.h"
+#include "usb_ehci_core.h"
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ hccr = (struct ehci_hccr *)(0xcd000100);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr
+ + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ printf("IXP4XX init hccr %x and hcor %x hc_length %d\n",
+ (uint32_t)hccr, (uint32_t)hcor,
+ (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
diff --git a/drivers/usb/usb_ehci_pci.c b/drivers/usb/usb_ehci_pci.c
new file mode 100644
index 0000000..3e7143c
--- /dev/null
+++ b/drivers/usb/usb_ehci_pci.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * 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 version 2 of
+ * the License.
+ *
+ * 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 <pci.h>
+#include <usb.h>
+#include "usb_ehci.h"
+#include "usb_ehci_core.h"
+
+#ifdef CONFIG_PCI_EHCI_DEVICE
+static struct pci_device_id ehci_pci_ids[] = {
+ /* Please add supported PCI EHCI controller ids here */
+ {0, 0}
+};
+#endif
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ pci_dev_t pdev;
+ uint32_t addr;
+
+ pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
+ if (pdev == -1) {
+ printf("EHCI host controller not found\n");
+ return -1;
+ }
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &addr);
+ hccr = (struct ehci_hccr *)addr;
+ hcor = (struct ehci_hcor *)((uint32_t) hccr +
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
diff --git a/include/configs/VCMA9.h b/include/configs/VCMA9.h
index 83d0d56..d9bcf6b 100644
--- a/include/configs/VCMA9.h
+++ b/include/configs/VCMA9.h
@@ -36,7 +36,6 @@
#define CONFIG_ARM920T 1 /* This is an ARM920T Core */
#define CONFIG_S3C2410 1 /* in a SAMSUNG S3C2410 SoC */
#define CONFIG_VCMA9 1 /* on a MPL VCMA9 Board */
-#define LITTLEENDIAN 1 /* used by usb_ohci.c */
/* input clock of PLL */
#define CONFIG_SYS_CLK_FREQ 12000000/* VCMA9 has 12MHz input clock */
diff --git a/include/configs/afeb9260.h b/include/configs/afeb9260.h
index e996bbd..9eed342 100644
--- a/include/configs/afeb9260.h
+++ b/include/configs/afeb9260.h
@@ -114,7 +114,6 @@
/* USB */
#define CONFIG_USB_OHCI_NEW 1
-#define LITTLEENDIAN 1
#define CONFIG_DOS_PARTITION 1
#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00500000 /* AT91SAM9260_UHP_BASE */
diff --git a/include/configs/at91cap9adk.h b/include/configs/at91cap9adk.h
index f1c5526..01da99b 100644
--- a/include/configs/at91cap9adk.h
+++ b/include/configs/at91cap9adk.h
@@ -131,7 +131,6 @@
/* USB */
#define CONFIG_USB_OHCI_NEW 1
-#define LITTLEENDIAN 1
#define CONFIG_DOS_PARTITION 1
#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00700000 /* AT91_BASE_UHP */
diff --git a/include/configs/at91sam9260ek.h b/include/configs/at91sam9260ek.h
index 4501cae..2f1a41f 100644
--- a/include/configs/at91sam9260ek.h
+++ b/include/configs/at91sam9260ek.h
@@ -116,7 +116,6 @@
/* USB */
#define CONFIG_USB_OHCI_NEW 1
-#define LITTLEENDIAN 1
#define CONFIG_DOS_PARTITION 1
#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00500000 /* AT91SAM9260_UHP_BASE */
diff --git a/include/configs/at91sam9261ek.h b/include/configs/at91sam9261ek.h
index 668fe3b..ebecfa4 100644
--- a/include/configs/at91sam9261ek.h
+++ b/include/configs/at91sam9261ek.h
@@ -129,7 +129,6 @@
/* USB */
#define CONFIG_USB_OHCI_NEW 1
-#define LITTLEENDIAN 1
#define CONFIG_DOS_PARTITION 1
#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00500000 /* AT91SAM9261_UHP_BASE */
diff --git a/include/configs/at91sam9263ek.h b/include/configs/at91sam9263ek.h
index c6603ff..09b871a 100644
--- a/include/configs/at91sam9263ek.h
+++ b/include/configs/at91sam9263ek.h
@@ -136,7 +136,6 @@
/* USB */
#define CONFIG_USB_OHCI_NEW 1
-#define LITTLEENDIAN 1
#define CONFIG_DOS_PARTITION 1
#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00a00000 /* AT91SAM9263_UHP_BASE */
diff --git a/include/configs/davinci_dvevm.h b/include/configs/davinci_dvevm.h
index a727f56..667c0d8 100644
--- a/include/configs/davinci_dvevm.h
+++ b/include/configs/davinci_dvevm.h
@@ -171,6 +171,8 @@
#define CONFIG_SYS_LONGHELP
#define CONFIG_CRC32_VERIFY
#define CONFIG_MX_CYCLIC
+#define CONFIG_MUSB_HCD
+#define CONFIG_USB_DAVINCI
/*===================*/
/* Linux Information */
/*===================*/
@@ -203,6 +205,22 @@
#else
#error "Either CONFIG_SYS_USE_NAND or CONFIG_SYS_USE_NOR _MUST_ be defined !!!"
#endif
+/*==========================*/
+/* USB MSC support (if any) */
+/*==========================*/
+#ifdef CONFIG_USB_DAVINCI
+#define CONFIG_CMD_USB
+#ifdef CONFIG_MUSB_HCD
+#define CONFIG_USB_STORAGE
+#define CONFIG_CMD_STORAGE
+#define CONFIG_CMD_FAT
+#define CONFIG_DOS_PARTITION
+#endif
+#ifdef CONFIG_USB_KEYBOARD
+#define CONFIG_SYS_USB_EVENT_POLL
+#define CONFIG_PREBOOT "usb start"
+#endif
+#endif
/*=======================*/
/* KGDB support (if any) */
/*=======================*/
diff --git a/include/configs/delta.h b/include/configs/delta.h
index fd97b74..abb2676 100644
--- a/include/configs/delta.h
+++ b/include/configs/delta.h
@@ -131,8 +131,6 @@
#define CONFIG_SYS_USB_OHCI_SLOT_NAME "delta"
#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 3
-#define LITTLEENDIAN 1 /* used by usb_ohci.c */
-
#define CONFIG_BOOTDELAY -1
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b
#define CONFIG_NETMASK 255.255.0.0
diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h
index fb10616..9ac7e9a 100644
--- a/include/configs/mp2usb.h
+++ b/include/configs/mp2usb.h
@@ -216,7 +216,6 @@
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */
#define CONFIG_SYS_DEVICE_DEREGISTER /* needs device_deregister */
-#define LITTLEENDIAN 1 /* used by usb_ohci.c */
#define CONFIG_SYS_HZ 1000
#define CONFIG_SYS_HZ_CLOCK (AT91C_MASTER_CLOCK/2) /* AT91C_TC0_CMR is implicitly set to */
diff --git a/include/configs/sh7785lcr.h b/include/configs/sh7785lcr.h
index 1b59059..ebca448 100644
--- a/include/configs/sh7785lcr.h
+++ b/include/configs/sh7785lcr.h
@@ -123,7 +123,6 @@
#undef CONFIG_SYS_DIRECT_FLASH_TFTP
/* R8A66597 */
-#define LITTLEENDIAN /* for include/usb.h */
#define CONFIG_USB_R8A66597_HCD
#define CONFIG_R8A66597_BASE_ADDR SH7785LCR_USB_BASE
#define CONFIG_R8A66597_XTAL 0x0000 /* 12MHz */
diff --git a/include/configs/smdk6400.h b/include/configs/smdk6400.h
index 57c82d1..c61667f 100644
--- a/include/configs/smdk6400.h
+++ b/include/configs/smdk6400.h
@@ -293,7 +293,6 @@
#define CONFIG_SYS_USB_OHCI_SLOT_NAME "s3c6400"
#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 3
#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
-#define LITTLEENDIAN 1 /* used by usb_ohci.c */
#define CONFIG_USB_STORAGE 1
#endif
diff --git a/include/configs/trab.h b/include/configs/trab.h
index 562cd60..0a7a73d 100644
--- a/include/configs/trab.h
+++ b/include/configs/trab.h
@@ -44,7 +44,6 @@
#define CONFIG_S3C2400 1 /* in a SAMSUNG S3C2400 SoC */
#define CONFIG_TRAB 1 /* on a TRAB Board */
#undef CONFIG_TRAB_50MHZ /* run the CPU at 50 MHz */
-#define LITTLEENDIAN 1 /* used by usb_ohci.c */
/* automatic software updates (see board/trab/auto_update.c) */
#define CONFIG_AUTO_UPDATE 1
diff --git a/include/configs/trizepsiv.h b/include/configs/trizepsiv.h
index b2065ee..0a8e994 100644
--- a/include/configs/trizepsiv.h
+++ b/include/configs/trizepsiv.h
@@ -42,8 +42,6 @@
*/
#define CONFIG_PXA27X 1 /* This is an PXA27x CPU */
-#define LITTLEENDIAN 1 /* used by usb_ohci.c */
-
#define CONFIG_MMC 1
#define BOARD_LATE_INIT 1
diff --git a/include/usb.h b/include/usb.h
index 510df95..7c47098 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -138,7 +138,7 @@
struct usb_device {
int devnum; /* Device number on USB bus */
- int slow; /* Slow device? */
+ int speed; /* full/low/high */
char mf[32]; /* manufacturer */
char prod[32]; /* product */
char serial[32]; /* serial number */
@@ -171,6 +171,7 @@
unsigned long status;
int act_len; /* transfered bytes */
int maxchild; /* Number of ports if hub */
+ int portnr;
struct usb_device *parent;
struct usb_device *children[USB_MAXCHILDREN];
};
@@ -180,8 +181,9 @@
*/
#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
- defined(CONFIG_USB_OHCI_NEW) || defined(CONFIG_USB_SL811HS) || \
- defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_R8A66597_HCD)
+ 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)
int usb_lowlevel_init(void);
int usb_lowlevel_stop(void);
@@ -263,13 +265,13 @@
((x_ & 0xFF000000UL) >> 24)); \
})
-#ifdef LITTLEENDIAN
+#ifdef __LITTLE_ENDIAN
# define swap_16(x) (x)
# define swap_32(x) (x)
#else
# define swap_16(x) __swap_16(x)
# define swap_32(x) __swap_32(x)
-#endif /* LITTLEENDIAN */
+#endif
/*
* Calling this entity a "pipe" is glorifying it. A USB pipe
@@ -279,7 +281,7 @@
* - endpoint number (4 bits)
* - current Data0/1 state (1 bit)
* - direction (1 bit)
- * - speed (1 bit)
+ * - speed (2 bits)
* - max packet size (2 bits: 8, 16, 32 or 64)
* - pipe type (2 bits: control, interrupt, bulk, isochronous)
*
@@ -296,7 +298,7 @@
* - device: bits 8-14
* - endpoint: bits 15-18
* - Data0/1: bit 19
- * - speed: bit 26 (0 = Full, 1 = Low Speed)
+ * - speed: bit 26 (0 = Full, 1 = Low Speed, 2 = High)
* - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt,
* 10 = control, 11 = bulk)
*
@@ -308,8 +310,8 @@
/* Create various pipes... */
#define create_pipe(dev,endpoint) \
(((dev)->devnum << 8) | (endpoint << 15) | \
- ((dev)->slow << 26) | (dev)->maxpacketsize)
-#define default_pipe(dev) ((dev)->slow << 26)
+ ((dev)->speed << 26) | (dev)->maxpacketsize)
+#define default_pipe(dev) ((dev)->speed << 26)
#define usb_sndctrlpipe(dev, endpoint) ((PIPE_CONTROL << 30) | \
create_pipe(dev, endpoint))
@@ -359,7 +361,8 @@
#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
#define usb_pipedata(pipe) (((pipe) >> 19) & 1)
-#define usb_pipeslow(pipe) (((pipe) >> 26) & 1)
+#define usb_pipespeed(pipe) (((pipe) >> 26) & 3)
+#define usb_pipeslow(pipe) (usb_pipespeed(pipe) == USB_SPEED_LOW)
#define usb_pipetype(pipe) (((pipe) >> 30) & 3)
#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT)
diff --git a/include/usb_defs.h b/include/usb_defs.h
index 353019f..8032e57 100644
--- a/include/usb_defs.h
+++ b/include/usb_defs.h
@@ -80,6 +80,12 @@
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
+/* USB device speeds */
+#define USB_SPEED_FULL 0x0 /* 12Mbps */
+#define USB_SPEED_LOW 0x1 /* 1.5Mbps */
+#define USB_SPEED_HIGH 0x2 /* 480Mbps */
+#define USB_SPEED_RESERVED 0x3
+
/* Descriptor types */
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
@@ -202,6 +208,7 @@
#define USB_PORT_FEAT_RESET 4
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9
+#define USB_PORT_FEAT_HIGHSPEED 10
#define USB_PORT_FEAT_C_CONNECTION 16
#define USB_PORT_FEAT_C_ENABLE 17
#define USB_PORT_FEAT_C_SUSPEND 18
@@ -216,6 +223,9 @@
#define USB_PORT_STAT_RESET 0x0010
#define USB_PORT_STAT_POWER 0x0100
#define USB_PORT_STAT_LOW_SPEED 0x0200
+#define USB_PORT_STAT_HIGH_SPEED 0x0400 /* support for EHCI */
+#define USB_PORT_STAT_SPEED \
+ (USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED)
/* wPortChange bits */
#define USB_PORT_STAT_C_CONNECTION 0x0001