From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Mon, 19 Dec 2011 23:33:03 +0000 (+0000)
Subject: kernel: update bcma and ssb to version master-2011-12-16 from wireless-testing
X-Git-Tag: reboot~15283
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=1aa5a61754d4995d8144a48dde0565211da0d5a8;p=openwrt%2Fstaging%2Fchunkeey.git

kernel: update bcma and ssb to version master-2011-12-16 from wireless-testing

SVN-Revision: 29574
---

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
index 740e96e81f..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0001-bcma-move-parsing-of-EEPROM-into-own-function.patch
+++ /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
index 48191abc3e..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0002-bcma-move-initializing-of-struct-bcma_bus-to-own-fun.patch
+++ /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
index 92cd65d396..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0003-bcma-add-functions-to-scan-cores-needed-on-SoCs.patch
+++ /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
index 6ad9dce4b8..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0004-bcma-add-SOC-bus.patch
+++ /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
index 31181a4883..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0005-bcma-add-mips-driver.patch
+++ /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
index fd7b8ae78e..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0006-bcma-add-serial-console-support.patch
+++ /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
index 7fa752056b..0000000000
--- a/target/linux/brcm47xx/patches-3.0/0007-bcma-get-CPU-clock.patch
+++ /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_ */
diff --git a/target/linux/brcm47xx/patches-3.0/0012-bcma-move-parallel-flash-into-a-union.patch b/target/linux/brcm47xx/patches-3.0/0012-bcma-move-parallel-flash-into-a-union.patch
index 9a4e877287..11855b4496 100644
--- a/target/linux/brcm47xx/patches-3.0/0012-bcma-move-parallel-flash-into-a-union.patch
+++ b/target/linux/brcm47xx/patches-3.0/0012-bcma-move-parallel-flash-into-a-union.patch
@@ -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
diff --git a/target/linux/brcm47xx/patches-3.0/0013-bcma-add-serial-flash-support-to-bcma.patch b/target/linux/brcm47xx/patches-3.0/0013-bcma-add-serial-flash-support-to-bcma.patch
index 14e5a3bcc9..e78f3c4576 100644
--- a/target/linux/brcm47xx/patches-3.0/0013-bcma-add-serial-flash-support-to-bcma.patch
+++ b/target/linux/brcm47xx/patches-3.0/0013-bcma-add-serial-flash-support-to-bcma.patch
@@ -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. */
diff --git a/target/linux/brcm47xx/patches-3.0/0023-bcma-use-randoom-mac-address-as-long-as-reading-it-o.patch b/target/linux/brcm47xx/patches-3.0/0023-bcma-use-randoom-mac-address-as-long-as-reading-it-o.patch
index d83ad5326e..fee1d0a5a6 100644
--- a/target/linux/brcm47xx/patches-3.0/0023-bcma-use-randoom-mac-address-as-long-as-reading-it-o.patch
+++ b/target/linux/brcm47xx/patches-3.0/0023-bcma-use-randoom-mac-address-as-long-as-reading-it-o.patch
@@ -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;
  
diff --git a/target/linux/brcm47xx/patches-3.0/220-bcm5354.patch b/target/linux/brcm47xx/patches-3.0/220-bcm5354.patch
index 6055e0a738..61f0a7ecad 100644
--- a/target/linux/brcm47xx/patches-3.0/220-bcm5354.patch
+++ b/target/linux/brcm47xx/patches-3.0/220-bcm5354.patch
@@ -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
index 30f133bb56..0000000000
--- a/target/linux/brcm47xx/patches-3.0/230-ssb_pci_sprom.patch
+++ /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) {
diff --git a/target/linux/brcm47xx/patches-3.0/951-brcm4716-defines.patch b/target/linux/brcm47xx/patches-3.0/951-brcm4716-defines.patch
index 25cd469964..18685af6eb 100644
--- a/target/linux/brcm47xx/patches-3.0/951-brcm4716-defines.patch
+++ b/target/linux/brcm47xx/patches-3.0/951-brcm4716-defines.patch
@@ -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
  
diff --git a/target/linux/generic/patches-2.6.30/025-bcma_backport.patch b/target/linux/generic/patches-2.6.30/025-bcma_backport.patch
index f9c994a60f..a95db6eb92 100644
--- a/target/linux/generic/patches-2.6.30/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.30/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-2.6.30/941-ssb_update.patch b/target/linux/generic/patches-2.6.30/941-ssb_update.patch
index 3b54067d74..71f5b74a7e 100644
--- a/target/linux/generic/patches-2.6.30/941-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.30/941-ssb_update.patch
@@ -33,7 +33,22 @@
  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) },
@@ -43,6 +58,15 @@
  	{ 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;
@@ -192,6 +216,15 @@
  {
 --- 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);
  }
@@ -359,6 +392,15 @@
 +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>
