CONFIG_BCM47XX_SSB=y
CONFIG_BCM47XX_WDT=y
CONFIG_BCMA=y
+CONFIG_BCMA_BLOCKIO=y
CONFIG_BCMA_DEBUG=y
CONFIG_BCMA_DRIVER_MIPS=y
CONFIG_BCMA_DRIVER_PCI_HOSTMODE=y
CONFIG_BCMA_HOST_PCI_POSSIBLE=y
CONFIG_BCMA_HOST_SOC=y
CONFIG_BCMA_POSSIBLE=y
+CONFIG_BCMA_SFLASH=y
# CONFIG_BRCMUTIL is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_BUG is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_MT_DISABLED=y
-CONFIG_MTD_BCM47XX=y
+CONFIG_MTD_BCM47XX_PARTS=y
+CONFIG_MTD_BCM47XX_PFLASH=y
+CONFIG_MTD_BCM47XX_SFLASH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NO_HZ=y
+++ /dev/null
---- a/drivers/ssb/driver_pcicore.c
-+++ b/drivers/ssb/driver_pcicore.c
-@@ -412,16 +412,6 @@ static int __devinit pcicore_is_in_hostm
- * Workarounds.
- **************************************************/
-
--static void __devinit ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
--{
-- u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
-- if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
-- tmp &= ~0xF000;
-- tmp |= (pc->dev->core_index << 12);
-- pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp);
-- }
--}
--
- static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc)
- {
- return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
-@@ -529,8 +519,6 @@ void __devinit ssb_pcicore_init(struct s
- if (!ssb_device_is_enabled(dev))
- ssb_device_enable(dev, 0);
-
-- ssb_pcicore_fix_sprom_core_index(pc);
--
- #ifdef CONFIG_SSB_PCICORE_HOSTMODE
- pc->hostmode = pcicore_is_in_hostmode(pc);
- if (pc->hostmode)
ssb_printk(KERN_ERR PFX
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
-@@ -155,9 +155,16 @@ struct ssb_bus_ops {
+@@ -157,9 +157,16 @@ struct ssb_bus_ops {
#define SSB_DEV_MINI_MACPHY 0x823
#define SSB_DEV_ARM_1176 0x824
#define SSB_DEV_ARM_7TDMI 0x825
-From c4fb5adbe45b3a1cfc509a64bb92429ab0d6fc37 Mon Sep 17 00:00:00 2001
+From e6defe46ea936ebb309c9cab4f7fd14bdc0c5416 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/14] bcma: move parsing of EEPROM into own function.
+Subject: [PATCH 01/22] 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 ++++++++++++++++++++++++++-------------------------
-From dd6cbe9b9e2ae563659b34184f4cd9d905dc90d5 Mon Sep 17 00:00:00 2001
+From 47b0447e18f72724caf57ba7e4573e309fb2bfae 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/14] bcma: move initializing of struct bcma_bus to own function.
+Subject: [PATCH 02/22] 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 +++++++++++------
-From 9a920f4d8eed485f7b73e9b13dab0e49c64d3ff8 Mon Sep 17 00:00:00 2001
+From beb36a1a49227ca6c5778a667aefc8cd3fd56a4f 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/14] bcma: add functions to scan cores needed on SoCs
+Subject: [PATCH 03/22] 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.
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 | 3 +
- drivers/bcma/main.c | 45 +++++++++++++
+ 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, 151 insertions(+), 6 deletions(-)
+ 7 files changed, 154 insertions(+), 6 deletions(-)
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
int bcma_sprom_get(struct bcma_bus *bus);
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
-@@ -23,6 +23,9 @@ static inline u32 bcma_cc_write32_masked
+@@ -26,6 +26,9 @@ void bcma_core_chipcommon_init(struct bc
+ u32 leddc_on = 10;
+ u32 leddc_off = 90;
- void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
- {
+ 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 +41,8 @@ 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");
+@@ -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
-@@ -159,7 +159,10 @@ static void bcma_pcicore_serdes_workarou
+@@ -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;
- bcma_pcicore_serdes_workaround(pc);
++
+ 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
-@@ -167,6 +167,51 @@ void bcma_bus_unregister(struct bcma_bus
+@@ -169,6 +169,52 @@ void bcma_bus_unregister(struct bcma_bus
bcma_unregister_cores(bus);
}
+ match.class = BCMA_CL_SIM;
+ match.rev = BCMA_ANY_REV;
+
-+ /* Scan for devices (cores) */
++ /* 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);
+ 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);
+}
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
-@@ -185,6 +185,7 @@ struct bcma_bus {
+@@ -190,6 +190,7 @@ struct bcma_bus {
struct bcma_device *mapped_core;
struct list_head cores;
u8 nr_cores;
struct bcma_drv_pci drv_pci;
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -259,6 +259,7 @@ struct bcma_drv_cc {
+@@ -252,6 +252,7 @@ struct bcma_drv_cc {
u32 status;
u32 capabilities;
u32 capabilities_ext;
-From a807b2fb233af60028ed38ba237953bcffdf33e9 Mon Sep 17 00:00:00 2001
+From 22573303ad477fa07c948a9944e9c18fea9af724 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/14] bcma: add SOC bus
+Subject: [PATCH 04/22] 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 an embedded bus. An embedded
-system like the bcm4716 could register this bus and it searches for the
-bcma cores then.
+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 | 5 +
+ drivers/bcma/Kconfig | 4 +
drivers/bcma/Makefile | 1 +
- drivers/bcma/host_soc.c | 178 +++++++++++++++++++++++++++++++++++++++++
- drivers/bcma/main.c | 1 +
- drivers/bcma/scan.c | 24 +++++-
- include/linux/bcma/bcma.h | 4 +
+ drivers/bcma/host_soc.c | 183 +++++++++++++++++++++++++++++++++++++++++
+ drivers/bcma/main.c | 6 +-
+ drivers/bcma/scan.c | 42 ++++++++-
+ include/linux/bcma/bcma.h | 5 +-
include/linux/bcma/bcma_soc.h | 16 ++++
- 7 files changed, 227 insertions(+), 2 deletions(-)
+ 7 files changed, 250 insertions(+), 7 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
-@@ -27,6 +27,11 @@ config BCMA_HOST_PCI
- bool "Support for BCMA on PCI-host bus"
- depends on BCMA_HOST_PCI_POSSIBLE
+@@ -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
-+ default n
+
config BCMA_DEBUG
bool "BCMA debugging"
depends on BCMA
--- 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
+@@ -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
--- /dev/null
+++ b/drivers/bcma/host_soc.c
-@@ -0,0 +1,178 @@
+@@ -0,0 +1,183 @@
+/*
+ * Broadcom specific AMBA
+ * System on Chip (SoC) Host
+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(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
++ bus->mmio = ioremap_nocache(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1);
+ if (!bus->mmio)
+ return -ENOMEM;
+
+ bus->ops = &bcma_host_soc_ops;
+
+ /* Register */
-+ return bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
++ 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
-@@ -95,6 +95,7 @@ static int bcma_register_cores(struct bc
+@@ -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,8 +97,8 @@ 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_NONE:
case BCMA_HOSTTYPE_SDIO:
+ case BCMA_HOSTTYPE_SOC:
break;
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
-@@ -337,6 +337,14 @@ static int bcma_get_next_core(struct bcm
+@@ -337,6 +337,16 @@ static int bcma_get_next_core(struct bcm
}
}
}
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
-+ core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
++ core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
+ if (!core->io_addr)
+ return -ENOMEM;
-+ core->io_wrap = ioremap(core->wrap, BCMA_CORE_SIZE);
-+ if (!core->io_wrap)
++ core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
++ if (!core->io_wrap) {
++ iounmap(core->io_addr);
+ return -ENOMEM;
++ }
+ }
return 0;
}
-@@ -369,7 +377,13 @@ int bcma_bus_scan(struct bcma_bus *bus)
+@@ -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(erombase, BCMA_CORE_SIZE);
++ eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+ if (!eromptr)
+ return -ENOMEM;
-+ } else
++ } else {
+ eromptr = bus->mmio;
++ }
+
eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
bcma_scan_switch_core(bus, erombase);
-@@ -417,7 +431,13 @@ int __init bcma_bus_scan_early(struct bc
- int err, core_num = 0;
+@@ -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(erombase, BCMA_CORE_SIZE);
++ eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
+ if (!eromptr)
+ return -ENOMEM;
-+ } else
++ } 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
-@@ -17,6 +17,7 @@ enum bcma_hosttype {
- BCMA_HOSTTYPE_NONE,
+@@ -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 {
-@@ -133,6 +134,9 @@ struct bcma_device {
+@@ -138,6 +138,9 @@ struct bcma_device {
u32 addr;
u32 wrap;
-From 0a1a5fd8aab864e7b531ab88fd317ff7278d884d Mon Sep 17 00:00:00 2001
+From 5961a1401605cd1941d5260a03b1dc2e8ae80619 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/14] bcma: add mips driver
+Subject: [PATCH 05/22] 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
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
- drivers/bcma/Kconfig | 11 ++-
- drivers/bcma/Makefile | 1 +
- drivers/bcma/driver_mips.c | 234 +++++++++++++++++++++++++++++++++
- drivers/bcma/main.c | 19 +++
- include/linux/bcma/bcma.h | 2 +
- include/linux/bcma/bcma_driver_mips.h | 49 +++++++
- 6 files changed, 315 insertions(+), 1 deletions(-)
+ 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
-@@ -29,9 +29,18 @@ config BCMA_HOST_PCI
+@@ -36,7 +36,16 @@ config BCMA_DRIVER_PCI_HOSTMODE
config BCMA_HOST_SOC
bool
-- depends on BCMA && MIPS
+ depends on BCMA_DRIVER_MIPS
- default n
-
++
+config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver"
-+ depends on BCMA && MIPS
+ 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 @@
- bcma-y += main.o scan.o core.o sprom.o
+@@ -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,234 @@
+@@ -0,0 +1,243 @@
+/*
+ * Broadcom specific AMBA
+ * Broadcom MIPS32 74K core driver
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
-+/* The 47162a0 hangs when reading its registers */
++/* 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)
+{
+
+ 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.
-+ * If disabled, 5 is returned.
+ */
+unsigned int bcma_core_mips_irq(struct bcma_device *dev)
+{
+{
+ struct bcma_bus *bus = mcore->core->bus;
+
-+ mcore->flash_buswidth = 2;
-+ if (bus->drv_cc.core) {
-+ mcore->flash_window = 0x1c000000;
-+ mcore->flash_window_size = 0x02000000;
-+ 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:
-+ if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
-+ BCMA_CC_OTPS) == 0)
-+ mcore->flash_buswidth = 1;
-+ break;
-+ }
-+ } else {
-+ mcore->flash_window = 0x1fc00000;
-+ mcore->flash_window_size = 0x00400000;
++ 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");
+ }
+}
+
+}
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
-@@ -80,6 +80,7 @@ static int bcma_register_cores(struct bc
+@@ -84,6 +84,7 @@ static int bcma_register_cores(struct bc
case BCMA_CORE_CHIPCOMMON:
case BCMA_CORE_PCI:
case BCMA_CORE_PCIE:
continue;
}
-@@ -141,6 +142,15 @@ int bcma_bus_register(struct bcma_bus *b
+@@ -144,6 +145,13 @@ int bcma_bus_register(struct bcma_bus *b
bcma_core_chipcommon_init(&bus->drv_cc);
}
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ /* 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);
+ }
-+#endif
+
/* Init PCIE core */
core = bcma_find_core(bus, BCMA_CORE_PCIE);
if (core) {
-@@ -208,6 +218,15 @@ int __init bcma_bus_early_register(struc
+@@ -214,6 +222,13 @@ int __init bcma_bus_early_register(struc
bcma_core_chipcommon_init(&bus->drv_cc);
}
-+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ /* 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);
+ }
-+#endif
+
pr_info("Early bus registered\n");
#include <linux/ssb/ssb.h> /* SPROM sharing */
#include "bcma_regs.h"
-@@ -193,6 +194,7 @@ struct bcma_bus {
+@@ -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;
/* 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 @@
+
+#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
++#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
++#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
++#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
++#define BCMA_MIPS_IPSFLAG_IRQ4 0x3F000000
++#define BCMA_MIPS_IPSFLAG_IRQ4_SHIFT 24
+
+/* MIPS 74K core registers */
+#define BCMA_MIPS_MIPS74K_CORECTL 0x0000
+ struct bcma_device *core;
+ u8 setup_done:1;
+ unsigned int assigned_irqs;
-+
-+ u8 flash_buswidth;
-+ u32 flash_window;
-+ u32 flash_window_size;
+};
+
++#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);
+
-From b7c100827012ba588089807475affe0c69a3f817 Mon Sep 17 00:00:00 2001
+From 5088e81ecc5c953df7de84eeedd0817326bc4be4 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/14] bcma: add serial console support
+Subject: [PATCH 06/22] bcma: add serial console support
-This adds support for serial console to bcma, when operating on an
-embedded device.
+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 | 6 +++
- drivers/bcma/driver_chipcommon.c | 64 +++++++++++++++++++++++++++++++++
- drivers/bcma/driver_mips.c | 9 +++++
- include/linux/bcma/bcma_driver_mips.h | 11 ++++++
- 4 files changed, 90 insertions(+), 0 deletions(-)
+ 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,12 @@ void bcma_init_bus(struct bcma_bus *bus)
+@@ -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
-+extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
-+ struct bcma_drv_mips_serial_port *ports);
++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
-@@ -92,3 +92,67 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+@@ -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
-+int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
-+ struct bcma_drv_mips_serial_port *ports)
++void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+{
-+ int nr_ports = 0;
-+ u32 plltype;
+ unsigned int irq;
-+ u32 baud_base, div;
-+ u32 i, n;
++ u32 baud_base;
++ u32 i;
+ unsigned int ccrev = cc->core->id.rev;
++ struct bcma_serial_port *ports = cc->serial_ports;
+
-+ plltype = (cc->capabilities & BCMA_CC_CAP_PLLT);
-+ irq = bcma_core_mips_irq(cc->core);
-+
-+ if ((ccrev >= 11) && (ccrev != 15) && (ccrev != 20)) {
++ if (ccrev >= 11 && ccrev != 15) {
+ /* Fixed ALP clock */
-+ baud_base = 20000000;
-+ if (cc->capabilities & BCMA_CC_CAP_PMU) {
-+ /* FIXME: baud_base is different for devices with a PMU */
-+ WARN_ON(1);
-+ }
-+ div = 1;
++ 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);
+ }
-+ } else
++ } else {
+ pr_err("serial not supported on this device ccrev: 0x%x\n",
+ ccrev);
++ return;
++ }
+
-+ /* Determine the registers of the UARTs */
-+ n = (cc->capabilities & BCMA_CC_CAP_NRUART);
-+ for (i = 0; i < n; i++) {
-+ void __iomem *cc_mmio;
-+ void __iomem *uart_regs;
-+
-+ cc_mmio = cc->core->bus->mmio +
-+ (cc->core->core_index * BCMA_CORE_SIZE);
-+ uart_regs = cc_mmio + BCMA_CC_UART0_DATA;
-+ uart_regs += (i * 256);
++ irq = bcma_core_mips_irq(cc->core);
+
-+ nr_ports++;
-+ ports[i].regs = uart_regs;
++ /* 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;
+ }
-+
-+ return nr_ports;
+}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -157,6 +157,14 @@ static void bcma_core_mips_dump_irq(stru
- }
+--- 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);
}
-
-+static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
++
++u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
+{
-+ struct bcma_bus *bus = mcore->core->bus;
++ struct bcma_bus *bus = cc->core->bus;
+
-+ mcore->nr_serial_ports = bcma_chipco_serial_init(&bus->drv_cc,
-+ mcore->serial_ports);
++ 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;
+}
-+
- static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
- {
- struct bcma_bus *bus = mcore->core->bus;
-@@ -229,6 +237,7 @@ void bcma_core_mips_init(struct bcma_drv
+--- 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_core_mips_serial_init(mcore);
++ bcma_chipco_serial_init(&bus->drv_cc);
bcma_core_mips_flash_detect(mcore);
mcore->setup_done = true;
}
---- a/include/linux/bcma/bcma_driver_mips.h
-+++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -32,11 +32,22 @@
-
- struct bcma_device;
+--- 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 */
-+struct bcma_drv_mips_serial_port {
++/* 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;
+};
-+
- struct bcma_drv_mips {
- struct bcma_device *core;
- u8 setup_done:1;
- unsigned int assigned_irqs;
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
-+ int nr_serial_ports;
-+ struct bcma_drv_mips_serial_port serial_ports[4];
+ 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;
+
- u8 flash_buswidth;
- u32 flash_window;
- u32 flash_window_size;
++ int nr_serial_ports;
++ struct bcma_serial_port serial_ports[4];
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+ };
+
-From 257d5fe12600f08df764cac0abc17bef7b6fae9b Mon Sep 17 00:00:00 2001
+From e993e8342e660f29a048be872522eedabaa177e1 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 19 Jun 2011 17:51:30 +0200
-Subject: [PATCH 07/14] bcma: get CPU clock
+Date: Sat, 16 Jul 2011 15:19:38 +0200
+Subject: [PATCH 07/22] 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 | 3 +
- drivers/bcma/driver_chipcommon_pmu.c | 87 +++++++++++++++++++++++++++
- drivers/bcma/driver_mips.c | 12 ++++
- include/linux/bcma/bcma_driver_chipcommon.h | 35 +++++++++++
- include/linux/bcma/bcma_driver_mips.h | 1 +
- 5 files changed, 138 insertions(+), 0 deletions(-)
+ 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
-@@ -29,6 +29,9 @@ void bcma_init_bus(struct bcma_bus *bus)
- /* sprom.c */
- int bcma_sprom_get(struct bcma_bus *bus);
+@@ -36,6 +36,7 @@ void bcma_chipco_serial_init(struct bcma
-+/* driver_chipcommon_pmu.c */
-+extern u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
-+
- /* driver_chipcommon.c */
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- extern int bcma_chipco_serial_init(struct bcma_drv_cc *cc,
+ /* 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 @@
static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
u32 offset, u32 mask, u32 set)
{
-@@ -136,3 +143,83 @@ void bcma_pmu_init(struct bcma_drv_cc *c
- bcma_pmu_swreg_init(cc);
- bcma_pmu_workarounds(cc);
+@@ -162,3 +169,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+ }
+ return BCMA_CC_PMU_ALP_CLOCK;
}
+
-+static 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:
-+ /* always 20Mhz */
-+ return 20000 * 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);
+
-+ BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
++ 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;
+ 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",
+{
+ struct bcma_bus *bus = cc->core->bus;
+
-+ if ((cc->pmu.rev == 5 || cc->pmu.rev == 6 || cc->pmu.rev == 7) &&
-+ (bus->chipinfo.id != 0x4319))
-+ return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
-+ BCMA_CC_PMU5_MAINPLL_CPU);
++ 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
-@@ -157,6 +157,18 @@ static void bcma_core_mips_dump_irq(stru
+@@ -166,6 +166,18 @@ static void bcma_core_mips_dump_irq(stru
}
}
+}
+EXPORT_SYMBOL(bcma_cpu_clock);
+
- static void bcma_core_mips_serial_init(struct bcma_drv_mips *mcore)
+ 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
-@@ -246,6 +246,41 @@
- #define BCMA_CC_PLLCTL_DATA 0x0664
- #define BCMA_CC_SPROM 0x0830 /* SPROM beginning */
+@@ -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
+/* PLL usage in 4716/47162 */
+#define BCMA_CC_PMU4716_MAINPLL_PLL0 12
+
-+/* ALP clock on pre-PMU chips */
-+#define BCMA_CC_PMU_ALP_CLOCK 20000000
++/* 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
-+
++#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
-@@ -54,6 +54,7 @@ struct bcma_drv_mips {
- };
+@@ -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 void bcma_core_mips_init(struct bcma_drv_mips *mcore);
+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
+From 1db44bc4e7d5abb2966154ac57d1f035dc3e4ec1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 6 Jun 2011 00:07:36 +0200
+Subject: [PATCH 08/22] bcm47xx: prepare to support different buses
+
+Prepare bcm47xx to support different System buses. Before adding
+support for bcma it should be possible to build bcm47xx without the
+need of ssb. With this patch bcm47xx does not directly contain a
+ssb_bus, but a union contain all the supported system buses. As a SoC
+just uses one system bus a union is a good choice.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/gpio.c | 56 ++++++++++++++++----------
+ arch/mips/bcm47xx/nvram.c | 15 +++++--
+ arch/mips/bcm47xx/serial.c | 13 +++++-
+ arch/mips/bcm47xx/setup.c | 33 ++++++++++++---
+ arch/mips/bcm47xx/time.c | 9 +++-
+ arch/mips/bcm47xx/wgt634u.c | 14 ++++--
+ arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 14 ++++++-
+ arch/mips/include/asm/mach-bcm47xx/gpio.h | 55 ++++++++++++++++++-------
+ drivers/watchdog/bcm47xx_wdt.c | 12 +++++-
+ 9 files changed, 160 insertions(+), 61 deletions(-)
+
+--- a/arch/mips/bcm47xx/gpio.c
++++ b/arch/mips/bcm47xx/gpio.c
+@@ -20,42 +20,54 @@ static DECLARE_BITMAP(gpio_in_use, BCM47
+
+ int gpio_request(unsigned gpio, const char *tag)
+ {
+- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
+- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+- return -EINVAL;
+-
+- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
+- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+- return -EINVAL;
+-
+- if (test_and_set_bit(gpio, gpio_in_use))
+- return -EBUSY;
+-
+- return 0;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
++ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
++ return -EINVAL;
++
++ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
++ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
++ return -EINVAL;
++
++ if (test_and_set_bit(gpio, gpio_in_use))
++ return -EBUSY;
++
++ return 0;
++ }
++ return -EINVAL;
+ }
+ EXPORT_SYMBOL(gpio_request);
+
+ void gpio_free(unsigned gpio)
+ {
+- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
+- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+- return;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
++ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
++ return;
++
++ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
++ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
++ return;
+
+- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
+- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
++ clear_bit(gpio, gpio_in_use);
+ return;
+-
+- clear_bit(gpio, gpio_in_use);
++ }
+ }
+ EXPORT_SYMBOL(gpio_free);
+
+ int gpio_to_irq(unsigned gpio)
+ {
+- if (ssb_chipco_available(&ssb_bcm47xx.chipco))
+- return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
+- else if (ssb_extif_available(&ssb_bcm47xx.extif))
+- return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
+- else
+- return -EINVAL;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
++ return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
++ else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
++ return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
++ else
++ return -EINVAL;
++ }
++ return -EINVAL;
+ }
+ EXPORT_SYMBOL_GPL(gpio_to_irq);
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -26,14 +26,21 @@ static char nvram_buf[NVRAM_SPACE];
+ /* Probe for NVRAM header */
+ static void early_nvram_init(void)
+ {
+- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
++ struct ssb_mipscore *mcore_ssb;
+ struct nvram_header *header;
+ int i;
+- u32 base, lim, off;
++ u32 base = 0;
++ u32 lim = 0;
++ u32 off;
+ u32 *src, *dst;
+
+- base = mcore->flash_window;
+- lim = mcore->flash_window_size;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
++ base = mcore_ssb->flash_window;
++ lim = mcore_ssb->flash_window_size;
++ break;
++ }
+
+ off = FLASH_MIN;
+ while (off <= lim) {
+--- a/arch/mips/bcm47xx/serial.c
++++ b/arch/mips/bcm47xx/serial.c
+@@ -23,10 +23,10 @@ static struct platform_device uart8250_d
+ },
+ };
+
+-static int __init uart8250_init(void)
++static int __init uart8250_init_ssb(void)
+ {
+ int i;
+- struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
++ struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
+
+ memset(&uart8250_data, 0, sizeof(uart8250_data));
+
+@@ -45,6 +45,15 @@ static int __init uart8250_init(void)
+ return platform_device_register(&uart8250_device);
+ }
+
++static int __init uart8250_init(void)
++{
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ return uart8250_init_ssb();
++ }
++ return -EINVAL;
++}
++
+ module_init(uart8250_init);
+
+ MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -35,15 +35,22 @@
+ #include <bcm47xx.h>
+ #include <asm/mach-bcm47xx/nvram.h>
+
+-struct ssb_bus ssb_bcm47xx;
+-EXPORT_SYMBOL(ssb_bcm47xx);
++union bcm47xx_bus bcm47xx_bus;
++EXPORT_SYMBOL(bcm47xx_bus);
++
++enum bcm47xx_bus_type bcm47xx_active_bus_type;
++EXPORT_SYMBOL(bcm47xx_active_bus_type);
+
+ static void bcm47xx_machine_restart(char *command)
+ {
+ printk(KERN_ALERT "Please stand by while rebooting the system...\n");
+ local_irq_disable();
+ /* Set the watchdog timer to reset immediately */
+- ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
++ break;
++ }
+ while (1)
+ cpu_relax();
+ }
+@@ -52,7 +59,11 @@ static void bcm47xx_machine_halt(void)
+ {
+ /* Disable interrupts and watchdog and spin forever */
+ local_irq_disable();
+- ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
++ break;
++ }
+ while (1)
+ cpu_relax();
+ }
+@@ -247,7 +258,7 @@ static int bcm47xx_get_invariants(struct
+ return 0;
+ }
+
+-void __init plat_mem_setup(void)
++static void __init bcm47xx_register_ssb(void)
+ {
+ int err;
+ char buf[100];
+@@ -258,12 +269,12 @@ void __init plat_mem_setup(void)
+ printk(KERN_WARNING "bcm47xx: someone else already registered"
+ " a ssb SPROM callback handler (err %d)\n", err);
+
+- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
++ err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
+ bcm47xx_get_invariants);
+ if (err)
+ panic("Failed to initialize SSB bus (err %d)\n", err);
+
+- mcore = &ssb_bcm47xx.mipscore;
++ mcore = &bcm47xx_bus.ssb.mipscore;
+ if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+ if (strstr(buf, "console=ttyS1")) {
+ struct ssb_serial_port port;
+@@ -276,6 +287,14 @@ void __init plat_mem_setup(void)
+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
+ }
+ }
++}
++
++void __init plat_mem_setup(void)
++{
++ struct cpuinfo_mips *c = ¤t_cpu_data;
++
++ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
++ bcm47xx_register_ssb();
+
+ _machine_restart = bcm47xx_machine_restart;
+ _machine_halt = bcm47xx_machine_halt;
+--- a/arch/mips/bcm47xx/time.c
++++ b/arch/mips/bcm47xx/time.c
+@@ -30,7 +30,7 @@
+
+ void __init plat_time_init(void)
+ {
+- unsigned long hz;
++ unsigned long hz = 0;
+
+ /*
+ * Use deterministic values for initial counter interrupt
+@@ -39,7 +39,12 @@ void __init plat_time_init(void)
+ write_c0_count(0);
+ write_c0_compare(0xffff);
+
+- hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
++ break;
++ }
++
+ if (!hz)
+ hz = 100000000;
+
+--- a/arch/mips/bcm47xx/wgt634u.c
++++ b/arch/mips/bcm47xx/wgt634u.c
+@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int ir
+
+ /* Interrupts are shared, check if the current one is
+ a GPIO interrupt. */
+- if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
++ if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
+ SSB_CHIPCO_IRQ_GPIO))
+ return IRQ_NONE;
+
+@@ -132,22 +132,26 @@ static int __init wgt634u_init(void)
+ * machine. Use the MAC address as an heuristic. Netgear Inc. has
+ * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
+ */
++ u8 *et0mac;
+
+- u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
++ if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
++ return -ENODEV;
++
++ et0mac = bcm47xx_bus.ssb.sprom.et0mac;
+
+ if (et0mac[0] == 0x00 &&
+ ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
+ (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
+- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
++ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
+
+ printk(KERN_INFO "WGT634U machine detected.\n");
+
+ if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
+ gpio_interrupt, IRQF_SHARED,
+- "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
++ "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
+ gpio_direction_input(WGT634U_GPIO_RESET);
+ gpio_intmask(WGT634U_GPIO_RESET, 1);
+- ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
++ ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
+ SSB_CHIPCO_IRQ_GPIO,
+ SSB_CHIPCO_IRQ_GPIO);
+ }
+--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
++++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+@@ -19,7 +19,17 @@
+ #ifndef __ASM_BCM47XX_H
+ #define __ASM_BCM47XX_H
+
+-/* SSB bus */
+-extern struct ssb_bus ssb_bcm47xx;
++#include <linux/ssb/ssb.h>
++
++enum bcm47xx_bus_type {
++ BCM47XX_BUS_TYPE_SSB,
++};
++
++union bcm47xx_bus {
++ struct ssb_bus ssb;
++};
++
++extern union bcm47xx_bus bcm47xx_bus;
++extern enum bcm47xx_bus_type bcm47xx_active_bus_type;
+
+ #endif /* __ASM_BCM47XX_H */
+--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
++++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
+@@ -21,41 +21,66 @@ extern int gpio_to_irq(unsigned gpio);
+
+ static inline int gpio_get_value(unsigned gpio)
+ {
+- return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
++ }
++ return -EINVAL;
+ }
+
+ static inline void gpio_set_value(unsigned gpio, int value)
+ {
+- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
++ value ? 1 << gpio : 0);
++ }
+ }
+
+ static inline int gpio_direction_input(unsigned gpio)
+ {
+- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
+- return 0;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
++ return 0;
++ }
++ return -EINVAL;
+ }
+
+ static inline int gpio_direction_output(unsigned gpio, int value)
+ {
+- /* first set the gpio out value */
+- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
+- /* then set the gpio mode */
+- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
+- return 0;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ /* first set the gpio out value */
++ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
++ value ? 1 << gpio : 0);
++ /* then set the gpio mode */
++ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
++ return 0;
++ }
++ return -EINVAL;
+ }
+
+ static inline int gpio_intmask(unsigned gpio, int value)
+ {
+- ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
+- value ? 1 << gpio : 0);
+- return 0;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
++ value ? 1 << gpio : 0);
++ return 0;
++ }
++ return -EINVAL;
+ }
+
+ static inline int gpio_polarity(unsigned gpio, int value)
+ {
+- ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
+- value ? 1 << gpio : 0);
+- return 0;
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
++ value ? 1 << gpio : 0);
++ return 0;
++ }
++ return -EINVAL;
+ }
+
+
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -54,12 +54,20 @@ static atomic_t ticks;
+ static inline void bcm47xx_wdt_hw_start(void)
+ {
+ /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
+- ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
++ break;
++ }
+ }
+
+ static inline int bcm47xx_wdt_hw_stop(void)
+ {
+- return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
++ switch (bcm47xx_active_bus_type) {
++ case BCM47XX_BUS_TYPE_SSB:
++ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
++ }
++ return -EINVAL;
+ }
+
+ static void bcm47xx_timer_tick(unsigned long unused)
+++ /dev/null
-From f93062e72447b4a4a51afbe33ea086ce8c922587 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 19 Jun 2011 17:52:09 +0200
-Subject: [PATCH 08/14] bcma: add pci(e) host mode
-
-This adds some stub for a pci(e) host controller. This controller is
-found on some embedded devices to attach other chips.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/Kconfig | 6 ++++
- drivers/bcma/Makefile | 1 +
- drivers/bcma/bcma_private.h | 6 ++++
- drivers/bcma/driver_pci.c | 14 ++++++++++-
- drivers/bcma/driver_pci_host.c | 43 ++++++++++++++++++++++++++++++++++
- include/linux/bcma/bcma_driver_pci.h | 1 +
- 6 files changed, 70 insertions(+), 1 deletions(-)
- create mode 100644 drivers/bcma/driver_pci_host.c
-
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -32,6 +32,12 @@ config BCMA_HOST_SOC
- depends on BCMA_DRIVER_MIPS
- default n
-
-+config BCMA_DRIVER_PCI_HOSTMODE
-+ bool "Hostmode support for BCMA PCI core"
-+ depends on BCMA_DRIVER_MIPS
-+ help
-+ PCIcore hostmode operation (external PCI bus).
-+
- config BCMA_DRIVER_MIPS
- bool "BCMA Broadcom MIPS core driver"
- depends on BCMA && MIPS
---- a/drivers/bcma/Makefile
-+++ b/drivers/bcma/Makefile
-@@ -1,6 +1,7 @@
- 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
---- a/drivers/bcma/bcma_private.h
-+++ b/drivers/bcma/bcma_private.h
-@@ -38,6 +38,12 @@ extern int bcma_chipco_serial_init(struc
- struct bcma_drv_mips_serial_port *ports);
- #endif /* CONFIG_BCMA_DRIVER_MIPS */
-
-+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
-+/* driver_pci_host.c */
-+int bcma_core_pci_in_hostmode(struct bcma_drv_pci *pc);
-+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
-+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-+
- #ifdef CONFIG_BCMA_HOST_PCI
- /* host_pci.c */
- extern int __init bcma_host_pci_init(void);
---- a/drivers/bcma/driver_pci.c
-+++ b/drivers/bcma/driver_pci.c
-@@ -159,9 +159,21 @@ static void bcma_pcicore_serdes_workarou
-
- void bcma_core_pci_init(struct bcma_drv_pci *pc)
- {
-+ struct bcma_device *core = pc->core;
-+
- if (pc->setup_done)
- return;
-- bcma_pcicore_serdes_workaround(pc);
-+
-+ if (!bcma_core_is_enabled(core))
-+ bcma_core_enable(core, 0);
-+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
-+ pc->hostmode = bcma_core_pci_in_hostmode(pc);
-+ if (pc->hostmode)
-+ bcma_core_pci_hostmode_init(pc);
-+#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-+ if (!pc->hostmode)
-+ bcma_pcicore_serdes_workaround(pc);
-+
- pc->setup_done = true;
- }
-
---- /dev/null
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -0,0 +1,43 @@
-+/*
-+ * Broadcom specific AMBA
-+ * PCI Host mode
-+ *
-+ * Copyright 2005, Broadcom Corporation
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include "bcma_private.h"
-+#include <linux/bcma/bcma.h>
-+
-+#include <asm/paccess.h>
-+/* Probe a 32bit value on the bus and catch bus exceptions.
-+ * Returns nonzero on a bus exception.
-+ * This is MIPS specific */
-+#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
-+
-+
-+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
-+{
-+ /* TODO: implement PCI host mode */
-+}
-+
-+int bcma_core_pci_in_hostmode(struct bcma_drv_pci *pc)
-+{
-+ struct bcma_bus *bus = pc->core->bus;
-+ u16 chipid_top;
-+ u32 tmp;
-+
-+ chipid_top = (bus->chipinfo.id & 0xFF00);
-+ if (chipid_top != 0x4700 &&
-+ chipid_top != 0x5300)
-+ return 0;
-+
-+/* TODO: add when sprom is available
-+ * if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
-+ * return 0;
-+ */
-+
-+ return !mips_busprobe32(tmp, (bus->mmio + (pc->core->core_index *
-+ BCMA_CORE_SIZE)));
-+}
---- a/include/linux/bcma/bcma_driver_pci.h
-+++ b/include/linux/bcma/bcma_driver_pci.h
-@@ -78,6 +78,7 @@ struct pci_dev;
- struct bcma_drv_pci {
- struct bcma_device *core;
- u8 setup_done:1;
-+ u8 hostmode:1;
- };
-
- /* Register access */
--- /dev/null
+From 1f25ff1b0bb5a8deae3aba2ea9c58f9b83f367bb Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 22 Jun 2011 22:16:35 +0200
+Subject: [PATCH 09/22] bcm47xx: make it possible to build bcm47xx without ssb.
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/Kconfig | 8 +-------
+ arch/mips/bcm47xx/Kconfig | 18 ++++++++++++++++++
+ arch/mips/bcm47xx/Makefile | 3 ++-
+ arch/mips/bcm47xx/gpio.c | 6 ++++++
+ arch/mips/bcm47xx/nvram.c | 4 ++++
+ arch/mips/bcm47xx/serial.c | 4 ++++
+ arch/mips/bcm47xx/setup.c | 8 ++++++++
+ arch/mips/bcm47xx/time.c | 2 ++
+ arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 4 ++++
+ arch/mips/include/asm/mach-bcm47xx/gpio.h | 12 ++++++++++++
+ arch/mips/pci/pci-bcm47xx.c | 6 ++++++
+ drivers/watchdog/bcm47xx_wdt.c | 4 ++++
+ 12 files changed, 71 insertions(+), 8 deletions(-)
+ create mode 100644 arch/mips/bcm47xx/Kconfig
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -91,15 +91,8 @@ config BCM47XX
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select IRQ_CPU
+- select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+- select SSB
+- select SSB_DRIVER_MIPS
+- select SSB_DRIVER_EXTIF
+- select SSB_EMBEDDED
+- select SSB_B43_PCI_BRIDGE if PCI
+- select SSB_PCICORE_HOSTMODE if PCI
+ select GENERIC_GPIO
+ select SYS_HAS_EARLY_PRINTK
+ select CFE
+@@ -785,6 +778,7 @@ endchoice
+
+ source "arch/mips/alchemy/Kconfig"
+ source "arch/mips/ath79/Kconfig"
++source "arch/mips/bcm47xx/Kconfig"
+ source "arch/mips/bcm63xx/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+ source "arch/mips/jz4740/Kconfig"
+--- /dev/null
++++ b/arch/mips/bcm47xx/Kconfig
+@@ -0,0 +1,18 @@
++if BCM47XX
++
++config BCM47XX_SSB
++ bool "SSB Support for Broadcom BCM47XX"
++ select SYS_HAS_CPU_MIPS32_R1
++ select SSB
++ select SSB_DRIVER_MIPS
++ select SSB_DRIVER_EXTIF
++ select SSB_EMBEDDED
++ select SSB_B43_PCI_BRIDGE if PCI
++ select SSB_PCICORE_HOSTMODE if PCI
++ default y
++ help
++ Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
++
++ This will generate an image with support for SSB and MIPS32 R1 instruction set.
++
++endif
+--- a/arch/mips/bcm47xx/Makefile
++++ b/arch/mips/bcm47xx/Makefile
+@@ -3,4 +3,5 @@
+ # under Linux.
+ #
+
+-obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
++obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
++obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
+--- a/arch/mips/bcm47xx/gpio.c
++++ b/arch/mips/bcm47xx/gpio.c
+@@ -21,6 +21,7 @@ static DECLARE_BITMAP(gpio_in_use, BCM47
+ int gpio_request(unsigned gpio, const char *tag)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+@@ -34,6 +35,7 @@ int gpio_request(unsigned gpio, const ch
+ return -EBUSY;
+
+ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -42,6 +44,7 @@ EXPORT_SYMBOL(gpio_request);
+ void gpio_free(unsigned gpio)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+@@ -53,6 +56,7 @@ void gpio_free(unsigned gpio)
+
+ clear_bit(gpio, gpio_in_use);
+ return;
++#endif
+ }
+ }
+ EXPORT_SYMBOL(gpio_free);
+@@ -60,6 +64,7 @@ EXPORT_SYMBOL(gpio_free);
+ int gpio_to_irq(unsigned gpio)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
+ return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
+@@ -67,6 +72,7 @@ int gpio_to_irq(unsigned gpio)
+ return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
+ else
+ return -EINVAL;
++#endif
+ }
+ return -EINVAL;
+ }
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -26,7 +26,9 @@ static char nvram_buf[NVRAM_SPACE];
+ /* Probe for NVRAM header */
+ static void early_nvram_init(void)
+ {
++#ifdef CONFIG_BCM47XX_SSB
+ struct ssb_mipscore *mcore_ssb;
++#endif
+ struct nvram_header *header;
+ int i;
+ u32 base = 0;
+@@ -35,11 +37,13 @@ static void early_nvram_init(void)
+ u32 *src, *dst;
+
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+ base = mcore_ssb->flash_window;
+ lim = mcore_ssb->flash_window_size;
+ break;
++#endif
+ }
+
+ off = FLASH_MIN;
+--- a/arch/mips/bcm47xx/serial.c
++++ b/arch/mips/bcm47xx/serial.c
+@@ -23,6 +23,7 @@ static struct platform_device uart8250_d
+ },
+ };
+
++#ifdef CONFIG_BCM47XX_SSB
+ static int __init uart8250_init_ssb(void)
+ {
+ int i;
+@@ -44,12 +45,15 @@ static int __init uart8250_init_ssb(void
+ }
+ return platform_device_register(&uart8250_device);
+ }
++#endif
+
+ static int __init uart8250_init(void)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return uart8250_init_ssb();
++#endif
+ }
+ return -EINVAL;
+ }
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -47,9 +47,11 @@ static void bcm47xx_machine_restart(char
+ local_irq_disable();
+ /* Set the watchdog timer to reset immediately */
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+ break;
++#endif
+ }
+ while (1)
+ cpu_relax();
+@@ -60,14 +62,17 @@ static void bcm47xx_machine_halt(void)
+ /* Disable interrupts and watchdog and spin forever */
+ local_irq_disable();
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ break;
++#endif
+ }
+ while (1)
+ cpu_relax();
+ }
+
++#ifdef CONFIG_BCM47XX_SSB
+ #define READ_FROM_NVRAM(_outvar, name, buf) \
+ if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
+ sprom->_outvar = simple_strtoul(buf, NULL, 0);
+@@ -288,13 +293,16 @@ static void __init bcm47xx_register_ssb(
+ }
+ }
+ }
++#endif
+
+ void __init plat_mem_setup(void)
+ {
+ struct cpuinfo_mips *c = ¤t_cpu_data;
+
++#ifdef CONFIG_BCM47XX_SSB
+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+ bcm47xx_register_ssb();
++#endif
+
+ _machine_restart = bcm47xx_machine_restart;
+ _machine_halt = bcm47xx_machine_halt;
+--- a/arch/mips/bcm47xx/time.c
++++ b/arch/mips/bcm47xx/time.c
+@@ -40,9 +40,11 @@ void __init plat_time_init(void)
+ write_c0_compare(0xffff);
+
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+ break;
++#endif
+ }
+
+ if (!hz)
+--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
++++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+@@ -22,11 +22,15 @@
+ #include <linux/ssb/ssb.h>
+
+ enum bcm47xx_bus_type {
++#ifdef CONFIG_BCM47XX_SSB
+ BCM47XX_BUS_TYPE_SSB,
++#endif
+ };
+
+ union bcm47xx_bus {
++#ifdef CONFIG_BCM47XX_SSB
+ struct ssb_bus ssb;
++#endif
+ };
+
+ extern union bcm47xx_bus bcm47xx_bus;
+--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
++++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
+@@ -22,8 +22,10 @@ extern int gpio_to_irq(unsigned gpio);
+ static inline int gpio_get_value(unsigned gpio)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -31,18 +33,22 @@ static inline int gpio_get_value(unsigne
+ static inline void gpio_set_value(unsigned gpio, int value)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
++#endif
+ }
+ }
+
+ static inline int gpio_direction_input(unsigned gpio)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -50,6 +56,7 @@ static inline int gpio_direction_input(u
+ static inline int gpio_direction_output(unsigned gpio, int value)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ /* first set the gpio out value */
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+@@ -57,6 +64,7 @@ static inline int gpio_direction_output(
+ /* then set the gpio mode */
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -64,10 +72,12 @@ static inline int gpio_direction_output(
+ static inline int gpio_intmask(unsigned gpio, int value)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -75,10 +85,12 @@ static inline int gpio_intmask(unsigned
+ static inline int gpio_polarity(unsigned gpio, int value)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
+ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+--- a/arch/mips/pci/pci-bcm47xx.c
++++ b/arch/mips/pci/pci-bcm47xx.c
+@@ -25,6 +25,7 @@
+ #include <linux/types.h>
+ #include <linux/pci.h>
+ #include <linux/ssb/ssb.h>
++#include <bcm47xx.h>
+
+ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+ {
+@@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct
+
+ int pcibios_plat_dev_init(struct pci_dev *dev)
+ {
++#ifdef CONFIG_BCM47XX_SSB
+ int res;
+ u8 slot, pin;
+
++ if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
++ return 0;
++
+ res = ssb_pcibios_plat_dev_init(dev);
+ if (res < 0) {
+ printk(KERN_ALERT "PCI: Failed to init device %s\n",
+@@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev
+ }
+
+ dev->irq = res;
++#endif
+ return 0;
+ }
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -55,17 +55,21 @@ static inline void bcm47xx_wdt_hw_start(
+ {
+ /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+ break;
++#endif
+ }
+ }
+
+ static inline int bcm47xx_wdt_hw_stop(void)
+ {
+ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
++#endif
+ }
+ return -EINVAL;
+ }
+++ /dev/null
-From 5972feafaa3c71c1497b4ef4101b3c6855b7b64e Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Sun, 19 Jun 2011 19:14:11 +0200
-Subject: [PATCH 09/14] bcma: add check if sprom is available before accessing it.
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- drivers/bcma/main.c | 4 +++-
- drivers/bcma/sprom.c | 3 +++
- 2 files changed, 6 insertions(+), 1 deletions(-)
-
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -160,7 +160,9 @@ int bcma_bus_register(struct bcma_bus *b
-
- /* Try to get SPROM */
- err = bcma_sprom_get(bus);
-- if (err) {
-+ if (err == -ENOENT) {
-+ pr_err("No SPROM available\n");
-+ } else if (err) {
- pr_err("Failed to get SPROM: %d\n", err);
- return -ENOENT;
- }
---- a/drivers/bcma/sprom.c
-+++ b/drivers/bcma/sprom.c
-@@ -143,6 +143,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
- if (!bus->drv_cc.core)
- return -EOPNOTSUPP;
-
-+ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
-+ return -ENOENT;
-+
- sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
- GFP_KERNEL);
- if (!sprom)
--- /dev/null
+From 27aa4f76cfe54b6ce3bf98f4d5fd70ab1f60071f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 6 Jun 2011 00:07:37 +0200
+Subject: [PATCH 10/22] bcm47xx: add support for bcma bus
+
+This patch add support for the bcma bus. Broadcom uses only Mips 74K
+CPUs on the new SoC and on the old ons using ssb bus there are no Mips
+74K CPUs.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/Kconfig | 13 ++++++
+ arch/mips/bcm47xx/gpio.c | 22 +++++++++++
+ arch/mips/bcm47xx/nvram.c | 10 +++++
+ arch/mips/bcm47xx/serial.c | 29 ++++++++++++++
+ arch/mips/bcm47xx/setup.c | 53 +++++++++++++++++++++++++-
+ arch/mips/bcm47xx/time.c | 5 ++
+ arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 8 ++++
+ arch/mips/include/asm/mach-bcm47xx/gpio.h | 41 ++++++++++++++++++++
+ drivers/watchdog/bcm47xx_wdt.c | 11 +++++
+ 9 files changed, 190 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/bcm47xx/Kconfig
++++ b/arch/mips/bcm47xx/Kconfig
+@@ -15,4 +15,17 @@ config BCM47XX_SSB
+
+ This will generate an image with support for SSB and MIPS32 R1 instruction set.
+
++config BCM47XX_BCMA
++ bool "BCMA Support for Broadcom BCM47XX"
++ select SYS_HAS_CPU_MIPS32_R2
++ select BCMA
++ select BCMA_HOST_SOC
++ select BCMA_DRIVER_MIPS
++ select BCMA_DRIVER_PCI_HOSTMODE if PCI
++ default y
++ help
++ Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
++
++ This will generate an image with support for BCMA and MIPS32 R2 instruction set.
++
+ endif
+--- a/arch/mips/bcm47xx/gpio.c
++++ b/arch/mips/bcm47xx/gpio.c
+@@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const ch
+
+ return 0;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
++ return -EINVAL;
++
++ if (test_and_set_bit(gpio, gpio_in_use))
++ return -EBUSY;
++
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
+ clear_bit(gpio, gpio_in_use);
+ return;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ if (gpio >= BCM47XX_CHIPCO_GPIO_LINES)
++ return;
++
++ clear_bit(gpio, gpio_in_use);
++ return;
++#endif
+ }
+ }
+ EXPORT_SYMBOL(gpio_free);
+@@ -73,6 +91,10 @@ int gpio_to_irq(unsigned gpio)
+ else
+ return -EINVAL;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
++#endif
+ }
+ return -EINVAL;
+ }
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -29,6 +29,9 @@ static void early_nvram_init(void)
+ #ifdef CONFIG_BCM47XX_SSB
+ struct ssb_mipscore *mcore_ssb;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ struct bcma_drv_cc *bcma_cc;
++#endif
+ struct nvram_header *header;
+ int i;
+ u32 base = 0;
+@@ -44,6 +47,13 @@ static void early_nvram_init(void)
+ lim = mcore_ssb->flash_window_size;
+ break;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ base = bcma_cc->pflash.window;
++ lim = bcma_cc->pflash.window_size;
++ break;
++#endif
+ }
+
+ off = FLASH_MIN;
+--- a/arch/mips/bcm47xx/serial.c
++++ b/arch/mips/bcm47xx/serial.c
+@@ -47,6 +47,31 @@ static int __init uart8250_init_ssb(void
+ }
+ #endif
+
++#ifdef CONFIG_BCM47XX_BCMA
++static int __init uart8250_init_bcma(void)
++{
++ int i;
++ struct bcma_drv_cc *cc = &(bcm47xx_bus.bcma.bus.drv_cc);
++
++ memset(&uart8250_data, 0, sizeof(uart8250_data));
++
++ for (i = 0; i < cc->nr_serial_ports; i++) {
++ struct plat_serial8250_port *p = &(uart8250_data[i]);
++ struct bcma_serial_port *bcma_port;
++ bcma_port = &(cc->serial_ports[i]);
++
++ p->mapbase = (unsigned int) bcma_port->regs;
++ p->membase = (void *) bcma_port->regs;
++ p->irq = bcma_port->irq + 2;
++ p->uartclk = bcma_port->baud_base;
++ p->regshift = bcma_port->reg_shift;
++ p->iotype = UPIO_MEM;
++ p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
++ }
++ return platform_device_register(&uart8250_device);
++}
++#endif
++
+ static int __init uart8250_init(void)
+ {
+ switch (bcm47xx_active_bus_type) {
+@@ -54,6 +79,10 @@ static int __init uart8250_init(void)
+ case BCM47XX_BUS_TYPE_SSB:
+ return uart8250_init_ssb();
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ return uart8250_init_bcma();
++#endif
+ }
+ return -EINVAL;
+ }
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -29,6 +29,7 @@
+ #include <linux/types.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_embedded.h>
++#include <linux/bcma/bcma_soc.h>
+ #include <asm/bootinfo.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+@@ -52,6 +53,11 @@ static void bcm47xx_machine_restart(char
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+ break;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
++ break;
++#endif
+ }
+ while (1)
+ cpu_relax();
+@@ -67,6 +73,11 @@ static void bcm47xx_machine_halt(void)
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ break;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
++ break;
++#endif
+ }
+ while (1)
+ cpu_relax();
+@@ -295,16 +306,54 @@ static void __init bcm47xx_register_ssb(
+ }
+ #endif
+
++#ifdef CONFIG_BCM47XX_BCMA
++static void __init bcm47xx_register_bcma(void)
++{
++ int err;
++
++ err = bcma_host_soc_register(&bcm47xx_bus.bcma);
++ if (err)
++ panic("Failed to initialize BCMA bus (err %d)\n", err);
++}
++#endif
++
+ void __init plat_mem_setup(void)
+ {
+ struct cpuinfo_mips *c = ¤t_cpu_data;
+
++ if (c->cputype == CPU_74K) {
++ printk(KERN_INFO "bcm47xx: using bcma bus\n");
++#ifdef CONFIG_BCM47XX_BCMA
++ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_BCMA;
++ bcm47xx_register_bcma();
++#endif
++ } else {
++ printk(KERN_INFO "bcm47xx: using ssb bus\n");
+ #ifdef CONFIG_BCM47XX_SSB
+- bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
+- bcm47xx_register_ssb();
++ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
++ bcm47xx_register_ssb();
+ #endif
++ }
+
+ _machine_restart = bcm47xx_machine_restart;
+ _machine_halt = bcm47xx_machine_halt;
+ pm_power_off = bcm47xx_machine_halt;
+ }
++
++static int __init bcm47xx_register_bus_complete(void)
++{
++ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ /* Nothing to do */
++ break;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_bus_register(&bcm47xx_bus.bcma.bus);
++ break;
++#endif
++ }
++ return 0;
++}
++device_initcall(bcm47xx_register_bus_complete);
+--- a/arch/mips/bcm47xx/time.c
++++ b/arch/mips/bcm47xx/time.c
+@@ -45,6 +45,11 @@ void __init plat_time_init(void)
+ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
+ break;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
++ break;
++#endif
+ }
+
+ if (!hz)
+--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
++++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+@@ -20,17 +20,25 @@
+ #define __ASM_BCM47XX_H
+
+ #include <linux/ssb/ssb.h>
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_soc.h>
+
+ enum bcm47xx_bus_type {
+ #ifdef CONFIG_BCM47XX_SSB
+ BCM47XX_BUS_TYPE_SSB,
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ BCM47XX_BUS_TYPE_BCMA,
++#endif
+ };
+
+ union bcm47xx_bus {
+ #ifdef CONFIG_BCM47XX_SSB
+ struct ssb_bus ssb;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ struct bcma_soc bcma;
++#endif
+ };
+
+ extern union bcm47xx_bus bcm47xx_bus;
+--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
++++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
+@@ -10,6 +10,7 @@
+ #define __BCM47XX_GPIO_H
+
+ #include <linux/ssb/ssb_embedded.h>
++#include <linux/bcma/bcma.h>
+ #include <asm/mach-bcm47xx/bcm47xx.h>
+
+ #define BCM47XX_EXTIF_GPIO_LINES 5
+@@ -26,6 +27,11 @@ static inline int gpio_get_value(unsigne
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
++ 1 << gpio);
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -37,6 +43,13 @@ static inline void gpio_set_value(unsign
+ case BCM47XX_BUS_TYPE_SSB:
+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
+ value ? 1 << gpio : 0);
++ return;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
++ value ? 1 << gpio : 0);
++ return;
+ #endif
+ }
+ }
+@@ -49,6 +62,12 @@ static inline int gpio_direction_input(u
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
+ return 0;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
++ 0);
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -65,6 +84,16 @@ static inline int gpio_direction_output(
+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
+ return 0;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ /* first set the gpio out value */
++ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
++ value ? 1 << gpio : 0);
++ /* then set the gpio mode */
++ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
++ 1 << gpio);
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -78,6 +107,12 @@ static inline int gpio_intmask(unsigned
+ value ? 1 << gpio : 0);
+ return 0;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
++ 1 << gpio, value ? 1 << gpio : 0);
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -91,6 +126,12 @@ static inline int gpio_polarity(unsigned
+ value ? 1 << gpio : 0);
+ return 0;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
++ 1 << gpio, value ? 1 << gpio : 0);
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+--- a/drivers/watchdog/bcm47xx_wdt.c
++++ b/drivers/watchdog/bcm47xx_wdt.c
+@@ -60,6 +60,12 @@ static inline void bcm47xx_wdt_hw_start(
+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
+ break;
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
++ 0xfffffff);
++ break;
++#endif
+ }
+ }
+
+@@ -70,6 +76,11 @@ static inline int bcm47xx_wdt_hw_stop(vo
+ case BCM47XX_BUS_TYPE_SSB:
+ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
+ #endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+++ /dev/null
-From c0886db6357de20fba4f7c0602eceefba3ad343b Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Mon, 6 Jun 2011 00:07:36 +0200
-Subject: [PATCH 10/14] bcm47xx: prepare to support different buses
-
-The ssb bus is not hod directly any more. there is now a union which
-contains all the supported buses, now just ssb. As just one system bus
-can be used at a time the union does not cause any problems.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/gpio.c | 56 ++++++++++++++++----------
- arch/mips/bcm47xx/nvram.c | 15 +++++--
- arch/mips/bcm47xx/serial.c | 13 +++++-
- arch/mips/bcm47xx/setup.c | 32 +++++++++++---
- arch/mips/bcm47xx/time.c | 9 +++-
- arch/mips/bcm47xx/wgt634u.c | 13 ++++--
- arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 14 ++++++-
- arch/mips/include/asm/mach-bcm47xx/gpio.h | 55 ++++++++++++++++++-------
- drivers/watchdog/bcm47xx_wdt.c | 12 +++++-
- 9 files changed, 158 insertions(+), 61 deletions(-)
-
---- a/arch/mips/bcm47xx/gpio.c
-+++ b/arch/mips/bcm47xx/gpio.c
-@@ -20,42 +20,54 @@ static DECLARE_BITMAP(gpio_in_use, BCM47
-
- int gpio_request(unsigned gpio, const char *tag)
- {
-- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
-- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-- return -EINVAL;
--
-- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
-- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-- return -EINVAL;
--
-- if (test_and_set_bit(gpio, gpio_in_use))
-- return -EBUSY;
--
-- return 0;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
-+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-+ return -EINVAL;
-+
-+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
-+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-+ return -EINVAL;
-+
-+ if (test_and_set_bit(gpio, gpio_in_use))
-+ return -EBUSY;
-+
-+ return 0;
-+ }
-+ return -EINVAL;
- }
- EXPORT_SYMBOL(gpio_request);
-
- void gpio_free(unsigned gpio)
- {
-- if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
-- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-- return;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
-+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-+ return;
-+
-+ if (ssb_extif_available(&bcm47xx_bus.ssb.extif) &&
-+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-+ return;
-
-- if (ssb_extif_available(&ssb_bcm47xx.extif) &&
-- ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
-+ clear_bit(gpio, gpio_in_use);
- return;
--
-- clear_bit(gpio, gpio_in_use);
-+ }
- }
- EXPORT_SYMBOL(gpio_free);
-
- int gpio_to_irq(unsigned gpio)
- {
-- if (ssb_chipco_available(&ssb_bcm47xx.chipco))
-- return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
-- else if (ssb_extif_available(&ssb_bcm47xx.extif))
-- return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
-- else
-- return -EINVAL;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
-+ return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
-+ else if (ssb_extif_available(&bcm47xx_bus.ssb.extif))
-+ return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
-+ else
-+ return -EINVAL;
-+ }
-+ return -EINVAL;
- }
- EXPORT_SYMBOL_GPL(gpio_to_irq);
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -26,14 +26,21 @@ static char nvram_buf[NVRAM_SPACE];
- /* Probe for NVRAM header */
- static void early_nvram_init(void)
- {
-- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
-+ struct ssb_mipscore *mcore_ssb;
- struct nvram_header *header;
- int i;
-- u32 base, lim, off;
-+ u32 base = 0;
-+ u32 lim = 0;
-+ u32 off;
- u32 *src, *dst;
-
-- base = mcore->flash_window;
-- lim = mcore->flash_window_size;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
-+ base = mcore_ssb->flash_window;
-+ lim = mcore_ssb->flash_window_size;
-+ break;
-+ }
-
- off = FLASH_MIN;
- while (off <= lim) {
---- a/arch/mips/bcm47xx/serial.c
-+++ b/arch/mips/bcm47xx/serial.c
-@@ -23,10 +23,10 @@ static struct platform_device uart8250_d
- },
- };
-
--static int __init uart8250_init(void)
-+static int __init uart8250_init_ssb(void)
- {
- int i;
-- struct ssb_mipscore *mcore = &(ssb_bcm47xx.mipscore);
-+ struct ssb_mipscore *mcore = &(bcm47xx_bus.ssb.mipscore);
-
- memset(&uart8250_data, 0, sizeof(uart8250_data));
-
-@@ -45,6 +45,15 @@ static int __init uart8250_init(void)
- return platform_device_register(&uart8250_device);
- }
-
-+static int __init uart8250_init(void)
-+{
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ return uart8250_init_ssb();
-+ }
-+ return -EINVAL;
-+}
-+
- module_init(uart8250_init);
-
- MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -35,15 +35,22 @@
- #include <bcm47xx.h>
- #include <asm/mach-bcm47xx/nvram.h>
-
--struct ssb_bus ssb_bcm47xx;
--EXPORT_SYMBOL(ssb_bcm47xx);
-+union bcm47xx_bus bcm47xx_bus;
-+EXPORT_SYMBOL(bcm47xx_bus);
-+
-+enum bcm47xx_bus_type bcm47xx_active_bus_type;
-+EXPORT_SYMBOL(bcm47xx_active_bus_type);
-
- static void bcm47xx_machine_restart(char *command)
- {
- printk(KERN_ALERT "Please stand by while rebooting the system...\n");
- local_irq_disable();
- /* Set the watchdog timer to reset immediately */
-- ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
-+ break;
-+ }
- while (1)
- cpu_relax();
- }
-@@ -52,7 +59,11 @@ static void bcm47xx_machine_halt(void)
- {
- /* Disable interrupts and watchdog and spin forever */
- local_irq_disable();
-- ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
-+ break;
-+ }
- while (1)
- cpu_relax();
- }
-@@ -247,7 +258,7 @@ static int bcm47xx_get_invariants(struct
- return 0;
- }
-
--void __init plat_mem_setup(void)
-+static void __init bcm47xx_register_ssb(void)
- {
- int err;
- char buf[100];
-@@ -258,12 +269,12 @@ void __init plat_mem_setup(void)
- printk(KERN_WARNING "bcm47xx: someone else already registered"
- " a ssb SPROM callback handler (err %d)\n", err);
-
-- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
-+ err = ssb_bus_ssbbus_register(&(bcm47xx_bus.ssb), SSB_ENUM_BASE,
- bcm47xx_get_invariants);
- if (err)
- panic("Failed to initialize SSB bus (err %d)\n", err);
-
-- mcore = &ssb_bcm47xx.mipscore;
-+ mcore = &bcm47xx_bus.ssb.mipscore;
- if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
- if (strstr(buf, "console=ttyS1")) {
- struct ssb_serial_port port;
-@@ -276,6 +287,14 @@ void __init plat_mem_setup(void)
- memcpy(&mcore->serial_ports[1], &port, sizeof(port));
- }
- }
-+}
-+
-+void __init plat_mem_setup(void)
-+{
-+ struct cpuinfo_mips *c = ¤t_cpu_data;
-+
-+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
-+ bcm47xx_register_ssb();
-
- _machine_restart = bcm47xx_machine_restart;
- _machine_halt = bcm47xx_machine_halt;
---- a/arch/mips/bcm47xx/time.c
-+++ b/arch/mips/bcm47xx/time.c
-@@ -30,7 +30,7 @@
-
- void __init plat_time_init(void)
- {
-- unsigned long hz;
-+ unsigned long hz = 0;
-
- /*
- * Use deterministic values for initial counter interrupt
-@@ -39,7 +39,12 @@ void __init plat_time_init(void)
- write_c0_count(0);
- write_c0_compare(0xffff);
-
-- hz = ssb_cpu_clock(&ssb_bcm47xx.mipscore) / 2;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
-+ break;
-+ }
-+
- if (!hz)
- hz = 100000000;
-
---- a/arch/mips/bcm47xx/wgt634u.c
-+++ b/arch/mips/bcm47xx/wgt634u.c
-@@ -108,7 +108,7 @@ static irqreturn_t gpio_interrupt(int ir
-
- /* Interrupts are shared, check if the current one is
- a GPIO interrupt. */
-- if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
-+ if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
- SSB_CHIPCO_IRQ_GPIO))
- return IRQ_NONE;
-
-@@ -133,21 +133,24 @@ static int __init wgt634u_init(void)
- * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
- */
-
-- u8 *et0mac = ssb_bcm47xx.sprom.et0mac;
-+ if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
-+ return -ENODEV;
-+
-+ u8 *et0mac = bcm47xx_bus.ssb.sprom.et0mac;
-
- if (et0mac[0] == 0x00 &&
- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
- (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
-- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
-+ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
-
- printk(KERN_INFO "WGT634U machine detected.\n");
-
- if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
- gpio_interrupt, IRQF_SHARED,
-- "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
-+ "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
- gpio_direction_input(WGT634U_GPIO_RESET);
- gpio_intmask(WGT634U_GPIO_RESET, 1);
-- ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
-+ ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
- SSB_CHIPCO_IRQ_GPIO,
- SSB_CHIPCO_IRQ_GPIO);
- }
---- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
-@@ -19,7 +19,17 @@
- #ifndef __ASM_BCM47XX_H
- #define __ASM_BCM47XX_H
-
--/* SSB bus */
--extern struct ssb_bus ssb_bcm47xx;
-+#include <linux/ssb/ssb.h>
-+
-+enum bcm47xx_bus_type {
-+ BCM47XX_BUS_TYPE_SSB,
-+};
-+
-+union bcm47xx_bus {
-+ struct ssb_bus ssb;
-+};
-+
-+extern union bcm47xx_bus bcm47xx_bus;
-+extern enum bcm47xx_bus_type bcm47xx_active_bus_type;
-
- #endif /* __ASM_BCM47XX_H */
---- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
-@@ -21,41 +21,66 @@ extern int gpio_to_irq(unsigned gpio);
-
- static inline int gpio_get_value(unsigned gpio)
- {
-- return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
-+ }
-+ return -EINVAL;
- }
-
- static inline void gpio_set_value(unsigned gpio, int value)
- {
-- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
-+ value ? 1 << gpio : 0);
-+ }
- }
-
- static inline int gpio_direction_input(unsigned gpio)
- {
-- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
-- return 0;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
-+ return 0;
-+ }
-+ return -EINVAL;
- }
-
- static inline int gpio_direction_output(unsigned gpio, int value)
- {
-- /* first set the gpio out value */
-- ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
-- /* then set the gpio mode */
-- ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
-- return 0;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ /* first set the gpio out value */
-+ ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
-+ value ? 1 << gpio : 0);
-+ /* then set the gpio mode */
-+ ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
-+ return 0;
-+ }
-+ return -EINVAL;
- }
-
- static inline int gpio_intmask(unsigned gpio, int value)
- {
-- ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
-- value ? 1 << gpio : 0);
-- return 0;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
-+ value ? 1 << gpio : 0);
-+ return 0;
-+ }
-+ return -EINVAL;
- }
-
- static inline int gpio_polarity(unsigned gpio, int value)
- {
-- ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
-- value ? 1 << gpio : 0);
-- return 0;
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
-+ value ? 1 << gpio : 0);
-+ return 0;
-+ }
-+ return -EINVAL;
- }
-
-
---- a/drivers/watchdog/bcm47xx_wdt.c
-+++ b/drivers/watchdog/bcm47xx_wdt.c
-@@ -54,12 +54,20 @@ static atomic_t ticks;
- static inline void bcm47xx_wdt_hw_start(void)
- {
- /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
-- ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
-+ break;
-+ }
- }
-
- static inline int bcm47xx_wdt_hw_stop(void)
- {
-- return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
-+ switch (bcm47xx_active_bus_type) {
-+ case BCM47XX_BUS_TYPE_SSB:
-+ return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
-+ }
-+ return -EINVAL;
- }
-
- static void bcm47xx_timer_tick(unsigned long unused)
--- /dev/null
+From a277b0b02837a167a5766c048dedef8dfc2fb707 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 6 Jun 2011 00:07:38 +0200
+Subject: [PATCH 11/22] bcm47xx: fix irq assignment for new SoCs.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/irq.c | 12 ++++++++++++
+ 1 files changed, 12 insertions(+), 0 deletions(-)
+
+--- a/arch/mips/bcm47xx/irq.c
++++ b/arch/mips/bcm47xx/irq.c
+@@ -26,6 +26,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <asm/irq_cpu.h>
++#include <bcm47xx.h>
+
+ void plat_irq_dispatch(void)
+ {
+@@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
+
+ void __init arch_init_irq(void)
+ {
++#ifdef CONFIG_BCM47XX_BCMA
++ if (bcm47xx_active_bus_type == BCM47XX_BUS_TYPE_BCMA) {
++ bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
++ BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
++ /*
++ * the kernel reads the timer irq from some register and thinks
++ * it's #5, but we offset it by 2 and route to #7
++ */
++ cp0_compare_irq = 7;
++ }
++#endif
+ mips_cpu_irq_init();
+ }
+++ /dev/null
-From 82d03f33ba3e41511e56bd6ae5ae93b3b1bd0b63 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Wed, 22 Jun 2011 22:16:35 +0200
-Subject: [PATCH 11/14] bcm47xx: make it possible to build bcm47xx without ssb.
-
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/Kconfig | 8 +-------
- arch/mips/bcm47xx/Kconfig | 18 ++++++++++++++++++
- arch/mips/bcm47xx/Makefile | 3 ++-
- arch/mips/bcm47xx/gpio.c | 6 ++++++
- arch/mips/bcm47xx/nvram.c | 4 ++++
- arch/mips/bcm47xx/serial.c | 4 ++++
- arch/mips/bcm47xx/setup.c | 8 ++++++++
- arch/mips/bcm47xx/time.c | 2 ++
- arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 4 ++++
- arch/mips/include/asm/mach-bcm47xx/gpio.h | 12 ++++++++++++
- arch/mips/pci/pci-bcm47xx.c | 6 ++++++
- drivers/watchdog/bcm47xx_wdt.c | 4 ++++
- 12 files changed, 71 insertions(+), 8 deletions(-)
- create mode 100644 arch/mips/bcm47xx/Kconfig
-
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -91,15 +91,8 @@ config BCM47XX
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select IRQ_CPU
-- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_LITTLE_ENDIAN
-- select SSB
-- select SSB_DRIVER_MIPS
-- select SSB_DRIVER_EXTIF
-- select SSB_EMBEDDED
-- select SSB_B43_PCI_BRIDGE if PCI
-- select SSB_PCICORE_HOSTMODE if PCI
- select GENERIC_GPIO
- select SYS_HAS_EARLY_PRINTK
- select CFE
-@@ -785,6 +778,7 @@ endchoice
-
- source "arch/mips/alchemy/Kconfig"
- source "arch/mips/ath79/Kconfig"
-+source "arch/mips/bcm47xx/Kconfig"
- source "arch/mips/bcm63xx/Kconfig"
- source "arch/mips/jazz/Kconfig"
- source "arch/mips/jz4740/Kconfig"
---- /dev/null
-+++ b/arch/mips/bcm47xx/Kconfig
-@@ -0,0 +1,18 @@
-+if BCM47XX
-+
-+config BCM47XX_SSB
-+ bool "SSB Support for Broadcom BCM47XX"
-+ select SYS_HAS_CPU_MIPS32_R1
-+ select SSB
-+ select SSB_DRIVER_MIPS
-+ select SSB_DRIVER_EXTIF
-+ select SSB_EMBEDDED
-+ select SSB_B43_PCI_BRIDGE if PCI
-+ select SSB_PCICORE_HOSTMODE if PCI
-+ default y
-+ help
-+ Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support bus.
-+
-+ This will generate an image with support for SSB and MIPS32 R2 instruction set.
-+
-+endif
---- a/arch/mips/bcm47xx/Makefile
-+++ b/arch/mips/bcm47xx/Makefile
-@@ -3,4 +3,5 @@
- # under Linux.
- #
-
--obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
-+obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o
-+obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
---- a/arch/mips/bcm47xx/gpio.c
-+++ b/arch/mips/bcm47xx/gpio.c
-@@ -21,6 +21,7 @@ static DECLARE_BITMAP(gpio_in_use, BCM47
- int gpio_request(unsigned gpio, const char *tag)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-@@ -34,6 +35,7 @@ int gpio_request(unsigned gpio, const ch
- return -EBUSY;
-
- return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -42,6 +44,7 @@ EXPORT_SYMBOL(gpio_request);
- void gpio_free(unsigned gpio)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco) &&
- ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
-@@ -53,6 +56,7 @@ void gpio_free(unsigned gpio)
-
- clear_bit(gpio, gpio_in_use);
- return;
-+#endif
- }
- }
- EXPORT_SYMBOL(gpio_free);
-@@ -60,6 +64,7 @@ EXPORT_SYMBOL(gpio_free);
- int gpio_to_irq(unsigned gpio)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- if (ssb_chipco_available(&bcm47xx_bus.ssb.chipco))
- return ssb_mips_irq(bcm47xx_bus.ssb.chipco.dev) + 2;
-@@ -67,6 +72,7 @@ int gpio_to_irq(unsigned gpio)
- return ssb_mips_irq(bcm47xx_bus.ssb.extif.dev) + 2;
- else
- return -EINVAL;
-+#endif
- }
- return -EINVAL;
- }
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -26,7 +26,9 @@ static char nvram_buf[NVRAM_SPACE];
- /* Probe for NVRAM header */
- static void early_nvram_init(void)
- {
-+#ifdef CONFIG_BCM47XX_SSB
- struct ssb_mipscore *mcore_ssb;
-+#endif
- struct nvram_header *header;
- int i;
- u32 base = 0;
-@@ -35,11 +37,13 @@ static void early_nvram_init(void)
- u32 *src, *dst;
-
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- mcore_ssb = &bcm47xx_bus.ssb.mipscore;
- base = mcore_ssb->flash_window;
- lim = mcore_ssb->flash_window_size;
- break;
-+#endif
- }
-
- off = FLASH_MIN;
---- a/arch/mips/bcm47xx/serial.c
-+++ b/arch/mips/bcm47xx/serial.c
-@@ -23,6 +23,7 @@ static struct platform_device uart8250_d
- },
- };
-
-+#ifdef CONFIG_BCM47XX_SSB
- static int __init uart8250_init_ssb(void)
- {
- int i;
-@@ -44,12 +45,15 @@ static int __init uart8250_init_ssb(void
- }
- return platform_device_register(&uart8250_device);
- }
-+#endif
-
- static int __init uart8250_init(void)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- return uart8250_init_ssb();
-+#endif
- }
- return -EINVAL;
- }
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -47,9 +47,11 @@ static void bcm47xx_machine_restart(char
- local_irq_disable();
- /* Set the watchdog timer to reset immediately */
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
- break;
-+#endif
- }
- while (1)
- cpu_relax();
-@@ -60,14 +62,17 @@ static void bcm47xx_machine_halt(void)
- /* Disable interrupts and watchdog and spin forever */
- local_irq_disable();
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
- break;
-+#endif
- }
- while (1)
- cpu_relax();
- }
-
-+#ifdef CONFIG_BCM47XX_SSB
- #define READ_FROM_NVRAM(_outvar, name, buf) \
- if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
- sprom->_outvar = simple_strtoul(buf, NULL, 0);
-@@ -288,13 +293,16 @@ static void __init bcm47xx_register_ssb(
- }
- }
- }
-+#endif
-
- void __init plat_mem_setup(void)
- {
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
-+#ifdef CONFIG_BCM47XX_SSB
- bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
- bcm47xx_register_ssb();
-+#endif
-
- _machine_restart = bcm47xx_machine_restart;
- _machine_halt = bcm47xx_machine_halt;
---- a/arch/mips/bcm47xx/time.c
-+++ b/arch/mips/bcm47xx/time.c
-@@ -40,9 +40,11 @@ void __init plat_time_init(void)
- write_c0_compare(0xffff);
-
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
- break;
-+#endif
- }
-
- if (!hz)
---- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
-@@ -22,11 +22,15 @@
- #include <linux/ssb/ssb.h>
-
- enum bcm47xx_bus_type {
-+#ifdef CONFIG_BCM47XX_SSB
- BCM47XX_BUS_TYPE_SSB,
-+#endif
- };
-
- union bcm47xx_bus {
-+#ifdef CONFIG_BCM47XX_SSB
- struct ssb_bus ssb;
-+#endif
- };
-
- extern union bcm47xx_bus bcm47xx_bus;
---- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
-@@ -22,8 +22,10 @@ extern int gpio_to_irq(unsigned gpio);
- static inline int gpio_get_value(unsigned gpio)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
-+#endif
- }
- return -EINVAL;
- }
-@@ -31,18 +33,22 @@ static inline int gpio_get_value(unsigne
- static inline void gpio_set_value(unsigned gpio, int value)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
- value ? 1 << gpio : 0);
-+#endif
- }
- }
-
- static inline int gpio_direction_input(unsigned gpio)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
- return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -50,6 +56,7 @@ static inline int gpio_direction_input(u
- static inline int gpio_direction_output(unsigned gpio, int value)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- /* first set the gpio out value */
- ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
-@@ -57,6 +64,7 @@ static inline int gpio_direction_output(
- /* then set the gpio mode */
- ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
- return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -64,10 +72,12 @@ static inline int gpio_direction_output(
- static inline int gpio_intmask(unsigned gpio, int value)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_gpio_intmask(&bcm47xx_bus.ssb, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -75,10 +85,12 @@ static inline int gpio_intmask(unsigned
- static inline int gpio_polarity(unsigned gpio, int value)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << gpio,
- value ? 1 << gpio : 0);
- return 0;
-+#endif
- }
- return -EINVAL;
- }
---- a/arch/mips/pci/pci-bcm47xx.c
-+++ b/arch/mips/pci/pci-bcm47xx.c
-@@ -25,6 +25,7 @@
- #include <linux/types.h>
- #include <linux/pci.h>
- #include <linux/ssb/ssb.h>
-+#include <bcm47xx.h>
-
- int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
- {
-@@ -33,9 +34,13 @@ int __init pcibios_map_irq(const struct
-
- int pcibios_plat_dev_init(struct pci_dev *dev)
- {
-+#ifdef CONFIG_BCM47XX_SSB
- int res;
- u8 slot, pin;
-
-+ if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
-+ return 0;
-+
- res = ssb_pcibios_plat_dev_init(dev);
- if (res < 0) {
- printk(KERN_ALERT "PCI: Failed to init device %s\n",
-@@ -55,5 +60,6 @@ int pcibios_plat_dev_init(struct pci_dev
- }
-
- dev->irq = res;
-+#endif
- return 0;
- }
---- a/drivers/watchdog/bcm47xx_wdt.c
-+++ b/drivers/watchdog/bcm47xx_wdt.c
-@@ -55,17 +55,21 @@ static inline void bcm47xx_wdt_hw_start(
- {
- /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
- break;
-+#endif
- }
- }
-
- static inline int bcm47xx_wdt_hw_stop(void)
- {
- switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
- case BCM47XX_BUS_TYPE_SSB:
- return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
-+#endif
- }
- return -EINVAL;
- }
+++ /dev/null
-From 0b7b4817579b5b283e48b96de24b7b2c1a861644 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Mon, 6 Jun 2011 00:07:37 +0200
-Subject: [PATCH 12/14] bcm47xx: add support for bcma bus
-
-This patch add support for the bcma bus. Broadcom uses only Mips 74K
-CPUs on the new SoC and on the old ons using ssb bus there are no Mips
-74K CPUs.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/Kconfig | 13 ++++++
- arch/mips/bcm47xx/gpio.c | 22 +++++++++++
- arch/mips/bcm47xx/nvram.c | 10 +++++
- arch/mips/bcm47xx/serial.c | 29 ++++++++++++++
- arch/mips/bcm47xx/setup.c | 53 +++++++++++++++++++++++++-
- arch/mips/bcm47xx/time.c | 5 ++
- arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 8 ++++
- arch/mips/include/asm/mach-bcm47xx/gpio.h | 41 ++++++++++++++++++++
- drivers/watchdog/bcm47xx_wdt.c | 11 +++++
- 9 files changed, 190 insertions(+), 2 deletions(-)
-
---- a/arch/mips/bcm47xx/Kconfig
-+++ b/arch/mips/bcm47xx/Kconfig
-@@ -15,4 +15,17 @@ config BCM47XX_SSB
-
- This will generate an image with support for SSB and MIPS32 R2 instruction set.
-
-+config BCM47XX_BCMA
-+ bool "SSB Support for Broadcom BCM47XX"
-+ select SYS_HAS_CPU_MIPS32_R2
-+ select BCMA
-+ select BCMA_HOST_SOC
-+ select BCMA_DRIVER_MIPS
-+ select BCMA_DRIVER_PCI_HOSTMODE if PCI
-+ default y
-+ help
-+ Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
-+
-+ This will generate an image with support for BCMA and MIPS32 R2 instruction set.
-+
- endif
---- a/arch/mips/bcm47xx/gpio.c
-+++ b/arch/mips/bcm47xx/gpio.c
-@@ -36,6 +36,16 @@ int gpio_request(unsigned gpio, const ch
-
- return 0;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)
-+ return -EINVAL;
-+
-+ if (test_and_set_bit(gpio, gpio_in_use))
-+ return -EBUSY;
-+
-+ return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -57,6 +67,14 @@ void gpio_free(unsigned gpio)
- clear_bit(gpio, gpio_in_use);
- return;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ if ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES)
-+ return;
-+
-+ clear_bit(gpio, gpio_in_use);
-+ return;
-+#endif
- }
- }
- EXPORT_SYMBOL(gpio_free);
-@@ -73,6 +91,10 @@ int gpio_to_irq(unsigned gpio)
- else
- return -EINVAL;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ return bcma_core_mips_irq(bcm47xx_bus.bcma.bus.drv_cc.core) + 2;
-+#endif
- }
- return -EINVAL;
- }
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -29,6 +29,9 @@ static void early_nvram_init(void)
- #ifdef CONFIG_BCM47XX_SSB
- struct ssb_mipscore *mcore_ssb;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ struct bcma_drv_mips *mcore_bcma;
-+#endif
- struct nvram_header *header;
- int i;
- u32 base = 0;
-@@ -44,6 +47,13 @@ static void early_nvram_init(void)
- lim = mcore_ssb->flash_window_size;
- break;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ mcore_bcma = &bcm47xx_bus.bcma.bus.drv_mips;
-+ base = mcore_bcma->flash_window;
-+ lim = mcore_bcma->flash_window_size;
-+ break;
-+#endif
- }
-
- off = FLASH_MIN;
---- a/arch/mips/bcm47xx/serial.c
-+++ b/arch/mips/bcm47xx/serial.c
-@@ -47,6 +47,31 @@ static int __init uart8250_init_ssb(void
- }
- #endif
-
-+#ifdef CONFIG_BCM47XX_BCMA
-+static int __init uart8250_init_bcma(void)
-+{
-+ int i;
-+ struct bcma_drv_mips *mcore = &(bcm47xx_bus.bcma.bus.drv_mips);
-+
-+ memset(&uart8250_data, 0, sizeof(uart8250_data));
-+
-+ for (i = 0; i < mcore->nr_serial_ports; i++) {
-+ struct plat_serial8250_port *p = &(uart8250_data[i]);
-+ struct bcma_drv_mips_serial_port *bcma_port;
-+ bcma_port = &(mcore->serial_ports[i]);
-+
-+ p->mapbase = (unsigned int) bcma_port->regs;
-+ p->membase = (void *) bcma_port->regs;
-+ p->irq = bcma_port->irq + 2;
-+ p->uartclk = bcma_port->baud_base;
-+ p->regshift = bcma_port->reg_shift;
-+ p->iotype = UPIO_MEM;
-+ p->flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-+ }
-+ return platform_device_register(&uart8250_device);
-+}
-+#endif
-+
- static int __init uart8250_init(void)
- {
- switch (bcm47xx_active_bus_type) {
-@@ -54,6 +79,10 @@ static int __init uart8250_init(void)
- case BCM47XX_BUS_TYPE_SSB:
- return uart8250_init_ssb();
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ return uart8250_init_bcma();
-+#endif
- }
- return -EINVAL;
- }
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -29,6 +29,7 @@
- #include <linux/types.h>
- #include <linux/ssb/ssb.h>
- #include <linux/ssb/ssb_embedded.h>
-+#include <linux/bcma/bcma_soc.h>
- #include <asm/bootinfo.h>
- #include <asm/reboot.h>
- #include <asm/time.h>
-@@ -52,6 +53,11 @@ static void bcm47xx_machine_restart(char
- ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
- break;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
-+ break;
-+#endif
- }
- while (1)
- cpu_relax();
-@@ -67,6 +73,11 @@ static void bcm47xx_machine_halt(void)
- ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
- break;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
-+ break;
-+#endif
- }
- while (1)
- cpu_relax();
-@@ -295,16 +306,54 @@ static void __init bcm47xx_register_ssb(
- }
- #endif
-
-+#ifdef CONFIG_BCM47XX_BCMA
-+static void __init bcm47xx_register_bcma(void)
-+{
-+ int err;
-+
-+ err = bcma_host_soc_register(&bcm47xx_bus.bcma);
-+ if (err)
-+ panic("Failed to initialize BCMA bus (err %d)\n", err);
-+}
-+#endif
-+
- void __init plat_mem_setup(void)
- {
- struct cpuinfo_mips *c = ¤t_cpu_data;
-
-+ if (c->cputype == CPU_74K) {
-+ printk(KERN_INFO "bcm47xx: using bcma bus\n");
-+#ifdef CONFIG_BCM47XX_BCMA
-+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_BCMA;
-+ bcm47xx_register_bcma();
-+#endif
-+ } else {
-+ printk(KERN_INFO "bcm47xx: using ssb bus\n");
- #ifdef CONFIG_BCM47XX_SSB
-- bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
-- bcm47xx_register_ssb();
-+ bcm47xx_active_bus_type = BCM47XX_BUS_TYPE_SSB;
-+ bcm47xx_register_ssb();
- #endif
-+ }
-
- _machine_restart = bcm47xx_machine_restart;
- _machine_halt = bcm47xx_machine_halt;
- pm_power_off = bcm47xx_machine_halt;
- }
-+
-+static int __init bcm47xx_register_bus_complete(void)
-+{
-+ switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ /* Nothing to do */
-+ break;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_bus_register(&bcm47xx_bus.bcma.bus);
-+ break;
-+#endif
-+ }
-+ return 0;
-+}
-+device_initcall(bcm47xx_register_bus_complete);
---- a/arch/mips/bcm47xx/time.c
-+++ b/arch/mips/bcm47xx/time.c
-@@ -45,6 +45,11 @@ void __init plat_time_init(void)
- hz = ssb_cpu_clock(&bcm47xx_bus.ssb.mipscore) / 2;
- break;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ hz = bcma_cpu_clock(&bcm47xx_bus.bcma.bus.drv_mips) / 2;
-+ break;
-+#endif
- }
-
- if (!hz)
---- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
-@@ -20,17 +20,25 @@
- #define __ASM_BCM47XX_H
-
- #include <linux/ssb/ssb.h>
-+#include <linux/bcma/bcma.h>
-+#include <linux/bcma/bcma_soc.h>
-
- enum bcm47xx_bus_type {
- #ifdef CONFIG_BCM47XX_SSB
- BCM47XX_BUS_TYPE_SSB,
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ BCM47XX_BUS_TYPE_BCMA,
-+#endif
- };
-
- union bcm47xx_bus {
- #ifdef CONFIG_BCM47XX_SSB
- struct ssb_bus ssb;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ struct bcma_soc bcma;
-+#endif
- };
-
- extern union bcm47xx_bus bcm47xx_bus;
---- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
-@@ -10,6 +10,7 @@
- #define __BCM47XX_GPIO_H
-
- #include <linux/ssb/ssb_embedded.h>
-+#include <linux/bcma/bcma.h>
- #include <asm/mach-bcm47xx/bcm47xx.h>
-
- #define BCM47XX_EXTIF_GPIO_LINES 5
-@@ -26,6 +27,11 @@ static inline int gpio_get_value(unsigne
- case BCM47XX_BUS_TYPE_SSB:
- return ssb_gpio_in(&bcm47xx_bus.ssb, 1 << gpio);
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ return bcma_chipco_gpio_in(&bcm47xx_bus.bcma.bus.drv_cc,
-+ 1 << gpio);
-+#endif
- }
- return -EINVAL;
- }
-@@ -37,6 +43,13 @@ static inline void gpio_set_value(unsign
- case BCM47XX_BUS_TYPE_SSB:
- ssb_gpio_out(&bcm47xx_bus.ssb, 1 << gpio,
- value ? 1 << gpio : 0);
-+ return;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
-+ value ? 1 << gpio : 0);
-+ return;
- #endif
- }
- }
-@@ -49,6 +62,12 @@ static inline int gpio_direction_input(u
- ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 0);
- return 0;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
-+ 0);
-+ return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -65,6 +84,16 @@ static inline int gpio_direction_output(
- ssb_gpio_outen(&bcm47xx_bus.ssb, 1 << gpio, 1 << gpio);
- return 0;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ /* first set the gpio out value */
-+ bcma_chipco_gpio_out(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
-+ value ? 1 << gpio : 0);
-+ /* then set the gpio mode */
-+ bcma_chipco_gpio_outen(&bcm47xx_bus.bcma.bus.drv_cc, 1 << gpio,
-+ 1 << gpio);
-+ return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -78,6 +107,12 @@ static inline int gpio_intmask(unsigned
- value ? 1 << gpio : 0);
- return 0;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_gpio_intmask(&bcm47xx_bus.bcma.bus.drv_cc,
-+ 1 << gpio, value ? 1 << gpio : 0);
-+ return 0;
-+#endif
- }
- return -EINVAL;
- }
-@@ -91,6 +126,12 @@ static inline int gpio_polarity(unsigned
- value ? 1 << gpio : 0);
- return 0;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_gpio_polarity(&bcm47xx_bus.bcma.bus.drv_cc,
-+ 1 << gpio, value ? 1 << gpio : 0);
-+ return 0;
-+#endif
- }
- return -EINVAL;
- }
---- a/drivers/watchdog/bcm47xx_wdt.c
-+++ b/drivers/watchdog/bcm47xx_wdt.c
-@@ -60,6 +60,12 @@ static inline void bcm47xx_wdt_hw_start(
- ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
- break;
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
-+ 0xfffffff);
-+ break;
-+#endif
- }
- }
-
-@@ -70,6 +76,11 @@ static inline int bcm47xx_wdt_hw_stop(vo
- case BCM47XX_BUS_TYPE_SSB:
- return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
- #endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
-+ return 0;
-+#endif
- }
- return -EINVAL;
- }
--- /dev/null
+From a1d9c96a6c9b37b26dc1149706f3061b57a62b50 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:51:47 +0200
+Subject: [PATCH 12/22] bcma: move parallel flash into a union
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/nvram.c | 7 ++-
+ drivers/bcma/driver_mips.c | 9 ++--
+ include/linux/bcma/bcma_driver_chipcommon.h | 75 ++++++++++++++++++++++++++-
+ 3 files changed, 84 insertions(+), 7 deletions(-)
+
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -50,8 +50,11 @@ static void early_nvram_init(void)
+ #ifdef CONFIG_BCM47XX_BCMA
+ case BCM47XX_BUS_TYPE_BCMA:
+ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
+- base = bcma_cc->pflash.window;
+- lim = bcma_cc->pflash.window_size;
++ if (bcma_cc->flash_type != BCMA_PFLASH)
++ return;
++
++ base = bcma_cc->flash.pflash.window;
++ lim = bcma_cc->flash.pflash.window_size;
+ break;
+ #endif
+ }
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -189,14 +189,15 @@ static void bcma_core_mips_flash_detect(
+ 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;
++ bus->drv_cc.flash_type = BCMA_PFLASH;
++ bus->drv_cc.flash.pflash.window = 0x1c000000;
++ bus->drv_cc.flash.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;
++ bus->drv_cc.flash.pflash.buswidth = 1;
+ else
+- bus->drv_cc.pflash.buswidth = 2;
++ bus->drv_cc.flash.pflash.buswidth = 2;
+ break;
+ default:
+ pr_err("flash not supported.\n");
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -108,10 +108,68 @@
+ #define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */
+ #define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */
+ #define BCMA_CC_FLASHCTL 0x0040
++
++/* Start/busy bit in flashcontrol */
++#define BCMA_CC_FLASHCTL_OPCODE 0x000000ff
++#define BCMA_CC_FLASHCTL_ACTION 0x00000700
++#define BCMA_CC_FLASHCTL_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */
+ #define BCMA_CC_FLASHCTL_START 0x80000000
+ #define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START
++
++/* flashcontrol action+opcodes for ST flashes */
++#define BCMA_CC_FLASHCTL_ST_WREN 0x0006 /* Write Enable */
++#define BCMA_CC_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */
++#define BCMA_CC_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */
++#define BCMA_CC_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */
++#define BCMA_CC_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */
++#define BCMA_CC_FLASHCTL_ST_PP 0x0302 /* Page Program */
++#define BCMA_CC_FLASHCTL_ST_SE 0x02d8 /* Sector Erase */
++#define BCMA_CC_FLASHCTL_ST_BE 0x00c7 /* Bulk Erase */
++#define BCMA_CC_FLASHCTL_ST_DP 0x00b9 /* Deep Power-down */
++#define BCMA_CC_FLASHCTL_ST_RES 0x03ab /* Read Electronic Signature */
++#define BCMA_CC_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
++#define BCMA_CC_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
++
++
++/* flashcontrol action+opcodes for Atmel flashes */
++#define BCMA_CC_FLASHCTL_AT_READ 0x07e8
++#define BCMA_CC_FLASHCTL_AT_PAGE_READ 0x07d2
++#define BCMA_CC_FLASHCTL_AT_BUF1_READ
++#define BCMA_CC_FLASHCTL_AT_BUF2_READ
++#define BCMA_CC_FLASHCTL_AT_STATUS 0x01d7
++#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE 0x0384
++#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE 0x0387
++#define BCMA_CC_FLASHCTL_AT_BUF1_ERASE_PROGRAM 0x0283
++#define BCMA_CC_FLASHCTL_AT_BUF2_ERASE_PROGRAM 0x0286
++#define BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM 0x0288
++#define BCMA_CC_FLASHCTL_AT_BUF2_PROGRAM 0x0289
++#define BCMA_CC_FLASHCTL_AT_PAGE_ERASE 0x0281
++#define BCMA_CC_FLASHCTL_AT_BLOCK_ERASE 0x0250
++#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
++#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
++#define BCMA_CC_FLASHCTL_AT_BUF1_LOAD 0x0253
++#define BCMA_CC_FLASHCTL_AT_BUF2_LOAD 0x0255
++#define BCMA_CC_FLASHCTL_AT_BUF1_COMPARE 0x0260
++#define BCMA_CC_FLASHCTL_AT_BUF2_COMPARE 0x0261
++#define BCMA_CC_FLASHCTL_AT_BUF1_REPROGRAM 0x0258
++#define BCMA_CC_FLASHCTL_AT_BUF2_REPROGRAM 0x0259
++
+ #define BCMA_CC_FLASHADDR 0x0044
+ #define BCMA_CC_FLASHDATA 0x0048
++
++/* Status register bits for ST flashes */
++#define BCMA_CC_FLASHDATA_ST_WIP 0x01 /* Write In Progress */
++#define BCMA_CC_FLASHDATA_ST_WEL 0x02 /* Write Enable Latch */
++#define BCMA_CC_FLASHDATA_ST_BP_MASK 0x1c /* Block Protect */
++#define BCMA_CC_FLASHDATA_ST_BP_SHIFT 2
++#define BCMA_CC_FLASHDATA_ST_SRWD 0x80 /* Status Register Write Disable */
++
++/* Status register bits for Atmel flashes */
++#define BCMA_CC_FLASHDATA_AT_READY 0x80
++#define BCMA_CC_FLASHDATA_AT_MISMATCH 0x40
++#define BCMA_CC_FLASHDATA_AT_ID_MASK 0x38
++#define BCMA_CC_FLASHDATA_AT_ID_SHIFT 3
++
+ #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
+
++#define BCMA_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
++#define BCMA_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
++#define BCMA_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
++#define BCMA_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
++
++
+ /* Data for the PMU, if available.
+ * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+ */
+@@ -292,12 +356,20 @@ struct bcma_chipcommon_pmu {
+ };
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
++enum bcma_flash_type {
++ BCMA_PFLASH,
++};
++
+ struct bcma_pflash {
+ u8 buswidth;
+ u32 window;
+ u32 window_size;
+ };
+
++union bcma_flash {
++ struct bcma_pflash pflash;
++};
++
+ struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+@@ -317,7 +389,8 @@ struct bcma_drv_cc {
+ u16 fast_pwrup_delay;
+ struct bcma_chipcommon_pmu pmu;
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+- struct bcma_pflash pflash;
++ enum bcma_flash_type flash_type;
++ union bcma_flash flash;
+
+ int nr_serial_ports;
+ struct bcma_serial_port serial_ports[4];
+++ /dev/null
-From 360eb82fd303ac24590a1b99ad1866162f6b0171 Mon Sep 17 00:00:00 2001
-From: Hauke Mehrtens <hauke@hauke-m.de>
-Date: Mon, 6 Jun 2011 00:07:38 +0200
-Subject: [PATCH 13/14] bcm47xx: fix irq assignment for new SoCs.
-
-Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
----
- arch/mips/bcm47xx/irq.c | 12 ++++++++++++
- 1 files changed, 12 insertions(+), 0 deletions(-)
-
---- a/arch/mips/bcm47xx/irq.c
-+++ b/arch/mips/bcm47xx/irq.c
-@@ -26,6 +26,7 @@
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <asm/irq_cpu.h>
-+#include <bcm47xx.h>
-
- void plat_irq_dispatch(void)
- {
-@@ -51,5 +52,16 @@ void plat_irq_dispatch(void)
-
- void __init arch_init_irq(void)
- {
-+#ifdef CONFIG_BCM47XX_BCMA
-+ if (bcm47xx_active_bus_type == BCM47XX_BUS_TYPE_BCMA) {
-+ bcma_write32(bcm47xx_bus.bcma.bus.drv_mips.core,
-+ BCMA_MIPS_MIPS74K_INTMASK(5), 1 << 31);
-+ /*
-+ * the kernel reads the timer irq from some register and thinks
-+ * it's #5, but we offset it by 2 and route to #7
-+ */
-+ cp0_compare_irq = 7;
-+ }
-+#endif
- mips_cpu_irq_init();
- }
--- /dev/null
+From b5be6e3037650ff5615cb869f1972dea5a49bcb6 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:53:07 +0200
+Subject: [PATCH 13/22] bcma: add serial flash support to bcma
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/Kconfig | 5 +
+ drivers/bcma/Makefile | 1 +
+ drivers/bcma/bcma_private.h | 5 +
+ drivers/bcma/driver_chipcommon_sflash.c | 554 +++++++++++++++++++++++++++
+ drivers/bcma/driver_mips.c | 8 +-
+ include/linux/bcma/bcma_driver_chipcommon.h | 24 ++
+ 6 files changed, 596 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/bcma/driver_chipcommon_sflash.c
+
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -38,6 +38,11 @@ config BCMA_HOST_SOC
+ bool
+ depends on BCMA_DRIVER_MIPS
+
++config BCMA_SFLASH
++ bool
++ depends on BCMA_DRIVER_MIPS
++ default y
++
+ config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver"
+ depends on BCMA && MIPS
+--- a/drivers/bcma/Makefile
++++ b/drivers/bcma/Makefile
+@@ -1,5 +1,6 @@
+ bcma-y += main.o scan.o core.o sprom.o
+ bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
++bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
+ bcma-y += driver_pci.o
+ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
+ 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
+ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
+ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);
+
++#ifdef CONFIG_BCMA_SFLASH
++/* driver_chipcommon_sflash.c */
++int bcma_sflash_init(struct bcma_drv_cc *cc);
++#endif /* CONFIG_BCMA_SFLASH */
++
+ #ifdef CONFIG_BCMA_HOST_PCI
+ /* host_pci.c */
+ extern int __init bcma_host_pci_init(void);
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -0,0 +1,554 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
++ * Copyright 2010, Broadcom Corporation
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_driver_chipcommon.h>
++#include <linux/delay.h>
++
++#include "bcma_private.h"
++
++#define NUM_RETRIES 3
++
++
++/* Issue a serial flash command */
++static inline void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
++{
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
++ BCMA_CC_FLASHCTL_START | opcode);
++ while (bcma_cc_read32(cc, BCMA_CC_FLASHCTL)
++ & BCMA_CC_FLASHCTL_BUSY);
++}
++
++
++static inline void bcma_sflash_write_u8(struct bcma_drv_cc *cc,
++ u32 offset, u8 byte)
++{
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
++ bcma_cc_write32(cc, BCMA_CC_FLASHDATA, byte);
++}
++
++/* Initialize serial flash access */
++int bcma_sflash_init(struct bcma_drv_cc *cc)
++{
++ u32 id, id2;
++
++ memset(&cc->flash.sflash, 0, sizeof(struct bcma_sflash));
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ /* Probe for ST chips */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_DP);
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 0);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
++ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
++ cc->flash.sflash.blocksize = 64 * 1024;
++ switch (id) {
++ case 0x11:
++ /* ST M25P20 2 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 4;
++ break;
++ case 0x12:
++ /* ST M25P40 4 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 8;
++ break;
++ case 0x13:
++ /* ST M25P80 8 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 16;
++ break;
++ case 0x14:
++ /* ST M25P16 16 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 32;
++ break;
++ case 0x15:
++ /* ST M25P32 32 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 64;
++ break;
++ case 0x16:
++ /* ST M25P64 64 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 128;
++ break;
++ case 0x17:
++ /* ST M25FL128 128 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 256;
++ break;
++ case 0xbf:
++ /* All of the following flashes are SST with
++ * 4KB subsectors. Others should be added but
++ * We'll have to revamp the way we identify them
++ * since RES is not eough to disambiguate them.
++ */
++ cc->flash.sflash.blocksize = 4 * 1024;
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, 1);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RES);
++ id2 = bcma_cc_read32(cc, BCMA_CC_FLASHDATA);
++ switch (id2) {
++ case 1:
++ /* SST25WF512 512 Kbit Serial Flash */
++ case 0x48:
++ /* SST25VF512 512 Kbit Serial Flash */
++ cc->flash.sflash.numblocks = 16;
++ break;
++ case 2:
++ /* SST25WF010 1 Mbit Serial Flash */
++ case 0x49:
++ /* SST25VF010 1 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 32;
++ break;
++ case 3:
++ /* SST25WF020 2 Mbit Serial Flash */
++ case 0x43:
++ /* SST25VF020 2 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 64;
++ break;
++ case 4:
++ /* SST25WF040 4 Mbit Serial Flash */
++ case 0x44:
++ /* SST25VF040 4 Mbit Serial Flash */
++ case 0x8d:
++ /* SST25VF040B 4 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 128;
++ break;
++ case 5:
++ /* SST25WF080 8 Mbit Serial Flash */
++ case 0x8e:
++ /* SST25VF080B 8 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 256;
++ break;
++ case 0x41:
++ /* SST25VF016 16 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 512;
++ break;
++ case 0x4a:
++ /* SST25VF032 32 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 1024;
++ break;
++ case 0x4b:
++ /* SST25VF064 64 Mbit Serial Flash */
++ cc->flash.sflash.numblocks = 2048;
++ break;
++ }
++ break;
++ }
++ break;
++
++ case BCMA_CC_FLASHT_ATSER:
++ /* Probe for Atmel chips */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
++ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
++ switch (id) {
++ case 0xc:
++ /* Atmel AT45DB011 1Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 256;
++ cc->flash.sflash.numblocks = 512;
++ break;
++ case 0x14:
++ /* Atmel AT45DB021 2Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 256;
++ cc->flash.sflash.numblocks = 1024;
++ break;
++ case 0x1c:
++ /* Atmel AT45DB041 4Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 256;
++ cc->flash.sflash.numblocks = 2048;
++ break;
++ case 0x24:
++ /* Atmel AT45DB081 8Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 256;
++ cc->flash.sflash.numblocks = 4096;
++ break;
++ case 0x2c:
++ /* Atmel AT45DB161 16Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 512;
++ cc->flash.sflash.numblocks = 4096;
++ break;
++ case 0x34:
++ /* Atmel AT45DB321 32Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 512;
++ cc->flash.sflash.numblocks = 8192;
++ break;
++ case 0x3c:
++ /* Atmel AT45DB642 64Mbit Serial Flash */
++ cc->flash.sflash.blocksize = 1024;
++ cc->flash.sflash.numblocks = 8192;
++ break;
++ }
++ break;
++ }
++
++ cc->flash.sflash.size = cc->flash.sflash.blocksize * cc->flash.sflash.numblocks;
++
++ return cc->flash.sflash.size ? 0 : -ENODEV;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ u8 *buf)
++{
++ u8 *from, *to;
++ u32 cnt, i;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->flash.sflash.size)
++ return -EINVAL;
++
++ if ((len >= 4) && (offset & 3))
++ cnt = 4 - (offset & 3);
++ else if ((len >= 4) && ((u32)buf & 3))
++ cnt = 4 - ((u32)buf & 3);
++ else
++ cnt = len;
++
++
++ if (cc->core->id.rev == 12)
++ from = (u8 *)KSEG1ADDR(BCMA_FLASH2 + offset);
++ else
++ from = (u8 *)KSEG0ADDR(BCMA_FLASH2 + offset);
++
++ to = (u8 *)buf;
++
++ if (cnt < 4) {
++ for (i = 0; i < cnt; i++) {
++ *to = readb(from);
++ from++;
++ to++;
++ }
++ return cnt;
++ }
++
++ while (cnt >= 4) {
++ *(u32 *)to = readl(from);
++ from += 4;
++ to += 4;
++ cnt -= 4;
++ }
++
++ return len - cnt;
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset)
++{
++ if (offset >= cc->flash.sflash.size)
++ return -22;
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ /* Check for ST Write In Progress bit */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_RDSR);
++ return bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
++ & BCMA_CC_FLASHDATA_ST_WIP;
++ case BCMA_CC_FLASHT_ATSER:
++ /* Check for Atmel Ready bit */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
++ return !(bcma_cc_read32(cc, BCMA_CC_FLASHDATA)
++ & BCMA_CC_FLASHDATA_AT_READY);
++ }
++
++ return 0;
++}
++
++
++static int sflash_st_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_bus *bus = cc->core->bus;
++ int ret = 0;
++ bool is4712b0 = (bus->chipinfo.id == 0x4712) && (bus->chipinfo.rev == 3);
++ u32 mask;
++
++
++ /* Enable writes */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
++ if (is4712b0) {
++ mask = 1 << 14;
++ bcma_sflash_write_u8(cc, offset, *buf++);
++ /* Set chip select */
++ bcma_cc_set32(cc, BCMA_CC_GPIOOUT, mask);
++ /* Issue a page program with the first byte */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, drop cs and return */
++ bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ bcma_sflash_cmd(cc, *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs */
++ bcma_cc_mask32(cc, BCMA_CC_GPIOOUT, ~mask);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ } else if (cc->core->id.rev >= 20) {
++ bcma_sflash_write_u8(cc, offset, *buf++);
++ /* Issue a page program with CSA bit set */
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_ST_CSA |
++ BCMA_CC_FLASHCTL_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, poll droping cs and return */
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_ST_CSA |
++ *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs & poll */
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
++ udelay(1);
++ if (!bcma_sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ } else {
++ ret = 1;
++ bcma_sflash_write_u8(cc, offset, *buf);
++ /* Page program */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_PP);
++ }
++ return ret;
++}
++
++static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_sflash *sfl = &cc->flash.sflash;
++ u32 page, byte, mask;
++ int ret = 0;
++ mask = sfl->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < sfl->blocksize)) {
++ int i = 100;
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ while (i > 0 && bcma_sflash_poll(cc, offset)) {
++ udelay(10);
++ i--;
++ }
++ BUG_ON(!bcma_sflash_poll(cc, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
++ bcma_sflash_write_u8(cc, byte++, *buf++);
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, page);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM);
++
++ return ret;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_sflash *sfl;
++ int ret = 0, tries = NUM_RETRIES;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->flash.sflash.size)
++ return -EINVAL;
++
++ sfl = &cc->flash.sflash;
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ do {
++ ret = sflash_st_write(cc, offset, len, buf);
++ tries--;
++ } while (ret == -EAGAIN && tries > 0);
++
++ if (ret == -EAGAIN && tries == 0) {
++ pr_info("ST Flash rejected write\n");
++ ret = -EIO;
++ }
++ break;
++ case BCMA_CC_FLASHT_ATSER:
++ ret = sflash_at_write(cc, offset, len, buf);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset)
++{
++ struct bcma_sflash *sfl;
++
++ if (offset >= cc->flash.sflash.size)
++ return -EINVAL;
++
++ sfl = &cc->flash.sflash;
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset);
++ /* Newer flashes have "sub-sectors" which can be erased independently
++ * with a new command: ST_SSE. The ST_SE command erases 64KB just as
++ * before.
++ */
++ bcma_sflash_cmd(cc, (sfl->blocksize < (64 * 1024)) ? BCMA_CC_FLASHCTL_ST_SSE : BCMA_CC_FLASHCTL_ST_SE);
++ return sfl->blocksize;
++ case BCMA_CC_FLASHT_ATSER:
++ bcma_cc_write32(cc, BCMA_CC_FLASHADDR, offset << 1);
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_PAGE_ERASE);
++ return sfl->blocksize;
++ }
++
++ return 0;
++}
++
++/*
++ * writes the appropriate range of flash, a NULL buf simply erases
++ * the region of flash
++ */
++int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_sflash *sfl;
++ u8 *block = NULL, *cur_ptr, *blk_ptr;
++ u32 blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
++ u32 blk_offset, blk_len, copied;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (len <= 0)
++ return 0;
++
++ sfl = &cc->flash.sflash;
++ if ((offset + len) > sfl->size)
++ return -EINVAL;
++
++ blocksize = sfl->blocksize;
++ mask = blocksize - 1;
++
++ /* Allocate a block of mem */
++ block = kmalloc(blocksize, GFP_KERNEL);
++ if (!block)
++ return -ENOMEM;
++
++ while (len) {
++ /* Align offset */
++ cur_offset = offset & ~mask;
++ cur_length = blocksize;
++ cur_ptr = block;
++
++ remainder = blocksize - (offset & mask);
++ if (len < remainder)
++ cur_retlen = len;
++ else
++ cur_retlen = remainder;
++
++ /* buf == NULL means erase only */
++ if (buf) {
++ /* Copy existing data into holding block if necessary */
++ if ((offset & mask) || (len < blocksize)) {
++ blk_offset = cur_offset;
++ blk_len = cur_length;
++ blk_ptr = cur_ptr;
++
++ /* Copy entire block */
++ while (blk_len) {
++ copied = bcma_sflash_read(cc,
++ blk_offset,
++ blk_len, blk_ptr);
++ blk_offset += copied;
++ blk_len -= copied;
++ blk_ptr += copied;
++ }
++ }
++
++ /* Copy input data into holding block */
++ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
++ }
++
++ /* Erase block */
++ ret = bcma_sflash_erase(cc, cur_offset);
++ if (ret < 0)
++ goto done;
++
++ while (bcma_sflash_poll(cc, cur_offset));
++
++ /* buf == NULL means erase only */
++ if (!buf) {
++ offset += cur_retlen;
++ len -= cur_retlen;
++ continue;
++ }
++
++ /* Write holding block */
++ while (cur_length > 0) {
++ bytes = bcma_sflash_write(cc, cur_offset,
++ cur_length, cur_ptr);
++
++ if (bytes < 0) {
++ ret = bytes;
++ goto done;
++ }
++
++ while (bcma_sflash_poll(cc, cur_offset));
++
++ cur_offset += bytes;
++ cur_length -= bytes;
++ cur_ptr += bytes;
++ }
++
++ offset += cur_retlen;
++ len -= cur_retlen;
++ buf += cur_retlen;
++ }
++
++ ret = len;
++done:
++ kfree(block);
++ return ret;
++}
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -185,7 +185,13 @@ static void bcma_core_mips_flash_detect(
+ 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");
++#ifdef CONFIG_BCMA_SFLASH
++ pr_info("found serial flash.\n");
++ bus->drv_cc.flash_type = BCMA_SFLASH;
++ bcma_sflash_init(&bus->drv_cc);
++#else
++ pr_info("serial flash not supported.\n");
++#endif /* CONFIG_BCMA_SFLASH */
+ break;
+ case BCMA_CC_FLASHT_PARA:
+ 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 {
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ enum bcma_flash_type {
+ BCMA_PFLASH,
++ BCMA_SFLASH,
+ };
+
+ struct bcma_pflash {
+@@ -366,8 +367,19 @@ struct bcma_pflash {
+ u32 window_size;
+ };
+
++#ifdef CONFIG_BCMA_SFLASH
++struct bcma_sflash {
++ u32 blocksize; /* Block size */
++ u32 numblocks; /* Number of blocks */
++ u32 size; /* Total size in bytes */
++};
++#endif /* CONFIG_BCMA_SFLASH */
++
+ union bcma_flash {
+ struct bcma_pflash pflash;
++#ifdef CONFIG_BCMA_SFLASH
++ struct bcma_sflash sflash;
++#endif /* CONFIG_BCMA_SFLASH */
+ };
+
+ struct bcma_serial_port {
+@@ -433,4 +445,16 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+ /* PMU support */
+ extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+
++#ifdef CONFIG_BCMA_SFLASH
++/* Chipcommon sflash support. */
++int bcma_sflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ u8 *buf);
++int bcma_sflash_poll(struct bcma_drv_cc *cc, u32 offset);
++int bcma_sflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf);
++int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
++int bcma_sflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf);
++#endif /* CONFIG_BCMA_SFLASH */
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
--- /dev/null
+From 4b449ce15d74e5973cde18381c2a3fa0616b2b3d Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:54:11 +0200
+Subject: [PATCH 14/18] mtd: bcm47xx: add bcm47xx part parser
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/mtd/Kconfig | 7 +
+ drivers/mtd/Makefile | 1 +
+ drivers/mtd/bcm47xxpart.c | 536 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 544 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/bcm47xxpart.c
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -173,6 +173,13 @@ config MTD_MYLOADER_PARTS
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
++config MTD_BCM47XX_PARTS
++ tristate "BCM47XX partitioning support"
++ default y
++ depends on BCM47XX
++ ---help---
++ bcm47XX partitioning support
++
+ comment "User Modules And Translation Layers"
+
+ config MTD_CHAR
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdli
+ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
+ obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
++obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
+
+ # 'Users' - code which presents functionality to userspace.
+ obj-$(CONFIG_MTD_CHAR) += mtdchar.o
+--- /dev/null
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -0,0 +1,536 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * original functions for finding root filesystem from Mike Baker
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * Flash mapping for BCM947XX boards
++ */
++
++#define pr_fmt(fmt) "bcm47xx_part: " fmt
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/crc32.h>
++#include <asm/io.h>
++#include <asm/mach-bcm47xx/nvram.h>
++#include <asm/mach-bcm47xx/bcm47xx.h>
++#include <asm/fw/cfe/cfe_api.h>
++
++
++#define TRX_MAGIC 0x30524448 /* "HDR0" */
++#define TRX_VERSION 1
++#define TRX_MAX_LEN 0x3A0000
++#define TRX_NO_HEADER 1 /* Do not write TRX header */
++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
++#define TRX_MAX_OFFSET 3
++
++struct trx_header {
++ u32 magic; /* "HDR0" */
++ u32 len; /* Length of file including header */
++ u32 crc32; /* 32-bit CRC from flag_version to end of file */
++ u32 flag_version; /* 0:15 flags, 16:31 version */
++ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
++};
++
++/* for Edimax Print servers which use an additional header
++ * then the firmware on flash looks like :
++ * EDIMAX HEADER | TRX HEADER
++ * As this header is 12 bytes long we have to handle it
++ * and skip it to find the TRX header
++ */
++#define EDIMAX_PS_HEADER_MAGIC 0x36315350 /* "PS16" */
++#define EDIMAX_PS_HEADER_LEN 0xc /* 12 bytes long for edimax header */
++
++#define NVRAM_SPACE 0x8000
++
++#define ROUTER_NETGEAR_WGR614L 1
++#define ROUTER_NETGEAR_WNR834B 2
++#define ROUTER_NETGEAR_WNDR3300 3
++#define ROUTER_NETGEAR_WNR3500L 4
++#define ROUTER_SIMPLETECH_SIMPLESHARE 5
++
++static struct mtd_partition bcm47xx_parts[] = {
++ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
++ { name: "linux", offset: 0, size: 0, },
++ { name: "rootfs", offset: 0, size: 0, },
++ { name: "nvram", offset: 0, size: 0, },
++ { name: NULL, }, /* Used to create custom partitons with the function get_router() */
++ { name: NULL, },
++};
++
++static int
++find_cfe_size(struct mtd_info *mtd)
++{
++ struct trx_header *trx;
++ unsigned char buf[512];
++ int off;
++ size_t len;
++ int blocksize;
++
++ trx = (struct trx_header *) buf;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < mtd->size; off += blocksize) {
++ memset(buf, 0xe5, sizeof(buf));
++
++ /*
++ * Read into buffer
++ */
++ if (mtd->read(mtd, off, sizeof(buf), &len, buf) ||
++ len != sizeof(buf))
++ continue;
++
++ if (le32_to_cpu(trx->magic) == EDIMAX_PS_HEADER_MAGIC) {
++ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN,
++ sizeof(buf), &len, buf) || len != sizeof(buf)) {
++ continue;
++ } else {
++ pr_notice("Found edimax header\n");
++ }
++ }
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
++ goto found;
++ }
++ }
++
++ pr_notice("%s: Couldn't find bootloader size\n", mtd->name);
++ return -1;
++
++ found:
++ pr_notice("bootloader size: %d\n", off);
++ return off;
++
++}
++
++/*
++ * Copied from mtdblock.c
++ *
++ * Cache stuff...
++ *
++ * Since typical flash erasable sectors are much larger than what Linux's
++ * buffer cache can handle, we must implement read-modify-write on flash
++ * sectors for each block write requests. To avoid over-erasing flash sectors
++ * and to speed things up, we locally cache a whole flash sector while it is
++ * being written to until a different sector is required.
++ */
++
++static void erase_callback(struct erase_info *done)
++{
++ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
++ wake_up(wait_q);
++}
++
++static int erase_write (struct mtd_info *mtd, unsigned long pos,
++ int len, const char *buf)
++{
++ struct erase_info erase;
++ DECLARE_WAITQUEUE(wait, current);
++ wait_queue_head_t wait_q;
++ size_t retlen;
++ int ret;
++
++ /*
++ * First, let's erase the flash block.
++ */
++
++ init_waitqueue_head(&wait_q);
++ erase.mtd = mtd;
++ erase.callback = erase_callback;
++ erase.addr = pos;
++ erase.len = len;
++ erase.priv = (u_long)&wait_q;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&wait_q, &wait);
++
++ ret = mtd->erase(mtd, &erase);
++ if (ret) {
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&wait_q, &wait);
++ pr_warn("erase of region [0x%lx, 0x%x] on \"%s\" failed\n",
++ pos, len, mtd->name);
++ return ret;
++ }
++
++ schedule(); /* Wait for erase to finish. */
++ remove_wait_queue(&wait_q, &wait);
++
++ /*
++ * Next, write data to flash.
++ */
++
++ ret = mtd->write (mtd, pos, len, &retlen, buf);
++ if (ret)
++ return ret;
++ if (retlen != len)
++ return -EIO;
++ return 0;
++}
++
++
++static int
++find_dual_image_off (struct mtd_info *mtd)
++{
++ struct trx_header trx;
++ int off, blocksize;
++ size_t len;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < mtd->size; off += blocksize) {
++ memset(&trx, 0xe5, sizeof(trx));
++ /*
++ * Read into buffer
++ */
++ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx))
++ continue;
++ /* found last TRX header */
++ if (le32_to_cpu(trx.magic) == TRX_MAGIC){
++ if (le32_to_cpu(trx.flag_version >> 16)==2){
++ pr_notice("dual image TRX header found\n");
++ return mtd->size / 2;
++ } else {
++ return 0;
++ }
++ }
++ }
++ return 0;
++}
++
++
++static int
++find_root(struct mtd_info *mtd, struct mtd_partition *part)
++{
++ struct trx_header trx, *trx2;
++ unsigned char buf[512], *block;
++ int off, blocksize, trxoff = 0;
++ u32 i, crc = ~0;
++ size_t len;
++ bool edimax = false;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < mtd->size; off += blocksize) {
++ memset(&trx, 0xe5, sizeof(trx));
++
++ /*
++ * Read into buffer
++ */
++ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx))
++ continue;
++
++ /* found an edimax header */
++ if (le32_to_cpu(trx.magic) == EDIMAX_PS_HEADER_MAGIC) {
++ /* read the correct trx header */
++ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN,
++ sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx)) {
++ continue;
++ } else {
++ pr_notice("Found an edimax ps header\n");
++ edimax = true;
++ }
++ }
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
++ part->offset = le32_to_cpu(trx.offsets[2]) ? :
++ le32_to_cpu(trx.offsets[1]);
++ part->size = le32_to_cpu(trx.len);
++
++ part->size -= part->offset;
++ part->offset += off;
++ if (edimax) {
++ off += EDIMAX_PS_HEADER_LEN;
++ trxoff = EDIMAX_PS_HEADER_LEN;
++ }
++
++ goto found;
++ }
++ }
++
++ pr_warn("%s: Couldn't find root filesystem\n",
++ mtd->name);
++ return -1;
++
++ found:
++ pr_notice("TRX offset : %x\n", trxoff);
++ if (part->size == 0)
++ return 0;
++
++ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++
++ /* Move the fs outside of the trx */
++ part->size = 0;
++
++ if (trx.len != part->offset + part->size - off) {
++ /* Update the trx offsets and length */
++ trx.len = part->offset + part->size - off;
++
++ /* Update the trx crc32 */
++ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
++ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
++ }
++ trx.crc32 = crc;
++
++ /* read first eraseblock from the trx */
++ block = kmalloc(mtd->erasesize, GFP_KERNEL);
++ trx2 = (struct trx_header *) block;
++ if (mtd->read(mtd, off - trxoff, mtd->erasesize, &len, block) || len != mtd->erasesize) {
++ pr_err("Error accessing the first trx eraseblock\n");
++ return 0;
++ }
++
++ pr_notice("Updating TRX offsets and length:\n");
++ pr_notice("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
++ pr_notice("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
++
++ /* Write updated trx header to the flash */
++ memcpy(block + trxoff, &trx, sizeof(trx));
++ if (mtd->unlock)
++ mtd->unlock(mtd, off - trxoff, mtd->erasesize);
++ erase_write(mtd, off - trxoff, mtd->erasesize, block);
++ if (mtd->sync)
++ mtd->sync(mtd);
++ kfree(block);
++ pr_notice("Done\n");
++ }
++
++ return part->size;
++}
++
++static int get_router(void)
++{
++ char buf[20];
++ u32 boardnum = 0;
++ u16 boardtype = 0;
++ u16 boardrev = 0;
++ u32 boardflags = 0;
++ u16 sdram_init = 0;
++ u16 cardbus = 0;
++ u16 strev = 0;
++
++ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0)
++ boardnum = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
++ boardtype = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
++ boardrev = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0)
++ boardflags = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("sdram_init", buf, sizeof(buf)) >= 0)
++ sdram_init = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
++ cardbus = simple_strtoul(buf, NULL, 0);
++ if (nvram_getenv("st_rev", buf, sizeof(buf)) >= 0)
++ strev = simple_strtoul(buf, NULL, 0);
++
++ if ((boardnum == 8 || boardnum == 01)
++ && boardtype == 0x0472 && cardbus == 1) {
++ /* Netgear WNR834B, Netgear WNR834Bv2 */
++ return ROUTER_NETGEAR_WNR834B;
++ }
++
++ if (boardnum == 01 && boardtype == 0x0472 && boardrev == 0x23) {
++ /* Netgear WNDR-3300 */
++ return ROUTER_NETGEAR_WNDR3300;
++ }
++
++ if ((boardnum == 83258 || boardnum == 01)
++ && boardtype == 0x048e
++ && (boardrev == 0x11 || boardrev == 0x10)
++ && boardflags == 0x750
++ && sdram_init == 0x000A) {
++ /* Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5 */
++ return ROUTER_NETGEAR_WGR614L;
++ }
++
++ if ((boardnum == 1 || boardnum == 3500)
++ && boardtype == 0x04CF
++ && (boardrev == 0x1213 || boardrev == 02)) {
++ /* Netgear WNR3500v2/U/L */
++ return ROUTER_NETGEAR_WNR3500L;
++ }
++
++ if (boardtype == 0x042f
++ && boardrev == 0x10
++ && boardflags == 0
++ && strev == 0x11) {
++ /* Simpletech Simpleshare */
++ return ROUTER_SIMPLETECH_SIMPLESHARE;
++ }
++
++ return 0;
++}
++
++static int parse_bcm47xx_partitions(struct mtd_info *mtd,
++ struct mtd_partition **pparts,
++// struct mtd_part_parser_data *data)
++ unsigned long data)
++{
++ int cfe_size;
++ int dual_image_offset = 0;
++ /* e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this
++ * part from our mapping to prevent overwriting len/checksum on e.g.
++ * Netgear WGR614v8/L/WW
++ */
++ int custom_data_size = 0;
++
++ if ((cfe_size = find_cfe_size(mtd)) < 0)
++ return 0;
++
++ /* boot loader */
++ bcm47xx_parts[0].offset = 0;
++ bcm47xx_parts[0].size = cfe_size;
++
++ /* nvram */
++ if (cfe_size != 384 * 1024) {
++
++ switch (get_router()) {
++ case ROUTER_NETGEAR_WGR614L:
++ case ROUTER_NETGEAR_WNR834B:
++ case ROUTER_NETGEAR_WNDR3300:
++ case ROUTER_NETGEAR_WNR3500L:
++ /* Netgear: checksum is @ 0x003AFFF8 for 4M flash or checksum
++ * is @ 0x007AFFF8 for 8M flash
++ */
++ custom_data_size = mtd->erasesize;
++
++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++
++ /* Place CFE board_data into a partition */
++ bcm47xx_parts[4].name = "board_data";
++ bcm47xx_parts[4].offset = bcm47xx_parts[3].offset - custom_data_size;
++ bcm47xx_parts[4].size = custom_data_size;
++ break;
++
++ case ROUTER_SIMPLETECH_SIMPLESHARE:
++ /* Fixup Simpletech Simple share nvram */
++
++ pr_notice("Setting up simpletech nvram\n");
++ custom_data_size = mtd->erasesize;
++
++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize) * 2;
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++
++ /* Place backup nvram into a partition */
++ bcm47xx_parts[4].name = "nvram_copy";
++ bcm47xx_parts[4].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
++ bcm47xx_parts[4].size = roundup(NVRAM_SPACE, mtd->erasesize);
++ break;
++
++ default:
++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize);
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++ }
++
++ } else {
++ /* nvram (old 128kb config partition on netgear wgt634u) */
++ bcm47xx_parts[3].offset = bcm47xx_parts[0].size;
++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize);
++ }
++
++ /* dual image offset*/
++ pr_notice("Looking for dual image\n");
++ dual_image_offset=find_dual_image_off(mtd);
++ /* linux (kernel and rootfs) */
++ if (cfe_size != 384 * 1024) {
++ if (get_router() == ROUTER_SIMPLETECH_SIMPLESHARE) {
++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
++ bcm47xx_parts[1].size = bcm47xx_parts[4].offset - dual_image_offset -
++ bcm47xx_parts[1].offset - custom_data_size;
++ } else {
++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
++ bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset -
++ bcm47xx_parts[1].offset - custom_data_size;
++ }
++ } else {
++ /* do not count the elf loader, which is on one block */
++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
++ bcm47xx_parts[3].size + mtd->erasesize;
++ bcm47xx_parts[1].size = mtd->size -
++ bcm47xx_parts[0].size -
++ (2*bcm47xx_parts[3].size) -
++ mtd->erasesize - custom_data_size;
++ }
++
++ /* find and size rootfs */
++ find_root(mtd, &bcm47xx_parts[2]);
++ bcm47xx_parts[2].size = mtd->size - dual_image_offset -
++ bcm47xx_parts[2].offset -
++ bcm47xx_parts[3].size - custom_data_size;
++ *pparts = bcm47xx_parts;
++ return bcm47xx_parts[4].name == NULL ? 4 : 5;
++}
++
++static struct mtd_part_parser bcm47xx_parser = {
++ .owner = THIS_MODULE,
++ .parse_fn = parse_bcm47xx_partitions,
++ .name = "bcm47xx",
++};
++
++static int __init bcm47xx_parser_init(void)
++{
++ return register_mtd_parser(&bcm47xx_parser);
++}
++
++static void __exit bcm47xx_parser_exit(void)
++{
++ deregister_mtd_parser(&bcm47xx_parser);
++}
++
++module_init(bcm47xx_parser_init);
++module_exit(bcm47xx_parser_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Parsing code for flash partitions on bcm47xx SoCs");
--- /dev/null
+From 941c7a12af5d985c9dabc6813db3b75908bd619c Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:55:18 +0200
+Subject: [PATCH 15/22] mtd: bcm47xx: add parallel flash driver
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/mtd/maps/Kconfig | 9 ++
+ drivers/mtd/maps/Makefile | 1 +
+ drivers/mtd/maps/bcm47xx-pflash.c | 196 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 206 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/maps/bcm47xx-pflash.c
+
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -264,6 +264,15 @@ config MTD_LANTIQ
+ help
+ Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
+
++config MTD_BCM47XX_PFLASH
++ tristate "bcm47xx parallel flash support"
++ default y
++ depends on BCM47XX
++ select MTD_PARTITIONS
++ select MTD_BCM47XX_PARTS
++ help
++ Support for bcm47xx parallel flash
++
+ config MTD_DILNETPC
+ tristate "CFI Flash device mapped on DIL/Net PC"
+ depends on X86 && MTD_CFI_INTELEXT && BROKEN
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -60,3 +60,4 @@ obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr
+ obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
+ obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
+ obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
++obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
+--- /dev/null
++++ b/drivers/mtd/maps/bcm47xx-pflash.c
+@@ -0,0 +1,196 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * original functions for finding root filesystem from Mike Baker
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * Flash mapping for BCM947XX boards
++ */
++
++#define pr_fmt(fmt) "bcm47xx_pflash: " fmt
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <asm/io.h>
++#include <asm/mach-bcm47xx/bcm47xx.h>
++#include <linux/platform_device.h>
++
++#define WINDOW_ADDR 0x1fc00000
++#define WINDOW_SIZE 0x400000
++#define BUSWIDTH 2
++
++static struct mtd_info *bcm47xx_mtd;
++
++static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ if (len==1) {
++ memcpy_fromio(to, map->virt + from, len);
++ } else {
++ int i;
++ u16 *dest = (u16 *) to;
++ u16 *src = (u16 *) (map->virt + from);
++ for (i = 0; i < (len / 2); i++) {
++ dest[i] = src[i];
++ }
++ if (len & 1)
++ *((u8 *)dest+len-1) = src[i] & 0xff;
++ }
++}
++
++static struct map_info bcm47xx_map = {
++ name: "Physically mapped flash",
++ size: WINDOW_SIZE,
++ bankwidth: BUSWIDTH,
++ phys: WINDOW_ADDR,
++};
++
++static const char *probes[] = { "bcm47xx", NULL };
++
++static int bcm47xx_mtd_probe(struct platform_device *pdev)
++{
++#ifdef CONFIG_BCM47XX_SSB
++ struct ssb_mipscore *mcore_ssb;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ struct bcma_drv_cc *bcma_cc;
++#endif
++ int ret = 0;
++ struct mtd_partition *partitions = NULL;
++ int num_partitions = 0;
++
++ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
++ bcm47xx_map.phys = mcore_ssb->flash_window;
++ bcm47xx_map.size = mcore_ssb->flash_window_size;
++ bcm47xx_map.bankwidth = mcore_ssb->flash_buswidth;
++ break;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ bcma_cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ if (bcma_cc->flash_type != BCMA_PFLASH)
++ return -ENODEV;
++
++ bcm47xx_map.phys = bcma_cc->flash.pflash.window;
++ bcm47xx_map.size = bcma_cc->flash.pflash.window_size;
++ bcm47xx_map.bankwidth = bcma_cc->flash.pflash.buswidth;
++ break;
++#endif
++ }
++
++ pr_notice("flash init: 0x%08x 0x%08lx\n", bcm47xx_map.phys, bcm47xx_map.size);
++ bcm47xx_map.virt = ioremap_nocache(bcm47xx_map.phys, bcm47xx_map.size);
++
++ if (!bcm47xx_map.virt) {
++ pr_err("Failed to ioremap\n");
++ return -EIO;
++ }
++
++ simple_map_init(&bcm47xx_map);
++ /* override copy_from routine */
++ bcm47xx_map.copy_from = bcm47xx_map_copy_from;
++
++ bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map);
++ if (!bcm47xx_mtd) {
++ pr_err("Failed to do_map_probe\n");
++ ret = -ENXIO;
++ goto err_unmap;
++ }
++ bcm47xx_mtd->owner = THIS_MODULE;
++
++ pr_notice("Flash device: 0x%lx at 0x%x\n", bcm47xx_map.size, WINDOW_ADDR);
++
++ num_partitions = parse_mtd_partitions(bcm47xx_mtd, probes, &partitions, 0);
++ if (num_partitions < 0) {
++ ret = num_partitions;
++ goto err_unmap;
++ }
++
++ ret = mtd_device_register(bcm47xx_mtd, partitions, num_partitions);
++
++// ret = mtd_device_parse_register(bcm47xx_mtd, "bcm47xx", NULL, NULL, 0);
++
++ if (ret) {
++ pr_err("Flash: mtd_device_register failed\n");
++ goto err_destroy;
++ }
++ return 0;
++
++err_destroy:
++ map_destroy(bcm47xx_mtd);
++err_unmap:
++ iounmap(bcm47xx_map.virt);
++ return ret;
++}
++
++static int __devexit bcm47xx_mtd_remove(struct platform_device *pdev)
++{
++ mtd_device_unregister(bcm47xx_mtd);
++ map_destroy(bcm47xx_mtd);
++ iounmap(bcm47xx_map.virt);
++ return 0;
++}
++
++static struct platform_driver bcm47xx_mtd_driver = {
++ .remove = __devexit_p(bcm47xx_mtd_remove),
++ .driver = {
++ .name = "bcm47xx_pflash",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init init_bcm47xx_mtd(void)
++{
++ int ret = platform_driver_probe(&bcm47xx_mtd_driver, bcm47xx_mtd_probe);
++
++ if (ret)
++ pr_err("error registering platform driver: %i\n", ret);
++ return ret;
++}
++
++static void __exit exit_bcm47xx_mtd(void)
++{
++ platform_driver_unregister(&bcm47xx_mtd_driver);
++}
++
++module_init(init_bcm47xx_mtd);
++module_exit(exit_bcm47xx_mtd);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("BCM47XX parallel flash driver");
--- /dev/null
+From 8a6398687998886c451c6df381c2320b6dddb3fe Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 14:55:45 +0200
+Subject: [PATCH 16/22] mtd: bcm47xx: add serial flash driver
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/mtd/maps/Kconfig | 9 ++
+ drivers/mtd/maps/Makefile | 1 +
+ drivers/mtd/maps/bcm47xx-sflash.c | 270 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 280 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/maps/bcm47xx-sflash.c
+
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -273,6 +273,15 @@ config MTD_BCM47XX_PFLASH
+ help
+ Support for bcm47xx parallel flash
+
++config MTD_BCM47XX_SFLASH
++ tristate "bcm47xx serial flash support"
++ default y
++ depends on BCM47XX
++ select MTD_PARTITIONS
++ select MTD_BCM47XX_PARTS
++ help
++ Support for bcm47xx parallel flash
++
+ config MTD_DILNETPC
+ tristate "CFI Flash device mapped on DIL/Net PC"
+ depends on X86 && MTD_CFI_INTELEXT && BROKEN
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -61,3 +61,4 @@ obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-f
+ obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
+ obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
+ obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
++obj-$(CONFIG_MTD_BCM47XX_SFLASH)+= bcm47xx-sflash.o
+--- /dev/null
++++ b/drivers/mtd/maps/bcm47xx-sflash.c
+@@ -0,0 +1,270 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#define pr_fmt(fmt) "bcm47xx_sflash: " fmt
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++
++#include <bcm47xx.h>
++
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_driver_chipcommon.h>
++#include <linux/platform_device.h>
++
++struct sflash_mtd {
++ struct bcma_drv_cc *cc;
++ struct mtd_info mtd;
++ struct mtd_erase_region_info region;
++};
++
++static struct sflash_mtd *sflash;
++
++static int
++sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
++{
++ unsigned long now = jiffies;
++ int ret = 0;
++
++ for (;;) {
++ if (!bcma_sflash_poll(sflash->cc, offset)) {
++ ret = 0;
++ break;
++ }
++ if (time_after(jiffies, now + timeout)) {
++ pr_err("timeout while polling\n");
++ ret = -ETIMEDOUT;
++ break;
++ }
++ udelay(1);
++ }
++
++ return ret;
++}
++
++static int
++sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++
++ if ((from + len) > mtd->size)
++ return -EINVAL;
++
++ *retlen = 0;
++
++ while (len) {
++ int ret = bcma_sflash_read(sflash->cc, from, len, buf);
++ if (ret < 0)
++ return ret;
++
++ from += (loff_t) ret;
++ len -= ret;
++ buf += ret;
++ *retlen += ret;
++ }
++
++ return 0;
++}
++
++static int
++sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
++{
++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++
++ if ((to + len) > mtd->size)
++ return -EINVAL;
++
++ *retlen = 0;
++ while (len) {
++ int bytes;
++ int ret = bcma_sflash_write(sflash->cc, to, len, buf);
++ if (ret < 0)
++ return ret;
++
++ bytes = ret;
++
++ ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10);
++ if (ret)
++ return ret;
++
++ to += (loff_t) bytes;
++ len -= bytes;
++ buf += bytes;
++ *retlen += bytes;
++ }
++
++ return 0;
++}
++
++static int
++sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
++{
++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
++ int i, j, ret = 0;
++ unsigned int addr, len;
++
++ /* Check address range */
++ if (!erase->len)
++ return 0;
++ if ((erase->addr + erase->len) > mtd->size)
++ return -EINVAL;
++
++ addr = erase->addr;
++ len = erase->len;
++
++ /* Ensure that requested regions are aligned */
++ for (i = 0; i < mtd->numeraseregions; i++) {
++ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
++ if (addr == mtd->eraseregions[i].offset +
++ mtd->eraseregions[i].erasesize * j &&
++ len >= mtd->eraseregions[i].erasesize) {
++ if ((ret = bcma_sflash_erase(sflash->cc, addr)) < 0)
++ break;
++ if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ)))
++ break;
++ addr += mtd->eraseregions[i].erasesize;
++ len -= mtd->eraseregions[i].erasesize;
++ }
++ }
++ if (ret)
++ break;
++ }
++
++ /* Set erase status */
++ if (ret)
++ erase->state = MTD_ERASE_FAILED;
++ else
++ erase->state = MTD_ERASE_DONE;
++
++ /* Call erase callback */
++ if (erase->callback)
++ erase->callback(erase);
++
++ return ret;
++}
++
++static const char *probes[] = { "bcm47xx", NULL };
++
++static int bcm47xx_sflash_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ struct mtd_partition *parts;
++ int num_partitions = 0;
++
++ sflash = kzalloc(sizeof(struct sflash_mtd), GFP_KERNEL);
++ if (!sflash)
++ return -ENOMEM;
++
++ sflash->cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ if (sflash->cc->flash_type != BCMA_SFLASH)
++ return -ENODEV;
++
++ pr_info("found serial flash: blocksize=%dKB, numblocks=%d, size=%dKB\n",
++ sflash->cc->flash.sflash.blocksize/1024,
++ sflash->cc->flash.sflash.numblocks,
++ sflash->cc->flash.sflash.size/1024);
++
++ /* Setup region info */
++ sflash->region.offset = 0;
++ sflash->region.erasesize = sflash->cc->flash.sflash.blocksize;
++ sflash->region.numblocks = sflash->cc->flash.sflash.numblocks;
++ if (sflash->region.erasesize > sflash->mtd.erasesize)
++ sflash->mtd.erasesize = sflash->region.erasesize;
++ sflash->mtd.size = sflash->cc->flash.sflash.size;
++ sflash->mtd.numeraseregions = 1;
++
++ /* Register with MTD */
++ sflash->mtd.name = "bcm47xx-sflash";
++ sflash->mtd.type = MTD_NORFLASH;
++ sflash->mtd.flags = MTD_CAP_NORFLASH;
++ sflash->mtd.eraseregions = &sflash->region;
++ sflash->mtd.erase = sflash_mtd_erase;
++ sflash->mtd.read = sflash_mtd_read;
++ sflash->mtd.write = sflash_mtd_write;
++ sflash->mtd.writesize = 1;
++ sflash->mtd.priv = sflash;
++ sflash->mtd.owner = THIS_MODULE;
++
++ num_partitions = parse_mtd_partitions(&sflash->mtd, probes, &parts, 0);
++ if (num_partitions < 0) {
++ ret = num_partitions;
++ goto err_destroy;
++ }
++
++ ret = mtd_device_register(&sflash->mtd, parts, num_partitions);
++
++// ret = mtd_device_parse_register(bcm47xx_mtd, "bcm47xx", NULL, NULL, 0);
++
++ if (ret) {
++ pr_err("mtd_device_register failed\n");
++ return ret;
++ }
++ return 0;
++
++err_destroy:
++ map_destroy(&sflash->mtd);
++ return ret;
++}
++
++static int __devexit bcm47xx_sflash_remove(struct platform_device *pdev)
++{
++ if (sflash) {
++ mtd_device_unregister(&sflash->mtd);
++ map_destroy(&sflash->mtd);
++ }
++ return 0;
++}
++
++static struct platform_driver bcm47xx_sflash_driver = {
++ .remove = __devexit_p(bcm47xx_sflash_remove),
++ .driver = {
++ .name = "bcm47xx_sflash",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init init_bcm47xx_sflash(void)
++{
++ int ret = platform_driver_probe(&bcm47xx_sflash_driver, bcm47xx_sflash_probe);
++
++ if (ret)
++ pr_err("error registering platform driver: %i\n", ret);
++ return ret;
++}
++
++static void __exit exit_bcm47xx_sflash(void)
++{
++ platform_driver_unregister(&bcm47xx_sflash_driver);
++}
++
++module_init(init_bcm47xx_sflash);
++module_exit(exit_bcm47xx_sflash);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("BCM47XX parallel flash driver");
--- /dev/null
+From 89b904335338c86ef2c40e7cc51e19673feb62c1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 17 Jul 2011 15:02:10 +0200
+Subject: [PATCH 17/22] bcm47xx: register flash drivers
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/mips/bcm47xx/setup.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 50 insertions(+), 0 deletions(-)
+
+--- a/arch/mips/bcm47xx/setup.c
++++ b/arch/mips/bcm47xx/setup.c
+@@ -30,6 +30,7 @@
+ #include <linux/ssb/ssb.h>
+ #include <linux/ssb/ssb_embedded.h>
+ #include <linux/bcma/bcma_soc.h>
++#include <linux/platform_device.h>
+ #include <asm/bootinfo.h>
+ #include <asm/reboot.h>
+ #include <asm/time.h>
+@@ -357,3 +358,52 @@ static int __init bcm47xx_register_bus_c
+ return 0;
+ }
+ device_initcall(bcm47xx_register_bus_complete);
++
++static struct resource bcm47xx_pflash_resource = {
++ .name = "para",
++ .start = 0,
++ .end = 0,
++ .flags = 0,
++};
++
++static struct platform_device bcm47xx_pflash = {
++ .name = "bcm47xx_pflash",
++ .resource = &bcm47xx_pflash_resource,
++ .num_resources = 1,
++};
++
++static struct resource bcm47xx_sflash_resource = {
++ .name = "serial",
++ .start = 0,
++ .end = 0,
++ .flags = 0,
++};
++
++static struct platform_device bcm47xx_sflash = {
++ .name = "bcm47xx_sflash",
++ .resource = &bcm47xx_sflash_resource,
++ .num_resources = 1,
++};
++
++static int __init bcm47xx_register_flash(void)
++{
++ switch (bcm47xx_active_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ return platform_device_register(&bcm47xx_pflash);
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_PFLASH) {
++ return platform_device_register(&bcm47xx_pflash);
++ } else if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH) {
++ return platform_device_register(&bcm47xx_sflash);
++ } else {
++ printk(KERN_ERR "No flash device found\n");
++ return -1;
++ }
++#endif
++ }
++ return 0;
++}
++fs_initcall(bcm47xx_register_flash);
--- /dev/null
+From 1b23f310d4a7d24efe5dffbbde6b2b84252e2d7b Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 22 Jul 2011 14:18:21 +0200
+Subject: [PATCH 19/22] bcma: to not route irqs on non pci devices
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/driver_pci.c | 9 ++++++++-
+ 1 files changed, 8 insertions(+), 1 deletions(-)
+
+--- 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
+From f3007275d7706afb1381adb0003f3ba69d359c8f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 22 Jul 2011 17:09:36 +0200
+Subject: [PATCH 20/22] bcma: small fixes needed to get b43 up with SoC
+
+When using an SoC these small cahnges are neede to get it up
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/core.c | 2 ++
+ drivers/bcma/main.c | 3 +++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+--- 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/main.c
++++ b/drivers/bcma/main.c
+@@ -99,7 +99,10 @@ static int bcma_register_cores(struct bc
+ core->irq = bus->host_pci->irq;
+ break;
+ case BCMA_HOSTTYPE_SDIO:
++ break;
+ case BCMA_HOSTTYPE_SOC:
++ core->dev.dma_mask = &core->dev.coherent_dma_mask;
++ core->dma_dev = &core->dev;
+ break;
+ }
+
--- /dev/null
+From 6dd27601bee9b3c26cdb67246b6da51dd696ac34 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 22 Jul 2011 17:11:51 +0200
+Subject: [PATCH 22/22] bcma: use randoom mac address as long as reading it out does not work
+
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/bcma/sprom.c | 5 ++++-
+ 1 files changed, 4 insertions(+), 1 deletions(-)
+
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -13,6 +13,7 @@
+ #include <linux/io.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/slab.h>
++#include <linux/etherdevice.h>
+
+ #define SPOFF(offset) ((offset) / sizeof(u16))
+
+@@ -144,8 +145,10 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ if (!bus->drv_cc.core)
+ return -EOPNOTSUPP;
+
+- if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
++ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM)) {
++ random_ether_addr(bus->sprom.il0mac);
+ return -ENOENT;
++ }
+
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL);
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -30,6 +30,8 @@
- #include <linux/ssb/ssb.h>
+@@ -31,6 +31,8 @@
#include <linux/ssb/ssb_embedded.h>
#include <linux/bcma/bcma_soc.h>
+ #include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
-@@ -274,6 +276,31 @@ static int bcm47xx_get_invariants(struct
+@@ -275,6 +277,31 @@ static int bcm47xx_get_invariants(struct
return 0;
}
static void __init bcm47xx_register_ssb(void)
{
int err;
-@@ -303,6 +330,10 @@ static void __init bcm47xx_register_ssb(
+@@ -304,6 +331,10 @@ static void __init bcm47xx_register_ssb(
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
}
}
+++ /dev/null
---- a/drivers/mtd/maps/Kconfig
-+++ b/drivers/mtd/maps/Kconfig
-@@ -332,6 +332,12 @@ config MTD_CFI_FLAGADM
- Mapping for the Flaga digital module. If you don't have one, ignore
- this setting.
-
-+config MTD_BCM47XX
-+ tristate "BCM47xx flash device"
-+ depends on MIPS && MTD_CFI && BCM47XX
-+ help
-+ Support for the flash chips on the BCM947xx board.
-+
- config MTD_SOLUTIONENGINE
- tristate "CFI Flash device mapped on Hitachi SolutionEngine"
- depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS
---- a/drivers/mtd/maps/Makefile
-+++ b/drivers/mtd/maps/Makefile
-@@ -28,6 +28,7 @@ obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcms
- obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
- obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
- obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
-+obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o
- obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
- obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
- obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
+++ /dev/null
---- a/drivers/mtd/maps/bcm47xx-flash.c
-+++ b/drivers/mtd/maps/bcm47xx-flash.c
-@@ -44,9 +44,7 @@
- #include <linux/wait.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
--#ifdef CONFIG_MTD_PARTITIONS
- #include <linux/mtd/partitions.h>
--#endif
- #include <linux/crc32.h>
- #ifdef CONFIG_SSB
- #include <linux/ssb/ssb.h>
-@@ -120,7 +118,6 @@ static struct map_info bcm47xx_map = {
- phys: WINDOW_ADDR,
- };
-
--#ifdef CONFIG_MTD_PARTITIONS
-
- static struct mtd_partition bcm47xx_parts[] = {
- { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
-@@ -552,7 +549,6 @@ init_mtd_partitions(struct mtd_info *mtd
-
- return bcm47xx_parts;
- }
--#endif
-
- int __init init_bcm47xx_map(void)
- {
-@@ -561,10 +557,8 @@ int __init init_bcm47xx_map(void)
- #endif
- size_t size;
- int ret = 0;
--#ifdef CONFIG_MTD_PARTITIONS
- struct mtd_partition *parts;
- int i;
--#endif
-
- #ifdef CONFIG_SSB
- u32 window = mcore->flash_window;
-@@ -602,15 +596,13 @@ int __init init_bcm47xx_map(void)
-
- printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
-
--#ifdef CONFIG_MTD_PARTITIONS
- parts = init_mtd_partitions(bcm47xx_mtd, size);
- for (i = 0; parts[i].name; i++);
-- ret = add_mtd_partitions(bcm47xx_mtd, parts, i);
-+ ret = mtd_device_register(bcm47xx_mtd, parts, i);
- if (ret) {
-- printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
-+ printk(KERN_ERR "Flash: mtd_device_register failed\n");
- goto fail;
- }
--#endif
- return 0;
-
- fail:
-@@ -624,9 +616,7 @@ int __init init_bcm47xx_map(void)
-
- void __exit cleanup_bcm47xx_map(void)
- {
--#ifdef CONFIG_MTD_PARTITIONS
-- del_mtd_partitions(bcm47xx_mtd);
--#endif
-+ mtd_device_unregister(bcm47xx_mtd);
- map_destroy(bcm47xx_mtd);
- iounmap((void *)bcm47xx_map.virt);
- }
+++ /dev/null
---- a/drivers/mtd/maps/bcm47xx-flash.c
-+++ b/drivers/mtd/maps/bcm47xx-flash.c
-@@ -46,11 +46,9 @@
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
- #include <linux/crc32.h>
--#ifdef CONFIG_SSB
--#include <linux/ssb/ssb.h>
--#endif
- #include <asm/io.h>
- #include <asm/mach-bcm47xx/nvram.h>
-+#include <asm/mach-bcm47xx/bcm47xx.h>
- #include <asm/fw/cfe/cfe_api.h>
-
-
-@@ -90,9 +88,6 @@ struct trx_header {
- #define ROUTER_NETGEAR_WNR3500L 4
- #define ROUTER_SIMPLETECH_SIMPLESHARE 5
-
--#ifdef CONFIG_SSB
--extern struct ssb_bus ssb_bcm47xx;
--#endif
- static struct mtd_info *bcm47xx_mtd;
-
- static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-@@ -552,27 +547,42 @@ init_mtd_partitions(struct mtd_info *mtd
-
- int __init init_bcm47xx_map(void)
- {
--#ifdef CONFIG_SSB
-- struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
-+#ifdef CONFIG_BCM47XX_SSB
-+ struct ssb_mipscore *mcore_ssb;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ struct bcma_drv_mips *mcore_bcma;
- #endif
- size_t size;
- int ret = 0;
-+ u32 window = 0;
-+ u32 window_size = 0;
- struct mtd_partition *parts;
- int i;
-
--#ifdef CONFIG_SSB
-- u32 window = mcore->flash_window;
-- u32 window_size = mcore->flash_window_size;
-+ switch (bcm47xx_active_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ mcore_ssb = &bcm47xx_bus.ssb.mipscore;
-+ window = mcore_ssb->flash_window;
-+ window_size = mcore_ssb->flash_window_size;
-+ bcm47xx_map.bankwidth = mcore_ssb->flash_buswidth;
-+ break;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ mcore_bcma = &bcm47xx_bus.bcma.bus.drv_mips;
-+ window = mcore_bcma->flash_window;
-+ window_size = mcore_bcma->flash_window_size;
-+ bcm47xx_map.bankwidth = mcore_bcma->flash_buswidth;
-+ break;
-+#endif
-+ }
-
- printk("flash init: 0x%08x 0x%08x\n", window, window_size);
- bcm47xx_map.phys = window;
- bcm47xx_map.size = window_size;
-- bcm47xx_map.bankwidth = mcore->flash_buswidth;
- bcm47xx_map.virt = ioremap_nocache(window, window_size);
--#else
-- printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
-- bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
--#endif
-
- if (!bcm47xx_map.virt) {
- printk("Failed to ioremap\n");
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
-@@ -114,3 +114,30 @@ int nvram_getenv(char *name, char *val,
+@@ -117,3 +117,30 @@ int nvram_getenv(char *name, char *val,
return NVRAM_ERR_ENVNOTFOUND;
}
EXPORT_SYMBOL(nvram_getenv);
+EXPORT_SYMBOL(nvram_get);
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -388,3 +388,20 @@ static int __init bcm47xx_register_bus_c
+@@ -438,3 +438,20 @@ static int __init bcm47xx_register_flash
return 0;
}
- device_initcall(bcm47xx_register_bus_complete);
+ fs_initcall(bcm47xx_register_flash);
+
+static int __init bcm47xx_register_gpiodev(void)
+{
-obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
--- a/arch/mips/bcm47xx/wgt634u.c
+++ /dev/null
-@@ -1,169 +0,0 @@
+@@ -1,170 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * machine. Use the MAC address as an heuristic. Netgear Inc. has
- * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
- */
+- u8 *et0mac;
-
- if (bcm47xx_active_bus_type != BCM47XX_BUS_TYPE_SSB)
- return -ENODEV;
-
-- u8 *et0mac = bcm47xx_bus.ssb.sprom.et0mac;
+- et0mac = bcm47xx_bus.ssb.sprom.et0mac;
-
- if (et0mac[0] == 0x00 &&
- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
/* Probe for NVRAM header */
static void early_nvram_init(void)
-@@ -55,6 +57,25 @@ static void early_nvram_init(void)
+@@ -58,6 +60,25 @@ static void early_nvram_init(void)
break;
#endif
}
off = FLASH_MIN;
while (off <= lim) {
-@@ -96,6 +117,12 @@ int nvram_getenv(char *name, char *val,
+@@ -99,6 +120,12 @@ int nvram_getenv(char *name, char *val,
if (!nvram_buf[0])
early_nvram_init();
/* Look for name=value and return value */
var = &nvram_buf[sizeof(struct nvram_header)];
end = nvram_buf + sizeof(nvram_buf) - 2;
-@@ -125,6 +152,9 @@ char *nvram_get(const char *name)
+@@ -128,6 +155,9 @@ char *nvram_get(const char *name)
if (!nvram_buf[0])
early_nvram_init();
ssb_printk(KERN_ERR PFX
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
-@@ -155,9 +155,16 @@ struct ssb_bus_ops {
+@@ -157,9 +157,16 @@ struct ssb_bus_ops {
#define SSB_DEV_MINI_MACPHY 0x823
#define SSB_DEV_ARM_1176 0x824
#define SSB_DEV_ARM_7TDMI 0x825
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -273,6 +273,10 @@ static int bcm47xx_get_invariants(struct
+@@ -274,6 +274,10 @@ static int bcm47xx_get_invariants(struct
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
{
struct ssb_bus *bus = pc->dev->bus;
u16 chipid_top;
-@@ -403,28 +408,129 @@ static int pcicore_is_in_hostmode(struct
+@@ -403,25 +408,133 @@ static int pcicore_is_in_hostmode(struct
}
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
-static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
{
++ ssb_pcicore_fix_sprom_core_index(pc);
++
/* Disable PCI interrupts. */
ssb_write32(pc->dev, SSB_INTVEC, 0);
++
++ /* Additional PCIe always once-executed workarounds */
++ if (pc->dev->id.coreid == SSB_DEV_PCIE) {
++ ssb_pcicore_serdes_workaround(pc);
++ /* TODO: ASPM */
++ /* TODO: Clock Request Update */
++ }
}
-void ssb_pcicore_init(struct ssb_pcicore *pc)
if (!ssb_device_is_enabled(dev))
ssb_device_enable(dev, 0);
-+ ssb_pcicore_fix_sprom_core_index(pc);
-+
- #ifdef CONFIG_SSB_PCICORE_HOSTMODE
- pc->hostmode = pcicore_is_in_hostmode(pc);
- if (pc->hostmode)
-@@ -432,6 +538,13 @@ void ssb_pcicore_init(struct ssb_pcicore
- #endif /* CONFIG_SSB_PCICORE_HOSTMODE */
- if (!pc->hostmode)
- ssb_pcicore_init_clientmode(pc);
-+
-+ /* Additional PCIe always once-executed workarounds */
-+ if (dev->id.coreid == SSB_DEV_PCIE) {
-+ ssb_pcicore_serdes_workaround(pc);
-+ /* TODO: ASPM */
-+ /* TODO: Clock Request Update */
-+ }
- }
-
- static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
@@ -446,11 +559,35 @@ static void ssb_pcie_write(struct ssb_pc
pcicore_write32(pc, 0x134, data);
}
}
int ssb_device_is_enabled(struct ssb_device *dev)
-@@ -1309,20 +1309,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown);
+@@ -1266,7 +1266,10 @@ u32 ssb_dma_translation(struct ssb_devic
+ 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)
{
return 0;
error:
ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
-@@ -1330,6 +1330,37 @@ error:
+@@ -1330,6 +1333,37 @@ error:
}
EXPORT_SYMBOL(ssb_bus_powerup);
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,
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
/* core.c */
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
-@@ -308,7 +308,7 @@ struct ssb_bus {
+@@ -27,6 +27,8 @@ struct ssb_sprom {
+ u8 et1mdcport; /* MDIO for enet1 */
+ u8 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 {
+ struct ssb_boardinfo {
+ u16 vendor;
+ u16 type;
+- u16 rev;
++ u8 rev;
+ };
+
+
+@@ -308,7 +310,7 @@ struct ssb_bus {
/* ID information about the Chip. */
u16 chip_id;
u16 sprom_offset;
u16 sprom_size; /* number of words in sprom */
u8 chip_package;
-@@ -404,7 +404,9 @@ extern bool ssb_is_sprom_available(struc
+@@ -404,7 +406,9 @@ extern bool ssb_is_sprom_available(struc
/* Set a fallback SPROM.
* See kdoc at the function definition for complete documentation. */
/* Suspend a SSB bus.
* Call this from the parent bus suspend routine. */
-@@ -518,6 +520,7 @@ extern int ssb_bus_may_powerdown(struct
+@@ -518,6 +522,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);
obj-$(CONFIG_STAGING) += staging/
--- /dev/null
+++ b/drivers/bcma/Kconfig
-@@ -0,0 +1,38 @@
+@@ -0,0 +1,44 @@
+config BCMA_POSSIBLE
+ bool
+ depends on HAS_IOMEM && HAS_DMA
+ bool "Support for BCMA on PCI-host bus"
+ depends on BCMA_HOST_PCI_POSSIBLE
+
++config BCMA_DRIVER_PCI_HOSTMODE
++ bool "Driver for PCI core working in hostmode"
++ depends on BCMA && MIPS
++ help
++ PCI core hostmode operation (external PCI bus).
++
+config BCMA_DEBUG
+ bool "BCMA debugging"
+ depends on BCMA
+endmenu
--- /dev/null
+++ b/drivers/bcma/Makefile
-@@ -0,0 +1,7 @@
+@@ -0,0 +1,8 @@
+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_HOST_PCI) += host_pci.o
+obj-$(CONFIG_BCMA) += bcma.o
+
+- Create kernel Documentation (use info from README)
--- /dev/null
+++ b/drivers/bcma/bcma_private.h
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,35 @@
+#ifndef LINUX_BCMA_PRIVATE_H_
+#define LINUX_BCMA_PRIVATE_H_
+
+extern void __exit bcma_host_pci_exit(void);
+#endif /* CONFIG_BCMA_HOST_PCI */
+
++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
++void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
++#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
++
+#endif
--- /dev/null
+++ b/drivers/bcma/core.c
-@@ -0,0 +1,52 @@
+@@ -0,0 +1,124 @@
+/*
+ * Broadcom specific AMBA
+ * Core ops
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcma_core_enable);
++
++void bcma_core_set_clockmode(struct bcma_device *core,
++ enum bcma_clkmode clkmode)
++{
++ u16 i;
++
++ WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON &&
++ core->id.id != BCMA_CORE_PCIE &&
++ core->id.id != BCMA_CORE_80211);
++
++ switch (clkmode) {
++ case BCMA_CLKMODE_FAST:
++ bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
++ udelay(64);
++ for (i = 0; i < 1500; i++) {
++ if (bcma_read32(core, BCMA_CLKCTLST) &
++ BCMA_CLKCTLST_HAVEHT) {
++ i = 0;
++ break;
++ }
++ udelay(10);
++ }
++ if (i)
++ pr_err("HT force timeout\n");
++ break;
++ case BCMA_CLKMODE_DYNAMIC:
++ pr_warn("Dynamic clockmode not supported yet!\n");
++ break;
++ }
++}
++EXPORT_SYMBOL_GPL(bcma_core_set_clockmode);
++
++void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
++{
++ u16 i;
++
++ WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ);
++ WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST);
++
++ if (on) {
++ bcma_set32(core, BCMA_CLKCTLST, req);
++ for (i = 0; i < 10000; i++) {
++ if ((bcma_read32(core, BCMA_CLKCTLST) & status) ==
++ status) {
++ i = 0;
++ break;
++ }
++ udelay(10);
++ }
++ if (i)
++ pr_err("PLL enable timeout\n");
++ } else {
++ pr_warn("Disabling PLL not supported yet!\n");
++ }
++}
++EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
++
++u32 bcma_core_dma_translation(struct bcma_device *core)
++{
++ switch (core->bus->hosttype) {
++ case BCMA_HOSTTYPE_PCI:
++ if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
++ return BCMA_DMA_TRANSLATION_DMA64_CMT;
++ else
++ return BCMA_DMA_TRANSLATION_DMA32_CMT;
++ default:
++ pr_err("DMA translation unknown for host %d\n",
++ core->bus->hosttype);
++ }
++ return BCMA_DMA_TRANSLATION_NONE;
++}
++EXPORT_SYMBOL(bcma_core_dma_translation);
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon.c
-@@ -0,0 +1,89 @@
+@@ -0,0 +1,103 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon core driver
+
+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);
+ 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.c
-@@ -0,0 +1,187 @@
+@@ -0,0 +1,223 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core
+ * Init.
+ **************************************************/
+
-+void bcma_core_pci_init(struct bcma_drv_pci *pc)
++static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
+{
+ bcma_pcicore_serdes_workaround(pc);
+}
+
++static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
++{
++ struct bcma_bus *bus = pc->core->bus;
++ u16 chipid_top;
++
++ chipid_top = (bus->chipinfo.id & 0xFF00);
++ if (chipid_top != 0x4700 &&
++ chipid_top != 0x5300)
++ return false;
++
++ if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++ return false;
++
++#if 0
++ /* TODO: on BCMA we use address from EROM instead of magic formula */
++ u32 tmp;
++ return !mips_busprobe32(tmp, (bus->mmio +
++ (pc->core->core_index * BCMA_CORE_SIZE)));
++#endif
++
++ return true;
++}
++
++void bcma_core_pci_init(struct bcma_drv_pci *pc)
++{
++ if (bcma_core_pci_is_in_hostmode(pc)) {
++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
++ bcma_core_pci_hostmode_init(pc);
++#else
++ pr_err("Driver compiled without support for hostmode PCI\n");
++#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
++ } else {
++ bcma_core_pci_clientmode_init(pc);
++ }
++}
++
+int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+ bool enable)
+{
+}
--- /dev/null
+++ b/drivers/bcma/main.c
-@@ -0,0 +1,255 @@
+@@ -0,0 +1,257 @@
+/*
+ * Broadcom specific AMBA
+ * Bus subsystem
+
+ /* Try to get SPROM */
+ err = bcma_sprom_get(bus);
-+ if (err) {
++ if (err == -ENOENT) {
++ pr_err("No SPROM available\n");
++ } else if (err) {
+ pr_err("Failed to get SPROM: %d\n", err);
+ return -ENOENT;
+ }
+#endif /* BCMA_SCAN_H_ */
--- /dev/null
+++ b/include/linux/bcma/bcma.h
-@@ -0,0 +1,250 @@
+@@ -0,0 +1,271 @@
+#ifndef LINUX_BCMA_H_
+#define LINUX_BCMA_H_
+
+ u8 pkg;
+};
+
++enum bcma_clkmode {
++ BCMA_CLKMODE_FAST,
++ BCMA_CLKMODE_DYNAMIC,
++};
++
+struct bcma_host_ops {
+ u8 (*read8)(struct bcma_device *core, u16 offset);
+ u16 (*read16)(struct bcma_device *core, u16 offset);
+ 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))
++
+extern bool bcma_core_is_enabled(struct bcma_device *core);
+extern void bcma_core_disable(struct bcma_device *core, u32 flags);
+extern int bcma_core_enable(struct bcma_device *core, u32 flags);
++extern void bcma_core_set_clockmode(struct bcma_device *core,
++ enum bcma_clkmode clkmode);
++extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
++ bool on);
++#define BCMA_DMA_TRANSLATION_MASK 0xC0000000
++#define BCMA_DMA_TRANSLATION_NONE 0x00000000
++#define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */
++#define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */
++extern u32 bcma_core_dma_translation(struct bcma_device *core);
+
+#endif /* LINUX_BCMA_H_ */
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -0,0 +1,303 @@
+@@ -0,0 +1,296 @@
+#ifndef LINUX_BCMA_DRIVER_CC_H_
+#define LINUX_BCMA_DRIVER_CC_H_
+
+#define BCMA_CC_PROG_WAITCNT 0x0124
+#define BCMA_CC_FLASH_CFG 0x0128
+#define BCMA_CC_FLASH_WAITCNT 0x012C
-+#define BCMA_CC_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */
-+#define BCMA_CC_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
-+#define BCMA_CC_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
-+#define BCMA_CC_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
-+#define BCMA_CC_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
-+#define BCMA_CC_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
-+#define BCMA_CC_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
-+#define BCMA_CC_CLKCTLST_HAVEHT 0x00010000 /* HT available */
-+#define BCMA_CC_CLKCTLST_HAVEALP 0x00020000 /* APL available */
++/* 0x1E0 is defined as shared BCMA_CLKCTLST */
+#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
+#define BCMA_CC_UART0_DATA 0x0300
+#define BCMA_CC_UART0_IMR 0x0304
+#define BCMA_CC_REGCTL_DATA 0x065C
+#define BCMA_CC_PLLCTL_ADDR 0x0660
+#define BCMA_CC_PLLCTL_DATA 0x0664
-+#define BCMA_CC_SPROM 0x0830 /* SPROM beginning */
++#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
++#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
+
+/* Data for the PMU, if available.
+ * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+#endif /* LINUX_BCMA_DRIVER_PCI_H_ */
--- /dev/null
+++ b/include/linux/bcma/bcma_regs.h
-@@ -0,0 +1,34 @@
+@@ -0,0 +1,59 @@
+#ifndef LINUX_BCMA_REGS_H_
+#define LINUX_BCMA_REGS_H_
+
++/* Some single registers are shared between many cores */
++/* BCMA_CLKCTLST: ChipCommon (rev >= 20), PCIe, 80211 */
++#define BCMA_CLKCTLST 0x01E0 /* Clock control and status */
++#define BCMA_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
++#define BCMA_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
++#define BCMA_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
++#define BCMA_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
++#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
++#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
++#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */
++#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */
++#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */
++#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */
++#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */
++#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */
++/* Is there any BCM4328 on BCMA bus? */
++#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */
++#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
++
+/* Agent registers (common for every core) */
-+#define BCMA_IOCTL 0x0408
++#define BCMA_IOCTL 0x0408 /* IO control */
+#define BCMA_IOCTL_CLK 0x0001
+#define BCMA_IOCTL_FGC 0x0002
+#define BCMA_IOCTL_CORE_BITS 0x3FFC
+#define BCMA_IOCTL_PME_EN 0x4000
+#define BCMA_IOCTL_BIST_EN 0x8000
++#define BCMA_IOST 0x0500 /* IO status */
++#define BCMA_IOST_CORE_BITS 0x0FFF
++#define BCMA_IOST_DMA64 0x1000
++#define BCMA_IOST_GATED_CLK 0x2000
++#define BCMA_IOST_BIST_ERROR 0x4000
++#define BCMA_IOST_BIST_DONE 0x8000
+#define BCMA_RESET_CTL 0x0800
+#define BCMA_RESET_CTL_RESET 0x0001
+
sizeof(struct virtio_device_id), "virtio",
--- /dev/null
+++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,162 @@
+@@ -0,0 +1,171 @@
+/*
+ * Broadcom specific AMBA
+ * SPROM reading
+ * R/W ops.
+ **************************************************/
+
-+static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom)
++static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
+{
+ int i;
+ for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+ sprom[i] = bcma_read16(bus->drv_cc.core,
-+ BCMA_CC_SPROM + (i * 2));
++ offset + (i * 2));
+}
+
+/**************************************************
+ return err;
+
+ revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
-+ if (revision != 8) {
++ if (revision != 8 && revision != 9) {
+ pr_err("Unsupported SPROM revision: %d\n", revision);
+ return -ENOENT;
+ }
+
+int bcma_sprom_get(struct bcma_bus *bus)
+{
++ u16 offset;
+ u16 *sprom;
+ int err = 0;
+
+ if (!bus->drv_cc.core)
+ return -EOPNOTSUPP;
+
++ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
++ return -ENOENT;
++
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL);
+ if (!sprom)
+ return -ENOMEM;
+
-+ bcma_sprom_read(bus, sprom);
++ /* 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 */
++ offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
++ BCMA_CC_SPROM_PCIE6;
++ bcma_sprom_read(bus, offset, sprom);
+
+ err = bcma_sprom_valid(sprom);
+ if (err)
+ kfree(sprom);
+ return err;
+}
+--- /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");
++}
static struct dentry *shmem_get_parent(struct dentry *child)
{
-@@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block
+@@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block
sb->s_magic = TMPFS_MAGIC;
sb->s_op = &shmem_ops;
sb->s_time_gran = 1;
config SSB_PCMCIAHOST_POSSIBLE
bool
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -17,6 +17,7 @@ config BCMA
+ config BCMA_BLOCKIO
+ bool
+ depends on BCMA
++ default y
+
+ config BCMA_HOST_PCI_POSSIBLE
+ bool
endif # BLOCK
-@@ -177,6 +176,10 @@ source "fs/hfsplus/Kconfig"
+@@ -193,6 +192,10 @@ source "fs/hfsplus/Kconfig"
source "fs/befs/Kconfig"
source "fs/bfs/Kconfig"
source "fs/efs/Kconfig"
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
+ 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);
+ }
+--- a/drivers/ssb/pci.c
++++ b/drivers/ssb/pci.c
+@@ -734,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,
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -53,8 +53,8 @@ static int ssb_pcihost_resume(struct pci
bus->chip_package = 0;
} else {
bus->chip_id = 0x4710;
+--- a/include/linux/ssb/ssb.h
++++ b/include/linux/ssb/ssb.h
+@@ -27,6 +27,8 @@ struct ssb_sprom {
+ u8 et1mdcport; /* MDIO for enet1 */
+ u8 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 {
+ struct ssb_boardinfo {
+ u16 vendor;
+ u16 type;
+- u16 rev;
++ u8 rev;
+ };
+
+
config BCMA_HOST_PCI_POSSIBLE
bool
depends on BCMA && PCI = y
+@@ -22,6 +27,12 @@ config BCMA_HOST_PCI
+ bool "Support for BCMA on PCI-host bus"
+ depends on BCMA_HOST_PCI_POSSIBLE
+
++config BCMA_DRIVER_PCI_HOSTMODE
++ bool "Driver for PCI core working in hostmode"
++ depends on BCMA && MIPS
++ help
++ PCI core hostmode operation (external PCI bus).
++
+ config BCMA_DEBUG
+ bool "BCMA debugging"
+ depends on BCMA
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
-@@ -1,4 +1,4 @@
+@@ -1,6 +1,7 @@
-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_HOST_PCI) += host_pci.o
+ obj-$(CONFIG_BCMA) += bcma.o
+
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
-@@ -13,12 +13,15 @@
+@@ -13,16 +13,23 @@
struct bcma_bus;
/* main.c */
#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
extern int __init bcma_host_pci_init(void);
+ extern void __exit bcma_host_pci_exit(void);
+ #endif /* CONFIG_BCMA_HOST_PCI */
+
++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
++void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
++#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
++
+ #endif
--- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c
@@ -19,7 +19,7 @@ bool bcma_core_is_enabled(struct bcma_de
int bcma_core_enable(struct bcma_device *core, u32 flags)
{
+@@ -49,3 +50,75 @@ int bcma_core_enable(struct bcma_device
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(bcma_core_enable);
++
++void bcma_core_set_clockmode(struct bcma_device *core,
++ enum bcma_clkmode clkmode)
++{
++ u16 i;
++
++ WARN_ON(core->id.id != BCMA_CORE_CHIPCOMMON &&
++ core->id.id != BCMA_CORE_PCIE &&
++ core->id.id != BCMA_CORE_80211);
++
++ switch (clkmode) {
++ case BCMA_CLKMODE_FAST:
++ bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
++ udelay(64);
++ for (i = 0; i < 1500; i++) {
++ if (bcma_read32(core, BCMA_CLKCTLST) &
++ BCMA_CLKCTLST_HAVEHT) {
++ i = 0;
++ break;
++ }
++ udelay(10);
++ }
++ if (i)
++ pr_err("HT force timeout\n");
++ break;
++ case BCMA_CLKMODE_DYNAMIC:
++ pr_warn("Dynamic clockmode not supported yet!\n");
++ break;
++ }
++}
++EXPORT_SYMBOL_GPL(bcma_core_set_clockmode);
++
++void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
++{
++ u16 i;
++
++ WARN_ON(req & ~BCMA_CLKCTLST_EXTRESREQ);
++ WARN_ON(status & ~BCMA_CLKCTLST_EXTRESST);
++
++ if (on) {
++ bcma_set32(core, BCMA_CLKCTLST, req);
++ for (i = 0; i < 10000; i++) {
++ if ((bcma_read32(core, BCMA_CLKCTLST) & status) ==
++ status) {
++ i = 0;
++ break;
++ }
++ udelay(10);
++ }
++ if (i)
++ pr_err("PLL enable timeout\n");
++ } else {
++ pr_warn("Disabling PLL not supported yet!\n");
++ }
++}
++EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
++
++u32 bcma_core_dma_translation(struct bcma_device *core)
++{
++ switch (core->bus->hosttype) {
++ case BCMA_HOSTTYPE_PCI:
++ if (bcma_aread32(core, BCMA_IOST) & BCMA_IOST_DMA64)
++ return BCMA_DMA_TRANSLATION_DMA64_CMT;
++ else
++ return BCMA_DMA_TRANSLATION_DMA32_CMT;
++ default:
++ pr_err("DMA translation unknown for host %d\n",
++ core->bus->hosttype);
++ }
++ return BCMA_DMA_TRANSLATION_NONE;
++}
++EXPORT_SYMBOL(bcma_core_dma_translation);
--- 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
bus->chipinfo.id);
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
-@@ -161,3 +161,27 @@ void bcma_core_pci_init(struct bcma_drv_
+@@ -157,7 +157,67 @@ static void bcma_pcicore_serdes_workarou
+ * Init.
+ **************************************************/
+
+-void bcma_core_pci_init(struct bcma_drv_pci *pc)
++static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{
bcma_pcicore_serdes_workaround(pc);
}
+
++static bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
++{
++ struct bcma_bus *bus = pc->core->bus;
++ u16 chipid_top;
++
++ chipid_top = (bus->chipinfo.id & 0xFF00);
++ if (chipid_top != 0x4700 &&
++ chipid_top != 0x5300)
++ return false;
++
++ if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
++ return false;
++
++#if 0
++ /* TODO: on BCMA we use address from EROM instead of magic formula */
++ u32 tmp;
++ return !mips_busprobe32(tmp, (bus->mmio +
++ (pc->core->core_index * BCMA_CORE_SIZE)));
++#endif
++
++ return true;
++}
++
++void bcma_core_pci_init(struct bcma_drv_pci *pc)
++{
++ if (bcma_core_pci_is_in_hostmode(pc)) {
++#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
++ bcma_core_pci_hostmode_init(pc);
++#else
++ pr_err("Driver compiled without support for hostmode PCI\n");
++#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
++ } else {
++ bcma_core_pci_clientmode_init(pc);
++ }
++}
++
+int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+ bool enable)
+{
break;
case BCMA_HOSTTYPE_NONE:
case BCMA_HOSTTYPE_SDIO:
-@@ -144,6 +147,13 @@ int bcma_bus_register(struct bcma_bus *b
+@@ -144,6 +147,15 @@ int bcma_bus_register(struct bcma_bus *b
bcma_core_pci_init(&bus->drv_pci);
}
+ /* Try to get SPROM */
+ err = bcma_sprom_get(bus);
-+ if (err) {
++ if (err == -ENOENT) {
++ pr_err("No SPROM available\n");
++ } else if (err) {
+ pr_err("Failed to get SPROM: %d\n", err);
+ return -ENOENT;
+ }
/* Register found cores */
bcma_register_cores(bus);
-@@ -151,13 +161,11 @@ int bcma_bus_register(struct bcma_bus *b
+@@ -151,13 +163,11 @@ int bcma_bus_register(struct bcma_bus *b
return 0;
}
{
--- /dev/null
+++ b/drivers/bcma/sprom.c
-@@ -0,0 +1,162 @@
+@@ -0,0 +1,171 @@
+/*
+ * Broadcom specific AMBA
+ * SPROM reading
+ * R/W ops.
+ **************************************************/
+
-+static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom)
++static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
+{
+ int i;
+ for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+ sprom[i] = bcma_read16(bus->drv_cc.core,
-+ BCMA_CC_SPROM + (i * 2));
++ offset + (i * 2));
+}
+
+/**************************************************
+ return err;
+
+ revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
-+ if (revision != 8) {
++ if (revision != 8 && revision != 9) {
+ pr_err("Unsupported SPROM revision: %d\n", revision);
+ return -ENOENT;
+ }
+
+int bcma_sprom_get(struct bcma_bus *bus)
+{
++ u16 offset;
+ u16 *sprom;
+ int err = 0;
+
+ if (!bus->drv_cc.core)
+ return -EOPNOTSUPP;
+
++ if (!(bus->drv_cc.capabilities & BCMA_CC_CAP_SPROM))
++ return -ENOENT;
++
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL);
+ if (!sprom)
+ return -ENOMEM;
+
-+ bcma_sprom_read(bus, sprom);
++ /* 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 */
++ offset = (bus->chipinfo.id == 0x4331) ? BCMA_CC_SPROM :
++ BCMA_CC_SPROM_PCIE6;
++ bcma_sprom_read(bus, offset, sprom);
+
+ err = bcma_sprom_valid(sprom);
+ if (err)
#include "bcma_regs.h"
-@@ -31,6 +32,12 @@ struct bcma_host_ops {
+@@ -24,6 +25,11 @@ struct bcma_chipinfo {
+ u8 pkg;
+ };
+
++enum bcma_clkmode {
++ BCMA_CLKMODE_FAST,
++ BCMA_CLKMODE_DYNAMIC,
++};
++
+ 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 {
void (*write8)(struct bcma_device *core, u16 offset, u8 value);
void (*write16)(struct bcma_device *core, u16 offset, u16 value);
void (*write32)(struct bcma_device *core, u16 offset, u32 value);
/* Agent ops */
u32 (*aread32)(struct bcma_device *core, u16 offset);
void (*awrite32)(struct bcma_device *core, u16 offset, u32 value);
-@@ -117,6 +124,8 @@ struct bcma_device {
+@@ -117,6 +129,8 @@ struct bcma_device {
struct bcma_device_id id;
struct device dev;
bool dev_registered;
u8 core_index;
-@@ -179,6 +188,10 @@ struct bcma_bus {
+@@ -179,6 +193,10 @@ struct bcma_bus {
struct bcma_drv_cc drv_cc;
struct bcma_drv_pci drv_pci;
};
extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
-@@ -208,6 +221,18 @@ void bcma_write32(struct bcma_device *co
+@@ -208,6 +226,18 @@ void bcma_write32(struct bcma_device *co
{
core->bus->ops->write32(core, offset, value);
}
extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
{
return core->bus->ops->aread32(core, offset);
-@@ -219,6 +244,7 @@ void bcma_awrite32(struct bcma_device *c
+@@ -218,7 +248,24 @@ void bcma_awrite32(struct bcma_device *c
+ 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))
++
extern bool bcma_core_is_enabled(struct bcma_device *core);
+extern void bcma_core_disable(struct bcma_device *core, u32 flags);
extern int bcma_core_enable(struct bcma_device *core, u32 flags);
++extern void bcma_core_set_clockmode(struct bcma_device *core,
++ enum bcma_clkmode clkmode);
++extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
++ bool on);
++#define BCMA_DMA_TRANSLATION_MASK 0xC0000000
++#define BCMA_DMA_TRANSLATION_NONE 0x00000000
++#define BCMA_DMA_TRANSLATION_DMA32_CMT 0x40000000 /* Client Mode Translation for 32-bit DMA */
++#define BCMA_DMA_TRANSLATION_DMA64_CMT 0x80000000 /* Client Mode Translation for 64-bit DMA */
++extern u32 bcma_core_dma_translation(struct bcma_device *core);
#endif /* LINUX_BCMA_H_ */
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -244,6 +244,7 @@
+@@ -179,15 +179,7 @@
+ #define BCMA_CC_PROG_WAITCNT 0x0124
+ #define BCMA_CC_FLASH_CFG 0x0128
+ #define BCMA_CC_FLASH_WAITCNT 0x012C
+-#define BCMA_CC_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */
+-#define BCMA_CC_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
+-#define BCMA_CC_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
+-#define BCMA_CC_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
+-#define BCMA_CC_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
+-#define BCMA_CC_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
+-#define BCMA_CC_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
+-#define BCMA_CC_CLKCTLST_HAVEHT 0x00010000 /* HT available */
+-#define BCMA_CC_CLKCTLST_HAVEALP 0x00020000 /* APL available */
++/* 0x1E0 is defined as shared BCMA_CLKCTLST */
+ #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 @@
#define BCMA_CC_REGCTL_DATA 0x065C
#define BCMA_CC_PLLCTL_ADDR 0x0660
#define BCMA_CC_PLLCTL_DATA 0x0664
-+#define BCMA_CC_SPROM 0x0830 /* SPROM beginning */
++#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
++#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+ 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 @@
+ #ifndef LINUX_BCMA_REGS_H_
+ #define LINUX_BCMA_REGS_H_
+
++/* Some single registers are shared between many cores */
++/* BCMA_CLKCTLST: ChipCommon (rev >= 20), PCIe, 80211 */
++#define BCMA_CLKCTLST 0x01E0 /* Clock control and status */
++#define BCMA_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
++#define BCMA_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
++#define BCMA_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
++#define BCMA_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
++#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
++#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
++#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */
++#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */
++#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */
++#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */
++#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */
++#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */
++/* Is there any BCM4328 on BCMA bus? */
++#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */
++#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */
++
+ /* Agent registers (common for every core) */
+-#define BCMA_IOCTL 0x0408
++#define BCMA_IOCTL 0x0408 /* IO control */
+ #define BCMA_IOCTL_CLK 0x0001
+ #define BCMA_IOCTL_FGC 0x0002
+ #define BCMA_IOCTL_CORE_BITS 0x3FFC
+ #define BCMA_IOCTL_PME_EN 0x4000
+ #define BCMA_IOCTL_BIST_EN 0x8000
++#define BCMA_IOST 0x0500 /* IO status */
++#define BCMA_IOST_CORE_BITS 0x0FFF
++#define BCMA_IOST_DMA64 0x1000
++#define BCMA_IOST_GATED_CLK 0x2000
++#define BCMA_IOST_BIST_ERROR 0x4000
++#define BCMA_IOST_BIST_DONE 0x8000
+ #define BCMA_RESET_CTL 0x0800
+ #define BCMA_RESET_CTL_RESET 0x0001
+
config SSB_PCMCIAHOST_POSSIBLE
bool
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -17,6 +17,7 @@ config BCMA
+ config BCMA_BLOCKIO
+ bool
+ depends on BCMA
++ default y
+
+ config BCMA_HOST_PCI_POSSIBLE
+ bool