aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/gemini/patches-3.3/130-usb-ehci-gemini-fot2gxx-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/gemini/patches-3.3/130-usb-ehci-gemini-fot2gxx-support.patch')
-rw-r--r--target/linux/gemini/patches-3.3/130-usb-ehci-gemini-fot2gxx-support.patch615
1 files changed, 615 insertions, 0 deletions
diff --git a/target/linux/gemini/patches-3.3/130-usb-ehci-gemini-fot2gxx-support.patch b/target/linux/gemini/patches-3.3/130-usb-ehci-gemini-fot2gxx-support.patch
new file mode 100644
index 0000000000..50ee4ab766
--- /dev/null
+++ b/target/linux/gemini/patches-3.3/130-usb-ehci-gemini-fot2gxx-support.patch
@@ -0,0 +1,615 @@
+--- /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
+@@ -581,7 +581,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
+@@ -227,9 +227,11 @@ static int ehci_halt (struct ehci_hcd *e
+ if ((temp & STS_HALT) != 0)
+ return 0;
+
++#ifndef CONFIG_ARCH_GEMINI
+ temp = ehci_readl(ehci, &ehci->regs->command);
+ temp &= ~CMD_RUN;
+ ehci_writel(ehci, temp, &ehci->regs->command);
++#endif
+ return handshake (ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
+ }
+@@ -342,8 +344,10 @@ static int ehci_reset (struct ehci_hcd *
+ if (retval)
+ return retval;
+
++#ifndef CONFIG_ARCH_GEMINI
+ if (ehci_is_TDI(ehci))
+ tdi_reset (ehci);
++#endif
+
+ if (ehci->debug)
+ dbgp_external_startup();
+@@ -478,12 +482,13 @@ static void ehci_silence_controller(stru
+ {
+ ehci_halt(ehci);
+ 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
+ }
+
+ /* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
+@@ -764,7 +769,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);
+
+@@ -784,9 +791,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();
+
+@@ -958,7 +967,9 @@ static irqreturn_t ehci_irq (struct usb_
+ ehci_halt(ehci);
+ dead:
+ ehci_reset(ehci);
++#ifndef CONFIG_ARCH_GEMINI
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
++#endif
+ usb_hc_died(hcd);
+ /* generic layer kills/unlinks all urbs, then
+ * uses ehci_stop to clean up the rest
+@@ -1256,6 +1267,11 @@ MODULE_LICENSE ("GPL");
+ #define PCI_DRIVER ehci_pci_driver
+ #endif
+
++#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
+@@ -882,6 +882,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
+@@ -76,6 +76,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 PCI
+
+ # some non-PCI HCDs implement xHCI
+@@ -94,7 +95,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
+@@ -110,9 +110,9 @@ struct ehci_regs {
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+-
++#ifndef CONFIG_ARCH_GEMINI
+ u32 reserved[9];
+-
++#endif
+ /* CONFIGFLAG: offset 0x40 */
+ u32 configured_flag;
+ #define FLAG_CF (1<<0) /* true: we'll support "high speed" */