kernel: update bcma and ssb to version master-2011-12-16 from wireless-testing
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Mon, 19 Dec 2011 23:33:03 +0000 (23:33 +0000)
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Mon, 19 Dec 2011 23:33:03 +0000 (23:33 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@29574 3c298f89-4303-0410-b956-a3cf2f4a3e73

31 files changed:
target/linux/brcm47xx/patches-3.0/0001-bcma-move-parsing-of-EEPROM-into-own-function.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0002-bcma-move-initializing-of-struct-bcma_bus-to-own-fun.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0003-bcma-add-functions-to-scan-cores-needed-on-SoCs.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0004-bcma-add-SOC-bus.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0005-bcma-add-mips-driver.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0006-bcma-add-serial-console-support.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0007-bcma-get-CPU-clock.patch [deleted file]
target/linux/brcm47xx/patches-3.0/0012-bcma-move-parallel-flash-into-a-union.patch
target/linux/brcm47xx/patches-3.0/0013-bcma-add-serial-flash-support-to-bcma.patch
target/linux/brcm47xx/patches-3.0/0023-bcma-use-randoom-mac-address-as-long-as-reading-it-o.patch
target/linux/brcm47xx/patches-3.0/220-bcm5354.patch
target/linux/brcm47xx/patches-3.0/230-ssb_pci_sprom.patch [deleted file]
target/linux/brcm47xx/patches-3.0/951-brcm4716-defines.patch
target/linux/generic/patches-2.6.30/025-bcma_backport.patch
target/linux/generic/patches-2.6.30/941-ssb_update.patch
target/linux/generic/patches-2.6.31/025-bcma_backport.patch
target/linux/generic/patches-2.6.31/941-ssb_update.patch
target/linux/generic/patches-2.6.32/025-bcma_backport.patch
target/linux/generic/patches-2.6.32/975-ssb_update.patch
target/linux/generic/patches-2.6.36/025-bcma_backport.patch
target/linux/generic/patches-2.6.36/941-ssb_update.patch
target/linux/generic/patches-2.6.37/020-ssb_update.patch
target/linux/generic/patches-2.6.37/025-bcma_backport.patch
target/linux/generic/patches-2.6.38/020-ssb_update.patch
target/linux/generic/patches-2.6.38/025-bcma_backport.patch
target/linux/generic/patches-2.6.39/020-ssb_update.patch
target/linux/generic/patches-2.6.39/025-bcma_backport.patch
target/linux/generic/patches-3.0/020-ssb_update.patch
target/linux/generic/patches-3.0/025-bcma_backport.patch
target/linux/generic/patches-3.1/020-ssb_update.patch [new file with mode: 0644]
target/linux/generic/patches-3.1/025-bcma_backport.patch [new file with mode: 0644]

diff --git a/target/linux/brcm47xx/patches-3.0/0001-bcma-move-parsing-of-EEPROM-into-own-function.patch b/target/linux/brcm47xx/patches-3.0/0001-bcma-move-parsing-of-EEPROM-into-own-function.patch
deleted file mode 100644 (file)
index 740e96e..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-From a1bf12e78294c6cd3d8747e1e07c48977ca1e3e3 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 11 Jun 2011 16:47:38 +0200
-Subject: [PATCH 01/26] bcma: move parsing of EEPROM into own function.
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Move the parsing of the EEPROM data in scan function for one core into
-an own function. Now we are able to use it in some other scan function
-as well.
-
-Acked-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/scan.c |  230 ++++++++++++++++++++++++++-------------------------
- 1 files changed, 118 insertions(+), 112 deletions(-)
-
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -200,16 +200,124 @@ static s32 bcma_erom_get_addr_desc(struc
-       return addrl;
- }
-+static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
-+                            struct bcma_device *core)
-+{
-+      s32 tmp;
-+      u8 i, j;
-+      s32 cia, cib;
-+      u8 ports[2], wrappers[2];
-+
-+      /* get CIs */
-+      cia = bcma_erom_get_ci(bus, eromptr);
-+      if (cia < 0) {
-+              bcma_erom_push_ent(eromptr);
-+              if (bcma_erom_is_end(bus, eromptr))
-+                      return -ESPIPE;
-+              return -EILSEQ;
-+      }
-+      cib = bcma_erom_get_ci(bus, eromptr);
-+      if (cib < 0)
-+              return -EILSEQ;
-+
-+      /* parse CIs */
-+      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+      if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+           (core->id.id == 0xFFF)) ||
-+          (ports[1] == 0)) {
-+              bcma_erom_skip_component(bus, eromptr);
-+              return -ENXIO;
-+      }
-+
-+      /* check if component is a core at all */
-+      if (wrappers[0] + wrappers[1] == 0) {
-+              /* we could save addrl of the router
-+              if (cid == BCMA_CORE_OOB_ROUTER)
-+               */
-+              bcma_erom_skip_component(bus, eromptr);
-+              return -ENXIO;
-+      }
-+
-+      if (bcma_erom_is_bridge(bus, eromptr)) {
-+              bcma_erom_skip_component(bus, eromptr);
-+              return -ENXIO;
-+      }
-+
-+      /* get & parse master ports */
-+      for (i = 0; i < ports[0]; i++) {
-+              u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
-+              if (mst_port_d < 0)
-+                      return -EILSEQ;
-+      }
-+
-+      /* get & parse slave ports */
-+      for (i = 0; i < ports[1]; i++) {
-+              for (j = 0; ; j++) {
-+                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
-+                              SCAN_ADDR_TYPE_SLAVE, i);
-+                      if (tmp < 0) {
-+                              /* no more entries for port _i_ */
-+                              /* pr_debug("erom: slave port %d "
-+                               * "has %d descriptors\n", i, j); */
-+                              break;
-+                      } else {
-+                              if (i == 0 && j == 0)
-+                                      core->addr = tmp;
-+                      }
-+              }
-+      }
-+
-+      /* get & parse master wrappers */
-+      for (i = 0; i < wrappers[0]; i++) {
-+              for (j = 0; ; j++) {
-+                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
-+                              SCAN_ADDR_TYPE_MWRAP, i);
-+                      if (tmp < 0) {
-+                              /* no more entries for port _i_ */
-+                              /* pr_debug("erom: master wrapper %d "
-+                               * "has %d descriptors\n", i, j); */
-+                              break;
-+                      } else {
-+                              if (i == 0 && j == 0)
-+                                      core->wrap = tmp;
-+                      }
-+              }
-+      }
-+
-+      /* get & parse slave wrappers */
-+      for (i = 0; i < wrappers[1]; i++) {
-+              u8 hack = (ports[1] == 1) ? 0 : 1;
-+              for (j = 0; ; j++) {
-+                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
-+                              SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                      if (tmp < 0) {
-+                              /* no more entries for port _i_ */
-+                              /* pr_debug("erom: master wrapper %d "
-+                               * has %d descriptors\n", i, j); */
-+                              break;
-+                      } else {
-+                              if (wrappers[0] == 0 && !i && !j)
-+                                      core->wrap = tmp;
-+                      }
-+              }
-+      }
-+      return 0;
-+}
-+
- int bcma_bus_scan(struct bcma_bus *bus)
- {
-       u32 erombase;
-       u32 __iomem *eromptr, *eromend;
--      s32 cia, cib;
--      u8 ports[2], wrappers[2];
--
-       s32 tmp;
--      u8 i, j;
-       int err;
-@@ -236,112 +344,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
-               INIT_LIST_HEAD(&core->list);
-               core->bus = bus;
--              /* get CIs */
--              cia = bcma_erom_get_ci(bus, &eromptr);
--              if (cia < 0) {
--                      bcma_erom_push_ent(&eromptr);
--                      if (bcma_erom_is_end(bus, &eromptr))
--                              break;
--                      err= -EILSEQ;
--                      goto out;
--              }
--              cib = bcma_erom_get_ci(bus, &eromptr);
--              if (cib < 0) {
--                      err= -EILSEQ;
--                      goto out;
--              }
--
--              /* parse CIs */
--              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
--              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
--              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
--              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
--              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
--              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
--              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
--              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
--
--              if (((core->id.manuf == BCMA_MANUF_ARM) &&
--                   (core->id.id == 0xFFF)) ||
--                  (ports[1] == 0)) {
--                      bcma_erom_skip_component(bus, &eromptr);
-+              err = bcma_get_next_core(bus, &eromptr, core);
-+              if (err == -ENXIO)
-                       continue;
--              }
--
--              /* check if component is a core at all */
--              if (wrappers[0] + wrappers[1] == 0) {
--                      /* we could save addrl of the router
--                      if (cid == BCMA_CORE_OOB_ROUTER)
--                       */
--                      bcma_erom_skip_component(bus, &eromptr);
--                      continue;
--              }
--
--              if (bcma_erom_is_bridge(bus, &eromptr)) {
--                      bcma_erom_skip_component(bus, &eromptr);
--                      continue;
--              }
--
--              /* get & parse master ports */
--              for (i = 0; i < ports[0]; i++) {
--                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
--                      if (mst_port_d < 0) {
--                              err= -EILSEQ;
--                              goto out;
--                      }
--              }
--
--              /* get & parse slave ports */
--              for (i = 0; i < ports[1]; i++) {
--                      for (j = 0; ; j++) {
--                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
--                                      SCAN_ADDR_TYPE_SLAVE, i);
--                              if (tmp < 0) {
--                                      /* no more entries for port _i_ */
--                                      /* pr_debug("erom: slave port %d "
--                                       * "has %d descriptors\n", i, j); */
--                                      break;
--                              } else {
--                                      if (i == 0 && j == 0)
--                                              core->addr = tmp;
--                              }
--                      }
--              }
--
--              /* get & parse master wrappers */
--              for (i = 0; i < wrappers[0]; i++) {
--                      for (j = 0; ; j++) {
--                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
--                                      SCAN_ADDR_TYPE_MWRAP, i);
--                              if (tmp < 0) {
--                                      /* no more entries for port _i_ */
--                                      /* pr_debug("erom: master wrapper %d "
--                                       * "has %d descriptors\n", i, j); */
--                                      break;
--                              } else {
--                                      if (i == 0 && j == 0)
--                                              core->wrap = tmp;
--                              }
--                      }
--              }
--
--              /* get & parse slave wrappers */
--              for (i = 0; i < wrappers[1]; i++) {
--                      u8 hack = (ports[1] == 1) ? 0 : 1;
--                      for (j = 0; ; j++) {
--                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
--                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
--                              if (tmp < 0) {
--                                      /* no more entries for port _i_ */
--                                      /* pr_debug("erom: master wrapper %d "
--                                       * has %d descriptors\n", i, j); */
--                                      break;
--                              } else {
--                                      if (wrappers[0] == 0 && !i && !j)
--                                              core->wrap = tmp;
--                              }
--                      }
--              }
-+              else if (err == -ESPIPE)
-+                      break;
-+              else if (err < 0)
-+                      return err;
-               pr_info("Core %d found: %s "
-                       "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-@@ -351,9 +360,6 @@ int bcma_bus_scan(struct bcma_bus *bus)
-               core->core_index = bus->nr_cores++;
-               list_add(&core->list, &bus->cores);
--              continue;
--out:
--              return err;
-       }
-       return 0;
diff --git a/target/linux/brcm47xx/patches-3.0/0002-bcma-move-initializing-of-struct-bcma_bus-to-own-fun.patch b/target/linux/brcm47xx/patches-3.0/0002-bcma-move-initializing-of-struct-bcma_bus-to-own-fun.patch
deleted file mode 100644 (file)
index 48191ab..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-From 30ef571a04dc19171c6b6664d88b60c39161eb42 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 18 Jun 2011 11:55:47 +0200
-Subject: [PATCH 02/26] bcma: move initializing of struct bcma_bus to own function.
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This makes it possible to use this code in some other method.
-
-Acked-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/scan.c |   17 +++++++++++------
- 1 files changed, 11 insertions(+), 6 deletions(-)
-
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -312,15 +312,10 @@ static int bcma_get_next_core(struct bcm
-       return 0;
- }
--int bcma_bus_scan(struct bcma_bus *bus)
-+static void bcma_init_bus(struct bcma_bus *bus)
- {
--      u32 erombase;
--      u32 __iomem *eromptr, *eromend;
--
-       s32 tmp;
--      int err;
--
-       INIT_LIST_HEAD(&bus->cores);
-       bus->nr_cores = 0;
-@@ -330,6 +325,16 @@ int bcma_bus_scan(struct bcma_bus *bus)
-       bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
-       bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
-       bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
-+}
-+
-+int bcma_bus_scan(struct bcma_bus *bus)
-+{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
-+
-+      int err;
-+
-+      bcma_init_bus(bus);
-       erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-       eromptr = bus->mmio;
diff --git a/target/linux/brcm47xx/patches-3.0/0003-bcma-add-functions-to-scan-cores-needed-on-SoCs.patch b/target/linux/brcm47xx/patches-3.0/0003-bcma-add-functions-to-scan-cores-needed-on-SoCs.patch
deleted file mode 100644 (file)
index 92cd65d..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-From f3c07dd351161cb33f1c8e1ff55a65ae0cc6b661 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 18 Jun 2011 14:30:55 +0200
-Subject: [PATCH 03/26] bcma: add functions to scan cores needed on SoCs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The chip common and mips core have to be setup early in the boot
-process to get the cpu clock.
-bcma_bus_early_register() gets pointers to some space to store the core
-data and searches for the chip common and mips core and initializes
-chip common. After that was done and the kernel is out of early boot we
-just have to run bcma_bus_register() and it will search for the other
-cores, initialize and register them.
-The cores are getting the same numbers as before.
-
-Acked-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/bcma_private.h                 |    7 ++
- drivers/bcma/driver_chipcommon.c            |    5 ++
- drivers/bcma/driver_pci.c                   |    5 ++
- drivers/bcma/main.c                         |   46 +++++++++++++
- drivers/bcma/scan.c                         |   95 +++++++++++++++++++++++++--
- include/linux/bcma/bcma.h                   |    1 +
- include/linux/bcma/bcma_driver_chipcommon.h |    1 +
- 7 files changed, 154 insertions(+), 6 deletions(-)
-
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -15,9 +15,16 @@ struct bcma_bus;
- /* main.c */
- int bcma_bus_register(struct bcma_bus *bus);
- void bcma_bus_unregister(struct bcma_bus *bus);
-+int __init bcma_bus_early_register(struct bcma_bus *bus,
-+                                 struct bcma_device *core_cc,
-+                                 struct bcma_device *core_mips);
- /* scan.c */
- int bcma_bus_scan(struct bcma_bus *bus);
-+int __init bcma_bus_scan_early(struct bcma_bus *bus,
-+                             struct bcma_device_id *match,
-+                             struct bcma_device *core);
-+void bcma_init_bus(struct bcma_bus *bus);
- /* sprom.c */
- int bcma_sprom_get(struct bcma_bus *bus);
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bc
-       u32 leddc_on = 10;
-       u32 leddc_off = 90;
-+      if (cc->setup_done)
-+              return;
-+
-       if (cc->core->id.rev >= 11)
-               cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
-       cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
-@@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bc
-                       ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
-                        (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
-       }
-+
-+      cc->setup_done = true;
- }
- /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -187,6 +187,9 @@ static bool bcma_core_pci_is_in_hostmode
- void bcma_core_pci_init(struct bcma_drv_pci *pc)
- {
-+      if (pc->setup_done)
-+              return;
-+
-       if (bcma_core_pci_is_in_hostmode(pc)) {
- #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
-               bcma_core_pci_hostmode_init(pc);
-@@ -196,6 +199,8 @@ void bcma_core_pci_init(struct bcma_drv_
-       } else {
-               bcma_core_pci_clientmode_init(pc);
-       }
-+
-+      pc->setup_done = true;
- }
- int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -169,6 +169,52 @@ void bcma_bus_unregister(struct bcma_bus
-       bcma_unregister_cores(bus);
- }
-+int __init bcma_bus_early_register(struct bcma_bus *bus,
-+                                 struct bcma_device *core_cc,
-+                                 struct bcma_device *core_mips)
-+{
-+      int err;
-+      struct bcma_device *core;
-+      struct bcma_device_id match;
-+
-+      bcma_init_bus(bus);
-+
-+      match.manuf = BCMA_MANUF_BCM;
-+      match.id = BCMA_CORE_CHIPCOMMON;
-+      match.class = BCMA_CL_SIM;
-+      match.rev = BCMA_ANY_REV;
-+
-+      /* Scan for chip common core */
-+      err = bcma_bus_scan_early(bus, &match, core_cc);
-+      if (err) {
-+              pr_err("Failed to scan for common core: %d\n", err);
-+              return -1;
-+      }
-+
-+      match.manuf = BCMA_MANUF_MIPS;
-+      match.id = BCMA_CORE_MIPS_74K;
-+      match.class = BCMA_CL_SIM;
-+      match.rev = BCMA_ANY_REV;
-+
-+      /* Scan for mips core */
-+      err = bcma_bus_scan_early(bus, &match, core_mips);
-+      if (err) {
-+              pr_err("Failed to scan for mips core: %d\n", err);
-+              return -1;
-+      }
-+
-+      /* Init CC core */
-+      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
-+      if (core) {
-+              bus->drv_cc.core = core;
-+              bcma_core_chipcommon_init(&bus->drv_cc);
-+      }
-+
-+      pr_info("Early bus registered\n");
-+
-+      return 0;
-+}
-+
- int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
- {
-       drv->drv.name = drv->name;
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -200,7 +200,20 @@ static s32 bcma_erom_get_addr_desc(struc
-       return addrl;
- }
-+static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
-+                                                 u16 index)
-+{
-+      struct bcma_device *core;
-+
-+      list_for_each_entry(core, &bus->cores, list) {
-+              if (core->core_index == index)
-+                      return core;
-+      }
-+      return NULL;
-+}
-+
- static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
-+                            struct bcma_device_id *match, int core_num,
-                             struct bcma_device *core)
- {
-       s32 tmp;
-@@ -251,6 +264,21 @@ static int bcma_get_next_core(struct bcm
-               return -ENXIO;
-       }
-+      if (bcma_find_core_by_index(bus, core_num)) {
-+              bcma_erom_skip_component(bus, eromptr);
-+              return -ENODEV;
-+      }
-+
-+      if (match && ((match->manuf != BCMA_ANY_MANUF &&
-+            match->manuf != core->id.manuf) ||
-+           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
-+           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
-+           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
-+          )) {
-+              bcma_erom_skip_component(bus, eromptr);
-+              return -ENODEV;
-+      }
-+
-       /* get & parse master ports */
-       for (i = 0; i < ports[0]; i++) {
-               u32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
-@@ -312,10 +340,13 @@ static int bcma_get_next_core(struct bcm
-       return 0;
- }
--static void bcma_init_bus(struct bcma_bus *bus)
-+void bcma_init_bus(struct bcma_bus *bus)
- {
-       s32 tmp;
-+      if (bus->init_done)
-+              return;
-+
-       INIT_LIST_HEAD(&bus->cores);
-       bus->nr_cores = 0;
-@@ -325,6 +356,7 @@ static void bcma_init_bus(struct bcma_bu
-       bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
-       bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
-       bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
-+      bus->init_done = true;
- }
- int bcma_bus_scan(struct bcma_bus *bus)
-@@ -332,7 +364,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
-       u32 erombase;
-       u32 __iomem *eromptr, *eromend;
--      int err;
-+      int err, core_num = 0;
-       bcma_init_bus(bus);
-@@ -349,23 +381,74 @@ int bcma_bus_scan(struct bcma_bus *bus)
-               INIT_LIST_HEAD(&core->list);
-               core->bus = bus;
--              err = bcma_get_next_core(bus, &eromptr, core);
--              if (err == -ENXIO)
-+              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
-+              if (err == -ENODEV) {
-+                      core_num++;
-+                      continue;
-+              } else if (err == -ENXIO)
-                       continue;
-               else if (err == -ESPIPE)
-                       break;
-               else if (err < 0)
-                       return err;
-+              core->core_index = core_num++;
-+              bus->nr_cores++;
-+
-               pr_info("Core %d found: %s "
-                       "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
--                      bus->nr_cores, bcma_device_name(&core->id),
-+                      core->core_index, bcma_device_name(&core->id),
-                       core->id.manuf, core->id.id, core->id.rev,
-                       core->id.class);
--              core->core_index = bus->nr_cores++;
-               list_add(&core->list, &bus->cores);
-       }
-       return 0;
- }
-+
-+int __init bcma_bus_scan_early(struct bcma_bus *bus,
-+                             struct bcma_device_id *match,
-+                             struct bcma_device *core)
-+{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
-+
-+      int err, core_num = 0;
-+
-+      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
-+      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
-+
-+      bcma_scan_switch_core(bus, erombase);
-+
-+      while (eromptr < eromend) {
-+              memset(core, 0, sizeof(*core));
-+              INIT_LIST_HEAD(&core->list);
-+              core->bus = bus;
-+
-+              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
-+              if (err == -ENODEV) {
-+                      core_num++;
-+                      continue;
-+              } else if (err == -ENXIO)
-+                      continue;
-+              else if (err == -ESPIPE)
-+                      break;
-+              else if (err < 0)
-+                      return err;
-+
-+              core->core_index = core_num++;
-+              bus->nr_cores++;
-+              pr_info("Core %d found: %s "
-+                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      core->core_index, bcma_device_name(&core->id),
-+                      core->id.manuf, core->id.id, core->id.rev,
-+                      core->id.class);
-+
-+              list_add(&core->list, &bus->cores);
-+              return 0;
-+      }
-+
-+      return -ENODEV;
-+}
---- a/include/linux/bcma/bcma.h
-+++ b/include/linux/bcma/bcma.h
-@@ -190,6 +190,7 @@ struct bcma_bus {
-       struct bcma_device *mapped_core;
-       struct list_head cores;
-       u8 nr_cores;
-+      u8 init_done:1;
-       struct bcma_drv_cc drv_cc;
-       struct bcma_drv_pci drv_pci;
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -252,6 +252,7 @@ struct bcma_drv_cc {
-       u32 status;
-       u32 capabilities;
-       u32 capabilities_ext;
-+      u8 setup_done:1;
-       /* Fast Powerup Delay constant */
-       u16 fast_pwrup_delay;
-       struct bcma_chipcommon_pmu pmu;
diff --git a/target/linux/brcm47xx/patches-3.0/0004-bcma-add-SOC-bus.patch b/target/linux/brcm47xx/patches-3.0/0004-bcma-add-SOC-bus.patch
deleted file mode 100644 (file)
index 6ad9dce..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-From d743a740b76a6be9e88fe1ae6991682927a7769c Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 18 Jun 2011 14:31:53 +0200
-Subject: [PATCH 04/26] bcma: add SOC bus
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch adds support for using bcma on a Broadcom SoC as the system
-bus. An SoC like the bcm4716 could register this bus and use it to
-searches for the bcma cores and register the devices on this bus.
-
-BCMA_HOSTTYPE_NONE was intended for SoCs at first but BCMA_HOSTTYPE_SOC
-is a better name.
-
-Acked-by: Rafał Miłecki <zajec5@gmail.com>
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/Kconfig          |    4 +
- drivers/bcma/Makefile         |    1 +
- drivers/bcma/core.c           |    2 +
- drivers/bcma/driver_pci.c     |    9 ++-
- drivers/bcma/host_soc.c       |  183 +++++++++++++++++++++++++++++++++++++++++
- drivers/bcma/main.c           |    9 ++-
- drivers/bcma/scan.c           |   42 ++++++++-
- include/linux/bcma/bcma.h     |    5 +-
- include/linux/bcma/bcma_soc.h |   16 ++++
- 9 files changed, 263 insertions(+), 8 deletions(-)
- create mode 100644 drivers/bcma/host_soc.c
- create mode 100644 include/linux/bcma/bcma_soc.h
-
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -34,6 +34,10 @@ config BCMA_DRIVER_PCI_HOSTMODE
-       help
-         PCI core hostmode operation (external PCI bus).
-+config BCMA_HOST_SOC
-+      bool
-+      depends on BCMA && MIPS
-+
- config BCMA_DEBUG
-       bool "BCMA debugging"
-       depends on BCMA
---- a/drivers/bcma/Makefile
-+++ b/drivers/bcma/Makefile
-@@ -3,6 +3,7 @@ bcma-y                                 += driver_chipcommon.o driver
- bcma-y                                        += driver_pci.o
- bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
- bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
-+bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
- obj-$(CONFIG_BCMA)                    += bcma.o
- ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
---- a/drivers/bcma/core.c
-+++ b/drivers/bcma/core.c
-@@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
- u32 bcma_core_dma_translation(struct bcma_device *core)
- {
-       switch (core->bus->hosttype) {
-+      case BCMA_HOSTTYPE_SOC:
-+              return 0;
-       case BCMA_HOSTTYPE_PCI:
-               if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
-                       return BCMA_DMA_TRANSLATION_DMA64_CMT;
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -208,7 +208,14 @@ int bcma_core_pci_irq_ctl(struct bcma_dr
- {
-       struct pci_dev *pdev = pc->core->bus->host_pci;
-       u32 coremask, tmp;
--      int err;
-+      int err = 0;
-+
-+      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
-+              /* This bcma device is not on a PCI host-bus. So the IRQs are
-+               * not routed through the PCI core.
-+               * So we must not enable routing through the PCI core. */
-+              goto out;
-+      }
-       err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
-       if (err)
---- /dev/null
-+++ b/drivers/bcma/host_soc.c
-@@ -0,0 +1,183 @@
-+/*
-+ * Broadcom specific AMBA
-+ * System on Chip (SoC) Host
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include "bcma_private.h"
-+#include "scan.h"
-+#include <linux/bcma/bcma.h>
-+#include <linux/bcma/bcma_soc.h>
-+
-+static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
-+{
-+      return readb(core->io_addr + offset);
-+}
-+
-+static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
-+{
-+      return readw(core->io_addr + offset);
-+}
-+
-+static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
-+{
-+      return readl(core->io_addr + offset);
-+}
-+
-+static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
-+                               u8 value)
-+{
-+      writeb(value, core->io_addr + offset);
-+}
-+
-+static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
-+                               u16 value)
-+{
-+      writew(value, core->io_addr + offset);
-+}
-+
-+static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
-+                               u32 value)
-+{
-+      writel(value, core->io_addr + offset);
-+}
-+
-+#ifdef CONFIG_BCMA_BLOCKIO
-+static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
-+                                   size_t count, u16 offset, u8 reg_width)
-+{
-+      void __iomem *addr = core->io_addr + offset;
-+
-+      switch (reg_width) {
-+      case sizeof(u8): {
-+              u8 *buf = buffer;
-+
-+              while (count) {
-+                      *buf = __raw_readb(addr);
-+                      buf++;
-+                      count--;
-+              }
-+              break;
-+      }
-+      case sizeof(u16): {
-+              __le16 *buf = buffer;
-+
-+              WARN_ON(count & 1);
-+              while (count) {
-+                      *buf = (__force __le16)__raw_readw(addr);
-+                      buf++;
-+                      count -= 2;
-+              }
-+              break;
-+      }
-+      case sizeof(u32): {
-+              __le32 *buf = buffer;
-+
-+              WARN_ON(count & 3);
-+              while (count) {
-+                      *buf = (__force __le32)__raw_readl(addr);
-+                      buf++;
-+                      count -= 4;
-+              }
-+              break;
-+      }
-+      default:
-+              WARN_ON(1);
-+      }
-+}
-+
-+static void bcma_host_soc_block_write(struct bcma_device *core,
-+                                    const void *buffer,
-+                                    size_t count, u16 offset, u8 reg_width)
-+{
-+      void __iomem *addr = core->io_addr + offset;
-+
-+      switch (reg_width) {
-+      case sizeof(u8): {
-+              const u8 *buf = buffer;
-+
-+              while (count) {
-+                      __raw_writeb(*buf, addr);
-+                      buf++;
-+                      count--;
-+              }
-+              break;
-+      }
-+      case sizeof(u16): {
-+              const __le16 *buf = buffer;
-+
-+              WARN_ON(count & 1);
-+              while (count) {
-+                      __raw_writew((__force u16)(*buf), addr);
-+                      buf++;
-+                      count -= 2;
-+              }
-+              break;
-+      }
-+      case sizeof(u32): {
-+              const __le32 *buf = buffer;
-+
-+              WARN_ON(count & 3);
-+              while (count) {
-+                      __raw_writel((__force u32)(*buf), addr);
-+                      buf++;
-+                      count -= 4;
-+              }
-+              break;
-+      }
-+      default:
-+              WARN_ON(1);
-+      }
-+}
-+#endif /* CONFIG_BCMA_BLOCKIO */
-+
-+static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
-+{
-+      return readl(core->io_wrap + offset);
-+}
-+
-+static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
-+                                u32 value)
-+{
-+      writel(value, core->io_wrap + offset);
-+}
-+
-+const struct bcma_host_ops bcma_host_soc_ops = {
-+      .read8          = bcma_host_soc_read8,
-+      .read16         = bcma_host_soc_read16,
-+      .read32         = bcma_host_soc_read32,
-+      .write8         = bcma_host_soc_write8,
-+      .write16        = bcma_host_soc_write16,
-+      .write32        = bcma_host_soc_write32,
-+#ifdef CONFIG_BCMA_BLOCKIO
-+      .block_read     = bcma_host_soc_block_read,
-+      .block_write    = bcma_host_soc_block_write,
-+#endif
-+      .aread32        = bcma_host_soc_aread32,
-+      .awrite32       = bcma_host_soc_awrite32,
-+};
-+
-+int __init bcma_host_soc_register(struct bcma_soc *soc)
-+{
-+      struct bcma_bus *bus = &soc->bus;
-+      int err;
-+
-+      /* iomap only first core. We have to read some register on this core
-+       * to scan the bus.
-+       */
-+      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
-+      if (!bus->mmio)
-+              return -ENOMEM;
-+
-+      /* Host specific */
-+      bus->hosttype = BCMA_HOSTTYPE_SOC;
-+      bus->ops = &bcma_host_soc_ops;
-+
-+      /* Register */
-+      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
-+      if (err)
-+              iounmap(bus->mmio);
-+
-+      return err;
-+}
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -66,6 +66,10 @@ static struct bcma_device *bcma_find_cor
- static void bcma_release_core_dev(struct device *dev)
- {
-       struct bcma_device *core = container_of(dev, struct bcma_device, dev);
-+      if (core->io_addr)
-+              iounmap(core->io_addr);
-+      if (core->io_wrap)
-+              iounmap(core->io_wrap);
-       kfree(core);
- }
-@@ -93,7 +97,10 @@ static int bcma_register_cores(struct bc
-                       core->dma_dev = &bus->host_pci->dev;
-                       core->irq = bus->host_pci->irq;
-                       break;
--              case BCMA_HOSTTYPE_NONE:
-+              case BCMA_HOSTTYPE_SOC:
-+                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
-+                      core->dma_dev = &core->dev;
-+                      break;
-               case BCMA_HOSTTYPE_SDIO:
-                       break;
-               }
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -337,6 +337,16 @@ static int bcma_get_next_core(struct bcm
-                       }
-               }
-       }
-+      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
-+              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
-+              if (!core->io_addr)
-+                      return -ENOMEM;
-+              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
-+              if (!core->io_wrap) {
-+                      iounmap(core->io_addr);
-+                      return -ENOMEM;
-+              }
-+      }
-       return 0;
- }
-@@ -369,7 +379,14 @@ int bcma_bus_scan(struct bcma_bus *bus)
-       bcma_init_bus(bus);
-       erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
--      eromptr = bus->mmio;
-+      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
-+              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
-+              if (!eromptr)
-+                      return -ENOMEM;
-+      } else {
-+              eromptr = bus->mmio;
-+      }
-+
-       eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
-       bcma_scan_switch_core(bus, erombase);
-@@ -404,6 +421,9 @@ int bcma_bus_scan(struct bcma_bus *bus)
-               list_add(&core->list, &bus->cores);
-       }
-+      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
-+              iounmap(eromptr);
-+
-       return 0;
- }
-@@ -414,10 +434,18 @@ int __init bcma_bus_scan_early(struct bc
-       u32 erombase;
-       u32 __iomem *eromptr, *eromend;
--      int err, core_num = 0;
-+      int err = -ENODEV;
-+      int core_num = 0;
-       erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
--      eromptr = bus->mmio;
-+      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
-+              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
-+              if (!eromptr)
-+                      return -ENOMEM;
-+      } else {
-+              eromptr = bus->mmio;
-+      }
-+
-       eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
-       bcma_scan_switch_core(bus, erombase);
-@@ -447,8 +475,12 @@ int __init bcma_bus_scan_early(struct bc
-                       core->id.class);
-               list_add(&core->list, &bus->cores);
--              return 0;
-+              err = 0;
-+              break;
-       }
--      return -ENODEV;
-+      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
-+              iounmap(eromptr);
-+
-+      return err;
- }
---- a/include/linux/bcma/bcma.h
-+++ b/include/linux/bcma/bcma.h
-@@ -14,9 +14,9 @@ struct bcma_device;
- struct bcma_bus;
- enum bcma_hosttype {
--      BCMA_HOSTTYPE_NONE,
-       BCMA_HOSTTYPE_PCI,
-       BCMA_HOSTTYPE_SDIO,
-+      BCMA_HOSTTYPE_SOC,
- };
- struct bcma_chipinfo {
-@@ -138,6 +138,9 @@ struct bcma_device {
-       u32 addr;
-       u32 wrap;
-+      void __iomem *io_addr;
-+      void __iomem *io_wrap;
-+
-       void *drvdata;
-       struct list_head list;
- };
---- /dev/null
-+++ b/include/linux/bcma/bcma_soc.h
-@@ -0,0 +1,16 @@
-+#ifndef LINUX_BCMA_SOC_H_
-+#define LINUX_BCMA_SOC_H_
-+
-+#include <linux/bcma/bcma.h>
-+
-+struct bcma_soc {
-+      struct bcma_bus bus;
-+      struct bcma_device core_cc;
-+      struct bcma_device core_mips;
-+};
-+
-+int __init bcma_host_soc_register(struct bcma_soc *soc);
-+
-+int bcma_bus_register(struct bcma_bus *bus);
-+
-+#endif /* LINUX_BCMA_SOC_H_ */
diff --git a/target/linux/brcm47xx/patches-3.0/0005-bcma-add-mips-driver.patch b/target/linux/brcm47xx/patches-3.0/0005-bcma-add-mips-driver.patch
deleted file mode 100644 (file)
index 31181a4..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-From 3be3bbe24a1d49283864a1e1ea1d88a2e1700b50 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Mon, 6 Jun 2011 00:07:32 +0200
-Subject: [PATCH 05/26] bcma: add mips driver
-
-This adds a mips driver to bcma. This is only found on embedded
-devices. For now the driver just initializes the irqs used on this
-system.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/Kconfig                        |    9 +
- drivers/bcma/Makefile                       |    1 +
- drivers/bcma/driver_mips.c                  |  243 +++++++++++++++++++++++++++
- drivers/bcma/main.c                         |   15 ++
- include/linux/bcma/bcma.h                   |    3 +
- include/linux/bcma/bcma_driver_chipcommon.h |   13 ++
- include/linux/bcma/bcma_driver_mips.h       |   49 ++++++
- 7 files changed, 333 insertions(+), 0 deletions(-)
- create mode 100644 drivers/bcma/driver_mips.c
- create mode 100644 include/linux/bcma/bcma_driver_mips.h
-
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -36,7 +36,16 @@ config BCMA_DRIVER_PCI_HOSTMODE
- config BCMA_HOST_SOC
-       bool
-+      depends on BCMA_DRIVER_MIPS
-+
-+config BCMA_DRIVER_MIPS
-+      bool "BCMA Broadcom MIPS core driver"
-       depends on BCMA && MIPS
-+      help
-+        Driver for the Broadcom MIPS core attached to Broadcom specific
-+        Advanced Microcontroller Bus.
-+
-+        If unsure, say N
- config BCMA_DEBUG
-       bool "BCMA debugging"
---- a/drivers/bcma/Makefile
-+++ b/drivers/bcma/Makefile
-@@ -2,6 +2,7 @@ bcma-y                                 += main.o scan.o core.o sprom
- bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
- bcma-y                                        += driver_pci.o
- bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
-+bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
- bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
- bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
- obj-$(CONFIG_BCMA)                    += bcma.o
---- /dev/null
-+++ b/drivers/bcma/driver_mips.c
-@@ -0,0 +1,243 @@
-+/*
-+ * Broadcom specific AMBA
-+ * Broadcom MIPS32 74K core driver
-+ *
-+ * Copyright 2009, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
-+ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
-+ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include "bcma_private.h"
-+
-+#include <linux/bcma/bcma.h>
-+
-+#include <linux/serial.h>
-+#include <linux/serial_core.h>
-+#include <linux/serial_reg.h>
-+#include <linux/time.h>
-+
-+/* The 47162a0 hangs when reading MIPS DMP registers registers */
-+static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
-+{
-+      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
-+             dev->id.id == BCMA_CORE_MIPS_74K;
-+}
-+
-+/* The 5357b0 hangs when reading USB20H DMP registers */
-+static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
-+{
-+      return (dev->bus->chipinfo.id == 0x5357 ||
-+              dev->bus->chipinfo.id == 0x4749) &&
-+             dev->bus->chipinfo.pkg == 11 &&
-+             dev->id.id == BCMA_CORE_USB20_HOST;
-+}
-+
-+static inline u32 mips_read32(struct bcma_drv_mips *mcore,
-+                            u16 offset)
-+{
-+      return bcma_read32(mcore->core, offset);
-+}
-+
-+static inline void mips_write32(struct bcma_drv_mips *mcore,
-+                              u16 offset,
-+                              u32 value)
-+{
-+      bcma_write32(mcore->core, offset, value);
-+}
-+
-+static const u32 ipsflag_irq_mask[] = {
-+      0,
-+      BCMA_MIPS_IPSFLAG_IRQ1,
-+      BCMA_MIPS_IPSFLAG_IRQ2,
-+      BCMA_MIPS_IPSFLAG_IRQ3,
-+      BCMA_MIPS_IPSFLAG_IRQ4,
-+};
-+
-+static const u32 ipsflag_irq_shift[] = {
-+      0,
-+      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
-+      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
-+      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
-+      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
-+};
-+
-+static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
-+{
-+      u32 flag;
-+
-+      if (bcma_core_mips_bcm47162a0_quirk(dev))
-+              return dev->core_index;
-+      if (bcma_core_mips_bcm5357b0_quirk(dev))
-+              return dev->core_index;
-+      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
-+
-+      return flag & 0x1F;
-+}
-+
-+/* Get the MIPS IRQ assignment for a specified device.
-+ * If unassigned, 0 is returned.
-+ */
-+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
-+{
-+      struct bcma_device *mdev = dev->bus->drv_mips.core;
-+      u32 irqflag;
-+      unsigned int irq;
-+
-+      irqflag = bcma_core_mips_irqflag(dev);
-+
-+      for (irq = 1; irq <= 4; irq++)
-+              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
-+                  (1 << irqflag))
-+                      return irq;
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(bcma_core_mips_irq);
-+
-+static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
-+{
-+      unsigned int oldirq = bcma_core_mips_irq(dev);
-+      struct bcma_bus *bus = dev->bus;
-+      struct bcma_device *mdev = bus->drv_mips.core;
-+      u32 irqflag;
-+
-+      irqflag = bcma_core_mips_irqflag(dev);
-+      BUG_ON(oldirq == 6);
-+
-+      dev->irq = irq + 2;
-+
-+      /* clear the old irq */
-+      if (oldirq == 0)
-+              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
-+                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
-+                          ~(1 << irqflag));
-+      else
-+              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
-+
-+      /* assign the new one */
-+      if (irq == 0) {
-+              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
-+                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
-+                          (1 << irqflag));
-+      } else {
-+              u32 oldirqflag = bcma_read32(mdev,
-+                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
-+              if (oldirqflag) {
-+                      struct bcma_device *core;
-+
-+                      /* backplane irq line is in use, find out who uses
-+                       * it and set user to irq 0
-+                       */
-+                      list_for_each_entry_reverse(core, &bus->cores, list) {
-+                              if ((1 << bcma_core_mips_irqflag(core)) ==
-+                                  oldirqflag) {
-+                                      bcma_core_mips_set_irq(core, 0);
-+                                      break;
-+                              }
-+                      }
-+              }
-+              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
-+                           1 << irqflag);
-+      }
-+
-+      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
-+              dev->id.id, oldirq + 2, irq + 2);
-+}
-+
-+static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
-+{
-+      int i;
-+      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
-+      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
-+      for (i = 0; i <= 6; i++)
-+              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
-+      printk("\n");
-+}
-+
-+static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
-+{
-+      struct bcma_device *core;
-+
-+      list_for_each_entry_reverse(core, &bus->cores, list) {
-+              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
-+      }
-+}
-+
-+static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
-+{
-+      struct bcma_bus *bus = mcore->core->bus;
-+
-+      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
-+      case BCMA_CC_FLASHT_STSER:
-+      case BCMA_CC_FLASHT_ATSER:
-+              pr_err("Serial flash not supported.\n");
-+              break;
-+      case BCMA_CC_FLASHT_PARA:
-+              pr_info("found parallel flash.\n");
-+              bus->drv_cc.pflash.window = 0x1c000000;
-+              bus->drv_cc.pflash.window_size = 0x02000000;
-+
-+              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
-+                   BCMA_CC_FLASH_CFG_DS) == 0)
-+                      bus->drv_cc.pflash.buswidth = 1;
-+              else
-+                      bus->drv_cc.pflash.buswidth = 2;
-+              break;
-+      default:
-+              pr_err("flash not supported.\n");
-+      }
-+}
-+
-+void bcma_core_mips_init(struct bcma_drv_mips *mcore)
-+{
-+      struct bcma_bus *bus;
-+      struct bcma_device *core;
-+      bus = mcore->core->bus;
-+
-+      pr_info("Initializing MIPS core...\n");
-+
-+      if (!mcore->setup_done)
-+              mcore->assigned_irqs = 1;
-+
-+      /* Assign IRQs to all cores on the bus */
-+      list_for_each_entry_reverse(core, &bus->cores, list) {
-+              int mips_irq;
-+              if (core->irq)
-+                      continue;
-+
-+              mips_irq = bcma_core_mips_irq(core);
-+              if (mips_irq > 4)
-+                      core->irq = 0;
-+              else
-+                      core->irq = mips_irq + 2;
-+              if (core->irq > 5)
-+                      continue;
-+              switch (core->id.id) {
-+              case BCMA_CORE_PCI:
-+              case BCMA_CORE_PCIE:
-+              case BCMA_CORE_ETHERNET:
-+              case BCMA_CORE_ETHERNET_GBIT:
-+              case BCMA_CORE_MAC_GBIT:
-+              case BCMA_CORE_80211:
-+              case BCMA_CORE_USB20_HOST:
-+                      /* These devices get their own IRQ line if available,
-+                       * the rest goes on IRQ0
-+                       */
-+                      if (mcore->assigned_irqs <= 4)
-+                              bcma_core_mips_set_irq(core,
-+                                                     mcore->assigned_irqs++);
-+                      break;
-+              }
-+      }
-+      pr_info("IRQ reconfiguration done\n");
-+      bcma_core_mips_dump_irq(bus);
-+
-+      if (mcore->setup_done)
-+              return;
-+
-+      bcma_core_mips_flash_detect(mcore);
-+      mcore->setup_done = true;
-+}
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -84,6 +84,7 @@ static int bcma_register_cores(struct bc
-               case BCMA_CORE_CHIPCOMMON:
-               case BCMA_CORE_PCI:
-               case BCMA_CORE_PCIE:
-+              case BCMA_CORE_MIPS_74K:
-                       continue;
-               }
-@@ -147,6 +148,13 @@ int bcma_bus_register(struct bcma_bus *b
-               bcma_core_chipcommon_init(&bus->drv_cc);
-       }
-+      /* Init MIPS core */
-+      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
-+      if (core) {
-+              bus->drv_mips.core = core;
-+              bcma_core_mips_init(&bus->drv_mips);
-+      }
-+
-       /* Init PCIE core */
-       core = bcma_find_core(bus, BCMA_CORE_PCIE);
-       if (core) {
-@@ -217,6 +225,13 @@ int __init bcma_bus_early_register(struc
-               bcma_core_chipcommon_init(&bus->drv_cc);
-       }
-+      /* Init MIPS core */
-+      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
-+      if (core) {
-+              bus->drv_mips.core = core;
-+              bcma_core_mips_init(&bus->drv_mips);
-+      }
-+
-       pr_info("Early bus registered\n");
-       return 0;
---- a/include/linux/bcma/bcma.h
-+++ b/include/linux/bcma/bcma.h
-@@ -6,6 +6,7 @@
- #include <linux/bcma/bcma_driver_chipcommon.h>
- #include <linux/bcma/bcma_driver_pci.h>
-+#include <linux/bcma/bcma_driver_mips.h>
- #include <linux/ssb/ssb.h> /* SPROM sharing */
- #include "bcma_regs.h"
-@@ -130,6 +131,7 @@ struct bcma_device {
-       struct device dev;
-       struct device *dma_dev;
-+
-       unsigned int irq;
-       bool dev_registered;
-@@ -197,6 +199,7 @@ struct bcma_bus {
-       struct bcma_drv_cc drv_cc;
-       struct bcma_drv_pci drv_pci;
-+      struct bcma_drv_mips drv_mips;
-       /* We decided to share SPROM struct with SSB as long as we do not need
-        * any hacks for BCMA. This simplifies drivers code. */
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -24,6 +24,7 @@
- #define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
- #define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
- #define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
-+#define   BCMA_CC_FLASHT_NFLASH               0x00000200
- #define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
- #define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
- #define   BCMA_PLLTYPE_NONE           0x00000000
-@@ -178,6 +179,7 @@
- #define BCMA_CC_PROG_CFG              0x0120
- #define BCMA_CC_PROG_WAITCNT          0x0124
- #define BCMA_CC_FLASH_CFG             0x0128
-+#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
- #define BCMA_CC_FLASH_WAITCNT         0x012C
- /* 0x1E0 is defined as shared BCMA_CLKCTLST */
- #define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
-@@ -247,6 +249,14 @@ struct bcma_chipcommon_pmu {
-       u32 crystalfreq;        /* The active crystal frequency (in kHz) */
- };
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
-+struct bcma_pflash {
-+      u8 buswidth;
-+      u32 window;
-+      u32 window_size;
-+};
-+#endif /* CONFIG_BCMA_DRIVER_MIPS */
-+
- struct bcma_drv_cc {
-       struct bcma_device *core;
-       u32 status;
-@@ -256,6 +266,9 @@ struct bcma_drv_cc {
-       /* Fast Powerup Delay constant */
-       u16 fast_pwrup_delay;
-       struct bcma_chipcommon_pmu pmu;
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
-+      struct bcma_pflash pflash;
-+#endif /* CONFIG_BCMA_DRIVER_MIPS */
- };
- /* Register access */
---- /dev/null
-+++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -0,0 +1,49 @@
-+#ifndef LINUX_BCMA_DRIVER_MIPS_H_
-+#define LINUX_BCMA_DRIVER_MIPS_H_
-+
-+#define BCMA_MIPS_IPSFLAG             0x0F08
-+/* which sbflags get routed to mips interrupt 1 */
-+#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
-+#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
-+/* which sbflags get routed to mips interrupt 2 */
-+#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
-+#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
-+/* which sbflags get routed to mips interrupt 3 */
-+#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
-+#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
-+/* which sbflags get routed to mips interrupt 4 */
-+#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
-+#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
-+
-+/* MIPS 74K core registers */
-+#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
-+#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
-+#define BCMA_MIPS_MIPS74K_BIST                0x000C
-+#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
-+#define BCMA_MIPS_MIPS74K_INTMASK(int) \
-+      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
-+#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
-+#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
-+#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
-+#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
-+#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
-+
-+#define BCMA_MIPS_OOBSELOUTA30                0x100
-+
-+struct bcma_device;
-+
-+struct bcma_drv_mips {
-+      struct bcma_device *core;
-+      u8 setup_done:1;
-+      unsigned int assigned_irqs;
-+};
-+
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
-+extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
-+#else
-+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
-+#endif
-+
-+extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
-+
-+#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
diff --git a/target/linux/brcm47xx/patches-3.0/0006-bcma-add-serial-console-support.patch b/target/linux/brcm47xx/patches-3.0/0006-bcma-add-serial-console-support.patch
deleted file mode 100644 (file)
index fd7b8ae..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-From 4d58b9a14669e5ea0026f0d27257041aecfcbed3 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Mon, 6 Jun 2011 00:07:33 +0200
-Subject: [PATCH 06/26] bcma: add serial console support
-
-This adds support for serial console to bcma, when operating on an SoC.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/bcma_private.h                 |    8 ++++
- drivers/bcma/driver_chipcommon.c            |   48 +++++++++++++++++++++++++++
- drivers/bcma/driver_chipcommon_pmu.c        |   26 ++++++++++++++
- drivers/bcma/driver_mips.c                  |    1 +
- include/linux/bcma/bcma_driver_chipcommon.h |   14 ++++++++
- 5 files changed, 97 insertions(+), 0 deletions(-)
-
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -29,6 +29,14 @@ void bcma_init_bus(struct bcma_bus *bus)
- /* sprom.c */
- int bcma_sprom_get(struct bcma_bus *bus);
-+/* driver_chipcommon.c */
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
-+void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
-+#endif /* CONFIG_BCMA_DRIVER_MIPS */
-+
-+/* driver_chipcommon_pmu.c */
-+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
-+
- #ifdef CONFIG_BCMA_HOST_PCI
- /* host_pci.c */
- extern int __init bcma_host_pci_init(void);
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -106,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcm
- {
-       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
- }
-+
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
-+void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
-+{
-+      unsigned int irq;
-+      u32 baud_base;
-+      u32 i;
-+      unsigned int ccrev = cc->core->id.rev;
-+      struct bcma_serial_port *ports = cc->serial_ports;
-+
-+      if (ccrev >= 11 && ccrev != 15) {
-+              /* Fixed ALP clock */
-+              baud_base = bcma_pmu_alp_clock(cc);
-+              if (ccrev >= 21) {
-+                      /* Turn off UART clock before switching clocksource. */
-+                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
-+                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
-+                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
-+              }
-+              /* Set the override bit so we don't divide it */
-+              bcma_cc_write32(cc, BCMA_CC_CORECTL,
-+                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
-+                             | BCMA_CC_CORECTL_UARTCLK0);
-+              if (ccrev >= 21) {
-+                      /* Re-enable the UART clock. */
-+                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
-+                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
-+                                     | BCMA_CC_CORECTL_UARTCLKEN);
-+              }
-+      } else {
-+              pr_err("serial not supported on this device ccrev: 0x%x\n",
-+                     ccrev);
-+              return;
-+      }
-+
-+      irq = bcma_core_mips_irq(cc->core);
-+
-+      /* Determine the registers of the UARTs */
-+      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
-+      for (i = 0; i < cc->nr_serial_ports; i++) {
-+              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
-+                              (i * 256);
-+              ports[i].irq = irq;
-+              ports[i].baud_base = baud_base;
-+              ports[i].reg_shift = 0;
-+      }
-+}
-+#endif /* CONFIG_BCMA_DRIVER_MIPS */
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -136,3 +136,29 @@ void bcma_pmu_init(struct bcma_drv_cc *c
-       bcma_pmu_swreg_init(cc);
-       bcma_pmu_workarounds(cc);
- }
-+
-+u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
-+{
-+      struct bcma_bus *bus = cc->core->bus;
-+
-+      switch (bus->chipinfo.id) {
-+      case 0x4716:
-+      case 0x4748:
-+      case 47162:
-+      case 0x4313:
-+      case 0x5357:
-+      case 0x4749:
-+      case 53572:
-+              /* always 20Mhz */
-+              return 20000 * 1000;
-+      case 0x5356:
-+      case 0x5300:
-+              /* always 25Mhz */
-+              return 25000 * 1000;
-+      default:
-+              pr_warn("No ALP clock specified for %04X device, "
-+                      "pmu rev. %d, using default %d Hz\n",
-+                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
-+      }
-+      return BCMA_CC_PMU_ALP_CLOCK;
-+}
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -238,6 +238,7 @@ void bcma_core_mips_init(struct bcma_drv
-       if (mcore->setup_done)
-               return;
-+      bcma_chipco_serial_init(&bus->drv_cc);
-       bcma_core_mips_flash_detect(mcore);
-       mcore->setup_done = true;
- }
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -241,6 +241,9 @@
- #define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
- #define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
-+/* ALP clock on pre-PMU chips */
-+#define BCMA_CC_PMU_ALP_CLOCK         20000000
-+
- /* Data for the PMU, if available.
-  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
-  */
-@@ -255,6 +258,14 @@ struct bcma_pflash {
-       u32 window;
-       u32 window_size;
- };
-+
-+struct bcma_serial_port {
-+      void *regs;
-+      unsigned long clockspeed;
-+      unsigned int irq;
-+      unsigned int baud_base;
-+      unsigned int reg_shift;
-+};
- #endif /* CONFIG_BCMA_DRIVER_MIPS */
- struct bcma_drv_cc {
-@@ -268,6 +279,9 @@ struct bcma_drv_cc {
-       struct bcma_chipcommon_pmu pmu;
- #ifdef CONFIG_BCMA_DRIVER_MIPS
-       struct bcma_pflash pflash;
-+
-+      int nr_serial_ports;
-+      struct bcma_serial_port serial_ports[4];
- #endif /* CONFIG_BCMA_DRIVER_MIPS */
- };
diff --git a/target/linux/brcm47xx/patches-3.0/0007-bcma-get-CPU-clock.patch b/target/linux/brcm47xx/patches-3.0/0007-bcma-get-CPU-clock.patch
deleted file mode 100644 (file)
index 7fa7520..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-From bd2bb5fbf1982b18f44b6fd78e45717e0757cdc0 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sat, 16 Jul 2011 15:19:38 +0200
-Subject: [PATCH 07/26] bcma: get CPU clock
-
-Add method to return the clock of the CPU. This is needed by the arch
-code to calculate the mips_hpt_frequency.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/bcma_private.h                 |    1 +
- drivers/bcma/driver_chipcommon_pmu.c        |  107 +++++++++++++++++++++++++++
- drivers/bcma/driver_mips.c                  |   12 +++
- include/linux/bcma/bcma_driver_chipcommon.h |   39 ++++++++++
- include/linux/bcma/bcma_driver_mips.h       |    2 +
- 5 files changed, 161 insertions(+), 0 deletions(-)
-
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -36,6 +36,7 @@ void bcma_chipco_serial_init(struct bcma
- /* driver_chipcommon_pmu.c */
- u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
-+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
- #ifdef CONFIG_BCMA_HOST_PCI
- /* host_pci.c */
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -11,6 +11,13 @@
- #include "bcma_private.h"
- #include <linux/bcma/bcma.h>
-+static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
-+{
-+      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-+      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-+      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
-+}
-+
- static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-                                       u32 offset, u32 mask, u32 set)
- {
-@@ -162,3 +169,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
-       }
-       return BCMA_CC_PMU_ALP_CLOCK;
- }
-+
-+/* Find the output of the "m" pll divider given pll controls that start with
-+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
-+ */
-+static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
-+{
-+      u32 tmp, div, ndiv, p1, p2, fc;
-+      struct bcma_bus *bus = cc->core->bus;
-+
-+      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
-+
-+      BUG_ON(!m || m > 4);
-+
-+      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
-+              /* Detect failure in clock setting */
-+              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
-+              if (tmp & 0x40000)
-+                      return 133 * 1000000;
-+      }
-+
-+      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
-+      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
-+      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
-+
-+      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
-+      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
-+              BCMA_CC_PPL_MDIV_MASK;
-+
-+      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
-+      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
-+
-+      /* Do calculation in Mhz */
-+      fc = bcma_pmu_alp_clock(cc) / 1000000;
-+      fc = (p1 * ndiv * fc) / p2;
-+
-+      /* Return clock in Hertz */
-+      return (fc / div) * 1000000;
-+}
-+
-+/* query bus clock frequency for PMU-enabled chipcommon */
-+u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
-+{
-+      struct bcma_bus *bus = cc->core->bus;
-+
-+      switch (bus->chipinfo.id) {
-+      case 0x4716:
-+      case 0x4748:
-+      case 47162:
-+              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
-+                                    BCMA_CC_PMU5_MAINPLL_SSB);
-+      case 0x5356:
-+              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
-+                                    BCMA_CC_PMU5_MAINPLL_SSB);
-+      case 0x5357:
-+      case 0x4749:
-+              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
-+                                    BCMA_CC_PMU5_MAINPLL_SSB);
-+      case 0x5300:
-+              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
-+                                    BCMA_CC_PMU5_MAINPLL_SSB);
-+      case 53572:
-+              return 75000000;
-+      default:
-+              pr_warn("No backplane clock specified for %04X device, "
-+                      "pmu rev. %d, using default %d Hz\n",
-+                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
-+      }
-+      return BCMA_CC_PMU_HT_CLOCK;
-+}
-+
-+/* query cpu clock frequency for PMU-enabled chipcommon */
-+u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
-+{
-+      struct bcma_bus *bus = cc->core->bus;
-+
-+      if (bus->chipinfo.id == 53572)
-+              return 300000000;
-+
-+      if (cc->pmu.rev >= 5) {
-+              u32 pll;
-+              switch (bus->chipinfo.id) {
-+              case 0x5356:
-+                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
-+                      break;
-+              case 0x5357:
-+              case 0x4749:
-+                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
-+                      break;
-+              default:
-+                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
-+                      break;
-+              }
-+
-+              /* TODO: if (bus->chipinfo.id == 0x5300)
-+                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
-+              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
-+      }
-+
-+      return bcma_pmu_get_clockcontrol(cc);
-+}
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -166,6 +166,18 @@ static void bcma_core_mips_dump_irq(stru
-       }
- }
-+u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
-+{
-+      struct bcma_bus *bus = mcore->core->bus;
-+
-+      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
-+              return bcma_pmu_get_clockcpu(&bus->drv_cc);
-+
-+      pr_err("No PMU available, need this to get the cpu clock\n");
-+      return 0;
-+}
-+EXPORT_SYMBOL(bcma_cpu_clock);
-+
- static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
- {
-       struct bcma_bus *bus = mcore->core->bus;
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -241,8 +241,47 @@
- #define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
- #define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
-+/* Divider allocation in 4716/47162/5356 */
-+#define BCMA_CC_PMU5_MAINPLL_CPU      1
-+#define BCMA_CC_PMU5_MAINPLL_MEM      2
-+#define BCMA_CC_PMU5_MAINPLL_SSB      3
-+
-+/* PLL usage in 4716/47162 */
-+#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
-+
-+/* PLL usage in 5356/5357 */
-+#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
-+#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
-+
-+/* 4706 PMU */
-+#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
-+
- /* ALP clock on pre-PMU chips */
- #define BCMA_CC_PMU_ALP_CLOCK         20000000
-+/* HT clock for systems with PMU-enabled chipcommon */
-+#define BCMA_CC_PMU_HT_CLOCK          80000000
-+
-+/* PMU rev 5 (& 6) */
-+#define BCMA_CC_PPL_P1P2_OFF          0
-+#define BCMA_CC_PPL_P1_MASK           0x0f000000
-+#define BCMA_CC_PPL_P1_SHIFT          24
-+#define BCMA_CC_PPL_P2_MASK           0x00f00000
-+#define BCMA_CC_PPL_P2_SHIFT          20
-+#define BCMA_CC_PPL_M14_OFF           1
-+#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
-+#define BCMA_CC_PPL_MDIV_WIDTH                8
-+#define BCMA_CC_PPL_NM5_OFF           2
-+#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
-+#define BCMA_CC_PPL_NDIV_SHIFT                20
-+#define BCMA_CC_PPL_FMAB_OFF          3
-+#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
-+#define BCMA_CC_PPL_MRAT_SHIFT                28
-+#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
-+#define BCMA_CC_PPL_ABRAT_SHIFT               27
-+#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
-+#define BCMA_CC_PPL_PLLCTL_OFF                4
-+#define BCMA_CC_PPL_PCHI_OFF          5
-+#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
- /* Data for the PMU, if available.
-  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
---- a/include/linux/bcma/bcma_driver_mips.h
-+++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -44,6 +44,8 @@ extern void bcma_core_mips_init(struct b
- static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
- #endif
-+extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
-+
- extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
- #endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
index 9a4e877..11855b4 100644 (file)
@@ -104,9 +104,9 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  #define BCMA_CC_BCAST_ADDR            0x0050
  #define BCMA_CC_BCAST_DATA            0x0054
  #define BCMA_CC_GPIOPULLUP            0x0058          /* Rev >= 20 only */
-@@ -283,6 +341,12 @@
- #define BCMA_CC_PPL_PCHI_OFF          5
- #define BCMA_CC_PPL_PCHI_MASK         0x0000003f
+@@ -300,6 +358,12 @@
+ #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
+ #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
  
 +#define       BCMA_FLASH2                     0x1c000000      /* Flash Region 2 (region 1 shadowed here) */
 +#define       BCMA_FLASH2_SZ                  0x02000000      /* Size of Flash Region 2 */
@@ -117,7 +117,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  /* Data for the PMU, if available.
   * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
   */
-@@ -292,6 +356,10 @@ struct bcma_chipcommon_pmu {
+@@ -309,6 +373,10 @@ struct bcma_chipcommon_pmu {
  };
  
  #ifdef CONFIG_BCMA_DRIVER_MIPS
@@ -128,7 +128,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  struct bcma_pflash {
        u8 buswidth;
        u32 window;
-@@ -317,7 +385,10 @@ struct bcma_drv_cc {
+@@ -334,7 +402,10 @@ struct bcma_drv_cc {
        u16 fast_pwrup_delay;
        struct bcma_chipcommon_pmu pmu;
  #ifdef CONFIG_BCMA_DRIVER_MIPS
index 14e5a3b..e78f3c4 100644 (file)
@@ -40,7 +40,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -38,6 +38,11 @@ void bcma_chipco_serial_init(struct bcma
+@@ -41,6 +41,11 @@ void bcma_chipco_serial_init(struct bcma
  u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
  u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
  
@@ -629,7 +629,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
                pr_info("found parallel flash.\n");
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -358,6 +358,7 @@ struct bcma_chipcommon_pmu {
+@@ -375,6 +375,7 @@ struct bcma_chipcommon_pmu {
  #ifdef CONFIG_BCMA_DRIVER_MIPS
  enum bcma_flash_type {
        BCMA_PFLASH,
@@ -637,7 +637,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  };
  
  struct bcma_pflash {
-@@ -366,6 +367,14 @@ struct bcma_pflash {
+@@ -383,6 +384,14 @@ struct bcma_pflash {
        u32 window_size;
  };
  
@@ -652,7 +652,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  struct bcma_serial_port {
        void *regs;
        unsigned long clockspeed;
-@@ -388,6 +397,9 @@ struct bcma_drv_cc {
+@@ -405,6 +414,9 @@ struct bcma_drv_cc {
        enum bcma_flash_type flash_type;
        union {
                struct bcma_pflash pflash;
@@ -662,9 +662,9 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
        };
  
        int nr_serial_ports;
-@@ -431,4 +443,16 @@ u32 bcma_chipco_gpio_polarity(struct bcm
- /* PMU support */
extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+@@ -459,4 +471,16 @@ extern void bcma_chipco_chipctl_maskset(
+ extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
                                     u32 offset, u32 mask, u32 set);
  
 +#ifdef CONFIG_BCMA_SFLASH
 +/* Chipcommon sflash support. */
index d83ad53..fee1d0a 100644 (file)
@@ -19,7 +19,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
  
  #define SPOFF(offset) ((offset) / sizeof(u16))
  
-@@ -144,8 +145,10 @@ int bcma_sprom_get(struct bcma_bus *bus)
+@@ -214,8 +215,10 @@ int bcma_sprom_get(struct bcma_bus *bus)
        if (!bus->drv_cc.core)
                return -EOPNOTSUPP;
  
index 6055e0a..61f0a7e 100644 (file)
@@ -31,7 +31,7 @@
        }
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -1104,6 +1104,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+@@ -1105,6 +1105,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
  
        if (bus->chip_id == 0x5365) {
                rate = 100000000;
diff --git a/target/linux/brcm47xx/patches-3.0/230-ssb_pci_sprom.patch b/target/linux/brcm47xx/patches-3.0/230-ssb_pci_sprom.patch
deleted file mode 100644 (file)
index 30f133b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
---- a/drivers/ssb/driver_pcicore.c
-+++ b/drivers/ssb/driver_pcicore.c
-@@ -516,10 +516,14 @@ static void ssb_pcicore_pcie_setup_worka
- static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
- {
--      ssb_pcicore_fix_sprom_core_index(pc);
-+      struct ssb_device *pdev = pc->dev;
-+      struct ssb_bus *bus = pdev->bus;
-+
-+      if (bus->bustype == SSB_BUSTYPE_PCI)
-+              ssb_pcicore_fix_sprom_core_index(pc);
-       /* Disable PCI interrupts. */
--      ssb_write32(pc->dev, SSB_INTVEC, 0);
-+      ssb_write32(pdev, SSB_INTVEC, 0);
-       /* Additional PCIe always once-executed workarounds */
-       if (pc->dev->id.coreid == SSB_DEV_PCIE) {
index 25cd469..18685af 100644 (file)
@@ -25,7 +25,7 @@
                ssb_printk(KERN_ERR PFX
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -157,9 +157,16 @@ struct ssb_bus_ops {
+@@ -166,9 +166,16 @@ struct ssb_bus_ops {
  #define SSB_DEV_MINI_MACPHY   0x823
  #define SSB_DEV_ARM_1176      0x824
  #define SSB_DEV_ARM_7TDMI     0x825
@@ -60,7 +60,7 @@
  
  /* Enumeration space constants */
  #define SSB_CORE_SIZE         0x1000  /* Size of a core MMIO area */
-@@ -499,5 +501,41 @@ enum {
+@@ -556,5 +558,41 @@ enum {
  #define SSB_ADM_BASE2                 0xFFFF0000      /* Type2 base address for the core */
  #define SSB_ADM_BASE2_SHIFT           16
  
index f9c994a..a95db6e 100644 (file)
@@ -71,7 +71,7 @@
  obj-y                         += platform/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warning("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warning("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index 3b54067..71f5b74 100644 (file)
  ssb-y                                 += driver_chipcommon.o
 --- a/drivers/ssb/b43_pci_bridge.c
 +++ b/drivers/ssb/b43_pci_bridge.c
-@@ -24,6 +24,7 @@ static const struct pci_device_id b43_pc
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+@@ -24,6 +25,7 @@ static const struct pci_device_id b43_pc
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
  {
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -28,6 +28,21 @@ static void ssb_chipco_pll_write(struct
        chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
  }
 +EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -12,6 +12,7 @@
  #include <linux/ssb/ssb_driver_gige.h>
  #include <linux/pci.h>
        u32 base, tmslow, tmshigh;
 --- a/drivers/ssb/driver_mipscore.c
 +++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = {
  
  static inline u32 ssb_irqflag(struct ssb_device *dev)
        ssb_mips_flash_detect(mcore);
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -432,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
+@@ -432,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -475,58 +559,104 @@ static void ssb_pcie_write(struct ssb_pc
+@@ -475,58 +563,104 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -551,13 +681,13 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -551,13 +685,13 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        might_sleep_if(pdev->id.coreid != SSB_DEV_PCI);
  
        /* Enable interrupts for this device. */
                err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
                if (err)
                        goto out;
-@@ -579,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -579,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
  out:
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -17,6 +17,8 @@
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,11 +12,14 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
  #include <linux/ssb/ssb_driver_gige.h>
  #include <linux/dma-mapping.h>
  #include <linux/pci.h>
  
  #include <pcmcia/cs_types.h>
  #include <pcmcia/cs.h>
-@@ -88,6 +90,25 @@ found:
+@@ -88,6 +91,25 @@ found:
  }
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  int ssb_for_each_bus_call(unsigned long data,
                          int (*func)(struct ssb_bus *bus, unsigned long data))
  {
-@@ -120,6 +141,19 @@ static void ssb_device_put(struct ssb_de
+@@ -120,6 +142,19 @@ static void ssb_device_put(struct ssb_de
                put_device(dev->dev);
  }
  
  static int ssb_device_resume(struct device *dev)
  {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
-@@ -190,90 +224,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
+@@ -190,90 +225,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
  EXPORT_SYMBOL(ssb_bus_suspend);
  
  #ifdef CONFIG_SSB_SPROM
  }
  #endif /* CONFIG_SSB_SPROM */
  
-@@ -360,6 +385,35 @@ static int ssb_device_uevent(struct devi
+@@ -360,6 +386,35 @@ static int ssb_device_uevent(struct devi
                             ssb_dev->id.revision);
  }
  
  static struct bus_type ssb_bustype = {
        .name           = "ssb",
        .match          = ssb_bus_match,
-@@ -369,6 +423,7 @@ static struct bus_type ssb_bustype = {
+@@ -369,6 +424,7 @@ static struct bus_type ssb_bustype = {
        .suspend        = ssb_device_suspend,
        .resume         = ssb_device_resume,
        .uevent         = ssb_device_uevent,
  };
  
  static void ssb_buses_lock(void)
-@@ -461,6 +516,7 @@ static int ssb_devices_register(struct s
+@@ -461,6 +517,7 @@ static int ssb_devices_register(struct s
  #ifdef CONFIG_SSB_PCIHOST
                        sdev->irq = bus->host_pci->irq;
                        dev->parent = &bus->host_pci->dev;
  #endif
                        break;
                case SSB_BUSTYPE_PCMCIA:
-@@ -469,8 +525,14 @@ static int ssb_devices_register(struct s
+@@ -469,8 +526,14 @@ static int ssb_devices_register(struct s
                        dev->parent = &bus->host_pcmcia->dev;
  #endif
                        break;
                        break;
                }
  
-@@ -497,7 +559,7 @@ error:
+@@ -497,7 +560,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -708,9 +770,9 @@ out:
+@@ -708,9 +771,9 @@ out:
        return err;
  }
  
  {
        int err;
  
-@@ -724,12 +786,18 @@ static int ssb_bus_register(struct ssb_b
+@@ -724,12 +787,18 @@ static int ssb_bus_register(struct ssb_b
        err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
        if (err)
                goto out;
  
        /* Init PCI-host device (if any) */
        err = ssb_pci_init(bus);
-@@ -776,6 +844,8 @@ err_pci_exit:
+@@ -776,6 +845,8 @@ err_pci_exit:
        ssb_pci_exit(bus);
  err_unmap:
        ssb_iounmap(bus);
  err_disable_xtal:
        ssb_buses_unlock();
        ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
-@@ -783,8 +853,8 @@ err_disable_xtal:
+@@ -783,8 +854,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
  {
        int err;
  
-@@ -796,6 +866,9 @@ int ssb_bus_pcibus_register(struct ssb_b
+@@ -796,6 +867,9 @@ int ssb_bus_pcibus_register(struct ssb_b
        if (!err) {
                ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
                           "PCI device %s\n", dev_name(&host_pci->dev));
        }
  
        return err;
-@@ -804,9 +877,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -804,9 +878,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -825,9 +898,32 @@ int ssb_bus_pcmciabus_register(struct ss
+@@ -825,9 +899,32 @@ int ssb_bus_pcmciabus_register(struct ss
  EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -908,8 +1004,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -908,8 +1005,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1024,23 +1120,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1024,23 +1121,22 @@ static u32 ssb_tmslow_reject_bitmask(str
  {
        u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
  
  }
  
  int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1099,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
+@@ -1099,10 +1195,10 @@ void ssb_device_enable(struct ssb_device
  }
  EXPORT_SYMBOL(ssb_device_enable);
  
  {
        int i;
        u32 val;
-@@ -1110,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1110,7 +1206,7 @@ static int ssb_wait_bit(struct ssb_devic
        for (i = 0; i < timeout; i++) {
                val = ssb_read32(dev, reg);
                if (set) {
                                return 0;
                } else {
                        if (!(val & bitmask))
-@@ -1127,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1127,20 +1223,38 @@ static int ssb_wait_bit(struct ssb_devic
  
  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
  {
  
        ssb_write32(dev, SSB_TMSLOW,
                    reject | SSB_TMSLOW_RESET |
-@@ -1155,7 +1268,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1149,13 +1263,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (dev->bus->host_pci->is_pcie &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
-@@ -1272,20 +1388,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1272,20 +1407,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
  
  int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
  {
        return 0;
  error:
        ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1293,6 +1409,37 @@ error:
+@@ -1293,6 +1428,37 @@ error:
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
  
  u32 ssb_admatch_base(u32 adm)
  {
        u32 base = 0;
-@@ -1358,8 +1505,10 @@ static int __init ssb_modinit(void)
+@@ -1358,8 +1524,10 @@ static int __init ssb_modinit(void)
        ssb_buses_lock();
        err = ssb_attach_queued_buses();
        ssb_buses_unlock();
  
        err = b43_pci_ssb_bridge_init();
        if (err) {
-@@ -1375,7 +1524,7 @@ static int __init ssb_modinit(void)
+@@ -1375,7 +1543,7 @@ static int __init ssb_modinit(void)
                /* don't fail SSB init because of this */
                err = 0;
        }
  /* ssb must be initialized after PCI but before the ssb drivers.
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,6 +17,7 @@
  
  #include <linux/ssb/ssb.h>
  
        /* Extract the antenna gain values. */
        SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01,
-@@ -509,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+@@ -509,6 +607,31 @@ static void sprom_extract_r8(struct ssb_
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
  
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
 +      sprom_extract_r458(out, in);
 +
        /* TODO - get remaining rev 8 stuff needed */
  }
  
-@@ -521,36 +621,34 @@ static int sprom_extract(struct ssb_bus
+@@ -521,36 +644,34 @@ static int sprom_extract(struct ssb_bus
        ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
        memset(out->et1mac, 0xFF, 6);
        }
  
        if (out->boardflags_lo == 0xFFFF)
-@@ -564,13 +662,34 @@ static int sprom_extract(struct ssb_bus
+@@ -564,13 +685,34 @@ static int sprom_extract(struct ssb_bus
  static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
  {
        bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
        sprom_do_read(bus, buf);
        err = sprom_check_crc(buf, bus->sprom_size);
-@@ -580,17 +699,24 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -580,17 +722,24 @@ static int ssb_pci_sprom_get(struct ssb_
                buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                              GFP_KERNEL);
                if (!buf)
                                err = 0;
                                goto out_free;
                        }
-@@ -602,19 +728,15 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -602,19 +751,15 @@ static int ssb_pci_sprom_get(struct ssb_
  
  out_free:
        kfree(buf);
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
-@@ -12,6 +12,7 @@
+@@ -6,12 +6,13 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
   */
  
  #include <linux/pci.h>
        driver->remove = ssb_pcihost_remove;
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -583,7 +583,7 @@ static int ssb_pcmcia_sprom_write_all(st
                        ssb_printk(".");
                err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
 +static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
 +                      tuple_t *tuple,
 +                      void *priv)
- {
--      tuple_t tuple;
--      int res;
--      unsigned char buf[32];
++{
 +      struct ssb_sprom *sprom = priv;
 +
 +      if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
 +static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
 +                                      tuple_t *tuple,
 +                                      void *priv)
-+{
+ {
+-      tuple_t tuple;
+-      int res;
+-      unsigned char buf[32];
 +      struct ssb_init_invariants *iv = priv;
        struct ssb_sprom *sprom = &iv->sprom;
        struct ssb_boardinfo *bi = &iv->boardinfo;
  
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -162,6 +162,8 @@ static u8 chipid_to_nrcores(u16 chipid)
  static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
                       u16 offset)
 + *
 + * Based on drivers/ssb/pcmcia.c
 + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
-+ * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + *
 +}
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -13,8 +13,11 @@
  
  #include "ssb_private.h"
  
  /**
 - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
-+ * ssb_arch_register_fallback_sprom - Registers a method providing a
-+ * fallback SPROM if no SPROM is found.
-  *
+- *
 - * @sprom: The SPROM data structure to register.
-+ * @sprom_callback: The callback function.
-  *
+- *
 - * With this function the architecture implementation may register a fallback
 - * SPROM data structure. The fallback is only used for PCI based SSB devices,
 - * where no valid SPROM can be found in the shadow registers.
-+ * With this function the architecture implementation may register a
-+ * callback handler which fills the SPROM data structure. The fallback is
-+ * only used for PCI based SSB devices, where no valid SPROM can be found
-+ * in the shadow registers.
++ * ssb_arch_register_fallback_sprom - Registers a method providing a
++ * fallback SPROM if no SPROM is found.
   *
 - * This function is useful for weird architectures that have a half-assed SSB device
 - * hardwired to their PCI bus.
-+ * This function is useful for weird architectures that have a half-assed
-+ * SSB device hardwired to their PCI bus.
++ * @sprom_callback: The callback function.
   *
 - * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
 - * don't use this fallback.
 - * Architectures must provide the SPROM for native SSB devices anyway,
 - * so the fallback also isn't used for native devices.
++ * With this function the architecture implementation may register a
++ * callback handler which fills the SPROM data structure. The fallback is
++ * only used for PCI based SSB devices, where no valid SPROM can be found
++ * in the shadow registers.
++ *
++ * This function is useful for weird architectures that have a half-assed
++ * SSB device hardwired to their PCI bus.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
  #define PCI_DEVICE_ID_TIGON3_5752M    0x1601
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,24 +27,60 @@ struct ssb_sprom {
+@@ -25,26 +25,62 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 -      u8 ant_available_a;     /* A-PHY antenna available bits (up to 4) */
 -      u8 ant_available_bg;    /* B/G-PHY antenna available bits (up to 4) */
  
        /* Antenna gain values for up to 4 antennas
         * on each band. Values in dBm/4 (Q5.2). Negative gain means the
-@@ -58,14 +94,14 @@ struct ssb_sprom {
+@@ -58,14 +94,23 @@ struct ssb_sprom {
                } ghz5;         /* 5GHz band */
        } antenna_gain;
  
 -      /* TODO - add any parameters needed from rev 2, 3, or 4 SPROMs */
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
 +      /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
  };
  
  };
  
  
-@@ -137,7 +173,7 @@ struct ssb_device {
+@@ -137,7 +182,7 @@ struct ssb_device {
         * is an optimization. */
        const struct ssb_bus_ops *ops;
  
  
        struct ssb_bus *bus;
        struct ssb_device_id id;
-@@ -208,6 +244,7 @@ enum ssb_bustype {
+@@ -195,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -208,6 +252,7 @@ enum ssb_bustype {
        SSB_BUSTYPE_SSB,        /* This SSB bus is the system bus */
        SSB_BUSTYPE_PCI,        /* SSB is connected to PCI bus */
        SSB_BUSTYPE_PCMCIA,     /* SSB is connected to PCMCIA bus */
  };
  
  /* board_vendor */
-@@ -238,20 +275,33 @@ struct ssb_bus {
+@@ -238,20 +283,33 @@ struct ssb_bus {
  
        const struct ssb_bus_ops *ops;
  
  
  #ifdef CONFIG_SSB_SPROM
        /* Mutex to protect the SPROM writing. */
-@@ -260,7 +310,8 @@ struct ssb_bus {
+@@ -260,7 +318,8 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
  
-@@ -306,6 +357,11 @@ struct ssb_bus {
+@@ -306,6 +365,11 @@ struct ssb_bus {
  #endif /* DEBUG */
  };
  
  /* The initialization-invariants. */
  struct ssb_init_invariants {
        /* Versioning information about the PCB. */
-@@ -336,12 +392,23 @@ extern int ssb_bus_pcmciabus_register(st
+@@ -336,12 +400,23 @@ extern int ssb_bus_pcmciabus_register(st
                                      struct pcmcia_device *pcmcia_dev,
                                      unsigned long baseaddr);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -612,6 +679,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -612,6 +687,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
  extern u32 ssb_admatch_base(u32 adm);
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -53,6 +53,7 @@
  #define  SSB_CHIPCO_CAP_64BIT         0x08000000      /* 64-bit Backplane */
  #define  SSB_CHIPCO_CAP_PMU           0x10000000      /* PMU available (rev >= 20) */
  #define  SSB_SPROM3_CCKPO_1M          0x000F  /* 1M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M          0x00F0  /* 2M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M_SHIFT    4
-@@ -264,104 +267,200 @@
+@@ -264,104 +267,257 @@
  #define  SSB_SPROM3_OFDMGPO           0x107A  /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
  
  /* SPROM Revision 4 */
 +#define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
 +#define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
 +#define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
 +#define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
 +#define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
  #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
 +#define SSB_SPROM8_OFDM5GPO           0x0146  /* 5.3GHz OFDM power offset */
 +#define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
 +#define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
  
  /* Values for SSB_SPROM1_BINF_CCODE */
  enum {
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
index 7203de3..f713e2b 100644 (file)
@@ -71,7 +71,7 @@
  obj-$(CONFIG_STAGING)         += staging/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warning("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warning("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index 2372435..e86ec9b 100644 (file)
  ssb-y                                 += driver_chipcommon.o
 --- a/drivers/ssb/b43_pci_bridge.c
 +++ b/drivers/ssb/b43_pci_bridge.c
-@@ -24,6 +24,7 @@ static const struct pci_device_id b43_pc
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+@@ -24,6 +25,7 @@ static const struct pci_device_id b43_pc
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4315) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
  {
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -28,6 +28,21 @@ static void ssb_chipco_pll_write(struct
        chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
  }
 +EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -12,6 +12,7 @@
  #include <linux/ssb/ssb_driver_gige.h>
  #include <linux/pci.h>
        u32 base, tmslow, tmshigh;
 --- a/drivers/ssb/driver_mipscore.c
 +++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -270,7 +270,6 @@ void ssb_mipscore_init(struct ssb_mipsco
                                set_irq(dev, irq++);
                        }
        ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -432,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
+@@ -432,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -475,58 +559,104 @@ static void ssb_pcie_write(struct ssb_pc
+@@ -475,58 +563,104 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -551,13 +681,13 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -551,13 +685,13 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        might_sleep_if(pdev->id.coreid != SSB_DEV_PCI);
  
        /* Enable interrupts for this device. */
                err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
                if (err)
                        goto out;
-@@ -579,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -579,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
  out:
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -17,6 +17,8 @@
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,11 +12,14 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
  #include <linux/ssb/ssb_driver_gige.h>
  #include <linux/dma-mapping.h>
  #include <linux/pci.h>
  
  #include <pcmcia/cs_types.h>
  #include <pcmcia/cs.h>
-@@ -88,6 +90,25 @@ found:
+@@ -88,6 +91,25 @@ found:
  }
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  int ssb_for_each_bus_call(unsigned long data,
                          int (*func)(struct ssb_bus *bus, unsigned long data))
  {
-@@ -120,6 +141,19 @@ static void ssb_device_put(struct ssb_de
+@@ -120,6 +142,19 @@ static void ssb_device_put(struct ssb_de
                put_device(dev->dev);
  }
  
  static int ssb_device_resume(struct device *dev)
  {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
-@@ -190,90 +224,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
+@@ -190,90 +225,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
  EXPORT_SYMBOL(ssb_bus_suspend);
  
  #ifdef CONFIG_SSB_SPROM
  }
  #endif /* CONFIG_SSB_SPROM */
  
-@@ -360,6 +385,35 @@ static int ssb_device_uevent(struct devi
+@@ -360,6 +386,35 @@ static int ssb_device_uevent(struct devi
                             ssb_dev->id.revision);
  }
  
  static struct bus_type ssb_bustype = {
        .name           = "ssb",
        .match          = ssb_bus_match,
-@@ -369,6 +423,7 @@ static struct bus_type ssb_bustype = {
+@@ -369,6 +424,7 @@ static struct bus_type ssb_bustype = {
        .suspend        = ssb_device_suspend,
        .resume         = ssb_device_resume,
        .uevent         = ssb_device_uevent,
  };
  
  static void ssb_buses_lock(void)
-@@ -461,6 +516,7 @@ static int ssb_devices_register(struct s
+@@ -461,6 +517,7 @@ static int ssb_devices_register(struct s
  #ifdef CONFIG_SSB_PCIHOST
                        sdev->irq = bus->host_pci->irq;
                        dev->parent = &bus->host_pci->dev;
  #endif
                        break;
                case SSB_BUSTYPE_PCMCIA:
-@@ -469,8 +525,14 @@ static int ssb_devices_register(struct s
+@@ -469,8 +526,14 @@ static int ssb_devices_register(struct s
                        dev->parent = &bus->host_pcmcia->dev;
  #endif
                        break;
                        break;
                }
  
-@@ -497,7 +559,7 @@ error:
+@@ -497,7 +560,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -708,9 +770,9 @@ out:
+@@ -708,9 +771,9 @@ out:
        return err;
  }
  
  {
        int err;
  
-@@ -724,12 +786,18 @@ static int ssb_bus_register(struct ssb_b
+@@ -724,12 +787,18 @@ static int ssb_bus_register(struct ssb_b
        err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
        if (err)
                goto out;
  
        /* Init PCI-host device (if any) */
        err = ssb_pci_init(bus);
-@@ -776,6 +844,8 @@ err_pci_exit:
+@@ -776,6 +845,8 @@ err_pci_exit:
        ssb_pci_exit(bus);
  err_unmap:
        ssb_iounmap(bus);
  err_disable_xtal:
        ssb_buses_unlock();
        ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
-@@ -783,8 +853,8 @@ err_disable_xtal:
+@@ -783,8 +854,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
  {
        int err;
  
-@@ -796,6 +866,9 @@ int ssb_bus_pcibus_register(struct ssb_b
+@@ -796,6 +867,9 @@ int ssb_bus_pcibus_register(struct ssb_b
        if (!err) {
                ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
                           "PCI device %s\n", dev_name(&host_pci->dev));
        }
  
        return err;
-@@ -804,9 +877,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -804,9 +878,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -825,9 +898,32 @@ int ssb_bus_pcmciabus_register(struct ss
+@@ -825,9 +899,32 @@ int ssb_bus_pcmciabus_register(struct ss
  EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -908,8 +1004,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -908,8 +1005,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1024,23 +1120,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1024,23 +1121,22 @@ static u32 ssb_tmslow_reject_bitmask(str
  {
        u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
  
  }
  
  int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1099,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
+@@ -1099,10 +1195,10 @@ void ssb_device_enable(struct ssb_device
  }
  EXPORT_SYMBOL(ssb_device_enable);
  
  {
        int i;
        u32 val;
-@@ -1110,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1110,7 +1206,7 @@ static int ssb_wait_bit(struct ssb_devic
        for (i = 0; i < timeout; i++) {
                val = ssb_read32(dev, reg);
                if (set) {
                                return 0;
                } else {
                        if (!(val & bitmask))
-@@ -1127,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1127,20 +1223,38 @@ static int ssb_wait_bit(struct ssb_devic
  
  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
  {
  
        ssb_write32(dev, SSB_TMSLOW,
                    reject | SSB_TMSLOW_RESET |
-@@ -1155,7 +1268,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1149,13 +1263,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (dev->bus->host_pci->is_pcie &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
-@@ -1272,20 +1388,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1272,20 +1407,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
  
  int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
  {
        return 0;
  error:
        ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1293,6 +1409,37 @@ error:
+@@ -1293,6 +1428,37 @@ error:
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
  
  u32 ssb_admatch_base(u32 adm)
  {
        u32 base = 0;
-@@ -1358,8 +1505,10 @@ static int __init ssb_modinit(void)
+@@ -1358,8 +1524,10 @@ static int __init ssb_modinit(void)
        ssb_buses_lock();
        err = ssb_attach_queued_buses();
        ssb_buses_unlock();
  
        err = b43_pci_ssb_bridge_init();
        if (err) {
-@@ -1375,7 +1524,7 @@ static int __init ssb_modinit(void)
+@@ -1375,7 +1543,7 @@ static int __init ssb_modinit(void)
                /* don't fail SSB init because of this */
                err = 0;
        }
  /* ssb must be initialized after PCI but before the ssb drivers.
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,6 +17,7 @@
  
  #include <linux/ssb/ssb.h>
  
        /* Extract the antenna gain values. */
        SPEX(antenna_gain.ghz24.a0, SSB_SPROM8_AGAIN01,
-@@ -509,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+@@ -509,6 +607,31 @@ static void sprom_extract_r8(struct ssb_
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
  
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
 +      sprom_extract_r458(out, in);
 +
        /* TODO - get remaining rev 8 stuff needed */
  }
  
-@@ -521,36 +621,34 @@ static int sprom_extract(struct ssb_bus
+@@ -521,36 +644,34 @@ static int sprom_extract(struct ssb_bus
        ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
        memset(out->et1mac, 0xFF, 6);
        }
  
        if (out->boardflags_lo == 0xFFFF)
-@@ -564,13 +662,34 @@ static int sprom_extract(struct ssb_bus
+@@ -564,13 +685,34 @@ static int sprom_extract(struct ssb_bus
  static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
  {
        bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
        sprom_do_read(bus, buf);
        err = sprom_check_crc(buf, bus->sprom_size);
-@@ -580,17 +699,24 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -580,17 +722,24 @@ static int ssb_pci_sprom_get(struct ssb_
                buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                              GFP_KERNEL);
                if (!buf)
                                err = 0;
                                goto out_free;
                        }
-@@ -602,19 +728,15 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -602,19 +751,15 @@ static int ssb_pci_sprom_get(struct ssb_
  
  out_free:
        kfree(buf);
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
-@@ -12,6 +12,7 @@
+@@ -6,12 +6,13 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
   */
  
  #include <linux/pci.h>
        driver->remove = ssb_pcihost_remove;
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(co
        }                                               \
    } while (0)
 +static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
 +                      tuple_t *tuple,
 +                      void *priv)
- {
--      tuple_t tuple;
--      int res;
--      unsigned char buf[32];
++{
 +      struct ssb_sprom *sprom = priv;
 +
 +      if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
 +static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
 +                                      tuple_t *tuple,
 +                                      void *priv)
-+{
+ {
+-      tuple_t tuple;
+-      int res;
+-      unsigned char buf[32];
 +      struct ssb_init_invariants *iv = priv;
        struct ssb_sprom *sprom = &iv->sprom;
        struct ssb_boardinfo *bi = &iv->boardinfo;
  
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -162,6 +162,8 @@ static u8 chipid_to_nrcores(u16 chipid)
  static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
                       u16 offset)
 + *
 + * Based on drivers/ssb/pcmcia.c
 + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
-+ * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + *
 +}
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -14,9 +14,10 @@
  #include "ssb_private.h"
  
  
  /**
 - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
+- *
+- * @sprom: The SPROM data structure to register.
 + * ssb_arch_register_fallback_sprom - Registers a method providing a
 + * fallback SPROM if no SPROM is found.
   *
-- * @sprom: The SPROM data structure to register.
-+ * @sprom_callback: The callback function.
-  *
 - * With this function the architecture implementation may register a fallback
 - * SPROM data structure. The fallback is only used for PCI based SSB devices,
 - * where no valid SPROM can be found in the shadow registers.
++ * @sprom_callback: The callback function.
+  *
+- * This function is useful for weird architectures that have a half-assed SSB device
+- * hardwired to their PCI bus.
 + * With this function the architecture implementation may register a
 + * callback handler which fills the SPROM data structure. The fallback is
 + * only used for PCI based SSB devices, where no valid SPROM can be found
 + * in the shadow registers.
-  *
-- * This function is useful for weird architectures that have a half-assed SSB device
-- * hardwired to their PCI bus.
++ *
 + * This function is useful for weird architectures that have a half-assed
 + * SSB device hardwired to their PCI bus.
-  *
-- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
-- * don't use this fallback.
-- * Architectures must provide the SPROM for native SSB devices anyway,
-- * so the fallback also isn't used for native devices.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
 + * the fallback also isn't used for native devices.
   *
+- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+- * don't use this fallback.
+- * Architectures must provide the SPROM for native SSB devices anyway,
+- * so the fallback also isn't used for native devices.
+- *
 - * This function is available for architecture code, only. So it is not exported.
 + * This function is available for architecture code, only. So it is not
 + * exported.
  #define PCI_DEVICE_ID_TIGON3_5752M    0x1601
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,24 +27,60 @@ struct ssb_sprom {
+@@ -25,26 +25,62 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 -      u8 ant_available_a;     /* A-PHY antenna available bits (up to 4) */
 -      u8 ant_available_bg;    /* B/G-PHY antenna available bits (up to 4) */
  
        /* Antenna gain values for up to 4 antennas
         * on each band. Values in dBm/4 (Q5.2). Negative gain means the
-@@ -58,14 +94,14 @@ struct ssb_sprom {
+@@ -58,14 +94,23 @@ struct ssb_sprom {
                } ghz5;         /* 5GHz band */
        } antenna_gain;
  
 -      /* TODO - add any parameters needed from rev 2, 3, or 4 SPROMs */
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
 +      /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
  };
  
  };
  
  
-@@ -137,7 +173,7 @@ struct ssb_device {
+@@ -137,7 +182,7 @@ struct ssb_device {
         * is an optimization. */
        const struct ssb_bus_ops *ops;
  
  
        struct ssb_bus *bus;
        struct ssb_device_id id;
-@@ -208,6 +244,7 @@ enum ssb_bustype {
+@@ -195,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -208,6 +252,7 @@ enum ssb_bustype {
        SSB_BUSTYPE_SSB,        /* This SSB bus is the system bus */
        SSB_BUSTYPE_PCI,        /* SSB is connected to PCI bus */
        SSB_BUSTYPE_PCMCIA,     /* SSB is connected to PCMCIA bus */
  };
  
  /* board_vendor */
-@@ -238,20 +275,33 @@ struct ssb_bus {
+@@ -238,20 +283,33 @@ struct ssb_bus {
  
        const struct ssb_bus_ops *ops;
  
  
  #ifdef CONFIG_SSB_SPROM
        /* Mutex to protect the SPROM writing. */
-@@ -260,7 +310,8 @@ struct ssb_bus {
+@@ -260,7 +318,8 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
  
-@@ -306,6 +357,11 @@ struct ssb_bus {
+@@ -306,6 +365,11 @@ struct ssb_bus {
  #endif /* DEBUG */
  };
  
  /* The initialization-invariants. */
  struct ssb_init_invariants {
        /* Versioning information about the PCB. */
-@@ -336,12 +392,23 @@ extern int ssb_bus_pcmciabus_register(st
+@@ -336,12 +400,23 @@ extern int ssb_bus_pcmciabus_register(st
                                      struct pcmcia_device *pcmcia_dev,
                                      unsigned long baseaddr);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -612,6 +679,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -612,6 +687,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
  extern u32 ssb_admatch_base(u32 adm);
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -53,6 +53,7 @@
  #define  SSB_CHIPCO_CAP_64BIT         0x08000000      /* 64-bit Backplane */
  #define  SSB_CHIPCO_CAP_PMU           0x10000000      /* PMU available (rev >= 20) */
  #define  SSB_SPROM3_CCKPO_1M          0x000F  /* 1M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M          0x00F0  /* 2M Rate PO */
  #define  SSB_SPROM3_CCKPO_2M_SHIFT    4
-@@ -264,104 +267,200 @@
+@@ -264,104 +267,257 @@
  #define  SSB_SPROM3_OFDMGPO           0x107A  /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
  
  /* SPROM Revision 4 */
 +#define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
 +#define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
 +#define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
 +#define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
 +#define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
  #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
 +#define SSB_SPROM8_OFDM5GPO           0x0146  /* 5.3GHz OFDM power offset */
 +#define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
 +#define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
  
  /* Values for SSB_SPROM1_BINF_CCODE */
  enum {
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
index 4d73540..3571bd1 100644 (file)
@@ -71,7 +71,7 @@
  obj-y                         += platform/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warning("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warning("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index 0dc9baf..a619e6c 100644 (file)
@@ -1,5 +1,14 @@
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
  {
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -332,6 +332,12 @@ static void ssb_pmu_pll_init(struct ssb_
        case 0x5354:
                ssb_pmu0_pllinit_r0(cc, crystalfreq);
  }
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -12,6 +12,7 @@
  #include <linux/ssb/ssb_driver_gige.h>
  #include <linux/pci.h>
        u32 base, tmslow, tmshigh;
 --- a/drivers/ssb/driver_mipscore.c
 +++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -270,7 +270,6 @@ void ssb_mipscore_init(struct ssb_mipsco
                                set_irq(dev, irq++);
                        }
        ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -432,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
+@@ -432,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -475,58 +559,104 @@ static void ssb_pcie_write(struct ssb_pc
+@@ -475,58 +563,104 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -551,13 +681,13 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -551,13 +685,13 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        might_sleep_if(pdev->id.coreid != SSB_DEV_PCI);
  
        /* Enable interrupts for this device. */
                err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
                if (err)
                        goto out;
-@@ -579,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -579,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
  out:
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -18,6 +18,7 @@
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,12 +12,14 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
  #include <linux/dma-mapping.h>
  #include <linux/pci.h>
  #include <linux/mmc/sdio_func.h>
  
  #include <pcmcia/cs_types.h>
  #include <pcmcia/cs.h>
-@@ -140,6 +141,19 @@ static void ssb_device_put(struct ssb_de
+@@ -140,6 +142,19 @@ static void ssb_device_put(struct ssb_de
                put_device(dev->dev);
  }
  
  static int ssb_device_resume(struct device *dev)
  {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
-@@ -210,90 +224,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
+@@ -210,90 +225,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
  EXPORT_SYMBOL(ssb_bus_suspend);
  
  #ifdef CONFIG_SSB_SPROM
 -              if (!dev->dev ||
 -                  !dev->dev->driver ||
 -                  !device_is_registered(dev->dev))
--                      continue;
--              drv = drv_to_ssb_drv(dev->dev->driver);
--              if (!drv)
 +              sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
 +              if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
 +                      ssb_device_put(sdev);
                        continue;
+-              drv = drv_to_ssb_drv(dev->dev->driver);
+-              if (!drv)
+-                      continue;
 -              err = drv->suspend(dev, state);
 -              if (err) {
 -                      ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
  }
  #endif /* CONFIG_SSB_SPROM */
  
-@@ -380,6 +385,35 @@ static int ssb_device_uevent(struct devi
+@@ -380,6 +386,35 @@ static int ssb_device_uevent(struct devi
                             ssb_dev->id.revision);
  }
  
  static struct bus_type ssb_bustype = {
        .name           = "ssb",
        .match          = ssb_bus_match,
-@@ -389,6 +423,7 @@ static struct bus_type ssb_bustype = {
+@@ -389,6 +424,7 @@ static struct bus_type ssb_bustype = {
        .suspend        = ssb_device_suspend,
        .resume         = ssb_device_resume,
        .uevent         = ssb_device_uevent,
  };
  
  static void ssb_buses_lock(void)
-@@ -481,6 +516,7 @@ static int ssb_devices_register(struct s
+@@ -481,6 +517,7 @@ static int ssb_devices_register(struct s
  #ifdef CONFIG_SSB_PCIHOST
                        sdev->irq = bus->host_pci->irq;
                        dev->parent = &bus->host_pci->dev;
  #endif
                        break;
                case SSB_BUSTYPE_PCMCIA:
-@@ -490,13 +526,13 @@ static int ssb_devices_register(struct s
+@@ -490,13 +527,13 @@ static int ssb_devices_register(struct s
  #endif
                        break;
                case SSB_BUSTYPE_SDIO:
                        break;
                }
  
-@@ -523,7 +559,7 @@ error:
+@@ -523,7 +560,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -734,9 +770,9 @@ out:
+@@ -734,9 +771,9 @@ out:
        return err;
  }
  
  {
        int err;
  
-@@ -817,8 +853,8 @@ err_disable_xtal:
+@@ -817,8 +854,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
  {
        int err;
  
-@@ -830,6 +866,9 @@ int ssb_bus_pcibus_register(struct ssb_b
+@@ -830,6 +867,9 @@ int ssb_bus_pcibus_register(struct ssb_b
        if (!err) {
                ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
                           "PCI device %s\n", dev_name(&host_pci->dev));
        }
  
        return err;
-@@ -838,9 +877,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -838,9 +878,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -860,8 +899,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+@@ -860,8 +900,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  #ifdef CONFIG_SSB_SDIOHOST
  {
        int err;
  
-@@ -881,9 +921,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -881,9 +922,9 @@ int ssb_bus_sdiobus_register(struct ssb_
  EXPORT_SYMBOL(ssb_bus_sdiobus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -964,8 +1004,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -964,8 +1005,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1080,23 +1120,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1080,23 +1121,22 @@ static u32 ssb_tmslow_reject_bitmask(str
  {
        u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
  
  }
  
  int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1155,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
+@@ -1155,10 +1195,10 @@ void ssb_device_enable(struct ssb_device
  }
  EXPORT_SYMBOL(ssb_device_enable);
  
  {
        int i;
        u32 val;
-@@ -1166,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1166,7 +1206,7 @@ static int ssb_wait_bit(struct ssb_devic
        for (i = 0; i < timeout; i++) {
                val = ssb_read32(dev, reg);
                if (set) {
                                return 0;
                } else {
                        if (!(val & bitmask))
-@@ -1183,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1183,20 +1223,38 @@ static int ssb_wait_bit(struct ssb_devic
  
  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
  {
  
        ssb_write32(dev, SSB_TMSLOW,
                    reject | SSB_TMSLOW_RESET |
-@@ -1211,7 +1268,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1205,13 +1263,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (dev->bus->host_pci->is_pcie &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
-@@ -1328,20 +1388,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1328,20 +1407,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
  
  int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
  {
        return 0;
  error:
        ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1349,6 +1409,37 @@ error:
+@@ -1349,6 +1428,37 @@ error:
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
  
        u32 base = 0;
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,6 +17,7 @@
  
  #include <linux/ssb/ssb.h>
        /* TODO - get remaining rev 4 stuff needed */
  }
  
-@@ -560,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+@@ -560,6 +607,31 @@ static void sprom_extract_r8(struct ssb_
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
  
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
 +      sprom_extract_r458(out, in);
 +
        /* TODO - get remaining rev 8 stuff needed */
  }
  
-@@ -572,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+@@ -572,37 +644,34 @@ static int sprom_extract(struct ssb_bus
        ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
        memset(out->et1mac, 0xFF, 6);
        }
  
        if (out->boardflags_lo == 0xFFFF)
-@@ -616,15 +662,14 @@ static int sprom_extract(struct ssb_bus
+@@ -616,15 +685,14 @@ static int sprom_extract(struct ssb_bus
  static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
  {
                /*
                 * get SPROM offset: SSB_SPROM_BASE1 except for
                 * chipcommon rev >= 31 or chip ID is 0x4312 and
-@@ -644,7 +689,7 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -644,7 +712,7 @@ static int ssb_pci_sprom_get(struct ssb_
  
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)
        bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
        sprom_do_read(bus, buf);
        err = sprom_check_crc(buf, bus->sprom_size);
-@@ -654,17 +699,24 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -654,17 +722,24 @@ static int ssb_pci_sprom_get(struct ssb_
                buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                              GFP_KERNEL);
                if (!buf)
                                err = 0;
                                goto out_free;
                        }
-@@ -676,19 +728,15 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -676,19 +751,15 @@ static int ssb_pci_sprom_get(struct ssb_
  
  out_free:
        kfree(buf);
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
-@@ -12,6 +12,7 @@
+@@ -6,12 +6,13 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
   */
  
  #include <linux/pci.h>
        driver->remove = ssb_pcihost_remove;
 --- a/drivers/ssb/pcmcia.c
 +++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(co
        }                                               \
    } while (0)
 +static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev,
 +                      tuple_t *tuple,
 +                      void *priv)
- {
--      tuple_t tuple;
--      int res;
--      unsigned char buf[32];
++{
 +      struct ssb_sprom *sprom = priv;
 +
 +      if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID)
 +static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
 +                                      tuple_t *tuple,
 +                                      void *priv)
-+{
+ {
+-      tuple_t tuple;
+-      int res;
+-      unsigned char buf[32];
 +      struct ssb_init_invariants *iv = priv;
        struct ssb_sprom *sprom = &iv->sprom;
        struct ssb_boardinfo *bi = &iv->boardinfo;
  
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -260,7 +260,10 @@ static int we_support_multiple_80211_cor
  #ifdef CONFIG_SSB_PCIHOST
        if (bus->bustype == SSB_BUSTYPE_PCI) {
                }
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -14,9 +14,10 @@
  #include "ssb_private.h"
  
  
  /**
 - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
+- *
+- * @sprom: The SPROM data structure to register.
 + * ssb_arch_register_fallback_sprom - Registers a method providing a
 + * fallback SPROM if no SPROM is found.
   *
-- * @sprom: The SPROM data structure to register.
-+ * @sprom_callback: The callback function.
-  *
 - * With this function the architecture implementation may register a fallback
 - * SPROM data structure. The fallback is only used for PCI based SSB devices,
 - * where no valid SPROM can be found in the shadow registers.
++ * @sprom_callback: The callback function.
+  *
+- * This function is useful for weird architectures that have a half-assed SSB device
+- * hardwired to their PCI bus.
 + * With this function the architecture implementation may register a
 + * callback handler which fills the SPROM data structure. The fallback is
 + * only used for PCI based SSB devices, where no valid SPROM can be found
 + * in the shadow registers.
-  *
-- * This function is useful for weird architectures that have a half-assed SSB device
-- * hardwired to their PCI bus.
++ *
 + * This function is useful for weird architectures that have a half-assed
 + * SSB device hardwired to their PCI bus.
-  *
-- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
-- * don't use this fallback.
-- * Architectures must provide the SPROM for native SSB devices anyway,
-- * so the fallback also isn't used for native devices.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
 + * the fallback also isn't used for native devices.
   *
+- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+- * don't use this fallback.
+- * Architectures must provide the SPROM for native SSB devices anyway,
+- * so the fallback also isn't used for native devices.
+- *
 - * This function is available for architecture code, only. So it is not exported.
 + * This function is available for architecture code, only. So it is not
 + * exported.
  #endif /* LINUX_SSB_PRIVATE_H_ */
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,6 +27,8 @@ struct ssb_sprom {
+@@ -25,8 +25,10 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 +      u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
 +      u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
        u8 rxpo2g;              /* 2GHz RX power offset */
        u8 rxpo5g;              /* 5GHz RX power offset */
        u8 rssisav2g;           /* 2GHz RSSI params */
-@@ -95,7 +101,7 @@ struct ssb_sprom {
+@@ -88,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -95,7 +110,7 @@ struct ssb_sprom {
  struct ssb_boardinfo {
        u16 vendor;
        u16 type;
  };
  
  
-@@ -167,7 +173,7 @@ struct ssb_device {
+@@ -167,7 +182,7 @@ struct ssb_device {
         * is an optimization. */
        const struct ssb_bus_ops *ops;
  
  
        struct ssb_bus *bus;
        struct ssb_device_id id;
-@@ -269,7 +275,8 @@ struct ssb_bus {
+@@ -225,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -269,7 +283,8 @@ struct ssb_bus {
  
        const struct ssb_bus_ops *ops;
  
        struct ssb_device *mapped_device;
        union {
                /* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */
-@@ -281,14 +288,17 @@ struct ssb_bus {
+@@ -281,14 +296,17 @@ struct ssb_bus {
         * On PCMCIA-host busses this is used to protect the whole MMIO access. */
        spinlock_t bar_lock;
  
  
        /* See enum ssb_quirks */
        unsigned int quirks;
-@@ -300,7 +310,7 @@ struct ssb_bus {
+@@ -300,7 +318,7 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
        u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
-@@ -396,7 +406,9 @@ extern bool ssb_is_sprom_available(struc
+@@ -396,7 +414,9 @@ extern bool ssb_is_sprom_available(struc
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -667,6 +679,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -667,6 +687,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
  #define  SSB_SPROM8_RSSISMF5G         0x000F
  #define  SSB_SPROM8_RSSISMC5G         0x00F0
  #define  SSB_SPROM8_RSSISMC5G_SHIFT   4
-@@ -374,47 +420,47 @@
+@@ -374,47 +420,104 @@
  #define  SSB_SPROM8_RSSISAV5G_SHIFT   8
  #define  SSB_SPROM8_BXA5G             0x1800
  #define  SSB_SPROM8_BXA5G_SHIFT               11
  #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
  #define  SSB_SPROM8_RXPO5G_SHIFT      8
 -#define SSB_SPROM8_MAXP_BG            0x10C0  /* Max Power 2GHz in path 1 */
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
 +#define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
  #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
  #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
 +#define SSB_SPROM8_OFDM5GPO           0x0146  /* 5.3GHz OFDM power offset */
 +#define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
 +#define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
  
  /* Values for SSB_SPROM1_BINF_CCODE */
  enum {
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -123,6 +123,8 @@
  #define SSB_CHIPCO_FLASHDATA          0x0048
  #define SSB_CHIPCO_BCAST_ADDR         0x0050
  #define SSB_CHIPCO_HW_WORKAROUND      0x01E4 /* Hardware workaround (rev >= 20) */
  #define SSB_CHIPCO_UART0_DATA         0x0300
  #define SSB_CHIPCO_UART0_IMR          0x0304
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -6,7 +6,7 @@
+  *
+  * Based on drivers/ssb/pcmcia.c
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  *
index 45da134..eb64b85 100644 (file)
@@ -71,7 +71,7 @@
  obj-$(CONFIG_STAGING)         += staging/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warn("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warn("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index f839231..e634a4a 100644 (file)
@@ -1,6 +1,23 @@
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -384,6 +384,35 @@ static int ssb_device_uevent(struct devi
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -384,6 +385,35 @@ static int ssb_device_uevent(struct devi
                             ssb_dev->id.revision);
  }
  
@@ -36,7 +53,7 @@
  static struct bus_type ssb_bustype = {
        .name           = "ssb",
        .match          = ssb_bus_match,
-@@ -393,6 +422,7 @@ static struct bus_type ssb_bustype = {
+@@ -393,6 +423,7 @@ static struct bus_type ssb_bustype = {
        .suspend        = ssb_device_suspend,
        .resume         = ssb_device_resume,
        .uevent         = ssb_device_uevent,
@@ -44,7 +61,7 @@
  };
  
  static void ssb_buses_lock(void)
-@@ -528,7 +558,7 @@ error:
+@@ -528,7 +559,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
@@ -53,7 +70,7 @@
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -739,9 +769,9 @@ out:
+@@ -739,9 +770,9 @@ out:
        return err;
  }
  
@@ -66,7 +83,7 @@
  {
        int err;
  
-@@ -822,8 +852,8 @@ err_disable_xtal:
+@@ -822,8 +853,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
@@ -77,7 +94,7 @@
  {
        int err;
  
-@@ -846,9 +876,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -846,9 +877,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -868,8 +898,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+@@ -868,8 +899,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  #ifdef CONFIG_SSB_SDIOHOST
  {
        int err;
  
-@@ -889,9 +920,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -889,9 +921,9 @@ int ssb_bus_sdiobus_register(struct ssb_
  EXPORT_SYMBOL(ssb_bus_sdiobus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -972,8 +1003,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -972,8 +1004,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1088,23 +1119,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1088,23 +1120,22 @@ static u32 ssb_tmslow_reject_bitmask(str
  {
        u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
  
  }
  
  int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1163,10 +1193,10 @@ void ssb_device_enable(struct ssb_device
+@@ -1163,10 +1194,10 @@ void ssb_device_enable(struct ssb_device
  }
  EXPORT_SYMBOL(ssb_device_enable);
  
  {
        int i;
        u32 val;
-@@ -1174,7 +1204,7 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1174,7 +1205,7 @@ static int ssb_wait_bit(struct ssb_devic
        for (i = 0; i < timeout; i++) {
                val = ssb_read32(dev, reg);
                if (set) {
                                return 0;
                } else {
                        if (!(val & bitmask))
-@@ -1191,20 +1221,38 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1191,20 +1222,38 @@ static int ssb_wait_bit(struct ssb_devic
  
  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
  {
  
        ssb_write32(dev, SSB_TMSLOW,
                    reject | SSB_TMSLOW_RESET |
-@@ -1219,7 +1267,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1213,13 +1262,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (pci_is_pcie(dev->bus->host_pci) &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
-@@ -1262,20 +1313,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1262,20 +1332,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
  
  int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
  {
        return 0;
  error:
        ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1283,6 +1334,37 @@ error:
+@@ -1283,6 +1353,37 @@ error:
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
  
        u32 base = 0;
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
        out->antenna_gain.ghz5.a3 = gain;
  }
        /* TODO - get remaining rev 4 stuff needed */
  }
  
-@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+@@ -561,6 +607,31 @@ static void sprom_extract_r8(struct ssb_
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
  
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
 +      sprom_extract_r458(out, in);
 +
        /* TODO - get remaining rev 8 stuff needed */
  }
  
-@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+@@ -573,37 +644,34 @@ static int sprom_extract(struct ssb_bus
        ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
        memset(out->et1mac, 0xFF, 6);
        }
  
        if (out->boardflags_lo == 0xFFFF)
-@@ -617,15 +662,14 @@ static int sprom_extract(struct ssb_bus
+@@ -617,15 +685,14 @@ static int sprom_extract(struct ssb_bus
  static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
  {
                /*
                 * get SPROM offset: SSB_SPROM_BASE1 except for
                 * chipcommon rev >= 31 or chip ID is 0x4312 and
-@@ -645,7 +689,7 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -645,7 +712,7 @@ static int ssb_pci_sprom_get(struct ssb_
  
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)
        bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
        sprom_do_read(bus, buf);
        err = sprom_check_crc(buf, bus->sprom_size);
-@@ -655,17 +699,24 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -655,17 +722,24 @@ static int ssb_pci_sprom_get(struct ssb_
                buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                              GFP_KERNEL);
                if (!buf)
                                err = 0;
                                goto out_free;
                        }
-@@ -677,19 +728,15 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -677,19 +751,15 @@ static int ssb_pci_sprom_get(struct ssb_
  
  out_free:
        kfree(buf);
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
+@@ -6,7 +6,7 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -53,12 +53,13 @@ static int ssb_pcihost_resume(struct pci
  # define ssb_pcihost_resume   NULL
  #endif /* CONFIG_PM */
        driver->remove = ssb_pcihost_remove;
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -259,7 +259,10 @@ static int we_support_multiple_80211_cor
  #ifdef CONFIG_SSB_PCIHOST
        if (bus->bustype == SSB_BUSTYPE_PCI) {
                }
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,6 +27,8 @@ struct ssb_sprom {
+@@ -25,8 +25,10 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 +      u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
 +      u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
        u8 rxpo2g;              /* 2GHz RX power offset */
        u8 rxpo5g;              /* 5GHz RX power offset */
        u8 rssisav2g;           /* 2GHz RSSI params */
-@@ -95,7 +101,7 @@ struct ssb_sprom {
+@@ -88,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -95,7 +110,7 @@ struct ssb_sprom {
  struct ssb_boardinfo {
        u16 vendor;
        u16 type;
  };
  
  
-@@ -304,7 +310,7 @@ struct ssb_bus {
+@@ -225,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -304,7 +318,7 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
        u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
-@@ -400,7 +406,9 @@ extern bool ssb_is_sprom_available(struc
+@@ -400,7 +414,9 @@ extern bool ssb_is_sprom_available(struc
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -514,6 +522,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -514,6 +530,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
  #define SSB_SPROM5_IL0MAC             0x0052  /* 6 byte MAC address for a/b/g/n */
  #define SSB_SPROM5_GPIOA              0x0076  /* Gen. Purpose IO # 0 and 1 */
  #define  SSB_SPROM5_GPIOA_P0          0x00FF  /* Pin 0 */
+@@ -386,6 +432,23 @@
+ #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
+ #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
+ #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
+ #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
+@@ -416,6 +479,46 @@
+ #define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
+ #define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
++
+ /* Values for SSB_SPROM1_BINF_CCODE */
+ enum {
+       SSB_SPROM1CCODE_WORLD = 0,
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -417,12 +417,14 @@ static void ssb_pmu_resources_init(struc
        u32 min_msk = 0, max_msk = 0;
        unsigned int i;
                 * min_msk = 0xCBB
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige
        gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
  }
        u32 base, tmslow, tmshigh;
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -403,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
+@@ -403,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pc
+@@ -446,11 +563,35 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
        u32 v;
        int i;
  
-@@ -458,46 +595,68 @@ static void ssb_pcie_mdio_write(struct s
+@@ -458,46 +599,68 @@ static void ssb_pcie_mdio_write(struct s
        v |= 0x2; /* MDIO Clock Divisor */
        pcicore_write32(pc, mdio_control, v);
  
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -550,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -550,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
  out:
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,7 +17,7 @@
  #include <linux/slab.h>
  
 + * callback handler which fills the SPROM data structure. The fallback is
 + * only used for PCI based SSB devices, where no valid SPROM can be found
 + * in the shadow registers.
-  *
-- * This function is useful for weird architectures that have a half-assed SSB device
-- * hardwired to their PCI bus.
++ *
 + * This function is useful for weird architectures that have a half-assed
 + * SSB device hardwired to their PCI bus.
-  *
-- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
-- * don't use this fallback.
-- * Architectures must provide the SPROM for native SSB devices anyway,
-- * so the fallback also isn't used for native devices.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
 + * the fallback also isn't used for native devices.
   *
+- * This function is useful for weird architectures that have a half-assed SSB device
+- * hardwired to their PCI bus.
+- *
+- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+- * don't use this fallback.
+- * Architectures must provide the SPROM for native SSB devices anyway,
+- * so the fallback also isn't used for native devices.
+- *
 - * This function is available for architecture code, only. So it is not exported.
 + * This function is available for architecture code, only. So it is not
 + * exported.
  /* core.c */
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -123,6 +123,8 @@
  #define SSB_CHIPCO_FLASHDATA          0x0048
  #define SSB_CHIPCO_BCAST_ADDR         0x0050
  #define SSB_CHIPCO_HW_WORKAROUND      0x01E4 /* Hardware workaround (rev >= 20) */
  #define SSB_CHIPCO_UART0_DATA         0x0300
  #define SSB_CHIPCO_UART0_IMR          0x0304
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -6,7 +6,7 @@
+  *
+  * Based on drivers/ssb/pcmcia.c
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  *
index 82872c7..b71b675 100644 (file)
@@ -1,6 +1,23 @@
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -383,6 +383,35 @@ static int ssb_device_uevent(struct devi
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -383,6 +384,35 @@ static int ssb_device_uevent(struct devi
                             ssb_dev->id.revision);
  }
  
@@ -36,7 +53,7 @@
  static struct bus_type ssb_bustype = {
        .name           = "ssb",
        .match          = ssb_bus_match,
-@@ -392,6 +421,7 @@ static struct bus_type ssb_bustype = {
+@@ -392,6 +422,7 @@ static struct bus_type ssb_bustype = {
        .suspend        = ssb_device_suspend,
        .resume         = ssb_device_resume,
        .uevent         = ssb_device_uevent,
@@ -44,7 +61,7 @@
  };
  
  static void ssb_buses_lock(void)
-@@ -527,7 +557,7 @@ error:
+@@ -527,7 +558,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
@@ -53,7 +70,7 @@
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -738,9 +768,9 @@ out:
+@@ -738,9 +769,9 @@ out:
        return err;
  }
  
@@ -66,7 +83,7 @@
  {
        int err;
  
-@@ -821,8 +851,8 @@ err_disable_xtal:
+@@ -821,8 +852,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
@@ -77,7 +94,7 @@
  {
        int err;
  
-@@ -845,9 +875,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -845,9 +876,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -867,8 +897,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+@@ -867,8 +898,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  #ifdef CONFIG_SSB_SDIOHOST
  {
        int err;
  
-@@ -888,9 +919,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -888,9 +920,9 @@ int ssb_bus_sdiobus_register(struct ssb_
  EXPORT_SYMBOL(ssb_bus_sdiobus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -971,8 +1002,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -971,8 +1003,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1087,23 +1118,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1087,23 +1119,22 @@ static u32 ssb_tmslow_reject_bitmask(str
  {
        u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
  
  }
  
  int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1162,10 +1192,10 @@ void ssb_device_enable(struct ssb_device
+@@ -1162,10 +1193,10 @@ void ssb_device_enable(struct ssb_device
  }
  EXPORT_SYMBOL(ssb_device_enable);
  
  {
        int i;
        u32 val;
-@@ -1173,7 +1203,7 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1173,7 +1204,7 @@ static int ssb_wait_bit(struct ssb_devic
        for (i = 0; i < timeout; i++) {
                val = ssb_read32(dev, reg);
                if (set) {
                                return 0;
                } else {
                        if (!(val & bitmask))
-@@ -1190,20 +1220,38 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1190,20 +1221,38 @@ static int ssb_wait_bit(struct ssb_devic
  
  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
  {
  
        ssb_write32(dev, SSB_TMSLOW,
                    reject | SSB_TMSLOW_RESET |
-@@ -1218,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1212,13 +1261,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (pci_is_pcie(dev->bus->host_pci) &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
-@@ -1261,20 +1312,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1261,20 +1331,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
  
  int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
  {
        return 0;
  error:
        ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1282,6 +1333,37 @@ error:
+@@ -1282,6 +1352,37 @@ error:
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
  
        u32 base = 0;
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ss
        out->antenna_gain.ghz5.a3 = gain;
  }
        /* TODO - get remaining rev 4 stuff needed */
  }
  
-@@ -561,6 +607,8 @@ static void sprom_extract_r8(struct ssb_
+@@ -561,6 +607,31 @@ static void sprom_extract_r8(struct ssb_
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
  
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
 +      sprom_extract_r458(out, in);
 +
        /* TODO - get remaining rev 8 stuff needed */
  }
  
-@@ -573,37 +621,34 @@ static int sprom_extract(struct ssb_bus
+@@ -573,37 +644,34 @@ static int sprom_extract(struct ssb_bus
        ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
        memset(out->et0mac, 0xFF, 6);           /* preset et0 and et1 mac */
        memset(out->et1mac, 0xFF, 6);
        }
  
        if (out->boardflags_lo == 0xFFFF)
-@@ -617,15 +662,14 @@ static int sprom_extract(struct ssb_bus
+@@ -617,15 +685,14 @@ static int sprom_extract(struct ssb_bus
  static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
  {
                /*
                 * get SPROM offset: SSB_SPROM_BASE1 except for
                 * chipcommon rev >= 31 or chip ID is 0x4312 and
-@@ -645,7 +689,7 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -645,7 +712,7 @@ static int ssb_pci_sprom_get(struct ssb_
  
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)
        bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
        sprom_do_read(bus, buf);
        err = sprom_check_crc(buf, bus->sprom_size);
-@@ -655,17 +699,24 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -655,17 +722,24 @@ static int ssb_pci_sprom_get(struct ssb_
                buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
                              GFP_KERNEL);
                if (!buf)
                                err = 0;
                                goto out_free;
                        }
-@@ -677,19 +728,15 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -677,19 +751,15 @@ static int ssb_pci_sprom_get(struct ssb_
  
  out_free:
        kfree(buf);
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
+@@ -6,7 +6,7 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -53,12 +53,13 @@ static int ssb_pcihost_resume(struct pci
  # define ssb_pcihost_resume   NULL
  #endif /* CONFIG_PM */
        driver->remove = ssb_pcihost_remove;
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -258,7 +258,10 @@ static int we_support_multiple_80211_cor
  #ifdef CONFIG_SSB_PCIHOST
        if (bus->bustype == SSB_BUSTYPE_PCI) {
                }
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,6 +27,8 @@ struct ssb_sprom {
+@@ -25,8 +25,10 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 +      u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
 +      u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
        u8 rxpo2g;              /* 2GHz RX power offset */
        u8 rxpo5g;              /* 5GHz RX power offset */
        u8 rssisav2g;           /* 2GHz RSSI params */
-@@ -95,7 +101,7 @@ struct ssb_sprom {
+@@ -88,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -95,7 +110,7 @@ struct ssb_sprom {
  struct ssb_boardinfo {
        u16 vendor;
        u16 type;
  };
  
  
-@@ -304,7 +310,7 @@ struct ssb_bus {
+@@ -225,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -304,7 +318,7 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
        u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
-@@ -400,7 +406,9 @@ extern bool ssb_is_sprom_available(struc
+@@ -400,7 +414,9 @@ extern bool ssb_is_sprom_available(struc
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -514,6 +522,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -514,6 +530,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
  #define SSB_SPROM5_IL0MAC             0x0052  /* 6 byte MAC address for a/b/g/n */
  #define SSB_SPROM5_GPIOA              0x0076  /* Gen. Purpose IO # 0 and 1 */
  #define  SSB_SPROM5_GPIOA_P0          0x00FF  /* Pin 0 */
+@@ -387,6 +432,23 @@
+ #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
+ #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
+ #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
+ #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
+@@ -417,6 +479,46 @@
+ #define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
+ #define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
++
+ /* Values for SSB_SPROM1_BINF_CCODE */
+ enum {
+       SSB_SPROM1CCODE_WORLD = 0,
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -417,12 +417,14 @@ static void ssb_pmu_resources_init(struc
        u32 min_msk = 0, max_msk = 0;
        unsigned int i;
                 * min_msk = 0xCBB
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige
        gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
  }
        u32 base, tmslow, tmshigh;
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -403,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
+@@ -403,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pc
+@@ -446,11 +563,35 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
        u32 v;
        int i;
  
-@@ -458,46 +595,68 @@ static void ssb_pcie_mdio_write(struct s
+@@ -458,46 +599,68 @@ static void ssb_pcie_mdio_write(struct s
        v |= 0x2; /* MDIO Clock Divisor */
        pcicore_write32(pc, mdio_control, v);
  
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -550,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -550,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
  out:
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,7 +17,7 @@
  #include <linux/slab.h>
  
 + * callback handler which fills the SPROM data structure. The fallback is
 + * only used for PCI based SSB devices, where no valid SPROM can be found
 + * in the shadow registers.
-  *
-- * This function is useful for weird architectures that have a half-assed SSB device
-- * hardwired to their PCI bus.
++ *
 + * This function is useful for weird architectures that have a half-assed
 + * SSB device hardwired to their PCI bus.
-  *
-- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
-- * don't use this fallback.
-- * Architectures must provide the SPROM for native SSB devices anyway,
-- * so the fallback also isn't used for native devices.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
 + * the fallback also isn't used for native devices.
   *
+- * This function is useful for weird architectures that have a half-assed SSB device
+- * hardwired to their PCI bus.
+- *
+- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+- * don't use this fallback.
+- * Architectures must provide the SPROM for native SSB devices anyway,
+- * so the fallback also isn't used for native devices.
+- *
 - * This function is available for architecture code, only. So it is not exported.
 + * This function is available for architecture code, only. So it is not
 + * exported.
  /* core.c */
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -123,6 +123,8 @@
  #define SSB_CHIPCO_FLASHDATA          0x0048
  #define SSB_CHIPCO_BCAST_ADDR         0x0050
  #define SSB_CHIPCO_HW_WORKAROUND      0x01E4 /* Hardware workaround (rev >= 20) */
  #define SSB_CHIPCO_UART0_DATA         0x0300
  #define SSB_CHIPCO_UART0_IMR          0x0304
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -6,7 +6,7 @@
+  *
+  * Based on drivers/ssb/pcmcia.c
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  *
index 1b5da3b..c3312a2 100644 (file)
@@ -71,7 +71,7 @@
  obj-$(CONFIG_STAGING)         += staging/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warn("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warn("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index 3db9613..a72a39b 100644 (file)
@@ -1,6 +1,136 @@
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -1192,10 +1192,10 @@ void ssb_device_enable(struct ssb_device
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -557,7 +558,7 @@ error:
+ }
+ /* Needs ssb_buses_lock() */
+-static int ssb_attach_queued_buses(void)
++static int __devinit ssb_attach_queued_buses(void)
+ {
+       struct ssb_bus *bus, *n;
+       int err = 0;
+@@ -768,9 +769,9 @@ out:
+       return err;
+ }
+-static int ssb_bus_register(struct ssb_bus *bus,
+-                          ssb_invariants_func_t get_invariants,
+-                          unsigned long baseaddr)
++static int __devinit ssb_bus_register(struct ssb_bus *bus,
++                                    ssb_invariants_func_t get_invariants,
++                                    unsigned long baseaddr)
+ {
+       int err;
+@@ -851,8 +852,8 @@ err_disable_xtal:
+ }
+ #ifdef CONFIG_SSB_PCIHOST
+-int ssb_bus_pcibus_register(struct ssb_bus *bus,
+-                          struct pci_dev *host_pci)
++int __devinit ssb_bus_pcibus_register(struct ssb_bus *bus,
++                                    struct pci_dev *host_pci)
+ {
+       int err;
+@@ -875,9 +876,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+ #endif /* CONFIG_SSB_PCIHOST */
+ #ifdef CONFIG_SSB_PCMCIAHOST
+-int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
+-                             struct pcmcia_device *pcmcia_dev,
+-                             unsigned long baseaddr)
++int __devinit ssb_bus_pcmciabus_register(struct ssb_bus *bus,
++                                       struct pcmcia_device *pcmcia_dev,
++                                       unsigned long baseaddr)
+ {
+       int err;
+@@ -897,8 +898,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+ #ifdef CONFIG_SSB_SDIOHOST
+-int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
+-                           unsigned int quirks)
++int __devinit ssb_bus_sdiobus_register(struct ssb_bus *bus,
++                                     struct sdio_func *func,
++                                     unsigned int quirks)
+ {
+       int err;
+@@ -918,9 +920,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+ EXPORT_SYMBOL(ssb_bus_sdiobus_register);
+ #endif /* CONFIG_SSB_PCMCIAHOST */
+-int ssb_bus_ssbbus_register(struct ssb_bus *bus,
+-                          unsigned long baseaddr,
+-                          ssb_invariants_func_t get_invariants)
++int __devinit ssb_bus_ssbbus_register(struct ssb_bus *bus,
++                                    unsigned long baseaddr,
++                                    ssb_invariants_func_t get_invariants)
+ {
+       int err;
+@@ -1001,8 +1003,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+       switch (plltype) {
+       case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+               if (m & SSB_CHIPCO_CLK_T6_MMASK)
+-                      return SSB_CHIPCO_CLK_T6_M0;
+-              return SSB_CHIPCO_CLK_T6_M1;
++                      return SSB_CHIPCO_CLK_T6_M1;
++              return SSB_CHIPCO_CLK_T6_M0;
+       case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+       case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+       case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+@@ -1117,23 +1119,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+ {
+       u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
+-      /* The REJECT bit changed position in TMSLOW between
+-       * Backplane revisions. */
++      /* The REJECT bit seems to be different for Backplane rev 2.3 */
+       switch (rev) {
+       case SSB_IDLOW_SSBREV_22:
+-              return SSB_TMSLOW_REJECT_22;
++      case SSB_IDLOW_SSBREV_24:
++      case SSB_IDLOW_SSBREV_26:
++              return SSB_TMSLOW_REJECT;
+       case SSB_IDLOW_SSBREV_23:
+               return SSB_TMSLOW_REJECT_23;
+-      case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
+-      case SSB_IDLOW_SSBREV_25:     /* same here */
+-      case SSB_IDLOW_SSBREV_26:     /* same here */
++      case SSB_IDLOW_SSBREV_25:     /* TODO - find the proper REJECT bit */
+       case SSB_IDLOW_SSBREV_27:     /* same here */
+-              return SSB_TMSLOW_REJECT_23;    /* this is a guess */
++              return SSB_TMSLOW_REJECT;       /* this is a guess */
+       default:
+               printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
+               WARN_ON(1);
+       }
+-      return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
++      return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
+ }
+ int ssb_device_is_enabled(struct ssb_device *dev)
+@@ -1192,10 +1193,10 @@ void ssb_device_enable(struct ssb_device
  }
  EXPORT_SYMBOL(ssb_device_enable);
  
  {
        int i;
        u32 val;
-@@ -1203,7 +1203,7 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1203,7 +1204,7 @@ static int ssb_wait_bit(struct ssb_devic
        for (i = 0; i < timeout; i++) {
                val = ssb_read32(dev, reg);
                if (set) {
                                return 0;
                } else {
                        if (!(val & bitmask))
-@@ -1220,20 +1220,38 @@ static int ssb_wait_bit(struct ssb_devic
+@@ -1220,20 +1221,38 @@ static int ssb_wait_bit(struct ssb_devic
  
  void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
  {
  
        ssb_write32(dev, SSB_TMSLOW,
                    reject | SSB_TMSLOW_RESET |
+@@ -1242,13 +1261,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_SSB:
+               return 0;
+       case SSB_BUSTYPE_PCI:
+-              return SSB_PCI_DMA;
++              if (pci_is_pcie(dev->bus->host_pci) &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
++                      return SSB_PCIE_DMA_H32;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+@@ -1291,20 +1331,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+ int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
+ {
+-      struct ssb_chipcommon *cc;
+       int err;
+       enum ssb_clkmode mode;
+       err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+       if (err)
+               goto error;
+-      cc = &bus->chipco;
+-      mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+-      ssb_chipco_set_clockmode(cc, mode);
+ #ifdef CONFIG_SSB_DEBUG
+       bus->powered_up = 1;
+ #endif
++
++      mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
++      ssb_chipco_set_clockmode(&bus->chipco, mode);
++
+       return 0;
+ error:
+       ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+@@ -1312,6 +1352,37 @@ error:
+ }
+ EXPORT_SYMBOL(ssb_bus_powerup);
++static void ssb_broadcast_value(struct ssb_device *dev,
++                              u32 address, u32 data)
++{
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      /* This is used for both, PCI and ChipCommon core, so be careful. */
++      BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
++      BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
++#endif
++
++      ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address);
++      ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */
++      ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data);
++      ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */
++}
++
++void ssb_commit_settings(struct ssb_bus *bus)
++{
++      struct ssb_device *dev;
++
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
++#else
++      dev = bus->chipco.dev;
++#endif
++      if (WARN_ON(!dev))
++              return;
++      /* This forces an update of the cached registers. */
++      ssb_broadcast_value(dev, 0xFD8, 0);
++}
++EXPORT_SYMBOL(ssb_commit_settings);
++
+ u32 ssb_admatch_base(u32 adm)
+ {
+       u32 base = 0;
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -468,10 +468,14 @@ static void sprom_extract_r45(struct ssb
                SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
                SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
        }
        SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
             SSB_SPROM4_ANTAVAIL_A_SHIFT);
-@@ -641,7 +645,7 @@ static int sprom_extract(struct ssb_bus
+@@ -603,6 +607,29 @@ static void sprom_extract_r8(struct ssb_
+       memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+              sizeof(out->antenna_gain.ghz5));
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
+       sprom_extract_r458(out, in);
+       /* TODO - get remaining rev 8 stuff needed */
+@@ -641,7 +668,7 @@ static int sprom_extract(struct ssb_bus
                break;
        default:
                ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
                           " v1\n", out->revision);
                out->revision = 1;
                sprom_extract_r123(out, in);
+@@ -658,7 +685,6 @@ static int sprom_extract(struct ssb_bus
+ static int ssb_pci_sprom_get(struct ssb_bus *bus,
+                            struct ssb_sprom *sprom)
+ {
+-      const struct ssb_sprom *fallback;
+       int err;
+       u16 *buf;
+@@ -666,7 +692,7 @@ static int ssb_pci_sprom_get(struct ssb_
+               ssb_printk(KERN_ERR PFX "No SPROM available!\n");
+               return -ENODEV;
+       }
+-      if (bus->chipco.dev) {  /* can be unavailible! */
++      if (bus->chipco.dev) {  /* can be unavailable! */
+               /*
+                * get SPROM offset: SSB_SPROM_BASE1 except for
+                * chipcommon rev >= 31 or chip ID is 0x4312 and
+@@ -703,10 +729,17 @@ static int ssb_pci_sprom_get(struct ssb_
+               if (err) {
+                       /* All CRC attempts failed.
+                        * Maybe there is no SPROM on the device?
+-                       * If we have a fallback, use that. */
+-                      fallback = ssb_get_fallback_sprom();
+-                      if (fallback) {
+-                              memcpy(sprom, fallback, sizeof(*sprom));
++                       * Now we ask the arch code if there is some sprom
++                       * available for this device in some other storage */
++                      err = ssb_fill_sprom_with_fallback(bus, sprom);
++                      if (err) {
++                              ssb_printk(KERN_WARNING PFX "WARNING: Using"
++                                         " fallback SPROM failed (err %d)\n",
++                                         err);
++                      } else {
++                              ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
++                                          " revision %d provided by"
++                                          " platform.\n", sprom->revision);
+                               err = 0;
+                               goto out_free;
+                       }
+@@ -724,12 +757,9 @@ out_free:
+ static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
+                                 struct ssb_boardinfo *bi)
+ {
+-      pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
+-                           &bi->vendor);
+-      pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
+-                           &bi->type);
+-      pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+-                           &bi->rev);
++      bi->vendor = bus->host_pci->subsystem_vendor;
++      bi->type = bus->host_pci->subsystem_device;
++      bi->rev = bus->host_pci->revision;
+ }
+ int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/include/linux/ssb/ssb_regs.h
 +++ b/include/linux/ssb/ssb_regs.h
 @@ -85,6 +85,8 @@
  #define SSB_INTVEC            0x0F94     /* SB Interrupt Mask */
  #define  SSB_INTVEC_PCI               0x00000001 /* Enable interrupts for PCI */
  #define  SSB_INTVEC_ENET0     0x00000002 /* Enable interrupts for enet 0 */
-@@ -97,7 +99,6 @@
+@@ -95,9 +97,8 @@
+ #define  SSB_INTVEC_ENET1     0x00000040 /* Enable interrupts for enet 1 */
+ #define SSB_TMSLOW            0x0F98     /* SB Target State Low */
  #define  SSB_TMSLOW_RESET     0x00000001 /* Reset */
- #define  SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */
+-#define  SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */
++#define  SSB_TMSLOW_REJECT    0x00000002 /* Reject (Standard Backplane) */
  #define  SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */
 -#define  SSB_TMSLOW_PHYCLK    0x00000010 /* MAC PHY Clock Control Enable */
  #define  SSB_TMSLOW_CLOCK     0x00010000 /* Clock Enable */
  #define SSB_SPROM5_IL0MAC             0x0052  /* 6 byte MAC address for a/b/g/n */
  #define SSB_SPROM5_GPIOA              0x0076  /* Gen. Purpose IO # 0 and 1 */
  #define  SSB_SPROM5_GPIOA_P0          0x00FF  /* Pin 0 */
-diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
-index 7c031fd..06d15b6 100644
+@@ -427,6 +432,23 @@
+ #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
+ #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
+ #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
+ #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
+@@ -457,6 +479,46 @@
+ #define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
+ #define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
++
+ /* Values for SSB_SPROM1_BINF_CCODE */
+ enum {
+       SSB_SPROM1CCODE_WORLD = 0,
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
-@@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
        bus = ccdev->bus;
@@ -223,7 +627,7 @@ index 7c031fd..06d15b6 100644
                break;
        default:
                SSB_WARN_ON(1);
-@@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+@@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chip
        if (cc->dev->id.revision >= 11)
                cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
        ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
@@ -236,11 +640,18 @@ index 7c031fd..06d15b6 100644
        ssb_pmu_init(cc);
        chipco_powercontrol_init(cc);
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
-diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
-index 5732bb2..a7aef47 100644
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
-@@ -417,12 +417,14 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+@@ -417,12 +417,14 @@ static void ssb_pmu_resources_init(struc
        u32 min_msk = 0, max_msk = 0;
        unsigned int i;
        const struct pmu_res_updown_tab_entry *updown_tab = NULL;
@@ -257,12 +668,19 @@ index 5732bb2..a7aef47 100644
        case 0x4322:
                /* We keep the default settings:
                 * min_msk = 0xCBB
-diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c
-index 5ba92a2..d758909 100644
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
-@@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige *dev,
-       gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige
+       gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
  }
  
 -static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn,
@@ -273,7 +691,7 @@ index 5ba92a2..d758909 100644
  {
        struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
        unsigned long flags;
-@@ -136,8 +137,9 @@ static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+@@ -136,8 +137,9 @@ static int ssb_gige_pci_read_config(stru
        return PCIBIOS_SUCCESSFUL;
  }
  
@@ -285,7 +703,7 @@ index 5ba92a2..d758909 100644
  {
        struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
        unsigned long flags;
-@@ -166,7 +168,8 @@ static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+@@ -166,7 +168,8 @@ static int ssb_gige_pci_write_config(str
        return PCIBIOS_SUCCESSFUL;
  }
  
@@ -295,10 +713,17 @@ index 5ba92a2..d758909 100644
  {
        struct ssb_gige *dev;
        u32 base, tmslow, tmshigh;
-diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
-index 0e8d352..11d85bf 100644
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
@@ -311,7 +736,7 @@ index 0e8d352..11d85bf 100644
  
  static inline
  u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
-@@ -309,7 +314,7 @@ int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+@@ -309,7 +314,7 @@ int ssb_pcicore_pcibios_map_irq(const st
        return ssb_mips_irq(extpci_core->dev) + 2;
  }
  
@@ -320,7 +745,7 @@ index 0e8d352..11d85bf 100644
  {
        u32 val;
  
-@@ -374,7 +379,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
+@@ -374,7 +379,7 @@ static void ssb_pcicore_init_hostmode(st
        register_pci_controller(&ssb_pcicore_controller);
  }
  
@@ -329,7 +754,7 @@ index 0e8d352..11d85bf 100644
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -403,25 +408,133 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
+@@ -403,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
@@ -442,10 +867,15 @@ index 0e8d352..11d85bf 100644
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
@@ -467,7 +897,7 @@ index 0e8d352..11d85bf 100644
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
+@@ -446,11 +563,35 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
@@ -505,7 +935,7 @@ index 0e8d352..11d85bf 100644
        u32 v;
        int i;
  
-@@ -458,46 +595,68 @@ static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+@@ -458,46 +599,68 @@ static void ssb_pcie_mdio_write(struct s
        v |= 0x2; /* MDIO Clock Divisor */
        pcicore_write32(pc, mdio_control, v);
  
@@ -549,35 +979,34 @@ index 0e8d352..11d85bf 100644
 -      /* This is used for both, PCI and ChipCommon core, so be careful. */
 -      BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
 -      BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
--
--      ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
--      ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
--      ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
--      ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
--}
 +      const u16 mdio_control = 0x128;
 +      const u16 mdio_data = 0x12C;
 +      int max_retries = 10;
 +      u32 v;
 +      int i;
  
--static void ssb_commit_settings(struct ssb_bus *bus)
--{
--      struct ssb_device *dev;
+-      ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
+-      ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
+-      ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
+-      ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
+-}
 +      v = 0x80; /* Enable Preamble Sequence */
 +      v |= 0x2; /* MDIO Clock Divisor */
 +      pcicore_write32(pc, mdio_control, v);
  
+-static void ssb_commit_settings(struct ssb_bus *bus)
+-{
+-      struct ssb_device *dev;
++      if (pc->dev->id.revision >= 10) {
++              max_retries = 200;
++              ssb_pcie_mdio_set_phy(pc, device);
++      }
 -      dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
 -      if (WARN_ON(!dev))
 -              return;
 -      /* This forces an update of the cached registers. */
 -      ssb_broadcast_value(dev, 0xFD8, 0);
-+      if (pc->dev->id.revision >= 10) {
-+              max_retries = 200;
-+              ssb_pcie_mdio_set_phy(pc, device);
-+      }
-+
 +      v = (1 << 30); /* Start of Transaction */
 +      v |= (1 << 28); /* Write Transaction */
 +      v |= (1 << 17); /* Turnaround */
@@ -598,7 +1027,7 @@ index 0e8d352..11d85bf 100644
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -550,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
+@@ -550,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
@@ -649,262 +1078,18 @@ index 0e8d352..11d85bf 100644
        }
        pc->setup_done = 1;
  out:
-diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
-index e05ba6e..6ec6e09 100644
---- a/drivers/ssb/main.c
-+++ b/drivers/ssb/main.c
-@@ -557,7 +557,7 @@ error:
- }
- /* Needs ssb_buses_lock() */
--static int ssb_attach_queued_buses(void)
-+static int __devinit ssb_attach_queued_buses(void)
- {
-       struct ssb_bus *bus, *n;
-       int err = 0;
-@@ -768,9 +768,9 @@ out:
-       return err;
- }
--static int ssb_bus_register(struct ssb_bus *bus,
--                          ssb_invariants_func_t get_invariants,
--                          unsigned long baseaddr)
-+static int __devinit ssb_bus_register(struct ssb_bus *bus,
-+                                    ssb_invariants_func_t get_invariants,
-+                                    unsigned long baseaddr)
- {
-       int err;
-@@ -851,8 +851,8 @@ err_disable_xtal:
- }
- #ifdef CONFIG_SSB_PCIHOST
--int ssb_bus_pcibus_register(struct ssb_bus *bus,
--                          struct pci_dev *host_pci)
-+int __devinit ssb_bus_pcibus_register(struct ssb_bus *bus,
-+                                    struct pci_dev *host_pci)
- {
-       int err;
-@@ -875,9 +875,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
- #endif /* CONFIG_SSB_PCIHOST */
- #ifdef CONFIG_SSB_PCMCIAHOST
--int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
--                             struct pcmcia_device *pcmcia_dev,
--                             unsigned long baseaddr)
-+int __devinit ssb_bus_pcmciabus_register(struct ssb_bus *bus,
-+                                       struct pcmcia_device *pcmcia_dev,
-+                                       unsigned long baseaddr)
- {
-       int err;
-@@ -897,8 +897,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
- #endif /* CONFIG_SSB_PCMCIAHOST */
- #ifdef CONFIG_SSB_SDIOHOST
--int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
--                           unsigned int quirks)
-+int __devinit ssb_bus_sdiobus_register(struct ssb_bus *bus,
-+                                     struct sdio_func *func,
-+                                     unsigned int quirks)
- {
-       int err;
-@@ -918,9 +919,9 @@ int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
- EXPORT_SYMBOL(ssb_bus_sdiobus_register);
- #endif /* CONFIG_SSB_PCMCIAHOST */
--int ssb_bus_ssbbus_register(struct ssb_bus *bus,
--                          unsigned long baseaddr,
--                          ssb_invariants_func_t get_invariants)
-+int __devinit ssb_bus_ssbbus_register(struct ssb_bus *bus,
-+                                    unsigned long baseaddr,
-+                                    ssb_invariants_func_t get_invariants)
- {
-       int err;
-@@ -1001,8 +1002,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m)
-       switch (plltype) {
-       case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
-               if (m & SSB_CHIPCO_CLK_T6_MMASK)
--                      return SSB_CHIPCO_CLK_T6_M0;
--              return SSB_CHIPCO_CLK_T6_M1;
-+                      return SSB_CHIPCO_CLK_T6_M1;
-+              return SSB_CHIPCO_CLK_T6_M0;
-       case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
-       case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
-       case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1117,23 +1118,22 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
- {
-       u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
--      /* The REJECT bit changed position in TMSLOW between
--       * Backplane revisions. */
-+      /* The REJECT bit seems to be different for Backplane rev 2.3 */
-       switch (rev) {
-       case SSB_IDLOW_SSBREV_22:
--              return SSB_TMSLOW_REJECT_22;
-+      case SSB_IDLOW_SSBREV_24:
-+      case SSB_IDLOW_SSBREV_26:
-+              return SSB_TMSLOW_REJECT;
-       case SSB_IDLOW_SSBREV_23:
-               return SSB_TMSLOW_REJECT_23;
--      case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
--      case SSB_IDLOW_SSBREV_25:     /* same here */
--      case SSB_IDLOW_SSBREV_26:     /* same here */
-+      case SSB_IDLOW_SSBREV_25:     /* TODO - find the proper REJECT bit */
-       case SSB_IDLOW_SSBREV_27:     /* same here */
--              return SSB_TMSLOW_REJECT_23;    /* this is a guess */
-+              return SSB_TMSLOW_REJECT;       /* this is a guess */
-       default:
-               printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
-               WARN_ON(1);
-       }
--      return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
-+      return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23);
- }
- int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1266,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_device *dev)
-       case SSB_BUSTYPE_SSB:
-               return 0;
-       case SSB_BUSTYPE_PCI:
--              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
-+                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
-       default:
-               __ssb_dma_not_implemented(dev);
-       }
-@@ -1309,20 +1312,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
- int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
- {
--      struct ssb_chipcommon *cc;
-       int err;
-       enum ssb_clkmode mode;
-       err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
-       if (err)
-               goto error;
--      cc = &bus->chipco;
--      mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
--      ssb_chipco_set_clockmode(cc, mode);
- #ifdef CONFIG_SSB_DEBUG
-       bus->powered_up = 1;
- #endif
-+
-+      mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
-+      ssb_chipco_set_clockmode(&bus->chipco, mode);
-+
-       return 0;
- error:
-       ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1330,6 +1333,37 @@ error:
- }
- EXPORT_SYMBOL(ssb_bus_powerup);
-+static void ssb_broadcast_value(struct ssb_device *dev,
-+                              u32 address, u32 data)
-+{
-+#ifdef CONFIG_SSB_DRIVER_PCICORE
-+      /* This is used for both, PCI and ChipCommon core, so be careful. */
-+      BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
-+      BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
-+#endif
-+
-+      ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address);
-+      ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */
-+      ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data);
-+      ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */
-+}
-+
-+void ssb_commit_settings(struct ssb_bus *bus)
-+{
-+      struct ssb_device *dev;
-+
-+#ifdef CONFIG_SSB_DRIVER_PCICORE
-+      dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
-+#else
-+      dev = bus->chipco.dev;
-+#endif
-+      if (WARN_ON(!dev))
-+              return;
-+      /* This forces an update of the cached registers. */
-+      ssb_broadcast_value(dev, 0xFD8, 0);
-+}
-+EXPORT_SYMBOL(ssb_commit_settings);
-+
- u32 ssb_admatch_base(u32 adm)
- {
-       u32 base = 0;
-diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
-index a467b20..a00b35f 100644
---- a/drivers/ssb/pci.c
-+++ b/drivers/ssb/pci.c
-@@ -662,7 +662,6 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
- static int ssb_pci_sprom_get(struct ssb_bus *bus,
-                            struct ssb_sprom *sprom)
- {
--      const struct ssb_sprom *fallback;
-       int err;
-       u16 *buf;
-@@ -670,7 +669,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
-               ssb_printk(KERN_ERR PFX "No SPROM available!\n");
-               return -ENODEV;
-       }
--      if (bus->chipco.dev) {  /* can be unavailible! */
-+      if (bus->chipco.dev) {  /* can be unavailable! */
-               /*
-                * get SPROM offset: SSB_SPROM_BASE1 except for
-                * chipcommon rev >= 31 or chip ID is 0x4312 and
-@@ -707,10 +706,17 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
-               if (err) {
-                       /* All CRC attempts failed.
-                        * Maybe there is no SPROM on the device?
--                       * If we have a fallback, use that. */
--                      fallback = ssb_get_fallback_sprom();
--                      if (fallback) {
--                              memcpy(sprom, fallback, sizeof(*sprom));
-+                       * Now we ask the arch code if there is some sprom
-+                       * available for this device in some other storage */
-+                      err = ssb_fill_sprom_with_fallback(bus, sprom);
-+                      if (err) {
-+                              ssb_printk(KERN_WARNING PFX "WARNING: Using"
-+                                         " fallback SPROM failed (err %d)\n",
-+                                         err);
-+                      } else {
-+                              ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
-+                                          " revision %d provided by"
-+                                          " platform.\n", sprom->revision);
-                               err = 0;
-                               goto out_free;
-                       }
-@@ -728,12 +734,9 @@ out_free:
- static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
-                                 struct ssb_boardinfo *bi)
- {
--      pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
--                           &bi->vendor);
--      pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
--                           &bi->type);
--      pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
--                           &bi->rev);
-+      bi->vendor = bus->host_pci->subsystem_vendor;
-+      bi->type = bus->host_pci->subsystem_device;
-+      bi->rev = bus->host_pci->revision;
- }
- int ssb_pci_get_invariants(struct ssb_bus *bus,
-diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
-index f6c8c81..d7a9813 100644
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
-@@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci_dev *dev)
+@@ -6,7 +6,7 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
  # define ssb_pcihost_resume   NULL
  #endif /* CONFIG_PM */
  
@@ -915,7 +1100,7 @@ index f6c8c81..d7a9813 100644
  {
        struct ssb_bus *ssb;
        int err = -ENOMEM;
-@@ -110,7 +110,7 @@ static void ssb_pcihost_remove(struct pci_dev *dev)
+@@ -110,7 +110,7 @@ static void ssb_pcihost_remove(struct pc
        pci_set_drvdata(dev, NULL);
  }
  
@@ -924,11 +1109,18 @@ index f6c8c81..d7a9813 100644
  {
        driver->probe = ssb_pcihost_probe;
        driver->remove = ssb_pcihost_remove;
-diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
-index 29884c0..8047f9a 100644
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
-@@ -258,7 +258,10 @@ static int we_support_multiple_80211_cores(struct ssb_bus *bus)
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+@@ -258,7 +258,10 @@ static int we_support_multiple_80211_cor
  #ifdef CONFIG_SSB_PCIHOST
        if (bus->bustype == SSB_BUSTYPE_PCI) {
                if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
@@ -950,10 +1142,17 @@ index 29884c0..8047f9a 100644
                        bus->chip_package = 0;
                } else {
                        bus->chip_id = 0x4710;
-diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
-index 4f7cc8d..45ff0e3 100644
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,7 +17,7 @@
  #include <linux/slab.h>
  
@@ -981,21 +1180,23 @@ index 4f7cc8d..45ff0e3 100644
 + * callback handler which fills the SPROM data structure. The fallback is
 + * only used for PCI based SSB devices, where no valid SPROM can be found
 + * in the shadow registers.
-  *
-- * This function is useful for weird architectures that have a half-assed SSB device
-- * hardwired to their PCI bus.
++ *
 + * This function is useful for weird architectures that have a half-assed
 + * SSB device hardwired to their PCI bus.
-  *
-- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
-- * don't use this fallback.
-- * Architectures must provide the SPROM for native SSB devices anyway,
-- * so the fallback also isn't used for native devices.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
 + * the fallback also isn't used for native devices.
   *
+- * This function is useful for weird architectures that have a half-assed SSB device
+- * hardwired to their PCI bus.
+- *
+- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+- * don't use this fallback.
+- * Architectures must provide the SPROM for native SSB devices anyway,
+- * so the fallback also isn't used for native devices.
+- *
 - * This function is available for architecture code, only. So it is not exported.
 + * This function is available for architecture code, only. So it is not
 + * exported.
@@ -1024,7 +1225,7 @@ index 4f7cc8d..45ff0e3 100644
  }
  
  /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
-@@ -185,7 +192,7 @@ bool ssb_is_sprom_available(struct ssb_bus *bus)
+@@ -185,7 +192,7 @@ bool ssb_is_sprom_available(struct ssb_b
        /* this routine differs from specs as we do not access SPROM directly
           on PCMCIA */
        if (bus->bustype == SSB_BUSTYPE_PCI &&
@@ -1033,11 +1234,9 @@ index 4f7cc8d..45ff0e3 100644
            bus->chipco.dev->id.revision >= 31)
                return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
  
-diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
-index 0331139..7765301 100644
 --- a/drivers/ssb/ssb_private.h
 +++ b/drivers/ssb/ssb_private.h
-@@ -171,7 +171,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
+@@ -171,7 +171,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_
                             const char *buf, size_t count,
                             int (*sprom_check_crc)(const u16 *sprom, size_t size),
                             int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
@@ -1047,20 +1246,37 @@ index 0331139..7765301 100644
  
  
  /* core.c */
-diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
-index 9659eff..8623217 100644
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,6 +27,8 @@ struct ssb_sprom {
+@@ -25,8 +25,10 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 +      u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
 +      u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
        u8 ant_available_a;     /* 2GHz antenna available bits (up to 4) */
        u8 ant_available_bg;    /* 5GHz antenna available bits (up to 4) */
        u16 pa0b0;
-@@ -99,7 +101,7 @@ struct ssb_sprom {
+@@ -92,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -99,7 +110,7 @@ struct ssb_sprom {
  struct ssb_boardinfo {
        u16 vendor;
        u16 type;
@@ -1069,7 +1285,21 @@ index 9659eff..8623217 100644
  };
  
  
-@@ -308,7 +310,7 @@ struct ssb_bus {
+@@ -229,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -308,7 +318,7 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
@@ -1078,7 +1308,7 @@ index 9659eff..8623217 100644
        u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
-@@ -404,7 +406,9 @@ extern bool ssb_is_sprom_available(struct ssb_bus *bus);
+@@ -404,7 +414,9 @@ extern bool ssb_is_sprom_available(struc
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
@@ -1089,7 +1319,7 @@ index 9659eff..8623217 100644
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -518,6 +522,7 @@ extern int ssb_bus_may_powerdown(struct ssb_bus *bus);
+@@ -518,6 +530,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
@@ -1097,10 +1327,17 @@ index 9659eff..8623217 100644
  
  /* Various helper functions */
  extern u32 ssb_admatch_base(u32 adm);
-diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
-index 2cdf249..a08d693 100644
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -123,6 +123,8 @@
  #define SSB_CHIPCO_FLASHDATA          0x0048
  #define SSB_CHIPCO_BCAST_ADDR         0x0050
@@ -1133,16 +1370,75 @@ index 2cdf249..a08d693 100644
  #define SSB_CHIPCO_HW_WORKAROUND      0x01E4 /* Hardware workaround (rev >= 20) */
  #define SSB_CHIPCO_UART0_DATA         0x0300
  #define SSB_CHIPCO_UART0_IMR          0x0304
-diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
-index 402955a..efbf459 100644
---- a/include/linux/ssb/ssb_regs.h
-+++ b/include/linux/ssb/ssb_regs.h
-@@ -97,7 +97,7 @@
- #define  SSB_INTVEC_ENET1     0x00000040 /* Enable interrupts for enet 1 */
- #define SSB_TMSLOW            0x0F98     /* SB Target State Low */
- #define  SSB_TMSLOW_RESET     0x00000001 /* Reset */
--#define  SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */
-+#define  SSB_TMSLOW_REJECT    0x00000002 /* Reject (Standard Backplane) */
- #define  SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */
- #define  SSB_TMSLOW_CLOCK     0x00010000 /* Clock Enable */
- #define  SSB_TMSLOW_FGC               0x00020000 /* Force Gated Clocks On */
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -6,7 +6,7 @@
+  *
+  * Based on drivers/ssb/pcmcia.c
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  *
index b36bb5f..60fefaf 100644 (file)
@@ -34,7 +34,7 @@
 +              belongs to. See include/linux/bcma/bcma.h for possible values.
 --- a/MAINTAINERS
 +++ b/MAINTAINERS
-@@ -5832,6 +5832,13 @@ S:      Maintained
+@@ -5791,6 +5791,13 @@ S:      Maintained
  F:    drivers/ssb/
  F:    include/linux/ssb/
  
@@ -71,7 +71,7 @@
  obj-$(CONFIG_STAGING)         += staging/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warn("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warn("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index f566288..be7071b 100644 (file)
@@ -1,5 +1,14 @@
 --- a/drivers/ssb/driver_chipcommon.c
 +++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb
        if (!ccdev)
                return;
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -417,12 +417,14 @@ static void ssb_pmu_resources_init(struc
        u32 min_msk = 0, max_msk = 0;
        unsigned int i;
                 * min_msk = 0xCBB
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige
        gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
  }
        u32 base, tmslow, tmshigh;
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -15,6 +15,11 @@
  
  #include "ssb_private.h"
  {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
-@@ -403,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
+@@ -403,25 +408,137 @@ static int pcicore_is_in_hostmode(struct
  }
  #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-+      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
 +
        /* Disable PCI interrupts. */
-       ssb_write32(pc->dev, SSB_INTVEC, 0);
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
 +
 +      /* Additional PCIe always once-executed workarounds */
 +      if (pc->dev->id.coreid == SSB_DEV_PCIE) {
        if (!ssb_device_is_enabled(dev))
                ssb_device_enable(dev, 0);
  
-@@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pc
+@@ -446,11 +563,35 @@ static void ssb_pcie_write(struct ssb_pc
        pcicore_write32(pc, 0x134, data);
  }
  
        u32 v;
        int i;
  
-@@ -458,46 +595,68 @@ static void ssb_pcie_mdio_write(struct s
+@@ -458,46 +599,68 @@ static void ssb_pcie_mdio_write(struct s
        v |= 0x2; /* MDIO Clock Divisor */
        pcicore_write32(pc, mdio_control, v);
  
  }
  
  int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
-@@ -550,48 +709,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
+@@ -550,48 +713,10 @@ int ssb_pcicore_dev_irqvecs_enable(struc
        if (pc->setup_done)
                goto out;
        if (pdev->id.coreid == SSB_DEV_PCI) {
  out:
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -557,7 +557,7 @@ error:
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -557,7 +558,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -768,9 +768,9 @@ out:
+@@ -768,9 +769,9 @@ out:
        return err;
  }
  
  {
        int err;
  
-@@ -851,8 +851,8 @@ err_disable_xtal:
+@@ -851,8 +852,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
  {
        int err;
  
-@@ -875,9 +875,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -875,9 +876,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -897,8 +897,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+@@ -897,8 +898,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  #ifdef CONFIG_SSB_SDIOHOST
  {
        int err;
  
-@@ -918,9 +919,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -918,9 +920,9 @@ int ssb_bus_sdiobus_register(struct ssb_
  EXPORT_SYMBOL(ssb_bus_sdiobus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -1001,8 +1002,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -1001,8 +1003,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1117,23 +1118,22 @@ static u32 ssb_tmslow_reject_bitmask(str
+@@ -1117,23 +1119,22 @@ static u32 ssb_tmslow_reject_bitmask(str
  {
        u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
  
  }
  
  int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1266,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1260,13 +1261,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (pci_is_pcie(dev->bus->host_pci) &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
-@@ -1309,20 +1312,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1309,20 +1331,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
  
  int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
  {
        return 0;
  error:
        ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1330,6 +1333,37 @@ error:
+@@ -1330,6 +1352,37 @@ error:
  }
  EXPORT_SYMBOL(ssb_bus_powerup);
  
        u32 base = 0;
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
-@@ -662,7 +662,6 @@ static int sprom_extract(struct ssb_bus
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+@@ -607,6 +607,29 @@ static void sprom_extract_r8(struct ssb_
+       memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+              sizeof(out->antenna_gain.ghz5));
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
+       sprom_extract_r458(out, in);
+       /* TODO - get remaining rev 8 stuff needed */
+@@ -662,7 +685,6 @@ static int sprom_extract(struct ssb_bus
  static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
  {
        int err;
        u16 *buf;
  
-@@ -707,10 +706,17 @@ static int ssb_pci_sprom_get(struct ssb_
+@@ -707,10 +729,17 @@ static int ssb_pci_sprom_get(struct ssb_
                if (err) {
                        /* All CRC attempts failed.
                         * Maybe there is no SPROM on the device?
                                err = 0;
                                goto out_free;
                        }
-@@ -728,12 +734,9 @@ out_free:
+@@ -728,12 +757,9 @@ out_free:
  static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
                                  struct ssb_boardinfo *bi)
  {
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
+@@ -6,7 +6,7 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
  # define ssb_pcihost_resume   NULL
  #endif /* CONFIG_PM */
        driver->remove = ssb_pcihost_remove;
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -258,7 +258,10 @@ static int we_support_multiple_80211_cor
  #ifdef CONFIG_SSB_PCIHOST
        if (bus->bustype == SSB_BUSTYPE_PCI) {
                        bus->chip_id = 0x4710;
 --- a/drivers/ssb/sprom.c
 +++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -17,7 +17,7 @@
  #include <linux/slab.h>
  
 + * callback handler which fills the SPROM data structure. The fallback is
 + * only used for PCI based SSB devices, where no valid SPROM can be found
 + * in the shadow registers.
-  *
-- * This function is useful for weird architectures that have a half-assed SSB device
-- * hardwired to their PCI bus.
++ *
 + * This function is useful for weird architectures that have a half-assed
 + * SSB device hardwired to their PCI bus.
-  *
-- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
-- * don't use this fallback.
-- * Architectures must provide the SPROM for native SSB devices anyway,
-- * so the fallback also isn't used for native devices.
++ *
 + * Note that it does only work with PCI attached SSB devices. PCMCIA
 + * devices currently don't use this fallback.
 + * Architectures must provide the SPROM for native SSB devices anyway, so
 + * the fallback also isn't used for native devices.
   *
+- * This function is useful for weird architectures that have a half-assed SSB device
+- * hardwired to their PCI bus.
+- *
+- * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+- * don't use this fallback.
+- * Architectures must provide the SPROM for native SSB devices anyway,
+- * so the fallback also isn't used for native devices.
+- *
 - * This function is available for architecture code, only. So it is not exported.
 + * This function is available for architecture code, only. So it is not
 + * exported.
  /* core.c */
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,6 +27,8 @@ struct ssb_sprom {
+@@ -25,8 +25,10 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 +      u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
 +      u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
        u8 ant_available_a;     /* 2GHz antenna available bits (up to 4) */
        u8 ant_available_bg;    /* 5GHz antenna available bits (up to 4) */
        u16 pa0b0;
-@@ -99,7 +101,7 @@ struct ssb_sprom {
+@@ -92,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -99,7 +110,7 @@ struct ssb_sprom {
  struct ssb_boardinfo {
        u16 vendor;
        u16 type;
  };
  
  
-@@ -308,7 +310,7 @@ struct ssb_bus {
+@@ -229,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+@@ -308,7 +318,7 @@ struct ssb_bus {
  
        /* ID information about the Chip. */
        u16 chip_id;
        u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
-@@ -404,7 +406,9 @@ extern bool ssb_is_sprom_available(struc
+@@ -404,7 +414,9 @@ extern bool ssb_is_sprom_available(struc
  
  /* Set a fallback SPROM.
   * See kdoc at the function definition for complete documentation. */
  
  /* Suspend a SSB bus.
   * Call this from the parent bus suspend routine. */
-@@ -518,6 +522,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -518,6 +530,7 @@ extern int ssb_bus_may_powerdown(struct
   * Otherwise static always-on powercontrol will be used. */
  extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
  
  extern u32 ssb_admatch_base(u32 adm);
 --- a/include/linux/ssb/ssb_driver_chipcommon.h
 +++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
 @@ -123,6 +123,8 @@
  #define SSB_CHIPCO_FLASHDATA          0x0048
  #define SSB_CHIPCO_BCAST_ADDR         0x0050
  #define  SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */
  #define  SSB_TMSLOW_CLOCK     0x00010000 /* Clock Enable */
  #define  SSB_TMSLOW_FGC               0x00020000 /* Force Gated Clocks On */
+@@ -432,6 +432,23 @@
+ #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
+ #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
+ #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
+ #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
+@@ -462,6 +479,46 @@
+ #define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
+ #define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
++
+ /* Values for SSB_SPROM1_BINF_CCODE */
+ enum {
+       SSB_SPROM1CCODE_WORLD = 0,
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -6,7 +6,7 @@
+  *
+  * Based on drivers/ssb/pcmcia.c
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  *
index b36bb5f..fa77868 100644 (file)
@@ -71,7 +71,7 @@
  obj-$(CONFIG_STAGING)         += staging/
 --- /dev/null
 +++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,57 @@
 +config BCMA_POSSIBLE
 +      bool
 +      depends on HAS_IOMEM && HAS_DMA
 +      help
 +        PCI core hostmode operation (external PCI bus).
 +
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
 +config BCMA_DEBUG
 +      bool "BCMA debugging"
 +      depends on BCMA
 +endmenu
 --- /dev/null
 +++ b/drivers/bcma/Makefile
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,10 @@
 +bcma-y                                        += main.o scan.o core.o sprom.o
 +bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
 +bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
 +bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
 +obj-$(CONFIG_BCMA)                    += bcma.o
 +
 +ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 +- Create kernel Documentation (use info from README)
 --- /dev/null
 +++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,54 @@
 +#ifndef LINUX_BCMA_PRIVATE_H_
 +#define LINUX_BCMA_PRIVATE_H_
 +
 +/* main.c */
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
 +
 +/* scan.c */
 +int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
 +
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
 +#ifdef CONFIG_BCMA_HOST_PCI
 +/* host_pci.c */
 +extern int __init bcma_host_pci_init(void);
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +EXPORT_SYMBOL(bcma_core_dma_translation);
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,156 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon core driver
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +      u32 leddc_on = 10;
 +      u32 leddc_off = 90;
 +
++      if (cc->setup_done)
++              return;
++
 +      if (cc->core->id.rev >= 11)
 +              cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 +      cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 +                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 +                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 +      }
++
++      cc->setup_done = true;
 +}
 +
 +/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 +{
 +      return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 +}
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- /dev/null
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -0,0 +1,138 @@
+@@ -0,0 +1,309 @@
 +/*
 + * Broadcom specific AMBA
 + * ChipCommon Power Management Unit driver
 + *
-+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
 + * Copyright 2007, Broadcom Corporation
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 +#include "bcma_private.h"
 +#include <linux/bcma/bcma.h>
 +
-+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-+                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 +{
-+      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
 +
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
 +      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
 +      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-+      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-+      value &= mask;
-+      value |= set;
-+      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-+      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
 +}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 +
 +static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 +{
 +      }
 +}
 +
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
 +void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 +{
 +      struct bcma_bus *bus = cc->core->bus;
 +              bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 +              break;
 +      case 0x4331:
-+              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 +              break;
 +      case 43224:
 +              if (bus->chipinfo.rev == 0) {
 +      bcma_pmu_swreg_init(cc);
 +      bcma_pmu_workarounds(cc);
 +}
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warn("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warn("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
 --- /dev/null
 +++ b/drivers/bcma/driver_pci.c
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,237 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Core
 + *
 + * Copyright 2005, Broadcom Corporation
-+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
 + *
 + * Licensed under the GNU/GPL. See COPYING for details.
 + */
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
 --- /dev/null
 +++ b/drivers/bcma/host_pci.c
-@@ -0,0 +1,251 @@
+@@ -0,0 +1,299 @@
 +/*
 + * Broadcom specific AMBA
 + * PCI Host
 +#include <linux/slab.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/pci.h>
++#include <linux/module.h>
 +
 +static void bcma_host_pci_switch_core(struct bcma_device *core)
 +{
 +      pr_debug("Switched to core: 0x%X\n", core->id.id);
 +}
 +
-+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
 +{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
 +      if (core->bus->mapped_core != core)
 +              bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread8(core->bus->mmio + offset);
 +}
 +
 +static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread16(core->bus->mmio + offset);
 +}
 +
 +static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      return ioread32(core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
 +                               u8 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite8(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
 +                               u16 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite16(value, core->bus->mmio + offset);
 +}
 +
 +static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 +                               u32 value)
 +{
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
 +      iowrite32(value, core->bus->mmio + offset);
 +}
 +
 +      pci_set_drvdata(dev, NULL);
 +}
 +
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
 +static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
 +      .id_table = bcma_pci_bridge_tbl,
 +      .probe = bcma_host_pci_probe,
 +      .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
 +};
 +
 +int __init bcma_host_pci_init(void)
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
 +static int bcma_bus_match(struct device *dev, struct device_driver *drv);
 +static int bcma_device_probe(struct device *dev);
 +static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
 +
 +static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
 +{
 +      .match          = bcma_bus_match,
 +      .probe          = bcma_device_probe,
 +      .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
 +      .dev_attrs      = bcma_device_attrs,
 +};
 +
 +static void bcma_release_core_dev(struct device *dev)
 +{
 +      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
 +      kfree(core);
 +}
 +
 +              case BCMA_CORE_CHIPCOMMON:
 +              case BCMA_CORE_PCI:
 +              case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
 +                      continue;
 +              }
 +
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
 +                      break;
-+              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
 +              case BCMA_HOSTTYPE_SDIO:
 +                      break;
 +              }
 +              bcma_core_chipcommon_init(&bus->drv_cc);
 +      }
 +
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
 +      /* Init PCIE core */
 +      core = bcma_find_core(bus, BCMA_CORE_PCIE);
 +      if (core) {
 +      bcma_unregister_cores(bus);
 +}
 +
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
 +{
 +      drv->drv.name = drv->name;
 +      return 0;
 +}
 +
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
 +static int __init bcma_modinit(void)
 +{
 +      int err;
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
 +      return addrl;
 +}
 +
-+int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
 +{
-+      u32 erombase;
-+      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
 +
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
 +      s32 cia, cib;
 +      u8 ports[2], wrappers[2];
 +
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
 +      s32 tmp;
-+      u8 i, j;
 +
-+      int err;
++      if (bus->init_done)
++              return;
 +
 +      INIT_LIST_HEAD(&bus->cores);
 +      bus->nr_cores = 0;
 +      bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
 +      bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
 +      bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
 +
 +      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
-+      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
 +      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
 +
 +      bcma_scan_switch_core(bus, erombase);
 +              INIT_LIST_HEAD(&core->list);
 +              core->bus = bus;
 +
-+              /* get CIs */
-+              cia = bcma_erom_get_ci(bus, &eromptr);
-+              if (cia < 0) {
-+                      bcma_erom_push_ent(&eromptr);
-+                      if (bcma_erom_is_end(bus, &eromptr))
-+                              break;
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+              cib = bcma_erom_get_ci(bus, &eromptr);
-+              if (cib < 0) {
-+                      err= -EILSEQ;
-+                      goto out;
-+              }
-+
-+              /* parse CIs */
-+              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
-+              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
-+              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
-+              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
-+              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
-+              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
-+              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
-+              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
-+
-+              if (((core->id.manuf == BCMA_MANUF_ARM) &&
-+                   (core->id.id == 0xFFF)) ||
-+                  (ports[1] == 0)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
 +                      continue;
-+              }
-+
-+              /* check if component is a core at all */
-+              if (wrappers[0] + wrappers[1] == 0) {
-+                      /* we could save addrl of the router
-+                      if (cid == BCMA_CORE_OOB_ROUTER)
-+                       */
-+                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
 +                      continue;
-+              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
 +
-+              if (bcma_erom_is_bridge(bus, &eromptr)) {
-+                      bcma_erom_skip_component(bus, &eromptr);
-+                      continue;
-+              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +
-+              /* get & parse master ports */
-+              for (i = 0; i < ports[0]; i++) {
-+                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
-+                      if (mst_port_d < 0) {
-+                              err= -EILSEQ;
-+                              goto out;
-+                      }
-+              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
 +
-+              /* get & parse slave ports */
-+              for (i = 0; i < ports[1]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SLAVE, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: slave port %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->addr = tmp;
-+                              }
-+                      }
-+              }
++              list_add(&core->list, &bus->cores);
++      }
 +
-+              /* get & parse master wrappers */
-+              for (i = 0; i < wrappers[0]; i++) {
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_MWRAP, i);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * "has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (i == 0 && j == 0)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
 +
-+              /* get & parse slave wrappers */
-+              for (i = 0; i < wrappers[1]; i++) {
-+                      u8 hack = (ports[1] == 1) ? 0 : 1;
-+                      for (j = 0; ; j++) {
-+                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
-+                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
-+                              if (tmp < 0) {
-+                                      /* no more entries for port _i_ */
-+                                      /* pr_debug("erom: master wrapper %d "
-+                                       * has %d descriptors\n", i, j); */
-+                                      break;
-+                              } else {
-+                                      if (wrappers[0] == 0 && !i && !j)
-+                                              core->wrap = tmp;
-+                              }
-+                      }
-+              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
 +
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
 +              pr_info("Core %d found: %s "
 +                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
-+                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
 +                      core->id.manuf, core->id.id, core->id.rev,
 +                      core->id.class);
 +
-+              core->core_index = bus->nr_cores++;
 +              list_add(&core->list, &bus->cores);
-+              continue;
-+out:
-+              return err;
++              err = 0;
++              break;
 +      }
 +
-+      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
 +}
 --- /dev/null
 +++ b/drivers/bcma/scan.h
 +#endif /* BCMA_SCAN_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,271 @@
+@@ -0,0 +1,298 @@
 +#ifndef LINUX_BCMA_H_
 +#define LINUX_BCMA_H_
 +
 +
 +#include <linux/bcma/bcma_driver_chipcommon.h>
 +#include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
 +
 +#include "bcma_regs.h"
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+      BCMA_HOSTTYPE_NONE,
 +      BCMA_HOSTTYPE_PCI,
 +      BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
 +
 +      struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
 +      bool dev_registered;
 +
 +      u32 addr;
 +      u32 wrap;
 +
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
 +      void *drvdata;
 +      struct list_head list;
 +};
 +};
 +extern
 +int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
-+static inline int bcma_driver_register(struct bcma_driver *drv)
-+{
-+      return __bcma_driver_register(drv, THIS_MODULE);
-+}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
 +extern void bcma_driver_unregister(struct bcma_driver *drv);
 +
 +struct bcma_bus {
 +      struct bcma_device *mapped_core;
 +      struct list_head cores;
 +      u8 nr_cores;
++      u8 init_done:1;
 +
 +      struct bcma_drv_cc drv_cc;
 +      struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
 +};
 +
-+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read8(core, offset);
 +}
-+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read16(core, offset);
 +}
-+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->read32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write8(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write16(core, offset, value);
 +}
-+extern inline
++static inline
 +void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->write32(core, offset, value);
 +}
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
-+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +{
 +      return core->bus->ops->aread32(core, offset);
 +}
-+extern inline
++static inline
 +void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
 +{
 +      core->bus->ops->awrite32(core, offset, value);
 +}
 +
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
 +extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
 +#endif /* LINUX_BCMA_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,296 @@
+@@ -0,0 +1,391 @@
 +#ifndef LINUX_BCMA_DRIVER_CC_H_
 +#define LINUX_BCMA_DRIVER_CC_H_
 +
 +#define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
 +#define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
 +#define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
 +#define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
 +#define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
 +#define   BCMA_PLLTYPE_NONE           0x00000000
 +#define BCMA_CC_PROG_CFG              0x0120
 +#define BCMA_CC_PROG_WAITCNT          0x0124
 +#define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
 +#define BCMA_CC_FLASH_WAITCNT         0x012C
 +/* 0x1E0 is defined as shared BCMA_CLKCTLST */
 +#define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
 +#define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
 +#define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
 +#define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
 +#define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
 +#define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
 +
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
 +/* Data for the PMU, if available.
 + * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
 + */
 +      u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 +};
 +
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
 +struct bcma_drv_cc {
 +      struct bcma_device *core;
 +      u32 status;
 +      u32 capabilities;
 +      u32 capabilities_ext;
++      u8 setup_done:1;
 +      /* Fast Powerup Delay constant */
 +      u16 fast_pwrup_delay;
 +      struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 +};
 +
 +/* Register access */
 +extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
 +extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
 +
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
 +extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
 +                                        u32 ticks);
 +
 +/* PMU support */
 +extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 +
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
 +#endif /* LINUX_BCMA_DRIVER_CC_H_ */
 --- /dev/null
 +++ b/include/linux/bcma/bcma_driver_pci.h
                         sizeof(struct virtio_device_id), "virtio",
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +{
 +      pr_err("No support for PCI core in hostmode yet\n");
 +}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
index 74e9c7f..32f5557 100644 (file)
@@ -1,5 +1,42 @@
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -5,12 +5,13 @@
+  * because of its small size we include it in the SSB core
+  * instead of creating a standalone module.
+  *
+- * Copyright 2007  Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007  Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_chipcommon.c
++++ b/drivers/ssb/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * Broadcom ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 --- a/drivers/ssb/driver_chipcommon_pmu.c
 +++ b/drivers/ssb/driver_chipcommon_pmu.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Broadcom ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
 @@ -417,9 +417,9 @@ static void ssb_pmu_resources_init(struc
        u32 min_msk = 0, max_msk = 0;
        unsigned int i;
  
        switch (bus->chip_id) {
        case 0x4312:
+--- a/drivers/ssb/driver_extif.c
++++ b/drivers/ssb/driver_extif.c
+@@ -3,7 +3,7 @@
+  * Broadcom EXTIF core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+  * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+  *
 --- a/drivers/ssb/driver_gige.c
 +++ b/drivers/ssb/driver_gige.c
+@@ -3,7 +3,7 @@
+  * Broadcom Gigabit Ethernet core driver
+  *
+  * Copyright 2008, Broadcom Corporation
+- * Copyright 2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -106,8 +106,9 @@ void gige_pcicfg_write32(struct ssb_gige
        gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
  }
  {
        struct ssb_gige *dev;
        u32 base, tmslow, tmshigh;
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -3,7 +3,7 @@
+  * Broadcom MIPS core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 --- a/drivers/ssb/driver_pcicore.c
 +++ b/drivers/ssb/driver_pcicore.c
+@@ -3,7 +3,7 @@
+  * Broadcom PCI-core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -314,7 +314,7 @@ int ssb_pcicore_pcibios_map_irq(const st
        return ssb_mips_irq(extpci_core->dev) + 2;
  }
  {
        u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
        if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
-@@ -514,7 +514,7 @@ static void ssb_pcicore_pcie_setup_worka
+@@ -514,12 +514,16 @@ static void ssb_pcicore_pcie_setup_worka
   * Generic and Clientmode operation code.
   **************************************************/
  
 -static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 +static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
  {
-       ssb_pcicore_fix_sprom_core_index(pc);
+-      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
  
-@@ -529,7 +529,7 @@ static void ssb_pcicore_init_clientmode(
+       /* Disable PCI interrupts. */
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
+       /* Additional PCIe always once-executed workarounds */
+       if (pc->dev->id.coreid == SSB_DEV_PCIE) {
+@@ -529,7 +533,7 @@ static void ssb_pcicore_init_clientmode(
        }
  }
  
  {
        struct ssb_device *dev = pc->dev;
  
+--- a/drivers/ssb/embedded.c
++++ b/drivers/ssb/embedded.c
+@@ -3,7 +3,7 @@
+  * Embedded systems support code
+  *
+  * Copyright 2005-2008, Broadcom Corporation
+- * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006-2008, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 --- a/drivers/ssb/main.c
 +++ b/drivers/ssb/main.c
-@@ -557,7 +557,7 @@ error:
+@@ -3,7 +3,7 @@
+  * Subsystem core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -12,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -557,7 +558,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
  {
        struct ssb_bus *bus, *n;
        int err = 0;
-@@ -768,9 +768,9 @@ out:
+@@ -768,9 +769,9 @@ out:
        return err;
  }
  
  {
        int err;
  
-@@ -851,8 +851,8 @@ err_disable_xtal:
+@@ -851,8 +852,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
  {
        int err;
  
-@@ -875,9 +875,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
+@@ -875,9 +876,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
  #endif /* CONFIG_SSB_PCIHOST */
  
  #ifdef CONFIG_SSB_PCMCIAHOST
  {
        int err;
  
-@@ -897,8 +897,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
+@@ -897,8 +898,9 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  #ifdef CONFIG_SSB_SDIOHOST
  {
        int err;
  
-@@ -918,9 +919,9 @@ int ssb_bus_sdiobus_register(struct ssb_
+@@ -918,9 +920,9 @@ int ssb_bus_sdiobus_register(struct ssb_
  EXPORT_SYMBOL(ssb_bus_sdiobus_register);
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
  {
        int err;
  
-@@ -1001,8 +1002,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
+@@ -1001,8 +1003,8 @@ u32 ssb_calc_clock_rate(u32 plltype, u32
        switch (plltype) {
        case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
                if (m & SSB_CHIPCO_CLK_T6_MMASK)
        case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
        case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
        case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
-@@ -1265,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_devic
+@@ -1259,13 +1261,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
        case SSB_BUSTYPE_SSB:
                return 0;
        case SSB_BUSTYPE_PCI:
 -              return SSB_PCI_DMA;
-+              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (pci_is_pcie(dev->bus->host_pci) &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
 +                      return SSB_PCIE_DMA_H32;
-+              else
-+                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
        default:
                __ssb_dma_not_implemented(dev);
        }
 --- a/drivers/ssb/pci.c
 +++ b/drivers/ssb/pci.c
-@@ -734,12 +734,9 @@ out_free:
+@@ -1,7 +1,7 @@
+ /*
+  * Sonics Silicon Backplane PCI-Hostbus related functions.
+  *
+- * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2006 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+@@ -607,6 +607,29 @@ static void sprom_extract_r8(struct ssb_
+       memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+              sizeof(out->antenna_gain.ghz5));
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
+       sprom_extract_r458(out, in);
+       /* TODO - get remaining rev 8 stuff needed */
+@@ -734,12 +757,9 @@ out_free:
  static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
                                  struct ssb_boardinfo *bi)
  {
  int ssb_pci_get_invariants(struct ssb_bus *bus,
 --- a/drivers/ssb/pcihost_wrapper.c
 +++ b/drivers/ssb/pcihost_wrapper.c
+@@ -6,7 +6,7 @@
+  * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+- * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
++ * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 @@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
  # define ssb_pcihost_resume   NULL
  #endif /* CONFIG_PM */
  {
        driver->probe = ssb_pcihost_probe;
        driver->remove = ssb_pcihost_remove;
+--- a/drivers/ssb/pcmcia.c
++++ b/drivers/ssb/pcmcia.c
+@@ -3,7 +3,7 @@
+  * PCMCIA-Hostbus related functions
+  *
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
 --- a/drivers/ssb/scan.c
 +++ b/drivers/ssb/scan.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Bus scanning
+  *
+- * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2007 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 @@ -310,8 +310,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
        } else {
                if (bus->bustype == SSB_BUSTYPE_PCI) {
                        bus->chip_package = 0;
                } else {
                        bus->chip_id = 0x4710;
+--- a/drivers/ssb/sdio.c
++++ b/drivers/ssb/sdio.c
+@@ -6,7 +6,7 @@
+  *
+  * Based on drivers/ssb/pcmcia.c
+  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+- * Copyright 2007-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright 2007-2008 Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  *
+--- a/drivers/ssb/sprom.c
++++ b/drivers/ssb/sprom.c
+@@ -2,7 +2,7 @@
+  * Sonics Silicon Backplane
+  * Common SPROM support routines
+  *
+- * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de>
++ * Copyright (C) 2005-2008 Michael Buesch <m@bues.ch>
+  * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
 --- a/include/linux/ssb/ssb.h
 +++ b/include/linux/ssb/ssb.h
-@@ -27,6 +27,8 @@ struct ssb_sprom {
+@@ -25,8 +25,10 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
        u8 et1mdcport;          /* MDIO for enet1 */
-       u8 board_rev;           /* Board revision number from SPROM. */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
        u8 country_code;        /* Country Code */
 +      u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
 +      u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
        u8 ant_available_a;     /* 2GHz antenna available bits (up to 4) */
        u8 ant_available_bg;    /* 5GHz antenna available bits (up to 4) */
        u16 pa0b0;
-@@ -99,7 +101,7 @@ struct ssb_sprom {
+@@ -92,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -99,7 +110,7 @@ struct ssb_sprom {
  struct ssb_boardinfo {
        u16 vendor;
        u16 type;
  };
  
  
+@@ -229,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -8,7 +8,7 @@
+  * gpio interface, extbus, and support for serial and parallel flashes.
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GPL version 2. See COPYING for details.
+  */
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -432,6 +432,23 @@
+ #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
+ #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
+ #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
+ #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
+@@ -462,6 +479,46 @@
+ #define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
+ #define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
++
+ /* Values for SSB_SPROM1_BINF_CCODE */
+ enum {
+       SSB_SPROM1CCODE_WORLD = 0,
index 5e6317f..95012ad 100644 (file)
@@ -12,7 +12,7 @@
  config BCMA_HOST_PCI_POSSIBLE
        bool
        depends on BCMA && PCI = y
-@@ -22,6 +27,12 @@ config BCMA_HOST_PCI
+@@ -22,6 +27,25 @@ config BCMA_HOST_PCI
        bool "Support for BCMA on PCI-host bus"
        depends on BCMA_HOST_PCI_POSSIBLE
  
 +      depends on BCMA && MIPS
 +      help
 +        PCI core hostmode operation (external PCI bus).
++
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
 +
  config BCMA_DEBUG
        bool "BCMA debugging"
        depends on BCMA
 --- a/drivers/bcma/Makefile
 +++ b/drivers/bcma/Makefile
-@@ -1,6 +1,7 @@
+@@ -1,7 +1,10 @@
 -bcma-y                                        += main.o scan.o core.o
 +bcma-y                                        += main.o scan.o core.o sprom.o
  bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
  bcma-y                                        += driver_pci.o
 +bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
  bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
  obj-$(CONFIG_BCMA)                    += bcma.o
  
+ ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
 --- a/drivers/bcma/bcma_private.h
 +++ b/drivers/bcma/bcma_private.h
-@@ -13,16 +13,23 @@
+@@ -13,11 +13,33 @@
  struct bcma_bus;
  
  /* main.c */
 -extern void bcma_bus_unregister(struct bcma_bus *bus);
 +int bcma_bus_register(struct bcma_bus *bus);
 +void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
  
  /* scan.c */
  int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
++
 +/* sprom.c */
 +int bcma_sprom_get(struct bcma_bus *bus);
 +
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
  #ifdef CONFIG_BCMA_HOST_PCI
  /* host_pci.c */
- extern int __init bcma_host_pci_init(void);
+@@ -25,4 +47,8 @@ extern int __init bcma_host_pci_init(voi
  extern void __exit bcma_host_pci_exit(void);
  #endif /* CONFIG_BCMA_HOST_PCI */
  
  
  int bcma_core_enable(struct bcma_device *core, u32 flags)
  {
-@@ -49,3 +50,75 @@ int bcma_core_enable(struct bcma_device
+@@ -49,3 +50,77 @@ int bcma_core_enable(struct bcma_device
        return 0;
  }
  EXPORT_SYMBOL_GPL(bcma_core_enable);
 +u32 bcma_core_dma_translation(struct bcma_device *core)
 +{
 +      switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
 +      case BCMA_HOSTTYPE_PCI:
 +              if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
 +                      return BCMA_DMA_TRANSLATION_DMA64_CMT;
 +      return BCMA_DMA_TRANSLATION_NONE;
 +}
 +EXPORT_SYMBOL(bcma_core_dma_translation);
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -3,7 +3,7 @@
+  * ChipCommon core driver
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -23,6 +23,12 @@ static inline u32 bcma_cc_write32_masked
+ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+ {
++      u32 leddc_on = 10;
++      u32 leddc_off = 90;
++
++      if (cc->setup_done)
++              return;
++
+       if (cc->core->id.rev >= 11)
+               cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+       cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
+@@ -38,6 +44,19 @@ void bcma_core_chipcommon_init(struct bc
+               bcma_pmu_init(cc);
+       if (cc->capabilities & BCMA_CC_CAP_PCTL)
+               pr_err("Power control not implemented!\n");
++
++      if (cc->core->id.rev >= 16) {
++              if (cc->core->bus->sprom.leddc_on_time &&
++                  cc->core->bus->sprom.leddc_off_time) {
++                      leddc_on = cc->core->bus->sprom.leddc_on_time;
++                      leddc_off = cc->core->bus->sprom.leddc_off_time;
++              }
++              bcma_cc_write32(cc, BCMA_CC_GPIOTIMER,
++                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
++                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
++      }
++
++      cc->setup_done = true;
+ }
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+@@ -87,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+ {
+       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+ }
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
 --- a/drivers/bcma/driver_chipcommon_pmu.c
 +++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -53,6 +53,7 @@ static void bcma_pmu_resources_init(stru
+@@ -2,7 +2,7 @@
+  * Broadcom specific AMBA
+  * ChipCommon Power Management Unit driver
+  *
+- * Copyright 2009, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2009, Michael Buesch <m@bues.ch>
+  * Copyright 2007, Broadcom Corporation
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+@@ -11,20 +11,47 @@
+ #include "bcma_private.h"
+ #include <linux/bcma/bcma.h>
+-static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+-                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ {
+-      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
+-      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
+       bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+       bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+-      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+-      value &= mask;
+-      value |= set;
+-      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
+-      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
+ static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
+ {
+@@ -53,6 +80,7 @@ static void bcma_pmu_resources_init(stru
                max_msk = 0xFFFF;
                break;
        case 43224:
                break;
        default:
                pr_err("PMU resource config unknown for device 0x%04X\n",
-@@ -74,6 +75,7 @@ void bcma_pmu_swreg_init(struct bcma_drv
+@@ -74,6 +102,7 @@ void bcma_pmu_swreg_init(struct bcma_drv
        case 0x4313:
        case 0x4331:
        case 43224:
                break;
        default:
                pr_err("PMU switch/regulators init unknown for device "
-@@ -96,11 +98,13 @@ void bcma_pmu_workarounds(struct bcma_dr
+@@ -81,6 +110,24 @@ void bcma_pmu_swreg_init(struct bcma_drv
+       }
+ }
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
+ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -90,17 +137,19 @@ void bcma_pmu_workarounds(struct bcma_dr
+               bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
+               break;
+       case 0x4331:
+-              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
+               break;
+       case 43224:
                if (bus->chipinfo.rev == 0) {
                        pr_err("Workarounds for 43224 rev 0 not fully "
                                "implemented\n");
        default:
                pr_err("Workarounds unknown for device 0x%04X\n",
                        bus->chipinfo.id);
+@@ -132,3 +181,129 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+       bcma_pmu_swreg_init(cc);
+       bcma_pmu_workarounds(cc);
+ }
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warn("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warn("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
 --- a/drivers/bcma/driver_pci.c
 +++ b/drivers/bcma/driver_pci.c
-@@ -157,7 +157,67 @@ static void bcma_pcicore_serdes_workarou
+@@ -3,7 +3,7 @@
+  * PCI Core
+  *
+  * Copyright 2005, Broadcom Corporation
+- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
+  *
+  * Licensed under the GNU/GPL. See COPYING for details.
+  */
+@@ -157,7 +157,81 @@ static void bcma_pcicore_serdes_workarou
   * Init.
   **************************************************/
  
 +          chipid_top != 0x5300)
 +              return false;
 +
-+      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++#ifdef CONFIG_SSB_DRIVER_PCICORE
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
 +              return false;
++#endif /* CONFIG_SSB_DRIVER_PCICORE */
 +
 +#if 0
 +      /* TODO: on BCMA we use address from EROM instead of magic formula */
 +
 +void bcma_core_pci_init(struct bcma_drv_pci *pc)
 +{
++      if (pc->setup_done)
++              return;
++
 +      if (bcma_core_pci_is_in_hostmode(pc)) {
 +#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
 +              bcma_core_pci_hostmode_init(pc);
 +      } else {
 +              bcma_core_pci_clientmode_init(pc);
 +      }
++
++      pc->setup_done = true;
 +}
 +
 +int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
 +{
 +      struct pci_dev *pdev = pc->core->bus->host_pci;
 +      u32 coremask, tmp;
-+      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
 +
 +      err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
 +      if (err)
 +      return err;
 +}
 +EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
+--- /dev/null
++++ b/drivers/bcma/driver_pci_host.c
+@@ -0,0 +1,14 @@
++/*
++ * Broadcom specific AMBA
++ * PCI Core in hostmode
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include <linux/bcma/bcma.h>
++
++void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
++{
++      pr_err("No support for PCI core in hostmode yet\n");
++}
 --- a/drivers/bcma/host_pci.c
 +++ b/drivers/bcma/host_pci.c
-@@ -65,6 +65,54 @@ static void bcma_host_pci_write32(struct
-       iowrite32(value, core->bus->mmio + offset);
+@@ -9,6 +9,7 @@
+ #include <linux/slab.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/pci.h>
++#include <linux/module.h>
+ static void bcma_host_pci_switch_core(struct bcma_device *core)
+ {
+@@ -20,50 +21,108 @@ static void bcma_host_pci_switch_core(st
+       pr_debug("Switched to core: 0x%X\n", core->id.id);
  }
  
+-static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
+-{
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
++{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
+       if (core->bus->mapped_core != core)
+               bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
+       return ioread8(core->bus->mmio + offset);
+ }
+ static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       return ioread16(core->bus->mmio + offset);
+ }
+ static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       return ioread32(core->bus->mmio + offset);
+ }
+ static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
+                                u8 value)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       iowrite8(value, core->bus->mmio + offset);
+ }
+ static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
+                                u16 value)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       iowrite16(value, core->bus->mmio + offset);
+ }
+ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
+                                u32 value)
+ {
++      offset += bcma_host_pci_provide_access_to_core(core);
++      iowrite32(value, core->bus->mmio + offset);
++}
++
 +#ifdef CONFIG_BCMA_BLOCKIO
 +void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
 +                            size_t count, u16 offset, u8 reg_width)
 +{
 +      void __iomem *addr = core->bus->mmio + offset;
-+      if (core->bus->mapped_core != core)
-+              bcma_host_pci_switch_core(core);
+       if (core->bus->mapped_core != core)
+               bcma_host_pci_switch_core(core);
+-      iowrite32(value, core->bus->mmio + offset);
 +      switch (reg_width) {
 +      case sizeof(u8):
 +              ioread8_rep(addr, buffer, count);
 +      default:
 +              WARN_ON(1);
 +      }
-+}
+ }
 +#endif
-+
  static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
  {
-       if (core->bus->mapped_core != core)
-@@ -87,6 +135,10 @@ const struct bcma_host_ops bcma_host_pci
+@@ -87,6 +146,10 @@ const struct bcma_host_ops bcma_host_pci
        .write8         = bcma_host_pci_write8,
        .write16        = bcma_host_pci_write16,
        .write32        = bcma_host_pci_write32,
        .aread32        = bcma_host_pci_aread32,
        .awrite32       = bcma_host_pci_awrite32,
  };
-@@ -175,6 +227,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+@@ -171,10 +234,46 @@ static void bcma_host_pci_remove(struct
+       pci_set_drvdata(dev, NULL);
+ }
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
+ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
        { 0, },
  };
+@@ -185,6 +284,8 @@ static struct pci_driver bcma_pci_bridge
+       .id_table = bcma_pci_bridge_tbl,
+       .probe = bcma_host_pci_probe,
+       .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
+ };
+ int __init bcma_host_pci_init(void)
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
 --- a/drivers/bcma/main.c
 +++ b/drivers/bcma/main.c
-@@ -7,6 +7,7 @@
+@@ -6,7 +6,9 @@
+  */
  
  #include "bcma_private.h"
++#include <linux/module.h>
  #include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
  
  MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
  MODULE_LICENSE("GPL");
-@@ -89,6 +90,8 @@ static int bcma_register_cores(struct bc
+@@ -14,6 +16,7 @@ MODULE_LICENSE("GPL");
+ static int bcma_bus_match(struct device *dev, struct device_driver *drv);
+ static int bcma_device_probe(struct device *dev);
+ static int bcma_device_remove(struct device *dev);
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
+ static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+@@ -48,6 +51,7 @@ static struct bus_type bcma_bus_type = {
+       .match          = bcma_bus_match,
+       .probe          = bcma_device_probe,
+       .remove         = bcma_device_remove,
++      .uevent         = bcma_device_uevent,
+       .dev_attrs      = bcma_device_attrs,
+ };
+@@ -65,6 +69,10 @@ static struct bcma_device *bcma_find_cor
+ static void bcma_release_core_dev(struct device *dev)
+ {
+       struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
+       kfree(core);
+ }
+@@ -79,6 +87,7 @@ static int bcma_register_cores(struct bc
+               case BCMA_CORE_CHIPCOMMON:
+               case BCMA_CORE_PCI:
+               case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
+                       continue;
+               }
+@@ -89,8 +98,13 @@ static int bcma_register_cores(struct bc
                switch (bus->hosttype) {
                case BCMA_HOSTTYPE_PCI:
                        core->dev.parent = &bus->host_pci->dev;
 +                      core->dma_dev = &bus->host_pci->dev;
 +                      core->irq = bus->host_pci->irq;
++                      break;
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
                        break;
-               case BCMA_HOSTTYPE_NONE:
+-              case BCMA_HOSTTYPE_NONE:
                case BCMA_HOSTTYPE_SDIO:
-@@ -144,6 +147,15 @@ int bcma_bus_register(struct bcma_bus *b
+                       break;
+               }
+@@ -137,6 +151,13 @@ int bcma_bus_register(struct bcma_bus *b
+               bcma_core_chipcommon_init(&bus->drv_cc);
+       }
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
+       /* Init PCIE core */
+       core = bcma_find_core(bus, BCMA_CORE_PCIE);
+       if (core) {
+@@ -144,6 +165,15 @@ int bcma_bus_register(struct bcma_bus *b
                bcma_core_pci_init(&bus->drv_pci);
        }
  
        /* Register found cores */
        bcma_register_cores(bus);
  
-@@ -151,13 +163,11 @@ int bcma_bus_register(struct bcma_bus *b
+@@ -151,13 +181,80 @@ int bcma_bus_register(struct bcma_bus *b
  
        return 0;
  }
        bcma_unregister_cores(bus);
  }
 -EXPORT_SYMBOL_GPL(bcma_bus_unregister);
++
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
  
  int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
  {
+@@ -217,6 +314,16 @@ static int bcma_device_remove(struct dev
+       return 0;
+ }
++static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++      struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++
++      return add_uevent_var(env,
++                            "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
++                            core->id.manuf, core->id.id,
++                            core->id.rev, core->id.class);
++}
++
+ static int __init bcma_modinit(void)
+ {
+       int err;
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -200,18 +200,162 @@ static s32 bcma_erom_get_addr_desc(struc
+       return addrl;
+ }
+-int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
+ {
+-      u32 erombase;
+-      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
++
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
+       s32 cia, cib;
+       u8 ports[2], wrappers[2];
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
+       s32 tmp;
+-      u8 i, j;
+-      int err;
++      if (bus->init_done)
++              return;
+       INIT_LIST_HEAD(&bus->cores);
+       bus->nr_cores = 0;
+@@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus)
+       bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
+       bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
+       bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
+       erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+-      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
+       eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+       bcma_scan_switch_core(bus, erombase);
+@@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus)
+               INIT_LIST_HEAD(&core->list);
+               core->bus = bus;
+-              /* get CIs */
+-              cia = bcma_erom_get_ci(bus, &eromptr);
+-              if (cia < 0) {
+-                      bcma_erom_push_ent(&eromptr);
+-                      if (bcma_erom_is_end(bus, &eromptr))
+-                              break;
+-                      err= -EILSEQ;
+-                      goto out;
+-              }
+-              cib = bcma_erom_get_ci(bus, &eromptr);
+-              if (cib < 0) {
+-                      err= -EILSEQ;
+-                      goto out;
+-              }
+-
+-              /* parse CIs */
+-              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+-              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+-              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+-              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+-              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+-              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+-              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+-              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+-
+-              if (((core->id.manuf == BCMA_MANUF_ARM) &&
+-                   (core->id.id == 0xFFF)) ||
+-                  (ports[1] == 0)) {
+-                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
+                       continue;
+-              }
+-
+-              /* check if component is a core at all */
+-              if (wrappers[0] + wrappers[1] == 0) {
+-                      /* we could save addrl of the router
+-                      if (cid == BCMA_CORE_OOB_ROUTER)
+-                       */
+-                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
+                       continue;
+-              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
+-              if (bcma_erom_is_bridge(bus, &eromptr)) {
+-                      bcma_erom_skip_component(bus, &eromptr);
+-                      continue;
+-              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
+-              /* get & parse master ports */
+-              for (i = 0; i < ports[0]; i++) {
+-                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
+-                      if (mst_port_d < 0) {
+-                              err= -EILSEQ;
+-                              goto out;
+-                      }
+-              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
+-              /* get & parse slave ports */
+-              for (i = 0; i < ports[1]; i++) {
+-                      for (j = 0; ; j++) {
+-                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+-                                      SCAN_ADDR_TYPE_SLAVE, i);
+-                              if (tmp < 0) {
+-                                      /* no more entries for port _i_ */
+-                                      /* pr_debug("erom: slave port %d "
+-                                       * "has %d descriptors\n", i, j); */
+-                                      break;
+-                              } else {
+-                                      if (i == 0 && j == 0)
+-                                              core->addr = tmp;
+-                              }
+-                      }
+-              }
++              list_add(&core->list, &bus->cores);
++      }
+-              /* get & parse master wrappers */
+-              for (i = 0; i < wrappers[0]; i++) {
+-                      for (j = 0; ; j++) {
+-                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+-                                      SCAN_ADDR_TYPE_MWRAP, i);
+-                              if (tmp < 0) {
+-                                      /* no more entries for port _i_ */
+-                                      /* pr_debug("erom: master wrapper %d "
+-                                       * "has %d descriptors\n", i, j); */
+-                                      break;
+-                              } else {
+-                                      if (i == 0 && j == 0)
+-                                              core->wrap = tmp;
+-                              }
+-                      }
+-              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
+-              /* get & parse slave wrappers */
+-              for (i = 0; i < wrappers[1]; i++) {
+-                      u8 hack = (ports[1] == 1) ? 0 : 1;
+-                      for (j = 0; ; j++) {
+-                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+-                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
+-                              if (tmp < 0) {
+-                                      /* no more entries for port _i_ */
+-                                      /* pr_debug("erom: master wrapper %d "
+-                                       * has %d descriptors\n", i, j); */
+-                                      break;
+-                              } else {
+-                                      if (wrappers[0] == 0 && !i && !j)
+-                                              core->wrap = tmp;
+-                              }
+-                      }
+-              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
+               pr_info("Core %d found: %s "
+                       "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+-                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
+                       core->id.manuf, core->id.id, core->id.rev,
+                       core->id.class);
+-              core->core_index = bus->nr_cores++;
+               list_add(&core->list, &bus->cores);
+-              continue;
+-out:
+-              return err;
++              err = 0;
++              break;
+       }
+-      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
+ }
 --- /dev/null
 +++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,171 @@
+@@ -0,0 +1,247 @@
 +/*
 + * Broadcom specific AMBA
 + * SPROM reading
 +      u16 v;
 +      int i;
 +
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
 +      for (i = 0; i < 3; i++) {
 +              v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
 +              *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
 +      }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
 +}
 +
 +int bcma_sprom_get(struct bcma_bus *bus)
 +      if (!sprom)
 +              return -ENOMEM;
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
 +      /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
 +       * According to brcm80211 this applies to cards with PCIe rev >= 6
 +       * TODO: understand this condition and use it */
 +              BCMA_CC_SPROM_PCIE6;
 +      bcma_sprom_read(bus, offset, sprom);
 +
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
 +      err = bcma_sprom_valid(sprom);
 +      if (err)
 +              goto out;
 +}
 --- a/include/linux/bcma/bcma.h
 +++ b/include/linux/bcma/bcma.h
-@@ -6,6 +6,7 @@
+@@ -6,6 +6,8 @@
  
  #include <linux/bcma/bcma_driver_chipcommon.h>
  #include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
 +#include <linux/ssb/ssb.h> /* SPROM sharing */
  
  #include "bcma_regs.h"
  
-@@ -24,6 +25,11 @@ struct bcma_chipinfo {
+@@ -13,9 +15,9 @@ struct bcma_device;
+ struct bcma_bus;
+ enum bcma_hosttype {
+-      BCMA_HOSTTYPE_NONE,
+       BCMA_HOSTTYPE_PCI,
+       BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
+ };
+ struct bcma_chipinfo {
+@@ -24,6 +26,11 @@ struct bcma_chipinfo {
        u8 pkg;
  };
  
  struct bcma_host_ops {
        u8 (*read8)(struct bcma_device *core, u16 offset);
        u16 (*read16)(struct bcma_device *core, u16 offset);
-@@ -31,6 +37,12 @@ struct bcma_host_ops {
+@@ -31,6 +38,12 @@ struct bcma_host_ops {
        void (*write8)(struct bcma_device *core, u16 offset, u8 value);
        void (*write16)(struct bcma_device *core, u16 offset, u16 value);
        void (*write32)(struct bcma_device *core, u16 offset, u32 value);
        /* Agent ops */
        u32 (*aread32)(struct bcma_device *core, u16 offset);
        void (*awrite32)(struct bcma_device *core, u16 offset, u32 value);
-@@ -117,6 +129,8 @@ struct bcma_device {
+@@ -117,6 +130,9 @@ struct bcma_device {
        struct bcma_device_id id;
  
        struct device dev;
 +      struct device *dma_dev;
++
 +      unsigned int irq;
        bool dev_registered;
  
        u8 core_index;
-@@ -179,6 +193,10 @@ struct bcma_bus {
+@@ -124,6 +140,9 @@ struct bcma_device {
+       u32 addr;
+       u32 wrap;
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
+       void *drvdata;
+       struct list_head list;
+ };
+@@ -151,10 +170,9 @@ struct bcma_driver {
+ };
+ extern
+ int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
+-static inline int bcma_driver_register(struct bcma_driver *drv)
+-{
+-      return __bcma_driver_register(drv, THIS_MODULE);
+-}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
+ extern void bcma_driver_unregister(struct bcma_driver *drv);
+ struct bcma_bus {
+@@ -176,49 +194,105 @@ struct bcma_bus {
+       struct bcma_device *mapped_core;
+       struct list_head cores;
+       u8 nr_cores;
++      u8 init_done:1;
  
        struct bcma_drv_cc drv_cc;
        struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
 +
 +      /* We decided to share SPROM struct with SSB as long as we do not need
 +       * any hacks for BCMA. This simplifies drivers code. */
 +      struct ssb_sprom sprom;
  };
  
- extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
-@@ -208,6 +226,18 @@ void bcma_write32(struct bcma_device *co
+-extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->read8(core, offset);
+ }
+-extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->read16(core, offset);
+ }
+-extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->read32(core, offset);
+ }
+-extern inline
++static inline
+ void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
+ {
+       core->bus->ops->write8(core, offset, value);
+ }
+-extern inline
++static inline
+ void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
+ {
+       core->bus->ops->write16(core, offset, value);
+ }
+-extern inline
++static inline
+ void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
  {
        core->bus->ops->write32(core, offset, value);
  }
+-extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 +#ifdef CONFIG_BCMA_BLOCKIO
-+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
 +                                 size_t count, u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_read(core, buffer, count, offset, reg_width);
 +}
-+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
-+                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
 +{
 +      core->bus->ops->block_write(core, buffer, count, offset, reg_width);
 +}
 +#endif
- extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
  {
        return core->bus->ops->aread32(core, offset);
-@@ -218,7 +248,24 @@ void bcma_awrite32(struct bcma_device *c
+ }
+-extern inline
++static inline
+ void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
+ {
        core->bus->ops->awrite32(core, offset, value);
  }
  
-+#define bcma_mask32(cc, offset, mask) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
-+#define bcma_set32(cc, offset, set) \
-+      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
-+#define bcma_maskset32(cc, offset, mask, set) \
-+      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
 +
  extern bool bcma_core_is_enabled(struct bcma_device *core);
 +extern void bcma_core_disable(struct bcma_device *core, u32 flags);
  #endif /* LINUX_BCMA_H_ */
 --- a/include/linux/bcma/bcma_driver_chipcommon.h
 +++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -179,15 +179,7 @@
+@@ -24,6 +24,7 @@
+ #define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
+ #define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
+ #define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
+ #define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
+ #define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
+ #define   BCMA_PLLTYPE_NONE           0x00000000
+@@ -178,16 +179,9 @@
+ #define BCMA_CC_PROG_CFG              0x0120
  #define BCMA_CC_PROG_WAITCNT          0x0124
  #define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
  #define BCMA_CC_FLASH_WAITCNT         0x012C
 -#define BCMA_CC_CLKCTLST              0x01E0 /* Clock control and status (rev >= 20) */
 -#define  BCMA_CC_CLKCTLST_FORCEALP    0x00000001 /* Force ALP request */
  #define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
  #define BCMA_CC_UART0_DATA            0x0300
  #define BCMA_CC_UART0_IMR             0x0304
-@@ -244,6 +236,8 @@
+@@ -209,6 +203,7 @@
+ #define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
+ #define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
+ #define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
+ #define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
+ #define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
+ #define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
+@@ -244,6 +239,66 @@
  #define BCMA_CC_REGCTL_DATA           0x065C
  #define BCMA_CC_PLLCTL_ADDR           0x0660
  #define BCMA_CC_PLLCTL_DATA           0x0664
 +#define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
 +#define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
++
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
  
  /* Data for the PMU, if available.
   * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+@@ -253,14 +308,37 @@ struct bcma_chipcommon_pmu {
+       u32 crystalfreq;        /* The active crystal frequency (in kHz) */
+ };
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
+ struct bcma_drv_cc {
+       struct bcma_device *core;
+       u32 status;
+       u32 capabilities;
+       u32 capabilities_ext;
++      u8 setup_done:1;
+       /* Fast Powerup Delay constant */
+       u16 fast_pwrup_delay;
+       struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
+ };
+ /* Register access */
+@@ -281,6 +359,8 @@ extern void bcma_core_chipcommon_init(st
+ extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
+ extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
+                                         u32 ticks);
+@@ -299,4 +379,13 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+ /* PMU support */
+ extern void bcma_pmu_init(struct bcma_drv_cc *cc);
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
 --- a/include/linux/bcma/bcma_driver_pci.h
 +++ b/include/linux/bcma/bcma_driver_pci.h
 @@ -85,5 +85,7 @@ struct bcma_drv_pci {
 +                               struct bcma_device *core, bool enable);
  
  #endif /* LINUX_BCMA_DRIVER_PCI_H_ */
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -23,6 +23,9 @@ static inline u32 bcma_cc_write32_masked
- void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
- {
-+      u32 leddc_on = 10;
-+      u32 leddc_off = 90;
-+
-       if (cc->core->id.rev >= 11)
-               cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
-       cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
-@@ -38,6 +41,17 @@ void bcma_core_chipcommon_init(struct bc
-               bcma_pmu_init(cc);
-       if (cc->capabilities & BCMA_CC_CAP_PCTL)
-               pr_err("Power control not implemented!\n");
-+
-+      if (cc->core->id.rev >= 16) {
-+              if (cc->core->bus->sprom.leddc_on_time &&
-+                  cc->core->bus->sprom.leddc_off_time) {
-+                      leddc_on = cc->core->bus->sprom.leddc_on_time;
-+                      leddc_off = cc->core->bus->sprom.leddc_off_time;
-+              }
-+              bcma_cc_write32(cc, BCMA_CC_GPIOTIMER,
-+                      ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
-+                       (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
-+      }
- }
- /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
---- /dev/null
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -0,0 +1,14 @@
-+/*
-+ * Broadcom specific AMBA
-+ * PCI Core in hostmode
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include "bcma_private.h"
-+#include <linux/bcma/bcma.h>
-+
-+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
-+{
-+      pr_err("No support for PCI core in hostmode yet\n");
-+}
 --- a/include/linux/bcma/bcma_regs.h
 +++ b/include/linux/bcma/bcma_regs.h
 @@ -1,13 +1,38 @@
  #define BCMA_RESET_CTL                        0x0800
  #define  BCMA_RESET_CTL_RESET         0x0001
  
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
diff --git a/target/linux/generic/patches-3.1/020-ssb_update.patch b/target/linux/generic/patches-3.1/020-ssb_update.patch
new file mode 100644 (file)
index 0000000..9dc63ad
--- /dev/null
@@ -0,0 +1,223 @@
+--- a/drivers/ssb/b43_pci_bridge.c
++++ b/drivers/ssb/b43_pci_bridge.c
+@@ -11,6 +11,7 @@
+  */
+ #include <linux/pci.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include "ssb_private.h"
+--- a/drivers/ssb/driver_pcicore.c
++++ b/drivers/ssb/driver_pcicore.c
+@@ -516,10 +516,14 @@ static void ssb_pcicore_pcie_setup_worka
+ static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+ {
+-      ssb_pcicore_fix_sprom_core_index(pc);
++      struct ssb_device *pdev = pc->dev;
++      struct ssb_bus *bus = pdev->bus;
++
++      if (bus->bustype == SSB_BUSTYPE_PCI)
++              ssb_pcicore_fix_sprom_core_index(pc);
+       /* Disable PCI interrupts. */
+-      ssb_write32(pc->dev, SSB_INTVEC, 0);
++      ssb_write32(pdev, SSB_INTVEC, 0);
+       /* Additional PCIe always once-executed workarounds */
+       if (pc->dev->id.coreid == SSB_DEV_PCIE) {
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -12,6 +12,7 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
++#include <linux/module.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_regs.h>
+ #include <linux/ssb/ssb_driver_gige.h>
+@@ -1260,16 +1261,34 @@ void ssb_device_disable(struct ssb_devic
+ }
+ EXPORT_SYMBOL(ssb_device_disable);
++/* Some chipsets need routing known for PCIe and 64-bit DMA */
++static bool ssb_dma_translation_special_bit(struct ssb_device *dev)
++{
++      u16 chip_id = dev->bus->chip_id;
++
++      if (dev->id.coreid == SSB_DEV_80211) {
++              return (chip_id == 0x4322 || chip_id == 43221 ||
++                      chip_id == 43231 || chip_id == 43222);
++      }
++
++      return 0;
++}
++
+ u32 ssb_dma_translation(struct ssb_device *dev)
+ {
+       switch (dev->bus->bustype) {
+       case SSB_BUSTYPE_SSB:
+               return 0;
+       case SSB_BUSTYPE_PCI:
+-              if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)
++              if (pci_is_pcie(dev->bus->host_pci) &&
++                  ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64) {
+                       return SSB_PCIE_DMA_H32;
+-              else
+-                      return SSB_PCI_DMA;
++              } else {
++                      if (ssb_dma_translation_special_bit(dev))
++                              return SSB_PCIE_DMA_H32;
++                      else
++                              return SSB_PCI_DMA;
++              }
+       default:
+               __ssb_dma_not_implemented(dev);
+       }
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -607,6 +607,29 @@ static void sprom_extract_r8(struct ssb_
+       memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+              sizeof(out->antenna_gain.ghz5));
++      /* Extract FEM info */
++      SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
++      SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT);
++      SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT);
++      SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT);
++      SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT);
++      SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
++              SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
++
+       sprom_extract_r458(out, in);
+       /* TODO - get remaining rev 8 stuff needed */
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -25,7 +25,7 @@ struct ssb_sprom {
+       u8 et1phyaddr;          /* MII address for enet1 */
+       u8 et0mdcport;          /* MDIO for enet0 */
+       u8 et1mdcport;          /* MDIO for enet1 */
+-      u8 board_rev;           /* Board revision number from SPROM. */
++      u16 board_rev;          /* Board revision number from SPROM. */
+       u8 country_code;        /* Country Code */
+       u16 leddc_on_time;      /* LED Powersave Duty Cycle On Count */
+       u16 leddc_off_time;     /* LED Powersave Duty Cycle Off Count */
+@@ -94,6 +94,15 @@ struct ssb_sprom {
+               } ghz5;         /* 5GHz band */
+       } antenna_gain;
++      struct {
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz2;
++              struct {
++                      u8 tssipos, extpa_gain, pdet_range, tr_iso, antswlut;
++              } ghz5;
++      } fem;
++
+       /* TODO - add any parameters needed from rev 2, 3, 4, 5 or 8 SPROMs */
+ };
+@@ -231,10 +240,9 @@ struct ssb_driver {
+ #define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
+ extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
+-static inline int ssb_driver_register(struct ssb_driver *drv)
+-{
+-      return __ssb_driver_register(drv, THIS_MODULE);
+-}
++#define ssb_driver_register(drv) \
++      __ssb_driver_register(drv, THIS_MODULE)
++
+ extern void ssb_driver_unregister(struct ssb_driver *drv);
+--- a/include/linux/ssb/ssb_regs.h
++++ b/include/linux/ssb/ssb_regs.h
+@@ -432,6 +432,23 @@
+ #define  SSB_SPROM8_RXPO2G            0x00FF  /* 2GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G            0xFF00  /* 5GHz RX power offset */
+ #define  SSB_SPROM8_RXPO5G_SHIFT      8
++#define SSB_SPROM8_FEM2G              0x00AE
++#define SSB_SPROM8_FEM5G              0x00B0
++#define  SSB_SROM8_FEM_TSSIPOS                0x0001
++#define  SSB_SROM8_FEM_TSSIPOS_SHIFT  0
++#define  SSB_SROM8_FEM_EXTPA_GAIN     0x0006
++#define  SSB_SROM8_FEM_EXTPA_GAIN_SHIFT       1
++#define  SSB_SROM8_FEM_PDET_RANGE     0x00F8
++#define  SSB_SROM8_FEM_PDET_RANGE_SHIFT       3
++#define  SSB_SROM8_FEM_TR_ISO         0x0700
++#define  SSB_SROM8_FEM_TR_ISO_SHIFT   8
++#define  SSB_SROM8_FEM_ANTSWLUT               0xF800
++#define  SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
++#define SSB_SPROM8_THERMAL            0x00B2
++#define SSB_SPROM8_MPWR_RAWTS         0x00B4
++#define SSB_SPROM8_TS_SLP_OPT_CORRX   0x00B6
++#define SSB_SPROM8_FOC_HWIQ_IQSWP     0x00B8
++#define SSB_SPROM8_PHYCAL_TEMPDELTA   0x00BA
+ #define SSB_SPROM8_MAXP_BG            0x00C0  /* Max Power 2GHz in path 1 */
+ #define  SSB_SPROM8_MAXP_BG_MASK      0x00FF  /* Mask for Max Power 2GHz */
+ #define  SSB_SPROM8_ITSSI_BG          0xFF00  /* Mask for path 1 itssi_bg */
+@@ -462,6 +479,46 @@
+ #define SSB_SPROM8_OFDM5GLPO          0x014A  /* 5.2GHz OFDM power offset */
+ #define SSB_SPROM8_OFDM5GHPO          0x014E  /* 5.8GHz OFDM power offset */
++/* Values for boardflags_lo read from SPROM */
++#define SSB_BFL_BTCOEXIST             0x0001  /* implements Bluetooth coexistance */
++#define SSB_BFL_PACTRL                        0x0002  /* GPIO 9 controlling the PA */
++#define SSB_BFL_AIRLINEMODE           0x0004  /* implements GPIO 13 radio disable indication */
++#define SSB_BFL_RSSI                  0x0008  /* software calculates nrssi slope. */
++#define SSB_BFL_ENETSPI                       0x0010  /* has ephy roboswitch spi */
++#define SSB_BFL_XTAL_NOSLOW           0x0020  /* no slow clock available */
++#define SSB_BFL_CCKHIPWR              0x0040  /* can do high power CCK transmission */
++#define SSB_BFL_ENETADM                       0x0080  /* has ADMtek switch */
++#define SSB_BFL_ENETVLAN              0x0100  /* can do vlan */
++#define SSB_BFL_AFTERBURNER           0x0200  /* supports Afterburner mode */
++#define SSB_BFL_NOPCI                 0x0400  /* board leaves PCI floating */
++#define SSB_BFL_FEM                   0x0800  /* supports the Front End Module */
++#define SSB_BFL_EXTLNA                        0x1000  /* has an external LNA */
++#define SSB_BFL_HGPA                  0x2000  /* had high gain PA */
++#define SSB_BFL_BTCMOD                        0x4000  /* BFL_BTCOEXIST is given in alternate GPIOs */
++#define SSB_BFL_ALTIQ                 0x8000  /* alternate I/Q settings */
++
++/* Values for boardflags_hi read from SPROM */
++#define SSB_BFH_NOPA                  0x0001  /* has no PA */
++#define SSB_BFH_RSSIINV                       0x0002  /* RSSI uses positive slope (not TSSI) */
++#define SSB_BFH_PAREF                 0x0004  /* uses the PARef LDO */
++#define SSB_BFH_3TSWITCH              0x0008  /* uses a triple throw switch shared with bluetooth */
++#define SSB_BFH_PHASESHIFT            0x0010  /* can support phase shifter */
++#define SSB_BFH_BUCKBOOST             0x0020  /* has buck/booster */
++#define SSB_BFH_FEM_BT                        0x0040  /* has FEM and switch to share antenna with bluetooth */
++
++/* Values for boardflags2_lo read from SPROM */
++#define SSB_BFL2_RXBB_INT_REG_DIS     0x0001  /* external RX BB regulator present */
++#define SSB_BFL2_APLL_WAR             0x0002  /* alternative A-band PLL settings implemented */
++#define SSB_BFL2_TXPWRCTRL_EN                 0x0004  /* permits enabling TX Power Control */
++#define SSB_BFL2_2X4_DIV              0x0008  /* 2x4 diversity switch */
++#define SSB_BFL2_5G_PWRGAIN           0x0010  /* supports 5G band power gain */
++#define SSB_BFL2_PCIEWAR_OVR          0x0020  /* overrides ASPM and Clkreq settings */
++#define SSB_BFL2_CAESERS_BRD          0x0040  /* is Caesers board (unused) */
++#define SSB_BFL2_BTC3WIRE             0x0080  /* used 3-wire bluetooth coexist */
++#define SSB_BFL2_SKWRKFEM_BRD         0x0100  /* 4321mcm93 uses Skyworks FEM */
++#define SSB_BFL2_SPUR_WAR             0x0200  /* has a workaround for clock-harmonic spurs */
++#define SSB_BFL2_GPLL_WAR             0x0400  /* altenative G-band PLL settings implemented */
++
+ /* Values for SSB_SPROM1_BINF_CCODE */
+ enum {
+       SSB_SPROM1CCODE_WORLD = 0,
diff --git a/target/linux/generic/patches-3.1/025-bcma_backport.patch b/target/linux/generic/patches-3.1/025-bcma_backport.patch
new file mode 100644 (file)
index 0000000..671c6ce
--- /dev/null
@@ -0,0 +1,2016 @@
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -33,6 +33,19 @@ config BCMA_DRIVER_PCI_HOSTMODE
+       help
+         PCI core hostmode operation (external PCI bus).
++config BCMA_HOST_SOC
++      bool
++      depends on BCMA_DRIVER_MIPS
++
++config BCMA_DRIVER_MIPS
++      bool "BCMA Broadcom MIPS core driver"
++      depends on BCMA && MIPS
++      help
++        Driver for the Broadcom MIPS core attached to Broadcom specific
++        Advanced Microcontroller Bus.
++
++        If unsure, say N
++
+ config BCMA_DEBUG
+       bool "BCMA debugging"
+       depends on BCMA
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -2,7 +2,9 @@ bcma-y                                 += main.o scan.o core.o sprom
+ bcma-y                                        += driver_chipcommon.o driver_chipcommon_pmu.o
+ bcma-y                                        += driver_pci.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)       += driver_pci_host.o
++bcma-$(CONFIG_BCMA_DRIVER_MIPS)               += driver_mips.o
+ bcma-$(CONFIG_BCMA_HOST_PCI)          += host_pci.o
++bcma-$(CONFIG_BCMA_HOST_SOC)          += host_soc.o
+ obj-$(CONFIG_BCMA)                    += bcma.o
+ ccflags-$(CONFIG_BCMA_DEBUG)          := -DDEBUG
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -15,13 +15,32 @@ struct bcma_bus;
+ /* main.c */
+ int bcma_bus_register(struct bcma_bus *bus);
+ void bcma_bus_unregister(struct bcma_bus *bus);
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips);
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus);
++#endif
+ /* scan.c */
+ int bcma_bus_scan(struct bcma_bus *bus);
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core);
++void bcma_init_bus(struct bcma_bus *bus);
+ /* sprom.c */
+ int bcma_sprom_get(struct bcma_bus *bus);
++/* driver_chipcommon.c */
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
++/* driver_chipcommon_pmu.c */
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
++
+ #ifdef CONFIG_BCMA_HOST_PCI
+ /* host_pci.c */
+ extern int __init bcma_host_pci_init(void);
+--- a/drivers/bcma/core.c
++++ b/drivers/bcma/core.c
+@@ -110,6 +110,8 @@ EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
+ u32 bcma_core_dma_translation(struct bcma_device *core)
+ {
+       switch (core->bus->hosttype) {
++      case BCMA_HOSTTYPE_SOC:
++              return 0;
+       case BCMA_HOSTTYPE_PCI:
+               if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
+                       return BCMA_DMA_TRANSLATION_DMA64_CMT;
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bc
+       u32 leddc_on = 10;
+       u32 leddc_off = 90;
++      if (cc->setup_done)
++              return;
++
+       if (cc->core->id.rev >= 11)
+               cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+       cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
+@@ -52,6 +55,8 @@ void bcma_core_chipcommon_init(struct bc
+                       ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
+                        (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
+       }
++
++      cc->setup_done = true;
+ }
+ /* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+@@ -101,3 +106,51 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+ {
+       return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+ }
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
++{
++      unsigned int irq;
++      u32 baud_base;
++      u32 i;
++      unsigned int ccrev = cc->core->id.rev;
++      struct bcma_serial_port *ports = cc->serial_ports;
++
++      if (ccrev >= 11 && ccrev != 15) {
++              /* Fixed ALP clock */
++              baud_base = bcma_pmu_alp_clock(cc);
++              if (ccrev >= 21) {
++                      /* Turn off UART clock before switching clocksource. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     & ~BCMA_CC_CORECTL_UARTCLKEN);
++              }
++              /* Set the override bit so we don't divide it */
++              bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                             bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                             | BCMA_CC_CORECTL_UARTCLK0);
++              if (ccrev >= 21) {
++                      /* Re-enable the UART clock. */
++                      bcma_cc_write32(cc, BCMA_CC_CORECTL,
++                                     bcma_cc_read32(cc, BCMA_CC_CORECTL)
++                                     | BCMA_CC_CORECTL_UARTCLKEN);
++              }
++      } else {
++              pr_err("serial not supported on this device ccrev: 0x%x\n",
++                     ccrev);
++              return;
++      }
++
++      irq = bcma_core_mips_irq(cc->core);
++
++      /* Determine the registers of the UARTs */
++      cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
++      for (i = 0; i < cc->nr_serial_ports; i++) {
++              ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
++                              (i * 256);
++              ports[i].irq = irq;
++              ports[i].baud_base = baud_base;
++              ports[i].reg_shift = 0;
++      }
++}
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -11,20 +11,47 @@
+ #include "bcma_private.h"
+ #include <linux/bcma/bcma.h>
+-static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+-                                      u32 offset, u32 mask, u32 set)
++static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+ {
+-      u32 value;
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
++}
+-      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
++void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
++
++void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                           u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
++
++void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                               u32 offset, u32 mask, u32 set)
++{
+       bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+       bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+-      value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+-      value &= mask;
+-      value |= set;
+-      bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
+-      bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
++      bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
+ }
++EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
++
++void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
++                              u32 set)
++{
++      bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
++      bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
++      bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
++}
++EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
+ static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
+ {
+@@ -83,6 +110,24 @@ void bcma_pmu_swreg_init(struct bcma_drv
+       }
+ }
++/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
++{
++      struct bcma_bus *bus = cc->core->bus;
++      u32 val;
++
++      val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
++      if (enable) {
++              val |= BCMA_CHIPCTL_4331_EXTPA_EN;
++              if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
++                      val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      } else {
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
++              val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
++      }
++      bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
++}
++
+ void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+ {
+       struct bcma_bus *bus = cc->core->bus;
+@@ -92,7 +137,7 @@ void bcma_pmu_workarounds(struct bcma_dr
+               bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
+               break;
+       case 0x4331:
+-              pr_err("Enabling Ext PA lines not implemented\n");
++              /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
+               break;
+       case 43224:
+               if (bus->chipinfo.rev == 0) {
+@@ -136,3 +181,129 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+       bcma_pmu_swreg_init(cc);
+       bcma_pmu_workarounds(cc);
+ }
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++      case 0x4313:
++      case 0x5357:
++      case 0x4749:
++      case 53572:
++              /* always 20Mhz */
++              return 20000 * 1000;
++      case 0x5356:
++      case 0x5300:
++              /* always 25Mhz */
++              return 25000 * 1000;
++      default:
++              pr_warn("No ALP clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
++      }
++      return BCMA_CC_PMU_ALP_CLOCK;
++}
++
++/* Find the output of the "m" pll divider given pll controls that start with
++ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
++ */
++static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
++{
++      u32 tmp, div, ndiv, p1, p2, fc;
++      struct bcma_bus *bus = cc->core->bus;
++
++      BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++
++      BUG_ON(!m || m > 4);
++
++      if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
++              /* Detect failure in clock setting */
++              tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
++              if (tmp & 0x40000)
++                      return 133 * 1000000;
++      }
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
++      p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
++      p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
++      div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
++              BCMA_CC_PPL_MDIV_MASK;
++
++      tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
++      ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
++
++      /* Do calculation in Mhz */
++      fc = bcma_pmu_alp_clock(cc) / 1000000;
++      fc = (p1 * ndiv * fc) / p2;
++
++      /* Return clock in Hertz */
++      return (fc / div) * 1000000;
++}
++
++/* query bus clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      switch (bus->chipinfo.id) {
++      case 0x4716:
++      case 0x4748:
++      case 47162:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5356:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5357:
++      case 0x4749:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 0x5300:
++              return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
++                                    BCMA_CC_PMU5_MAINPLL_SSB);
++      case 53572:
++              return 75000000;
++      default:
++              pr_warn("No backplane clock specified for %04X device, "
++                      "pmu rev. %d, using default %d Hz\n",
++                      bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
++      }
++      return BCMA_CC_PMU_HT_CLOCK;
++}
++
++/* query cpu clock frequency for PMU-enabled chipcommon */
++u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
++{
++      struct bcma_bus *bus = cc->core->bus;
++
++      if (bus->chipinfo.id == 53572)
++              return 300000000;
++
++      if (cc->pmu.rev >= 5) {
++              u32 pll;
++              switch (bus->chipinfo.id) {
++              case 0x5356:
++                      pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
++                      break;
++              case 0x5357:
++              case 0x4749:
++                      pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
++                      break;
++              default:
++                      pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
++                      break;
++              }
++
++              /* TODO: if (bus->chipinfo.id == 0x5300)
++                return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
++              return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
++      }
++
++      return bcma_pmu_get_clockcontrol(cc);
++}
+--- /dev/null
++++ b/drivers/bcma/driver_mips.c
+@@ -0,0 +1,256 @@
++/*
++ * Broadcom specific AMBA
++ * Broadcom MIPS32 74K core driver
++ *
++ * Copyright 2009, Broadcom Corporation
++ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
++ * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
++ * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++
++#include <linux/bcma/bcma.h>
++
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/time.h>
++
++/* The 47162a0 hangs when reading MIPS DMP registers registers */
++static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
++{
++      return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
++             dev->id.id == BCMA_CORE_MIPS_74K;
++}
++
++/* The 5357b0 hangs when reading USB20H DMP registers */
++static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
++{
++      return (dev->bus->chipinfo.id == 0x5357 ||
++              dev->bus->chipinfo.id == 0x4749) &&
++             dev->bus->chipinfo.pkg == 11 &&
++             dev->id.id == BCMA_CORE_USB20_HOST;
++}
++
++static inline u32 mips_read32(struct bcma_drv_mips *mcore,
++                            u16 offset)
++{
++      return bcma_read32(mcore->core, offset);
++}
++
++static inline void mips_write32(struct bcma_drv_mips *mcore,
++                              u16 offset,
++                              u32 value)
++{
++      bcma_write32(mcore->core, offset, value);
++}
++
++static const u32 ipsflag_irq_mask[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1,
++      BCMA_MIPS_IPSFLAG_IRQ2,
++      BCMA_MIPS_IPSFLAG_IRQ3,
++      BCMA_MIPS_IPSFLAG_IRQ4,
++};
++
++static const u32 ipsflag_irq_shift[] = {
++      0,
++      BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
++      BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
++};
++
++static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
++{
++      u32 flag;
++
++      if (bcma_core_mips_bcm47162a0_quirk(dev))
++              return dev->core_index;
++      if (bcma_core_mips_bcm5357b0_quirk(dev))
++              return dev->core_index;
++      flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
++
++      return flag & 0x1F;
++}
++
++/* Get the MIPS IRQ assignment for a specified device.
++ * If unassigned, 0 is returned.
++ */
++unsigned int bcma_core_mips_irq(struct bcma_device *dev)
++{
++      struct bcma_device *mdev = dev->bus->drv_mips.core;
++      u32 irqflag;
++      unsigned int irq;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++
++      for (irq = 1; irq <= 4; irq++)
++              if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
++                  (1 << irqflag))
++                      return irq;
++
++      return 0;
++}
++EXPORT_SYMBOL(bcma_core_mips_irq);
++
++static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
++{
++      unsigned int oldirq = bcma_core_mips_irq(dev);
++      struct bcma_bus *bus = dev->bus;
++      struct bcma_device *mdev = bus->drv_mips.core;
++      u32 irqflag;
++
++      irqflag = bcma_core_mips_irqflag(dev);
++      BUG_ON(oldirq == 6);
++
++      dev->irq = irq + 2;
++
++      /* clear the old irq */
++      if (oldirq == 0)
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
++                          ~(1 << irqflag));
++      else
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
++
++      /* assign the new one */
++      if (irq == 0) {
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
++                          bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
++                          (1 << irqflag));
++      } else {
++              u32 oldirqflag = bcma_read32(mdev,
++                                           BCMA_MIPS_MIPS74K_INTMASK(irq));
++              if (oldirqflag) {
++                      struct bcma_device *core;
++
++                      /* backplane irq line is in use, find out who uses
++                       * it and set user to irq 0
++                       */
++                      list_for_each_entry_reverse(core, &bus->cores, list) {
++                              if ((1 << bcma_core_mips_irqflag(core)) ==
++                                  oldirqflag) {
++                                      bcma_core_mips_set_irq(core, 0);
++                                      break;
++                              }
++                      }
++              }
++              bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
++                           1 << irqflag);
++      }
++
++      pr_info("set_irq: core 0x%04x, irq %d => %d\n",
++              dev->id.id, oldirq + 2, irq + 2);
++}
++
++static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
++{
++      int i;
++      static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
++      printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
++      for (i = 0; i <= 6; i++)
++              printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
++      printk("\n");
++}
++
++static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
++      }
++}
++
++u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
++              return bcma_pmu_get_clockcpu(&bus->drv_cc);
++
++      pr_err("No PMU available, need this to get the cpu clock\n");
++      return 0;
++}
++EXPORT_SYMBOL(bcma_cpu_clock);
++
++static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus = mcore->core->bus;
++
++      switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++      case BCMA_CC_FLASHT_STSER:
++      case BCMA_CC_FLASHT_ATSER:
++              pr_err("Serial flash not supported.\n");
++              break;
++      case BCMA_CC_FLASHT_PARA:
++              pr_info("found parallel flash.\n");
++              bus->drv_cc.pflash.window = 0x1c000000;
++              bus->drv_cc.pflash.window_size = 0x02000000;
++
++              if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++                   BCMA_CC_FLASH_CFG_DS) == 0)
++                      bus->drv_cc.pflash.buswidth = 1;
++              else
++                      bus->drv_cc.pflash.buswidth = 2;
++              break;
++      default:
++              pr_err("flash not supported.\n");
++      }
++}
++
++void bcma_core_mips_init(struct bcma_drv_mips *mcore)
++{
++      struct bcma_bus *bus;
++      struct bcma_device *core;
++      bus = mcore->core->bus;
++
++      pr_info("Initializing MIPS core...\n");
++
++      if (!mcore->setup_done)
++              mcore->assigned_irqs = 1;
++
++      /* Assign IRQs to all cores on the bus */
++      list_for_each_entry_reverse(core, &bus->cores, list) {
++              int mips_irq;
++              if (core->irq)
++                      continue;
++
++              mips_irq = bcma_core_mips_irq(core);
++              if (mips_irq > 4)
++                      core->irq = 0;
++              else
++                      core->irq = mips_irq + 2;
++              if (core->irq > 5)
++                      continue;
++              switch (core->id.id) {
++              case BCMA_CORE_PCI:
++              case BCMA_CORE_PCIE:
++              case BCMA_CORE_ETHERNET:
++              case BCMA_CORE_ETHERNET_GBIT:
++              case BCMA_CORE_MAC_GBIT:
++              case BCMA_CORE_80211:
++              case BCMA_CORE_USB20_HOST:
++                      /* These devices get their own IRQ line if available,
++                       * the rest goes on IRQ0
++                       */
++                      if (mcore->assigned_irqs <= 4)
++                              bcma_core_mips_set_irq(core,
++                                                     mcore->assigned_irqs++);
++                      break;
++              }
++      }
++      pr_info("IRQ reconfiguration done\n");
++      bcma_core_mips_dump_irq(bus);
++
++      if (mcore->setup_done)
++              return;
++
++      bcma_chipco_serial_init(&bus->drv_cc);
++      bcma_core_mips_flash_detect(mcore);
++      mcore->setup_done = true;
++}
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -173,7 +173,7 @@ static bool bcma_core_pci_is_in_hostmode
+               return false;
+ #ifdef CONFIG_SSB_DRIVER_PCICORE
+-      if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++      if (bus->sprom.boardflags_lo & SSB_BFL_NOPCI)
+               return false;
+ #endif /* CONFIG_SSB_DRIVER_PCICORE */
+@@ -189,6 +189,9 @@ static bool bcma_core_pci_is_in_hostmode
+ void bcma_core_pci_init(struct bcma_drv_pci *pc)
+ {
++      if (pc->setup_done)
++              return;
++
+       if (bcma_core_pci_is_in_hostmode(pc)) {
+ #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
+               bcma_core_pci_hostmode_init(pc);
+@@ -198,6 +201,8 @@ void bcma_core_pci_init(struct bcma_drv_
+       } else {
+               bcma_core_pci_clientmode_init(pc);
+       }
++
++      pc->setup_done = true;
+ }
+ int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+@@ -205,7 +210,14 @@ int bcma_core_pci_irq_ctl(struct bcma_dr
+ {
+       struct pci_dev *pdev = pc->core->bus->host_pci;
+       u32 coremask, tmp;
+-      int err;
++      int err = 0;
++
++      if (core->bus->hosttype != BCMA_HOSTTYPE_PCI) {
++              /* This bcma device is not on a PCI host-bus. So the IRQs are
++               * not routed through the PCI core.
++               * So we must not enable routing through the PCI core. */
++              goto out;
++      }
+       err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
+       if (err)
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -9,6 +9,7 @@
+ #include <linux/slab.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/pci.h>
++#include <linux/module.h>
+ static void bcma_host_pci_switch_core(struct bcma_device *core)
+ {
+@@ -20,48 +21,58 @@ static void bcma_host_pci_switch_core(st
+       pr_debug("Switched to core: 0x%X\n", core->id.id);
+ }
+-static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
+-{
++/* Provides access to the requested core. Returns base offset that has to be
++ * used. It makes use of fixed windows when possible. */
++static u16 bcma_host_pci_provide_access_to_core(struct bcma_device *core)
++{
++      switch (core->id.id) {
++      case BCMA_CORE_CHIPCOMMON:
++              return 3 * BCMA_CORE_SIZE;
++      case BCMA_CORE_PCIE:
++              return 2 * BCMA_CORE_SIZE;
++      }
++
+       if (core->bus->mapped_core != core)
+               bcma_host_pci_switch_core(core);
++      return 0;
++}
++
++static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
++{
++      offset += bcma_host_pci_provide_access_to_core(core);
+       return ioread8(core->bus->mmio + offset);
+ }
+ static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       return ioread16(core->bus->mmio + offset);
+ }
+ static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       return ioread32(core->bus->mmio + offset);
+ }
+ static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
+                                u8 value)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       iowrite8(value, core->bus->mmio + offset);
+ }
+ static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
+                                u16 value)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       iowrite16(value, core->bus->mmio + offset);
+ }
+ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
+                                u32 value)
+ {
+-      if (core->bus->mapped_core != core)
+-              bcma_host_pci_switch_core(core);
++      offset += bcma_host_pci_provide_access_to_core(core);
+       iowrite32(value, core->bus->mmio + offset);
+ }
+@@ -223,6 +234,41 @@ static void bcma_host_pci_remove(struct
+       pci_set_drvdata(dev, NULL);
+ }
++#ifdef CONFIG_PM
++static int bcma_host_pci_suspend(struct pci_dev *dev, pm_message_t state)
++{
++      /* Host specific */
++      pci_save_state(dev);
++      pci_disable_device(dev);
++      pci_set_power_state(dev, pci_choose_state(dev, state));
++
++      return 0;
++}
++
++static int bcma_host_pci_resume(struct pci_dev *dev)
++{
++      struct bcma_bus *bus = pci_get_drvdata(dev);
++      int err;
++
++      /* Host specific */
++      pci_set_power_state(dev, 0);
++      err = pci_enable_device(dev);
++      if (err)
++              return err;
++      pci_restore_state(dev);
++
++      /* Bus specific */
++      err = bcma_bus_resume(bus);
++      if (err)
++              return err;
++
++      return 0;
++}
++#else /* CONFIG_PM */
++# define bcma_host_pci_suspend        NULL
++# define bcma_host_pci_resume NULL
++#endif /* CONFIG_PM */
++
+ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
+@@ -238,6 +284,8 @@ static struct pci_driver bcma_pci_bridge
+       .id_table = bcma_pci_bridge_tbl,
+       .probe = bcma_host_pci_probe,
+       .remove = bcma_host_pci_remove,
++      .suspend = bcma_host_pci_suspend,
++      .resume = bcma_host_pci_resume,
+ };
+ int __init bcma_host_pci_init(void)
+--- /dev/null
++++ b/drivers/bcma/host_soc.c
+@@ -0,0 +1,183 @@
++/*
++ * Broadcom specific AMBA
++ * System on Chip (SoC) Host
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include "bcma_private.h"
++#include "scan.h"
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
++
++static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset)
++{
++      return readb(core->io_addr + offset);
++}
++
++static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset)
++{
++      return readw(core->io_addr + offset);
++}
++
++static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_addr + offset);
++}
++
++static void bcma_host_soc_write8(struct bcma_device *core, u16 offset,
++                               u8 value)
++{
++      writeb(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write16(struct bcma_device *core, u16 offset,
++                               u16 value)
++{
++      writew(value, core->io_addr + offset);
++}
++
++static void bcma_host_soc_write32(struct bcma_device *core, u16 offset,
++                               u32 value)
++{
++      writel(value, core->io_addr + offset);
++}
++
++#ifdef CONFIG_BCMA_BLOCKIO
++static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer,
++                                   size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              u8 *buf = buffer;
++
++              while (count) {
++                      *buf = __raw_readb(addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      *buf = (__force __le16)__raw_readw(addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      *buf = (__force __le32)__raw_readl(addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++
++static void bcma_host_soc_block_write(struct bcma_device *core,
++                                    const void *buffer,
++                                    size_t count, u16 offset, u8 reg_width)
++{
++      void __iomem *addr = core->io_addr + offset;
++
++      switch (reg_width) {
++      case sizeof(u8): {
++              const u8 *buf = buffer;
++
++              while (count) {
++                      __raw_writeb(*buf, addr);
++                      buf++;
++                      count--;
++              }
++              break;
++      }
++      case sizeof(u16): {
++              const __le16 *buf = buffer;
++
++              WARN_ON(count & 1);
++              while (count) {
++                      __raw_writew((__force u16)(*buf), addr);
++                      buf++;
++                      count -= 2;
++              }
++              break;
++      }
++      case sizeof(u32): {
++              const __le32 *buf = buffer;
++
++              WARN_ON(count & 3);
++              while (count) {
++                      __raw_writel((__force u32)(*buf), addr);
++                      buf++;
++                      count -= 4;
++              }
++              break;
++      }
++      default:
++              WARN_ON(1);
++      }
++}
++#endif /* CONFIG_BCMA_BLOCKIO */
++
++static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
++{
++      return readl(core->io_wrap + offset);
++}
++
++static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
++                                u32 value)
++{
++      writel(value, core->io_wrap + offset);
++}
++
++const struct bcma_host_ops bcma_host_soc_ops = {
++      .read8          = bcma_host_soc_read8,
++      .read16         = bcma_host_soc_read16,
++      .read32         = bcma_host_soc_read32,
++      .write8         = bcma_host_soc_write8,
++      .write16        = bcma_host_soc_write16,
++      .write32        = bcma_host_soc_write32,
++#ifdef CONFIG_BCMA_BLOCKIO
++      .block_read     = bcma_host_soc_block_read,
++      .block_write    = bcma_host_soc_block_write,
++#endif
++      .aread32        = bcma_host_soc_aread32,
++      .awrite32       = bcma_host_soc_awrite32,
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc)
++{
++      struct bcma_bus *bus = &soc->bus;
++      int err;
++
++      /* iomap only first core. We have to read some register on this core
++       * to scan the bus.
++       */
++      bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++      if (!bus->mmio)
++              return -ENOMEM;
++
++      /* Host specific */
++      bus->hosttype = BCMA_HOSTTYPE_SOC;
++      bus->ops = &bcma_host_soc_ops;
++
++      /* Register */
++      err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++      if (err)
++              iounmap(bus->mmio);
++
++      return err;
++}
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -6,6 +6,7 @@
+  */
+ #include "bcma_private.h"
++#include <linux/module.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/slab.h>
+@@ -68,6 +69,10 @@ static struct bcma_device *bcma_find_cor
+ static void bcma_release_core_dev(struct device *dev)
+ {
+       struct bcma_device *core = container_of(dev, struct bcma_device, dev);
++      if (core->io_addr)
++              iounmap(core->io_addr);
++      if (core->io_wrap)
++              iounmap(core->io_wrap);
+       kfree(core);
+ }
+@@ -82,6 +87,7 @@ static int bcma_register_cores(struct bc
+               case BCMA_CORE_CHIPCOMMON:
+               case BCMA_CORE_PCI:
+               case BCMA_CORE_PCIE:
++              case BCMA_CORE_MIPS_74K:
+                       continue;
+               }
+@@ -95,7 +101,10 @@ static int bcma_register_cores(struct bc
+                       core->dma_dev = &bus->host_pci->dev;
+                       core->irq = bus->host_pci->irq;
+                       break;
+-              case BCMA_HOSTTYPE_NONE:
++              case BCMA_HOSTTYPE_SOC:
++                      core->dev.dma_mask = &core->dev.coherent_dma_mask;
++                      core->dma_dev = &core->dev;
++                      break;
+               case BCMA_HOSTTYPE_SDIO:
+                       break;
+               }
+@@ -142,6 +151,13 @@ int bcma_bus_register(struct bcma_bus *b
+               bcma_core_chipcommon_init(&bus->drv_cc);
+       }
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
+       /* Init PCIE core */
+       core = bcma_find_core(bus, BCMA_CORE_PCIE);
+       if (core) {
+@@ -171,6 +187,75 @@ void bcma_bus_unregister(struct bcma_bus
+       bcma_unregister_cores(bus);
+ }
++int __init bcma_bus_early_register(struct bcma_bus *bus,
++                                 struct bcma_device *core_cc,
++                                 struct bcma_device *core_mips)
++{
++      int err;
++      struct bcma_device *core;
++      struct bcma_device_id match;
++
++      bcma_init_bus(bus);
++
++      match.manuf = BCMA_MANUF_BCM;
++      match.id = BCMA_CORE_CHIPCOMMON;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for chip common core */
++      err = bcma_bus_scan_early(bus, &match, core_cc);
++      if (err) {
++              pr_err("Failed to scan for common core: %d\n", err);
++              return -1;
++      }
++
++      match.manuf = BCMA_MANUF_MIPS;
++      match.id = BCMA_CORE_MIPS_74K;
++      match.class = BCMA_CL_SIM;
++      match.rev = BCMA_ANY_REV;
++
++      /* Scan for mips core */
++      err = bcma_bus_scan_early(bus, &match, core_mips);
++      if (err) {
++              pr_err("Failed to scan for mips core: %d\n", err);
++              return -1;
++      }
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.core = core;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      /* Init MIPS core */
++      core = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++      if (core) {
++              bus->drv_mips.core = core;
++              bcma_core_mips_init(&bus->drv_mips);
++      }
++
++      pr_info("Early bus registered\n");
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++int bcma_bus_resume(struct bcma_bus *bus)
++{
++      struct bcma_device *core;
++
++      /* Init CC core */
++      core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++      if (core) {
++              bus->drv_cc.setup_done = false;
++              bcma_core_chipcommon_init(&bus->drv_cc);
++      }
++
++      return 0;
++}
++#endif
++
+ int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
+ {
+       drv->drv.name = drv->name;
+--- a/drivers/bcma/scan.c
++++ b/drivers/bcma/scan.c
+@@ -200,18 +200,162 @@ static s32 bcma_erom_get_addr_desc(struc
+       return addrl;
+ }
+-int bcma_bus_scan(struct bcma_bus *bus)
++static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
++                                                 u16 index)
+ {
+-      u32 erombase;
+-      u32 __iomem *eromptr, *eromend;
++      struct bcma_device *core;
++      list_for_each_entry(core, &bus->cores, list) {
++              if (core->core_index == index)
++                      return core;
++      }
++      return NULL;
++}
++
++static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
++                            struct bcma_device_id *match, int core_num,
++                            struct bcma_device *core)
++{
++      s32 tmp;
++      u8 i, j;
+       s32 cia, cib;
+       u8 ports[2], wrappers[2];
++      /* get CIs */
++      cia = bcma_erom_get_ci(bus, eromptr);
++      if (cia < 0) {
++              bcma_erom_push_ent(eromptr);
++              if (bcma_erom_is_end(bus, eromptr))
++                      return -ESPIPE;
++              return -EILSEQ;
++      }
++      cib = bcma_erom_get_ci(bus, eromptr);
++      if (cib < 0)
++              return -EILSEQ;
++
++      /* parse CIs */
++      core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
++      core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
++      core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
++      ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
++      ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
++      wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
++      wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
++      core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
++
++      if (((core->id.manuf == BCMA_MANUF_ARM) &&
++           (core->id.id == 0xFFF)) ||
++          (ports[1] == 0)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      /* check if component is a core at all */
++      if (wrappers[0] + wrappers[1] == 0) {
++              /* we could save addrl of the router
++              if (cid == BCMA_CORE_OOB_ROUTER)
++               */
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_erom_is_bridge(bus, eromptr)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENXIO;
++      }
++
++      if (bcma_find_core_by_index(bus, core_num)) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      if (match && ((match->manuf != BCMA_ANY_MANUF &&
++            match->manuf != core->id.manuf) ||
++           (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
++           (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
++           (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
++          )) {
++              bcma_erom_skip_component(bus, eromptr);
++              return -ENODEV;
++      }
++
++      /* get & parse master ports */
++      for (i = 0; i < ports[0]; i++) {
++              s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
++              if (mst_port_d < 0)
++                      return -EILSEQ;
++      }
++
++      /* get & parse slave ports */
++      for (i = 0; i < ports[1]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SLAVE, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: slave port %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->addr = tmp;
++                      }
++              }
++      }
++
++      /* get & parse master wrappers */
++      for (i = 0; i < wrappers[0]; i++) {
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_MWRAP, i);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * "has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (i == 0 && j == 0)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++
++      /* get & parse slave wrappers */
++      for (i = 0; i < wrappers[1]; i++) {
++              u8 hack = (ports[1] == 1) ? 0 : 1;
++              for (j = 0; ; j++) {
++                      tmp = bcma_erom_get_addr_desc(bus, eromptr,
++                              SCAN_ADDR_TYPE_SWRAP, i + hack);
++                      if (tmp < 0) {
++                              /* no more entries for port _i_ */
++                              /* pr_debug("erom: master wrapper %d "
++                               * has %d descriptors\n", i, j); */
++                              break;
++                      } else {
++                              if (wrappers[0] == 0 && !i && !j)
++                                      core->wrap = tmp;
++                      }
++              }
++      }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
++              if (!core->io_addr)
++                      return -ENOMEM;
++              core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++              if (!core->io_wrap) {
++                      iounmap(core->io_addr);
++                      return -ENOMEM;
++              }
++      }
++      return 0;
++}
++
++void bcma_init_bus(struct bcma_bus *bus)
++{
+       s32 tmp;
+-      u8 i, j;
+-      int err;
++      if (bus->init_done)
++              return;
+       INIT_LIST_HEAD(&bus->cores);
+       bus->nr_cores = 0;
+@@ -222,9 +366,27 @@ int bcma_bus_scan(struct bcma_bus *bus)
+       bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
+       bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
+       bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
++      bus->init_done = true;
++}
++
++int bcma_bus_scan(struct bcma_bus *bus)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++
++      int err, core_num = 0;
++
++      bcma_init_bus(bus);
+       erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+-      eromptr = bus->mmio;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
+       eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+       bcma_scan_switch_core(bus, erombase);
+@@ -236,125 +398,89 @@ int bcma_bus_scan(struct bcma_bus *bus)
+               INIT_LIST_HEAD(&core->list);
+               core->bus = bus;
+-              /* get CIs */
+-              cia = bcma_erom_get_ci(bus, &eromptr);
+-              if (cia < 0) {
+-                      bcma_erom_push_ent(&eromptr);
+-                      if (bcma_erom_is_end(bus, &eromptr))
+-                              break;
+-                      err= -EILSEQ;
+-                      goto out;
+-              }
+-              cib = bcma_erom_get_ci(bus, &eromptr);
+-              if (cib < 0) {
+-                      err= -EILSEQ;
+-                      goto out;
+-              }
+-
+-              /* parse CIs */
+-              core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+-              core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+-              core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+-              ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+-              ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+-              wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+-              wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+-              core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+-
+-              if (((core->id.manuf == BCMA_MANUF_ARM) &&
+-                   (core->id.id == 0xFFF)) ||
+-                  (ports[1] == 0)) {
+-                      bcma_erom_skip_component(bus, &eromptr);
++              err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
+                       continue;
+-              }
+-
+-              /* check if component is a core at all */
+-              if (wrappers[0] + wrappers[1] == 0) {
+-                      /* we could save addrl of the router
+-                      if (cid == BCMA_CORE_OOB_ROUTER)
+-                       */
+-                      bcma_erom_skip_component(bus, &eromptr);
++              } else if (err == -ENXIO)
+                       continue;
+-              }
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
+-              if (bcma_erom_is_bridge(bus, &eromptr)) {
+-                      bcma_erom_skip_component(bus, &eromptr);
+-                      continue;
+-              }
++              core->core_index = core_num++;
++              bus->nr_cores++;
+-              /* get & parse master ports */
+-              for (i = 0; i < ports[0]; i++) {
+-                      u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
+-                      if (mst_port_d < 0) {
+-                              err= -EILSEQ;
+-                              goto out;
+-                      }
+-              }
++              pr_info("Core %d found: %s "
++                      "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
++                      core->core_index, bcma_device_name(&core->id),
++                      core->id.manuf, core->id.id, core->id.rev,
++                      core->id.class);
+-              /* get & parse slave ports */
+-              for (i = 0; i < ports[1]; i++) {
+-                      for (j = 0; ; j++) {
+-                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+-                                      SCAN_ADDR_TYPE_SLAVE, i);
+-                              if (tmp < 0) {
+-                                      /* no more entries for port _i_ */
+-                                      /* pr_debug("erom: slave port %d "
+-                                       * "has %d descriptors\n", i, j); */
+-                                      break;
+-                              } else {
+-                                      if (i == 0 && j == 0)
+-                                              core->addr = tmp;
+-                              }
+-                      }
+-              }
++              list_add(&core->list, &bus->cores);
++      }
+-              /* get & parse master wrappers */
+-              for (i = 0; i < wrappers[0]; i++) {
+-                      for (j = 0; ; j++) {
+-                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+-                                      SCAN_ADDR_TYPE_MWRAP, i);
+-                              if (tmp < 0) {
+-                                      /* no more entries for port _i_ */
+-                                      /* pr_debug("erom: master wrapper %d "
+-                                       * "has %d descriptors\n", i, j); */
+-                                      break;
+-                              } else {
+-                                      if (i == 0 && j == 0)
+-                                              core->wrap = tmp;
+-                              }
+-                      }
+-              }
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
+-              /* get & parse slave wrappers */
+-              for (i = 0; i < wrappers[1]; i++) {
+-                      u8 hack = (ports[1] == 1) ? 0 : 1;
+-                      for (j = 0; ; j++) {
+-                              tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+-                                      SCAN_ADDR_TYPE_SWRAP, i + hack);
+-                              if (tmp < 0) {
+-                                      /* no more entries for port _i_ */
+-                                      /* pr_debug("erom: master wrapper %d "
+-                                       * has %d descriptors\n", i, j); */
+-                                      break;
+-                              } else {
+-                                      if (wrappers[0] == 0 && !i && !j)
+-                                              core->wrap = tmp;
+-                              }
+-                      }
+-              }
++      return 0;
++}
++
++int __init bcma_bus_scan_early(struct bcma_bus *bus,
++                             struct bcma_device_id *match,
++                             struct bcma_device *core)
++{
++      u32 erombase;
++      u32 __iomem *eromptr, *eromend;
++      int err = -ENODEV;
++      int core_num = 0;
++
++      erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
++              eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
++              if (!eromptr)
++                      return -ENOMEM;
++      } else {
++              eromptr = bus->mmio;
++      }
++
++      eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
++
++      bcma_scan_switch_core(bus, erombase);
++
++      while (eromptr < eromend) {
++              memset(core, 0, sizeof(*core));
++              INIT_LIST_HEAD(&core->list);
++              core->bus = bus;
++
++              err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
++              if (err == -ENODEV) {
++                      core_num++;
++                      continue;
++              } else if (err == -ENXIO)
++                      continue;
++              else if (err == -ESPIPE)
++                      break;
++              else if (err < 0)
++                      return err;
++
++              core->core_index = core_num++;
++              bus->nr_cores++;
+               pr_info("Core %d found: %s "
+                       "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+-                      bus->nr_cores, bcma_device_name(&core->id),
++                      core->core_index, bcma_device_name(&core->id),
+                       core->id.manuf, core->id.id, core->id.rev,
+                       core->id.class);
+-              core->core_index = bus->nr_cores++;
+               list_add(&core->list, &bus->cores);
+-              continue;
+-out:
+-              return err;
++              err = 0;
++              break;
+       }
+-      return 0;
++      if (bus->hosttype == BCMA_HOSTTYPE_SOC)
++              iounmap(eromptr);
++
++      return err;
+ }
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -129,10 +129,80 @@ static void bcma_sprom_extract_r8(struct
+       u16 v;
+       int i;
++      bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
++              SSB_SPROM_REVISION_REV;
++
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
+       }
++
++      bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
++
++      bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
++      bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
++           SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
++      bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
++      bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
++           SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
++
++      bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
++      bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
++           SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
++      bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
++      bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
++           SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
++
++      bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
++      bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
++           SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
++      bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
++      bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
++           SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
++
++      bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
++      bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
++           SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
++      bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
++      bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
++           SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
++
++      bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
++      bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
++      bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
++      bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
++
++      bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
++
++      bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
++      bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
++      bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
++      bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
++      bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
++      bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
++              SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
+ }
+ int bcma_sprom_get(struct bcma_bus *bus)
+@@ -152,6 +222,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+       if (!sprom)
+               return -ENOMEM;
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
++
+       /* Most cards have SPROM moved by additional offset 0x30 (48 dwords).
+        * According to brcm80211 this applies to cards with PCIe rev >= 6
+        * TODO: understand this condition and use it */
+@@ -159,6 +232,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
+               BCMA_CC_SPROM_PCIE6;
+       bcma_sprom_read(bus, offset, sprom);
++      if (bus->chipinfo.id == 0x4331)
++              bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
++
+       err = bcma_sprom_valid(sprom);
+       if (err)
+               goto out;
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -6,6 +6,7 @@
+ #include <linux/bcma/bcma_driver_chipcommon.h>
+ #include <linux/bcma/bcma_driver_pci.h>
++#include <linux/bcma/bcma_driver_mips.h>
+ #include <linux/ssb/ssb.h> /* SPROM sharing */
+ #include "bcma_regs.h"
+@@ -14,9 +15,9 @@ struct bcma_device;
+ struct bcma_bus;
+ enum bcma_hosttype {
+-      BCMA_HOSTTYPE_NONE,
+       BCMA_HOSTTYPE_PCI,
+       BCMA_HOSTTYPE_SDIO,
++      BCMA_HOSTTYPE_SOC,
+ };
+ struct bcma_chipinfo {
+@@ -130,6 +131,7 @@ struct bcma_device {
+       struct device dev;
+       struct device *dma_dev;
++
+       unsigned int irq;
+       bool dev_registered;
+@@ -138,6 +140,9 @@ struct bcma_device {
+       u32 addr;
+       u32 wrap;
++      void __iomem *io_addr;
++      void __iomem *io_wrap;
++
+       void *drvdata;
+       struct list_head list;
+ };
+@@ -165,10 +170,9 @@ struct bcma_driver {
+ };
+ extern
+ int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
+-static inline int bcma_driver_register(struct bcma_driver *drv)
+-{
+-      return __bcma_driver_register(drv, THIS_MODULE);
+-}
++#define bcma_driver_register(drv) \
++      __bcma_driver_register(drv, THIS_MODULE)
++
+ extern void bcma_driver_unregister(struct bcma_driver *drv);
+ struct bcma_bus {
+@@ -190,70 +194,93 @@ struct bcma_bus {
+       struct bcma_device *mapped_core;
+       struct list_head cores;
+       u8 nr_cores;
++      u8 init_done:1;
+       struct bcma_drv_cc drv_cc;
+       struct bcma_drv_pci drv_pci;
++      struct bcma_drv_mips drv_mips;
+       /* We decided to share SPROM struct with SSB as long as we do not need
+        * any hacks for BCMA. This simplifies drivers code. */
+       struct ssb_sprom sprom;
+ };
+-extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->read8(core, offset);
+ }
+-extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read16(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->read16(core, offset);
+ }
+-extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_read32(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->read32(core, offset);
+ }
+-extern inline
++static inline
+ void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
+ {
+       core->bus->ops->write8(core, offset, value);
+ }
+-extern inline
++static inline
+ void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
+ {
+       core->bus->ops->write16(core, offset, value);
+ }
+-extern inline
++static inline
+ void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
+ {
+       core->bus->ops->write32(core, offset, value);
+ }
+ #ifdef CONFIG_BCMA_BLOCKIO
+-extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
++static inline void bcma_block_read(struct bcma_device *core, void *buffer,
+                                  size_t count, u16 offset, u8 reg_width)
+ {
+       core->bus->ops->block_read(core, buffer, count, offset, reg_width);
+ }
+-extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
+-                                  size_t count, u16 offset, u8 reg_width)
++static inline void bcma_block_write(struct bcma_device *core,
++                                  const void *buffer, size_t count,
++                                  u16 offset, u8 reg_width)
+ {
+       core->bus->ops->block_write(core, buffer, count, offset, reg_width);
+ }
+ #endif
+-extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
++static inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
+ {
+       return core->bus->ops->aread32(core, offset);
+ }
+-extern inline
++static inline
+ void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
+ {
+       core->bus->ops->awrite32(core, offset, value);
+ }
+-#define bcma_mask32(cc, offset, mask) \
+-      bcma_write32(cc, offset, bcma_read32(cc, offset) & (mask))
+-#define bcma_set32(cc, offset, set) \
+-      bcma_write32(cc, offset, bcma_read32(cc, offset) | (set))
+-#define bcma_maskset32(cc, offset, mask, set) \
+-      bcma_write32(cc, offset, (bcma_read32(cc, offset) & (mask)) | (set))
++static inline void bcma_mask32(struct bcma_device *cc, u16 offset, u32 mask)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) & mask);
++}
++static inline void bcma_set32(struct bcma_device *cc, u16 offset, u32 set)
++{
++      bcma_write32(cc, offset, bcma_read32(cc, offset) | set);
++}
++static inline void bcma_maskset32(struct bcma_device *cc,
++                                u16 offset, u32 mask, u32 set)
++{
++      bcma_write32(cc, offset, (bcma_read32(cc, offset) & mask) | set);
++}
++static inline void bcma_mask16(struct bcma_device *cc, u16 offset, u16 mask)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) & mask);
++}
++static inline void bcma_set16(struct bcma_device *cc, u16 offset, u16 set)
++{
++      bcma_write16(cc, offset, bcma_read16(cc, offset) | set);
++}
++static inline void bcma_maskset16(struct bcma_device *cc,
++                                u16 offset, u16 mask, u16 set)
++{
++      bcma_write16(cc, offset, (bcma_read16(cc, offset) & mask) | set);
++}
+ extern bool bcma_core_is_enabled(struct bcma_device *core);
+ extern void bcma_core_disable(struct bcma_device *core, u32 flags);
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -24,6 +24,7 @@
+ #define   BCMA_CC_FLASHT_NONE         0x00000000      /* No flash */
+ #define   BCMA_CC_FLASHT_STSER                0x00000100      /* ST serial flash */
+ #define   BCMA_CC_FLASHT_ATSER                0x00000200      /* Atmel serial flash */
++#define   BCMA_CC_FLASHT_NFLASH               0x00000200
+ #define         BCMA_CC_FLASHT_PARA           0x00000700      /* Parallel flash */
+ #define  BCMA_CC_CAP_PLLT             0x00038000      /* PLL Type */
+ #define   BCMA_PLLTYPE_NONE           0x00000000
+@@ -178,6 +179,7 @@
+ #define BCMA_CC_PROG_CFG              0x0120
+ #define BCMA_CC_PROG_WAITCNT          0x0124
+ #define BCMA_CC_FLASH_CFG             0x0128
++#define  BCMA_CC_FLASH_CFG_DS         0x0010  /* Data size, 0=8bit, 1=16bit */
+ #define BCMA_CC_FLASH_WAITCNT         0x012C
+ /* 0x1E0 is defined as shared BCMA_CLKCTLST */
+ #define BCMA_CC_HW_WORKAROUND         0x01E4 /* Hardware workaround (rev >= 20) */
+@@ -201,6 +203,7 @@
+ #define BCMA_CC_PMU_CTL                       0x0600 /* PMU control */
+ #define  BCMA_CC_PMU_CTL_ILP_DIV      0xFFFF0000 /* ILP div mask */
+ #define  BCMA_CC_PMU_CTL_ILP_DIV_SHIFT        16
++#define  BCMA_CC_PMU_CTL_PLL_UPD      0x00000400
+ #define  BCMA_CC_PMU_CTL_NOILPONW     0x00000200 /* No ILP on wait */
+ #define  BCMA_CC_PMU_CTL_HTREQEN      0x00000100 /* HT req enable */
+ #define  BCMA_CC_PMU_CTL_ALPREQEN     0x00000080 /* ALP req enable */
+@@ -239,6 +242,64 @@
+ #define BCMA_CC_SPROM                 0x0800 /* SPROM beginning */
+ #define BCMA_CC_SPROM_PCIE6           0x0830 /* SPROM beginning on PCIe rev >= 6 */
++/* Divider allocation in 4716/47162/5356 */
++#define BCMA_CC_PMU5_MAINPLL_CPU      1
++#define BCMA_CC_PMU5_MAINPLL_MEM      2
++#define BCMA_CC_PMU5_MAINPLL_SSB      3
++
++/* PLL usage in 4716/47162 */
++#define BCMA_CC_PMU4716_MAINPLL_PLL0  12
++
++/* PLL usage in 5356/5357 */
++#define BCMA_CC_PMU5356_MAINPLL_PLL0  0
++#define BCMA_CC_PMU5357_MAINPLL_PLL0  0
++
++/* 4706 PMU */
++#define BCMA_CC_PMU4706_MAINPLL_PLL0  0
++
++/* ALP clock on pre-PMU chips */
++#define BCMA_CC_PMU_ALP_CLOCK         20000000
++/* HT clock for systems with PMU-enabled chipcommon */
++#define BCMA_CC_PMU_HT_CLOCK          80000000
++
++/* PMU rev 5 (& 6) */
++#define BCMA_CC_PPL_P1P2_OFF          0
++#define BCMA_CC_PPL_P1_MASK           0x0f000000
++#define BCMA_CC_PPL_P1_SHIFT          24
++#define BCMA_CC_PPL_P2_MASK           0x00f00000
++#define BCMA_CC_PPL_P2_SHIFT          20
++#define BCMA_CC_PPL_M14_OFF           1
++#define BCMA_CC_PPL_MDIV_MASK         0x000000ff
++#define BCMA_CC_PPL_MDIV_WIDTH                8
++#define BCMA_CC_PPL_NM5_OFF           2
++#define BCMA_CC_PPL_NDIV_MASK         0xfff00000
++#define BCMA_CC_PPL_NDIV_SHIFT                20
++#define BCMA_CC_PPL_FMAB_OFF          3
++#define BCMA_CC_PPL_MRAT_MASK         0xf0000000
++#define BCMA_CC_PPL_MRAT_SHIFT                28
++#define BCMA_CC_PPL_ABRAT_MASK                0x08000000
++#define BCMA_CC_PPL_ABRAT_SHIFT               27
++#define BCMA_CC_PPL_FDIV_MASK         0x07ffffff
++#define BCMA_CC_PPL_PLLCTL_OFF                4
++#define BCMA_CC_PPL_PCHI_OFF          5
++#define BCMA_CC_PPL_PCHI_MASK         0x0000003f
++
++/* BCM4331 ChipControl numbers. */
++#define BCMA_CHIPCTL_4331_BT_COEXIST          BIT(0)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SECI                        BIT(1)  /* 0 SECI is disabled (JATG functional) */
++#define BCMA_CHIPCTL_4331_EXT_LNA             BIT(2)  /* 0 disable */
++#define BCMA_CHIPCTL_4331_SPROM_GPIO13_15     BIT(3)  /* sprom/gpio13-15 mux */
++#define BCMA_CHIPCTL_4331_EXTPA_EN            BIT(4)  /* 0 ext pa disable, 1 ext pa enabled */
++#define BCMA_CHIPCTL_4331_GPIOCLK_ON_SPROMCS  BIT(5)  /* set drive out GPIO_CLK on sprom_cs pin */
++#define BCMA_CHIPCTL_4331_PCIE_MDIO_ON_SPROMCS        BIT(6)  /* use sprom_cs pin as PCIE mdio interface */
++#define BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5    BIT(7)  /* aband extpa will be at gpio2/5 and sprom_dout */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXCLKEN    BIT(8)  /* override core control on pipe_AuxClkEnable */
++#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN  BIT(9)  /* override core control on pipe_AuxPowerDown */
++#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN               BIT(10) /* pcie_auxclkenable */
++#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN   BIT(11) /* pcie_pipe_pllpowerdown */
++#define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4    BIT(16) /* enable bt_shd0 at gpio4 */
++#define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5    BIT(17) /* enable bt_shd1 at gpio5 */
++
+ /* Data for the PMU, if available.
+  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+  */
+@@ -247,14 +308,37 @@ struct bcma_chipcommon_pmu {
+       u32 crystalfreq;        /* The active crystal frequency (in kHz) */
+ };
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++struct bcma_pflash {
++      u8 buswidth;
++      u32 window;
++      u32 window_size;
++};
++
++struct bcma_serial_port {
++      void *regs;
++      unsigned long clockspeed;
++      unsigned int irq;
++      unsigned int baud_base;
++      unsigned int reg_shift;
++};
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
++
+ struct bcma_drv_cc {
+       struct bcma_device *core;
+       u32 status;
+       u32 capabilities;
+       u32 capabilities_ext;
++      u8 setup_done:1;
+       /* Fast Powerup Delay constant */
+       u16 fast_pwrup_delay;
+       struct bcma_chipcommon_pmu pmu;
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++      struct bcma_pflash pflash;
++
++      int nr_serial_ports;
++      struct bcma_serial_port serial_ports[4];
++#endif /* CONFIG_BCMA_DRIVER_MIPS */
+ };
+ /* Register access */
+@@ -275,6 +359,8 @@ extern void bcma_core_chipcommon_init(st
+ extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
++void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
++
+ extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
+                                         u32 ticks);
+@@ -293,4 +379,13 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+ /* PMU support */
+ extern void bcma_pmu_init(struct bcma_drv_cc *cc);
++extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
++                                u32 value);
++extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
++                                  u32 mask, u32 set);
++extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
++                                      u32 offset, u32 mask, u32 set);
++extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
++                                     u32 offset, u32 mask, u32 set);
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -0,0 +1,51 @@
++#ifndef LINUX_BCMA_DRIVER_MIPS_H_
++#define LINUX_BCMA_DRIVER_MIPS_H_
++
++#define BCMA_MIPS_IPSFLAG             0x0F08
++/* which sbflags get routed to mips interrupt 1 */
++#define  BCMA_MIPS_IPSFLAG_IRQ1               0x0000003F
++#define  BCMA_MIPS_IPSFLAG_IRQ1_SHIFT 0
++/* which sbflags get routed to mips interrupt 2 */
++#define  BCMA_MIPS_IPSFLAG_IRQ2               0x00003F00
++#define  BCMA_MIPS_IPSFLAG_IRQ2_SHIFT 8
++/* which sbflags get routed to mips interrupt 3 */
++#define  BCMA_MIPS_IPSFLAG_IRQ3               0x003F0000
++#define  BCMA_MIPS_IPSFLAG_IRQ3_SHIFT 16
++/* which sbflags get routed to mips interrupt 4 */
++#define  BCMA_MIPS_IPSFLAG_IRQ4               0x3F000000
++#define  BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
++
++/* MIPS 74K core registers */
++#define BCMA_MIPS_MIPS74K_CORECTL     0x0000
++#define BCMA_MIPS_MIPS74K_EXCEPTBASE  0x0004
++#define BCMA_MIPS_MIPS74K_BIST                0x000C
++#define BCMA_MIPS_MIPS74K_INTMASK_INT0        0x0014
++#define BCMA_MIPS_MIPS74K_INTMASK(int) \
++      ((int) * 4 + BCMA_MIPS_MIPS74K_INTMASK_INT0)
++#define BCMA_MIPS_MIPS74K_NMIMASK     0x002C
++#define BCMA_MIPS_MIPS74K_GPIOSEL     0x0040
++#define BCMA_MIPS_MIPS74K_GPIOOUT     0x0044
++#define BCMA_MIPS_MIPS74K_GPIOEN      0x0048
++#define BCMA_MIPS_MIPS74K_CLKCTLST    0x01E0
++
++#define BCMA_MIPS_OOBSELOUTA30                0x100
++
++struct bcma_device;
++
++struct bcma_drv_mips {
++      struct bcma_device *core;
++      u8 setup_done:1;
++      unsigned int assigned_irqs;
++};
++
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++#else
++static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++#endif
++
++extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
++
++extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
++
++#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
+--- /dev/null
++++ b/include/linux/bcma/bcma_soc.h
+@@ -0,0 +1,16 @@
++#ifndef LINUX_BCMA_SOC_H_
++#define LINUX_BCMA_SOC_H_
++
++#include <linux/bcma/bcma.h>
++
++struct bcma_soc {
++      struct bcma_bus bus;
++      struct bcma_device core_cc;
++      struct bcma_device core_mips;
++};
++
++int __init bcma_host_soc_register(struct bcma_soc *soc);
++
++int bcma_bus_register(struct bcma_bus *bus);
++
++#endif /* LINUX_BCMA_SOC_H_ */
This page took 0.672895 seconds and 4 git commands to generate.