Index: firmware/export/usb_core.h
===================================================================
--- firmware/export/usb_core.h	(revision 17139)
+++ firmware/export/usb_core.h	(working copy)
@@ -33,7 +33,11 @@
 
 /* endpoints */
 #define EP_CONTROL 0
+#if CONFIG_CPU == IMX31L
+#define NUM_ENDPOINTS 8
+#else
 #define NUM_ENDPOINTS 3
+#endif
 
 extern int usb_max_pkt_size;
 
Index: firmware/export/mc13783.h
===================================================================
--- firmware/export/mc13783.h	(revision 17139)
+++ firmware/export/mc13783.h	(working copy)
@@ -104,8 +104,10 @@
 #define MC13783_LOBATL      (1 << 13)
 #define MC13783_LOBATH      (1 << 14)
 #define MC13783_UDP         (1 << 15)
-#define MC13783_USB         (1 << 16)
-#define MC13783_ID          (1 << 19)
+#define MC13783_USB4V4      (1 << 16)
+#define MC13783_USB2V0      (1 << 17)
+#define MC13783_USB0V8      (1 << 18)
+#define MC13783_IDFLOAT     (1 << 19)
 #define MC13783_SE1         (1 << 21)
 #define MC13783_CKDET       (1 << 22)
 #define MC13783_UDM         (1 << 23)
Index: firmware/export/config-gigabeat-s.h
===================================================================
--- firmware/export/config-gigabeat-s.h	(revision 17139)
+++ firmware/export/config-gigabeat-s.h	(working copy)
@@ -112,8 +112,19 @@
 #define CPU_FREQ 16934400
 
 /* define this if the unit can be powered or charged via USB */
-#define HAVE_USB_POWER
+//#define HAVE_USB_POWER
 
+/* USB On-the-go */
+#define CONFIG_USBOTG USBOTG_ARC
+
+/* enable these for the experimental usb stack */
+#define USE_HIGH_SPEED
+#define USE_ROCKBOX_USB
+#define HAVE_USBSTACK
+#define USB_STORAGE
+#define USB_VENDOR_ID 0x0930
+#define USB_PRODUCT_ID 0x0010
+
 /* Define this if you have ATA power-off control */
 #define HAVE_ATA_POWER_OFF
 
Index: firmware/export/imx31l.h
===================================================================
--- firmware/export/imx31l.h	(revision 17139)
+++ firmware/export/imx31l.h	(working copy)
@@ -32,7 +32,11 @@
 #define LCD_BUFFER_SIZE ((320*240*2))
 #define TTB_SIZE (0x4000)
 #define TTB_BASE ((unsigned int *)TTB_BASE_ADDR)
-
+/* TTB_BASE_ADDR is 16K aligned so work back from the largest first */
+#define _qh_array       (TTB_BASE_ADDR - 2*2*64*8) /* 2K-aligned */
+#define _td_array       (_qh_array - 2*32*NUM_ENDPOINTS)
+#define __response_data (_td_array - 256)
+#define UNCACHED_ADDR(x) (x)
 /*
  * AIPS 1
  */
@@ -1032,4 +1036,6 @@
 #define writew(v,a)             (*(REG16_PTR_T)(a) = (v))
 #define readw(a)                (*(REG16_PTR_T)(a))
 
+#define USB_BASE                OTG_BASE_ADDR
+
 #endif /* __IMX31L_H__ */
Index: firmware/usbstack/usb_core.c
===================================================================
--- firmware/usbstack/usb_core.c	(revision 17139)
+++ firmware/usbstack/usb_core.c	(working copy)
@@ -245,7 +245,9 @@
 static int ack_control(struct usb_ctrlrequest* req);
 
 static unsigned char *response_data;
+#ifndef __response_data
 static unsigned char __response_data[CACHEALIGN_UP(256)] CACHEALIGN_ATTR;
+#endif
 
 static struct usb_transfer_completion_event_data events[NUM_ENDPOINTS];
 
@@ -317,7 +319,7 @@
     if (initialized)
         return;
 
-    response_data = (void*)UNCACHED_ADDR(&__response_data);
+    response_data = (void*)UNCACHED_ADDR(__response_data);
 
     usb_drv_init();
 
Index: firmware/SOURCES
===================================================================
--- firmware/SOURCES	(revision 17139)
+++ firmware/SOURCES	(working copy)
@@ -233,7 +233,7 @@
 usbstack/usb_core.c
 usbstack/usb_storage.c
 usbstack/usb_serial.c
-#ifdef CPU_PP502x
+#if defined(CPU_PP502x) || CONFIG_CPU == IMX31L
 target/arm/usb-drv-pp502x.c
 #endif
 #else /* !defined(HAVE_USBSTACK) */
