summaryrefslogtreecommitdiff
path: root/target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch
diff options
context:
space:
mode:
authorjuhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>2013-03-12 18:22:22 +0000
committerjuhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>2013-03-12 18:22:22 +0000
commit86b8cf69ac6c1cdf37ccb576a9273c9b3f80a35a (patch)
tree7e34ec312060b92b19ce18a4662b6f4542a34909 /target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch
parent33f7576d1ed86a19c3e0fad2a18a385ad613d2d6 (diff)
gemini: add support for 3.8
Signed-off-by: Gabor Juhos <juhosg@openwrt.org> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@35993 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch')
-rw-r--r--target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch617
1 files changed, 617 insertions, 0 deletions
diff --git a/target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch b/target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch
new file mode 100644
index 0000000000..4e7fdcfe05
--- /dev/null
+++ b/target/linux/gemini/patches-3.8/130-usb-ehci-gemini-fot2gxx-support.patch
@@ -0,0 +1,617 @@
+--- /dev/null
++++ b/drivers/usb/host/ehci-fotg2xx.c
+@@ -0,0 +1,465 @@
++/*
++ * EHCI Host Controller driver
++ *
++ * Copyright (C) 2006 Sony Computer Entertainment Inc.
++ * Copyright 2006 Sony Corp.
++ *
++ * 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.
++ */
++
++#include <linux/platform_device.h>
++#include <mach/hardware.h>
++
++#define otg_set(port, bits) writel(readl(hcd->regs + port) | bits, hcd->regs + port)
++
++#define otg_clear(port, bits) writel(readl(hcd->regs + port) & ~bits, hcd->regs + port)
++
++#define GLOBAL_ISR 0xC0
++#define GLOBAL_ICR 0xC4
++
++#define HCD_MISC 0x40
++
++#define OTGC_SCR 0x80
++#define OTGC_INT_EN 0x88
++
++#define GLOBAL_INT_POLARITY (1 << 3)
++#define GLOBAL_INT_MASK_HC (1 << 2)
++#define GLOBAL_INT_MASK_OTG (1 << 1)
++#define GLOBAL_INT_MASK_DEV (1 << 0)
++
++#define OTGC_SCR_ID (1 << 21)
++#define OTGC_SCR_CROLE (1 << 20)
++#define OTGC_SCR_VBUS_VLD (1 << 19)
++#define OTGC_SCR_A_SRP_RESP_TYPE (1 << 8)
++#define OTGC_SCR_A_SRP_DET_EN (1 << 7)
++#define OTGC_SCR_A_SET_B_HNP_EN (1 << 6)
++#define OTGC_SCR_A_BUS_DROP (1 << 5)
++#define OTGC_SCR_A_BUS_REQ (1 << 4)
++
++#define OTGC_INT_APLGRMV (1 << 12)
++#define OTGC_INT_BPLGRMV (1 << 11)
++#define OTGC_INT_OVC (1 << 10)
++#define OTGC_INT_IDCHG (1 << 9)
++#define OTGC_INT_RLCHG (1 << 8)
++#define OTGC_INT_AVBUSERR (1 << 5)
++#define OTGC_INT_ASRPDET (1 << 4)
++#define OTGC_INT_BSRPDN (1 << 0)
++
++#define OTGC_INT_A_TYPE (OTGC_INT_ASRPDET|OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG|OTGC_INT_APLGRMV)
++#define OTGC_INT_B_TYPE (OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG)
++
++static void fotg2xx_otgc_role_change(struct usb_hcd *hcd);
++
++static void fotg2xx_otgc_init(struct usb_hcd *hcd)
++{
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++ unsigned int reg;
++
++ reg = __raw_readl(hcd->regs + OTGC_SCR);
++ ehci_info(ehci, "role detected: %s, ",
++ (reg & OTGC_SCR_CROLE) ? "Peripheral" : "Host");
++
++ if (reg & OTGC_SCR_ID)
++ ehci_info(ehci, "B-Device (may be unsupported!)\n");
++ else
++ ehci_info(ehci, "A-Device\n");
++
++ /* Enable the SRP detect */
++ reg &= ~OTGC_SCR_A_SRP_RESP_TYPE;
++ __raw_writel(reg, hcd->regs + OTGC_SCR);
++
++ reg = __raw_readl(hcd->regs + OTGC_INT_EN);
++ /* clear INT B: bits AVBUSERR | OVC | RLCHG | IDCHG */
++ reg &= ~OTGC_INT_B_TYPE;
++ /* set INT A: bits ASRPDET | AVBUSERR | OVC | RLCHG | IDCHG | APLGRMV */
++ reg |= OTGC_INT_A_TYPE;
++ __raw_writel(reg, hcd->regs + OTGC_INT_EN);
++
++ reg = __raw_readl(hcd->regs + GLOBAL_ICR);
++ reg &= ~GLOBAL_INT_MASK_OTG;
++ __raw_writel(reg, hcd->regs + GLOBAL_ICR);
++
++ /* setup MISC register, fixes timing problems */
++ reg = __raw_readl(hcd->regs + HCD_MISC);
++ reg |= 0xD;
++ __raw_writel(reg, hcd->regs + HCD_MISC);
++
++ fotg2xx_otgc_role_change(hcd);
++}
++
++static void fotg2xx_otgh_close(struct usb_hcd *hcd)
++{
++ unsigned int reg;
++
++ /* <1>.Enable Interrupt Mask */
++ reg = __raw_readl(hcd->regs + GLOBAL_ICR);
++ reg |= GLOBAL_INT_MASK_HC;
++ __raw_writel(reg, hcd->regs + GLOBAL_ICR);
++
++ /* <2>.Clear the Interrupt status */
++ reg = __raw_readl(hcd->regs + 0x18);
++ reg &= 0x0000003F;
++ __raw_writel(reg, hcd->regs + 0x14);
++}
++
++static void fotg2xx_otgh_open(struct usb_hcd *hcd)
++{
++ unsigned int reg;
++
++ reg = __raw_readl(hcd->regs + OTGC_SCR);
++ reg &= ~OTGC_SCR_A_SRP_DET_EN;
++ __raw_writel(reg, hcd->regs + OTGC_SCR);
++
++ reg = __raw_readl(hcd->regs + GLOBAL_ICR);
++ reg &= ~GLOBAL_INT_MASK_HC;
++ __raw_writel(reg, hcd->regs + GLOBAL_ICR);
++}
++
++/* change to host role */
++static void fotg2xx_otgc_role_change(struct usb_hcd *hcd)
++{
++
++ /* clear A_SET_B_HNP_EN */
++ otg_clear(0x80, BIT(6));
++
++ /*** Enable VBUS driving */
++ if (readl(hcd->regs + 0x80) & BIT(19))
++ printk(KERN_INFO "VBUS already enabled\n");
++ else {
++ int cnt = 0;
++
++ /* clear A_BUS_DROP */
++ otg_clear(0x80, BIT(5));
++
++ /* set A_BUS_REQ */
++ otg_set(0x80, BIT(4));
++
++ /* set global bus reg to VBUS on */
++ writel(readl(IO_ADDRESS(0x40000000) + 0x30) | ((BIT(21)|BIT(22))),
++ IO_ADDRESS(0x40000000) + 0x30);
++
++ if (readl(hcd->regs + 0x80) & (1<<19)) {
++ printk(KERN_INFO "Waiting for VBus");
++ while (!(readl(hcd->regs + 0x80) & (1<<19)) && (cnt < 80)) {
++ printk(KERN_CONT ".");
++ cnt++;
++ }
++ printk(KERN_CONT "\n");
++ } else
++ printk(KERN_INFO "VBUS enabled.\n");
++
++ mdelay(1);
++ }
++ fotg2xx_otgh_open(hcd);
++}
++
++static int fotg2xx_ehci_hc_reset(struct usb_hcd *hcd)
++{
++ int result;
++ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++ ehci->caps = hcd->regs;
++ ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
++
++ dbg_hcs_params(ehci, "reset");
++ dbg_hcc_params(ehci, "reset");
++
++ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++ hcd->has_tt = 1;
++
++ result = ehci_halt(ehci);
++ if (result)
++ return result;
++
++ result = ehci_init(hcd);
++ if (result)
++ return result;
++
++ ehci_port_power(ehci, 0);
++
++ return result;
++}
++
++/*
++ * Name: OTGC_INT_ISR
++ * Description:This interrupt service routine belongs to the OTG-Controller
++ * <1>.Check for ID_Change
++ * <2>.Check for RL_Change
++ * <3>.Error Detect
++ * Input: wINTStatus
++ * Output:void
++ */
++void fotg2xx_int_isr(struct usb_hcd *hcd, u32 wINTStatus)
++{
++ /* <1>.Check for ID_Change */
++ if (wINTStatus&OTGC_INT_IDCHG) {
++ if ((readl(hcd->regs + 0x80) & BIT(21)) != 0)
++ fotg2xx_otgc_init(hcd); /* Change to B Type */
++ else
++ fotg2xx_otgc_init(hcd); /* Change to A Type */
++
++ return;
++ }
++
++ /* <2>.Check for RL_Change */
++ if (wINTStatus&OTGC_INT_RLCHG)
++ fotg2xx_otgc_role_change(hcd);
++
++ /* <3>.Error Detect */
++ if (wINTStatus&OTGC_INT_AVBUSERR)
++ printk(KERN_ERR "VBus error!\n");
++
++ if (wINTStatus&OTGC_INT_OVC)
++ printk(KERN_WARNING "Overcurrent detected!\n");
++
++ /* <3>.Check for Type-A/Type-B Interrupt */
++ if ((readl(hcd->regs + 0x80) & BIT(21)) == 0) { /*For Type-A Interrupt*/
++ if (wINTStatus & (OTGC_INT_A_TYPE | OTGC_INT_ASRPDET)) {
++ /* <1>.SRP detected => then set global variable */
++ printk(KERN_WARNING "SRP detected, but not implemented!\n");
++
++#if 0
++ u32 wTempCounter;
++ /* <2>.Turn on the V Bus */
++ pFTC_OTG->otg.state = OTG_STATE_A_WAIT_VRISE;
++ OTGC_enable_vbus_draw_storlink(1);
++ pFTC_OTG->otg.state = OTG_STATE_A_HOST;
++ /* <3>.Should waiting for Device-Connect Wait 300ms */
++ INFO(pFTC_OTG, ">>> OTG-A Waiting for OTG-B Connect,\n");
++ wTempCounter = 0;
++ while (mwHost20_PORTSC_ConnectStatus_Rd() == 0) {
++ mdelay(1);
++ wTempCounter++;
++ /* Waiting for 300 ms */
++ if (wTempCounter > 300) {
++ mdwOTGC_Control_A_SRP_DET_EN_Clr();
++ INFO(pFTC_OTG, ">>> OTG-B do not connect under 300 ms...\n");
++ break;
++ }
++ }
++ /* <4>.If Connect => issue quick Reset */
++ if (mwHost20_PORTSC_ConnectStatus_Rd() > 0) {
++ mdelay(300); /* For OPT-A Test */
++ OTGH_host_quick_Reset();
++ OTGH_Open();
++ pFTC_OTG->otg.host->A_Disable_Set_Feature_HNP = 0;
++ }
++#endif
++ }
++ } else { /* For Type-B Interrupt */
++ BUG();
++ }
++}
++
++static irqreturn_t fotg2xx_ehci_irq(int irq, void *devid)
++{
++ struct usb_hcd *hcd = devid;
++ u32 val;
++
++ /* OTG Interrupt Status Register */
++ val = readl(hcd->regs + 0x84);
++
++ /* OTG stuff */
++ if (val) {
++ /* supposed to do "INT STS Clr" - XXX */
++ writel(readl(hcd->regs + 0x84) | val, hcd->regs + 0x84);
++
++ fotg2xx_int_isr(hcd, val);
++
++ /* supposed to do "INT STS Clr" - XXX */
++ writel(readl(hcd->regs + 0x84) | val, hcd->regs + 0x84);
++
++ return IRQ_HANDLED;
++ }
++
++ if ((readl(hcd->regs + 0x80) & BIT(20)) == 0) { /* Role is HOST */
++ if (readl(hcd->regs + 0xC0) & BIT(2)) { /* INT STS HOST */
++ /* leave this for ehci irq handler */
++ return IRQ_NONE;
++ }
++ } else
++ printk(KERN_WARNING
++ "received irq for peripheral - don't know what to do!\n");
++
++ /* do not call the ehci irq handler */
++ return IRQ_HANDLED;
++}
++
++static int fotg2xx_ehci_run(struct usb_hcd *hcd)
++{
++ int retval;
++
++ retval = ehci_run(hcd);
++
++ fotg2xx_otgh_close(hcd);
++ fotg2xx_otgc_init(hcd);
++
++ return retval;
++}
++
++static const struct hc_driver fotg2xx_ehci_hc_driver = {
++ .description = hcd_name,
++ .product_desc = "FOTG2XX EHCI Host Controller",
++ .hcd_priv_size = sizeof(struct ehci_hcd),
++ .irq = ehci_irq,
++ .flags = HCD_MEMORY | HCD_USB2,
++ .reset = fotg2xx_ehci_hc_reset,
++ .start = fotg2xx_ehci_run,
++ .stop = ehci_stop,
++ .shutdown = ehci_shutdown,
++
++ .urb_enqueue = ehci_urb_enqueue,
++ .urb_dequeue = ehci_urb_dequeue,
++ .endpoint_disable = ehci_endpoint_disable,
++ .endpoint_reset = ehci_endpoint_reset,
++
++ .get_frame_number = ehci_get_frame,
++
++ .hub_status_data = ehci_hub_status_data,
++ .hub_control = ehci_hub_control,
++#if defined(CONFIG_PM)
++ .bus_suspend = ehci_bus_suspend,
++ .bus_resume = ehci_bus_resume,
++#endif
++ .relinquish_port = ehci_relinquish_port,
++ .port_handed_over = ehci_port_handed_over,
++
++ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static int fotg2xx_ehci_probe(struct platform_device *pdev)
++{
++ const struct hc_driver *driver = &fotg2xx_ehci_hc_driver;
++ struct usb_hcd *hcd;
++ struct resource *res;
++ int irq;
++ int retval;
++
++ pr_debug("initializing FOTG2XX-SOC USB Controller\n");
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_err(&pdev->dev,
++ "Found HC with no IRQ. Check %s setup!\n",
++ dev_name(&pdev->dev));
++ return -ENODEV;
++ }
++
++ irq = res->start;
++
++ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++ if (!hcd) {
++ retval = -ENOMEM;
++ goto err1;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev,
++ "Found HC with no register addr. Check %s setup!\n",
++ dev_name(&pdev->dev));
++ retval = -ENODEV;
++ goto err2;
++ }
++
++ hcd->rsrc_start = res->start;
++ hcd->rsrc_len = res->end - res->start + 1;
++ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
++ driver->description)) {
++ dev_dbg(&pdev->dev, "controller already in use\n");
++ retval = -EBUSY;
++ goto err2;
++ }
++
++ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++ if (hcd->regs == NULL) {
++ dev_dbg(&pdev->dev, "error mapping memory\n");
++ retval = -EFAULT;
++ goto err3;
++ }
++
++
++ /* set global reg to mini-A host */
++ writel(readl(IO_ADDRESS(0x40000000) + 0x30) & ~(BIT(30)|BIT(29)),
++ IO_ADDRESS(0x40000000) + 0x30);
++
++ /* USB0&USB1 - VBUS off */
++ writel(readl(IO_ADDRESS(0x40000000) + 0x30) & ~(BIT(21)|BIT(22)),
++ IO_ADDRESS(0x40000000) + 0x30);
++
++ if ((readl(hcd->regs) == 0x01000010) &&
++ (readl(hcd->regs + 4) == 0x00000001) &&
++ (readl(hcd->regs + 8) == 0x00000006)) {
++ dev_info(&pdev->dev,
++ "Found Faraday OTG 2XX controller (base = 0x%08lX)\n",
++ (unsigned long) hcd->rsrc_start);
++ } else {
++ dev_err(&pdev->dev, "fotg2xx id mismatch: found %d.%d.%d\n",
++ readl(hcd->regs + 0x00),
++ readl(hcd->regs + 0x04),
++ readl(hcd->regs + 0x08));
++ retval = -ENODEV;
++ goto err4;
++ }
++
++ platform_set_drvdata(pdev, hcd);
++
++ /* mask interrupts - peripheral, otg, host, hi-active (bits 0,1,2,3) */
++ otg_set(0xc4, BIT(3)); /* hi active */
++
++ otg_set(0xc4, BIT(2)); /* host */
++ otg_set(0xc4, BIT(1)); /* otg */
++ otg_set(0xc4, BIT(0)); /* peripheral */
++
++ /* register additional interrupt - here we check otg status */
++ if ((request_irq(irq, &fotg2xx_ehci_irq, IRQF_SHARED | IRQF_DISABLED,
++ hcd->irq_descr, hcd)) != 0) {
++ dev_dbg(&pdev->dev, "error requesting irq %d\n", irq);
++ retval = -EFAULT;
++ goto err4;
++ }
++
++ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
++ if (retval != 0)
++ goto err4;
++ return retval;
++
++err4:
++ iounmap(hcd->regs);
++err3:
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err2:
++ usb_put_hcd(hcd);
++err1:
++ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
++ return retval;
++}
++
++/* may be called without controller electrically present */
++/* may be called with controller, bus, and devices active */
++
++int fotg2xx_ehci_remove(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd =
++ (struct usb_hcd *)platform_get_drvdata(pdev);
++
++ usb_remove_hcd(hcd);
++ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ iounmap(hcd->regs);
++ usb_put_hcd(hcd);
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++
++MODULE_ALIAS("platform:ehci-fotg2xx");
++
++static struct platform_driver fotg2xx_ehci_driver = {
++ .probe = fotg2xx_ehci_probe,
++ .remove = fotg2xx_ehci_remove,
++ .driver = {
++ .name = "ehci-fotg2xx",
++ },
++};
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -600,7 +600,12 @@ static inline unsigned int
+ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+ {
+ if (ehci_is_TDI(ehci)) {
++#ifdef CONFIG_ARCH_GEMINI
++ portsc = readl(ehci_to_hcd(ehci)->regs + 0x80);
++ switch ((portsc>>22)&3) {
++#else
+ switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
++#endif
+ case 0:
+ return 0;
+ case 1:
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -204,10 +204,12 @@ static int ehci_halt (struct ehci_hcd *e
+ * This routine gets called during probe before ehci->command
+ * has been initialized, so we can't rely on its value.
+ */
++#ifndef CONFIG_ARCH_GEMINI
+ ehci->command &= ~CMD_RUN;
+ temp = ehci_readl(ehci, &ehci->regs->command);
+ temp &= ~(CMD_RUN | CMD_IAAD);
+ ehci_writel(ehci, temp, &ehci->regs->command);
++#endif
+
+ spin_unlock_irq(&ehci->lock);
+ synchronize_irq(ehci_to_hcd(ehci)->irq);
+@@ -257,13 +259,17 @@ static int ehci_reset (struct ehci_hcd *
+ if (ehci->has_hostpc) {
+ ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
+ &ehci->regs->usbmode_ex);
++#ifndef CONFIG_ARCH_GEMINI
+ ehci_writel(ehci, TXFIFO_DEFAULT, &ehci->regs->txfill_tuning);
++#endif
+ }
+ if (retval)
+ return retval;
+
++#ifndef CONFIG_ARCH_GEMINI
+ if (ehci_is_TDI(ehci))
+ tdi_reset (ehci);
++#endif
+
+ if (ehci->debug)
+ dbgp_external_startup(ehci_to_hcd(ehci));
+@@ -340,11 +346,14 @@ static void ehci_silence_controller(stru
+ ehci->rh_state = EHCI_RH_HALTED;
+ ehci_turn_off_all_ports(ehci);
+
++#ifndef CONFIG_ARCH_GEMINI
+ /* make BIOS/etc use companion controller during reboot */
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+
+ /* unblock posted writes */
+ ehci_readl(ehci, &ehci->regs->configured_flag);
++#endif
++
+ spin_unlock_irq(&ehci->lock);
+ }
+
+@@ -599,7 +608,9 @@ static int ehci_run (struct usb_hcd *hcd
+ // Philips, Intel, and maybe others need CMD_RUN before the
+ // root hub will detect new devices (why?); NEC doesn't
+ ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
++#ifndef CONFIG_ARCH_GEMINI
+ ehci->command |= CMD_RUN;
++#endif
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ dbg_cmd (ehci, "init", ehci->command);
+
+@@ -619,9 +630,11 @@ static int ehci_run (struct usb_hcd *hcd
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ ehci->rh_state = EHCI_RH_RUNNING;
++#ifndef CONFIG_ARCH_GEMINI
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ msleep(5);
++#endif /* !CONFIG_ARCH_GEMINI */
+ up_write(&ehci_cf_port_reset_rwsem);
+ ehci->last_periodic_enable = ktime_get_real();
+
+@@ -1242,6 +1255,11 @@ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_AUTHOR (DRIVER_AUTHOR);
+ MODULE_LICENSE ("GPL");
+
++#ifdef CONFIG_ARCH_GEMINI
++#include "ehci-fotg2xx.c"
++#define PLATFORM_DRIVER fotg2xx_ehci_driver
++#endif
++
+ #ifdef CONFIG_USB_EHCI_FSL
+ #include "ehci-fsl.c"
+ #define PLATFORM_DRIVER ehci_fsl_driver
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -912,6 +912,12 @@ static int ehci_hub_control (
+ /* see what we found out */
+ temp = check_reset_complete (ehci, wIndex, status_reg,
+ ehci_readl(ehci, status_reg));
++#ifdef CONFIG_ARCH_GEMINI
++ /* restart schedule */
++ ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) | CMD_RUN, &ehci->regs->command);
++
++// hcd->state = HC_STATE_RUNNING;
++#endif
+ }
+
+ if (!(temp & (PORT_RESUME|PORT_RESET))) {
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -47,6 +47,7 @@ config USB_ARCH_HAS_EHCI
+ default y if MICROBLAZE
+ default y if SPARC_LEON
+ default y if ARCH_MMP
++ default y if ARCH_GEMINI
+ default y if MACH_LOONGSON1
+ default y if PLAT_ORION
+ default PCI
+@@ -96,7 +97,7 @@ config USB
+ traditional PC serial port. The bus supplies power to peripherals
+ and allows for hot swapping. Up to 127 USB peripherals can be
+ connected to a single USB host in a tree structure.
+-
++
+ The USB host is the root of the tree, the peripherals are the
+ leaves and the inner nodes are special USB devices called hubs.
+ Most PCs now have USB host ports, used to connect peripherals
+--- a/include/linux/usb/ehci_def.h
++++ b/include/linux/usb/ehci_def.h
+@@ -111,6 +111,7 @@ struct ehci_regs {
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
++#ifndef CONFIG_ARCH_GEMINI
+ u32 reserved1[2];
+
+ /* TXFILLTUNING: offset 0x24 */
+@@ -118,6 +119,7 @@ struct ehci_regs {
+ #define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
+
+ u32 reserved2[6];
++#endif /* !CONFIG_ARCH_GEMINI */
+
+ /* CONFIGFLAG: offset 0x40 */
+ u32 configured_flag;