@@ -403,6 +445,15 @@
  	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)
@@ -567,6 +618,15 @@
  	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"
@@ -646,7 +706,7 @@
  {
  	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 */
  
@@ -759,10 +819,15 @@
 -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) {
@@ -784,7 +849,7 @@
  	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);
  }
  
@@ -914,7 +979,7 @@
  }
  
  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. */
@@ -930,7 +995,7 @@
  		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) {
@@ -983,7 +1048,22 @@
  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>
@@ -992,7 +1072,7 @@
  
  #include <pcmcia/cs_types.h>
  #include <pcmcia/cs.h>
-@@ -88,6 +90,25 @@ found:
+@@ -88,6 +91,25 @@ found:
  }
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
@@ -1018,7 +1098,7 @@
  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);
  }
  
@@ -1038,7 +1118,7 @@
  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
@@ -1181,7 +1261,7 @@
  }
  #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);
  }
  
@@ -1217,7 +1297,7 @@
  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,
@@ -1225,7 +1305,7 @@
  };
  
  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;
@@ -1233,7 +1313,7 @@
  #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;
@@ -1248,7 +1328,7 @@
  			break;
  		}
  
-@@ -497,7 +559,7 @@ error:
+@@ -497,7 +560,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
@@ -1257,7 +1337,7 @@
  {
  	struct ssb_bus *bus, *n;
  	int err = 0;
-@@ -708,9 +770,9 @@ out:
+@@ -708,9 +771,9 @@ out:
  	return err;
  }
  
@@ -1270,7 +1350,7 @@
  {
  	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;
@@ -1290,7 +1370,7 @@
  
  	/* 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);
@@ -1299,7 +1379,7 @@
  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
@@ -1310,7 +1390,7 @@
  {
  	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));
@@ -1320,7 +1400,7 @@
  	}
  
  	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
@@ -1333,7 +1413,7 @@
  {
  	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 */
  
@@ -1369,7 +1449,7 @@
  {
  	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)
@@ -1380,7 +1460,7 @@
  	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;
  
@@ -1411,7 +1491,7 @@
  }
  
  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);
  
@@ -1425,7 +1505,7 @@
  {
  	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) {
@@ -1434,7 +1514,7 @@
  				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)
  {
@@ -1482,19 +1562,43 @@
  
  	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)
  {
@@ -1519,7 +1623,7 @@
  	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);
  
@@ -1557,7 +1661,7 @@
  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();
@@ -1569,7 +1673,7 @@
  
  	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;
  	}
@@ -1580,6 +1684,15 @@
  /* 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>
@@ -1768,16 +1881,39 @@
  
  	/* 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);
@@ -1835,7 +1971,7 @@
  	}
  
  	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)
  {
@@ -1873,7 +2009,7 @@
  	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)
@@ -1903,7 +2039,7 @@
  				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);
@@ -1928,7 +2064,14 @@
  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>
@@ -1976,6 +2119,15 @@
  	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]);
@@ -2003,10 +2155,7 @@
 +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)
@@ -2022,7 +2171,10 @@
 +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;
@@ -2249,6 +2401,15 @@
  
 --- 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)
@@ -2360,7 +2521,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.
 + *
@@ -2964,6 +3125,15 @@
 +}
 --- 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"
@@ -3043,29 +3213,31 @@
  
  /**
 - * 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
@@ -3219,9 +3391,12 @@
  #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) */
@@ -3286,11 +3461,20 @@
  
  	/* 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 */
  };
  
@@ -3303,7 +3487,7 @@
  };
  
  
-@@ -137,7 +173,7 @@ struct ssb_device {
+@@ -137,7 +182,7 @@ struct ssb_device {
  	 * is an optimization. */
  	const struct ssb_bus_ops *ops;
  
@@ -3312,7 +3496,21 @@
  
  	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 */
@@ -3320,7 +3518,7 @@
  };
  
  /* board_vendor */
-@@ -238,20 +275,33 @@ struct ssb_bus {
+@@ -238,20 +283,33 @@ struct ssb_bus {
  
  	const struct ssb_bus_ops *ops;
  
@@ -3362,7 +3560,7 @@
  
  #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;
@@ -3372,7 +3570,7 @@
  	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 */
  };
  
@@ -3384,7 +3582,7 @@
  /* 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 */
@@ -3409,7 +3607,7 @@
  
  /* 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);
  
@@ -3419,6 +3617,15 @@
  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) */
@@ -3669,7 +3876,7 @@
  #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 */
@@ -3893,6 +4100,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 */
@@ -3924,6 +4148,68 @@
 +#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.
+  */
diff --git a/target/linux/generic/patches-2.6.31/025-bcma_backport.patch b/target/linux/generic/patches-2.6.31/025-bcma_backport.patch
index 7203de393c..f713e2bf9b 100644
--- a/target/linux/generic/patches-2.6.31/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.31/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-2.6.31/941-ssb_update.patch b/target/linux/generic/patches-2.6.31/941-ssb_update.patch
index 2372435d17..e86ec9ba1a 100644
--- a/target/linux/generic/patches-2.6.31/941-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.31/941-ssb_update.patch
@@ -33,7 +33,22 @@
  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) },