Index: firmware/target/arm/usb-drv-pp502x.c
===================================================================
--- firmware/target/arm/usb-drv-pp502x.c	(revision 17139)
+++ firmware/target/arm/usb-drv-pp502x.c	(working copy)
@@ -26,6 +26,11 @@
 //#define LOGF_ENABLE
 #include "logf.h"
 
+#if CONFIG_CPU == IMX31L
+#include "avic-imx31.h"
+void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void);
+#endif
+
 /* USB device mode registers (Little Endian) */
 
 #define REG_ID               (*(volatile unsigned int *)(USB_BASE+0x000))
@@ -302,7 +307,9 @@
     unsigned int reserved;
 } __attribute__ ((packed));
 
+#ifndef _td_array
 static struct transfer_descriptor _td_array[NUM_ENDPOINTS*2] __attribute((aligned (32)));
+#endif
 static struct transfer_descriptor* td_array;
 
 /* manual: 32.13.1 Endpoint Queue Head (dQH) */
@@ -318,7 +325,9 @@
     unsigned int wait;              /* for softwate use, indicates if the transfer is blocking */
 } __attribute__((packed));
 
+#ifndef _qh_array
 static struct queue_head _qh_array[NUM_ENDPOINTS*2] __attribute((aligned (2048)));
+#endif
 static struct queue_head* qh_array;
 static struct event_queue transfer_completion_queue[NUM_ENDPOINTS*2];
 
@@ -354,21 +363,29 @@
 void usb_drv_init(void)
 {
     REG_USBCMD &= ~USBCMD_RUN;
+#if CONFIG_CPU == IMX31L
+    sleep(HZ/20);
+#else
     udelay(50000);
+#endif
     REG_USBCMD |= USBCMD_CTRL_RESET;
     while (REG_USBCMD & USBCMD_CTRL_RESET);
 
-
     REG_USBMODE = USBMODE_CTRL_MODE_DEVICE;
 
+#if CONFIG_CPU == IMX31L
+    /* Set to ULPI */
+    REG_PORTSC1 = (REG_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | (0x2 << 30);
+#endif
+
 #ifndef USE_HIGH_SPEED
     /* Force device to full speed */
     /* See 32.9.5.9.2 */
     REG_PORTSC1 |= PORTSCX_PORT_FORCE_FULL_SPEED;
 #endif
 
-    td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array);
-    qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array);
+    td_array = (struct transfer_descriptor*)UNCACHED_ADDR(_td_array);
+    qh_array = (struct queue_head*)UNCACHED_ADDR(_qh_array);
     init_control_queue_heads();
     memset(td_array, 0, sizeof _td_array);
 
@@ -383,13 +400,16 @@
         USBINTR_RESET_EN |
         USBINTR_SYS_ERR_EN;
 
+#if CONFIG_CPU == IMX31L
+    avic_enable_int(USB_OTG, IRQ, 7, USB_OTG_HANDLER);
+#else
     /* enable USB IRQ in CPU */
     CPU_INT_EN |= USB_MASK;
+#endif
 
     /* go go go */
     REG_USBCMD |= USBCMD_RUN;
 
-
     logf("usb_drv_init() finished");
     logf("usb id %x", REG_ID);
     logf("usb dciversion %x", REG_DCIVERSION);
@@ -411,10 +431,18 @@
     REG_USBCMD |= USBCMD_CTRL_RESET;
     */
 
+#if CONFIG_CPU == IMX31L
+    avic_disable_int(USB_OTG);
+#endif
+
     cancel_cpu_boost();
 }
 
+#if CONFIG_CPU == IMX31L
+void __attribute__((interrupt("IRQ"))) USB_OTG_HANDLER(void)
+#else
 void usb_drv_int(void)
+#endif
 {
     unsigned int status = REG_USBSTS;
 
@@ -492,16 +520,64 @@
 
 int usb_drv_send_nonblocking(int endpoint, void* ptr, int length)
 {
+#if CONFIG_CPU == IMX31L
+    if (ptr && length > 0)
+    {
+        uintptr_t phys = (uintptr_t)ptr;
+        clean_dcache_range(ptr, length);
+
+        if (phys < 0x04000000ul)
+        {
+            /* In RAM */
+            if (phys >= 0x00100000ul)
+                phys += 0x00100000ul;
+        }
+
+        ptr = (void *)(phys | 0x80000000ul);
+    }
+#endif
     return prime_transfer(endpoint, ptr, length, true, false);
 }
 
 int usb_drv_send(int endpoint, void* ptr, int length)
 {
+#if CONFIG_CPU == IMX31L
+    if (ptr && length > 0)
+    {
+        uintptr_t phys = (uintptr_t)ptr;
+        clean_dcache_range(ptr, length);
+
+        if (phys < 0x04000000ul)
+        {
+            /* In RAM */
+            if (phys >= 0x00100000ul)
+                phys += 0x00100000ul;
+        }
+
+        ptr = (void *)(phys | 0x80000000ul);
+    }
+#endif
     return prime_transfer(endpoint, ptr, length, true, true);
 }
 
 int usb_drv_recv(int endpoint, void* ptr, int length)
 {
+#if CONFIG_CPU == IMX31L
+    if (ptr && length > 0)
+    {
+        uintptr_t phys = (uintptr_t)ptr;
+        clean_dcache_range(ptr, length);
+
+        if (phys < 0x04000000ul)
+        {
+            /* In RAM */
+            if (phys >= 0x00100000ul)
+                phys += 0x00100000ul;
+        }
+
+        ptr = (void *)(phys | 0x80000000ul);
+    }
+#endif
     //logf("usbrecv(%x, %d)", ptr, length);
     return prime_transfer(endpoint, ptr, length, false, false);
 }
@@ -734,6 +810,7 @@
                     qh->wait=0;
                     queue_post(&transfer_completion_queue[pipe],0, 0);
                 }
