brcm47xx: add new usb driver for bcma bus and replace ssb usb driver.
authorHauke Mehrtens <hauke@hauke-m.de>
Mon, 19 Dec 2011 23:39:13 +0000 (23:39 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Mon, 19 Dec 2011 23:39:13 +0000 (23:39 +0000)
This new usb driver uses an extra device so the ehci and the ohci driver are not depending on ech other any more.

SVN-Revision: 29575

package/kernel/modules/usb.mk
target/linux/brcm47xx/patches-3.0/0028-bcma-scan-for-extra-address-space.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/0029-bcma-add-function-to-check-every-10-s-if-a-reg-is-se.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/0030-USB-OHCI-Add-a-generic-platform-device-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/0031-USB-EHCI-Add-a-generic-platform-device-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/0032-USB-Add-driver-for-the-bcma-bus.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/0033-USB-Add-driver-for-the-ssb-bus.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/0034-USB-OHCI-remove-old-SSB-OHCI-driver.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.0/022-USB-Add-ehci-ssb-driver.patch [deleted file]
target/linux/brcm47xx/patches-3.0/023-usb_ehci_ohci.patch [deleted file]
target/linux/brcm47xx/patches-3.0/280-activate_ssb_support_in_usb.patch

index 834baa984f17ff4696d65982b475703976ff7f63..fd027bca613962f99ac0358a601dd442bbc92457 100644 (file)
@@ -88,6 +88,7 @@ $(eval $(call KernelPackage,usb-uhci,1))
 
 define KernelPackage/usb-ohci
   TITLE:=Support for OHCI controllers
+  DEPENDS:=+TARGET_brcm47xx:kmod-usb-brcm47xx
   KCONFIG:= \
        CONFIG_USB_OHCI \
        CONFIG_USB_OHCI_HCD \
@@ -199,6 +200,7 @@ $(eval $(call KernelPackage,usb-isp116x-hcd))
 
 define KernelPackage/usb2
   TITLE:=Support for USB2 controllers
+  DEPENDS:=+TARGET_brcm47xx:kmod-usb-brcm47xx
   KCONFIG:=CONFIG_USB_EHCI_HCD \
     CONFIG_USB_EHCI_AR71XX=y \
     CONFIG_USB_OCTEON_EHCI=y \
@@ -983,3 +985,20 @@ define KernelPackage/usb-rt305x-dwc_otg/description
 endef
 
 $(eval $(call KernelPackage,usb-rt305x-dwc_otg))
+
+define KernelPackage/usb-brcm47xx
+  SUBMENU:=$(USB_MENU)
+  TITLE:=Support for USB on bcm47xx
+  DEPENDS:=@USB_SUPPORT @TARGET_brcm47xx
+  KCONFIG:= \
+       CONFIG_USB_HCD_BCMA \
+       CONFIG_USB_HCD_SSB
+  FILES:= \
+       $(LINUX_DIR)/drivers/usb/host/bcma-hcd.ko \
+       $(LINUX_DIR)/drivers/usb/host/ssb-hcd.ko
+  AUTOLOAD:=$(call AutoLoad,19,bcma-hcd ssb-hcd,1)
+  $(call AddDepends/usb)
+endef
+
+$(eval $(call KernelPackage,usb-brcm47xx))
+
diff --git a/target/linux/brcm47xx/patches-3.0/0028-bcma-scan-for-extra-address-space.patch b/target/linux/brcm47xx/patches-3.0/0028-bcma-scan-for-extra-address-space.patch
new file mode 100644 (file)
index 0000000..d74dfcb
--- /dev/null
@@ -0,0 +1,60 @@
+From 1735daf1db79d338dccfc55444b52ed52af79e86 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 20 Nov 2011 18:22:35 +0100
+Subject: [PATCH 15/21] bcma: scan for extra address space
+
+Some cores like the USB core have two address spaces. In the USB host
+controller one address space is used for the OHCI and the other for the
+EHCI controller interface. The USB controller is the only core I found
+with two address spaces. This code is based on the AI scan function
+ai_scan() in shared/aiutils.c i the Broadcom SDK.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/scan.c       |   17 ++++++++++++++++-
+ include/linux/bcma/bcma.h |    1 +
+ 2 files changed, 17 insertions(+), 1 deletions(-)
+
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -286,6 +286,21 @@ static int bcma_get_next_core(struct bcm
+                       return -EILSEQ;
+       }
++
++      /* First Slave Address Descriptor should be port 0:
++       * the main register space for the core
++       */
++      tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
++      if (tmp < 0) {
++              /* Try again to see if it is a bridge */
++              tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_BRIDGE, 0);
++              if (tmp) {
++                      printk("found bridge\n");
++              }
++
++      }
++      core->addr = tmp;
++
+       /* get & parse slave ports */
+       for (i = 0; i < ports[1]; i++) {
+               for (j = 0; ; j++) {
+@@ -298,7 +313,7 @@ static int bcma_get_next_core(struct bcm
+                               break;
+                       } else {
+                               if (i == 0 && j == 0)
+-                                      core->addr = tmp;
++                                      core->addr1 = tmp;
+                       }
+               }
+       }
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -138,6 +138,7 @@ struct bcma_device {
+       u8 core_index;
+       u32 addr;
++      u32 addr1;
+       u32 wrap;
+       void __iomem *io_addr;
diff --git a/target/linux/brcm47xx/patches-3.0/0029-bcma-add-function-to-check-every-10-s-if-a-reg-is-se.patch b/target/linux/brcm47xx/patches-3.0/0029-bcma-add-function-to-check-every-10-s-if-a-reg-is-se.patch
new file mode 100644 (file)
index 0000000..2c0462f
--- /dev/null
@@ -0,0 +1,115 @@
+From 6e8ae6e2cee0e7e5939dc7042584c808366e61e0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 27 Nov 2011 14:01:01 +0100
+Subject: [PATCH 16/21] =?UTF-8?q?bcma:=20add=20function=20to=20check=20every?=
+ =?UTF-8?q?=2010=20=C2=B5s=20if=20a=20reg=20is=20set?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This function checks if a reg get set or cleared every 10 microseconds.
+It is used in bcma_core_set_clockmode() and bcma_core_pll_ctl() to
+reduce code duplication. In addition it is needed in the USB host
+driver.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/core.c       |   48 ++++++++++++++++++++++++++++----------------
+ include/linux/bcma/bcma.h |    2 +
+ 2 files changed, 32 insertions(+), 18 deletions(-)
+
+--- a/drivers/bcma/core.c
++++ b/drivers/bcma/core.c
+@@ -51,11 +51,36 @@ int bcma_core_enable(struct bcma_device
+ }
+ EXPORT_SYMBOL_GPL(bcma_core_enable);
++/* Wait for bitmask in a register to get set or cleared.
++ * timeout is in units of ten-microseconds.
++ */
++int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask, int timeout,
++                 int set)
++{
++      int i;
++      u32 val;
++
++      for (i = 0; i < timeout; i++) {
++              val = bcma_read32(dev, reg);
++              if (set) {
++                      if ((val & bitmask) == bitmask)
++                              return 0;
++              } else {
++                      if (!(val & bitmask))
++                              return 0;
++              }
++              udelay(10);
++      }
++      pr_err("Timeout waiting for bitmask %08X on register %04X to %s.\n",
++             bitmask, reg, (set ? "set" : "clear"));
++
++      return -ETIMEDOUT;
++}
++EXPORT_SYMBOL_GPL(bcma_wait_bits);
++
+ void bcma_core_set_clockmode(struct bcma_device *core,
+                            enum bcma_clkmode clkmode)
+ {
+-      u16 i;
+-
+       WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON &&
+               core->id.id != BCMA_CORE_PCIE &&
+               core->id.id != BCMA_CORE_80211);
+@@ -64,15 +89,8 @@ void bcma_core_set_clockmode(struct bcma
+       case BCMA_CLKMODE_FAST:
+               bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+               udelay(64);
+-              for (i = 0; i < 1500; i++) {
+-                      if (bcma_read32(core, BCMA_CLKCTLST) &
+-                          BCMA_CLKCTLST_HAVEHT) {
+-                              i = 0;
+-                              break;
+-                      }
+-                      udelay(10);
+-              }
+-              if (i)
++              if (bcma_wait_bits(core, BCMA_CLKCTLST, BCMA_CLKCTLST_HAVEHT,
++                                 1500, 1))
+                       pr_err("HT force timeout\n");
+               break;
+       case BCMA_CLKMODE_DYNAMIC:
+@@ -84,22 +102,12 @@ EXPORT_SYMBOL_GPL(bcma_core_set_clockmod
+ void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
+ {
+-      u16 i;
+-
+       WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ);
+       WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST);
+       if (on) {
+               bcma_set32(core, BCMA_CLKCTLST, req);
+-              for (i = 0; i < 10000; i++) {
+-                      if ((bcma_read32(core, BCMA_CLKCTLST) & status) ==
+-                          status) {
+-                              i = 0;
+-                              break;
+-                      }
+-                      udelay(10);
+-              }
+-              if (i)
++              if (bcma_wait_bits(core, BCMA_CLKCTLST, status, 10000, 1))
+                       pr_err("PLL enable timeout\n");
+       } else {
+               pr_warn("Disabling PLL not supported yet!\n");
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -283,6 +283,9 @@ static inline void bcma_maskset16(struct
+       bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
+ }
++extern int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
++                        int timeout, int set);
++
+ extern bool bcma_core_is_enabled(struct bcma_device *core);
+ extern void bcma_core_disable(struct bcma_device *core, u32 flags);
+ extern int bcma_core_enable(struct bcma_device *core, u32 flags);
diff --git a/target/linux/brcm47xx/patches-3.0/0030-USB-OHCI-Add-a-generic-platform-device-driver.patch b/target/linux/brcm47xx/patches-3.0/0030-USB-OHCI-Add-a-generic-platform-device-driver.patch
new file mode 100644 (file)
index 0000000..51b112a
--- /dev/null
@@ -0,0 +1,291 @@
+From b39adeae5b06e40699c174ed78ca7c45b8d7976f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 26 Nov 2011 21:20:54 +0100
+Subject: [PATCH 17/21] USB: OHCI: Add a generic platform device driver
+
+This adds a generic driver for platform devices. It works like the PCI
+driver and is based on it. This is for devices which do not have an own
+bus but their OHCI controller works like a PCI controller. It will be
+used for the Broadcom bcma and ssb USB OHCI controller.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/Kconfig         |   10 ++
+ drivers/usb/host/ohci-hcd.c      |   21 ++++-
+ drivers/usb/host/ohci-platform.c |  197 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 227 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/usb/host/ohci-platform.c
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -378,6 +378,16 @@ config USB_CNS3XXX_OHCI
+         Enable support for the CNS3XXX SOC's on-chip OHCI controller.
+         It is needed for low-speed USB 1.0 device support.
++config USB_OHCI_HCD_PLATFORM
++      bool "OHCI driver for a platform device"
++      depends on USB_OHCI_HCD && EXPERIMENTAL
++      default n
++      ---help---
++        Adds an OHCI host driver for a generic platform device, which
++        provieds a memory space and an irq.
++
++        If unsure, say N.
++
+ config USB_OHCI_BIG_ENDIAN_DESC
+       bool
+       depends on USB_OHCI_HCD
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -1114,6 +1114,11 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER               ohci_hcd_ath79_driver
+ #endif
++#ifdef CONFIG_USB_OHCI_HCD_PLATFORM
++#include "ohci-platform.c"
++#define PLATFORM_OHCI_DRIVER  ohci_platform_driver
++#endif
++
+ #if   !defined(PCI_DRIVER) &&         \
+       !defined(PLATFORM_DRIVER) &&    \
+       !defined(OMAP1_PLATFORM_DRIVER) &&      \
+@@ -1123,7 +1128,8 @@ MODULE_LICENSE ("GPL");
+       !defined(PS3_SYSTEM_BUS_DRIVER) && \
+       !defined(SM501_OHCI_DRIVER) && \
+       !defined(TMIO_OHCI_DRIVER) && \
+-      !defined(SSB_OHCI_DRIVER)
++      !defined(SSB_OHCI_DRIVER) && \
++      !defined(PLATFORM_OHCI_DRIVER)
+ #error "missing bus glue for ohci-hcd"
+ #endif
+@@ -1207,9 +1213,19 @@ static int __init ohci_hcd_mod_init(void
+               goto error_tmio;
+ #endif
++#ifdef PLATFORM_OHCI_DRIVER
++      retval = platform_driver_register(&PLATFORM_OHCI_DRIVER);
++      if (retval)
++              goto error_platform;
++#endif
++
+       return retval;
+       /* Error path */
++#ifdef PLATFORM_OHCI_DRIVER
++      platform_driver_unregister(&PLATFORM_OHCI_DRIVER);
++ error_platform:
++#endif
+ #ifdef TMIO_OHCI_DRIVER
+       platform_driver_unregister(&TMIO_OHCI_DRIVER);
+  error_tmio:
+@@ -1263,6 +1279,9 @@ module_init(ohci_hcd_mod_init);
+ static void __exit ohci_hcd_mod_exit(void)
+ {
++#ifdef PLATFORM_OHCI_DRIVER
++      platform_driver_unregister(&PLATFORM_OHCI_DRIVER);
++#endif
+ #ifdef TMIO_OHCI_DRIVER
+       platform_driver_unregister(&TMIO_OHCI_DRIVER);
+ #endif
+--- /dev/null
++++ b/drivers/usb/host/ohci-platform.c
+@@ -0,0 +1,197 @@
++/*
++ * Generic platform ohci driver
++ *
++ * Copyright 2007 Michael Buesch <m@bues.ch>
++ * Copyright 2011 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Derived from the OHCI-PCI driver
++ * Copyright 1999 Roman Weissgaerber
++ * Copyright 2000-2002 David Brownell
++ * Copyright 1999 Linus Torvalds
++ * Copyright 1999 Gregory P. Smith
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++#include <linux/platform_device.h>
++
++static int ohci_platform_reset(struct usb_hcd *hcd)
++{
++      struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++      int err;
++
++      ohci_hcd_init(ohci);
++      err = ohci_init(ohci);
++
++      return err;
++}
++
++static int ohci_platform_start(struct usb_hcd *hcd)
++{
++      struct ohci_hcd *ohci = hcd_to_ohci(hcd);
++      int err;
++
++      err = ohci_run(ohci);
++      if (err < 0) {
++              ohci_err(ohci, "can't start\n");
++              ohci_stop(hcd);
++      }
++
++      return err;
++}
++
++static const struct hc_driver ohci_platform_hc_driver = {
++      .description            = "platform-usb-ohci",
++      .product_desc           = "Generic Platform OHCI Controller",
++      .hcd_priv_size          = sizeof(struct ohci_hcd),
++
++      .irq                    = ohci_irq,
++      .flags                  = HCD_MEMORY | HCD_USB11,
++
++      .reset                  = ohci_platform_reset,
++      .start                  = ohci_platform_start,
++      .stop                   = ohci_stop,
++      .shutdown               = ohci_shutdown,
++
++      .urb_enqueue            = ohci_urb_enqueue,
++      .urb_dequeue            = ohci_urb_dequeue,
++      .endpoint_disable       = ohci_endpoint_disable,
++
++      .get_frame_number       = ohci_get_frame,
++
++      .hub_status_data        = ohci_hub_status_data,
++      .hub_control            = ohci_hub_control,
++#ifdef        CONFIG_PM
++      .bus_suspend            = ohci_bus_suspend,
++      .bus_resume             = ohci_bus_resume,
++#endif
++
++      .start_port_reset       = ohci_start_port_reset,
++};
++
++static int ohci_platform_attach(struct platform_device *dev)
++{
++      struct usb_hcd *hcd;
++      struct resource *res_irq, *res_mem;
++      int err = -ENOMEM;
++
++      hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
++                      dev_name(&dev->dev));
++      if (!hcd)
++              goto err_return;
++
++      res_irq = platform_get_resource(dev, IORESOURCE_IRQ, 0);
++      if (!res_irq) {
++              err = -ENXIO;
++              goto err_return;
++      }
++      res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
++      if (!res_mem) {
++              err = -ENXIO;
++              goto err_return;
++      }
++      hcd->rsrc_start = res_mem->start;
++      hcd->rsrc_len = res_mem->end - res_mem->start + 1;
++
++      hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
++      if (!hcd->regs)
++              goto err_put_hcd;
++      err = usb_add_hcd(hcd, res_irq->start, IRQF_SHARED);
++      if (err)
++              goto err_iounmap;
++
++      platform_set_drvdata(dev, hcd);
++
++      return err;
++
++err_iounmap:
++      iounmap(hcd->regs);
++err_put_hcd:
++      usb_put_hcd(hcd);
++err_return:
++      return err;
++}
++
++static int ohci_platform_probe(struct platform_device *dev)
++{
++      int err;
++
++      if (usb_disabled())
++              return -ENODEV;
++
++      /* We currently always attach BCMA_DEV_USB11_HOSTDEV
++       * as HOST OHCI. If we want to attach it as Client device,
++       * we must branch here and call into the (yet to
++       * be written) Client mode driver. Same for remove(). */
++
++      err = ohci_platform_attach(dev);
++
++      return err;
++}
++
++static int ohci_platform_remove(struct platform_device *dev)
++{
++      struct usb_hcd *hcd;
++
++      hcd = platform_get_drvdata(dev);
++      if (!hcd)
++              return -ENODEV;
++
++      usb_remove_hcd(hcd);
++      iounmap(hcd->regs);
++      release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++      usb_put_hcd(hcd);
++
++      return 0;
++}
++
++static void ohci_platform_shutdown(struct platform_device *dev)
++{
++      struct usb_hcd *hcd;
++
++      hcd = platform_get_drvdata(dev);
++      if (!hcd)
++              return;
++
++      if (hcd->driver->shutdown)
++              hcd->driver->shutdown(hcd);
++}
++
++#ifdef CONFIG_PM
++
++static int ohci_platform_suspend(struct platform_device *dev,
++                               pm_message_t state)
++{
++
++      return 0;
++}
++
++static int ohci_platform_resume(struct platform_device *dev)
++{
++      struct usb_hcd *hcd = platform_get_drvdata(dev);
++
++      ohci_finish_controller_resume(hcd);
++      return 0;
++}
++
++#else /* !CONFIG_PM */
++#define ohci_platform_suspend NULL
++#define ohci_platform_resume  NULL
++#endif /* CONFIG_PM */
++
++static const struct platform_device_id ohci_platform_table[] = {
++      { "ohci-platform", 0 },
++      { }
++};
++MODULE_DEVICE_TABLE(platform, ohci_platform_table);
++
++static struct platform_driver ohci_platform_driver = {
++      .id_table       = ohci_platform_table,
++      .probe          = ohci_platform_probe,
++      .remove         = ohci_platform_remove,
++      .shutdown       = ohci_platform_shutdown,
++      .suspend        = ohci_platform_suspend,
++      .resume         = ohci_platform_resume,
++      .driver         = {
++              .name   = "ohci-platform",
++      }
++};
diff --git a/target/linux/brcm47xx/patches-3.0/0031-USB-EHCI-Add-a-generic-platform-device-driver.patch b/target/linux/brcm47xx/patches-3.0/0031-USB-EHCI-Add-a-generic-platform-device-driver.patch
new file mode 100644 (file)
index 0000000..43cf86a
--- /dev/null
@@ -0,0 +1,265 @@
+From aa05e0048cec25719921291e8749674b8cc66fc0 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 26 Nov 2011 21:28:56 +0100
+Subject: [PATCH 18/21] USB: EHCI: Add a generic platform device driver
+
+This adds a generic driver for platform devices. It works like the PCI
+driver and is based on it. This is for devices which do not have an own
+bus but their EHCI controller works like a PCI controller. It will be
+used for the Broadcom bcma and ssb USB EHCI controller.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/Kconfig         |   10 ++
+ drivers/usb/host/ehci-hcd.c      |    5 +
+ drivers/usb/host/ehci-platform.c |  211 ++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 226 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/usb/host/ehci-platform.c
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -388,6 +388,16 @@ config USB_OHCI_HCD_PLATFORM
+         If unsure, say N.
++config USB_EHCI_HCD_PLATFORM
++      bool "Generic EHCI driver for a platform device"
++      depends on USB_EHCI_HCD && EXPERIMENTAL
++      default n
++      ---help---
++        Adds an EHCI host driver for a generic platform device, which
++        provieds a memory space and an irq.
++
++        If unsure, say N.
++
+ config USB_OHCI_BIG_ENDIAN_DESC
+       bool
+       depends on USB_OHCI_HCD
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -1312,6 +1312,11 @@ MODULE_LICENSE ("GPL");
+ #define PLATFORM_DRIVER               ehci_grlib_driver
+ #endif
++#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
++#include "ehci-platform.c"
++#define PLATFORM_DRIVER               ehci_platform_driver
++#endif
++
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
+     !defined(XILINX_OF_PLATFORM_DRIVER)
+--- /dev/null
++++ b/drivers/usb/host/ehci-platform.c
+@@ -0,0 +1,211 @@
++/*
++ * Generic platform ehci driver
++ *
++ * Copyright 2007 Steven Brown <sbrown@cortland.com>
++ * Copyright 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Derived from the ohci-ssb driver
++ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
++ *
++ * Derived from the EHCI-PCI driver
++ * Copyright (c) 2000-2004 by David Brownell
++ *
++ * Derived from the ohci-pci driver
++ * Copyright 1999 Roman Weissgaerber
++ * Copyright 2000-2002 David Brownell
++ * Copyright 1999 Linus Torvalds
++ * Copyright 1999 Gregory P. Smith
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++#include <linux/platform_device.h>
++
++static int ehci_platform_reset(struct usb_hcd *hcd)
++{
++      struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++      int retval;
++
++      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");
++
++      /* cache this readonly data; minimize chip reads */
++      ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++      retval = ehci_halt(ehci);
++      if (retval)
++              return retval;
++
++      /* data structure init */
++      retval = ehci_init(hcd);
++      if (retval)
++              return retval;
++
++      ehci_reset(ehci);
++
++      ehci_port_power(ehci, 1);
++
++      return retval;
++}
++
++static const struct hc_driver ehci_platform_hc_driver = {
++      .description            = "platform-usb-ehci",
++      .product_desc           = "Generic Platform EHCI Controller",
++      .hcd_priv_size          = sizeof(struct ehci_hcd),
++
++      .irq                    = ehci_irq,
++      .flags                  = HCD_MEMORY | HCD_USB2,
++
++      .reset                  = ehci_platform_reset,
++      .start                  = 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,
++
++      .update_device          = ehci_update_device,
++
++      .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
++};
++
++static int ehci_platform_attach(struct platform_device *dev)
++{
++      struct usb_hcd *hcd;
++      struct resource *res_irq, *res_mem;
++      int err = -ENOMEM;
++
++      hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
++                           dev_name(&dev->dev));
++      if (!hcd)
++              goto err_return;
++
++      res_irq = platform_get_resource(dev, IORESOURCE_IRQ, 0);
++      if (!res_irq) {
++              err = -ENXIO;
++              goto err_return;
++      }
++      res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
++      if (!res_mem) {
++              err = -ENXIO;
++              goto err_return;
++      }
++      hcd->rsrc_start = res_mem->start;
++      hcd->rsrc_len = res_mem->end - res_mem->start + 1;
++
++      /*
++       * start & size modified per sbutils.c
++       */
++      hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
++      if (!hcd->regs)
++              goto err_put_hcd;
++      err = usb_add_hcd(hcd, res_irq->start, IRQF_SHARED);
++      if (err)
++              goto err_iounmap;
++
++      platform_set_drvdata(dev, hcd);
++
++      return err;
++
++err_iounmap:
++      iounmap(hcd->regs);
++err_put_hcd:
++      usb_put_hcd(hcd);
++err_return:
++      return err;
++}
++
++static int ehci_platform_probe(struct platform_device *dev)
++{
++      int err;
++
++      if (usb_disabled())
++              return -ENODEV;
++
++      err = ehci_platform_attach(dev);
++
++      return err;
++}
++
++static int ehci_platform_remove(struct platform_device *dev)
++{
++      struct usb_hcd *hcd;
++
++      hcd = platform_get_drvdata(dev);
++      if (!hcd)
++              return -ENODEV;
++
++      usb_remove_hcd(hcd);
++      iounmap(hcd->regs);
++      release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++      usb_put_hcd(hcd);
++
++      return 0;
++}
++
++static void ehci_platform_shutdown(struct platform_device *dev)
++{
++      struct usb_hcd *hcd;
++
++      hcd = platform_get_drvdata(dev);
++      if (!hcd)
++              return;
++
++      if (hcd->driver->shutdown)
++              hcd->driver->shutdown(hcd);
++}
++
++#ifdef CONFIG_PM
++
++static int ehci_platform_suspend(struct platform_device *dev,
++                               pm_message_t state)
++{
++      return 0;
++}
++
++static int ehci_platform_resume(struct platform_device *dev)
++{
++      struct usb_hcd *hcd = platform_get_drvdata(dev);
++
++      ehci_finish_controller_resume(hcd);
++      return 0;
++}
++
++#else /* !CONFIG_PM */
++#define ehci_platform_suspend NULL
++#define ehci_platform_resume  NULL
++#endif /* CONFIG_PM */
++
++static const struct platform_device_id ehci_platform_table[] = {
++      { "ehci-platform", 0 },
++      { }
++};
++MODULE_DEVICE_TABLE(platform, ehci_platform_table);
++
++static struct platform_driver ehci_platform_driver = {
++      .id_table       = ehci_platform_table,
++      .probe          = ehci_platform_probe,
++      .remove         = ehci_platform_remove,
++      .shutdown       = ehci_platform_shutdown,
++      .suspend        = ehci_platform_suspend,
++      .resume         = ehci_platform_resume,
++      .driver         = {
++              .name   = "ehci-platform",
++      }
++};
diff --git a/target/linux/brcm47xx/patches-3.0/0032-USB-Add-driver-for-the-bcma-bus.patch b/target/linux/brcm47xx/patches-3.0/0032-USB-Add-driver-for-the-bcma-bus.patch
new file mode 100644 (file)
index 0000000..3a35ac8
--- /dev/null
@@ -0,0 +1,347 @@
+From 7151c34627b938486008cfab25bfb4e4f730a021 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 26 Nov 2011 21:33:41 +0100
+Subject: [PATCH 19/21] USB: Add driver for the bcma bus
+
+This adds a USB driver using the generic platform device driver for the
+USB controller found on the Broadcom bcma bus. The bcma bus just
+exposes one device which serves the OHCI and the EHCI controller at the
+same time. This driver probes for this USB controller and creates and
+registers two new platform devices which will be probed by the new
+generic platform device driver. This makes it possible to use the EHCI
+and the OCHI controller on the bcma bus at the same time.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/Kconfig    |   12 ++
+ drivers/usb/host/Makefile   |    1 +
+ drivers/usb/host/bcma-hcd.c |  350 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 363 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/usb/host/bcma-hcd.c
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -598,3 +598,15 @@ config USB_OCTEON_OHCI
+ config USB_OCTEON2_COMMON
+       bool
+       default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
++
++config USB_HCD_BCMA
++      tristate "BCMA usb host driver"
++      depends on BCMA && EXPERIMENTAL
++      select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
++      select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
++      help
++        Enbale support for the EHCI and OCHI host controller on an bcma bus.
++        It converts the bcma driver into two platform device drivers
++        for ehci and ohci.
++
++        If unsure, say N.
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -35,3 +35,4 @@ obj-$(CONFIG_USB_HWA_HCD)    += hwa-hc.o
+ obj-$(CONFIG_USB_IMX21_HCD)   += imx21-hcd.o
+ obj-$(CONFIG_USB_FSL_MPH_DR_OF)       += fsl-mph-dr-of.o
+ obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
++obj-$(CONFIG_USB_HCD_BCMA)    += bcma-hcd.o
+--- /dev/null
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -0,0 +1,298 @@
++/*
++ * Broadcom specific Advanced Microcontroller Bus
++ * Broadcom USB-core driver (BCMA bus glue)
++ *
++ * Copyright 2011 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Based on ssb-ohci driver
++ * Copyright 2007 Michael Buesch <m@bues.ch>
++ *
++ * Derived from the OHCI-PCI driver
++ * Copyright 1999 Roman Weissgaerber
++ * Copyright 2000-2002 David Brownell
++ * Copyright 1999 Linus Torvalds
++ * Copyright 1999 Gregory P. Smith
++ *
++ * Derived from the USBcore related parts of Broadcom-SB
++ * Copyright 2005-2011 Broadcom Corporation
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++#include <linux/bcma/bcma.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/module.h>
++
++MODULE_AUTHOR("Hauke Mehrtens");
++MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
++MODULE_LICENSE("GPL");
++
++#define BCMA_CORE_SIZE                0x1000
++
++struct bcma_hcd_device {
++      struct platform_device *ehci_dev;
++      struct platform_device *ohci_dev;
++};
++
++/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
++static void bcma_hcd_init_chip(struct bcma_device *dev)
++{
++      u32 tmp;
++
++      /*
++       * USB 2.0 special considerations:
++       *
++       * 1. Since the core supports both OHCI and EHCI functions, it must
++       *    only be reset once.
++       *
++       * 2. In addition to the standard SI reset sequence, the Host Control
++       *    Register must be programmed to bring the USB core and various
++       *    phy components out of reset.
++       */
++      if (!bcma_core_is_enabled(dev)) {
++              bcma_core_enable(dev, 0);
++              mdelay(10);
++              if (dev->id.rev >= 5) {
++                      /* Enable Misc PLL */
++                      tmp = bcma_read32(dev, 0x1e0);
++                      tmp |= 0x100;
++                      bcma_write32(dev, 0x1e0, tmp);
++                      if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100, 0))
++                              printk(KERN_EMERG "Failed to enable misc PPL!\n");
++
++                      /* Take out of resets */
++                      bcma_write32(dev, 0x200, 0x4ff);
++                      udelay(25);
++                      bcma_write32(dev, 0x200, 0x6ff);
++                      udelay(25);
++
++                      /* Make sure digital and AFE are locked in USB PHY */
++                      bcma_write32(dev, 0x524, 0x6b);
++                      udelay(50);
++                      tmp = bcma_read32(dev, 0x524);
++                      udelay(50);
++                      bcma_write32(dev, 0x524, 0xab);
++                      udelay(50);
++                      tmp = bcma_read32(dev, 0x524);
++                      udelay(50);
++                      bcma_write32(dev, 0x524, 0x2b);
++                      udelay(50);
++                      tmp = bcma_read32(dev, 0x524);
++                      udelay(50);
++                      bcma_write32(dev, 0x524, 0x10ab);
++                      udelay(50);
++                      tmp = bcma_read32(dev, 0x524);
++
++                      if (bcma_wait_bits(dev, 0x528, 0xc000, 10000, 1))
++                              printk(KERN_EMERG
++                                     "USB20H mdio_rddata 0x%08x\n", tmp);
++
++                      bcma_write32(dev, 0x528, 0x80000000);
++                      tmp = bcma_read32(dev, 0x314);
++                      udelay(265);
++                      bcma_write32(dev, 0x200, 0x7ff);
++                      udelay(10);
++
++                      /* Take USB and HSIC out of non-driving modes */
++                      bcma_write32(dev, 0x510, 0);
++              } else {
++                      bcma_write32(dev, 0x200, 0x7ff);
++
++                      udelay(1);
++              }
++      }
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      /* Work around for 4716 failures. */
++      if (dev->bus->chipinfo.id == 0x4716) {
++              u32 clk_freq;
++
++              clk_freq = bcma_cpu_clock(&dev->bus->drv_mips);
++              if (clk_freq >= 480000000)
++                      tmp = 0x1846b; /* set CDR to 0x11(fast) */
++              else if (clk_freq == 453000000)
++                      tmp = 0x1046b; /* set CDR to 0x10(slow) */
++              else
++                      tmp = 0;
++
++              /* Change Shim mdio control reg to fix host not acking at
++               * high frequencies
++               */
++              if (tmp) {
++                      bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
++                      udelay(500);
++
++                      bcma_write32(dev, 0x524, tmp);
++                      udelay(500);
++                      bcma_write32(dev, 0x524, 0x4ab);
++                      udelay(500);
++                      tmp = bcma_read32(dev, 0x528);
++                      bcma_write32(dev, 0x528, 0x80000000);
++              }
++      }
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++}
++
++static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
++                                                  char *name, u32 addr)
++{
++      struct platform_device *hci_dev;
++      struct resource *hci_res;
++      int ret = -ENOMEM;
++
++      hci_res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
++      if (!hci_res)
++              return ERR_PTR(-ENOMEM);
++
++      hci_res[0].start = addr;
++      hci_res[0].end = hci_res[0].start + BCMA_CORE_SIZE - 1;
++      hci_res[0].flags = IORESOURCE_MEM;
++
++      hci_res[1].start = dev->irq;
++      hci_res[1].flags = IORESOURCE_IRQ;
++
++      hci_dev = platform_device_alloc(name, 0);
++      if (!hci_dev)
++              goto err_alloc;
++
++      hci_dev->dev.parent = &dev->dev;
++      hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
++
++      ret = platform_device_add_resources(hci_dev, hci_res, 2);
++      if (ret)
++              goto err_alloc;
++
++      ret = platform_device_add(hci_dev);
++      if (ret) {
++err_alloc:
++              kfree(hci_res);
++              platform_device_put(hci_dev);
++              return ERR_PTR(ret);
++      }
++
++      return hci_dev;
++}
++
++static int bcma_hcd_probe(struct bcma_device *dev)
++{
++      int err;
++      u16 chipid_top;
++      struct bcma_hcd_device *usb_dev;
++
++      /* USBcores are only connected on embedded devices. */
++      chipid_top = (dev->bus->chipinfo.id & 0xFF00);
++      if (chipid_top != 0x4700 && chipid_top != 0x5300)
++              return -ENODEV;
++
++      /* TODO: Probably need checks here; is the core connected? */
++
++      if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
++          dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
++              return -EOPNOTSUPP;
++
++      usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
++      if (!usb_dev)
++              return -ENOMEM;
++
++      bcma_hcd_init_chip(dev);
++
++      usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform",
++                                               dev->addr1);
++      if (IS_ERR(usb_dev->ohci_dev)) {
++              err = PTR_ERR(usb_dev->ohci_dev);
++              goto err_free_usb_dev;
++      }
++
++      usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform",
++                                               dev->addr);
++      if (IS_ERR(usb_dev->ehci_dev)) {
++              err = PTR_ERR(usb_dev->ehci_dev);
++              goto err_unregister_ohci_dev;
++
++      }
++
++      bcma_set_drvdata(dev, usb_dev);
++      return 0;
++
++err_unregister_ohci_dev:
++      platform_device_unregister(usb_dev->ohci_dev);
++err_free_usb_dev:
++      kfree(usb_dev);
++      return err;
++}
++
++static void bcma_hcd_remove(struct bcma_device *dev)
++{
++      struct bcma_hcd_device *usb_dev;
++      struct platform_device *ohci_dev;
++      struct platform_device *ehci_dev;
++
++      usb_dev = bcma_get_drvdata(dev);
++      if (!usb_dev)
++              return;
++
++      ohci_dev = usb_dev->ohci_dev;
++      ehci_dev = usb_dev->ehci_dev;
++
++      if (ohci_dev) {
++              platform_device_unregister(ohci_dev);
++      }
++      if (ehci_dev) {
++              platform_device_unregister(ehci_dev);
++      }
++
++      bcma_core_disable(dev, 0);
++}
++
++static void bcma_hcd_shutdown(struct bcma_device *dev)
++{
++      bcma_core_disable(dev, 0);
++}
++
++#ifdef CONFIG_PM
++
++static int bcma_hcd_suspend(struct bcma_device *dev, pm_message_t state)
++{
++      bcma_core_disable(dev, 0);
++
++      return 0;
++}
++
++static int bcma_hcd_resume(struct bcma_device *dev)
++{
++      bcma_core_enable(dev, 0);
++
++      return 0;
++}
++
++#else /* !CONFIG_PM */
++#define bcma_hcd_suspend      NULL
++#define bcma_hcd_resume       NULL
++#endif /* CONFIG_PM */
++
++static const struct bcma_device_id bcma_hcd_table[] = {
++      BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
++      BCMA_CORETABLE_END
++};
++MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
++
++static struct bcma_driver bcma_hcd_driver = {
++      .name           = KBUILD_MODNAME,
++      .id_table       = bcma_hcd_table,
++      .probe          = bcma_hcd_probe,
++      .remove         = bcma_hcd_remove,
++      .shutdown       = bcma_hcd_shutdown,
++      .suspend        = bcma_hcd_suspend,
++      .resume         = bcma_hcd_resume,
++};
++
++static int __init bcma_hcd_init(void)
++{
++      return bcma_driver_register(&bcma_hcd_driver);
++}
++module_init(bcma_hcd_init);
++
++static void __exit bcma_hcd_exit(void)
++{
++      bcma_driver_unregister(&bcma_hcd_driver);
++}
++module_exit(bcma_hcd_exit);
diff --git a/target/linux/brcm47xx/patches-3.0/0033-USB-Add-driver-for-the-ssb-bus.patch b/target/linux/brcm47xx/patches-3.0/0033-USB-Add-driver-for-the-ssb-bus.patch
new file mode 100644 (file)
index 0000000..866540b
--- /dev/null
@@ -0,0 +1,321 @@
+From b61e70ad9080a6dbd3731917ec21dbcbb9d382a2 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 26 Nov 2011 21:35:17 +0100
+Subject: [PATCH 20/21] USB: Add driver for the ssb bus
+
+This adds a USB driver using the generic platform device driver for the
+USB controller found on the Broadcom ssb bus. The ssb bus just
+exposes one device which serves the OHCI and the EHCI controller at the
+same time. This driver probes for this USB controller and creates and
+registers two new platform devices which will be probed by the new
+generic platform device driver. This makes it possible to use the EHCI
+and the OCHI controller on the ssb bus at the same time.
+
+The old ssb OHCI USB driver will be removed in the next step as this
+driver also provide an OHCI driver and an EHCI for the cores supporting
+it.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/Kconfig   |   12 ++
+ drivers/usb/host/Makefile  |    1 +
+ drivers/usb/host/ssb-hcd.c |  320 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 333 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/usb/host/ssb-hcd.c
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -610,3 +610,15 @@ config USB_HCD_BCMA
+         for ehci and ohci.
+         If unsure, say N.
++
++config USB_HCD_SSB
++      tristate "SSB usb host driver"
++      depends on SSB && EXPERIMENTAL
++      select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
++      select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
++      help
++        Enbale support for the EHCI and OCHI host controller on an bcma bus.
++        It converts the bcma driver into two platform device drivers
++        for ehci and ohci.
++
++        If unsure, say N.
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -36,3 +36,4 @@ obj-$(CONFIG_USB_IMX21_HCD)  += imx21-hcd
+ obj-$(CONFIG_USB_FSL_MPH_DR_OF)       += fsl-mph-dr-of.o
+ obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
+ obj-$(CONFIG_USB_HCD_BCMA)    += bcma-hcd.o
++obj-$(CONFIG_USB_HCD_SSB)     += ssb-hcd.o
+--- /dev/null
++++ b/drivers/usb/host/ssb-hcd.c
+@@ -0,0 +1,268 @@
++/*
++ * Sonics Silicon Backplane
++ * Broadcom USB-core driver  (SSB bus glue)
++ *
++ * Copyright 2011 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Based on ssb-ohci driver
++ * Copyright 2007 Michael Buesch <m@bues.ch>
++ *
++ * Derived from the OHCI-PCI driver
++ * Copyright 1999 Roman Weissgaerber
++ * Copyright 2000-2002 David Brownell
++ * Copyright 1999 Linus Torvalds
++ * Copyright 1999 Gregory P. Smith
++ *
++ * Derived from the USBcore related parts of Broadcom-SB
++ * Copyright 2005-2011 Broadcom Corporation
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++#include <linux/ssb/ssb.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <linux/module.h>
++
++MODULE_AUTHOR("Hauke Mehrtens");
++MODULE_DESCRIPTION("Common USB driver for SSB Bus");
++MODULE_LICENSE("GPL");
++
++#define SSB_HCD_TMSLOW_HOSTMODE       (1 << 29)
++
++struct ssb_hcd_device {
++      struct platform_device *ehci_dev;
++      struct platform_device *ohci_dev;
++
++      u32 enable_flags;
++};
++
++/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
++static u32 ssb_hcd_init_chip(struct ssb_device *dev)
++{
++      u32 tmp, flags = 0;
++
++      if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
++              /* Put the device into host-mode. */
++              flags |= SSB_HCD_TMSLOW_HOSTMODE;
++              ssb_device_enable(dev, flags);
++      } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
++              /*
++               * USB 2.0 special considerations:
++               *
++               * In addition to the standard SSB reset sequence, the Host
++               * Control Register must be programmed to bring the USB core
++               * and various phy components out of reset.
++               */
++              ssb_device_enable(dev, 0);
++              ssb_write32(dev, 0x200, 0x7ff);
++
++              /* Change Flush control reg */
++              tmp = ssb_read32(dev, 0x400);
++              tmp &= ~8;
++              ssb_write32(dev, 0x400, tmp);
++              tmp = ssb_read32(dev, 0x400);
++
++              /* Change Shim control reg */
++              tmp = ssb_read32(dev, 0x304);
++              tmp &= ~0x100;
++              ssb_write32(dev, 0x304, tmp);
++              tmp = ssb_read32(dev, 0x304);
++
++              udelay(1);
++
++              /* Work around for 5354 failures */
++              if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
++                      /* Change syn01 reg */
++                      tmp = 0x00fe00fe;
++                      ssb_write32(dev, 0x894, tmp);
++
++                      /* Change syn03 reg */
++                      tmp = ssb_read32(dev, 0x89c);
++                      tmp |= 0x1;
++                      ssb_write32(dev, 0x89c, tmp);
++              }
++      } else
++              ssb_device_enable(dev, 0);
++
++      return flags;
++}
++
++static struct platform_device *ssb_hcd_create_pdev(struct ssb_device *dev,
++                                                 char *name, u32 addr,
++                                                 u32 len)
++{
++      struct platform_device *hci_dev;
++      struct resource *hci_res;
++      int ret = -ENOMEM;
++
++      hci_res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
++      if (!hci_res)
++              return ERR_PTR(-ENOMEM);
++
++      hci_res[0].start = addr;
++      hci_res[0].end = hci_res[0].start + len - 1;
++      hci_res[0].flags = IORESOURCE_MEM;
++
++      hci_res[1].start = dev->irq;
++      hci_res[1].flags = IORESOURCE_IRQ;
++
++      hci_dev = platform_device_alloc(name, 0);
++      if (!hci_dev)
++              goto err_alloc;
++
++      hci_dev->dev.parent = dev->dev;
++      hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
++
++      ret = platform_device_add_resources(hci_dev, hci_res, 2);
++      if (ret)
++              goto err_alloc;
++
++      ret = platform_device_add(hci_dev);
++      if (ret) {
++err_alloc:
++              kfree(hci_res);
++              platform_device_put(hci_dev);
++              return ERR_PTR(ret);
++      }
++
++      return hci_dev;
++}
++
++static int ssb_hcd_probe(struct ssb_device *dev, const struct ssb_device_id *id)
++{
++      int err, tmp;
++      int start, len;
++      u16 chipid_top;
++      struct ssb_hcd_device *usb_dev;
++
++      /* USBcores are only connected on embedded devices. */
++      chipid_top = (dev->bus->chip_id & 0xFF00);
++      if (chipid_top != 0x4700 && chipid_top != 0x5300)
++              return -ENODEV;
++
++      /* TODO: Probably need checks here; is the core connected? */
++
++      if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
++          dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
++              return -EOPNOTSUPP;
++
++      usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL);
++      if (!usb_dev)
++              return -ENOMEM;
++
++      /* We currently always attach SSB_DEV_USB11_HOSTDEV
++       * as HOST OHCI. If we want to attach it as Client device,
++       * we must branch here and call into the (yet to
++       * be written) Client mode driver. Same for remove(). */
++      usb_dev->enable_flags = ssb_hcd_init_chip(dev);
++
++      tmp = ssb_read32(dev, SSB_ADMATCH0);
++
++      start = ssb_admatch_base(tmp);
++      len = ssb_admatch_size(tmp);
++      usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, "ohci-platform", start,
++                                              len);
++      if (IS_ERR(usb_dev->ohci_dev)) {
++              err = PTR_ERR(usb_dev->ohci_dev);
++              goto err_free_usb_dev;
++      }
++
++      if (dev->id.coreid == SSB_DEV_USB20_HOST) {
++              start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
++              len = 0x100; /* ehci reg block size */
++              usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, "ehci-platform",
++                                                      start, len);
++              if (IS_ERR(usb_dev->ehci_dev)) {
++                      err = PTR_ERR(usb_dev->ehci_dev);
++                      goto err_unregister_ohci_dev;
++              }
++      }
++
++      ssb_set_drvdata(dev, usb_dev);
++      return 0;
++
++err_unregister_ohci_dev:
++      platform_device_unregister(usb_dev->ohci_dev);
++err_free_usb_dev:
++      kfree(usb_dev);
++      return err;
++}
++
++static void ssb_hcd_remove(struct ssb_device *dev)
++{
++      struct ssb_hcd_device *usb_dev;
++      struct platform_device *ohci_dev;
++      struct platform_device *ehci_dev;
++
++      usb_dev = ssb_get_drvdata(dev);
++      if (!usb_dev)
++              return;
++
++      ohci_dev = usb_dev->ohci_dev;
++      ehci_dev = usb_dev->ehci_dev;
++
++      if (ohci_dev) {
++              platform_device_unregister(ohci_dev);
++      }
++      if (ehci_dev) {
++              platform_device_unregister(ehci_dev);
++      }
++
++      ssb_device_disable(dev, 0);
++}
++
++static void ssb_hcd_shutdown(struct ssb_device *dev)
++{
++      ssb_device_disable(dev, 0);
++}
++
++#ifdef CONFIG_PM
++
++static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state)
++{
++      ssb_device_disable(dev, 0);
++
++      return 0;
++}
++
++static int ssb_hcd_resume(struct ssb_device *dev)
++{
++      ssb_device_enable(dev, usb_dev->enable_flags);
++
++      return 0;
++}
++
++#else /* !CONFIG_PM */
++#define ssb_hcd_suspend       NULL
++#define ssb_hcd_resume        NULL
++#endif /* CONFIG_PM */
++
++static const struct ssb_device_id ssb_hcd_table[] = {
++      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
++      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
++      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
++      SSB_DEVTABLE_END
++};
++MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
++
++static struct ssb_driver ssb_hcd_driver = {
++      .name           = KBUILD_MODNAME,
++      .id_table       = ssb_hcd_table,
++      .probe          = ssb_hcd_probe,
++      .remove         = ssb_hcd_remove,
++      .shutdown       = ssb_hcd_shutdown,
++      .suspend        = ssb_hcd_suspend,
++      .resume         = ssb_hcd_resume,
++};
++
++static int __init ssb_hcd_init(void)
++{
++      return ssb_driver_register(&ssb_hcd_driver);
++}
++module_init(ssb_hcd_init);
++
++static void __exit ssb_hcd_exit(void)
++{
++      ssb_driver_unregister(&ssb_hcd_driver);
++}
++module_exit(ssb_hcd_exit);
diff --git a/target/linux/brcm47xx/patches-3.0/0034-USB-OHCI-remove-old-SSB-OHCI-driver.patch b/target/linux/brcm47xx/patches-3.0/0034-USB-OHCI-remove-old-SSB-OHCI-driver.patch
new file mode 100644 (file)
index 0000000..18c3e9f
--- /dev/null
@@ -0,0 +1,357 @@
+From 8483de69568d1da9c106683d35d2b79c729b56c2 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 26 Nov 2011 21:36:50 +0100
+Subject: [PATCH 21/21] USB: OHCI: remove old SSB OHCI driver
+
+This is now replaced by the new ssb USB driver, which also supports
+devices with an EHCI controller.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/Kconfig    |   13 --
+ drivers/usb/host/ohci-hcd.c |   19 ---
+ drivers/usb/host/ohci-ssb.c |  260 -------------------------------------------
+ 3 files changed, 0 insertions(+), 292 deletions(-)
+ delete mode 100644 drivers/usb/host/ohci-ssb.c
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -351,19 +351,6 @@ config USB_OHCI_HCD_PCI
+         Enables support for PCI-bus plug-in USB controller cards.
+         If unsure, say Y.
+-config USB_OHCI_HCD_SSB
+-      bool "OHCI support for Broadcom SSB OHCI core"
+-      depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL
+-      default n
+-      ---help---
+-        Support for the Sonics Silicon Backplane (SSB) attached
+-        Broadcom USB OHCI core.
+-
+-        This device is present in some embedded devices with
+-        Broadcom based SSB bus.
+-
+-        If unsure, say N.
+-
+ config USB_OHCI_SH
+       bool "OHCI support for SuperH USB controller"
+       depends on USB_OHCI_HCD && SUPERH
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -1079,11 +1079,6 @@ MODULE_LICENSE ("GPL");
+ #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
+ #endif
+-#ifdef CONFIG_USB_OHCI_HCD_SSB
+-#include "ohci-ssb.c"
+-#define SSB_OHCI_DRIVER               ssb_ohci_driver
+-#endif
+-
+ #ifdef CONFIG_MFD_SM501
+ #include "ohci-sm501.c"
+ #define SM501_OHCI_DRIVER     ohci_hcd_sm501_driver
+@@ -1128,7 +1123,6 @@ MODULE_LICENSE ("GPL");
+       !defined(PS3_SYSTEM_BUS_DRIVER) && \
+       !defined(SM501_OHCI_DRIVER) && \
+       !defined(TMIO_OHCI_DRIVER) && \
+-      !defined(SSB_OHCI_DRIVER) && \
+       !defined(PLATFORM_OHCI_DRIVER)
+ #error "missing bus glue for ohci-hcd"
+ #endif
+@@ -1195,12 +1189,6 @@ static int __init ohci_hcd_mod_init(void
+               goto error_pci;
+ #endif
+-#ifdef SSB_OHCI_DRIVER
+-      retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+-      if (retval)
+-              goto error_ssb;
+-#endif
+-
+ #ifdef SM501_OHCI_DRIVER
+       retval = platform_driver_register(&SM501_OHCI_DRIVER);
+       if (retval < 0)
+@@ -1234,10 +1222,6 @@ static int __init ohci_hcd_mod_init(void
+       platform_driver_unregister(&SM501_OHCI_DRIVER);
+  error_sm501:
+ #endif
+-#ifdef SSB_OHCI_DRIVER
+-      ssb_driver_unregister(&SSB_OHCI_DRIVER);
+- error_ssb:
+-#endif
+ #ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
+  error_pci:
+@@ -1288,9 +1272,6 @@ static void __exit ohci_hcd_mod_exit(voi
+ #ifdef SM501_OHCI_DRIVER
+       platform_driver_unregister(&SM501_OHCI_DRIVER);
+ #endif
+-#ifdef SSB_OHCI_DRIVER
+-      ssb_driver_unregister(&SSB_OHCI_DRIVER);
+-#endif
+ #ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
+ #endif
+--- a/drivers/usb/host/ohci-ssb.c
++++ /dev/null
+@@ -1,260 +0,0 @@
+-/*
+- * Sonics Silicon Backplane
+- * Broadcom USB-core OHCI driver
+- *
+- * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+- *
+- * Derived from the OHCI-PCI driver
+- * Copyright 1999 Roman Weissgaerber
+- * Copyright 2000-2002 David Brownell
+- * Copyright 1999 Linus Torvalds
+- * Copyright 1999 Gregory P. Smith
+- *
+- * Derived from the USBcore related parts of Broadcom-SB
+- * Copyright 2005 Broadcom Corporation
+- *
+- * Licensed under the GNU/GPL. See COPYING for details.
+- */
+-#include <linux/ssb/ssb.h>
+-
+-
+-#define SSB_OHCI_TMSLOW_HOSTMODE      (1 << 29)
+-
+-struct ssb_ohci_device {
+-      struct ohci_hcd ohci; /* _must_ be at the beginning. */
+-
+-      u32 enable_flags;
+-};
+-
+-static inline
+-struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+-{
+-      return (struct ssb_ohci_device *)(hcd->hcd_priv);
+-}
+-
+-
+-static int ssb_ohci_reset(struct usb_hcd *hcd)
+-{
+-      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+-      struct ohci_hcd *ohci = &ohcidev->ohci;
+-      int err;
+-
+-      ohci_hcd_init(ohci);
+-      err = ohci_init(ohci);
+-
+-      return err;
+-}
+-
+-static int ssb_ohci_start(struct usb_hcd *hcd)
+-{
+-      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+-      struct ohci_hcd *ohci = &ohcidev->ohci;
+-      int err;
+-
+-      err = ohci_run(ohci);
+-      if (err < 0) {
+-              ohci_err(ohci, "can't start\n");
+-              ohci_stop(hcd);
+-      }
+-
+-      return err;
+-}
+-
+-static const struct hc_driver ssb_ohci_hc_driver = {
+-      .description            = "ssb-usb-ohci",
+-      .product_desc           = "SSB OHCI Controller",
+-      .hcd_priv_size          = sizeof(struct ssb_ohci_device),
+-
+-      .irq                    = ohci_irq,
+-      .flags                  = HCD_MEMORY | HCD_USB11,
+-
+-      .reset                  = ssb_ohci_reset,
+-      .start                  = ssb_ohci_start,
+-      .stop                   = ohci_stop,
+-      .shutdown               = ohci_shutdown,
+-
+-      .urb_enqueue            = ohci_urb_enqueue,
+-      .urb_dequeue            = ohci_urb_dequeue,
+-      .endpoint_disable       = ohci_endpoint_disable,
+-
+-      .get_frame_number       = ohci_get_frame,
+-
+-      .hub_status_data        = ohci_hub_status_data,
+-      .hub_control            = ohci_hub_control,
+-#ifdef        CONFIG_PM
+-      .bus_suspend            = ohci_bus_suspend,
+-      .bus_resume             = ohci_bus_resume,
+-#endif
+-
+-      .start_port_reset       = ohci_start_port_reset,
+-};
+-
+-static void ssb_ohci_detach(struct ssb_device *dev)
+-{
+-      struct usb_hcd *hcd = ssb_get_drvdata(dev);
+-
+-      if (hcd->driver->shutdown)
+-              hcd->driver->shutdown(hcd);
+-      usb_remove_hcd(hcd);
+-      iounmap(hcd->regs);
+-      release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+-      usb_put_hcd(hcd);
+-      ssb_device_disable(dev, 0);
+-}
+-
+-static int ssb_ohci_attach(struct ssb_device *dev)
+-{
+-      struct ssb_ohci_device *ohcidev;
+-      struct usb_hcd *hcd;
+-      int err = -ENOMEM;
+-      u32 tmp, flags = 0;
+-
+-      if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+-          dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+-              return -EOPNOTSUPP;
+-
+-      if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
+-              /* Put the device into host-mode. */
+-              flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+-              ssb_device_enable(dev, flags);
+-      } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
+-              /*
+-               * USB 2.0 special considerations:
+-               *
+-               * In addition to the standard SSB reset sequence, the Host
+-               * Control Register must be programmed to bring the USB core
+-               * and various phy components out of reset.
+-               */
+-              ssb_device_enable(dev, 0);
+-              ssb_write32(dev, 0x200, 0x7ff);
+-
+-              /* Change Flush control reg */
+-              tmp = ssb_read32(dev, 0x400);
+-              tmp &= ~8;
+-              ssb_write32(dev, 0x400, tmp);
+-              tmp = ssb_read32(dev, 0x400);
+-
+-              /* Change Shim control reg */
+-              tmp = ssb_read32(dev, 0x304);
+-              tmp &= ~0x100;
+-              ssb_write32(dev, 0x304, tmp);
+-              tmp = ssb_read32(dev, 0x304);
+-
+-              udelay(1);
+-
+-              /* Work around for 5354 failures */
+-              if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
+-                      /* Change syn01 reg */
+-                      tmp = 0x00fe00fe;
+-                      ssb_write32(dev, 0x894, tmp);
+-
+-                      /* Change syn03 reg */
+-                      tmp = ssb_read32(dev, 0x89c);
+-                      tmp |= 0x1;
+-                      ssb_write32(dev, 0x89c, tmp);
+-              }
+-      } else
+-              ssb_device_enable(dev, 0);
+-
+-      hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+-                      dev_name(dev->dev));
+-      if (!hcd)
+-              goto err_dev_disable;
+-      ohcidev = hcd_to_ssb_ohci(hcd);
+-      ohcidev->enable_flags = flags;
+-
+-      tmp = ssb_read32(dev, SSB_ADMATCH0);
+-      hcd->rsrc_start = ssb_admatch_base(tmp);
+-      hcd->rsrc_len = ssb_admatch_size(tmp);
+-      hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+-      if (!hcd->regs)
+-              goto err_put_hcd;
+-      err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
+-      if (err)
+-              goto err_iounmap;
+-
+-      ssb_set_drvdata(dev, hcd);
+-
+-      return err;
+-
+-err_iounmap:
+-      iounmap(hcd->regs);
+-err_put_hcd:
+-      usb_put_hcd(hcd);
+-err_dev_disable:
+-      ssb_device_disable(dev, flags);
+-      return err;
+-}
+-
+-static int ssb_ohci_probe(struct ssb_device *dev,
+-              const struct ssb_device_id *id)
+-{
+-      int err;
+-      u16 chipid_top;
+-
+-      /* USBcores are only connected on embedded devices. */
+-      chipid_top = (dev->bus->chip_id & 0xFF00);
+-      if (chipid_top != 0x4700 && chipid_top != 0x5300)
+-              return -ENODEV;
+-
+-      /* TODO: Probably need checks here; is the core connected? */
+-
+-      if (usb_disabled())
+-              return -ENODEV;
+-
+-      /* We currently always attach SSB_DEV_USB11_HOSTDEV
+-       * as HOST OHCI. If we want to attach it as Client device,
+-       * we must branch here and call into the (yet to
+-       * be written) Client mode driver. Same for remove(). */
+-
+-      err = ssb_ohci_attach(dev);
+-
+-      return err;
+-}
+-
+-static void ssb_ohci_remove(struct ssb_device *dev)
+-{
+-      ssb_ohci_detach(dev);
+-}
+-
+-#ifdef CONFIG_PM
+-
+-static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+-{
+-      ssb_device_disable(dev, 0);
+-
+-      return 0;
+-}
+-
+-static int ssb_ohci_resume(struct ssb_device *dev)
+-{
+-      struct usb_hcd *hcd = ssb_get_drvdata(dev);
+-      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+-
+-      ssb_device_enable(dev, ohcidev->enable_flags);
+-
+-      ohci_finish_controller_resume(hcd);
+-      return 0;
+-}
+-
+-#else /* !CONFIG_PM */
+-#define ssb_ohci_suspend      NULL
+-#define ssb_ohci_resume       NULL
+-#endif /* CONFIG_PM */
+-
+-static const struct ssb_device_id ssb_ohci_table[] = {
+-      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+-      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+-      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
+-      SSB_DEVTABLE_END
+-};
+-MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+-
+-static struct ssb_driver ssb_ohci_driver = {
+-      .name           = KBUILD_MODNAME,
+-      .id_table       = ssb_ohci_table,
+-      .probe          = ssb_ohci_probe,
+-      .remove         = ssb_ohci_remove,
+-      .suspend        = ssb_ohci_suspend,
+-      .resume         = ssb_ohci_resume,
+-};
diff --git a/target/linux/brcm47xx/patches-3.0/022-USB-Add-ehci-ssb-driver.patch b/target/linux/brcm47xx/patches-3.0/022-USB-Add-ehci-ssb-driver.patch
deleted file mode 100644 (file)
index 33e23c2..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
---- a/drivers/usb/host/Kconfig
-+++ b/drivers/usb/host/Kconfig
-@@ -230,6 +230,19 @@ config USB_OXU210HP_HCD
-         To compile this driver as a module, choose M here: the
-         module will be called oxu210hp-hcd.
-+config USB_EHCI_HCD_SSB
-+      bool "EHCI support for Broadcom SSB EHCI core"
-+      depends on USB_EHCI_HCD && (SSB = y || SSB = USB_EHCI_HCD) && EXPERIMENTAL
-+      default n
-+      ---help---
-+        Support for the Sonics Silicon Backplane (SSB) attached
-+        Broadcom USB EHCI core.
-+
-+        This device is present in some embedded devices with
-+        Broadcom based SSB bus.
-+
-+        If unsure, say N.
-+
- config USB_ISP116X_HCD
-       tristate "ISP116X HCD support"
-       depends on USB
---- a/drivers/usb/host/ehci-hcd.c
-+++ b/drivers/usb/host/ehci-hcd.c
-@@ -1312,9 +1312,14 @@ MODULE_LICENSE ("GPL");
- #define PLATFORM_DRIVER               ehci_grlib_driver
- #endif
-+#ifdef CONFIG_USB_EHCI_HCD_SSB
-+#include "ehci-ssb.c"
-+#define SSB_EHCI_DRIVER               ssb_ehci_driver
-+#endif
-+
- #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
-     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
--    !defined(XILINX_OF_PLATFORM_DRIVER)
-+    !defined(XILINX_OF_PLATFORM_DRIVER) && !defined(SSB_EHCI_DRIVER)
- #error "missing bus glue for ehci-hcd"
- #endif
-@@ -1374,10 +1379,20 @@ static int __init ehci_hcd_init(void)
-       if (retval < 0)
-               goto clean4;
- #endif
-+
-+#ifdef SSB_EHCI_DRIVER
-+      retval = ssb_driver_register(&SSB_EHCI_DRIVER);
-+      if (retval < 0)
-+              goto clean5;
-+#endif
-       return retval;
-+#ifdef SSB_EHCI_DRIVER
-+      /* ssb_driver_unregister(&SSB_EHCI_DRIVER); */
-+clean5:
-+#endif
- #ifdef XILINX_OF_PLATFORM_DRIVER
--      /* platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); */
-+      platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER);
- clean4:
- #endif
- #ifdef OF_PLATFORM_DRIVER
-@@ -1408,6 +1423,9 @@ module_init(ehci_hcd_init);
- static void __exit ehci_hcd_cleanup(void)
- {
-+#ifdef SSB_EHCI_DRIVER
-+      ssb_driver_unregister(&SSB_EHCI_DRIVER);
-+#endif
- #ifdef XILINX_OF_PLATFORM_DRIVER
-       platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER);
- #endif
---- /dev/null
-+++ b/drivers/usb/host/ehci-ssb.c
-@@ -0,0 +1,255 @@
-+/*
-+ * Sonics Silicon Backplane
-+ * Broadcom USB-core EHCI driver (SSB bus glue)
-+ *
-+ * Copyright 2007 Steven Brown <sbrown@cortland.com>
-+ * Copyright 2010 Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * Derived from the OHCI-SSB driver
-+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
-+ *
-+ * Derived from the EHCI-PCI driver
-+ * Copyright (c) 2000-2004 by David Brownell
-+ *
-+ * Derived from the OHCI-PCI driver
-+ * Copyright 1999 Roman Weissgaerber
-+ * Copyright 2000-2002 David Brownell
-+ * Copyright 1999 Linus Torvalds
-+ * Copyright 1999 Gregory P. Smith
-+ *
-+ * Derived from the USBcore related parts of Broadcom-SB
-+ * Copyright 2005 Broadcom Corporation
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+#include <linux/ssb/ssb.h>
-+
-+
-+struct ssb_ehci_device {
-+      struct ehci_hcd ehci; /* _must_ be at the beginning. */
-+};
-+
-+static inline
-+struct ssb_ehci_device *hcd_to_ssb_ehci(struct usb_hcd *hcd)
-+{
-+      return (struct ssb_ehci_device *)(hcd->hcd_priv);
-+}
-+
-+static int ssb_ehci_reset(struct usb_hcd *hcd)
-+{
-+      struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-+      int err;
-+
-+      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);
-+
-+      err = ehci_halt(ehci);
-+
-+      if (err)
-+              return err;
-+
-+      err = ehci_init(hcd);
-+
-+      if (err)
-+              return err;
-+
-+      ehci_reset(ehci);
-+
-+      return err;
-+}
-+
-+static const struct hc_driver ssb_ehci_hc_driver = {
-+      .description            = "ssb-usb-ehci",
-+      .product_desc           = "SSB EHCI Controller",
-+      .hcd_priv_size          = sizeof(struct ssb_ehci_device),
-+
-+      .irq                    = ehci_irq,
-+      .flags                  = HCD_MEMORY | HCD_USB2,
-+
-+      .reset                  = ssb_ehci_reset,
-+      .start                  = 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 void ssb_ehci_detach(struct ssb_device *dev)
-+{
-+      struct usb_hcd *hcd = ssb_get_drvdata(dev);
-+
-+      if (hcd->driver->shutdown)
-+              hcd->driver->shutdown(hcd);
-+      usb_remove_hcd(hcd);
-+      iounmap(hcd->regs);
-+      release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-+      usb_put_hcd(hcd);
-+      ssb_device_disable(dev, 0);
-+}
-+
-+static int ssb_ehci_attach(struct ssb_device *dev)
-+{
-+      struct ssb_ehci_device *ehcidev;
-+      struct usb_hcd *hcd;
-+      int err = -ENOMEM;
-+      u32 tmp;
-+
-+      if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
-+          dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
-+              return -EOPNOTSUPP;
-+
-+      /*
-+       * USB 2.0 special considerations:
-+       *
-+       * In addition to the standard SSB reset sequence, the Host Control
-+       * Register must be programmed to bring the USB core and various phy
-+       * components out of reset.
-+       */
-+      ssb_device_enable(dev, 0);
-+      ssb_write32(dev, 0x200, 0x7ff);
-+
-+      /* Change Flush control reg */
-+      tmp = ssb_read32(dev, 0x400);
-+      tmp &= ~8;
-+      ssb_write32(dev, 0x400, tmp);
-+      tmp = ssb_read32(dev, 0x400);
-+
-+      /* Change Shim control reg */
-+      tmp = ssb_read32(dev, 0x304);
-+      tmp &= ~0x100;
-+      ssb_write32(dev, 0x304, tmp);
-+      tmp = ssb_read32(dev, 0x304);
-+
-+      udelay(1);
-+
-+      /* Work around for 5354 failures */
-+      if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
-+              /* Change syn01 reg */
-+              tmp = 0x00fe00fe;
-+              ssb_write32(dev, 0x894, tmp);
-+
-+              /* Change syn03 reg */
-+              tmp = ssb_read32(dev, 0x89c);
-+              tmp |= 0x1;
-+              ssb_write32(dev, 0x89c, tmp);
-+      }
-+
-+      hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev,
-+                           dev_name(dev->dev));
-+      if (!hcd)
-+              goto err_dev_disable;
-+
-+      ehcidev = hcd_to_ssb_ehci(hcd);
-+      tmp = ssb_read32(dev, SSB_ADMATCH0);
-+      hcd->rsrc_start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
-+      hcd->rsrc_len = 0x100; /* ehci reg block size */
-+      /*
-+       * start & size modified per sbutils.c
-+       */
-+      hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-+      if (!hcd->regs)
-+              goto err_put_hcd;
-+      err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
-+      if (err)
-+              goto err_iounmap;
-+
-+      ssb_set_drvdata(dev, hcd);
-+
-+      return err;
-+
-+err_iounmap:
-+      iounmap(hcd->regs);
-+err_put_hcd:
-+      usb_put_hcd(hcd);
-+err_dev_disable:
-+      ssb_device_disable(dev, 0);
-+      return err;
-+}
-+
-+static int ssb_ehci_probe(struct ssb_device *dev,
-+              const struct ssb_device_id *id)
-+{
-+      int err;
-+      u16 chipid_top;
-+
-+      /* USBcores are only connected on embedded devices. */
-+      chipid_top = (dev->bus->chip_id & 0xFF00);
-+      if (chipid_top != 0x4700 && chipid_top != 0x5300)
-+              return -ENODEV;
-+
-+      /* TODO: Probably need checks here; is the core connected? */
-+
-+      if (usb_disabled())
-+              return -ENODEV;
-+
-+      err = ssb_ehci_attach(dev);
-+
-+      return err;
-+}
-+
-+static void ssb_ehci_remove(struct ssb_device *dev)
-+{
-+      ssb_ehci_detach(dev);
-+}
-+
-+#ifdef CONFIG_PM
-+
-+static int ssb_ehci_suspend(struct ssb_device *dev, pm_message_t state)
-+{
-+      ssb_device_disable(dev, 0);
-+
-+      return 0;
-+}
-+
-+static int ssb_ehci_resume(struct ssb_device *dev)
-+{
-+      struct usb_hcd *hcd = ssb_get_drvdata(dev);
-+      struct ssb_ehci_device *ehcidev = hcd_to_ssb_ehci(hcd);
-+
-+      ssb_device_enable(dev, 0);
-+
-+      ehci_finish_controller_resume(hcd);
-+      return 0;
-+}
-+
-+#else /* !CONFIG_PM */
-+#define ssb_ehci_suspend      NULL
-+#define ssb_ehci_resume       NULL
-+#endif /* CONFIG_PM */
-+
-+static const struct ssb_device_id ssb_ehci_table[] = {
-+      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
-+      SSB_DEVTABLE_END
-+};
-+MODULE_DEVICE_TABLE(ssb, ssb_ehci_table);
-+
-+static struct ssb_driver ssb_ehci_driver = {
-+      .name           = KBUILD_MODNAME,
-+      .id_table       = ssb_ehci_table,
-+      .probe          = ssb_ehci_probe,
-+      .remove         = ssb_ehci_remove,
-+      .suspend        = ssb_ehci_suspend,
-+      .resume         = ssb_ehci_resume,
-+};
diff --git a/target/linux/brcm47xx/patches-3.0/023-usb_ehci_ohci.patch b/target/linux/brcm47xx/patches-3.0/023-usb_ehci_ohci.patch
deleted file mode 100644 (file)
index 5140a72..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
---- a/drivers/usb/host/ohci-ssb.c
-+++ b/drivers/usb/host/ohci-ssb.c
-@@ -17,6 +17,8 @@
-  */
- #include <linux/ssb/ssb.h>
-+extern int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **hcd);
-+extern void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd);
- #define SSB_OHCI_TMSLOW_HOSTMODE      (1 << 29)
-@@ -24,6 +26,9 @@ struct ssb_ohci_device {
-       struct ohci_hcd ohci; /* _must_ be at the beginning. */
-       u32 enable_flags;
-+#ifdef CONFIG_USB_EHCI_HCD_SSB
-+      struct usb_hcd *ehci_hcd;
-+#endif
- };
- static inline
-@@ -92,6 +97,9 @@ static const struct hc_driver ssb_ohci_h
- static void ssb_ohci_detach(struct ssb_device *dev)
- {
-       struct usb_hcd *hcd = ssb_get_drvdata(dev);
-+#ifdef CONFIG_USB_EHCI_HCD_SSB
-+      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-+#endif
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
-@@ -99,6 +107,14 @@ static void ssb_ohci_detach(struct ssb_d
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       usb_put_hcd(hcd);
-+
-+#ifdef CONFIG_USB_EHCI_HCD_SSB
-+      /*
-+       * Also detach ehci function
-+       */
-+      if (dev->id.coreid == SSB_DEV_USB20_HOST)
-+              ssb_ehci_detach(dev, ohcidev->ehci_hcd);
-+#endif
-       ssb_device_disable(dev, 0);
- }
-@@ -121,6 +137,9 @@ static int ssb_ohci_attach(struct ssb_de
-               /*
-                * USB 2.0 special considerations:
-                *
-+               * Since the core supports both OHCI and EHCI functions, 
-+               * it must only be reset once.
-+               *
-                * In addition to the standard SSB reset sequence, the Host
-                * Control Register must be programmed to bring the USB core
-                * and various phy components out of reset.
-@@ -175,6 +194,14 @@ static int ssb_ohci_attach(struct ssb_de
-       ssb_set_drvdata(dev, hcd);
-+#ifdef CONFIG_USB_EHCI_HCD_SSB
-+      /*
-+       *  attach ehci function in this core
-+       */
-+      if (dev->id.coreid == SSB_DEV_USB20_HOST)
-+              err = ssb_ehci_attach(dev, &(ohcidev->ehci_hcd));
-+#endif
-+
-       return err;
- err_iounmap:
---- a/drivers/usb/host/ehci-ssb.c
-+++ b/drivers/usb/host/ehci-ssb.c
-@@ -106,10 +106,18 @@ static void ssb_ehci_detach(struct ssb_d
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       usb_put_hcd(hcd);
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
-+      ssb_device_disable(dev, 0);
-+#endif
-       ssb_device_disable(dev, 0);
- }
-+EXPORT_SYMBOL_GPL(ssb_ehci_detach);
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
- static int ssb_ehci_attach(struct ssb_device *dev)
-+#else
-+static int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **ehci_hcd)
-+#endif
- {
-       struct ssb_ehci_device *ehcidev;
-       struct usb_hcd *hcd;
-@@ -120,6 +128,7 @@ static int ssb_ehci_attach(struct ssb_de
-           dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
-               return -EOPNOTSUPP;
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
-       /*
-        * USB 2.0 special considerations:
-        *
-@@ -155,6 +164,7 @@ static int ssb_ehci_attach(struct ssb_de
-               tmp |= 0x1;
-               ssb_write32(dev, 0x89c, tmp);
-       }
-+#endif
-       hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev,
-                            dev_name(dev->dev));
-@@ -175,7 +185,11 @@ static int ssb_ehci_attach(struct ssb_de
-       if (err)
-               goto err_iounmap;
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
-       ssb_set_drvdata(dev, hcd);
-+#else
-+      *ehci_hcd = hcd;
-+#endif
-       return err;
-@@ -187,7 +201,9 @@ err_dev_disable:
-       ssb_device_disable(dev, 0);
-       return err;
- }
-+EXPORT_SYMBOL_GPL(ssb_ehci_attach);
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
- static int ssb_ehci_probe(struct ssb_device *dev,
-               const struct ssb_device_id *id)
- {
-@@ -238,6 +254,7 @@ static int ssb_ehci_resume(struct ssb_de
- #define ssb_ehci_suspend      NULL
- #define ssb_ehci_resume       NULL
- #endif /* CONFIG_PM */
-+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
- static const struct ssb_device_id ssb_ehci_table[] = {
-       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
-@@ -245,6 +262,8 @@ static const struct ssb_device_id ssb_eh
- };
- MODULE_DEVICE_TABLE(ssb, ssb_ehci_table);
-+
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
- static struct ssb_driver ssb_ehci_driver = {
-       .name           = KBUILD_MODNAME,
-       .id_table       = ssb_ehci_table,
-@@ -253,3 +272,4 @@ static struct ssb_driver ssb_ehci_driver
-       .suspend        = ssb_ehci_suspend,
-       .resume         = ssb_ehci_resume,
- };
-+#endif
---- a/drivers/usb/host/ehci-hcd.c
-+++ b/drivers/usb/host/ehci-hcd.c
-@@ -1380,17 +1380,21 @@ static int __init ehci_hcd_init(void)
-               goto clean4;
- #endif
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
- #ifdef SSB_EHCI_DRIVER
-       retval = ssb_driver_register(&SSB_EHCI_DRIVER);
-       if (retval < 0)
-               goto clean5;
- #endif
-+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
-       return retval;
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
- #ifdef SSB_EHCI_DRIVER
-       /* ssb_driver_unregister(&SSB_EHCI_DRIVER); */
- clean5:
- #endif
-+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
- #ifdef XILINX_OF_PLATFORM_DRIVER
-       platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER);
- clean4:
-@@ -1423,9 +1427,11 @@ module_init(ehci_hcd_init);
- static void __exit ehci_hcd_cleanup(void)
- {
-+#ifndef CONFIG_USB_OHCI_HCD_SSB
- #ifdef SSB_EHCI_DRIVER
-       ssb_driver_unregister(&SSB_EHCI_DRIVER);
- #endif
-+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
- #ifdef XILINX_OF_PLATFORM_DRIVER
-       platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER);
- #endif
index d3a8817bacd67401fa7438fb8f8de321c9326756..c535c05db550d9d31a98908c2994e035a0387054 100644 (file)
@@ -3,14 +3,23 @@ This prevents the options from being delete with make kernel_oldconfig.
  drivers/ssb/Kconfig |    2 ++
  1 file changed, 2 insertions(+)
 
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -37,6 +37,7 @@ config BCMA_DRIVER_PCI_HOSTMODE
+ config BCMA_HOST_SOC
+       bool
+       depends on BCMA_DRIVER_MIPS
++      select USB_HCD_BCMA if USB_EHCI_HCD || USB_OHCI_HCD
+ config BCMA_SFLASH
+       bool
 --- a/drivers/ssb/Kconfig
 +++ b/drivers/ssb/Kconfig
-@@ -147,6 +147,8 @@ config SSB_SFLASH
+@@ -147,6 +147,7 @@ config SSB_SFLASH
  config SSB_EMBEDDED
        bool
        depends on SSB_DRIVER_MIPS
-+      select USB_EHCI_HCD_SSB if USB_EHCI_HCD
-+      select USB_OHCI_HCD_SSB if USB_OHCI_HCD
++      select USB_HCD_SSB if USB_EHCI_HCD || USB_OHCI_HCD
        default y
  
  config SSB_DRIVER_EXTIF