@@ -43,6 +58,15 @@
  	{ 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;
@@ -192,6 +216,15 @@
  {
 --- 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);
  }
@@ -359,6 +392,15 @@
 +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>
@@ -403,6 +445,15 @@
  	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++);
  			}
@@ -424,6 +475,15 @@
  	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"
@@ -503,7 +563,7 @@
  {
  	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 */
  
@@ -616,10 +676,15 @@
 -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) {
@@ -641,7 +706,7 @@
  	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);
  }
  
@@ -771,7 +836,7 @@
  }
  
  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. */
@@ -787,7 +852,7 @@
  		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) {
@@ -840,7 +905,22 @@
  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>
@@ -849,7 +929,7 @@
  
  #include <pcmcia/cs_types.h>
  #include <pcmcia/cs.h>
-@@ -88,6 +90,25 @@ found:
+@@ -88,6 +91,25 @@ found:
  }
  #endif /* CONFIG_SSB_PCMCIAHOST */
  
@@ -875,7 +955,7 @@
  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);
  }
  
@@ -895,7 +975,7 @@
  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
@@ -1038,7 +1118,7 @@
  }
  #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);
  }
  
@@ -1074,7 +1154,7 @@
  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,
@@ -1082,7 +1162,7 @@
  };
  
  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;
@@ -1090,7 +1170,7 @@
  #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;
@@ -1105,7 +1185,7 @@
  			break;
  		}
  
-@@ -497,7 +559,7 @@ error:
+@@ -497,7 +560,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
@@ -1114,7 +1194,7 @@
  {
  	struct ssb_bus *bus, *n;
  	int err = 0;
-@@ -708,9 +770,9 @@ out:
+@@ -708,9 +771,9 @@ out:
  	return err;
  }
  
@@ -1127,7 +1207,7 @@
  {
  	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;
@@ -1147,7 +1227,7 @@
  
  	/* 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);
@@ -1156,7 +1236,7 @@
  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
@@ -1167,7 +1247,7 @@
  {
  	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));
@@ -1177,7 +1257,7 @@
  	}
  
  	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
@@ -1190,7 +1270,7 @@
  {
  	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 */
  
@@ -1226,7 +1306,7 @@
  {
  	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)
@@ -1237,7 +1317,7 @@
  	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;
  
@@ -1268,7 +1348,7 @@
  }
  
  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);
  
@@ -1282,7 +1362,7 @@
  {
  	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) {
@@ -1291,7 +1371,7 @@
  				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)
  {
@@ -1339,19 +1419,43 @@
  
  	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)
  {
@@ -1376,7 +1480,7 @@
  	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);
  
@@ -1414,7 +1518,7 @@
  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();
@@ -1426,7 +1530,7 @@
  
  	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;
  	}
@@ -1437,6 +1541,15 @@
  /* 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>
@@ -1625,16 +1738,39 @@
  
  	/* 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);
@@ -1692,7 +1828,7 @@
  	}
  
  	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)
  {
@@ -1730,7 +1866,7 @@
  	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)
@@ -1760,7 +1896,7 @@
  				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);
@@ -1785,7 +1921,14 @@
  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>
@@ -1833,6 +1976,15 @@
  	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)
@@ -1842,10 +1994,7 @@
 +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)
@@ -1861,7 +2010,10 @@
 +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;
@@ -2090,6 +2242,15 @@
  
 --- 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)
@@ -2201,7 +2362,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.
 + *
@@ -2805,6 +2966,15 @@
 +}
 --- 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"
  
@@ -2851,34 +3021,36 @@
  
  /**
 - * 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.
@@ -3027,9 +3199,12 @@
  #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) */
@@ -3094,11 +3269,20 @@
  
  	/* 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 */
  };
  
@@ -3111,7 +3295,7 @@
  };
  
  