+
                 usb_core_transfer_complete(ep, dir, qh->status, qh->length);
             }
         }
@@ -758,8 +835,13 @@
             logf("usb: double reset");
             return;
         }
-
+#if CONFIG_CPU == IMX31L
+        int x;
+        for (x = 0; x < 30000; x++)
+            asm volatile ("");
+#else
         udelay(100);
+#endif
     }
     if (REG_ENDPTPRIME) {
         logf("usb: short reset timeout");
Index: firmware/target/arm/imx31/gigabeat-s/usb-target.h
===================================================================
--- firmware/target/arm/imx31/gigabeat-s/usb-target.h	(revision 17139)
+++ firmware/target/arm/imx31/gigabeat-s/usb-target.h	(working copy)
@@ -19,6 +19,7 @@
 #ifndef USB_TARGET_H
 #define USB_TARGET_H
 
+void usb_set_status(bool plugged);
 bool usb_init_device(void);
 int usb_detect(void);
 void usb_enable(bool on);
Index: firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c
===================================================================
--- firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c	(revision 17139)
+++ firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c	(working copy)
@@ -27,6 +27,7 @@
 #include "power-imx31.h"
 #include "button-target.h"
 #include "adc-target.h"
+#include "usb-target.h"
 
 /* This is all based on communicating with the MC13783 PMU which is on 
  * CSPI2 with the chip select at 0. The LCD controller resides on
@@ -67,6 +68,7 @@
 
     /* Check initial states for events with a sense bit */
     value = mc13783_read(MC13783_INTERRUPT_SENSE0);
+    usb_set_status(value & MC13783_USB4V4);
     set_charger_inserted(value & MC13783_CHGDET);
 
     value = mc13783_read(MC13783_INTERRUPT_SENSE1);
@@ -98,12 +100,15 @@
 
             /* Handle interrupts that have a sense bit that needs to
              * be checked */
-            if (pending[0] & MC13783_CHGDET)
+            if (pending[0] & (MC13783_CHGDET | MC13783_USB4V4))
             {
                 value = mc13783_read(MC13783_INTERRUPT_SENSE0);
 
                 if (pending[0] & MC13783_CHGDET)
                     set_charger_inserted(value & MC13783_CHGDET);
+
+                if (pending[0] & MC13783_USB4V4)
+                    usb_set_status(value & MC13783_USB4V4);
             }
         }
 
Index: firmware/target/arm/imx31/gigabeat-s/usb-imx31.c
===================================================================
--- firmware/target/arm/imx31/gigabeat-s/usb-imx31.c	(revision 17139)
+++ firmware/target/arm/imx31/gigabeat-s/usb-imx31.c	(working copy)
@@ -22,17 +22,39 @@
 #include "kernel.h"
 #include "ata.h"
 #include "usb.h"
+#include "usb_core.h"
+#include "clkctl-imx31.h"
+#include "mc13783.h"
 
-inline int usb_detect(void)
+static int usb_status = USB_EXTRACTED;
+
+void usb_set_status(bool plugged)
 {
-    return USB_EXTRACTED;
+    usb_status = plugged ? USB_INSERTED : USB_EXTRACTED;
 }
 
+int usb_detect(void)
+{
+    return usb_status;
+}
+
 void usb_init_device(void)
 {
+    mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_USB4V4);
 }
 
 void usb_enable(bool on)
 {
-    (void)on;
+    if (on)
+    {
+        GPIO1_DR &= ~(1 << 30); /* Select ISP1504 */
+        imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_ON_ALL);
+        usb_core_init();
+    }
+    else
+    {
+        usb_core_exit();
+        imx31_clkctl_module_clock_gating(CG_USBOTG, CGM_OFF);
+        GPIO1_DR |= (1 << 30); /* Deselect ISP1504 */
+    }
 }