-@@ -137,7 +173,7 @@ struct ssb_device {
+@@ -137,7 +182,7 @@ struct ssb_device {
  	 * is an optimization. */
  	const struct ssb_bus_ops *ops;
  
@@ -3120,7 +3304,21 @@
  
  	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 */
@@ -3128,7 +3326,7 @@
  };
  
  /* board_vendor */
-@@ -238,20 +275,33 @@ struct ssb_bus {
+@@ -238,20 +283,33 @@ struct ssb_bus {
  
  	const struct ssb_bus_ops *ops;
  
@@ -3170,7 +3368,7 @@
  
  #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;
@@ -3180,7 +3378,7 @@
  	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 */
  };
  
@@ -3192,7 +3390,7 @@
  /* 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 */
@@ -3217,7 +3415,7 @@
  
  /* 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);
  
@@ -3227,6 +3425,15 @@
  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) */
@@ -3477,7 +3684,7 @@
  #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 */
@@ -3701,6 +3908,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 */
@@ -3732,6 +3956,68 @@
 +#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.
+  */
diff --git a/target/linux/generic/patches-2.6.32/025-bcma_backport.patch b/target/linux/generic/patches-2.6.32/025-bcma_backport.patch
index 4d73540a09..3571bd1984 100644
--- a/target/linux/generic/patches-2.6.32/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.32/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-2.6.32/975-ssb_update.patch b/target/linux/generic/patches-2.6.32/975-ssb_update.patch
index 0dc9bafb5c..a619e6cc6b 100644
--- a/target/linux/generic/patches-2.6.32/975-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.32/975-ssb_update.patch
@@ -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;
@@ -146,6 +155,15 @@
  {
 --- 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);
@@ -212,6 +230,15 @@
  }
 --- 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>
@@ -256,6 +283,15 @@
  	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++);
  			}
@@ -277,6 +313,15 @@
  	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"
@@ -356,7 +401,7 @@
  {
  	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 */
  
@@ -469,10 +514,15 @@
 -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) {
@@ -494,7 +544,7 @@
  	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);
  }
  
@@ -624,7 +674,7 @@
  }
  
  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. */
@@ -640,7 +690,7 @@
  		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) {
@@ -693,7 +743,23 @@
  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>
@@ -701,7 +767,7 @@
  
  #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);
  }
  
@@ -721,7 +787,7 @@
  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
@@ -776,13 +842,13 @@
 -		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",
@@ -864,7 +930,7 @@
  }
  #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);
  }
  
@@ -900,7 +966,7 @@
  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,
@@ -908,7 +974,7 @@
  };
  
  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;
@@ -916,7 +982,7 @@
  #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:
@@ -932,7 +998,7 @@
  			break;
  		}
  
-@@ -523,7 +559,7 @@ error:
+@@ -523,7 +560,7 @@ error:
  }
  
  /* Needs ssb_buses_lock() */
@@ -941,7 +1007,7 @@
  {
  	struct ssb_bus *bus, *n;
  	int err = 0;
-@@ -734,9 +770,9 @@ out:
+@@ -734,9 +771,9 @@ out:
  	return err;
  }
  
@@ -954,7 +1020,7 @@
  {
  	int err;
  
-@@ -817,8 +853,8 @@ err_disable_xtal:
+@@ -817,8 +854,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
@@ -965,7 +1031,7 @@
  {
  	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));
@@ -975,7 +1041,7 @@
  	}
  
  	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
@@ -988,7 +1054,7 @@
  {
  	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
@@ -1000,7 +1066,7 @@
  {
  	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 */
  
@@ -1013,7 +1079,7 @@
  {
  	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)
@@ -1024,7 +1090,7 @@
  	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;
  
@@ -1055,7 +1121,7 @@
  }
  
  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);
  
@@ -1069,7 +1135,7 @@
  {
  	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) {
@@ -1078,7 +1144,7 @@
  				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)
  {
@@ -1126,19 +1192,43 @@
  
  	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)
  {
@@ -1163,7 +1253,7 @@
  	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);
  
@@ -1203,6 +1293,15 @@
  	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>
@@ -1291,16 +1390,39 @@
  	/* 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);
@@ -1359,7 +1481,7 @@
  	}
  
  	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)
  {
@@ -1377,7 +1499,7 @@
  		/*
  		 * 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)
@@ -1386,7 +1508,7 @@
  	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)
@@ -1416,7 +1538,7 @@
  				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);
@@ -1441,7 +1563,14 @@
  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>
@@ -1489,6 +1618,15 @@
  	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)
@@ -1498,10 +1636,7 @@
 +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)
@@ -1517,7 +1652,10 @@
 +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;
@@ -1746,6 +1884,15 @@
  
 --- 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) {
@@ -1796,6 +1943,15 @@
  		}
 --- 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"
  
@@ -1842,34 +1998,36 @@
  
  /**
 - * 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.
@@ -1957,9 +2115,12 @@
  #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 */
@@ -1977,7 +2138,23 @@
  	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;
@@ -1986,7 +2163,7 @@
  };
  
  
-@@ -167,7 +173,7 @@ struct ssb_device {
+@@ -167,7 +182,7 @@ struct ssb_device {
  	 * is an optimization. */
  	const struct ssb_bus_ops *ops;
  
@@ -1995,7 +2172,21 @@
  
  	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;
  
@@ -2005,7 +2196,7 @@
  	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;
  
@@ -2030,7 +2221,7 @@
  
  	/* 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;
@@ -2039,7 +2230,7 @@
  	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. */
@@ -2050,7 +2241,7 @@
  
  /* 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);
  
@@ -2416,7 +2607,7 @@
  #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
@@ -2436,6 +2627,23 @@
  #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 */
@@ -2484,11 +2692,60 @@
 +#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
@@ -2521,3 +2778,53 @@
  #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.
+  *
diff --git a/target/linux/generic/patches-2.6.36/025-bcma_backport.patch b/target/linux/generic/patches-2.6.36/025-bcma_backport.patch
index 45da134a41..eb64b85826 100644
--- a/target/linux/generic/patches-2.6.36/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.36/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-2.6.36/941-ssb_update.patch b/target/linux/generic/patches-2.6.36/941-ssb_update.patch
index f83923102d..e634a4a46c 100644
--- a/target/linux/generic/patches-2.6.36/941-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.36/941-ssb_update.patch
@@ -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
@@ -90,7 +107,7 @@
  {
  	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
@@ -102,7 +119,7 @@
  {
  	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 */
  
@@ -115,7 +132,7 @@
  {
  	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)
@@ -126,7 +143,7 @@
  	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;
  
@@ -157,7 +174,7 @@
  }
  
  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);
  
@@ -171,7 +188,7 @@
  {
  	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) {
@@ -180,7 +197,7 @@
  				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)
  {
@@ -228,19 +245,43 @@
  
  	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)
  {
@@ -265,7 +306,7 @@
  	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);
  
@@ -305,6 +346,15 @@
  	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;
  }
@@ -376,16 +426,39 @@
  	/* 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);
@@ -444,7 +517,7 @@
  	}
  
  	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)
  {
@@ -462,7 +535,7 @@
  		/*
  		 * 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)
@@ -471,7 +544,7 @@
  	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)
@@ -501,7 +574,7 @@
  				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);
@@ -526,6 +599,15 @@
  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 */
@@ -566,6 +648,15 @@
  	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) {
@@ -620,9 +711,12 @@
  		}
 --- 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 */
@@ -640,7 +734,23 @@
  	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;
@@ -649,7 +759,21 @@
  };
  
  
-@@ -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;
@@ -658,7 +782,7 @@
  	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. */
@@ -669,7 +793,7 @@
  
  /* 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);
  
@@ -792,8 +916,88 @@
  #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;
@@ -894,6 +1098,15 @@
  	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;
@@ -913,6 +1126,15 @@
  		 * 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);
  }
@@ -949,6 +1171,15 @@
  	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"
@@ -979,7 +1210,7 @@
  {
  	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 */
  
@@ -1092,10 +1323,15 @@
 -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) {
@@ -1117,7 +1353,7 @@
  	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);
  }
  
@@ -1155,7 +1391,7 @@
  	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);
  
@@ -1247,7 +1483,7 @@
  }
  
  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) {
@@ -1300,6 +1536,15 @@
  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>
  
@@ -1327,21 +1572,23 @@
 + * 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.
@@ -1393,6 +1640,15 @@
  /* 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
@@ -1425,3 +1681,75 @@
  #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.
+  *
diff --git a/target/linux/generic/patches-2.6.37/020-ssb_update.patch b/target/linux/generic/patches-2.6.37/020-ssb_update.patch
index 82872c78ad..b71b67598e 100644
--- a/target/linux/generic/patches-2.6.37/020-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.37/020-ssb_update.patch
@@ -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
@@ -90,7 +107,7 @@
  {
  	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
@@ -102,7 +119,7 @@
  {
  	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 */
  
@@ -115,7 +132,7 @@
  {
  	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)
@@ -126,7 +143,7 @@
  	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;
  
@@ -157,7 +174,7 @@
  }
  
  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);
  
@@ -171,7 +188,7 @@
  {
  	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) {
@@ -180,7 +197,7 @@
  				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)
  {
@@ -228,19 +245,43 @@
  
  	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)
  {
@@ -265,7 +306,7 @@
  	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);
  
@@ -305,6 +346,15 @@
  	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;
  }
@@ -376,16 +426,39 @@
  	/* 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);
@@ -444,7 +517,7 @@
  	}
  
  	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)
  {
@@ -462,7 +535,7 @@
  		/*
  		 * 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)
@@ -471,7 +544,7 @@
  	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)
@@ -501,7 +574,7 @@
  				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);
@@ -526,6 +599,15 @@
  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 */
@@ -566,6 +648,15 @@
  	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) {
@@ -620,9 +711,12 @@
  		}
 --- 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 */
@@ -640,7 +734,23 @@
  	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;
@@ -649,7 +759,21 @@
  };
  
  
-@@ -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;
@@ -658,7 +782,7 @@
  	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. */
@@ -669,7 +793,7 @@
  
  /* 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);
  
@@ -764,8 +888,88 @@
  #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;
@@ -866,6 +1070,15 @@
  	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;
@@ -885,6 +1098,15 @@
  		 * 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);
  }
@@ -921,6 +1143,15 @@
  	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"
@@ -951,7 +1182,7 @@
  {
  	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 */
  
@@ -1064,10 +1295,15 @@
 -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) {
@@ -1089,7 +1325,7 @@
  	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);
  }
  
@@ -1127,7 +1363,7 @@
  	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);
  
@@ -1219,7 +1455,7 @@
  }
  
  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) {
@@ -1272,6 +1508,15 @@
  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>
  
@@ -1299,21 +1544,23 @@
 + * 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.
@@ -1365,6 +1612,15 @@
  /* 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
@@ -1397,3 +1653,75 @@
  #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.
+  *
diff --git a/target/linux/generic/patches-2.6.37/025-bcma_backport.patch b/target/linux/generic/patches-2.6.37/025-bcma_backport.patch
index 1b5da3b010..c3312a2004 100644
--- a/target/linux/generic/patches-2.6.37/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.37/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-2.6.38/020-ssb_update.patch b/target/linux/generic/patches-2.6.38/020-ssb_update.patch
index 3db961367b..a72a39b8ba 100644
--- a/target/linux/generic/patches-2.6.38/020-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.38/020-ssb_update.patch
@@ -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);
  
@@ -14,7 +144,7 @@
  {
  	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) {
@@ -23,7 +153,7 @@
  				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)
  {
@@ -71,8 +201,116 @@
  
  	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);
@@ -88,7 +326,37 @@
  	}
  	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"
@@ -97,6 +365,61 @@
  			   " 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 @@
@@ -108,9 +431,12 @@
  #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 */
@@ -134,11 +460,89 @@
  #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.
+  *
diff --git a/target/linux/generic/patches-2.6.38/025-bcma_backport.patch b/target/linux/generic/patches-2.6.38/025-bcma_backport.patch
index b36bb5f8e1..60fefaf452 100644
--- a/target/linux/generic/patches-2.6.38/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.38/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-2.6.39/020-ssb_update.patch b/target/linux/generic/patches-2.6.39/020-ssb_update.patch
index f566288375..be7071b93f 100644
--- a/target/linux/generic/patches-2.6.39/020-ssb_update.patch
+++ b/target/linux/generic/patches-2.6.39/020-ssb_update.patch
@@ -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;
@@ -100,6 +109,15 @@
  	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;
@@ -119,6 +137,15 @@
  		 * 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);
  }
@@ -155,6 +182,15 @@
  	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"
@@ -185,7 +221,7 @@
  {
  	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 */
  
@@ -298,10 +334,15 @@
 -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) {
@@ -323,7 +364,7 @@
  	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);
  }
  
@@ -361,7 +402,7 @@
  	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);
  
@@ -453,7 +494,7 @@
  }
  
  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) {
@@ -506,7 +547,24 @@
  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() */
@@ -515,7 +573,7 @@
  {
  	struct ssb_bus *bus, *n;
  	int err = 0;
-@@ -768,9 +768,9 @@ out:
+@@ -768,9 +769,9 @@ out:
  	return err;
  }
  
@@ -528,7 +586,7 @@
  {
  	int err;
  
-@@ -851,8 +851,8 @@ err_disable_xtal:
+@@ -851,8 +852,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
@@ -539,7 +597,7 @@
  {
  	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
@@ -552,7 +610,7 @@
  {
  	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
@@ -564,7 +622,7 @@
  {
  	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 */
  
@@ -577,7 +635,7 @@
  {
  	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)
@@ -588,7 +646,7 @@
  	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;
  
@@ -619,19 +677,43 @@
  }
  
  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)
  {
@@ -656,7 +738,7 @@
  	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);
  
@@ -696,7 +778,46 @@
  	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)
  {
@@ -704,7 +825,7 @@
  	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?
@@ -726,7 +847,7 @@
  				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)
  {
@@ -744,6 +865,15 @@
  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 */
@@ -766,6 +896,15 @@
  	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) {
@@ -790,6 +929,15 @@
  			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>
  
@@ -817,21 +965,23 @@
 + * 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.
@@ -874,16 +1024,35 @@
  /* 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;
@@ -892,7 +1061,21 @@
  };
  
  
-@@ -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;
@@ -901,7 +1084,7 @@
  	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. */
@@ -912,7 +1095,7 @@
  
  /* 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);
  
@@ -922,6 +1105,15 @@
  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
@@ -965,3 +1157,146 @@
  #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.
+  *
diff --git a/target/linux/generic/patches-2.6.39/025-bcma_backport.patch b/target/linux/generic/patches-2.6.39/025-bcma_backport.patch
index b36bb5f8e1..fa77868783 100644
--- a/target/linux/generic/patches-2.6.39/025-bcma_backport.patch
+++ b/target/linux/generic/patches-2.6.39/025-bcma_backport.patch
@@ -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
@@ -107,6 +107,19 @@
 +	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
@@ -118,12 +131,14 @@
 +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
@@ -157,7 +172,7 @@
 +- 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_
 +
@@ -175,13 +190,32 @@
 +/* 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);
@@ -195,7 +229,7 @@
 +#endif
 --- /dev/null
 +++ b/drivers/bcma/core.c
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,126 @@
 +/*
 + * Broadcom specific AMBA
 + * Core ops
@@ -308,6 +342,8 @@
 +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;
@@ -322,13 +358,13 @@
 +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.
 + */
@@ -351,6 +387,9 @@
 +	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);
@@ -377,6 +416,8 @@
 +			((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 */
@@ -426,14 +467,62 @@
 +{
 +	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.
@@ -442,20 +531,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)
 +{
@@ -514,6 +630,24 @@
 +	}
 +}
 +
++/* 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;
@@ -523,7 +657,7 @@
 +		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) {
@@ -567,15 +701,141 @@
 +	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.
 + */
@@ -744,8 +1004,10 @@
 +	    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 */
@@ -759,6 +1021,9 @@
 +
 +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);
@@ -768,6 +1033,8 @@
 +	} 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,
@@ -775,7 +1042,14 @@
 +{
 +	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)
@@ -795,7 +1069,7 @@
 +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
@@ -807,6 +1081,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)
 +{
@@ -818,48 +1093,58 @@
 +	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);
 +}
 +
@@ -1021,6 +1306,41 @@
 +	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) },
@@ -1036,6 +1356,8 @@
 +	.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)
@@ -1049,7 +1371,7 @@
 +}
 --- /dev/null
 +++ b/drivers/bcma/main.c
-@@ -0,0 +1,257 @@
+@@ -0,0 +1,354 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus subsystem
@@ -1058,6 +1380,7 @@
 + */
 +
 +#include "bcma_private.h"
++#include <linux/module.h>
 +#include <linux/bcma/bcma.h>
 +#include <linux/slab.h>
 +
@@ -1067,6 +1390,7 @@
 +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)
 +{
@@ -1101,6 +1425,7 @@
 +	.match		= bcma_bus_match,
 +	.probe		= bcma_device_probe,
 +	.remove		= bcma_device_remove,
++	.uevent		= bcma_device_uevent,
 +	.dev_attrs	= bcma_device_attrs,
 +};
 +
@@ -1118,6 +1443,10 @@
 +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);
 +}
 +
@@ -1132,6 +1461,7 @@
 +		case BCMA_CORE_CHIPCOMMON:
 +		case BCMA_CORE_PCI:
 +		case BCMA_CORE_PCIE:
++		case BCMA_CORE_MIPS_74K:
 +			continue;
 +		}
 +
@@ -1145,7 +1475,10 @@
 +			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;
 +		}
@@ -1192,6 +1525,13 @@
 +		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) {
@@ -1221,6 +1561,75 @@
 +	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;
@@ -1279,6 +1688,16 @@
 +	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;
@@ -1309,7 +1728,7 @@
 +module_exit(bcma_modexit)
 --- /dev/null
 +++ b/drivers/bcma/scan.c
-@@ -0,0 +1,360 @@
+@@ -0,0 +1,486 @@
 +/*
 + * Broadcom specific AMBA
 + * Bus scanning
@@ -1512,18 +1931,162 @@
 +	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;
@@ -1534,9 +2097,27 @@
 +	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);
@@ -1548,127 +2129,91 @@
 +		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
@@ -1731,7 +2276,7 @@
 +#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_
 +
@@ -1740,6 +2285,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"
@@ -1748,9 +2294,9 @@
 +struct bcma_bus;
 +
 +enum bcma_hosttype {
-+	BCMA_HOSTTYPE_NONE,
 +	BCMA_HOSTTYPE_PCI,
 +	BCMA_HOSTTYPE_SDIO,
++	BCMA_HOSTTYPE_SOC,
 +};
 +
 +struct bcma_chipinfo {
@@ -1864,6 +2410,7 @@
 +
 +	struct device dev;
 +	struct device *dma_dev;
++
 +	unsigned int irq;
 +	bool dev_registered;
 +
@@ -1872,6 +2419,9 @@
 +	u32 addr;
 +	u32 wrap;
 +
++	void __iomem *io_addr;
++	void __iomem *io_wrap;
++
 +	void *drvdata;
 +	struct list_head list;
 +};
@@ -1899,10 +2449,9 @@
 +};
 +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 {
@@ -1924,70 +2473,93 @@
 +	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);
@@ -2005,7 +2577,7 @@
 +#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_
 +
@@ -2032,6 +2604,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
@@ -2186,6 +2759,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) */
@@ -2209,6 +2783,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 */
@@ -2247,6 +2822,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)
 + */
@@ -2255,14 +2888,37 @@
 +	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 */
@@ -2283,6 +2939,8 @@
 +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);
 +
@@ -2301,6 +2959,15 @@
 +/* 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
@@ -2524,7 +3191,7 @@
  			 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
@@ -2656,10 +3323,80 @@
 +	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)
@@ -2679,6 +3416,9 @@
 +	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 */
@@ -2686,6 +3426,9 @@
 +		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;
@@ -2713,3 +3456,521 @@
 +{
 +	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_ */
diff --git a/target/linux/generic/patches-3.0/020-ssb_update.patch b/target/linux/generic/patches-3.0/020-ssb_update.patch
index 74e9c7fa12..32f5557673 100644
--- a/target/linux/generic/patches-3.0/020-ssb_update.patch
+++ b/target/linux/generic/patches-3.0/020-ssb_update.patch
@@ -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;
@@ -12,8 +49,28 @@
  
  	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);
  }
@@ -48,8 +105,28 @@
  {
  	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;
  }
@@ -77,16 +154,27 @@
  {
  	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(
  	}
  }
  
@@ -95,9 +183,37 @@
  {
  	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() */
@@ -106,7 +222,7 @@
  {
  	struct ssb_bus *bus, *n;
  	int err = 0;
-@@ -768,9 +768,9 @@ out:
+@@ -768,9 +769,9 @@ out:
  	return err;
  }
  
@@ -119,7 +235,7 @@
  {
  	int err;
  
-@@ -851,8 +851,8 @@ err_disable_xtal:
+@@ -851,8 +852,8 @@ err_disable_xtal:
  }
  
  #ifdef CONFIG_SSB_PCIHOST
@@ -130,7 +246,7 @@
  {
  	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
@@ -143,7 +259,7 @@
  {
  	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
@@ -155,7 +271,7 @@
  {
  	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 */
  
@@ -168,7 +284,7 @@
  {
  	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)
@@ -179,21 +295,84 @@
  	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)
  {
@@ -211,6 +390,15 @@
  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 */
@@ -231,8 +419,28 @@
  {
  	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) {
@@ -243,18 +451,59 @@
  			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;
@@ -263,3 +512,101 @@
  };
  
  
+@@ -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,
diff --git a/target/linux/generic/patches-3.0/025-bcma_backport.patch b/target/linux/generic/patches-3.0/025-bcma_backport.patch
index 5e6317f34c..95012ad8dd 100644
--- a/target/linux/generic/patches-3.0/025-bcma_backport.patch
+++ b/target/linux/generic/patches-3.0/025-bcma_backport.patch
@@ -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
  
@@ -21,24 +21,40 @@
 +	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 */
@@ -46,16 +62,35 @@
 -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 */
  
@@ -83,7 +118,7 @@
  
  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);
@@ -147,6 +182,8 @@
 +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;
@@ -159,9 +196,171 @@
 +	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:
@@ -169,7 +368,7 @@
  		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:
@@ -177,7 +376,39 @@
  		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");
@@ -192,9 +423,407 @@
  	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.
   **************************************************/
  
@@ -214,8 +843,10 @@
 +	    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 */
@@ -229,6 +860,9 @@
 +
 +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);
@@ -238,6 +872,8 @@
 +	} 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,
@@ -245,7 +881,14 @@
 +{
 +	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)
@@ -263,19 +906,110 @@
 +	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);
@@ -314,13 +1048,12 @@
 +	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,
@@ -331,7 +1064,46 @@
  	.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) },
@@ -339,26 +1111,278 @@
  	{ 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);
  	}
  
@@ -374,7 +1398,7 @@
  	/* 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;
  }
@@ -385,12 +1409,492 @@
  	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
@@ -522,10 +2026,80 @@
 +	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)
@@ -545,6 +2119,9 @@
 +	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 */
@@ -552,6 +2129,9 @@
 +		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;
@@ -564,15 +2144,27 @@
 +}
 --- 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;
  };
  
@@ -584,7 +2176,7 @@
  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);
@@ -597,55 +2189,139 @@
  	/* 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);
@@ -663,9 +2339,19 @@
  #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 */
@@ -680,15 +2366,196 @@
  #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 {
@@ -699,53 +2566,6 @@
 +				 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 @@
@@ -788,3 +2608,22 @@
  #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
index 0000000000..9dc63adfa2
--- /dev/null
+++ b/target/linux/generic/patches-3.1/020-ssb_update.patch
@@ -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
index 0000000000..671c6ce24b
--- /dev/null
+++ b/target/linux/generic/patches-3.1/025-bcma_backport.patch
@@ -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_ */