summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-10-25 14:33:47 +0000
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-10-25 14:33:47 +0000
commit288f3f6650cf72a566a2e582d0065f2b9d47858a (patch)
treebbbcac3fb6d358126698f3764c562345b210dc9c
parent3f93d0a04a77c8f800d9f2b4c47e6eec4ee9a870 (diff)
kernel: update bcma and ssb to master-2012-10-18 from wireless-testing
* update the flash driver for bcm47xx to use the stubs already in bcma * do some misc enhancements to the flash drivers for bcm47xx git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33920 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r--package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch48
-rw-r--r--target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch129
-rw-r--r--target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch505
-rw-r--r--target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch151
-rw-r--r--target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch573
-rw-r--r--target/linux/brcm47xx/patches-3.3/024-brcm47xx-add-common-interface-for-sflash.patch168
-rw-r--r--target/linux/brcm47xx/patches-3.3/028-bcm47xx-register-flash-drivers.patch136
-rw-r--r--target/linux/brcm47xx/patches-3.3/029-bcm47xx-read-nvram-from-sflash.patch143
-rw-r--r--target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch1146
-rw-r--r--target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch (renamed from target/linux/brcm47xx/patches-3.3/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch)0
-rw-r--r--target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch (renamed from target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch)48
-rw-r--r--target/linux/brcm47xx/patches-3.3/052-mtd-add-serial-flash-driver.patch (renamed from target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch)60
-rw-r--r--target/linux/brcm47xx/patches-3.3/053-mtd-add-nand-flash-driver.patch710
-rw-r--r--target/linux/brcm47xx/patches-3.3/060-ssb-add-serial-flash-driver.patch527
-rw-r--r--target/linux/brcm47xx/patches-3.3/061-ssb-register-parallel-flash-device.patch76
-rw-r--r--target/linux/brcm47xx/patches-3.3/070-bcma-add-functions-to-write-to-serial-flash.patch345
-rw-r--r--target/linux/brcm47xx/patches-3.3/071-bcma-add-functions-to-write-to-nand-flash.patch232
-rw-r--r--target/linux/brcm47xx/patches-3.3/072-bcma-register-parallel-flash-device.patch67
-rw-r--r--target/linux/brcm47xx/patches-3.3/080-MIPS-BCM47XX-rewrite-nvram-probing.patch183
-rw-r--r--target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch10
-rw-r--r--target/linux/brcm47xx/patches-3.3/194-MIPS-BCM47XX-read-sprom-without-prefix-if-no-ieee802.patch2
-rw-r--r--target/linux/brcm47xx/patches-3.3/195-MIPS-BCM47xx-sprom-read-values-without-prefix-as-fal.patch6
-rw-r--r--target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch181
-rw-r--r--target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch37
-rw-r--r--target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch26
-rw-r--r--target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch8
-rw-r--r--target/linux/brcm47xx/patches-3.3/400-arch-bcm47xx.patch2
-rw-r--r--target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch4
-rw-r--r--target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch4
-rw-r--r--target/linux/brcm47xx/patches-3.3/812-disable_wgt634u_crap.patch16
-rw-r--r--target/linux/brcm47xx/patches-3.3/820-wgt634u-nvram-fix.patch26
-rw-r--r--target/linux/brcm47xx/patches-3.3/980-wnr834b_no_cardbus_invariant.patch2
-rw-r--r--target/linux/brcm47xx/patches-3.3/999-wl_exports.patch6
-rw-r--r--target/linux/generic/patches-3.3/020-ssb_update.patch82
-rw-r--r--target/linux/generic/patches-3.3/025-bcma_backport.patch1249
-rw-r--r--target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch29
-rw-r--r--target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch55
-rw-r--r--target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch29
-rw-r--r--target/linux/generic/patches-3.3/029-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch15
-rw-r--r--target/linux/generic/patches-3.6/020-ssb_update.patch82
-rw-r--r--target/linux/generic/patches-3.6/025-bcma_backport.patch1035
41 files changed, 4589 insertions, 3564 deletions
diff --git a/package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch b/package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch
new file mode 100644
index 000000000..6d4c1d8b8
--- /dev/null
+++ b/package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch
@@ -0,0 +1,48 @@
+diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
+index 73730e9..7358ea2 100644
+--- a/drivers/net/wireless/b43/main.c
++++ b/drivers/net/wireless/b43/main.c
+@@ -4652,7 +4652,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
+ switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+ case B43_BUS_BCMA:
+- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci,
++ bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0],
+ dev->dev->bdev, true);
+ break;
+ #endif
+diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+index b89f127..de96290 100644
+--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+@@ -692,7 +692,7 @@ void ai_pci_up(struct si_pub *sih)
+ sii = container_of(sih, struct si_info, pub);
+
+ if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
+- bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
++ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], true);
+ }
+
+ /* Unconfigure and/or apply various WARs when going down */
+@@ -703,7 +703,7 @@ void ai_pci_down(struct si_pub *sih)
+ sii = container_of(sih, struct si_info, pub);
+
+ if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI)
+- bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
++ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], false);
+ }
+
+ /* Enable BT-COEX & Ex-PA for 4313 */
+diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+index 75086b3..565c15a 100644
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -5077,7 +5077,7 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
+ * Configure pci/pcmcia here instead of in brcms_c_attach()
+ * to allow mfg hotswap: down, hotswap (chip power cycle), up.
+ */
+- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
++ bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core,
+ true);
+
+ /*
diff --git a/target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch b/target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch
deleted file mode 100644
index 98c855fbd..000000000
--- a/target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch
+++ /dev/null
@@ -1,129 +0,0 @@
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -50,6 +50,9 @@ static void early_nvram_init(void)
- #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;
-+
- base = bcma_cc->pflash.window;
- lim = bcma_cc->pflash.window_size;
- break;
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -189,6 +189,7 @@ static void bcma_core_mips_flash_detect(
- break;
- case BCMA_CC_FLASHT_PARA:
- bcma_info(bus, "found parallel flash.\n");
-+ bus->drv_cc.flash_type = BCMA_PFLASH;
- bus->drv_cc.pflash.window = 0x1c000000;
- bus->drv_cc.pflash.window_size = 0x02000000;
-
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -122,10 +122,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 */
-@@ -360,6 +418,12 @@
- /* 4313 Chip specific ChipControl register bits */
- #define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
-
-+#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)
- */
-@@ -369,6 +433,10 @@ struct bcma_chipcommon_pmu {
- };
-
- #ifdef CONFIG_BCMA_DRIVER_MIPS
-+enum bcma_flash_type {
-+ BCMA_PFLASH,
-+};
-+
- struct bcma_pflash {
- u8 buswidth;
- u32 window;
-@@ -394,7 +462,10 @@ 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 {
-+ struct bcma_pflash pflash;
-+ };
-
- int nr_serial_ports;
- struct bcma_serial_port serial_ports[4];
diff --git a/target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch b/target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch
deleted file mode 100644
index 7382636b3..000000000
--- a/target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch
+++ /dev/null
@@ -1,505 +0,0 @@
---- 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
-@@ -51,6 +51,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,398 @@
-+/*
-+ * Broadcom SiliconBackplane chipcommon serial flash interface
-+ *
-+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
-+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
-+ * 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->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->sflash.blocksize = 64 * 1024;
-+ switch (id) {
-+ case 0x11:
-+ /* ST M25P20 2 Mbit Serial Flash */
-+ cc->sflash.numblocks = 4;
-+ break;
-+ case 0x12:
-+ /* ST M25P40 4 Mbit Serial Flash */
-+ cc->sflash.numblocks = 8;
-+ break;
-+ case 0x13:
-+ /* ST M25P80 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 0x14:
-+ /* ST M25P16 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 0x15:
-+ /* ST M25P32 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 64;
-+ break;
-+ case 0x16:
-+ /* ST M25P64 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 128;
-+ break;
-+ case 0x17:
-+ /* ST M25FL128 128 Mbit Serial Flash */
-+ cc->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->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->sflash.numblocks = 16;
-+ break;
-+ case 2:
-+ /* SST25WF010 1 Mbit Serial Flash */
-+ case 0x49:
-+ /* SST25VF010 1 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 3:
-+ /* SST25WF020 2 Mbit Serial Flash */
-+ case 0x43:
-+ /* SST25VF020 2 Mbit Serial Flash */
-+ cc->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->sflash.numblocks = 128;
-+ break;
-+ case 5:
-+ /* SST25WF080 8 Mbit Serial Flash */
-+ case 0x8e:
-+ /* SST25VF080B 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 256;
-+ break;
-+ case 0x41:
-+ /* SST25VF016 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x4a:
-+ /* SST25VF032 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x4b:
-+ /* SST25VF064 64 Mbit Serial Flash */
-+ cc->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->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x14:
-+ /* Atmel AT45DB021 2Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x1c:
-+ /* Atmel AT45DB041 4Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ case 0x24:
-+ /* Atmel AT45DB081 8Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x2c:
-+ /* Atmel AT45DB161 16Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x34:
-+ /* Atmel AT45DB321 32Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ case 0x3c:
-+ /* Atmel AT45DB642 64Mbit Serial Flash */
-+ cc->sflash.blocksize = 1024;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ }
-+ break;
-+ }
-+
-+ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
-+
-+ return cc->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->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;
-+
-+ 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->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)
-+{
-+ int written = 1;
-+
-+ /* Enable writes */
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
-+ 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);
-+ 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 written;
-+ } else {
-+ /* Write single byte */
-+ bcma_sflash_cmd(cc,
-+ BCMA_CC_FLASHCTL_ST_CSA |
-+ *buf++);
-+ }
-+ written++;
-+ 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;
-+ }
-+ return written;
-+}
-+
-+static int sflash_at_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct bcma_sflash *sfl = &cc->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->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->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) {
-+ bcma_info(cc->core->bus, "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->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->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.
-+ */
-+ if (sfl->blocksize < (64 * 1024))
-+ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SSE);
-+ else
-+ bcma_sflash_cmd(cc, 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;
-+}
---- 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:
-- bcma_err(bus, "Serial flash not supported.\n");
-+#ifdef CONFIG_BCMA_SFLASH
-+ bcma_info(bus, "found serial flash.\n");
-+ bus->drv_cc.flash_type = BCMA_SFLASH;
-+ bcma_sflash_init(&bus->drv_cc);
-+#else
-+ bcma_info(bus, "serial flash not supported.\n");
-+#endif /* CONFIG_BCMA_SFLASH */
- break;
- case BCMA_CC_FLASHT_PARA:
- bcma_info(bus, "found parallel flash.\n");
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -435,6 +435,7 @@ struct bcma_chipcommon_pmu {
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- enum bcma_flash_type {
- BCMA_PFLASH,
-+ BCMA_SFLASH,
- };
-
- struct bcma_pflash {
-@@ -443,6 +444,14 @@ 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 */
-+
- struct bcma_serial_port {
- void *regs;
- unsigned long clockspeed;
-@@ -465,6 +474,9 @@ struct bcma_drv_cc {
- enum bcma_flash_type flash_type;
- union {
- struct bcma_pflash pflash;
-+#ifdef CONFIG_BCMA_SFLASH
-+ struct bcma_sflash sflash;
-+#endif /* CONFIG_BCMA_SFLASH */
- };
-
- int nr_serial_ports;
-@@ -520,4 +532,14 @@ extern void bcma_chipco_regctl_maskset(s
- u32 offset, u32 mask, u32 set);
- extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
-
-+#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);
-+#endif /* CONFIG_BCMA_SFLASH */
-+
- #endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch b/target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch
deleted file mode 100644
index 12055bff0..000000000
--- a/target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch
+++ /dev/null
@@ -1,151 +0,0 @@
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -27,7 +27,7 @@ static char nvram_buf[NVRAM_SPACE];
- static void early_nvram_init(void)
- {
- #ifdef CONFIG_BCM47XX_SSB
-- struct ssb_mipscore *mcore_ssb;
-+ struct ssb_chipcommon *ssb_cc;
- #endif
- #ifdef CONFIG_BCM47XX_BCMA
- struct bcma_drv_cc *bcma_cc;
-@@ -42,9 +42,9 @@ static void early_nvram_init(void)
- switch (bcm47xx_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;
-+ ssb_cc = &bcm47xx_bus.ssb.chipco;
-+ base = ssb_cc->pflash.window;
-+ lim = ssb_cc->pflash.window_size;
- break;
- #endif
- #ifdef CONFIG_BCM47XX_BCMA
---- a/arch/mips/bcm47xx/wgt634u.c
-+++ b/arch/mips/bcm47xx/wgt634u.c
-@@ -142,24 +142,24 @@ static int __init wgt634u_init(void)
- if (et0mac[0] == 0x00 &&
- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
- (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
-- struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
-+ struct ssb_chipcommon *ccore = &bcm47xx_bus.ssb.chipco;
-
- printk(KERN_INFO "WGT634U machine detected.\n");
-
- if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
- gpio_interrupt, IRQF_SHARED,
-- "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
-+ "WGT634U GPIO", ccore)) {
- gpio_direction_input(WGT634U_GPIO_RESET);
- gpio_intmask(WGT634U_GPIO_RESET, 1);
-- ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
-+ ssb_chipco_irq_mask(ccore,
- SSB_CHIPCO_IRQ_GPIO,
- SSB_CHIPCO_IRQ_GPIO);
- }
-
-- wgt634u_flash_data.width = mcore->flash_buswidth;
-- wgt634u_flash_resource.start = mcore->flash_window;
-- wgt634u_flash_resource.end = mcore->flash_window
-- + mcore->flash_window_size
-+ wgt634u_flash_data.width = ccore->pflash.buswidth;
-+ wgt634u_flash_resource.start = ccore->pflash.window;
-+ wgt634u_flash_resource.end = ccore->pflash.window
-+ + ccore->pflash.window_size
- - 1;
- return platform_add_devices(wgt634u_devices,
- ARRAY_SIZE(wgt634u_devices));
---- a/drivers/ssb/driver_mipscore.c
-+++ b/drivers/ssb/driver_mipscore.c
-@@ -190,16 +190,34 @@ static void ssb_mips_flash_detect(struct
- {
- struct ssb_bus *bus = mcore->dev->bus;
-
-- mcore->flash_buswidth = 2;
-- if (bus->chipco.dev) {
-- mcore->flash_window = 0x1c000000;
-- mcore->flash_window_size = 0x02000000;
-+ /* When there is no chipcommon on the bus there is 4MB flash */
-+ if (!bus->chipco.dev) {
-+ pr_info("found parallel flash.\n");
-+ bus->chipco.flash_type = SSB_PFLASH;
-+ bus->chipco.pflash.window = SSB_FLASH1;
-+ bus->chipco.pflash.window_size = SSB_FLASH1_SZ;
-+ bus->chipco.pflash.buswidth = 2;
-+ return;
-+ }
-+
-+ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ pr_info("serial flash not supported.\n");
-+ break;
-+ case SSB_CHIPCO_FLASHT_PARA:
-+ pr_info("found parallel flash.\n");
-+ bus->chipco.flash_type = SSB_PFLASH;
-+ bus->chipco.pflash.window = SSB_FLASH2;
-+ bus->chipco.pflash.window_size = SSB_FLASH2_SZ;
- if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
-- & SSB_CHIPCO_CFG_DS16) == 0)
-- mcore->flash_buswidth = 1;
-- } else {
-- mcore->flash_window = 0x1fc00000;
-- mcore->flash_window_size = 0x00400000;
-+ & SSB_CHIPCO_CFG_DS16) == 0)
-+ bus->chipco.pflash.buswidth = 1;
-+ else
-+ bus->chipco.pflash.buswidth = 2;
-+ break;
-+ default:
-+ pr_err("flash not supported.\n");
- }
- }
-
---- a/include/linux/ssb/ssb_driver_chipcommon.h
-+++ b/include/linux/ssb/ssb_driver_chipcommon.h
-@@ -582,6 +582,18 @@ struct ssb_chipcommon_pmu {
- u32 crystalfreq; /* The active crystal frequency (in kHz) */
- };
-
-+#ifdef CONFIG_SSB_DRIVER_MIPS
-+enum ssb_flash_type {
-+ SSB_PFLASH,
-+};
-+
-+struct ssb_pflash {
-+ u8 buswidth;
-+ u32 window;
-+ u32 window_size;
-+};
-+#endif /* CONFIG_SSB_DRIVER_MIPS */
-+
- struct ssb_chipcommon {
- struct ssb_device *dev;
- u32 capabilities;
-@@ -589,6 +601,12 @@ struct ssb_chipcommon {
- /* Fast Powerup Delay constant */
- u16 fast_pwrup_delay;
- struct ssb_chipcommon_pmu pmu;
-+#ifdef CONFIG_SSB_DRIVER_MIPS
-+ enum ssb_flash_type flash_type;
-+ union {
-+ struct ssb_pflash pflash;
-+ };
-+#endif /* CONFIG_SSB_DRIVER_MIPS */
- };
-
- static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
---- a/include/linux/ssb/ssb_driver_mips.h
-+++ b/include/linux/ssb/ssb_driver_mips.h
-@@ -19,10 +19,6 @@ struct ssb_mipscore {
-
- int nr_serial_ports;
- struct ssb_serial_port serial_ports[4];
--
-- u8 flash_buswidth;
-- u32 flash_window;
-- u32 flash_window_size;
- };
-
- extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
diff --git a/target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch b/target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch
deleted file mode 100644
index ba5a5c2d1..000000000
--- a/target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch
+++ /dev/null
@@ -1,573 +0,0 @@
---- a/drivers/ssb/Kconfig
-+++ b/drivers/ssb/Kconfig
-@@ -137,6 +137,12 @@ config SSB_DRIVER_MIPS
-
- If unsure, say N
-
-+config SSB_SFLASH
-+ bool
-+ depends on SSB_DRIVER_MIPS
-+ default y
-+
-+
- # Assumption: We are on embedded, if we compile the MIPS core.
- config SSB_EMBEDDED
- bool
---- a/drivers/ssb/Makefile
-+++ b/drivers/ssb/Makefile
-@@ -11,6 +11,7 @@ ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o
- # built-in drivers
- ssb-y += driver_chipcommon.o
- ssb-y += driver_chipcommon_pmu.o
-+ssb-$(CONFIG_SSB_SFLASH) += driver_chipcommon_sflash.o
- ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
- ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
- ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
---- /dev/null
-+++ b/drivers/ssb/driver_chipcommon_sflash.c
-@@ -0,0 +1,451 @@
-+/*
-+ * Broadcom SiliconBackplane chipcommon serial flash interface
-+ *
-+ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
-+ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
-+ * Copyright 2010, Broadcom Corporation
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include <linux/ssb/ssb.h>
-+#include <linux/ssb/ssb_driver_chipcommon.h>
-+#include <linux/delay.h>
-+
-+#include "ssb_private.h"
-+
-+#define NUM_RETRIES 3
-+
-+
-+/* Issue a serial flash command */
-+static inline void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
-+{
-+ chipco_write32(cc, SSB_CHIPCO_FLASHCTL,
-+ SSB_CHIPCO_FLASHCTL_START | opcode);
-+ while (chipco_read32(cc, SSB_CHIPCO_FLASHCTL)
-+ & SSB_CHIPCO_FLASHCTL_BUSY)
-+ ;
-+}
-+
-+
-+static inline void ssb_sflash_write_u8(struct ssb_chipcommon *cc,
-+ u32 offset, u8 byte)
-+{
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset);
-+ chipco_write32(cc, SSB_CHIPCO_FLASHDATA, byte);
-+}
-+
-+/* Initialize serial flash access */
-+int ssb_sflash_init(struct ssb_chipcommon *cc)
-+{
-+ u32 id, id2;
-+
-+ memset(&cc->sflash, 0, sizeof(struct ssb_sflash));
-+
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ /* Probe for ST chips */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_DP);
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 0);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
-+ id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
-+ cc->sflash.blocksize = 64 * 1024;
-+ switch (id) {
-+ case 0x11:
-+ /* ST M25P20 2 Mbit Serial Flash */
-+ cc->sflash.numblocks = 4;
-+ break;
-+ case 0x12:
-+ /* ST M25P40 4 Mbit Serial Flash */
-+ cc->sflash.numblocks = 8;
-+ break;
-+ case 0x13:
-+ /* ST M25P80 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 0x14:
-+ /* ST M25P16 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 0x15:
-+ /* ST M25P32 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 64;
-+ break;
-+ case 0x16:
-+ /* ST M25P64 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 128;
-+ break;
-+ case 0x17:
-+ /* ST M25FL128 128 Mbit Serial Flash */
-+ cc->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->sflash.blocksize = 4 * 1024;
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, 1);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RES);
-+ id2 = chipco_read32(cc, SSB_CHIPCO_FLASHDATA);
-+ switch (id2) {
-+ case 1:
-+ /* SST25WF512 512 Kbit Serial Flash */
-+ case 0x48:
-+ /* SST25VF512 512 Kbit Serial Flash */
-+ cc->sflash.numblocks = 16;
-+ break;
-+ case 2:
-+ /* SST25WF010 1 Mbit Serial Flash */
-+ case 0x49:
-+ /* SST25VF010 1 Mbit Serial Flash */
-+ cc->sflash.numblocks = 32;
-+ break;
-+ case 3:
-+ /* SST25WF020 2 Mbit Serial Flash */
-+ case 0x43:
-+ /* SST25VF020 2 Mbit Serial Flash */
-+ cc->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->sflash.numblocks = 128;
-+ break;
-+ case 5:
-+ /* SST25WF080 8 Mbit Serial Flash */
-+ case 0x8e:
-+ /* SST25VF080B 8 Mbit Serial Flash */
-+ cc->sflash.numblocks = 256;
-+ break;
-+ case 0x41:
-+ /* SST25VF016 16 Mbit Serial Flash */
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x4a:
-+ /* SST25VF032 32 Mbit Serial Flash */
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x4b:
-+ /* SST25VF064 64 Mbit Serial Flash */
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ }
-+ break;
-+ }
-+ break;
-+
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ /* Probe for Atmel chips */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
-+ id = chipco_read32(cc, SSB_CHIPCO_FLASHDATA) & 0x3c;
-+ switch (id) {
-+ case 0xc:
-+ /* Atmel AT45DB011 1Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 512;
-+ break;
-+ case 0x14:
-+ /* Atmel AT45DB021 2Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 1024;
-+ break;
-+ case 0x1c:
-+ /* Atmel AT45DB041 4Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 2048;
-+ break;
-+ case 0x24:
-+ /* Atmel AT45DB081 8Mbit Serial Flash */
-+ cc->sflash.blocksize = 256;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x2c:
-+ /* Atmel AT45DB161 16Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 4096;
-+ break;
-+ case 0x34:
-+ /* Atmel AT45DB321 32Mbit Serial Flash */
-+ cc->sflash.blocksize = 512;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ case 0x3c:
-+ /* Atmel AT45DB642 64Mbit Serial Flash */
-+ cc->sflash.blocksize = 1024;
-+ cc->sflash.numblocks = 8192;
-+ break;
-+ }
-+ break;
-+ }
-+
-+ cc->sflash.size = cc->sflash.blocksize * cc->sflash.numblocks;
-+
-+ return cc->sflash.size ? 0 : -ENODEV;
-+}
-+
-+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
-+int ssb_sflash_read(struct ssb_chipcommon *cc, u32 offset, u32 len, u8 *buf)
-+{
-+ u8 *from, *to;
-+ u32 cnt, i;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > cc->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->dev->id.revision == 12)
-+ from = (u8 *)KSEG1ADDR(SSB_FLASH2 + offset);
-+ else
-+ from = (u8 *)KSEG0ADDR(SSB_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 ssb_sflash_poll(struct ssb_chipcommon *cc, u32 offset)
-+{
-+ if (offset >= cc->sflash.size)
-+ return -22;
-+
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ /* Check for ST Write In Progress bit */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_RDSR);
-+ return chipco_read32(cc, SSB_CHIPCO_FLASHDATA)
-+ & SSB_CHIPCO_FLASHSTA_ST_WIP;
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ /* Check for Atmel Ready bit */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_STATUS);
-+ return !(chipco_read32(cc, SSB_CHIPCO_FLASHDATA)
-+ & SSB_CHIPCO_FLASHSTA_AT_READY);
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int sflash_st_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_bus *bus = cc->dev->bus;
-+ int ret = 0;
-+ bool is4712b0 = (bus->chip_id == 0x4712) && (bus->chip_rev == 3);
-+ u32 mask;
-+
-+ /* Enable writes */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_WREN);
-+ if (is4712b0) {
-+ mask = 1 << 14;
-+ ssb_sflash_write_u8(cc, offset, *buf++);
-+ /* Set chip select */
-+ chipco_set32(cc, SSB_CHIPCO_GPIOOUT, mask);
-+ /* Issue a page program with the first byte */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, drop cs and return */
-+ chipco_mask32(cc, SSB_CHIPCO_GPIOOUT, ~mask);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ ssb_sflash_cmd(cc, *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs */
-+ chipco_mask32(cc, SSB_CHIPCO_GPIOOUT, ~mask);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ } else if (cc->dev->id.revision >= 20) {
-+ ssb_sflash_write_u8(cc, offset, *buf++);
-+ /* Issue a page program with CSA bit set */
-+ ssb_sflash_cmd(cc,
-+ SSB_CHIPCO_FLASHCTL_ST_CSA |
-+ SSB_CHIPCO_FLASHCTL_ST_PP);
-+ ret = 1;
-+ offset++;
-+ len--;
-+ while (len > 0) {
-+ if ((offset & 255) == 0) {
-+ /* Page boundary, poll droping cs and return */
-+ chipco_write32(cc, SSB_CHIPCO_FLASHCTL, 0);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ return ret;
-+ } else {
-+ /* Write single byte */
-+ ssb_sflash_cmd(cc,
-+ SSB_CHIPCO_FLASHCTL_ST_CSA |
-+ *buf++);
-+ }
-+ ret++;
-+ offset++;
-+ len--;
-+ }
-+ /* All done, drop cs & poll */
-+ chipco_write32(cc, SSB_CHIPCO_FLASHCTL, 0);
-+ udelay(1);
-+ if (!ssb_sflash_poll(cc, offset)) {
-+ /* Flash rejected command */
-+ return -EAGAIN;
-+ }
-+ } else {
-+ ret = 1;
-+ ssb_sflash_write_u8(cc, offset, *buf);
-+ /* Page program */
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_PP);
-+ }
-+ return ret;
-+}
-+
-+static int sflash_at_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_sflash *sfl = &cc->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;
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, page);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD);
-+ /* 250 us for AT45DB321B */
-+ while (i > 0 && ssb_sflash_poll(cc, offset)) {
-+ udelay(10);
-+ i--;
-+ }
-+ BUG_ON(!ssb_sflash_poll(cc, offset));
-+ }
-+ /* Write into buffer 1 */
-+ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
-+ ssb_sflash_write_u8(cc, byte++, *buf++);
-+ ssb_sflash_cmd(cc,
-+ SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE);
-+ }
-+ /* Write buffer 1 into main memory page */
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, page);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_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 ssb_sflash_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ struct ssb_sflash *sfl;
-+ int ret = 0, tries = NUM_RETRIES;
-+
-+ if (!len)
-+ return 0;
-+
-+ if ((offset + len) > cc->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->sflash;
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_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 SSB_CHIPCO_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 ssb_sflash_erase(struct ssb_chipcommon *cc, u32 offset)
-+{
-+ struct ssb_sflash *sfl;
-+
-+ if (offset >= cc->sflash.size)
-+ return -EINVAL;
-+
-+ sfl = &cc->sflash;
-+ switch (cc->capabilities & SSB_CHIPCO_CAP_FLASHT) {
-+ case SSB_CHIPCO_FLASHT_STSER:
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_WREN);
-+ chipco_write32(cc, SSB_CHIPCO_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.
-+ */
-+ if (sfl->blocksize < (64 * 1024))
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_SSE);
-+ else
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_ST_SE);
-+ return sfl->blocksize;
-+ case SSB_CHIPCO_FLASHT_ATSER:
-+ chipco_write32(cc, SSB_CHIPCO_FLASHADDR, offset << 1);
-+ ssb_sflash_cmd(cc, SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE);
-+ return sfl->blocksize;
-+ }
-+
-+ return 0;
-+}
---- a/drivers/ssb/driver_mipscore.c
-+++ b/drivers/ssb/driver_mipscore.c
-@@ -203,7 +203,13 @@ static void ssb_mips_flash_detect(struct
- switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
- case SSB_CHIPCO_FLASHT_STSER:
- case SSB_CHIPCO_FLASHT_ATSER:
-+#ifdef CONFIG_SSB_SFLASH
-+ pr_info("found serial flash.\n");
-+ bus->chipco.flash_type = SSB_SFLASH;
-+ ssb_sflash_init(&bus->chipco);
-+#else
- pr_info("serial flash not supported.\n");
-+#endif /* CONFIG_SSB_SFLASH */
- break;
- case SSB_CHIPCO_FLASHT_PARA:
- pr_info("found parallel flash.\n");
---- a/drivers/ssb/ssb_private.h
-+++ b/drivers/ssb/ssb_private.h
-@@ -192,6 +192,10 @@ extern int ssb_devices_freeze(struct ssb
- extern int ssb_devices_thaw(struct ssb_freeze_context *ctx);
-
-
-+#ifdef CONFIG_SSB_SFLASH
-+/* driver_chipcommon_sflash.c */
-+int ssb_sflash_init(struct ssb_chipcommon *cc);
-+#endif /* CONFIG_SSB_SFLASH */
-
- /* b43_pci_bridge.c */
- #ifdef CONFIG_SSB_B43_PCI_BRIDGE
---- a/include/linux/ssb/ssb_driver_chipcommon.h
-+++ b/include/linux/ssb/ssb_driver_chipcommon.h
-@@ -503,8 +503,10 @@
- #define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
- #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
- #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
--#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
--#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
-+#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00D9 /* Deep Power-down */
-+#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
-+#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
-+#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
-
- /* Status register bits for ST flashes */
- #define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
-@@ -585,6 +587,7 @@ struct ssb_chipcommon_pmu {
- #ifdef CONFIG_SSB_DRIVER_MIPS
- enum ssb_flash_type {
- SSB_PFLASH,
-+ SSB_SFLASH,
- };
-
- struct ssb_pflash {
-@@ -592,6 +595,14 @@ struct ssb_pflash {
- u32 window;
- u32 window_size;
- };
-+
-+#ifdef CONFIG_SSB_SFLASH
-+struct ssb_sflash {
-+ u32 blocksize; /* Block size */
-+ u32 numblocks; /* Number of blocks */
-+ u32 size; /* Total size in bytes */
-+};
-+#endif /* CONFIG_SSB_SFLASH */
- #endif /* CONFIG_SSB_DRIVER_MIPS */
-
- struct ssb_chipcommon {
-@@ -605,6 +616,9 @@ struct ssb_chipcommon {
- enum ssb_flash_type flash_type;
- union {
- struct ssb_pflash pflash;
-+#ifdef CONFIG_SSB_SFLASH
-+ struct ssb_sflash sflash;
-+#endif /* CONFIG_SSB_SFLASH */
- };
- #endif /* CONFIG_SSB_DRIVER_MIPS */
- };
-@@ -666,6 +680,16 @@ extern int ssb_chipco_serial_init(struct
- struct ssb_serial_port *ports);
- #endif /* CONFIG_SSB_SERIAL */
-
-+#ifdef CONFIG_SSB_SFLASH
-+/* Chipcommon sflash support. */
-+int ssb_sflash_read(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ u8 *buf);
-+int ssb_sflash_poll(struct ssb_chipcommon *cc, u32 offset);
-+int ssb_sflash_write(struct ssb_chipcommon *cc, u32 offset, u32 len,
-+ const u8 *buf);
-+int ssb_sflash_erase(struct ssb_chipcommon *cc, u32 offset);
-+#endif /* CONFIG_SSB_SFLASH */
-+
- /* PMU support */
- extern void ssb_pmu_init(struct ssb_chipcommon *cc);
-
diff --git a/target/linux/brcm47xx/patches-3.3/024-brcm47xx-add-common-interface-for-sflash.patch b/target/linux/brcm47xx/patches-3.3/024-brcm47xx-add-common-interface-for-sflash.patch
deleted file mode 100644
index fd4befcfa..000000000
--- a/target/linux/brcm47xx/patches-3.3/024-brcm47xx-add-common-interface-for-sflash.patch
+++ /dev/null
@@ -1,168 +0,0 @@
---- a/arch/mips/bcm47xx/Makefile
-+++ b/arch/mips/bcm47xx/Makefile
-@@ -3,5 +3,5 @@
- # under Linux.
- #
-
--obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
-+obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o bus.o
- obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
---- /dev/null
-+++ b/arch/mips/bcm47xx/bus.c
-@@ -0,0 +1,86 @@
-+/*
-+ * BCM947xx nvram variable access
-+ *
-+ * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * 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.
-+ */
-+
-+#include <bus.h>
-+
-+#ifdef CONFIG_BCM47XX_BCMA
-+static int bcm47xx_sflash_bcma_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
-+{
-+ return bcma_sflash_read(dev->bcc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_bcma_poll(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return bcma_sflash_poll(dev->bcc, offset);
-+}
-+
-+static int bcm47xx_sflash_bcma_write(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
-+{
-+ return bcma_sflash_write(dev->bcc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_bcma_erase(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return bcma_sflash_erase(dev->bcc, offset);
-+}
-+
-+void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc)
-+{
-+ sflash->sflash_type = BCM47XX_BUS_TYPE_BCMA;
-+ sflash->bcc = bcc;
-+
-+ sflash->read = bcm47xx_sflash_bcma_read;
-+ sflash->poll = bcm47xx_sflash_bcma_poll;
-+ sflash->write = bcm47xx_sflash_bcma_write;
-+ sflash->erase = bcm47xx_sflash_bcma_erase;
-+
-+ sflash->blocksize = bcc->sflash.blocksize;
-+ sflash->numblocks = bcc->sflash.numblocks;
-+ sflash->size = bcc->sflash.size;
-+}
-+#endif
-+
-+#ifdef CONFIG_BCM47XX_SSB
-+static int bcm47xx_sflash_ssb_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
-+{
-+ return ssb_sflash_read(dev->scc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_ssb_poll(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return ssb_sflash_poll(dev->scc, offset);
-+}
-+
-+static int bcm47xx_sflash_ssb_write(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf)
-+{
-+ return ssb_sflash_write(dev->scc, offset, len, buf);
-+}
-+
-+static int bcm47xx_sflash_ssb_erase(struct bcm47xx_sflash *dev, u32 offset)
-+{
-+ return ssb_sflash_erase(dev->scc, offset);
-+}
-+
-+void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc)
-+{
-+ sflash->sflash_type = BCM47XX_BUS_TYPE_SSB;
-+ sflash->scc = scc;
-+
-+ sflash->read = bcm47xx_sflash_ssb_read;
-+ sflash->poll = bcm47xx_sflash_ssb_poll;
-+ sflash->write = bcm47xx_sflash_ssb_write;
-+ sflash->erase = bcm47xx_sflash_ssb_erase;
-+
-+ sflash->blocksize = scc->sflash.blocksize;
-+ sflash->numblocks = scc->sflash.numblocks;
-+ sflash->size = scc->sflash.size;
-+}
-+#endif
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -43,6 +43,8 @@ EXPORT_SYMBOL(bcm47xx_bus);
- enum bcm47xx_bus_type bcm47xx_bus_type;
- EXPORT_SYMBOL(bcm47xx_bus_type);
-
-+struct bcm47xx_sflash bcm47xx_sflash;
-+
- static void bcm47xx_machine_restart(char *command)
- {
- printk(KERN_ALERT "Please stand by while rebooting the system...\n");
-@@ -137,6 +139,9 @@ static void __init bcm47xx_register_ssb(
- if (err)
- panic("Failed to initialize SSB bus (err %d)", err);
-
-+ if (bcm47xx_bus.ssb.chipco.flash_type == SSB_SFLASH)
-+ bcm47xx_sflash_struct_ssb_init(&bcm47xx_sflash, &bcm47xx_bus.ssb.chipco);
-+
- mcore = &bcm47xx_bus.ssb.mipscore;
- if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
- if (strstr(buf, "console=ttyS1")) {
-@@ -195,6 +200,9 @@ static void __init bcm47xx_register_bcma
- if (err)
- panic("Failed to initialize BCMA bus (err %d)", err);
-
-+ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH)
-+ bcm47xx_sflash_struct_bcma_init(&bcm47xx_sflash, &bcm47xx_bus.bcma.bus.drv_cc);
-+
- bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
- }
- #endif
---- /dev/null
-+++ b/arch/mips/include/asm/mach-bcm47xx/bus.h
-@@ -0,0 +1,36 @@
-+/*
-+ * BCM947xx nvram variable access
-+ *
-+ * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/ssb/ssb.h>
-+#include <linux/bcma/bcma.h>
-+#include <bcm47xx.h>
-+
-+struct bcm47xx_sflash {
-+ enum bcm47xx_bus_type sflash_type;
-+ union {
-+ struct ssb_chipcommon *scc;
-+ struct bcma_drv_cc *bcc;
-+ };
-+
-+ int (*read)(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf);
-+ int (*poll)(struct bcm47xx_sflash *dev, u32 offset);
-+ int (*write)(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf);
-+ int (*erase)(struct bcm47xx_sflash *dev, u32 offset);
-+
-+ u32 blocksize; /* Block size */
-+ u32 numblocks; /* Number of blocks */
-+ u32 size; /* Total size in bytes */
-+};
-+
-+void bcm47xx_sflash_struct_bcma_init(struct bcm47xx_sflash *sflash, struct bcma_drv_cc *bcc);
-+void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc);
-+
-+extern struct bcm47xx_sflash bcm47xx_sflash;
diff --git a/target/linux/brcm47xx/patches-3.3/028-bcm47xx-register-flash-drivers.patch b/target/linux/brcm47xx/patches-3.3/028-bcm47xx-register-flash-drivers.patch
deleted file mode 100644
index 7de051dad..000000000
--- a/target/linux/brcm47xx/patches-3.3/028-bcm47xx-register-flash-drivers.patch
+++ /dev/null
@@ -1,136 +0,0 @@
---- a/arch/mips/bcm47xx/Kconfig
-+++ b/arch/mips/bcm47xx/Kconfig
-@@ -9,6 +9,7 @@ config BCM47XX_SSB
- select SSB_EMBEDDED
- select SSB_B43_PCI_BRIDGE if PCI
- select SSB_PCICORE_HOSTMODE if PCI
-+ select SSB_SFLASH
- default y
- help
- Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
-@@ -23,6 +24,7 @@ config BCM47XX_BCMA
- select BCMA_DRIVER_MIPS
- select BCMA_HOST_PCI if PCI
- select BCMA_DRIVER_PCI_HOSTMODE if PCI
-+ select BCMA_SFLASH
- default y
- help
- Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -31,10 +31,12 @@
- #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>
- #include <bcm47xx.h>
-+#include <bus.h>
- #include <asm/mach-bcm47xx/nvram.h>
-
- union bcm47xx_bus bcm47xx_bus;
-@@ -45,6 +47,32 @@ EXPORT_SYMBOL(bcm47xx_bus_type);
-
- struct bcm47xx_sflash bcm47xx_sflash;
-
-+static struct resource bcm47xx_pflash_resource = {
-+ .name = "bcm47xx_pflash",
-+ .start = 0,
-+ .end = 0,
-+ .flags = 0,
-+};
-+
-+static struct platform_device bcm47xx_pflash_dev = {
-+ .name = "bcm47xx_pflash",
-+ .resource = &bcm47xx_pflash_resource,
-+ .num_resources = 1,
-+};
-+
-+static struct resource bcm47xx_sflash_resource = {
-+ .name = "bcm47xx_sflash",
-+ .start = 0,
-+ .end = 0,
-+ .flags = 0,
-+};
-+
-+static struct platform_device bcm47xx_sflash_dev = {
-+ .name = "bcm47xx_sflash",
-+ .resource = &bcm47xx_sflash_resource,
-+ .num_resources = 1,
-+};
-+
- static void bcm47xx_machine_restart(char *command)
- {
- printk(KERN_ALERT "Please stand by while rebooting the system...\n");
-@@ -156,6 +184,24 @@ static void __init bcm47xx_register_ssb(
- }
- }
- }
-+
-+static int __init bcm47xx_register_flash_ssb(void)
-+{
-+ struct ssb_chipcommon *chipco = &bcm47xx_bus.ssb.chipco;
-+
-+ switch (chipco->flash_type) {
-+ case SSB_PFLASH:
-+ bcm47xx_pflash_resource.start = chipco->pflash.window;
-+ bcm47xx_pflash_resource.end = chipco->pflash.window + chipco->pflash.window_size;
-+ return platform_device_register(&bcm47xx_pflash_dev);
-+ case SSB_SFLASH:
-+ bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
-+ return platform_device_register(&bcm47xx_sflash_dev);
-+ default:
-+ printk(KERN_ERR "No flash device found\n");
-+ return -1;
-+ }
-+}
- #endif
-
- #ifdef CONFIG_BCM47XX_BCMA
-@@ -205,6 +251,24 @@ static void __init bcm47xx_register_bcma
-
- bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
- }
-+
-+static int __init bcm47xx_register_flash_bcma(void)
-+{
-+ struct bcma_drv_cc *drv_cc = &bcm47xx_bus.bcma.bus.drv_cc;
-+
-+ switch (drv_cc->flash_type) {
-+ case BCMA_PFLASH:
-+ bcm47xx_pflash_resource.start = drv_cc->pflash.window;
-+ bcm47xx_pflash_resource.end = drv_cc->pflash.window + drv_cc->pflash.window_size;
-+ return platform_device_register(&bcm47xx_pflash_dev);
-+ case BCMA_SFLASH:
-+ bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
-+ return platform_device_register(&bcm47xx_sflash_dev);
-+ default:
-+ printk(KERN_ERR "No flash device found\n");
-+ return -1;
-+ }
-+}
- #endif
-
- void __init plat_mem_setup(void)
-@@ -247,3 +311,19 @@ static int __init bcm47xx_register_bus_c
- return 0;
- }
- device_initcall(bcm47xx_register_bus_complete);
-+
-+static int __init bcm47xx_register_flash(void)
-+{
-+ switch (bcm47xx_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ return bcm47xx_register_flash_ssb();
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ return bcm47xx_register_flash_bcma();
-+#endif
-+ }
-+ return -1;
-+}
-+fs_initcall(bcm47xx_register_flash);
diff --git a/target/linux/brcm47xx/patches-3.3/029-bcm47xx-read-nvram-from-sflash.patch b/target/linux/brcm47xx/patches-3.3/029-bcm47xx-read-nvram-from-sflash.patch
deleted file mode 100644
index 1a994d903..000000000
--- a/target/linux/brcm47xx/patches-3.3/029-bcm47xx-read-nvram-from-sflash.patch
+++ /dev/null
@@ -1,143 +0,0 @@
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -20,11 +20,12 @@
- #include <asm/addrspace.h>
- #include <asm/mach-bcm47xx/nvram.h>
- #include <asm/mach-bcm47xx/bcm47xx.h>
-+#include <asm/mach-bcm47xx/bus.h>
-
- static char nvram_buf[NVRAM_SPACE];
-
- /* Probe for NVRAM header */
--static void early_nvram_init(void)
-+static void early_nvram_init_pflash(void)
- {
- #ifdef CONFIG_BCM47XX_SSB
- struct ssb_chipcommon *ssb_cc;
-@@ -50,9 +51,6 @@ static void early_nvram_init(void)
- #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;
--
- base = bcma_cc->pflash.window;
- lim = bcma_cc->pflash.window_size;
- break;
-@@ -86,7 +84,115 @@ found:
- for (i = 0; i < sizeof(struct nvram_header); i += 4)
- *dst++ = *src++;
- for (; i < header->len && i < NVRAM_SPACE; i += 4)
-- *dst++ = le32_to_cpu(*src++);
-+ *dst++ = *src++;
-+}
-+
-+static int find_nvram_size(void)
-+{
-+ struct nvram_header header;
-+ int nvram_sizes[] = {NVRAM_SPACE, 0xF000, 2 * NVRAM_SPACE};
-+ int i;
-+ int ret;
-+
-+ for (i = 0; i < sizeof(nvram_sizes); i++) {
-+ ret = bcm47xx_sflash.read(&bcm47xx_sflash, bcm47xx_sflash.size - nvram_sizes[i], sizeof(header), (u8 *)&header);
-+ if (ret != sizeof(header))
-+ return ret;
-+ if (header.magic == NVRAM_HEADER)
-+ return nvram_sizes[i];
-+ }
-+ return -1;
-+}
-+
-+static int early_nvram_init_sflash(void)
-+{
-+ u32 off;
-+ int ret;
-+ char *dst;
-+ int len;
-+ int size;
-+
-+ /* check if the struct is already initilized */
-+ if (!bcm47xx_sflash.size)
-+ return -1;
-+
-+ size = find_nvram_size();
-+ if (size <= 0)
-+ return size;
-+
-+ len = NVRAM_SPACE;
-+ dst = nvram_buf;
-+ off = bcm47xx_sflash.size;
-+ if (size > len) {
-+ printk(KERN_WARNING "nvram on flash is bigger than the reserved"
-+ " space in memory, will just copy the first %i bytes\n",
-+ len);
-+ }
-+ while (len) {
-+ ret = bcm47xx_sflash.read(&bcm47xx_sflash, off - size, len, dst);
-+ if (ret < 0)
-+ return ret;
-+ off += ret;
-+ len -= ret;
-+ dst += ret;
-+ }
-+ return 0;
-+}
-+
-+#ifdef CONFIG_BCM47XX_SSB
-+static void early_nvram_init_ssb(void)
-+{
-+ int err;
-+
-+ switch (bcm47xx_bus.ssb.chipco.flash_type) {
-+ case SSB_PFLASH:
-+ early_nvram_init_pflash();
-+ break;
-+ case SSB_SFLASH:
-+ err = early_nvram_init_sflash();
-+ if (err < 0)
-+ printk(KERN_WARNING "can not read from flash: %i\n", err);
-+ break;
-+ default:
-+ printk(KERN_WARNING "unknow flash type\n");
-+ }
-+}
-+#endif
-+
-+#ifdef CONFIG_BCM47XX_BCMA
-+static void early_nvram_init_bcma(void)
-+{
-+ int err;
-+
-+ switch (bcm47xx_bus.bcma.bus.drv_cc.flash_type) {
-+ case BCMA_PFLASH:
-+ early_nvram_init_pflash();
-+ break;
-+ case BCMA_SFLASH:
-+ err = early_nvram_init_sflash();
-+ if (err < 0)
-+ printk(KERN_WARNING "can not read from flash: %i\n", err);
-+ break;
-+ default:
-+ printk(KERN_WARNING "unknow flash type\n");
-+ }
-+}
-+#endif
-+
-+static void early_nvram_init(void)
-+{
-+ switch (bcm47xx_bus_type) {
-+#ifdef CONFIG_BCM47XX_SSB
-+ case BCM47XX_BUS_TYPE_SSB:
-+ early_nvram_init_ssb();
-+ break;
-+#endif
-+#ifdef CONFIG_BCM47XX_BCMA
-+ case BCM47XX_BUS_TYPE_BCMA:
-+ early_nvram_init_bcma();
-+ break;
-+#endif
-+ }
- }
-
- int nvram_getenv(char *name, char *val, size_t val_len)
diff --git a/target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch b/target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch
deleted file mode 100644
index 53f6e98d1..000000000
--- a/target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch
+++ /dev/null
@@ -1,1146 +0,0 @@
---- a/arch/mips/bcm47xx/Kconfig
-+++ b/arch/mips/bcm47xx/Kconfig
-@@ -25,6 +25,7 @@ config BCM47XX_BCMA
- select BCMA_HOST_PCI if PCI
- select BCMA_DRIVER_PCI_HOSTMODE if PCI
- select BCMA_SFLASH
-+ select BCMA_NFLASH
- default y
- help
- Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
---- a/arch/mips/bcm47xx/bus.c
-+++ b/arch/mips/bcm47xx/bus.c
-@@ -2,6 +2,7 @@
- * BCM947xx nvram variable access
- *
- * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
- *
- * 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
-@@ -46,6 +47,12 @@ void bcm47xx_sflash_struct_bcma_init(str
- sflash->numblocks = bcc->sflash.numblocks;
- sflash->size = bcc->sflash.size;
- }
-+
-+void bcm47xx_nflash_struct_bcma_init(struct bcm47xx_nflash *nflash, struct bcma_drv_cc *bcc)
-+{
-+ nflash->nflash_type = BCM47XX_BUS_TYPE_BCMA;
-+ nflash->bcc = bcc;
-+}
- #endif
-
- #ifdef CONFIG_BCM47XX_SSB
---- a/arch/mips/bcm47xx/nvram.c
-+++ b/arch/mips/bcm47xx/nvram.c
-@@ -4,6 +4,7 @@
- * Copyright (C) 2005 Broadcom Corporation
- * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
- *
- * 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
-@@ -21,6 +22,7 @@
- #include <asm/mach-bcm47xx/nvram.h>
- #include <asm/mach-bcm47xx/bcm47xx.h>
- #include <asm/mach-bcm47xx/bus.h>
-+#include <linux/mtd/bcm47xx_nand.h>
-
- static char nvram_buf[NVRAM_SPACE];
-
-@@ -160,6 +162,51 @@ static void early_nvram_init_ssb(void)
- #endif
-
- #ifdef CONFIG_BCM47XX_BCMA
-+static int early_nvram_init_nflash(void)
-+{
-+ struct nvram_header *header;
-+ u32 off;
-+ int ret;
-+ int len;
-+ u32 flash_size = bcm47xx_nflash.size;
-+ u8 tmpbuf[NFL_SECTOR_SIZE];
-+ int i;
-+ u32 *src, *dst;
-+
-+ /* check if the struct is already initilized */
-+ if (!flash_size)
-+ return -1;
-+
-+ cfe_env = 0;
-+
-+ off = FLASH_MIN;
-+ while (off <= flash_size) {
-+ ret = bcma_nflash_read(bcm47xx_nflash.bcc, off, NFL_SECTOR_SIZE, tmpbuf);
-+ if (ret != NFL_SECTOR_SIZE)
-+ goto done;
-+ header = (struct nvram_header *)tmpbuf;
-+ if (header->magic == NVRAM_HEADER)
-+ goto found;
-+ off <<= 1;
-+ }
-+
-+ ret = -1;
-+ goto done;
-+
-+found:
-+ len = header->len;
-+ header = (struct nvram_header *) KSEG1ADDR(NAND_FLASH1 + off);
-+ src = (u32 *) header;
-+ dst = (u32 *) nvram_buf;
-+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
-+ *dst++ = *src++;
-+ for (; i < len && i < NVRAM_SPACE; i += 4)
-+ *dst++ = *src++;
-+ ret = 0;
-+done:
-+ return ret;
-+}
-+
- static void early_nvram_init_bcma(void)
- {
- int err;
-@@ -173,6 +220,11 @@ static void early_nvram_init_bcma(void)
- if (err < 0)
- printk(KERN_WARNING "can not read from flash: %i\n", err);
- break;
-+ case BCMA_NFLASH:
-+ err = early_nvram_init_nflash();
-+ if (err < 0)
-+ printk(KERN_WARNING "can not read from nflash: %i\n", err);
-+ break;
- default:
- printk(KERN_WARNING "unknow flash type\n");
- }
---- a/arch/mips/bcm47xx/setup.c
-+++ b/arch/mips/bcm47xx/setup.c
-@@ -4,6 +4,7 @@
- * Copyright (C) 2006 Michael Buesch <m@bues.ch>
- * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
- * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
- *
- * 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
-@@ -234,6 +235,21 @@ static int bcm47xx_get_sprom_bcma(struct
- }
- }
-
-+struct bcm47xx_nflash bcm47xx_nflash;
-+
-+static struct resource bcm47xx_nflash_resource = {
-+ .name = "bcm47xx_nflash",
-+ .start = 0,
-+ .end = 0,
-+ .flags = 0,
-+};
-+
-+static struct platform_device bcm47xx_nflash_dev = {
-+ .name = "bcm47xx_nflash",
-+ .resource = &bcm47xx_nflash_resource,
-+ .num_resources = 1,
-+};
-+
- static void __init bcm47xx_register_bcma(void)
- {
- int err;
-@@ -248,6 +264,9 @@ static void __init bcm47xx_register_bcma
-
- if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_SFLASH)
- bcm47xx_sflash_struct_bcma_init(&bcm47xx_sflash, &bcm47xx_bus.bcma.bus.drv_cc);
-+
-+ if (bcm47xx_bus.bcma.bus.drv_cc.flash_type == BCMA_NFLASH)
-+ bcm47xx_nflash_struct_bcma_init(&bcm47xx_nflash, &bcm47xx_bus.bcma.bus.drv_cc);
-
- bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
- }
-@@ -264,6 +283,9 @@ static int __init bcm47xx_register_flash
- case BCMA_SFLASH:
- bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash;
- return platform_device_register(&bcm47xx_sflash_dev);
-+ case BCMA_NFLASH:
-+ bcm47xx_nflash_dev.dev.platform_data = &bcm47xx_nflash;
-+ return platform_device_register(&bcm47xx_nflash_dev);
- default:
- printk(KERN_ERR "No flash device found\n");
- return -1;
---- a/arch/mips/include/asm/mach-bcm47xx/bus.h
-+++ b/arch/mips/include/asm/mach-bcm47xx/bus.h
-@@ -2,6 +2,7 @@
- * BCM947xx nvram variable access
- *
- * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de>
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
- *
- * 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
-@@ -12,6 +13,7 @@
- #include <linux/ssb/ssb.h>
- #include <linux/bcma/bcma.h>
- #include <bcm47xx.h>
-+#include <linux/mtd/nand.h>
-
- struct bcm47xx_sflash {
- enum bcm47xx_bus_type sflash_type;
-@@ -34,3 +36,18 @@ void bcm47xx_sflash_struct_bcma_init(str
- void bcm47xx_sflash_struct_ssb_init(struct bcm47xx_sflash *sflash, struct ssb_chipcommon *scc);
-
- extern struct bcm47xx_sflash bcm47xx_sflash;
-+
-+struct bcm47xx_nflash {
-+ enum bcm47xx_bus_type nflash_type;
-+ struct bcma_drv_cc *bcc;
-+
-+ u32 size; /* Total size in bytes */
-+ u32 next_opcode; /* Next expected command from upper NAND layer */
-+
-+ struct mtd_info mtd;
-+ struct nand_chip nand;
-+};
-+
-+void bcm47xx_nflash_struct_bcma_init(struct bcm47xx_nflash *nflash, struct bcma_drv_cc *bcc);
-+
-+extern struct bcm47xx_nflash bcm47xx_nflash;
---- a/drivers/bcma/Kconfig
-+++ b/drivers/bcma/Kconfig
-@@ -43,6 +43,11 @@ config BCMA_SFLASH
- depends on BCMA_DRIVER_MIPS
- default y
-
-+config BCMA_NFLASH
-+ 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,6 +1,7 @@
- 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-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.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
-@@ -56,6 +56,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
- int bcma_sflash_init(struct bcma_drv_cc *cc);
- #endif /* CONFIG_BCMA_SFLASH */
-
-+#ifdef CONFIG_BCMA_NFLASH
-+/* driver_chipcommon_nflash.c */
-+int bcma_nflash_init(struct bcma_drv_cc *cc);
-+#endif /* CONFIG_BCMA_NFLASH */
-+
- #ifdef CONFIG_BCMA_HOST_PCI
- /* host_pci.c */
- extern int __init bcma_host_pci_init(void);
---- /dev/null
-+++ b/drivers/bcma/driver_chipcommon_nflash.c
-@@ -0,0 +1,154 @@
-+/*
-+ * BCMA nand flash interface
-+ *
-+ * Copyright 2011, Tathagata Das <tathagata@alumnux.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 <linux/mtd/bcm47xx_nand.h>
-+#include <linux/mtd/nand.h>
-+
-+#include "bcma_private.h"
-+
-+/* Issue a nand flash command */
-+static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
-+{
-+ bcma_cc_write32(cc, NAND_CMD_START, opcode);
-+ bcma_cc_read32(cc, NAND_CMD_START);
-+}
-+
-+/* Check offset and length */
-+static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, u32 len, u32 mask)
-+{
-+ if ((offset & mask) != 0 || (len & mask) != 0) {
-+ pr_err("%s(): Address is not aligned. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
-+ return 1;
-+ }
-+
-+ if ((((offset + len) >> 20) >= cc->nflash.size) &&
-+ (((offset + len) & ((1 << 20) - 1)) != 0)) {
-+ pr_err("%s(): Address is outside Flash memory region. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/* Read len bytes starting at offset into buf. Returns number of bytes read. */
-+int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf)
-+{
-+ u32 mask;
-+ int i;
-+ u32 *to, val, res;
-+
-+ mask = NFL_SECTOR_SIZE - 1;
-+ if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
-+ return 0;
-+
-+ to = (u32 *)buf;
-+ res = len;
-+ while (res > 0) {
-+ bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
-+ bcma_nflash_cmd(cc, NCMD_PAGE_RD);
-+ if (bcma_nflash_poll(cc) < 0)
-+ break;
-+ val = bcma_cc_read32(cc, NAND_INTFC_STATUS);
-+ if ((val & NIST_CACHE_VALID) == 0)
-+ break;
-+ bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
-+ for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
-+ *to = bcma_cc_read32(cc, NAND_CACHE_DATA);
-+ }
-+ res -= NFL_SECTOR_SIZE;
-+ offset += NFL_SECTOR_SIZE;
-+ }
-+ return (len - res);
-+}
-+
-+#define NF_RETRIES 1000000
-+
-+/* Poll for command completion. Returns zero when complete. */
-+int bcma_nflash_poll(struct bcma_drv_cc *cc)
-+{
-+ u32 retries = NF_RETRIES;
-+ u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY;
-+ u32 mask;
-+
-+ while (retries--) {
-+ mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask;
-+ if (mask == pollmask)
-+ return 0;
-+ cpu_relax();
-+ }
-+
-+ if (!retries) {
-+ pr_err("bcma_nflash_poll: not ready\n");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+/* Write len bytes starting at offset into buf. Returns success (0) or failure (!0).
-+ * Should poll for completion.
-+ */
-+int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
-+ const u8 *buf)
-+{
-+ u32 mask;
-+ int i;
-+ u32 *from, res, reg;
-+
-+ mask = cc->nflash.pagesize - 1;
-+ if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
-+ return 1;
-+
-+ /* disable partial page enable */
-+ reg = bcma_cc_read32(cc, NAND_ACC_CONTROL);
-+ reg &= ~NAC_PARTIAL_PAGE_EN;
-+ bcma_cc_write32(cc, NAND_ACC_CONTROL, reg);
-+
-+ from = (u32 *)buf;
-+ res = len;
-+ while (res > 0) {
-+ bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
-+ for (i = 0; i < cc->nflash.pagesize; i += 4, from++) {
-+ if (i % 512 == 0)
-+ bcma_cc_write32(cc, NAND_CMD_ADDR, i);
-+ bcma_cc_write32(cc, NAND_CACHE_DATA, *from);
-+ }
-+ bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize - 512);
-+ bcma_nflash_cmd(cc, NCMD_PAGE_PROG);
-+ if (bcma_nflash_poll(cc) < 0)
-+ break;
-+ res -= cc->nflash.pagesize;
-+ offset += cc->nflash.pagesize;
-+ }
-+
-+ if (res <= 0)
-+ return 0;
-+ else
-+ return (len - res);
-+}
-+
-+/* Erase a region. Returns success (0) or failure (-1).
-+ * Poll for completion.
-+ */
-+int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset)
-+{
-+ if ((offset >> 20) >= cc->nflash.size)
-+ return -1;
-+ if ((offset & (cc->nflash.blocksize - 1)) != 0)
-+ return -1;
-+
-+ bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
-+ bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE);
-+ if (bcma_nflash_poll(cc) < 0)
-+ return -1;
-+ return 0;
-+}
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -6,6 +6,7 @@
- * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
- * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
- * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
- *
- * Licensed under the GNU/GPL. See COPYING for details.
- */
-@@ -182,6 +183,17 @@ static void bcma_core_mips_flash_detect(
- {
- struct bcma_bus *bus = mcore->core->bus;
-
-+ if (bus->drv_cc.core->id.rev == 38
-+ && (bus->drv_cc.status & (1 << 4)) != 0) {
-+#ifdef CONFIG_BCMA_NFLASH
-+ pr_info("found nand flash.\n");
-+ bus->drv_cc.flash_type = BCMA_NFLASH;
-+#else
-+ pr_info("NAND flash not supported.\n");
-+#endif
-+ return;
-+ }
-+
- switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
- case BCMA_CC_FLASHT_STSER:
- case BCMA_CC_FLASHT_ATSER:
---- a/drivers/mtd/nand/Kconfig
-+++ b/drivers/mtd/nand/Kconfig
-@@ -536,4 +536,12 @@ config MTD_NAND_FSMC
- Enables support for NAND Flash chips on the ST Microelectronics
- Flexible Static Memory Controller (FSMC)
-
-+config MTD_NAND_BCM47XX
-+ tristate "bcm47xx nand flash support"
-+ default y
-+ depends on BCM47XX && BCMA_NFLASH
-+ select MTD_PARTITIONS
-+ help
-+ Support for bcm47xx nand flash
-+
- endif # MTD_NAND
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mp
- obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
- obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
- obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
-+obj-$(CONFIG_MTD_NAND_BCM47XX) += bcm47xx_nand.o
-
- nand-objs := nand_base.o nand_bbt.o
---- /dev/null
-+++ b/drivers/mtd/nand/bcm47xx_nand.c
-@@ -0,0 +1,506 @@
-+/*
-+ * BCMA nand flash interface
-+ *
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
-+ * Copyright 2010, Broadcom Corporation
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#define pr_fmt(fmt) "bcm47xx_nflash: " 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 <linux/platform_device.h>
-+#include <bcm47xx.h>
-+#include <bus.h>
-+#include <linux/cramfs_fs.h>
-+#include <linux/romfs_fs.h>
-+#include <linux/magic.h>
-+#include <linux/byteorder/generic.h>
-+#include <linux/mtd/bcm47xx_nand.h>
-+#include <linux/mtd/nand.h>
-+
-+static int bcm47xx_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
-+static int bcm47xx_erase(struct mtd_info *mtd, unsigned int addr, unsigned int len);
-+
-+/* Private Global variable */
-+static u32 read_offset = 0;
-+static u32 write_offset;
-+
-+static int
-+nflash_mtd_poll(struct bcm47xx_nflash *nflash, unsigned int offset, int timeout)
-+{
-+ unsigned long now = jiffies;
-+ int ret = 0;
-+
-+ for (;;) {
-+ if (!bcma_nflash_poll(nflash->bcc)) {
-+ ret = 0;
-+ break;
-+ }
-+ if (time_after(jiffies, now + timeout)) {
-+ pr_err("timeout while polling\n");
-+ ret = -ETIMEDOUT;
-+ break;
-+ }
-+ udelay(1);
-+ }
-+
-+ return ret;
-+}
-+
-+static int
-+bcm47xx_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-+{
-+ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
-+ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
-+ int bytes, ret = 0;
-+ u32 extra = 0;
-+ u8 *tmpbuf = NULL;
-+ int size;
-+ u32 offset, blocksize, mask, off;
-+ u32 skip_bytes = 0;
-+ int need_copy = 0;
-+ u8 *ptr = NULL;
-+
-+ /* Check address range */
-+ if (!len)
-+ return 0;
-+ if ((from + len) > mtd->size)
-+ return -EINVAL;
-+ offset = from;
-+ if ((offset & (NFL_SECTOR_SIZE - 1)) != 0) {
-+ extra = offset & (NFL_SECTOR_SIZE - 1);
-+ offset -= extra;
-+ len += extra;
-+ need_copy = 1;
-+ }
-+ size = (len + (NFL_SECTOR_SIZE - 1)) & ~(NFL_SECTOR_SIZE - 1);
-+ if (size != len) {
-+ need_copy = 1;
-+ }
-+ if (!need_copy) {
-+ ptr = buf;
-+ } else {
-+ tmpbuf = (u8 *)kmalloc(size, GFP_KERNEL);
-+ ptr = tmpbuf;
-+ }
-+
-+ blocksize = mtd->erasesize;
-+ mask = blocksize - 1;
-+ *retlen = 0;
-+ while (len > 0) {
-+ off = offset + skip_bytes;
-+ if ((bytes = bcma_nflash_read(nflash->bcc, off, NFL_SECTOR_SIZE, ptr)) < 0) {
-+ ret = bytes;
-+ goto done;
-+ }
-+ if (bytes > len)
-+ bytes = len;
-+ offset += bytes;
-+ len -= bytes;
-+ ptr += bytes;
-+ *retlen += bytes;
-+ }
-+
-+done:
-+ if (tmpbuf) {
-+ *retlen -= extra;
-+ memcpy(buf, tmpbuf+extra, *retlen);
-+ kfree(tmpbuf);
-+ }
-+
-+ return ret;
-+}
-+
-+static void bcm47xx_write(struct mtd_info *mtd, u32 to, const u_char *buf, u32 len)
-+{
-+ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
-+ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
-+ u32 offset, blocksize, mask, off;
-+ int read_len;
-+ u32 copy_len, write_len, from;
-+ u_char *write_ptr, *block;
-+ const u_char *ptr;
-+ int ret, bytes;
-+
-+ /* Check address range */
-+ if (!len) {
-+ pr_err("Error: Attempted to write too small data\n");
-+ return;
-+ }
-+
-+ if (!to)
-+ return;
-+
-+ if ((to + len) > mtd->size) {
-+ pr_err("Error: Attempted to write too large data\n");
-+ return;
-+ }
-+
-+ ptr = buf;
-+ block = NULL;
-+ offset = to;
-+ blocksize = mtd->erasesize;
-+ if (!(block = kmalloc(blocksize, GFP_KERNEL)))
-+ return;
-+ mask = blocksize - 1;
-+ while (len) {
-+ /* Align offset */
-+ from = offset & ~mask;
-+ /* Copy existing data into holding block if necessary */
-+ if (((offset & (blocksize-1)) != 0) || (len < blocksize)) {
-+ if ((ret = bcm47xx_read(mtd, from, blocksize, &read_len, block)))
-+ goto done;
-+ if (read_len != blocksize) {
-+ ret = -EINVAL;
-+ goto done;
-+ }
-+ }
-+
-+ /* Copy input data into holding block */
-+ copy_len = min(len, blocksize - (offset & mask));
-+ memcpy(block + (offset & mask), ptr, copy_len);
-+ off = (uint) from;
-+ /* Erase block */
-+ if ((ret = bcm47xx_erase(mtd, off, blocksize)) < 0)
-+ goto done;
-+ /* Write holding block */
-+ write_ptr = block;
-+ write_len = blocksize;
-+ if ((bytes = bcma_nflash_write(nflash->bcc, (uint)from, (uint)write_len, (u8 *) write_ptr)) != 0) {
-+ ret = bytes;
-+ goto done;
-+ }
-+ offset += copy_len;
-+ if (len < copy_len)
-+ len = 0;
-+ else
-+ len -= copy_len;
-+ ptr += copy_len;
-+ }
-+
-+done:
-+ if (block)
-+ kfree(block);
-+ return;
-+}
-+
-+static int bcm47xx_erase(struct mtd_info *mtd, unsigned int addr, unsigned int len)
-+{
-+ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
-+ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
-+
-+ /* Check address range */
-+ if (!len)
-+ return 1;
-+ if ((addr + len) > mtd->size)
-+ return 1;
-+
-+ if (bcma_nflash_erase(nflash->bcc, addr)) {
-+ pr_err("ERASE: nflash erase error\n");
-+ return 1;
-+ }
-+
-+ if (nflash_mtd_poll(nflash, addr, 10 * HZ)) {
-+ pr_err("ERASE: nflash_mtd_poll error\n");
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/* This functions is used by upper layer to checks if device is ready */
-+static int bcm47xx_dev_ready(struct mtd_info *mtd)
-+{
-+ return 1;
-+}
-+
-+/* Issue a nand flash command */
-+static inline void bcm47xx_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
-+{
-+ bcma_cc_write32(cc, NAND_CMD_START, opcode);
-+ bcma_cc_read32(cc, NAND_CMD_START);
-+}
-+
-+static void bcm47xx_command(struct mtd_info *mtd, unsigned command,
-+ int column, int page_addr)
-+{
-+ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
-+ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
-+ u32 pagesize = 1 << nchip->page_shift;
-+
-+ /* Command pre-processing step */
-+ switch (command) {
-+ case NAND_CMD_RESET:
-+ bcm47xx_nflash_cmd(nflash->bcc, NCMD_FLASH_RESET);
-+ break;
-+
-+ case NAND_CMD_STATUS:
-+ nflash->next_opcode = NAND_CMD_STATUS;
-+ read_offset = 0;
-+ write_offset = 0;
-+ break;
-+
-+ case NAND_CMD_READ0:
-+ read_offset = page_addr * pagesize;
-+ nflash->next_opcode = 0;
-+ break;
-+
-+ case NAND_CMD_READOOB:
-+ read_offset = page_addr * pagesize;
-+ nflash->next_opcode = 0;
-+ break;
-+
-+ case NAND_CMD_SEQIN:
-+ write_offset = page_addr * pagesize;
-+ nflash->next_opcode = 0;
-+ break;
-+
-+ case NAND_CMD_PAGEPROG:
-+ nflash->next_opcode = 0;
-+ break;
-+
-+ case NAND_CMD_READID:
-+ read_offset = column;
-+ bcm47xx_nflash_cmd(nflash->bcc, NCMD_ID_RD);
-+ nflash->next_opcode = NAND_DEVID;
-+ break;
-+
-+ case NAND_CMD_ERASE1:
-+ nflash->next_opcode = 0;
-+ bcm47xx_erase(mtd, page_addr*pagesize, pagesize);
-+ break;
-+
-+ case NAND_CMD_ERASE2:
-+ break;
-+
-+ case NAND_CMD_RNDOUT:
-+ if (column > mtd->writesize)
-+ read_offset += (column - mtd->writesize);
-+ else
-+ read_offset += column;
-+ break;
-+
-+ default:
-+ pr_err("COMMAND not supported %x\n", command);
-+ nflash->next_opcode = 0;
-+ break;
-+ }
-+}
-+
-+/* This function is used by upper layer for select and
-+ * deselect of the NAND chip.
-+ * It is dummy function. */
-+static void bcm47xx_select_chip(struct mtd_info *mtd, int chip)
-+{
-+}
-+
-+static u_char bcm47xx_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *nchip = mtd->priv;
-+ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
-+ uint8_t ret = 0;
-+ static u32 id;
-+
-+ if (nflash->next_opcode == 0)
-+ return ret;
-+
-+ if (nflash->next_opcode == NAND_CMD_STATUS)
-+ return NAND_STATUS_WP;
-+
-+ id = bcma_cc_read32(nflash->bcc, nflash->next_opcode);
-+
-+ if (nflash->next_opcode == NAND_DEVID) {
-+ ret = (id >> (8*read_offset)) & 0xff;
-+ read_offset++;
-+ }
-+
-+ return ret;
-+}
-+
-+static uint16_t bcm47xx_read_word(struct mtd_info *mtd)
-+{
-+ loff_t from = read_offset;
-+ uint16_t buf = 0;
-+ int bytes;
-+
-+ bcm47xx_read(mtd, from, sizeof(buf), &bytes, (u_char *)&buf);
-+ return buf;
-+}
-+
-+/* Write data of length len to buffer buf. The data to be
-+ * written on NAND Flash is first copied to RAMbuffer. After the Data Input
-+ * Operation by the NFC, the data is written to NAND Flash */
-+static void bcm47xx_write_buf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ bcm47xx_write(mtd, write_offset, buf, len);
-+}
-+
-+/* Read the data buffer from the NAND Flash. To read the data from NAND
-+ * Flash first the data output cycle is initiated by the NFC, which copies
-+ * the data to RAMbuffer. This data of length len is then copied to buffer buf.
-+ */
-+static void bcm47xx_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+ loff_t from = read_offset;
-+ int bytes;
-+
-+ bcm47xx_read(mtd, from, len, &bytes, buf);
-+}
-+
-+/* Used by the upper layer to verify the data in NAND Flash
-+ * with the data in the buf. */
-+static int bcm47xx_verify_buf(struct mtd_info *mtd,
-+ const u_char *buf, int len)
-+{
-+ return -EFAULT;
-+}
-+
-+static int bcm47xx_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
-+{
-+ struct nand_chip *nchip = mtd->priv;
-+ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
-+ int i;
-+ uint off;
-+ u32 pagesize = 1 << nchip->page_shift;
-+ u32 blocksize = mtd->erasesize;
-+
-+ if ((ofs >> 20) >= nflash->size)
-+ return 1;
-+ if ((ofs & (blocksize - 1)) != 0)
-+ return 1;
-+
-+ for (i = 0; i < 2; i++) {
-+ off = ofs + pagesize;
-+ bcma_cc_write32(nflash->bcc, NAND_CMD_ADDR, off);
-+ bcm47xx_nflash_cmd(nflash->bcc, NCMD_SPARE_RD);
-+ if (bcma_nflash_poll(nflash->bcc) < 0)
-+ break;
-+ if ((bcma_cc_read32(nflash->bcc, NAND_INTFC_STATUS) & NIST_SPARE_VALID) != NIST_SPARE_VALID)
-+ return 1;
-+ if ((bcma_cc_read32(nflash->bcc, NAND_SPARE_RD0) & 0xff) != 0xff)
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+const char *part_probes[] = { "cmdlinepart", NULL };
-+static int bcm47xx_probe(struct platform_device *pdev)
-+{
-+ struct nand_chip *nchip;
-+ struct mtd_info *mtd;
-+ struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev);
-+ int ret = 0;
-+
-+ mtd = &nflash->mtd;
-+ nchip = &nflash->nand;
-+
-+ /* Register with MTD */
-+ mtd->priv = nchip;
-+ mtd->owner = THIS_MODULE;
-+ mtd->dev.parent = &pdev->dev;
-+
-+ /* 50 us command delay time */
-+ nchip->chip_delay = 50;
-+
-+ nchip->priv = nflash;
-+ nchip->dev_ready = bcm47xx_dev_ready;
-+ nchip->cmdfunc = bcm47xx_command;
-+ nchip->select_chip = bcm47xx_select_chip;
-+ nchip->read_byte = bcm47xx_read_byte;
-+ nchip->read_word = bcm47xx_read_word;
-+ nchip->write_buf = bcm47xx_write_buf;
-+ nchip->read_buf = bcm47xx_read_buf;
-+ nchip->verify_buf = bcm47xx_verify_buf;
-+ nchip->block_bad = bcm47xx_block_bad;
-+ nchip->options = NAND_SKIP_BBTSCAN;
-+
-+ /* Not known */
-+ nchip->ecc.mode = NAND_ECC_NONE;
-+
-+ /* first scan to find the device and get the page size */
-+ if (nand_scan_ident(mtd, 1, NULL)) {
-+ pr_err("nand_scan_ident failed\n");
-+ ret = -ENXIO;
-+ goto done;
-+ }
-+ nflash->bcc->nflash.size = mtd->size;
-+ nflash->bcc->nflash.pagesize = 1 << nchip->page_shift;
-+ nflash->bcc->nflash.blocksize = mtd->erasesize;
-+ bcm47xx_nflash.size = mtd->size;
-+
-+ /* second phase scan */
-+ if (nand_scan_tail(mtd)) {
-+ pr_err("nand_scan_tail failed\n");
-+ ret = -ENXIO;
-+ goto done;
-+ }
-+
-+ mtd->name = "bcm47xx-nflash";
-+ mtd->flags |= MTD_WRITEABLE;
-+ ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
-+
-+ if (ret) {
-+ pr_err("mtd_device_register failed\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+
-+done:
-+ return ret;
-+}
-+
-+static int __devexit bcm47xx_remove(struct platform_device *pdev)
-+{
-+ struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev);
-+ struct mtd_info *mtd = &nflash->mtd;
-+
-+ if (nflash) {
-+ /* Release resources, unregister device */
-+ nand_release(mtd);
-+ }
-+
-+ return 0;
-+}
-+
-+static struct platform_driver bcm47xx_driver = {
-+ .remove = __devexit_p(bcm47xx_remove),
-+ .driver = {
-+ .name = "bcm47xx_nflash",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init init_bcm47xx_nflash(void)
-+{
-+ int ret = platform_driver_probe(&bcm47xx_driver, bcm47xx_probe);
-+
-+ if (ret)
-+ pr_err("error registering platform driver: %i\n", ret);
-+ return ret;
-+}
-+
-+static void __exit exit_bcm47xx_nflash(void)
-+{
-+ platform_driver_unregister(&bcm47xx_driver);
-+}
-+
-+module_init(init_bcm47xx_nflash);
-+module_exit(exit_bcm47xx_nflash);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("BCM47XX NAND flash driver");
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -436,6 +436,7 @@ struct bcma_chipcommon_pmu {
- enum bcma_flash_type {
- BCMA_PFLASH,
- BCMA_SFLASH,
-+ BCMA_NFLASH,
- };
-
- struct bcma_pflash {
-@@ -452,6 +453,14 @@ struct bcma_sflash {
- };
- #endif /* CONFIG_BCMA_SFLASH */
-
-+#ifdef CONFIG_BCMA_NFLASH
-+struct bcma_nflash {
-+ u32 blocksize; /* Block size */
-+ u32 pagesize; /* Page size */
-+ u32 size; /* Total size in bytes */
-+};
-+#endif
-+
- struct bcma_serial_port {
- void *regs;
- unsigned long clockspeed;
-@@ -477,6 +486,9 @@ struct bcma_drv_cc {
- #ifdef CONFIG_BCMA_SFLASH
- struct bcma_sflash sflash;
- #endif /* CONFIG_BCMA_SFLASH */
-+#ifdef CONFIG_BCMA_NFLASH
-+ struct bcma_nflash nflash;
-+#endif
- };
-
- int nr_serial_ports;
-@@ -542,4 +554,13 @@ int bcma_sflash_write(struct bcma_drv_cc
- int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset);
- #endif /* CONFIG_BCMA_SFLASH */
-
-+#ifdef CONFIG_BCMA_NFLASH
-+/* Chipcommon nflash support. */
-+int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf);
-+int bcma_nflash_poll(struct bcma_drv_cc *cc);
-+int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
-+int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset);
-+int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
-+#endif
-+
- #endif /* LINUX_BCMA_DRIVER_CC_H_ */
---- /dev/null
-+++ b/include/linux/mtd/bcm47xx_nand.h
-@@ -0,0 +1,134 @@
-+/*
-+ * Broadcom chipcommon NAND flash interface
-+ *
-+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
-+ * Copyright (C) 2009, 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.
-+ *
-+ */
-+
-+#ifndef _nflash_h_
-+#define _nflash_h_
-+
-+#define NAND_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
-+
-+/* nand_cmd_start commands */
-+#define NCMD_NULL 0
-+#define NCMD_PAGE_RD 1
-+#define NCMD_SPARE_RD 2
-+#define NCMD_STATUS_RD 3
-+#define NCMD_PAGE_PROG 4
-+#define NCMD_SPARE_PROG 5
-+#define NCMD_COPY_BACK 6
-+#define NCMD_ID_RD 7
-+#define NCMD_BLOCK_ERASE 8
-+#define NCMD_FLASH_RESET 9
-+#define NCMD_LOCK 0xa
-+#define NCMD_LOCK_DOWN 0xb
-+#define NCMD_UNLOCK 0xc
-+#define NCMD_LOCK_STATUS 0xd
-+
-+/* nand_acc_control */
-+#define NAC_RD_ECC_EN 0x80000000
-+#define NAC_WR_ECC_EN 0x40000000
-+#define NAC_RD_ECC_BLK0_EN 0x20000000
-+#define NAC_FAST_PGM_RDIN 0x10000000
-+#define NAC_RD_ERASED_ECC_EN 0x08000000
-+#define NAC_PARTIAL_PAGE_EN 0x04000000
-+#define NAC_PAGE_HIT_EN 0x01000000
-+#define NAC_ECC_LEVEL0 0x00f00000
-+#define NAC_ECC_LEVEL 0x000f0000
-+#define NAC_SPARE_SIZE0 0x00003f00
-+#define NAC_SPARE_SIZE 0x0000003f
-+
-+/* nand_config */
-+#define NCF_CONFIG_LOCK 0x80000000
-+#define NCF_BLOCK_SIZE_MASK 0x70000000
-+#define NCF_BLOCK_SIZE_SHIFT 28
-+#define NCF_DEVICE_SIZE_MASK 0x0f000000
-+#define NCF_DEVICE_SIZE_SHIFT 24
-+#define NCF_DEVICE_WIDTH 0x00800000
-+#define NCF_PAGE_SIZE_MASK 0x00300000
-+#define NCF_PAGE_SIZE_SHIFT 20
-+#define NCF_FULL_ADDR_BYTES_MASK 0x00070000
-+#define NCF_FULL_ADDR_BYTES_SHIFT 16
-+#define NCF_COL_ADDR_BYTES_MASK 0x00007000
-+#define NCF_COL_ADDR_BYTES_SHIFT 12
-+#define NCF_BLK_ADDR_BYTES_MASK 0x00000700
-+#define NCF_BLK_ADDR_BYTES_SHIFT 8
-+
-+/* nand_intfc_status */
-+#define NIST_CTRL_READY 0x80000000
-+#define NIST_FLASH_READY 0x40000000
-+#define NIST_CACHE_VALID 0x20000000
-+#define NIST_SPARE_VALID 0x10000000
-+#define NIST_ERASED 0x08000000
-+#define NIST_STATUS 0x000000ff
-+
-+#define NFL_SECTOR_SIZE 512
-+
-+#define NFL_TABLE_END 0xffffffff
-+#define NFL_BOOT_SIZE 0x200000
-+#define NFL_BOOT_OS_SIZE 0x2000000
-+
-+/* Nand flash MLC controller registers (corerev >= 38) */
-+#define NAND_REVISION 0xC00
-+#define NAND_CMD_START 0xC04
-+#define NAND_CMD_ADDR_X 0xC08
-+#define NAND_CMD_ADDR 0xC0C
-+#define NAND_CMD_END_ADDR 0xC10
-+#define NAND_CS_NAND_SELECT 0xC14
-+#define NAND_CS_NAND_XOR 0xC18
-+#define NAND_SPARE_RD0 0xC20
-+#define NAND_SPARE_RD4 0xC24
-+#define NAND_SPARE_RD8 0xC28
-+#define NAND_SPARE_RD12 0xC2C
-+#define NAND_SPARE_WR0 0xC30
-+#define NAND_SPARE_WR4 0xC34
-+#define NAND_SPARE_WR8 0xC38
-+#define NAND_SPARE_WR12 0xC3C
-+#define NAND_ACC_CONTROL 0xC40
-+#define NAND_CONFIG 0xC48
-+#define NAND_TIMING_1 0xC50
-+#define NAND_TIMING_2 0xC54
-+#define NAND_SEMAPHORE 0xC58
-+#define NAND_DEVID 0xC60
-+#define NAND_DEVID_X 0xC64
-+#define NAND_BLOCK_LOCK_STATUS 0xC68
-+#define NAND_INTFC_STATUS 0xC6C
-+#define NAND_ECC_CORR_ADDR_X 0xC70
-+#define NAND_ECC_CORR_ADDR 0xC74
-+#define NAND_ECC_UNC_ADDR_X 0xC78
-+#define NAND_ECC_UNC_ADDR 0xC7C
-+#define NAND_READ_ERROR_COUNT 0xC80
-+#define NAND_CORR_STAT_THRESHOLD 0xC84
-+#define NAND_READ_ADDR_X 0xC90
-+#define NAND_READ_ADDR 0xC94
-+#define NAND_PAGE_PROGRAM_ADDR_X 0xC98
-+#define NAND_PAGE_PROGRAM_ADDR 0xC9C
-+#define NAND_COPY_BACK_ADDR_X 0xCA0
-+#define NAND_COPY_BACK_ADDR 0xCA4
-+#define NAND_BLOCK_ERASE_ADDR_X 0xCA8
-+#define NAND_BLOCK_ERASE_ADDR 0xCAC
-+#define NAND_INV_READ_ADDR_X 0xCB0
-+#define NAND_INV_READ_ADDR 0xCB4
-+#define NAND_BLK_WR_PROTECT 0xCC0
-+#define NAND_ACC_CONTROL_CS1 0xCD0
-+#define NAND_CONFIG_CS1 0xCD4
-+#define NAND_TIMING_1_CS1 0xCD8
-+#define NAND_TIMING_2_CS1 0xCDC
-+#define NAND_SPARE_RD16 0xD30
-+#define NAND_SPARE_RD20 0xD34
-+#define NAND_SPARE_RD24 0xD38
-+#define NAND_SPARE_RD28 0xD3C
-+#define NAND_CACHE_ADDR 0xD40
-+#define NAND_CACHE_DATA 0xD44
-+#define NAND_CTRL_CONFIG 0xD48
-+#define NAND_CTRL_STATUS 0xD4C
-+
-+#endif /* _nflash_h_ */
diff --git a/target/linux/brcm47xx/patches-3.3/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch b/target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch
index 5381e2f6c..5381e2f6c 100644
--- a/target/linux/brcm47xx/patches-3.3/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch
+++ b/target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch
diff --git a/target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch
index 7f8f64f28..86336ed57 100644
--- a/target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch
+++ b/target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch
@@ -25,7 +25,7 @@
+obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o
--- /dev/null
+++ b/drivers/mtd/maps/bcm47xx-pflash.c
-@@ -0,0 +1,188 @@
+@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
@@ -107,10 +107,10 @@
+
+static const char *probes[] = { "bcm47xx", NULL };
+
-+static int bcm47xx_mtd_probe(struct platform_device *pdev)
++static int bcm47xx_pflash_probe(struct platform_device *pdev)
+{
+#ifdef CONFIG_BCM47XX_SSB
-+ struct ssb_chipcommon *ssb_cc;
++ struct ssb_mipscore *ssb_mcore;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+ struct bcma_drv_cc *bcma_cc;
@@ -120,19 +120,19 @@
+ switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+ case BCM47XX_BUS_TYPE_SSB:
-+ ssb_cc = &bcm47xx_bus.ssb.chipco;
-+ if (ssb_cc->flash_type != SSB_PFLASH)
++ ssb_mcore = &bcm47xx_bus.ssb.mipscore;
++ if (!ssb_mcore->pflash.present)
+ return -ENODEV;
+
-+ bcm47xx_map.phys = ssb_cc->pflash.window;
-+ bcm47xx_map.size = ssb_cc->pflash.window_size;
-+ bcm47xx_map.bankwidth = ssb_cc->pflash.buswidth;
++ bcm47xx_map.phys = ssb_mcore->pflash.window;
++ bcm47xx_map.size = ssb_mcore->pflash.window_size;
++ bcm47xx_map.bankwidth = ssb_mcore->pflash.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)
++ if (!bcma_cc->pflash.present)
+ return -ENODEV;
+
+ bcm47xx_map.phys = bcma_cc->pflash.window;
@@ -179,7 +179,7 @@
+ return ret;
+}
+
-+static int __devexit bcm47xx_mtd_remove(struct platform_device *pdev)
++static int __devexit bcm47xx_pflash_remove(struct platform_device *pdev)
+{
+ mtd_device_unregister(bcm47xx_mtd);
+ map_destroy(bcm47xx_mtd);
@@ -187,30 +187,38 @@
+ return 0;
+}
+
-+static struct platform_driver bcm47xx_mtd_driver = {
-+ .remove = __devexit_p(bcm47xx_mtd_remove),
-+ .driver = {
-+ .name = "bcm47xx_pflash",
++static const struct platform_device_id bcm47xx_pflash_table[] = {
++ { "bcm47xx-pflash", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(platform, bcm47xx_pflash_table);
++
++static struct platform_driver bcm47xx_pflash_driver = {
++ .id_table = bcm47xx_pflash_table,
++ .probe = bcm47xx_pflash_probe,
++ .remove = __devexit_p(bcm47xx_pflash_remove),
++ .driver = {
++ .name = "bcm47xx-pflash",
+ .owner = THIS_MODULE,
+ },
+};
+
-+static int __init init_bcm47xx_mtd(void)
++static int __init init_bcm47xx_pflash(void)
+{
-+ int ret = platform_driver_probe(&bcm47xx_mtd_driver, bcm47xx_mtd_probe);
++ int ret = platform_driver_register(&bcm47xx_pflash_driver);
+
+ if (ret)
+ pr_err("error registering platform driver: %i\n", ret);
+ return ret;
+}
+
-+static void __exit exit_bcm47xx_mtd(void)
++static void __exit exit_bcm47xx_pflash(void)
+{
-+ platform_driver_unregister(&bcm47xx_mtd_driver);
++ platform_driver_unregister(&bcm47xx_pflash_driver);
+}
+
-+module_init(init_bcm47xx_mtd);
-+module_exit(exit_bcm47xx_mtd);
++module_init(init_bcm47xx_pflash);
++module_exit(exit_bcm47xx_pflash);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("BCM47XX parallel flash driver");
diff --git a/target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/052-mtd-add-serial-flash-driver.patch
index 3aec60c11..1e408fa70 100644
--- a/target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch
+++ b/target/linux/brcm47xx/patches-3.3/052-mtd-add-serial-flash-driver.patch
@@ -25,7 +25,7 @@
+obj-$(CONFIG_MTD_BCM47XX_SFLASH)+= bcm47xx-sflash.o
--- /dev/null
+++ b/drivers/mtd/maps/bcm47xx-sflash.c
-@@ -0,0 +1,263 @@
+@@ -0,0 +1,270 @@
+/*
+ * Broadcom SiliconBackplane chipcommon serial flash interface
+ *
@@ -47,8 +47,7 @@
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
-+#include <bcm47xx.h>
-+#include <bus.h>
++#include <linux/mtd/bcm47xx_sflash.h>
+
+static int
+sflash_mtd_poll(struct bcm47xx_sflash *sflash, unsigned int offset, int timeout)
@@ -262,17 +261,25 @@
+ return 0;
+}
+
++static const struct platform_device_id bcm47xx_sflash_table[] = {
++ { "bcm47xx-sflash", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(platform, bcm47xx_sflash_table);
++
+static struct platform_driver bcm47xx_sflash_driver = {
-+ .remove = __devexit_p(bcm47xx_sflash_remove),
-+ .driver = {
-+ .name = "bcm47xx_sflash",
++ .id_table = bcm47xx_sflash_table,
++ .probe = bcm47xx_sflash_probe,
++ .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);
++ int ret = platform_driver_register(&bcm47xx_sflash_driver);
+
+ if (ret)
+ pr_err("error registering platform driver: %i\n", ret);
@@ -288,4 +295,41 @@
+module_exit(exit_bcm47xx_sflash);
+
+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("BCM47XX parallel flash driver");
++MODULE_DESCRIPTION("BCM47XX serial flash driver");
+--- /dev/null
++++ b/include/linux/mtd/bcm47xx_sflash.h
+@@ -0,0 +1,34 @@
++#ifndef LINUX_MTD_BCM47XX_SFLASH_H_
++#define LINUX_MTD_BCM47XX_SFLASH_H_
++
++#include <linux/mtd/mtd.h>
++
++enum bcm47xx_sflash_type {
++ BCM47XX_SFLASH_SSB,
++ BCM47XX_SFLASH_BCMA,
++};
++
++struct ssb_chipcommon;
++struct bcma_drv_cc;
++
++struct bcm47xx_sflash {
++ enum bcm47xx_sflash_type type;
++ union {
++ struct ssb_chipcommon *scc;
++ struct bcma_drv_cc *bcc;
++ };
++
++ bool present;
++ u16 numblocks;
++ u32 window;
++ u32 blocksize;
++ u32 size;
++
++ int (*read)(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf);
++ int (*poll)(struct bcm47xx_sflash *dev, u32 offset);
++ int (*write)(struct bcm47xx_sflash *dev, u32 offset, u32 len, const u8 *buf);
++ int (*erase)(struct bcm47xx_sflash *dev, u32 offset);
++
++ struct mtd_info *mtd;
++};
++#endif /* LINUX_MTD_BCM47XX_SFLASH_H_ */
diff --git a/target/linux/brcm47xx/patches-3.3/053-mtd-add-nand-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/053-mtd-add-nand-flash-driver.patch
new file mode 100644
index 000000000..7635d424d
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/053-mtd-add-nand-flash-driver.patch
@@ -0,0 +1,710 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -536,4 +536,12 @@ config MTD_NAND_FSMC
+ Enables support for NAND Flash chips on the ST Microelectronics
+ Flexible Static Memory Controller (FSMC)
+
++config MTD_NAND_BCM47XX
++ tristate "bcm47xx nand flash support"
++ default y
++ depends on BCM47XX && BCMA_NFLASH
++ select MTD_PARTITIONS
++ help
++ Support for bcm47xx nand flash
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mp
+ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
+ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
+ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
++obj-$(CONFIG_MTD_NAND_BCM47XX) += bcm47xx_nand.o
+
+ nand-objs := nand_base.o nand_bbt.o
+--- /dev/null
++++ b/drivers/mtd/nand/bcm47xx_nand.c
+@@ -0,0 +1,528 @@
++/*
++ * BCMA nand flash interface
++ *
++ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
++ * Copyright 2010, Broadcom Corporation
++ *
++ * 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.
++ *
++ */
++
++#define pr_fmt(fmt) "bcm47xx_nflash: " 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 <linux/platform_device.h>
++#include <bcm47xx.h>
++#include <linux/cramfs_fs.h>
++#include <linux/romfs_fs.h>
++#include <linux/magic.h>
++#include <linux/byteorder/generic.h>
++#include <linux/mtd/bcm47xx_nand.h>
++#include <linux/mtd/nand.h>
++
++static int bcm47xx_nflash_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip);
++static int bcm47xx_nflash_erase(struct mtd_info *mtd, unsigned int addr, unsigned int len);
++
++/* Private Global variable */
++static u32 read_offset = 0;
++static u32 write_offset;
++
++static int
++nflash_mtd_poll(struct bcm47xx_nflash *nflash, unsigned int offset, int timeout)
++{
++ unsigned long now = jiffies;
++ int ret = 0;
++
++ for (;;) {
++ if (!bcma_nflash_poll(nflash->bcc)) {
++ ret = 0;
++ break;
++ }
++ if (time_after(jiffies, now + timeout)) {
++ pr_err("timeout while polling\n");
++ ret = -ETIMEDOUT;
++ break;
++ }
++ udelay(1);
++ }
++
++ return ret;
++}
++
++static int
++bcm47xx_nflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
++ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
++ int bytes, ret = 0;
++ u32 extra = 0;
++ u8 *tmpbuf = NULL;
++ int size;
++ u32 offset, blocksize, mask, off;
++ u32 skip_bytes = 0;
++ int need_copy = 0;
++ u8 *ptr = NULL;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++ if ((from + len) > mtd->size)
++ return -EINVAL;
++ offset = from;
++ if ((offset & (NFL_SECTOR_SIZE - 1)) != 0) {
++ extra = offset & (NFL_SECTOR_SIZE - 1);
++ offset -= extra;
++ len += extra;
++ need_copy = 1;
++ }
++ size = (len + (NFL_SECTOR_SIZE - 1)) & ~(NFL_SECTOR_SIZE - 1);
++ if (size != len) {
++ need_copy = 1;
++ }
++ if (!need_copy) {
++ ptr = buf;
++ } else {
++ tmpbuf = (u8 *)kmalloc(size, GFP_KERNEL);
++ ptr = tmpbuf;
++ }
++
++ blocksize = mtd->erasesize;
++ mask = blocksize - 1;
++ *retlen = 0;
++ while (len > 0) {
++ off = offset + skip_bytes;
++ if ((bytes = bcma_nflash_read(nflash->bcc, off, NFL_SECTOR_SIZE, ptr)) < 0) {
++ ret = bytes;
++ goto done;
++ }
++ if (bytes > len)
++ bytes = len;
++ offset += bytes;
++ len -= bytes;
++ ptr += bytes;
++ *retlen += bytes;
++ }
++
++done:
++ if (tmpbuf) {
++ *retlen -= extra;
++ memcpy(buf, tmpbuf+extra, *retlen);
++ kfree(tmpbuf);
++ }
++
++ return ret;
++}
++
++static void bcm47xx_nflash_write(struct mtd_info *mtd, u32 to, const u_char *buf, u32 len)
++{
++ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
++ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
++ u32 offset, blocksize, mask, off;
++ int read_len;
++ u32 copy_len, write_len, from;
++ u_char *write_ptr, *block;
++ const u_char *ptr;
++ int ret, bytes;
++
++ /* Check address range */
++ if (!len) {
++ pr_err("Error: Attempted to write too small data\n");
++ return;
++ }
++
++ if (!to)
++ return;
++
++ if ((to + len) > mtd->size) {
++ pr_err("Error: Attempted to write too large data\n");
++ return;
++ }
++
++ ptr = buf;
++ block = NULL;
++ offset = to;
++ blocksize = mtd->erasesize;
++ if (!(block = kmalloc(blocksize, GFP_KERNEL)))
++ return;
++ mask = blocksize - 1;
++ while (len) {
++ /* Align offset */
++ from = offset & ~mask;
++ /* Copy existing data into holding block if necessary */
++ if (((offset & (blocksize-1)) != 0) || (len < blocksize)) {
++ if ((ret = bcm47xx_nflash_read(mtd, from, blocksize, &read_len, block)))
++ goto done;
++ if (read_len != blocksize) {
++ ret = -EINVAL;
++ goto done;
++ }
++ }
++
++ /* Copy input data into holding block */
++ copy_len = min(len, blocksize - (offset & mask));
++ memcpy(block + (offset & mask), ptr, copy_len);
++ off = (uint) from;
++ /* Erase block */
++ if ((ret = bcm47xx_nflash_erase(mtd, off, blocksize)) < 0)
++ goto done;
++ /* Write holding block */
++ write_ptr = block;
++ write_len = blocksize;
++ if ((bytes = bcma_nflash_write(nflash->bcc, (uint)from, (uint)write_len, (u8 *) write_ptr)) != 0) {
++ ret = bytes;
++ goto done;
++ }
++ offset += copy_len;
++ if (len < copy_len)
++ len = 0;
++ else
++ len -= copy_len;
++ ptr += copy_len;
++ }
++
++done:
++ if (block)
++ kfree(block);
++ return;
++}
++
++static int bcm47xx_nflash_erase(struct mtd_info *mtd, unsigned int addr, unsigned int len)
++{
++ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
++ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
++
++ /* Check address range */
++ if (!len)
++ return 1;
++ if ((addr + len) > mtd->size)
++ return 1;
++
++ if (bcma_nflash_erase(nflash->bcc, addr)) {
++ pr_err("ERASE: nflash erase error\n");
++ return 1;
++ }
++
++ if (nflash_mtd_poll(nflash, addr, 10 * HZ)) {
++ pr_err("ERASE: nflash_mtd_poll error\n");
++ return 1;
++ }
++
++ return 0;
++}
++
++/* This functions is used by upper layer to checks if device is ready */
++static int bcm47xx_nflash_dev_ready(struct mtd_info *mtd)
++{
++ return 1;
++}
++
++/* Issue a nand flash command */
++static inline void bcm47xx_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
++{
++ bcma_cc_write32(cc, NAND_CMD_START, opcode);
++ bcma_cc_read32(cc, NAND_CMD_START);
++}
++
++static void bcm47xx_nflash_command(struct mtd_info *mtd, unsigned command,
++ int column, int page_addr)
++{
++ struct nand_chip *nchip = (struct nand_chip *)mtd->priv;
++ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
++ u32 pagesize = 1 << nchip->page_shift;
++
++ /* Command pre-processing step */
++ switch (command) {
++ case NAND_CMD_RESET:
++ bcm47xx_nflash_cmd(nflash->bcc, NCMD_FLASH_RESET);
++ break;
++
++ case NAND_CMD_STATUS:
++ nflash->next_opcode = NAND_CMD_STATUS;
++ read_offset = 0;
++ write_offset = 0;
++ break;
++
++ case NAND_CMD_READ0:
++ read_offset = page_addr * pagesize;
++ nflash->next_opcode = 0;
++ break;
++
++ case NAND_CMD_READOOB:
++ read_offset = page_addr * pagesize;
++ nflash->next_opcode = 0;
++ break;
++
++ case NAND_CMD_SEQIN:
++ write_offset = page_addr * pagesize;
++ nflash->next_opcode = 0;
++ break;
++
++ case NAND_CMD_PAGEPROG:
++ nflash->next_opcode = 0;
++ break;
++
++ case NAND_CMD_READID:
++ read_offset = column;
++ bcm47xx_nflash_cmd(nflash->bcc, NCMD_ID_RD);
++ nflash->next_opcode = NAND_DEVID;
++ break;
++
++ case NAND_CMD_ERASE1:
++ nflash->next_opcode = 0;
++ bcm47xx_nflash_erase(mtd, page_addr*pagesize, pagesize);
++ break;
++
++ case NAND_CMD_ERASE2:
++ break;
++
++ case NAND_CMD_RNDOUT:
++ if (column > mtd->writesize)
++ read_offset += (column - mtd->writesize);
++ else
++ read_offset += column;
++ break;
++
++ default:
++ pr_err("COMMAND not supported %x\n", command);
++ nflash->next_opcode = 0;
++ break;
++ }
++}
++
++/* This function is used by upper layer for select and
++ * deselect of the NAND chip.
++ * It is dummy function. */
++static void bcm47xx_nflash_select_chip(struct mtd_info *mtd, int chip)
++{
++}
++
++static u_char bcm47xx_nflash_read_byte(struct mtd_info *mtd)
++{
++ struct nand_chip *nchip = mtd->priv;
++ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
++ uint8_t ret = 0;
++ static u32 id;
++
++ if (nflash->next_opcode == 0)
++ return ret;
++
++ if (nflash->next_opcode == NAND_CMD_STATUS)
++ return NAND_STATUS_WP;
++
++ id = bcma_cc_read32(nflash->bcc, nflash->next_opcode);
++
++ if (nflash->next_opcode == NAND_DEVID) {
++ ret = (id >> (8*read_offset)) & 0xff;
++ read_offset++;
++ }
++
++ return ret;
++}
++
++static uint16_t bcm47xx_nflash_read_word(struct mtd_info *mtd)
++{
++ loff_t from = read_offset;
++ uint16_t buf = 0;
++ int bytes;
++
++ bcm47xx_nflash_read(mtd, from, sizeof(buf), &bytes, (u_char *)&buf);
++ return buf;
++}
++
++/* Write data of length len to buffer buf. The data to be
++ * written on NAND Flash is first copied to RAMbuffer. After the Data Input
++ * Operation by the NFC, the data is written to NAND Flash */
++static void bcm47xx_nflash_write_buf(struct mtd_info *mtd,
++ const u_char *buf, int len)
++{
++ bcm47xx_nflash_write(mtd, write_offset, buf, len);
++}
++
++/* Read the data buffer from the NAND Flash. To read the data from NAND
++ * Flash first the data output cycle is initiated by the NFC, which copies
++ * the data to RAMbuffer. This data of length len is then copied to buffer buf.
++ */
++static void bcm47xx_nflash_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++ loff_t from = read_offset;
++ int bytes;
++
++ bcm47xx_nflash_read(mtd, from, len, &bytes, buf);
++}
++
++/* Used by the upper layer to verify the data in NAND Flash
++ * with the data in the buf. */
++static int bcm47xx_nflash_verify_buf(struct mtd_info *mtd,
++ const u_char *buf, int len)
++{
++ return -EFAULT;
++}
++
++static int bcm47xx_nflash_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
++{
++ struct nand_chip *nchip = mtd->priv;
++ struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv;
++ int i;
++ uint off;
++ u32 pagesize = 1 << nchip->page_shift;
++ u32 blocksize = mtd->erasesize;
++
++ if ((ofs >> 20) >= nflash->size)
++ return 1;
++ if ((ofs & (blocksize - 1)) != 0)
++ return 1;
++
++ for (i = 0; i < 2; i++) {
++ off = ofs + pagesize;
++ bcma_cc_write32(nflash->bcc, NAND_CMD_ADDR, off);
++ bcm47xx_nflash_cmd(nflash->bcc, NCMD_SPARE_RD);
++ if (bcma_nflash_poll(nflash->bcc) < 0)
++ break;
++ if ((bcma_cc_read32(nflash->bcc, NAND_INTFC_STATUS) & NIST_SPARE_VALID) != NIST_SPARE_VALID)
++ return 1;
++ if ((bcma_cc_read32(nflash->bcc, NAND_SPARE_RD0) & 0xff) != 0xff)
++ return 1;
++ }
++ return 0;
++}
++
++const char *part_probes[] = { "cmdlinepart", NULL };
++static int bcm47xx_nflash_probe(struct platform_device *pdev)
++{
++ struct nand_chip *nchip;
++ struct mtd_info *mtd;
++ struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev);
++ int ret = 0;
++
++ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
++ if (!mtd){
++ ret = -ENOMEM;
++ goto err_out;
++ }
++
++ nchip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
++ if (!nchip) {
++ ret = -ENOMEM;
++ goto err_free_mtd;
++ }
++
++ /* Register with MTD */
++ mtd->priv = nchip;
++ mtd->owner = THIS_MODULE;
++ mtd->dev.parent = &pdev->dev;
++
++ /* 50 us command delay time */
++ nchip->chip_delay = 50;
++
++ nchip->priv = nflash;
++ nchip->dev_ready = bcm47xx_nflash_dev_ready;
++ nchip->cmdfunc = bcm47xx_nflash_command;
++ nchip->select_chip = bcm47xx_nflash_select_chip;
++ nchip->read_byte = bcm47xx_nflash_read_byte;
++ nchip->read_word = bcm47xx_nflash_read_word;
++ nchip->write_buf = bcm47xx_nflash_write_buf;
++ nchip->read_buf = bcm47xx_nflash_read_buf;
++ nchip->verify_buf = bcm47xx_nflash_verify_buf;
++ nchip->block_bad = bcm47xx_nflash_block_bad;
++ nchip->options = NAND_SKIP_BBTSCAN;
++
++ /* Not known */
++ nchip->ecc.mode = NAND_ECC_NONE;
++
++ /* first scan to find the device and get the page size */
++ if (nand_scan_ident(mtd, 1, NULL)) {
++ pr_err("nand_scan_ident failed\n");
++ ret = -ENXIO;
++ goto err_free_nchip;
++ }
++ nflash->size = mtd->size;
++ nflash->pagesize = 1 << nchip->page_shift;
++ nflash->blocksize = mtd->erasesize;
++ nflash->mtd = mtd;
++
++ /* second phase scan */
++ if (nand_scan_tail(mtd)) {
++ pr_err("nand_scan_tail failed\n");
++ ret = -ENXIO;
++ goto err_free_nchip;
++ }
++
++ mtd->name = "bcm47xx-nflash";
++ mtd->flags |= MTD_WRITEABLE;
++ ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
++
++ if (ret) {
++ pr_err("mtd_device_register failed\n");
++ goto err_free_nchip;
++ }
++
++ return 0;
++
++err_free_nchip:
++ kfree(nchip);
++err_free_mtd:
++ kfree(mtd);
++err_out:
++ return ret;
++}
++
++static int __devexit bcm47xx_nflash_remove(struct platform_device *pdev)
++{
++ struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev);
++ struct mtd_info *mtd = nflash->mtd;
++
++ if (nflash) {
++ /* Release resources, unregister device */
++ nand_release(mtd);
++ kfree(mtd->priv);
++ kfree(mtd);
++ }
++
++ return 0;
++}
++
++static const struct platform_device_id bcm47xx_nflash_table[] = {
++ { "bcm47xx-nflash", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(platform, bcm47xx_nflash_table);
++
++static struct platform_driver bcm47xx_nflash_driver = {
++ .id_table = bcm47xx_nflash_table,
++ .probe = bcm47xx_nflash_probe,
++ .remove = __devexit_p(bcm47xx_nflash_remove),
++ .driver = {
++ .name = "bcm47xx-nflash",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init init_bcm47xx_nflash(void)
++{
++ int ret = platform_driver_register(&bcm47xx_nflash_driver);
++
++ if (ret)
++ pr_err("error registering platform driver: %i\n", ret);
++ return ret;
++}
++
++static void __exit exit_bcm47xx_nflash(void)
++{
++ platform_driver_unregister(&bcm47xx_nflash_driver);
++}
++
++module_init(init_bcm47xx_nflash);
++module_exit(exit_bcm47xx_nflash);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("BCM47XX NAND flash driver");
+--- /dev/null
++++ b/include/linux/mtd/bcm47xx_nand.h
+@@ -0,0 +1,152 @@
++/*
++ * Broadcom chipcommon NAND flash interface
++ *
++ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com>
++ * Copyright (C) 2009, 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.
++ *
++ */
++
++#ifndef LINUX_MTD_BCM47XX_NAND_H_
++#define LINUX_MTD_BCM47XX_NAND_H_
++
++#include <linux/mtd/mtd.h>
++
++#define NAND_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
++
++/* nand_cmd_start commands */
++#define NCMD_NULL 0
++#define NCMD_PAGE_RD 1
++#define NCMD_SPARE_RD 2
++#define NCMD_STATUS_RD 3
++#define NCMD_PAGE_PROG 4
++#define NCMD_SPARE_PROG 5
++#define NCMD_COPY_BACK 6
++#define NCMD_ID_RD 7
++#define NCMD_BLOCK_ERASE 8
++#define NCMD_FLASH_RESET 9
++#define NCMD_LOCK 0xa
++#define NCMD_LOCK_DOWN 0xb
++#define NCMD_UNLOCK 0xc
++#define NCMD_LOCK_STATUS 0xd
++
++/* nand_acc_control */
++#define NAC_RD_ECC_EN 0x80000000
++#define NAC_WR_ECC_EN 0x40000000
++#define NAC_RD_ECC_BLK0_EN 0x20000000
++#define NAC_FAST_PGM_RDIN 0x10000000
++#define NAC_RD_ERASED_ECC_EN 0x08000000
++#define NAC_PARTIAL_PAGE_EN 0x04000000
++#define NAC_PAGE_HIT_EN 0x01000000
++#define NAC_ECC_LEVEL0 0x00f00000
++#define NAC_ECC_LEVEL 0x000f0000
++#define NAC_SPARE_SIZE0 0x00003f00
++#define NAC_SPARE_SIZE 0x0000003f
++
++/* nand_config */
++#define NCF_CONFIG_LOCK 0x80000000
++#define NCF_BLOCK_SIZE_MASK 0x70000000
++#define NCF_BLOCK_SIZE_SHIFT 28
++#define NCF_DEVICE_SIZE_MASK 0x0f000000
++#define NCF_DEVICE_SIZE_SHIFT 24
++#define NCF_DEVICE_WIDTH 0x00800000
++#define NCF_PAGE_SIZE_MASK 0x00300000
++#define NCF_PAGE_SIZE_SHIFT 20
++#define NCF_FULL_ADDR_BYTES_MASK 0x00070000
++#define NCF_FULL_ADDR_BYTES_SHIFT 16
++#define NCF_COL_ADDR_BYTES_MASK 0x00007000
++#define NCF_COL_ADDR_BYTES_SHIFT 12
++#define NCF_BLK_ADDR_BYTES_MASK 0x00000700
++#define NCF_BLK_ADDR_BYTES_SHIFT 8
++
++/* nand_intfc_status */
++#define NIST_CTRL_READY 0x80000000
++#define NIST_FLASH_READY 0x40000000
++#define NIST_CACHE_VALID 0x20000000
++#define NIST_SPARE_VALID 0x10000000
++#define NIST_ERASED 0x08000000
++#define NIST_STATUS 0x000000ff
++
++#define NFL_SECTOR_SIZE 512
++
++#define NFL_TABLE_END 0xffffffff
++#define NFL_BOOT_SIZE 0x200000
++#define NFL_BOOT_OS_SIZE 0x2000000
++
++/* Nand flash MLC controller registers (corerev >= 38) */
++#define NAND_REVISION 0xC00
++#define NAND_CMD_START 0xC04
++#define NAND_CMD_ADDR_X 0xC08
++#define NAND_CMD_ADDR 0xC0C
++#define NAND_CMD_END_ADDR 0xC10
++#define NAND_CS_NAND_SELECT 0xC14
++#define NAND_CS_NAND_XOR 0xC18
++#define NAND_SPARE_RD0 0xC20
++#define NAND_SPARE_RD4 0xC24
++#define NAND_SPARE_RD8 0xC28
++#define NAND_SPARE_RD12 0xC2C
++#define NAND_SPARE_WR0 0xC30
++#define NAND_SPARE_WR4 0xC34
++#define NAND_SPARE_WR8 0xC38
++#define NAND_SPARE_WR12 0xC3C
++#define NAND_ACC_CONTROL 0xC40
++#define NAND_CONFIG 0xC48
++#define NAND_TIMING_1 0xC50
++#define NAND_TIMING_2 0xC54
++#define NAND_SEMAPHORE 0xC58
++#define NAND_DEVID 0xC60
++#define NAND_DEVID_X 0xC64
++#define NAND_BLOCK_LOCK_STATUS 0xC68
++#define NAND_INTFC_STATUS 0xC6C
++#define NAND_ECC_CORR_ADDR_X 0xC70
++#define NAND_ECC_CORR_ADDR 0xC74
++#define NAND_ECC_UNC_ADDR_X 0xC78
++#define NAND_ECC_UNC_ADDR 0xC7C
++#define NAND_READ_ERROR_COUNT 0xC80
++#define NAND_CORR_STAT_THRESHOLD 0xC84
++#define NAND_READ_ADDR_X 0xC90
++#define NAND_READ_ADDR 0xC94
++#define NAND_PAGE_PROGRAM_ADDR_X 0xC98
++#define NAND_PAGE_PROGRAM_ADDR 0xC9C
++#define NAND_COPY_BACK_ADDR_X 0xCA0
++#define NAND_COPY_BACK_ADDR 0xCA4
++#define NAND_BLOCK_ERASE_ADDR_X 0xCA8
++#define NAND_BLOCK_ERASE_ADDR 0xCAC
++#define NAND_INV_READ_ADDR_X 0xCB0
++#define NAND_INV_READ_ADDR 0xCB4
++#define NAND_BLK_WR_PROTECT 0xCC0
++#define NAND_ACC_CONTROL_CS1 0xCD0
++#define NAND_CONFIG_CS1 0xCD4
++#define NAND_TIMING_1_CS1 0xCD8
++#define NAND_TIMING_2_CS1 0xCDC
++#define NAND_SPARE_RD16 0xD30
++#define NAND_SPARE_RD20 0xD34
++#define NAND_SPARE_RD24 0xD38
++#define NAND_SPARE_RD28 0xD3C
++#define NAND_CACHE_ADDR 0xD40
++#define NAND_CACHE_DATA 0xD44
++#define NAND_CTRL_CONFIG 0xD48
++#define NAND_CTRL_STATUS 0xD4C
++
++struct bcma_drv_cc;
++
++struct bcm47xx_nflash {
++ struct bcma_drv_cc *bcc;
++
++ bool present;
++ bool boot; /* This is the flash the SoC boots from */
++ u32 blocksize; /* Block size */
++ u32 pagesize; /* Page size */
++
++ u32 size; /* Total size in bytes */
++ u32 next_opcode; /* Next expected command from upper NAND layer */
++
++ struct mtd_info *mtd;
++};
++
++#endif /* LINUX_MTD_BCM47XX_NAND_H_ */
diff --git a/target/linux/brcm47xx/patches-3.3/060-ssb-add-serial-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/060-ssb-add-serial-flash-driver.patch
new file mode 100644
index 000000000..d65fc0a5b
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/060-ssb-add-serial-flash-driver.patch
@@ -0,0 +1,527 @@
+--- a/drivers/ssb/Kconfig
++++ b/drivers/ssb/Kconfig
+@@ -143,6 +143,11 @@ config SSB_EMBEDDED
+ depends on SSB_DRIVER_MIPS
+ default y
+
++config SSB_SFLASH
++ bool
++ depends on SSB_DRIVER_MIPS
++ default y
++
+ config SSB_DRIVER_EXTIF
+ bool "SSB Broadcom EXTIF core driver"
+ depends on SSB_DRIVER_MIPS
+--- a/drivers/ssb/Makefile
++++ b/drivers/ssb/Makefile
+@@ -11,6 +11,7 @@ ssb-$(CONFIG_SSB_SDIOHOST) += sdio.o
+ # built-in drivers
+ ssb-y += driver_chipcommon.o
+ ssb-y += driver_chipcommon_pmu.o
++ssb-$(CONFIG_SSB_SFLASH) += driver_chipcommon_sflash.o
+ ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
+ ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
+ ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
+--- /dev/null
++++ b/drivers/ssb/driver_chipcommon_sflash.c
+@@ -0,0 +1,395 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon serial flash interface
++ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
++ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright 2010, Broadcom Corporation
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/ssb/ssb.h>
++#include <linux/ssb/ssb_driver_chipcommon.h>
++
++#include "ssb_private.h"
++
++#define NUM_RETRIES 3
++
++static struct resource ssb_sflash_resource = {
++ .name = "ssb_sflash",
++ .start = SSB_FLASH2,
++ .end = 0,
++ .flags = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device ssb_sflash_dev = {
++ .name = "bcm47xx-sflash",
++ .resource = &ssb_sflash_resource,
++ .num_resources = 1,
++};
++
++struct ssb_sflash_tbl_e {
++ char *name;
++ u32 id;
++ u32 blocksize;
++ u16 numblocks;
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
++ { "M25P20", 0x11, 0x10000, 4, },
++ { "M25P40", 0x12, 0x10000, 8, },
++
++ { "M25P16", 0x14, 0x10000, 32, },
++ { "M25P32", 0x14, 0x10000, 64, },
++ { "M25P64", 0x16, 0x10000, 128, },
++ { "M25FL128", 0x17, 0x10000, 256, },
++ { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
++ { "SST25WF512", 1, 0x1000, 16, },
++ { "SST25VF512", 0x48, 0x1000, 16, },
++ { "SST25WF010", 2, 0x1000, 32, },
++ { "SST25VF010", 0x49, 0x1000, 32, },
++ { "SST25WF020", 3, 0x1000, 64, },
++ { "SST25VF020", 0x43, 0x1000, 64, },
++ { "SST25WF040", 4, 0x1000, 128, },
++ { "SST25VF040", 0x44, 0x1000, 128, },
++ { "SST25VF040B", 0x8d, 0x1000, 128, },
++ { "SST25WF080", 5, 0x1000, 256, },
++ { "SST25VF080B", 0x8e, 0x1000, 256, },
++ { "SST25VF016", 0x41, 0x1000, 512, },
++ { "SST25VF032", 0x4a, 0x1000, 1024, },
++ { "SST25VF064", 0x4b, 0x1000, 2048, },
++ { 0 },
++};
++
++static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
++ { "AT45DB011", 0xc, 256, 512, },
++ { "AT45DB021", 0x14, 256, 1024, },
++ { "AT45DB041", 0x1c, 256, 2048, },
++ { "AT45DB081", 0x24, 256, 4096, },
++ { "AT45DB161", 0x2c, 512, 4096, },
++ { "AT45DB321", 0x34, 512, 8192, },
++ { "AT45DB642", 0x3c, 1024, 8192, },
++ { 0 },
++};
++
++static void ssb_sflash_cmd(struct ssb_chipcommon *chipco, u32 opcode)
++{
++ int i;
++ chipco_write32(chipco, SSB_CHIPCO_FLASHCTL,
++ SSB_CHIPCO_FLASHCTL_START | opcode);
++ for (i = 0; i < 1000; i++) {
++ if (!(chipco_read32(chipco, SSB_CHIPCO_FLASHCTL) &
++ SSB_CHIPCO_FLASHCTL_BUSY))
++ return;
++ cpu_relax();
++ }
++ pr_err("SFLASH control command failed (timeout)!\n");
++}
++
++static void ssb_sflash_write_u8(struct ssb_chipcommon *chipco, u32 offset, u8 byte)
++{
++ chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, offset);
++ chipco_write32(chipco, SSB_CHIPCO_FLASHDATA, byte);
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++static int ssb_sflash_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
++{
++ u8 *from, *to;
++ u32 cnt, i;
++ struct ssb_chipcommon *chipco = dev->scc;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > chipco->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;
++
++ from = (u8 *)KSEG0ADDR(SSB_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. */
++static int ssb_sflash_poll(struct bcm47xx_sflash *dev, u32 offset)
++{
++ struct ssb_chipcommon *chipco = dev->scc;
++
++ if (offset >= chipco->sflash.size)
++ return -22;
++
++ switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ /* Check for ST Write In Progress bit */
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_RDSR);
++ return chipco_read32(chipco, SSB_CHIPCO_FLASHDATA)
++ & SSB_CHIPCO_FLASHDATA_ST_WIP;
++ case SSB_CHIPCO_FLASHT_ATSER:
++ /* Check for Atmel Ready bit */
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++ return !(chipco_read32(chipco, SSB_CHIPCO_FLASHDATA)
++ & SSB_CHIPCO_FLASHDATA_AT_READY);
++ }
++
++ return 0;
++}
++
++
++static int sflash_st_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
++ const u8 *buf)
++{
++ int written = 1;
++ struct ssb_chipcommon *chipco = dev->scc;
++
++ /* Enable writes */
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_WREN);
++ ssb_sflash_write_u8(chipco, offset, *buf++);
++ /* Issue a page program with CSA bit set */
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_CSA | SSB_CHIPCO_FLASHCTL_ST_PP);
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, poll droping cs and return */
++ chipco_write32(chipco, SSB_CHIPCO_FLASHCTL, 0);
++ udelay(1);
++ if (!ssb_sflash_poll(dev, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return written;
++ } else {
++ /* Write single byte */
++ ssb_sflash_cmd(chipco,
++ SSB_CHIPCO_FLASHCTL_ST_CSA |
++ *buf++);
++ }
++ written++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs & poll */
++ chipco_write32(chipco, SSB_CHIPCO_FLASHCTL, 0);
++ udelay(1);
++ if (!ssb_sflash_poll(dev, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return written;
++}
++
++static int sflash_at_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct ssb_chipcommon *chipco = dev->scc;
++ u32 page, byte, mask;
++ int ret = 0;
++
++ mask = dev->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < dev->blocksize)) {
++ int i = 100;
++ chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, page);
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ while (i > 0 && ssb_sflash_poll(dev, offset)) {
++ udelay(10);
++ i--;
++ }
++ BUG_ON(!ssb_sflash_poll(dev, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < dev->blocksize); ret++) {
++ ssb_sflash_write_u8(chipco, byte++, *buf++);
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, page);
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM);
++
++ return ret;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++static int ssb_sflash_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
++ const u8 *buf)
++{
++ int ret = 0, tries = NUM_RETRIES;
++ struct ssb_chipcommon *chipco = dev->scc;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > chipco->sflash.size)
++ return -EINVAL;
++
++ switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ do {
++ ret = sflash_st_write(dev, 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 SSB_CHIPCO_FLASHT_ATSER:
++ ret = sflash_at_write(dev, offset, len, buf);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++static int ssb_sflash_erase(struct bcm47xx_sflash *dev, u32 offset)
++{
++ struct ssb_chipcommon *chipco = dev->scc;
++
++ if (offset >= chipco->sflash.size)
++ return -EINVAL;
++
++ switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_WREN);
++ chipco_write32(chipco, SSB_CHIPCO_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.
++ */
++ if (dev->blocksize < (64 * 1024))
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_SSE);
++ else
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_SE);
++ return dev->blocksize;
++ case SSB_CHIPCO_FLASHT_ATSER:
++ chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, offset << 1);
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE);
++ return dev->blocksize;
++ }
++
++ return 0;
++}
++
++/* Initialize serial flash achipcoess */
++int ssb_sflash_init(struct ssb_chipcommon *chipco)
++{
++ struct bcm47xx_sflash *sflash = &chipco->sflash;
++ const struct ssb_sflash_tbl_e *e;
++ u32 id, id2;
++
++ switch (chipco->capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_DP);
++
++ chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, 0);
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_RES);
++ id = chipco_read32(chipco, SSB_CHIPCO_FLASHDATA);
++
++ chipco_write32(chipco, SSB_CHIPCO_FLASHADDR, 1);
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_ST_RES);
++ id2 = chipco_read32(chipco, SSB_CHIPCO_FLASHDATA);
++
++ switch (id) {
++ case 0xbf:
++ for (e = ssb_sflash_sst_tbl; e->name; e++) {
++ if (e->id == id2)
++ break;
++ }
++ break;
++ case 0x13:
++ return -ENOTSUPP;
++ default:
++ for (e = ssb_sflash_st_tbl; e->name; e++) {
++ if (e->id == id)
++ break;
++ }
++ break;
++ }
++ if (!e->name) {
++ pr_err("Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2);
++ return -ENOTSUPP;
++ }
++
++ break;
++ case SSB_CHIPCO_FLASHT_ATSER:
++ ssb_sflash_cmd(chipco, SSB_CHIPCO_FLASHCTL_AT_STATUS);
++ id = chipco_read32(chipco, SSB_CHIPCO_FLASHDATA) & 0x3c;
++
++ for (e = ssb_sflash_at_tbl; e->name; e++) {
++ if (e->id == id)
++ break;
++ }
++ if (!e->name) {
++ pr_err("Unsupported Atmel serial flash (id: 0x%X)\n", id);
++ return -ENOTSUPP;
++ }
++
++ break;
++ default:
++ pr_err("Unsupported flash type\n");
++ return -ENOTSUPP;
++ }
++
++ sflash->window = SSB_FLASH2;
++ sflash->blocksize = e->blocksize;
++ sflash->numblocks = e->numblocks;
++ sflash->size = sflash->blocksize * sflash->numblocks;
++ sflash->present = true;
++ sflash->read = ssb_sflash_read;
++ sflash->poll = ssb_sflash_poll;
++ sflash->write = ssb_sflash_write;
++ sflash->erase = ssb_sflash_erase;
++ sflash->type = BCM47XX_SFLASH_SSB;
++ sflash->scc = chipco;
++
++ pr_info("Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
++ e->name, sflash->size / 1024, sflash->blocksize,
++ sflash->numblocks);
++
++ /* Prepare platform device, but don't register it yet. It's too early,
++ * malloc (required by device_private_init) is not available yet. */
++ ssb_sflash_dev.resource[0].end = ssb_sflash_dev.resource[0].start +
++ sflash->size;
++ ssb_sflash_dev.dev.platform_data = sflash;
++
++ return 0;
++}
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -203,7 +203,8 @@ static void ssb_mips_flash_detect(struct
+ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
+ case SSB_CHIPCO_FLASHT_STSER:
+ case SSB_CHIPCO_FLASHT_ATSER:
+- pr_err("Serial flash not supported\n");
++ pr_debug("Found serial flash\n");
++ ssb_sflash_init(&bus->chipco);
+ break;
+ case SSB_CHIPCO_FLASHT_PARA:
+ pr_debug("Found parallel flash\n");
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -18,6 +18,7 @@
+ #include <linux/ssb/ssb_driver_gige.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/pci.h>
++#include <linux/platform_device.h>
+ #include <linux/mmc/sdio_func.h>
+ #include <linux/slab.h>
+
+@@ -534,6 +535,15 @@ static int ssb_devices_register(struct s
+ dev_idx++;
+ }
+
++#ifdef CONFIG_SSB_SFLASH
++ if (bus->chipco.sflash.present) {
++ err = platform_device_register(&ssb_sflash_dev);
++ if (err)
++ ssb_printk(KERN_ERR PFX
++ "Error registering serial flash\n");
++ }
++#endif
++
+ return 0;
+ error:
+ /* Unwind the already registered devices. */
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -211,4 +211,16 @@ static inline void b43_pci_ssb_bridge_ex
+ extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc);
+ extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc);
+
++#ifdef CONFIG_SSB_SFLASH
++/* driver_chipcommon_sflash.c */
++int ssb_sflash_init(struct ssb_chipcommon *chipco);
++extern struct platform_device ssb_sflash_dev;
++#else
++static inline int ssb_sflash_init(struct ssb_chipcommon *chipco)
++{
++ pr_err("Serial flash not supported\n");
++ return 0;
++}
++#endif /* CONFIG_SSB_SFLASH */
++
+ #endif /* LINUX_SSB_PRIVATE_H_ */
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -13,6 +13,8 @@
+ * Licensed under the GPL version 2. See COPYING for details.
+ */
+
++#include <linux/mtd/bcm47xx_sflash.h>
++
+ /** ChipCommon core registers. **/
+
+ #define SSB_CHIPCO_CHIPID 0x0000
+@@ -121,6 +123,17 @@
+ #define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START
+ #define SSB_CHIPCO_FLASHADDR 0x0044
+ #define SSB_CHIPCO_FLASHDATA 0x0048
++/* Status register bits for ST flashes */
++#define SSB_CHIPCO_FLASHDATA_ST_WIP 0x01 /* Write In Progress */
++#define SSB_CHIPCO_FLASHDATA_ST_WEL 0x02 /* Write Enable Latch */
++#define SSB_CHIPCO_FLASHDATA_ST_BP_MASK 0x1c /* Block Protect */
++#define SSB_CHIPCO_FLASHDATA_ST_BP_SHIFT 2
++#define SSB_CHIPCO_FLASHDATA_ST_SRWD 0x80 /* Status Register Write Disable */
++/* Status register bits for Atmel flashes */
++#define SSB_CHIPCO_FLASHDATA_AT_READY 0x80
++#define SSB_CHIPCO_FLASHDATA_AT_MISMATCH 0x40
++#define SSB_CHIPCO_FLASHDATA_AT_ID_MASK 0x38
++#define SSB_CHIPCO_FLASHDATA_AT_ID_SHIFT 3
+ #define SSB_CHIPCO_BCAST_ADDR 0x0050
+ #define SSB_CHIPCO_BCAST_DATA 0x0054
+ #define SSB_CHIPCO_GPIOPULLUP 0x0058 /* Rev >= 20 only */
+@@ -503,7 +516,7 @@
+ #define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
+ #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
+ #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
+-#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
++#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00D9 /* Deep Power-down */
+ #define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
+ #define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
+ #define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
+@@ -591,6 +604,9 @@ struct ssb_chipcommon {
+ /* Fast Powerup Delay constant */
+ u16 fast_pwrup_delay;
+ struct ssb_chipcommon_pmu pmu;
++#ifdef CONFIG_SSB_SFLASH
++ struct bcm47xx_sflash sflash;
++#endif
+ };
+
+ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
diff --git a/target/linux/brcm47xx/patches-3.3/061-ssb-register-parallel-flash-device.patch b/target/linux/brcm47xx/patches-3.3/061-ssb-register-parallel-flash-device.patch
new file mode 100644
index 000000000..6e0d49184
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/061-ssb-register-parallel-flash-device.patch
@@ -0,0 +1,76 @@
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -14,6 +14,7 @@
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+ #include <linux/time.h>
++#include <linux/platform_device.h>
+
+ #include "ssb_private.h"
+
+@@ -186,6 +187,19 @@ static void ssb_mips_serial_init(struct
+ mcore->nr_serial_ports = 0;
+ }
+
++static struct resource ssb_pflash_resource = {
++ .name = "ssb_pflash",
++ .start = 0,
++ .end = 0,
++ .flags = 0,
++};
++
++struct platform_device ssb_pflash_dev = {
++ .name = "bcm47xx-pflash",
++ .resource = &ssb_pflash_resource,
++ .num_resources = 1,
++};
++
+ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
+ {
+ struct ssb_bus *bus = mcore->dev->bus;
+@@ -196,6 +210,9 @@ static void ssb_mips_flash_detect(struct
+ mcore->pflash.buswidth = 2;
+ mcore->pflash.window = SSB_FLASH1;
+ mcore->pflash.window_size = SSB_FLASH1_SZ;
++ ssb_pflash_resource.start = mcore->pflash.window;
++ ssb_pflash_resource.end = mcore->pflash.window +
++ mcore->pflash.window_size;
+ return;
+ }
+
+@@ -216,6 +233,9 @@ static void ssb_mips_flash_detect(struct
+ mcore->pflash.buswidth = 1;
+ else
+ mcore->pflash.buswidth = 2;
++ ssb_pflash_resource.start = mcore->pflash.window;
++ ssb_pflash_resource.end = mcore->pflash.window +
++ mcore->pflash.window_size;
+ break;
+ }
+ }
+--- a/drivers/ssb/main.c
++++ b/drivers/ssb/main.c
+@@ -543,6 +543,14 @@ static int ssb_devices_register(struct s
+ "Error registering serial flash\n");
+ }
+ #endif
++#ifdef CONFIG_SSB_DRIVER_MIPS
++ if (bus->mipscore.pflash.present) {
++ err = platform_device_register(&ssb_pflash_dev);
++ if (err)
++ ssb_printk(KERN_ERR PFX
++ "Error registering parallel flash\n");
++ }
++#endif
+
+ return 0;
+ error:
+--- a/drivers/ssb/ssb_private.h
++++ b/drivers/ssb/ssb_private.h
+@@ -223,4 +223,6 @@ static inline int ssb_sflash_init(struct
+ }
+ #endif /* CONFIG_SSB_SFLASH */
+
++extern struct platform_device ssb_pflash_dev;
++
+ #endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/target/linux/brcm47xx/patches-3.3/070-bcma-add-functions-to-write-to-serial-flash.patch b/target/linux/brcm47xx/patches-3.3/070-bcma-add-functions-to-write-to-serial-flash.patch
new file mode 100644
index 000000000..8fb70d68f
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/070-bcma-add-functions-to-write-to-serial-flash.patch
@@ -0,0 +1,345 @@
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -1,15 +1,22 @@
+ /*
+ * Broadcom specific AMBA
+ * ChipCommon serial flash interface
++ * Copyright 2011, Jonas Gorski <jonas.gorski@gmail.com>
++ * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright 2010, Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+ #include <linux/platform_device.h>
++#include <linux/delay.h>
+ #include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_driver_chipcommon.h>
+
+ #include "bcma_private.h"
+
++#define NUM_RETRIES 3
++
+ static struct resource bcma_sflash_resource = {
+ .name = "bcma_sflash",
+ .start = BCMA_SOC_FLASH2,
+@@ -18,7 +25,7 @@ static struct resource bcma_sflash_resou
+ };
+
+ struct platform_device bcma_sflash_dev = {
+- .name = "bcma_sflash",
++ .name = "bcm47xx-sflash",
+ .resource = &bcma_sflash_resource,
+ .num_resources = 1,
+ };
+@@ -30,7 +37,7 @@ struct bcma_sflash_tbl_e {
+ u16 numblocks;
+ };
+
+-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+ { "M25P20", 0x11, 0x10000, 4, },
+ { "M25P40", 0x12, 0x10000, 8, },
+
+@@ -41,7 +48,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
+ { 0 },
+ };
+
+-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+ { "SST25WF512", 1, 0x1000, 16, },
+ { "SST25VF512", 0x48, 0x1000, 16, },
+ { "SST25WF010", 2, 0x1000, 32, },
+@@ -59,7 +66,7 @@ static struct bcma_sflash_tbl_e bcma_sfl
+ { 0 },
+ };
+
+-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+ { "AT45DB011", 0xc, 256, 512, },
+ { "AT45DB021", 0x14, 256, 1024, },
+ { "AT45DB041", 0x1c, 256, 2048, },
+@@ -84,12 +91,230 @@ static void bcma_sflash_cmd(struct bcma_
+ bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
+ }
+
++static 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);
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++static int bcma_sflash_read(struct bcm47xx_sflash *dev, u32 offset, u32 len, u8 *buf)
++{
++ u8 *from, *to;
++ u32 cnt, i;
++ struct bcma_drv_cc *cc = dev->bcc;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->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;
++
++ from = (u8 *)KSEG0ADDR(BCMA_SOC_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. */
++static int bcma_sflash_poll(struct bcm47xx_sflash *dev, u32 offset)
++{
++ struct bcma_drv_cc *cc = dev->bcc;
++
++ if (offset >= cc->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 bcm47xx_sflash *dev, u32 offset, u32 len,
++ const u8 *buf)
++{
++ int written = 1;
++ struct bcma_drv_cc *cc = dev->bcc;
++
++ /* Enable writes */
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_WREN);
++ 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);
++ 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(dev, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return written;
++ } else {
++ /* Write single byte */
++ bcma_sflash_cmd(cc,
++ BCMA_CC_FLASHCTL_ST_CSA |
++ *buf++);
++ }
++ written++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs & poll */
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL, 0);
++ udelay(1);
++ if (!bcma_sflash_poll(dev, offset)) {
++ /* Flash rejected command */
++ return -EAGAIN;
++ }
++ return written;
++}
++
++static int sflash_at_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
++ const u8 *buf)
++{
++ struct bcma_drv_cc *cc = dev->bcc;
++ u32 page, byte, mask;
++ int ret = 0;
++
++ mask = dev->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < dev->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(dev, offset)) {
++ udelay(10);
++ i--;
++ }
++ BUG_ON(!bcma_sflash_poll(dev, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < dev->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.
++ */
++static int bcma_sflash_write(struct bcm47xx_sflash *dev, u32 offset, u32 len,
++ const u8 *buf)
++{
++ int ret = 0, tries = NUM_RETRIES;
++ struct bcma_drv_cc *cc = dev->bcc;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > cc->sflash.size)
++ return -EINVAL;
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ do {
++ ret = sflash_st_write(dev, offset, len, buf);
++ tries--;
++ } while (ret == -EAGAIN && tries > 0);
++
++ if (ret == -EAGAIN && tries == 0) {
++ bcma_info(cc->core->bus, "ST Flash rejected write\n");
++ ret = -EIO;
++ }
++ break;
++ case BCMA_CC_FLASHT_ATSER:
++ ret = sflash_at_write(dev, offset, len, buf);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++static int bcma_sflash_erase(struct bcm47xx_sflash *dev, u32 offset)
++{
++ struct bcma_drv_cc *cc = dev->bcc;
++
++ if (offset >= cc->sflash.size)
++ return -EINVAL;
++
++ 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.
++ */
++ if (dev->blocksize < (64 * 1024))
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SSE);
++ else
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_ST_SE);
++ return dev->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 dev->blocksize;
++ }
++
++ return 0;
++}
++
+ /* Initialize serial flash access */
+ int bcma_sflash_init(struct bcma_drv_cc *cc)
+ {
+ struct bcma_bus *bus = cc->core->bus;
+- struct bcma_sflash *sflash = &cc->sflash;
+- struct bcma_sflash_tbl_e *e;
++ struct bcm47xx_sflash *sflash = &cc->sflash;
++ const struct bcma_sflash_tbl_e *e;
+ u32 id, id2;
+
+ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+@@ -150,6 +375,12 @@ int bcma_sflash_init(struct bcma_drv_cc
+ sflash->numblocks = e->numblocks;
+ sflash->size = sflash->blocksize * sflash->numblocks;
+ sflash->present = true;
++ sflash->read = bcma_sflash_read;
++ sflash->poll = bcma_sflash_poll;
++ sflash->write = bcma_sflash_write;
++ sflash->erase = bcma_sflash_erase;
++ sflash->type = BCM47XX_SFLASH_BCMA;
++ sflash->bcc = cc;
+
+ bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
+ e->name, sflash->size / 1024, sflash->blocksize,
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -1,6 +1,8 @@
+ #ifndef LINUX_BCMA_DRIVER_CC_H_
+ #define LINUX_BCMA_DRIVER_CC_H_
+
++#include <linux/mtd/bcm47xx_sflash.h>
++
+ /** ChipCommon core registers. **/
+ #define BCMA_CC_ID 0x0000
+ #define BCMA_CC_ID_ID 0x0000FFFF
+@@ -516,17 +518,6 @@ struct bcma_pflash {
+ u32 window_size;
+ };
+
+-#ifdef CONFIG_BCMA_SFLASH
+-struct bcma_sflash {
+- bool present;
+- u32 window;
+- u32 blocksize;
+- u16 numblocks;
+- u32 size;
+-
+- struct mtd_info *mtd;
+-};
+-#endif
+
+ #ifdef CONFIG_BCMA_NFLASH
+ struct mtd_info;
+@@ -561,7 +552,7 @@ struct bcma_drv_cc {
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash pflash;
+ #ifdef CONFIG_BCMA_SFLASH
+- struct bcma_sflash sflash;
++ struct bcm47xx_sflash sflash;
+ #endif
+ #ifdef CONFIG_BCMA_NFLASH
+ struct bcma_nflash nflash;
diff --git a/target/linux/brcm47xx/patches-3.3/071-bcma-add-functions-to-write-to-nand-flash.patch b/target/linux/brcm47xx/patches-3.3/071-bcma-add-functions-to-write-to-nand-flash.patch
new file mode 100644
index 000000000..27c667720
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/071-bcma-add-functions-to-write-to-nand-flash.patch
@@ -0,0 +1,232 @@
+--- a/drivers/bcma/driver_chipcommon_nflash.c
++++ b/drivers/bcma/driver_chipcommon_nflash.c
+@@ -2,16 +2,23 @@
+ * Broadcom specific AMBA
+ * ChipCommon NAND flash interface
+ *
++ * Copyright 2011, Tathagata Das <tathagata@alumnux.com>
++ * Copyright 2010, Broadcom Corporation
++ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
++#include <linux/delay.h>
++#include <linux/mtd/bcm47xx_nand.h>
++#include <linux/mtd/nand.h>
+ #include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_driver_chipcommon.h>
+
+ #include "bcma_private.h"
+
+ struct platform_device bcma_nflash_dev = {
+- .name = "bcma_nflash",
++ .name = "bcm47xx-nflash",
+ .num_resources = 0,
+ };
+
+@@ -31,6 +38,11 @@ int bcma_nflash_init(struct bcma_drv_cc
+ return -ENODEV;
+ }
+
++ if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
++ bcma_err(bus, "NAND flash support for BCM4706 not implemented\n");
++ return -ENOTSUPP;
++ }
++
+ cc->nflash.present = true;
+ if (cc->core->id.rev == 38 &&
+ (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
+@@ -42,3 +54,141 @@ int bcma_nflash_init(struct bcma_drv_cc
+
+ return 0;
+ }
++
++/* Issue a nand flash command */
++static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
++{
++ bcma_cc_write32(cc, NAND_CMD_START, opcode);
++ bcma_cc_read32(cc, NAND_CMD_START);
++}
++
++/* Check offset and length */
++static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, u32 len, u32 mask)
++{
++ if ((offset & mask) != 0 || (len & mask) != 0) {
++ pr_err("%s(): Address is not aligned. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
++ return 1;
++ }
++
++ if ((((offset + len) >> 20) >= cc->nflash.size) &&
++ (((offset + len) & ((1 << 20) - 1)) != 0)) {
++ pr_err("%s(): Address is outside Flash memory region. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask);
++ return 1;
++ }
++
++ return 0;
++}
++
++#define NF_RETRIES 1000000
++
++/* Poll for command completion. Returns zero when complete. */
++int bcma_nflash_poll(struct bcma_drv_cc *cc)
++{
++ u32 retries = NF_RETRIES;
++ u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY;
++ u32 mask;
++
++ while (retries--) {
++ mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask;
++ if (mask == pollmask)
++ return 0;
++ cpu_relax();
++ }
++
++ if (!retries) {
++ pr_err("bcma_nflash_poll: not ready\n");
++ return -1;
++ }
++
++ return 0;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf)
++{
++ u32 mask;
++ int i;
++ u32 *to, val, res;
++
++ mask = NFL_SECTOR_SIZE - 1;
++ if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
++ return 0;
++
++ to = (u32 *)buf;
++ res = len;
++ while (res > 0) {
++ bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
++ bcma_nflash_cmd(cc, NCMD_PAGE_RD);
++ if (bcma_nflash_poll(cc) < 0)
++ break;
++ val = bcma_cc_read32(cc, NAND_INTFC_STATUS);
++ if ((val & NIST_CACHE_VALID) == 0)
++ break;
++ bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
++ for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) {
++ *to = bcma_cc_read32(cc, NAND_CACHE_DATA);
++ }
++ res -= NFL_SECTOR_SIZE;
++ offset += NFL_SECTOR_SIZE;
++ }
++ return (len - res);
++}
++
++/* Write len bytes starting at offset into buf. Returns success (0) or failure (!0).
++ * Should poll for completion.
++ */
++int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len,
++ const u8 *buf)
++{
++ u32 mask;
++ int i;
++ u32 *from, res, reg;
++
++ mask = cc->nflash.pagesize - 1;
++ if (bcma_nflash_offset_is_valid(cc, offset, len, mask))
++ return 1;
++
++ /* disable partial page enable */
++ reg = bcma_cc_read32(cc, NAND_ACC_CONTROL);
++ reg &= ~NAC_PARTIAL_PAGE_EN;
++ bcma_cc_write32(cc, NAND_ACC_CONTROL, reg);
++
++ from = (u32 *)buf;
++ res = len;
++ while (res > 0) {
++ bcma_cc_write32(cc, NAND_CACHE_ADDR, 0);
++ for (i = 0; i < cc->nflash.pagesize; i += 4, from++) {
++ if (i % 512 == 0)
++ bcma_cc_write32(cc, NAND_CMD_ADDR, i);
++ bcma_cc_write32(cc, NAND_CACHE_DATA, *from);
++ }
++ bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize - 512);
++ bcma_nflash_cmd(cc, NCMD_PAGE_PROG);
++ if (bcma_nflash_poll(cc) < 0)
++ break;
++ res -= cc->nflash.pagesize;
++ offset += cc->nflash.pagesize;
++ }
++
++ if (res <= 0)
++ return 0;
++ else
++ return (len - res);
++}
++
++/* Erase a region. Returns success (0) or failure (-1).
++ * Poll for completion.
++ */
++int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset)
++{
++ if ((offset >> 20) >= cc->nflash.size)
++ return -1;
++ if ((offset & (cc->nflash.blocksize - 1)) != 0)
++ return -1;
++
++ bcma_cc_write32(cc, NAND_CMD_ADDR, offset);
++ bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE);
++ if (bcma_nflash_poll(cc) < 0)
++ return -1;
++ return 0;
++}
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -2,6 +2,7 @@
+ #define LINUX_BCMA_DRIVER_CC_H_
+
+ #include <linux/mtd/bcm47xx_sflash.h>
++#include <linux/mtd/bcm47xx_nand.h>
+
+ /** ChipCommon core registers. **/
+ #define BCMA_CC_ID 0x0000
+@@ -519,17 +520,6 @@ struct bcma_pflash {
+ };
+
+
+-#ifdef CONFIG_BCMA_NFLASH
+-struct mtd_info;
+-
+-struct bcma_nflash {
+- bool present;
+- bool boot; /* This is the flash the SoC boots from */
+-
+- struct mtd_info *mtd;
+-};
+-#endif
+-
+ struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+@@ -555,7 +545,7 @@ struct bcma_drv_cc {
+ struct bcm47xx_sflash sflash;
+ #endif
+ #ifdef CONFIG_BCMA_NFLASH
+- struct bcma_nflash nflash;
++ struct bcm47xx_nflash nflash;
+ #endif
+
+ int nr_serial_ports;
+@@ -613,4 +603,13 @@ extern void bcma_chipco_regctl_maskset(s
+ u32 offset, u32 mask, u32 set);
+ extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid);
+
++#ifdef CONFIG_BCMA_NFLASH
++/* Chipcommon nflash support. */
++int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf);
++int bcma_nflash_poll(struct bcma_drv_cc *cc);
++int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
++int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset);
++int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf);
++#endif
++
+ #endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/target/linux/brcm47xx/patches-3.3/072-bcma-register-parallel-flash-device.patch b/target/linux/brcm47xx/patches-3.3/072-bcma-register-parallel-flash-device.patch
new file mode 100644
index 000000000..cacb90343
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/072-bcma-register-parallel-flash-device.patch
@@ -0,0 +1,67 @@
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -45,6 +45,7 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ /* driver_chipcommon.c */
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_pflash_dev;
+ #endif /* CONFIG_BCMA_DRIVER_MIPS */
+
+ /* driver_chipcommon_pmu.c */
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -18,6 +18,7 @@
+ #include <linux/serial_core.h>
+ #include <linux/serial_reg.h>
+ #include <linux/time.h>
++#include <linux/platform_device.h>
+
+ /* The 47162a0 hangs when reading MIPS DMP registers registers */
+ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
+@@ -178,6 +179,19 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
+ }
+ EXPORT_SYMBOL(bcma_cpu_clock);
+
++static struct resource bcma_pflash_resource = {
++ .name = "bcma_pflash",
++ .start = 0,
++ .end = 0,
++ .flags = 0,
++};
++
++struct platform_device bcma_pflash_dev = {
++ .name = "bcm47xx-pflash",
++ .resource = &bcma_pflash_resource,
++ .num_resources = 1,
++};
++
+ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+ {
+ struct bcma_bus *bus = mcore->core->bus;
+@@ -200,6 +214,9 @@ static void bcma_core_mips_flash_detect(
+ cc->pflash.buswidth = 1;
+ else
+ cc->pflash.buswidth = 2;
++
++ bcma_pflash_resource.start = cc->pflash.window;
++ bcma_pflash_resource.end = cc->pflash.window + cc->pflash.window_size;
+ break;
+ default:
+ bcma_err(bus, "Flash type not supported\n");
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -149,6 +149,14 @@ static int bcma_register_cores(struct bc
+ dev_id++;
+ }
+
++#ifdef CONFIG_BCMA_DRIVER_MIPS
++ if (bus->drv_cc.pflash.present) {
++ err = platform_device_register(&bcma_pflash_dev);
++ if (err)
++ bcma_err(bus, "Error registering parallel flash\n");
++ }
++#endif
++
+ #ifdef CONFIG_BCMA_SFLASH
+ if (bus->drv_cc.sflash.present) {
+ err = platform_device_register(&bcma_sflash_dev);
diff --git a/target/linux/brcm47xx/patches-3.3/080-MIPS-BCM47XX-rewrite-nvram-probing.patch b/target/linux/brcm47xx/patches-3.3/080-MIPS-BCM47XX-rewrite-nvram-probing.patch
new file mode 100644
index 000000000..a271876fa
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.3/080-MIPS-BCM47XX-rewrite-nvram-probing.patch
@@ -0,0 +1,183 @@
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+- * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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
+@@ -23,69 +23,139 @@
+
+ static char nvram_buf[NVRAM_SPACE];
+
++static u32 find_nvram_size(u32 end)
++{
++ struct nvram_header *header;
++ u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
++ header = (struct nvram_header *)KSEG1ADDR(end - nvram_sizes[i]);
++ if (header->magic == NVRAM_HEADER)
++ return nvram_sizes[i];
++ }
++
++ return 0;
++}
++
+ /* Probe for NVRAM header */
+-static void early_nvram_init(void)
++static void early_nvram_init_fill(u32 base, u32 lim)
+ {
+-#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;
+- u32 lim = 0;
+ u32 off;
+ u32 *src, *dst;
++ u32 size;
+
+- switch (bcm47xx_bus_type) {
+-#ifdef CONFIG_BCM47XX_SSB
+- case BCM47XX_BUS_TYPE_SSB:
+- mcore_ssb = &bcm47xx_bus.ssb.mipscore;
+- base = mcore_ssb->pflash.window;
+- lim = mcore_ssb->pflash.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
+- }
+-
++ /* TODO: when nvram is on nand flash check for bad blocks first. */
+ off = FLASH_MIN;
+ while (off <= lim) {
+ /* Windowed flash access */
+- header = (struct nvram_header *)
+- KSEG1ADDR(base + off - NVRAM_SPACE);
+- if (header->magic == NVRAM_HEADER)
++ size = find_nvram_size(base + off);
++ if (size) {
++ header = (struct nvram_header *)KSEG1ADDR(base + off -
++ size);
+ goto found;
++ }
+ off <<= 1;
+ }
+
+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+ header = (struct nvram_header *) KSEG1ADDR(base + 4096);
+- if (header->magic == NVRAM_HEADER)
++ if (header->magic == NVRAM_HEADER) {
++ size = NVRAM_SPACE;
+ goto found;
++ }
+
+ header = (struct nvram_header *) KSEG1ADDR(base + 1024);
+- if (header->magic == NVRAM_HEADER)
++ if (header->magic == NVRAM_HEADER) {
++ size = NVRAM_SPACE;
+ goto found;
++ }
+
++ pr_err("no nvram found\n");
+ return;
+
+ found:
++
++ if (header->len > size)
++ pr_err("The nvram size accoridng to the header seems to be bigger than the partition on flash\n");
++ if (header->len > NVRAM_SPACE)
++ pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
++ header->len, NVRAM_SPACE);
++
+ src = (u32 *) header;
+ dst = (u32 *) nvram_buf;
+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
+ *dst++ = *src++;
+- for (; i < header->len && i < NVRAM_SPACE; i += 4)
++ for (; i < header->len && i < NVRAM_SPACE && i < size; i += 4)
+ *dst++ = le32_to_cpu(*src++);
+ }
+
++#ifdef CONFIG_BCM47XX_BCMA
++static void early_nvram_init_bcma(void)
++{
++ struct bcma_drv_cc *cc = &bcm47xx_bus.bcma.bus.drv_cc;
++ u32 base = 0;
++ u32 lim = 0;
++
++ if (cc->nflash.boot) {
++ base = BCMA_SOC_FLASH1;
++ lim = BCMA_SOC_FLASH1_SZ;
++ } else if (cc->pflash.present) {
++ base = cc->pflash.window;
++ lim = cc->pflash.window_size;
++ } else if (cc->sflash.present) {
++ base = cc->sflash.window;
++ lim = cc->sflash.size;
++ } else {
++ pr_err("No supported flash found\n");
++ return;
++ }
++
++ early_nvram_init_fill(base, lim);
++}
++#endif
++
++#ifdef CONFIG_BCM47XX_SSB
++static void early_nvram_init_ssb(void)
++{
++ struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
++ struct ssb_chipcommon *chipco = &bcm47xx_bus.ssb.chipco;
++ u32 base = 0;
++ u32 lim = 0;
++
++ if (mcore->pflash.present) {
++ base = mcore->pflash.window;
++ lim = mcore->pflash.window_size;
++ } else if (chipco->sflash.present) {
++ base = chipco->sflash.window;
++ lim = chipco->sflash.size;
++ } else {
++ pr_err("No supported flash found\n");
++ return;
++ }
++
++ early_nvram_init_fill(base, lim);
++}
++#endif
++
++static void early_nvram_init(void)
++{
++ switch (bcm47xx_bus_type) {
++#ifdef CONFIG_BCM47XX_SSB
++ case BCM47XX_BUS_TYPE_SSB:
++ early_nvram_init_ssb();
++ break;
++#endif
++#ifdef CONFIG_BCM47XX_BCMA
++ case BCM47XX_BUS_TYPE_BCMA:
++ early_nvram_init_bcma();
++ break;
++#endif
++ }
++}
++
+ int nvram_getenv(char *name, char *val, size_t val_len)
+ {
+ char *var, *value, *end, *eq;
diff --git a/target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch b/target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch
index 901397237..5e324e473 100644
--- a/target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch
+++ b/target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch
@@ -15,16 +15,16 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -33,6 +33,8 @@
+@@ -31,6 +31,8 @@
+ #include <linux/ssb/ssb.h>
#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>
-@@ -152,6 +154,31 @@ static int bcm47xx_get_invariants(struct
+@@ -121,6 +123,31 @@ static int bcm47xx_get_invariants(struct
return 0;
}
@@ -56,7 +56,7 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
static void __init bcm47xx_register_ssb(void)
{
int err;
-@@ -184,6 +211,10 @@ static void __init bcm47xx_register_ssb(
+@@ -150,6 +177,10 @@ static void __init bcm47xx_register_ssb(
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
}
}
@@ -65,5 +65,5 @@ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ bcm47xx_early_serial_setup(mcore);
+#endif
}
+ #endif
- static int __init bcm47xx_register_flash_ssb(void)
diff --git a/target/linux/brcm47xx/patches-3.3/194-MIPS-BCM47XX-read-sprom-without-prefix-if-no-ieee802.patch b/target/linux/brcm47xx/patches-3.3/194-MIPS-BCM47XX-read-sprom-without-prefix-if-no-ieee802.patch
index 69d034cca..9487d301f 100644
--- a/target/linux/brcm47xx/patches-3.3/194-MIPS-BCM47XX-read-sprom-without-prefix-if-no-ieee802.patch
+++ b/target/linux/brcm47xx/patches-3.3/194-MIPS-BCM47XX-read-sprom-without-prefix-if-no-ieee802.patch
@@ -1,6 +1,6 @@
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -258,6 +258,8 @@ static int bcm47xx_get_sprom_bcma(struct
+@@ -206,6 +206,8 @@ static int bcm47xx_get_sprom_bcma(struct
snprintf(prefix, sizeof(prefix), "sb/%u/",
core->core_index);
bcm47xx_fill_sprom(out, prefix);
diff --git a/target/linux/brcm47xx/patches-3.3/195-MIPS-BCM47xx-sprom-read-values-without-prefix-as-fal.patch b/target/linux/brcm47xx/patches-3.3/195-MIPS-BCM47xx-sprom-read-values-without-prefix-as-fal.patch
index c486e68c0..6b1db2580 100644
--- a/target/linux/brcm47xx/patches-3.3/195-MIPS-BCM47xx-sprom-read-values-without-prefix-as-fal.patch
+++ b/target/linux/brcm47xx/patches-3.3/195-MIPS-BCM47xx-sprom-read-values-without-prefix-as-fal.patch
@@ -1,6 +1,6 @@
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -127,7 +127,7 @@ static int bcm47xx_get_sprom_ssb(struct
+@@ -96,7 +96,7 @@ static int bcm47xx_get_sprom_ssb(struct
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
@@ -9,7 +9,7 @@
return 0;
} else {
printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n");
-@@ -146,7 +146,7 @@ static int bcm47xx_get_invariants(struct
+@@ -115,7 +115,7 @@ static int bcm47xx_get_invariants(struct
bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
@@ -18,7 +18,7 @@
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
-@@ -248,18 +248,17 @@ static int bcm47xx_get_sprom_bcma(struct
+@@ -196,18 +196,17 @@ static int bcm47xx_get_sprom_bcma(struct
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
diff --git a/target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch b/target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch
deleted file mode 100644
index 6ef5ecd51..000000000
--- a/target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch
+++ /dev/null
@@ -1,181 +0,0 @@
---- a/drivers/bcma/driver_chipcommon.c
-+++ b/drivers/bcma/driver_chipcommon.c
-@@ -22,12 +22,9 @@ static inline u32 bcma_cc_write32_masked
- return value;
- }
-
--void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
-+void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
- {
-- u32 leddc_on = 10;
-- u32 leddc_off = 90;
--
-- if (cc->setup_done)
-+ if (cc->early_setup_done)
- return;
-
- if (cc->core->id.rev >= 11)
-@@ -36,6 +33,22 @@ void bcma_core_chipcommon_init(struct bc
- if (cc->core->id.rev >= 35)
- cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
-
-+ if (cc->capabilities & BCMA_CC_CAP_PMU)
-+ bcma_pmu_early_init(cc);
-+
-+ cc->early_setup_done = true;
-+}
-+
-+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
-+{
-+ u32 leddc_on = 10;
-+ u32 leddc_off = 90;
-+
-+ if (cc->setup_done)
-+ return;
-+
-+ bcma_core_chipcommon_early_init(cc);
-+
- if (cc->core->id.rev >= 20) {
- bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
- bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -141,7 +141,7 @@ void bcma_pmu_workarounds(struct bcma_dr
- }
- }
-
--void bcma_pmu_init(struct bcma_drv_cc *cc)
-+void bcma_pmu_early_init(struct bcma_drv_cc *cc)
- {
- u32 pmucap;
-
-@@ -150,7 +150,10 @@ void bcma_pmu_init(struct bcma_drv_cc *c
-
- bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
- cc->pmu.rev, pmucap);
-+}
-
-+void bcma_pmu_init(struct bcma_drv_cc *cc)
-+{
- if (cc->pmu.rev == 1)
- bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
- ~BCMA_CC_PMU_CTL_NOILPONW);
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -222,16 +222,33 @@ static void bcma_core_mips_flash_detect(
- }
- }
-
-+void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
-+{
-+ struct bcma_bus *bus = mcore->core->bus;
-+
-+ if (mcore->early_setup_done)
-+ return;
-+
-+ bcma_chipco_serial_init(&bus->drv_cc);
-+ bcma_core_mips_flash_detect(mcore);
-+
-+ mcore->early_setup_done = true;
-+}
-+
- void bcma_core_mips_init(struct bcma_drv_mips *mcore)
- {
- struct bcma_bus *bus;
- struct bcma_device *core;
- bus = mcore->core->bus;
-
-+ if (mcore->setup_done)
-+ return;
-+
- bcma_info(bus, "Initializing MIPS core...\n");
-
-- if (!mcore->setup_done)
-- mcore->assigned_irqs = 1;
-+ bcma_core_mips_early_init(mcore);
-+
-+ mcore->assigned_irqs = 1;
-
- /* Assign IRQs to all cores on the bus */
- list_for_each_entry(core, &bus->cores, list) {
-@@ -266,10 +283,5 @@ void bcma_core_mips_init(struct bcma_drv
- bcma_info(bus, "IRQ reconfiguration done\n");
- bcma_core_mips_dump_irq(bus);
-
-- if (mcore->setup_done)
-- return;
--
-- bcma_chipco_serial_init(&bus->drv_cc);
-- bcma_core_mips_flash_detect(mcore);
- mcore->setup_done = true;
- }
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -247,18 +247,18 @@ int __init bcma_bus_early_register(struc
- return -1;
- }
-
-- /* Init CC core */
-+ /* Early init CC core */
- core = bcma_find_core(bus, bcma_cc_core_id(bus));
- if (core) {
- bus->drv_cc.core = core;
-- bcma_core_chipcommon_init(&bus->drv_cc);
-+ bcma_core_chipcommon_early_init(&bus->drv_cc);
- }
-
-- /* Init MIPS core */
-+ /* Early 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);
-+ bcma_core_mips_early_init(&bus->drv_mips);
- }
-
- bcma_info(bus, "Early bus registered\n");
---- a/include/linux/bcma/bcma_driver_chipcommon.h
-+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -476,6 +476,7 @@ struct bcma_drv_cc {
- u32 capabilities;
- u32 capabilities_ext;
- u8 setup_done:1;
-+ u8 early_setup_done:1;
- /* Fast Powerup Delay constant */
- u16 fast_pwrup_delay;
- struct bcma_chipcommon_pmu pmu;
-@@ -510,6 +511,7 @@ struct bcma_drv_cc {
- bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
-
- extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
-+extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
-
- extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
- extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
-@@ -533,6 +535,7 @@ u32 bcma_chipco_gpio_polarity(struct bcm
-
- /* PMU support */
- extern void bcma_pmu_init(struct bcma_drv_cc *cc);
-+extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
-
- extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
- u32 value);
---- a/include/linux/bcma/bcma_driver_mips.h
-+++ b/include/linux/bcma/bcma_driver_mips.h
-@@ -35,13 +35,16 @@ struct bcma_device;
- struct bcma_drv_mips {
- struct bcma_device *core;
- u8 setup_done:1;
-+ u8 early_setup_done:1;
- unsigned int assigned_irqs;
- };
-
- #ifdef CONFIG_BCMA_DRIVER_MIPS
- extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
-+extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
- #else
- static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
-+static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
- #endif
-
- extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
diff --git a/target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch b/target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch
deleted file mode 100644
index 03540f04c..000000000
--- a/target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch
+++ /dev/null
@@ -1,37 +0,0 @@
---- a/drivers/bcma/main.c
-+++ b/drivers/bcma/main.c
-@@ -165,6 +165,20 @@ int __devinit bcma_bus_register(struct b
- return -1;
- }
-
-+ /* Early init CC core */
-+ core = bcma_find_core(bus, bcma_cc_core_id(bus));
-+ if (core) {
-+ bus->drv_cc.core = core;
-+ bcma_core_chipcommon_early_init(&bus->drv_cc);
-+ }
-+
-+ /* Try to get SPROM */
-+ err = bcma_sprom_get(bus);
-+ if (err == -ENOENT) {
-+ bcma_err(bus, "No SPROM available\n");
-+ } else if (err)
-+ bcma_err(bus, "Failed to get SPROM: %d\n", err);
-+
- /* Init CC core */
- core = bcma_find_core(bus, bcma_cc_core_id(bus));
- if (core) {
-@@ -193,13 +207,6 @@ int __devinit bcma_bus_register(struct b
- bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
- }
-
-- /* Try to get SPROM */
-- err = bcma_sprom_get(bus);
-- if (err == -ENOENT) {
-- bcma_err(bus, "No SPROM available\n");
-- } else if (err)
-- bcma_err(bus, "Failed to get SPROM: %d\n", err);
--
- /* Register found cores */
- bcma_register_cores(bus);
-
diff --git a/target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch b/target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch
deleted file mode 100644
index 302ac8d95..000000000
--- a/target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch
+++ /dev/null
@@ -1,26 +0,0 @@
---- a/drivers/bcma/driver_pci_host.c
-+++ b/drivers/bcma/driver_pci_host.c
-@@ -35,11 +35,6 @@ bool __devinit bcma_core_pci_is_in_hostm
- chipid_top != 0x5300)
- return false;
-
-- if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-- bcma_info(bus, "This PCI core is disabled and not working\n");
-- return false;
-- }
--
- bcma_core_enable(pc->core, 0);
-
- return !mips_busprobe32(tmp, pc->core->io_addr);
-@@ -396,6 +391,11 @@ void __devinit bcma_core_pci_hostmode_in
-
- bcma_info(bus, "PCIEcore in host mode found\n");
-
-+ if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-+ bcma_info(bus, "This PCIE core is disabled and not working\n");
-+ return;
-+ }
-+
- pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
- if (!pc_host) {
- bcma_err(bus, "can not allocate memory");
diff --git a/target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch b/target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch
index c535c05db..8b858e11b 100644
--- a/target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch
+++ b/target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch
@@ -11,12 +11,12 @@ This prevents the options from being delete with make kernel_oldconfig.
depends on BCMA_DRIVER_MIPS
+ select USB_HCD_BCMA if USB_EHCI_HCD || USB_OHCI_HCD
- config BCMA_SFLASH
- bool
+ config BCMA_DRIVER_MIPS
+ bool "BCMA Broadcom MIPS core driver"
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
-@@ -147,6 +147,7 @@ config SSB_SFLASH
- config SSB_EMBEDDED
+@@ -146,6 +146,7 @@ config SSB_EMBEDDED
+ config SSB_SFLASH
bool
depends on SSB_DRIVER_MIPS
+ select USB_HCD_SSB if USB_EHCI_HCD || USB_OHCI_HCD
diff --git a/target/linux/brcm47xx/patches-3.3/400-arch-bcm47xx.patch b/target/linux/brcm47xx/patches-3.3/400-arch-bcm47xx.patch
index a232bff91..bdd2c040d 100644
--- a/target/linux/brcm47xx/patches-3.3/400-arch-bcm47xx.patch
+++ b/target/linux/brcm47xx/patches-3.3/400-arch-bcm47xx.patch
@@ -1,6 +1,6 @@
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
-@@ -274,3 +274,30 @@ int nvram_getenv(char *name, char *val,
+@@ -183,3 +183,30 @@ int nvram_getenv(char *name, char *val,
return NVRAM_ERR_ENVNOTFOUND;
}
EXPORT_SYMBOL(nvram_getenv);
diff --git a/target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch b/target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch
index 951c6d40e..b8f72a12c 100644
--- a/target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch
+++ b/target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch
@@ -99,7 +99,7 @@
void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -495,6 +495,9 @@ struct bcma_drv_cc {
+@@ -551,6 +551,9 @@ struct bcma_drv_cc {
int nr_serial_ports;
struct bcma_serial_port serial_ports[4];
#endif /* CONFIG_BCMA_DRIVER_MIPS */
@@ -109,7 +109,7 @@
};
/* Register access */
-@@ -525,13 +528,22 @@ void bcma_chipco_irq_mask(struct bcma_dr
+@@ -581,13 +584,22 @@ void bcma_chipco_irq_mask(struct bcma_dr
u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask);
diff --git a/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch b/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch
index 2f62728d6..187e64e87 100644
--- a/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch
+++ b/target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch
@@ -276,7 +276,7 @@
+EXPORT_SYMBOL(gpio_set_value);
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -346,6 +346,8 @@ void __init plat_mem_setup(void)
+@@ -252,6 +252,8 @@ void __init plat_mem_setup(void)
_machine_restart = bcm47xx_machine_restart;
_machine_halt = bcm47xx_machine_halt;
pm_power_off = bcm47xx_machine_halt;
@@ -307,7 +307,7 @@
+
if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
gpio_interrupt, IRQF_SHARED,
- "WGT634U GPIO", ccore)) {
+ "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -56,4 +56,6 @@ void bcm47xx_fill_bcma_boardinfo(struct
diff --git a/target/linux/brcm47xx/patches-3.3/812-disable_wgt634u_crap.patch b/target/linux/brcm47xx/patches-3.3/812-disable_wgt634u_crap.patch
index a2902e7c7..2819ca173 100644
--- a/target/linux/brcm47xx/patches-3.3/812-disable_wgt634u_crap.patch
+++ b/target/linux/brcm47xx/patches-3.3/812-disable_wgt634u_crap.patch
@@ -3,7 +3,7 @@
@@ -4,4 +4,3 @@
#
- obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o bus.o
+ obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
-obj-$(CONFIG_BCM47XX_SSB) += wgt634u.o
--- a/arch/mips/bcm47xx/wgt634u.c
+++ /dev/null
@@ -153,7 +153,7 @@
- if (et0mac[0] == 0x00 &&
- ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
- (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
-- struct ssb_chipcommon *ccore = &bcm47xx_bus.ssb.chipco;
+- struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
-
- printk(KERN_INFO "WGT634U machine detected.\n");
-
@@ -165,18 +165,18 @@
-
- if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
- gpio_interrupt, IRQF_SHARED,
-- "WGT634U GPIO", ccore)) {
+- "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
- gpio_direction_input(WGT634U_GPIO_RESET);
- gpio_intmask(WGT634U_GPIO_RESET, 1);
-- ssb_chipco_irq_mask(ccore,
+- ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
- SSB_CHIPCO_IRQ_GPIO,
- SSB_CHIPCO_IRQ_GPIO);
- }
-
-- wgt634u_flash_data.width = ccore->pflash.buswidth;
-- wgt634u_flash_resource.start = ccore->pflash.window;
-- wgt634u_flash_resource.end = ccore->pflash.window
-- + ccore->pflash.window_size
+- wgt634u_flash_data.width = mcore->pflash.buswidth;
+- wgt634u_flash_resource.start = mcore->pflash.window;
+- wgt634u_flash_resource.end = mcore->pflash.window
+- + mcore->pflash.window_size
- - 1;
- return platform_add_devices(wgt634u_devices,
- ARRAY_SIZE(wgt634u_devices));
diff --git a/target/linux/brcm47xx/patches-3.3/820-wgt634u-nvram-fix.patch b/target/linux/brcm47xx/patches-3.3/820-wgt634u-nvram-fix.patch
index 457958a9d..0aef7952d 100644
--- a/target/linux/brcm47xx/patches-3.3/820-wgt634u-nvram-fix.patch
+++ b/target/linux/brcm47xx/patches-3.3/820-wgt634u-nvram-fix.patch
@@ -9,8 +9,8 @@ out the configuration than the in kernel cfe config reader.
# under Linux.
#
--obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o bus.o
-+obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o bus.o cfe_env.o
+-obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
++obj-y += gpio.o irq.o nvram.o prom.o serial.o setup.o time.o sprom.o cfe_env.o
--- /dev/null
+++ b/arch/mips/bcm47xx/cfe_env.c
@@ -0,0 +1,229 @@
@@ -245,18 +245,18 @@ out the configuration than the in kernel cfe config reader.
+
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
-@@ -25,6 +25,8 @@
- #include <linux/mtd/bcm47xx_nand.h>
+@@ -22,6 +22,8 @@
+ #include <asm/mach-bcm47xx/bcm47xx.h>
static char nvram_buf[NVRAM_SPACE];
+static int cfe_env;
+extern char *cfe_env_get(char *nv_buf, const char *name);
- /* Probe for NVRAM header */
- static void early_nvram_init_pflash(void)
-@@ -58,6 +60,25 @@ static void early_nvram_init_pflash(void
- break;
- #endif
+ static u32 find_nvram_size(u32 end)
+ {
+@@ -59,6 +61,25 @@ static void early_nvram_init_fill(u32 ba
+ }
+ off <<= 1;
}
+ cfe_env = 0;
+
@@ -278,9 +278,9 @@ out the configuration than the in kernel cfe config reader.
+ }
+ }
- off = FLASH_MIN;
- while (off <= lim) {
-@@ -257,6 +278,12 @@ int nvram_getenv(char *name, char *val,
+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+ header = (struct nvram_header *) KSEG1ADDR(base + 4096);
+@@ -166,6 +187,12 @@ int nvram_getenv(char *name, char *val,
if (!nvram_buf[0])
early_nvram_init();
@@ -293,7 +293,7 @@ out the configuration than the in kernel cfe config reader.
/* Look for name=value and return value */
var = &nvram_buf[sizeof(struct nvram_header)];
end = nvram_buf + sizeof(nvram_buf) - 2;
-@@ -285,6 +312,9 @@ char *nvram_get(const char *name)
+@@ -194,6 +221,9 @@ char *nvram_get(const char *name)
if (!nvram_buf[0])
early_nvram_init();
diff --git a/target/linux/brcm47xx/patches-3.3/980-wnr834b_no_cardbus_invariant.patch b/target/linux/brcm47xx/patches-3.3/980-wnr834b_no_cardbus_invariant.patch
index 7626c62ab..1c0c6195e 100644
--- a/target/linux/brcm47xx/patches-3.3/980-wnr834b_no_cardbus_invariant.patch
+++ b/target/linux/brcm47xx/patches-3.3/980-wnr834b_no_cardbus_invariant.patch
@@ -1,6 +1,6 @@
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
-@@ -151,6 +151,10 @@ static int bcm47xx_get_invariants(struct
+@@ -120,6 +120,10 @@ static int bcm47xx_get_invariants(struct
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
diff --git a/target/linux/brcm47xx/patches-3.3/999-wl_exports.patch b/target/linux/brcm47xx/patches-3.3/999-wl_exports.patch
index e45b40242..1bf09f36b 100644
--- a/target/linux/brcm47xx/patches-3.3/999-wl_exports.patch
+++ b/target/linux/brcm47xx/patches-3.3/999-wl_exports.patch
@@ -1,8 +1,8 @@
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
-@@ -24,7 +24,8 @@
- #include <asm/mach-bcm47xx/bus.h>
- #include <linux/mtd/bcm47xx_nand.h>
+@@ -21,7 +21,8 @@
+ #include <asm/mach-bcm47xx/nvram.h>
+ #include <asm/mach-bcm47xx/bcm47xx.h>
-static char nvram_buf[NVRAM_SPACE];
+char nvram_buf[NVRAM_SPACE];
diff --git a/target/linux/generic/patches-3.3/020-ssb_update.patch b/target/linux/generic/patches-3.3/020-ssb_update.patch
index e427574f7..10c70abbb 100644
--- a/target/linux/generic/patches-3.3/020-ssb_update.patch
+++ b/target/linux/generic/patches-3.3/020-ssb_update.patch
@@ -100,7 +100,48 @@
+}
--- a/drivers/ssb/driver_mipscore.c
+++ b/drivers/ssb/driver_mipscore.c
-@@ -208,6 +208,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
+@@ -190,16 +190,32 @@ static void ssb_mips_flash_detect(struct
+ {
+ struct ssb_bus *bus = mcore->dev->bus;
+
+- mcore->flash_buswidth = 2;
+- if (bus->chipco.dev) {
+- mcore->flash_window = 0x1c000000;
+- mcore->flash_window_size = 0x02000000;
++ /* When there is no chipcommon on the bus there is 4MB flash */
++ if (!bus->chipco.dev) {
++ mcore->pflash.present = true;
++ mcore->pflash.buswidth = 2;
++ mcore->pflash.window = SSB_FLASH1;
++ mcore->pflash.window_size = SSB_FLASH1_SZ;
++ return;
++ }
++
++ /* There is ChipCommon, so use it to read info about flash */
++ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ case SSB_CHIPCO_FLASHT_ATSER:
++ pr_err("Serial flash not supported\n");
++ break;
++ case SSB_CHIPCO_FLASHT_PARA:
++ pr_debug("Found parallel flash\n");
++ mcore->pflash.present = true;
++ mcore->pflash.window = SSB_FLASH2;
++ mcore->pflash.window_size = SSB_FLASH2_SZ;
+ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+ & SSB_CHIPCO_CFG_DS16) == 0)
+- mcore->flash_buswidth = 1;
+- } else {
+- mcore->flash_window = 0x1fc00000;
+- mcore->flash_window_size = 0x00400000;
++ mcore->pflash.buswidth = 1;
++ else
++ mcore->pflash.buswidth = 2;
++ break;
+ }
+ }
+
+@@ -208,6 +224,9 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
struct ssb_bus *bus = mcore->dev->bus;
u32 pll_type, n, m, rate = 0;
@@ -673,6 +714,19 @@
/* Vendor-ID values */
#define SSB_VENDOR_BROADCOM 0x4243
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -504,7 +504,9 @@
+ #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
+ #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
+ #define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
+-#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
++#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
++#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
++#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
+
+ /* Status register bits for ST flashes */
+ #define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
--- a/include/linux/ssb/ssb_driver_gige.h
+++ b/include/linux/ssb/ssb_driver_gige.h
@@ -2,6 +2,7 @@
@@ -683,6 +737,32 @@
#include <linux/pci.h>
#include <linux/spinlock.h>
+--- a/include/linux/ssb/ssb_driver_mips.h
++++ b/include/linux/ssb/ssb_driver_mips.h
+@@ -13,6 +13,12 @@ struct ssb_serial_port {
+ unsigned int reg_shift;
+ };
+
++struct ssb_pflash {
++ bool present;
++ u8 buswidth;
++ u32 window;
++ u32 window_size;
++};
+
+ struct ssb_mipscore {
+ struct ssb_device *dev;
+@@ -20,9 +26,7 @@ struct ssb_mipscore {
+ int nr_serial_ports;
+ struct ssb_serial_port serial_ports[4];
+
+- u8 flash_buswidth;
+- u32 flash_window;
+- u32 flash_window_size;
++ struct ssb_pflash pflash;
+ };
+
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -228,6 +228,7 @@
diff --git a/target/linux/generic/patches-3.3/025-bcma_backport.patch b/target/linux/generic/patches-3.3/025-bcma_backport.patch
index 29aaa2958..824c4455c 100644
--- a/target/linux/generic/patches-3.3/025-bcma_backport.patch
+++ b/target/linux/generic/patches-3.3/025-bcma_backport.patch
@@ -1,3 +1,33 @@
+--- a/arch/mips/bcm47xx/nvram.c
++++ b/arch/mips/bcm47xx/nvram.c
+@@ -43,8 +43,8 @@ static void early_nvram_init(void)
+ #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;
++ base = mcore_ssb->pflash.window;
++ lim = mcore_ssb->pflash.window_size;
+ break;
+ #endif
+ #ifdef CONFIG_BCM47XX_BCMA
+--- a/arch/mips/bcm47xx/wgt634u.c
++++ b/arch/mips/bcm47xx/wgt634u.c
+@@ -156,10 +156,10 @@ static int __init wgt634u_init(void)
+ SSB_CHIPCO_IRQ_GPIO);
+ }
+
+- wgt634u_flash_data.width = mcore->flash_buswidth;
+- wgt634u_flash_resource.start = mcore->flash_window;
+- wgt634u_flash_resource.end = mcore->flash_window
+- + mcore->flash_window_size
++ wgt634u_flash_data.width = mcore->pflash.buswidth;
++ wgt634u_flash_resource.start = mcore->pflash.window;
++ wgt634u_flash_resource.end = mcore->pflash.window
++ + mcore->pflash.window_size
+ - 1;
+ return platform_add_devices(wgt634u_devices,
+ ARRAY_SIZE(wgt634u_devices));
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -29,7 +29,7 @@ config BCMA_HOST_PCI
@@ -9,10 +39,20 @@
help
PCI core hostmode operation (external PCI bus).
-@@ -46,6 +46,15 @@ config BCMA_DRIVER_MIPS
+@@ -46,6 +46,25 @@ config BCMA_DRIVER_MIPS
If unsure, say N
++config BCMA_SFLASH
++ bool
++ depends on BCMA_DRIVER_MIPS
++ default y
++
++config BCMA_NFLASH
++ bool
++ depends on BCMA_DRIVER_MIPS
++ default y
++
+config BCMA_DRIVER_GMAC_CMN
+ bool "BCMA Broadcom GBIT MAC COMMON core driver"
+ depends on BCMA
@@ -27,7 +67,11 @@
depends on BCMA
--- a/drivers/bcma/Makefile
+++ b/drivers/bcma/Makefile
-@@ -3,6 +3,7 @@ bcma-y += driver_chipcommon.o driver
+@@ -1,8 +1,11 @@
+ 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-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
bcma-y += driver_pci.o
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
@@ -58,7 +102,37 @@
void bcma_bus_unregister(struct bcma_bus *bus);
int __init bcma_bus_early_register(struct bcma_bus *bus,
struct bcma_device *core_cc,
-@@ -48,8 +57,12 @@ extern int __init bcma_host_pci_init(voi
+@@ -42,14 +51,42 @@ 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);
++extern struct platform_device bcma_sflash_dev;
++#else
++static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
++{
++ bcma_err(cc->core->bus, "Serial flash not supported\n");
++ return 0;
++}
++#endif /* CONFIG_BCMA_SFLASH */
++
++#ifdef CONFIG_BCMA_NFLASH
++/* driver_chipcommon_nflash.c */
++int bcma_nflash_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_nflash_dev;
++#else
++static inline int bcma_nflash_init(struct bcma_drv_cc *cc)
++{
++ bcma_err(cc->core->bus, "NAND flash not supported\n");
++ return 0;
++}
++#endif /* CONFIG_BCMA_NFLASH */
++
+ #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 */
@@ -82,6 +156,15 @@
udelay(1);
}
EXPORT_SYMBOL_GPL(bcma_core_disable);
+@@ -64,7 +65,7 @@ void bcma_core_set_clockmode(struct bcma
+ switch (clkmode) {
+ case BCMA_CLKMODE_FAST:
+ bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+- udelay(64);
++ usleep_range(64, 300);
+ for (i = 0; i < 1500; i++) {
+ if (bcma_read32(core, BCMA_CLKCTLST) &
+ BCMA_CLKCTLST_HAVEHT) {
@@ -74,10 +75,10 @@ void bcma_core_set_clockmode(struct bcma
udelay(10);
}
@@ -120,7 +203,45 @@
}
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
-@@ -44,7 +44,7 @@ void bcma_core_chipcommon_init(struct bc
+@@ -22,12 +22,9 @@ static inline u32 bcma_cc_write32_masked
+ return value;
+ }
+
+-void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
++void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
+- u32 leddc_on = 10;
+- u32 leddc_off = 90;
+-
+- if (cc->setup_done)
++ if (cc->early_setup_done)
+ return;
+
+ if (cc->core->id.rev >= 11)
+@@ -36,6 +33,22 @@ void bcma_core_chipcommon_init(struct bc
+ if (cc->core->id.rev >= 35)
+ cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
+
++ if (cc->capabilities & BCMA_CC_CAP_PMU)
++ bcma_pmu_early_init(cc);
++
++ cc->early_setup_done = true;
++}
++
++void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
++{
++ u32 leddc_on = 10;
++ u32 leddc_off = 90;
++
++ if (cc->setup_done)
++ return;
++
++ bcma_core_chipcommon_early_init(cc);
++
+ if (cc->core->id.rev >= 20) {
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
+@@ -44,7 +57,7 @@ void bcma_core_chipcommon_init(struct bc
if (cc->capabilities & BCMA_CC_CAP_PMU)
bcma_pmu_init(cc);
if (cc->capabilities & BCMA_CC_CAP_PCTL)
@@ -129,7 +250,7 @@
if (cc->core->id.rev >= 16) {
if (cc->core->bus->sprom.leddc_on_time &&
-@@ -137,8 +137,7 @@ void bcma_chipco_serial_init(struct bcma
+@@ -137,8 +150,7 @@ void bcma_chipco_serial_init(struct bcma
| BCMA_CC_CORECTL_UARTCLKEN);
}
} else {
@@ -139,6 +260,53 @@
return;
}
+--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_nflash.c
+@@ -0,0 +1,44 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon NAND flash interface
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/bcma/bcma.h>
++
++#include "bcma_private.h"
++
++struct platform_device bcma_nflash_dev = {
++ .name = "bcma_nflash",
++ .num_resources = 0,
++};
++
++/* Initialize NAND flash access */
++int bcma_nflash_init(struct bcma_drv_cc *cc)
++{
++ struct bcma_bus *bus = cc->core->bus;
++
++ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
++ cc->core->id.rev != 0x38) {
++ bcma_err(bus, "NAND flash on unsupported board!\n");
++ return -ENOTSUPP;
++ }
++
++ if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) {
++ bcma_err(bus, "NAND flash not present according to ChipCommon\n");
++ return -ENODEV;
++ }
++
++ cc->nflash.present = true;
++ if (cc->core->id.rev == 38 &&
++ (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
++ cc->nflash.boot = true;
++
++ /* Prepare platform device, but don't register it yet. It's too early,
++ * malloc (required by device_private_init) is not available yet. */
++ bcma_nflash_dev.dev.platform_data = &cc->nflash;
++
++ return 0;
++}
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -3,7 +3,8 @@
@@ -193,7 +361,7 @@
}
/* Set the resource masks. */
-@@ -93,22 +75,9 @@ static void bcma_pmu_resources_init(stru
+@@ -93,22 +75,12 @@ static void bcma_pmu_resources_init(stru
bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
if (max_msk)
bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
@@ -213,12 +381,15 @@
- pr_err("PMU switch/regulators init unknown for device "
- "0x%04X\n", bus->chipinfo.id);
- }
-+ /* Add some delay; allow resources to come up and settle. */
++ /*
++ * Add some delay; allow resources to come up and settle.
++ * Delay is required for SoC (early init).
++ */
+ mdelay(2);
}
/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
-@@ -122,8 +91,11 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
+@@ -122,51 +94,69 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
val |= BCMA_CHIPCTL_4331_EXTPA_EN;
if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
@@ -230,7 +401,11 @@
val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
}
bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
-@@ -134,26 +106,38 @@ void bcma_pmu_workarounds(struct bcma_dr
+ }
+
+-void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
++static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+ {
struct bcma_bus *bus = cc->core->bus;
switch (bus->chipinfo.id) {
@@ -240,7 +415,7 @@
+ /* enable 12 mA drive strenth for 4313 and set chipControl
+ register bit 1 */
+ bcma_chipco_chipctl_maskset(cc, 0,
-+ BCMA_CCTRL_4313_12MA_LED_DRIVE,
++ ~BCMA_CCTRL_4313_12MA_LED_DRIVE,
+ BCMA_CCTRL_4313_12MA_LED_DRIVE);
break;
- case 0x4331:
@@ -260,15 +435,15 @@
- "implemented\n");
- bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
+ bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
-+ BCMA_CCTRL_43224_GPIO_TOGGLE,
++ ~BCMA_CCTRL_43224_GPIO_TOGGLE,
+ BCMA_CCTRL_43224_GPIO_TOGGLE);
+ bcma_chipco_chipctl_maskset(cc, 0,
-+ BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
++ ~BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
+ BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
} else {
- bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
+ bcma_chipco_chipctl_maskset(cc, 0,
-+ BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
++ ~BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
+ BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
}
break;
@@ -282,7 +457,11 @@
}
}
-@@ -164,8 +148,8 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+-void bcma_pmu_init(struct bcma_drv_cc *cc)
++void bcma_pmu_early_init(struct bcma_drv_cc *cc)
+ {
+ u32 pmucap;
+
pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
@@ -290,10 +469,14 @@
- pmucap);
+ bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
+ cc->pmu.rev, pmucap);
++}
++void bcma_pmu_init(struct bcma_drv_cc *cc)
++{
if (cc->pmu.rev == 1)
bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
-@@ -174,12 +158,7 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+ ~BCMA_CC_PMU_CTL_NOILPONW);
+@@ -174,12 +164,7 @@ void bcma_pmu_init(struct bcma_drv_cc *c
bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
BCMA_CC_PMU_CTL_NOILPONW);
@@ -306,7 +489,7 @@
bcma_pmu_workarounds(cc);
}
-@@ -188,23 +167,22 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
+@@ -188,23 +173,22 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_c
struct bcma_bus *bus = cc->core->bus;
switch (bus->chipinfo.id) {
@@ -341,7 +524,7 @@
}
return BCMA_CC_PMU_ALP_CLOCK;
}
-@@ -221,7 +199,8 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -221,7 +205,8 @@ static u32 bcma_pmu_clock(struct bcma_dr
BUG_ON(!m || m > 4);
@@ -351,7 +534,7 @@
/* Detect failure in clock setting */
tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
if (tmp & 0x40000)
-@@ -247,33 +226,62 @@ static u32 bcma_pmu_clock(struct bcma_dr
+@@ -247,33 +232,62 @@ static u32 bcma_pmu_clock(struct bcma_dr
return (fc / div) * 1000000;
}
@@ -386,7 +569,8 @@
+}
+
/* query bus clock frequency for PMU-enabled chipcommon */
- u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+-u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
@@ -427,7 +611,7 @@
}
return BCMA_CC_PMU_HT_CLOCK;
}
-@@ -283,17 +291,21 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -283,17 +297,21 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
{
struct bcma_bus *bus = cc->core->bus;
@@ -453,7 +637,7 @@
pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
break;
default:
-@@ -301,10 +313,188 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+@@ -301,10 +319,188 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
break;
}
@@ -645,6 +829,174 @@
+}
+EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
--- /dev/null
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -0,0 +1,165 @@
++/*
++ * Broadcom specific AMBA
++ * ChipCommon serial flash interface
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/bcma/bcma.h>
++
++#include "bcma_private.h"
++
++static struct resource bcma_sflash_resource = {
++ .name = "bcma_sflash",
++ .start = BCMA_SOC_FLASH2,
++ .end = 0,
++ .flags = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device bcma_sflash_dev = {
++ .name = "bcma_sflash",
++ .resource = &bcma_sflash_resource,
++ .num_resources = 1,
++};
++
++struct bcma_sflash_tbl_e {
++ char *name;
++ u32 id;
++ u32 blocksize;
++ u16 numblocks;
++};
++
++static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++ { "M25P20", 0x11, 0x10000, 4, },
++ { "M25P40", 0x12, 0x10000, 8, },
++
++ { "M25P16", 0x14, 0x10000, 32, },
++ { "M25P32", 0x14, 0x10000, 64, },
++ { "M25P64", 0x16, 0x10000, 128, },
++ { "M25FL128", 0x17, 0x10000, 256, },
++ { 0 },
++};
++
++static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++ { "SST25WF512", 1, 0x1000, 16, },
++ { "SST25VF512", 0x48, 0x1000, 16, },
++ { "SST25WF010", 2, 0x1000, 32, },
++ { "SST25VF010", 0x49, 0x1000, 32, },
++ { "SST25WF020", 3, 0x1000, 64, },
++ { "SST25VF020", 0x43, 0x1000, 64, },
++ { "SST25WF040", 4, 0x1000, 128, },
++ { "SST25VF040", 0x44, 0x1000, 128, },
++ { "SST25VF040B", 0x8d, 0x1000, 128, },
++ { "SST25WF080", 5, 0x1000, 256, },
++ { "SST25VF080B", 0x8e, 0x1000, 256, },
++ { "SST25VF016", 0x41, 0x1000, 512, },
++ { "SST25VF032", 0x4a, 0x1000, 1024, },
++ { "SST25VF064", 0x4b, 0x1000, 2048, },
++ { 0 },
++};
++
++static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++ { "AT45DB011", 0xc, 256, 512, },
++ { "AT45DB021", 0x14, 256, 1024, },
++ { "AT45DB041", 0x1c, 256, 2048, },
++ { "AT45DB081", 0x24, 256, 4096, },
++ { "AT45DB161", 0x2c, 512, 4096, },
++ { "AT45DB321", 0x34, 512, 8192, },
++ { "AT45DB642", 0x3c, 1024, 8192, },
++ { 0 },
++};
++
++static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
++{
++ int i;
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
++ BCMA_CC_FLASHCTL_START | opcode);
++ for (i = 0; i < 1000; i++) {
++ if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) &
++ BCMA_CC_FLASHCTL_BUSY))
++ return;
++ cpu_relax();
++ }
++ bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
++}
++
++/* Initialize serial flash access */
++int bcma_sflash_init(struct bcma_drv_cc *cc)
++{
++ struct bcma_bus *bus = cc->core->bus;
++ struct bcma_sflash *sflash = &cc->sflash;
++ struct bcma_sflash_tbl_e *e;
++ u32 id, id2;
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ 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);
++
++ 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 (id) {
++ case 0xbf:
++ for (e = bcma_sflash_sst_tbl; e->name; e++) {
++ if (e->id == id2)
++ break;
++ }
++ break;
++ case 0x13:
++ return -ENOTSUPP;
++ default:
++ for (e = bcma_sflash_st_tbl; e->name; e++) {
++ if (e->id == id)
++ break;
++ }
++ break;
++ }
++ if (!e->name) {
++ bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2);
++ return -ENOTSUPP;
++ }
++
++ break;
++ case BCMA_CC_FLASHT_ATSER:
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
++ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
++
++ for (e = bcma_sflash_at_tbl; e->name; e++) {
++ if (e->id == id)
++ break;
++ }
++ if (!e->name) {
++ bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n", id);
++ return -ENOTSUPP;
++ }
++
++ break;
++ default:
++ bcma_err(bus, "Unsupported flash type\n");
++ return -ENOTSUPP;
++ }
++
++ sflash->window = BCMA_SOC_FLASH2;
++ sflash->blocksize = e->blocksize;
++ sflash->numblocks = e->numblocks;
++ sflash->size = sflash->blocksize * sflash->numblocks;
++ sflash->present = true;
++
++ bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
++ e->name, sflash->size / 1024, sflash->blocksize,
++ sflash->numblocks);
++
++ /* Prepare platform device, but don't register it yet. It's too early,
++ * malloc (required by device_private_init) is not available yet. */
++ bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start +
++ sflash->size;
++ bcma_sflash_dev.dev.platform_data = sflash;
++
++ return 0;
++}
+--- /dev/null
+++ b/drivers/bcma/driver_gmac_cmn.c
@@ -0,0 +1,14 @@
+/*
@@ -683,6 +1035,15 @@
dev->bus->chipinfo.pkg == 11 &&
dev->id.id == BCMA_CORE_USB20_HOST;
}
+@@ -131,7 +131,7 @@ static void bcma_core_mips_set_irq(struc
+ /* backplane irq line is in use, find out who uses
+ * it and set user to irq 0
+ */
+- list_for_each_entry_reverse(core, &bus->cores, list) {
++ list_for_each_entry(core, &bus->cores, list) {
+ if ((1 << bcma_core_mips_irqflag(core)) ==
+ oldirqflag) {
+ bcma_core_mips_set_irq(core, 0);
@@ -143,8 +143,8 @@ static void bcma_core_mips_set_irq(struc
1 << irqflag);
}
@@ -694,6 +1055,15 @@
}
static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
+@@ -161,7 +161,7 @@ static void bcma_core_mips_dump_irq(stru
+ {
+ struct bcma_device *core;
+
+- list_for_each_entry_reverse(core, &bus->cores, list) {
++ list_for_each_entry(core, &bus->cores, list) {
+ bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
+ }
+ }
@@ -173,7 +173,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips
if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
return bcma_pmu_get_clockcpu(&bus->drv_cc);
@@ -703,38 +1073,89 @@
return 0;
}
EXPORT_SYMBOL(bcma_cpu_clock);
-@@ -185,10 +185,10 @@ static void bcma_core_mips_flash_detect(
- switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
+@@ -181,26 +181,50 @@ EXPORT_SYMBOL(bcma_cpu_clock);
+ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+ {
+ struct bcma_bus *bus = mcore->core->bus;
++ struct bcma_drv_cc *cc = &bus->drv_cc;
+
+- switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
case BCMA_CC_FLASHT_ATSER:
- pr_err("Serial flash not supported.\n");
-+ bcma_err(bus, "Serial flash not supported.\n");
++ bcma_debug(bus, "Found serial flash\n");
++ bcma_sflash_init(cc);
break;
case BCMA_CC_FLASHT_PARA:
- pr_info("found parallel flash.\n");
-+ bcma_info(bus, "found parallel flash.\n");
- bus->drv_cc.pflash.window = 0x1c000000;
- bus->drv_cc.pflash.window_size = 0x02000000;
-
-@@ -199,7 +199,7 @@ static void bcma_core_mips_flash_detect(
- bus->drv_cc.pflash.buswidth = 2;
+- bus->drv_cc.pflash.window = 0x1c000000;
+- bus->drv_cc.pflash.window_size = 0x02000000;
++ bcma_debug(bus, "Found parallel flash\n");
++ cc->pflash.present = true;
++ cc->pflash.window = BCMA_SOC_FLASH2;
++ cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
+
+- if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++ if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
+ BCMA_CC_FLASH_CFG_DS) == 0)
+- bus->drv_cc.pflash.buswidth = 1;
++ cc->pflash.buswidth = 1;
+ else
+- bus->drv_cc.pflash.buswidth = 2;
++ cc->pflash.buswidth = 2;
break;
default:
- pr_err("flash not supported.\n");
-+ bcma_err(bus, "flash not supported.\n");
++ bcma_err(bus, "Flash type not supported\n");
}
++
++ if (cc->core->id.rev == 38 ||
++ bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
++ if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
++ bcma_debug(bus, "Found NAND flash\n");
++ bcma_nflash_init(cc);
++ }
++ }
++}
++
++void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
++{
++ struct bcma_bus *bus = mcore->core->bus;
++
++ if (mcore->early_setup_done)
++ return;
++
++ bcma_chipco_serial_init(&bus->drv_cc);
++ bcma_core_mips_flash_detect(mcore);
++
++ mcore->early_setup_done = true;
}
-@@ -209,7 +209,7 @@ void bcma_core_mips_init(struct bcma_drv
+ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
+@@ -209,13 +233,17 @@ void bcma_core_mips_init(struct bcma_drv
struct bcma_device *core;
bus = mcore->core->bus;
- pr_info("Initializing MIPS core...\n");
++ if (mcore->setup_done)
++ return;
++
+ bcma_info(bus, "Initializing MIPS core...\n");
++
++ bcma_core_mips_early_init(mcore);
+
+- if (!mcore->setup_done)
+- mcore->assigned_irqs = 1;
++ mcore->assigned_irqs = 1;
- if (!mcore->setup_done)
- mcore->assigned_irqs = 1;
-@@ -244,7 +244,7 @@ void bcma_core_mips_init(struct bcma_drv
+ /* Assign IRQs to all cores on the bus */
+- list_for_each_entry_reverse(core, &bus->cores, list) {
++ list_for_each_entry(core, &bus->cores, list) {
+ int mips_irq;
+ if (core->irq)
+ continue;
+@@ -244,13 +272,8 @@ void bcma_core_mips_init(struct bcma_drv
break;
}
}
@@ -742,7 +1163,13 @@
+ bcma_info(bus, "IRQ reconfiguration done\n");
bcma_core_mips_dump_irq(bus);
- if (mcore->setup_done)
+- if (mcore->setup_done)
+- return;
+-
+- bcma_chipco_serial_init(&bus->drv_cc);
+- bcma_core_mips_flash_detect(mcore);
+ mcore->setup_done = true;
+ }
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -2,8 +2,9 @@
@@ -756,7 +1183,7 @@
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
-@@ -16,40 +17,39 @@
+@@ -16,120 +17,124 @@
* R/W ops.
**************************************************/
@@ -812,9 +1239,10 @@
+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
break;
- msleep(1);
+- msleep(1);
++ usleep_range(1000, 2000);
}
-@@ -57,79 +57,84 @@ static void bcma_pcie_mdio_set_phy(struc
+ }
static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
{
@@ -868,7 +1296,8 @@
+ ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
break;
}
- msleep(1);
+- msleep(1);
++ usleep_range(1000, 2000);
}
- pcicore_write32(pc, mdio_control, 0);
+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
@@ -923,7 +1352,8 @@
+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
break;
- msleep(1);
+- msleep(1);
++ usleep_range(1000, 2000);
}
- pcicore_write32(pc, mdio_control, 0);
+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
@@ -1103,7 +1533,7 @@
+EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer);
--- a/drivers/bcma/driver_pci_host.c
+++ b/drivers/bcma/driver_pci_host.c
-@@ -2,13 +2,592 @@
+@@ -2,13 +2,596 @@
* Broadcom specific AMBA
* PCI Core in hostmode
*
@@ -1140,11 +1570,6 @@
+ chipid_top != 0x5300)
+ return false;
+
-+ if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
-+ bcma_info(bus, "This PCI core is disabled and not working\n");
-+ return false;
-+ }
-+
+ bcma_core_enable(pc->core, 0);
+
+ return !mips_busprobe32(tmp, pc->core->io_addr);
@@ -1503,6 +1928,11 @@
+
+ bcma_info(bus, "PCIEcore in host mode found\n");
+
++ if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
++ bcma_info(bus, "This PCIE core is disabled and not working\n");
++ return;
++ }
++
+ pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
+ if (!pc_host) {
+ bcma_err(bus, "can not allocate memory");
@@ -1532,9 +1962,9 @@
+ pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
+
+ /* Reset RC */
-+ udelay(3000);
++ usleep_range(3000, 5000);
+ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
-+ udelay(1000);
++ usleep_range(1000, 2000);
+ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
+ BCMA_CORE_PCI_CTL_RST_OE);
+
@@ -1559,6 +1989,8 @@
+ pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
+ pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
+ BCMA_SOC_PCI_MEM_SZ - 1;
++ pc_host->io_resource.start = 0x100;
++ pc_host->io_resource.end = 0x47F;
+ pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+ tmp | BCMA_SOC_PCI_MEM);
@@ -1566,6 +1998,8 @@
+ pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
+ pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
+ BCMA_SOC_PCI_MEM_SZ - 1;
++ pc_host->io_resource.start = 0x480;
++ pc_host->io_resource.end = 0x7FF;
+ pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
+ pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
@@ -1588,7 +2022,7 @@
+ * before issuing configuration requests to PCI Express
+ * devices.
+ */
-+ udelay(100000);
++ msleep(100);
+
+ bcma_core_pci_enable_crs(pc);
+
@@ -1608,7 +2042,7 @@
+ set_io_port_base(pc_host->pci_controller.io_map_base);
+ /* Give some time to the PCI controller to configure itself with the new
+ * values. Not waiting at this point causes crashes of the machine. */
-+ mdelay(10);
++ usleep_range(10000, 15000);
+ register_pci_controller(&pc_host->pci_controller);
+ return;
+}
@@ -1709,7 +2143,39 @@
}
/* Provides access to the requested core. Returns base offset that has to be
-@@ -154,8 +154,8 @@ const struct bcma_host_ops bcma_host_pci
+@@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct
+ }
+
+ #ifdef CONFIG_BCMA_BLOCKIO
+-void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+- size_t count, u16 offset, u8 reg_width)
++static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
++ size_t count, u16 offset, u8 reg_width)
+ {
+ void __iomem *addr = core->bus->mmio + offset;
+ if (core->bus->mapped_core != core)
+@@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcm
+ }
+ }
+
+-void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
+- size_t count, u16 offset, u8 reg_width)
++static void bcma_host_pci_block_write(struct bcma_device *core,
++ const void *buffer, size_t count,
++ u16 offset, u8 reg_width)
+ {
+ void __iomem *addr = core->bus->mmio + offset;
+ if (core->bus->mapped_core != core)
+@@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struc
+ iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+ }
+
+-const struct bcma_host_ops bcma_host_pci_ops = {
++static const struct bcma_host_ops bcma_host_pci_ops = {
+ .read8 = bcma_host_pci_read8,
+ .read16 = bcma_host_pci_read16,
+ .read32 = bcma_host_pci_read32,
+@@ -154,8 +155,8 @@ const struct bcma_host_ops bcma_host_pci
.awrite32 = bcma_host_pci_awrite32,
};
@@ -1720,7 +2186,7 @@
{
struct bcma_bus *bus;
int err = -ENOMEM;
-@@ -188,7 +188,7 @@ static int bcma_host_pci_probe(struct pc
+@@ -188,7 +189,7 @@ static int bcma_host_pci_probe(struct pc
/* SSB needed additional powering up, do we have any AMBA PCI cards? */
if (!pci_is_pcie(dev))
@@ -1729,7 +2195,7 @@
/* Map MMIO */
err = -ENOMEM;
-@@ -201,6 +201,9 @@ static int bcma_host_pci_probe(struct pc
+@@ -201,6 +202,9 @@ static int bcma_host_pci_probe(struct pc
bus->hosttype = BCMA_HOSTTYPE_PCI;
bus->ops = &bcma_host_pci_ops;
@@ -1739,7 +2205,7 @@
/* Register */
err = bcma_bus_register(bus);
if (err)
-@@ -222,7 +225,7 @@ err_kfree_bus:
+@@ -222,7 +226,7 @@ err_kfree_bus:
return err;
}
@@ -1748,7 +2214,7 @@
{
struct bcma_bus *bus = pci_get_drvdata(dev);
-@@ -265,6 +268,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bc
+@@ -265,9 +269,12 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bc
static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
@@ -1756,7 +2222,12 @@
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
-@@ -277,7 +281,7 @@ static struct pci_driver bcma_pci_bridge
++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ { 0, },
+ };
+@@ -277,7 +284,7 @@ static struct pci_driver bcma_pci_bridge
.name = "bcma-pci-bridge",
.id_table = bcma_pci_bridge_tbl,
.probe = bcma_host_pci_probe,
@@ -1765,9 +2236,27 @@
.driver.pm = BCMA_PM_OPS,
};
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struc
+ writel(value, core->io_wrap + offset);
+ }
+
+-const struct bcma_host_ops bcma_host_soc_ops = {
++static const struct bcma_host_ops bcma_host_soc_ops = {
+ .read8 = bcma_host_soc_read8,
+ .read16 = bcma_host_soc_read16,
+ .read32 = bcma_host_soc_read32,
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
-@@ -13,6 +13,12 @@
+@@ -7,12 +7,19 @@
+
+ #include "bcma_private.h"
+ #include <linux/module.h>
++#include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/slab.h>
+
MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
MODULE_LICENSE("GPL");
@@ -1780,7 +2269,7 @@
static int bcma_bus_match(struct device *dev, struct device_driver *drv);
static int bcma_device_probe(struct device *dev);
static int bcma_device_remove(struct device *dev);
-@@ -55,7 +61,14 @@ static struct bus_type bcma_bus_type = {
+@@ -55,7 +62,14 @@ static struct bus_type bcma_bus_type = {
.dev_attrs = bcma_device_attrs,
};
@@ -1796,15 +2285,27 @@
{
struct bcma_device *core;
-@@ -65,6 +78,7 @@ static struct bcma_device *bcma_find_cor
+@@ -65,6 +79,19 @@ static struct bcma_device *bcma_find_cor
}
return NULL;
}
+EXPORT_SYMBOL_GPL(bcma_find_core);
++
++static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
++ u8 unit)
++{
++ struct bcma_device *core;
++
++ list_for_each_entry(core, &bus->cores, list) {
++ if (core->id.id == coreid && core->core_unit == unit)
++ return core;
++ }
++ return NULL;
++}
static void bcma_release_core_dev(struct device *dev)
{
-@@ -84,16 +98,18 @@ static int bcma_register_cores(struct bc
+@@ -84,16 +111,18 @@ static int bcma_register_cores(struct bc
list_for_each_entry(core, &bus->cores, list) {
/* We support that cores ourself */
switch (core->id.id) {
@@ -1824,7 +2325,7 @@
switch (bus->hosttype) {
case BCMA_HOSTTYPE_PCI:
-@@ -111,8 +127,9 @@ static int bcma_register_cores(struct bc
+@@ -111,41 +140,77 @@ static int bcma_register_cores(struct bc
err = device_register(&core->dev);
if (err) {
@@ -1836,7 +2337,38 @@
continue;
}
core->dev_registered = true;
-@@ -132,20 +149,24 @@ static void bcma_unregister_cores(struct
+ dev_id++;
+ }
+
++#ifdef CONFIG_BCMA_SFLASH
++ if (bus->drv_cc.sflash.present) {
++ err = platform_device_register(&bcma_sflash_dev);
++ if (err)
++ bcma_err(bus, "Error registering serial flash\n");
++ }
++#endif
++
++#ifdef CONFIG_BCMA_NFLASH
++ if (bus->drv_cc.nflash.present) {
++ err = platform_device_register(&bcma_nflash_dev);
++ if (err)
++ bcma_err(bus, "Error registering NAND flash\n");
++ }
++#endif
++
+ return 0;
+ }
+
+ static void bcma_unregister_cores(struct bcma_bus *bus)
+ {
+- struct bcma_device *core;
++ struct bcma_device *core, *tmp;
+
+- list_for_each_entry(core, &bus->cores, list) {
++ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
++ list_del(&core->list);
+ if (core->dev_registered)
+ device_unregister(&core->dev);
}
}
@@ -1858,31 +2390,58 @@
return -1;
}
++ /* Early init CC core */
++ core = bcma_find_core(bus, bcma_cc_core_id(bus));
++ if (core) {
++ bus->drv_cc.core = core;
++ bcma_core_chipcommon_early_init(&bus->drv_cc);
++ }
++
++ /* Try to get SPROM */
++ err = bcma_sprom_get(bus);
++ if (err == -ENOENT) {
++ bcma_err(bus, "No SPROM available\n");
++ } else if (err)
++ bcma_err(bus, "Failed to get SPROM: %d\n", err);
++
/* Init CC core */
- core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+ core = bcma_find_core(bus, bcma_cc_core_id(bus));
if (core) {
bus->drv_cc.core = core;
bcma_core_chipcommon_init(&bus->drv_cc);
-@@ -165,17 +186,24 @@ int bcma_bus_register(struct bcma_bus *b
- bcma_core_pci_init(&bus->drv_pci);
+@@ -159,30 +224,47 @@ int bcma_bus_register(struct bcma_bus *b
}
+ /* Init PCIE core */
+- core = bcma_find_core(bus, BCMA_CORE_PCIE);
++ core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0);
+ if (core) {
+- bus->drv_pci.core = core;
+- bcma_core_pci_init(&bus->drv_pci);
++ bus->drv_pci[0].core = core;
++ bcma_core_pci_init(&bus->drv_pci[0]);
+ }
+
+- /* Try to get SPROM */
+- err = bcma_sprom_get(bus);
+- if (err == -ENOENT) {
+- pr_err("No SPROM available\n");
+- } else if (err)
+- pr_err("Failed to get SPROM: %d\n", err);
++ /* Init PCIE core */
++ core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
++ if (core) {
++ bus->drv_pci[1].core = core;
++ bcma_core_pci_init(&bus->drv_pci[1]);
++ }
++
+ /* Init GBIT MAC COMMON core */
+ core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
+ if (core) {
+ bus->drv_gmac_cmn.core = core;
+ bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
+ }
-+
- /* Try to get SPROM */
- err = bcma_sprom_get(bus);
- if (err == -ENOENT) {
-- pr_err("No SPROM available\n");
-+ bcma_err(bus, "No SPROM available\n");
- } else if (err)
-- pr_err("Failed to get SPROM: %d\n", err);
-+ bcma_err(bus, "Failed to get SPROM: %d\n", err);
/* Register found cores */
bcma_register_cores(bus);
@@ -1892,7 +2451,24 @@
return 0;
}
-@@ -196,14 +224,14 @@ int __init bcma_bus_early_register(struc
+
+ void bcma_bus_unregister(struct bcma_bus *bus)
+ {
++ struct bcma_device *cores[3];
++
++ cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++ cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
++ cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
++
+ bcma_unregister_cores(bus);
++
++ kfree(cores[2]);
++ kfree(cores[1]);
++ kfree(cores[0]);
+ }
+
+ int __init bcma_bus_early_register(struct bcma_bus *bus,
+@@ -196,14 +278,14 @@ int __init bcma_bus_early_register(struc
bcma_init_bus(bus);
match.manuf = BCMA_MANUF_BCM;
@@ -1909,7 +2485,7 @@
return -1;
}
-@@ -215,12 +243,12 @@ int __init bcma_bus_early_register(struc
+@@ -215,25 +297,25 @@ int __init bcma_bus_early_register(struc
/* Scan for mips core */
err = bcma_bus_scan_early(bus, &match, core_mips);
if (err) {
@@ -1918,14 +2494,23 @@
return -1;
}
- /* Init CC core */
+- /* Init CC core */
- core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
++ /* Early init CC core */
+ core = bcma_find_core(bus, bcma_cc_core_id(bus));
if (core) {
bus->drv_cc.core = core;
- bcma_core_chipcommon_init(&bus->drv_cc);
-@@ -233,7 +261,7 @@ int __init bcma_bus_early_register(struc
- bcma_core_mips_init(&bus->drv_mips);
+- bcma_core_chipcommon_init(&bus->drv_cc);
++ bcma_core_chipcommon_early_init(&bus->drv_cc);
+ }
+
+- /* Init MIPS core */
++ /* Early 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);
++ bcma_core_mips_early_init(&bus->drv_mips);
}
- pr_info("Early bus registered\n");
@@ -1933,7 +2518,7 @@
return 0;
}
-@@ -259,8 +287,7 @@ int bcma_bus_resume(struct bcma_bus *bus
+@@ -259,8 +341,7 @@ int bcma_bus_resume(struct bcma_bus *bus
struct bcma_device *core;
/* Init CC core */
@@ -2038,12 +2623,12 @@
+ break;
+ default:
+ return "UNKNOWN";
-+ }
+ }
+
+ for (i = 0; i < size; i++) {
+ if (names[i].id == id->id)
+ return names[i].name;
- }
++ }
+
return "UNKNOWN";
}
@@ -2144,15 +2729,28 @@
bus->init_done = true;
}
-@@ -392,6 +460,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
+@@ -392,9 +460,12 @@ int bcma_bus_scan(struct bcma_bus *bus)
bcma_scan_switch_core(bus, erombase);
while (eromptr < eromend) {
+ struct bcma_device *other_core;
struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
- if (!core)
- return -ENOMEM;
-@@ -414,14 +483,15 @@ int bcma_bus_scan(struct bcma_bus *bus)
+- if (!core)
+- return -ENOMEM;
++ if (!core) {
++ err = -ENOMEM;
++ goto out;
++ }
+ INIT_LIST_HEAD(&core->list);
+ core->bus = bus;
+
+@@ -409,25 +480,28 @@ int bcma_bus_scan(struct bcma_bus *bus)
+ } else if (err == -ESPIPE) {
+ break;
+ }
+- return err;
++ goto out;
+ }
core->core_index = core_num++;
bus->nr_cores++;
@@ -2173,8 +2771,22 @@
+ list_add_tail(&core->list, &bus->cores);
}
++ err = 0;
++out:
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
-@@ -471,13 +541,12 @@ int __init bcma_bus_scan_early(struct bc
+ iounmap(eromptr);
+
+- return 0;
++ return err;
+ }
+
+ int __init bcma_bus_scan_early(struct bcma_bus *bus,
+@@ -467,21 +541,21 @@ int __init bcma_bus_scan_early(struct bc
+ else if (err == -ESPIPE)
+ break;
+ else if (err < 0)
+- return err;
++ goto out;
core->core_index = core_num++;
bus->nr_cores++;
@@ -2193,6 +2805,11 @@
err = 0;
break;
}
+
++out:
+ if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+ iounmap(eromptr);
+
--- a/drivers/bcma/scan.h
+++ b/drivers/bcma/scan.h
@@ -27,7 +27,7 @@
@@ -2313,77 +2930,13 @@
bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
SSB_SPROM_REVISION_REV;
-@@ -137,102 +216,378 @@ static void bcma_sprom_extract_r8(struct
+@@ -137,107 +216,390 @@ static void bcma_sprom_extract_r8(struct
*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
}
- bus->sprom.board_rev = sprom[SPOFF(SSB_SPROM8_BOARDREV)];
+ SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
-
-- bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
-- SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
-- bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
-- SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
-- bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
-- SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
-- bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
-- SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
--
-- bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
-- SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
-- bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
-- SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
-- bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
-- SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
-- bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
-- SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
--
-- bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
-- SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
-- bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
-- SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
-- bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
-- SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
-- bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
-- SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
--
-- bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
-- SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
-- bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
-- SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
-- bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
-- SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
-- bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
-- SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
--
-- bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
-- bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
-- bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
-- bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
--
-- bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
--
-- bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-- SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
-- bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-- SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
-- bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-- SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
-- bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-- SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
-- bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
-- SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
--
-- bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-- SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
-- bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-- SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
-- bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-- SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
-- bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-- SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
-- bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
-- SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
++
+ SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
+ SSB_SPROM4_TXPID2G0_SHIFT);
+ SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1,
@@ -2459,7 +3012,71 @@
+ SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0);
+ SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0);
+ }
-+
+
+- bus->sprom.txpid2g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
+- SSB_SPROM4_TXPID2G0) >> SSB_SPROM4_TXPID2G0_SHIFT;
+- bus->sprom.txpid2g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID2G01)] &
+- SSB_SPROM4_TXPID2G1) >> SSB_SPROM4_TXPID2G1_SHIFT;
+- bus->sprom.txpid2g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
+- SSB_SPROM4_TXPID2G2) >> SSB_SPROM4_TXPID2G2_SHIFT;
+- bus->sprom.txpid2g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID2G23)] &
+- SSB_SPROM4_TXPID2G3) >> SSB_SPROM4_TXPID2G3_SHIFT;
+-
+- bus->sprom.txpid5gl[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
+- SSB_SPROM4_TXPID5GL0) >> SSB_SPROM4_TXPID5GL0_SHIFT;
+- bus->sprom.txpid5gl[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL01)] &
+- SSB_SPROM4_TXPID5GL1) >> SSB_SPROM4_TXPID5GL1_SHIFT;
+- bus->sprom.txpid5gl[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
+- SSB_SPROM4_TXPID5GL2) >> SSB_SPROM4_TXPID5GL2_SHIFT;
+- bus->sprom.txpid5gl[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GL23)] &
+- SSB_SPROM4_TXPID5GL3) >> SSB_SPROM4_TXPID5GL3_SHIFT;
+-
+- bus->sprom.txpid5g[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
+- SSB_SPROM4_TXPID5G0) >> SSB_SPROM4_TXPID5G0_SHIFT;
+- bus->sprom.txpid5g[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5G01)] &
+- SSB_SPROM4_TXPID5G1) >> SSB_SPROM4_TXPID5G1_SHIFT;
+- bus->sprom.txpid5g[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
+- SSB_SPROM4_TXPID5G2) >> SSB_SPROM4_TXPID5G2_SHIFT;
+- bus->sprom.txpid5g[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5G23)] &
+- SSB_SPROM4_TXPID5G3) >> SSB_SPROM4_TXPID5G3_SHIFT;
+-
+- bus->sprom.txpid5gh[0] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
+- SSB_SPROM4_TXPID5GH0) >> SSB_SPROM4_TXPID5GH0_SHIFT;
+- bus->sprom.txpid5gh[1] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH01)] &
+- SSB_SPROM4_TXPID5GH1) >> SSB_SPROM4_TXPID5GH1_SHIFT;
+- bus->sprom.txpid5gh[2] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
+- SSB_SPROM4_TXPID5GH2) >> SSB_SPROM4_TXPID5GH2_SHIFT;
+- bus->sprom.txpid5gh[3] = (sprom[SPOFF(SSB_SPROM4_TXPID5GH23)] &
+- SSB_SPROM4_TXPID5GH3) >> SSB_SPROM4_TXPID5GH3_SHIFT;
+-
+- bus->sprom.boardflags_lo = sprom[SPOFF(SSB_SPROM8_BFLLO)];
+- bus->sprom.boardflags_hi = sprom[SPOFF(SSB_SPROM8_BFLHI)];
+- bus->sprom.boardflags2_lo = sprom[SPOFF(SSB_SPROM8_BFL2LO)];
+- bus->sprom.boardflags2_hi = sprom[SPOFF(SSB_SPROM8_BFL2HI)];
+-
+- bus->sprom.country_code = sprom[SPOFF(SSB_SPROM8_CCODE)];
+-
+- bus->sprom.fem.ghz2.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+- SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
+- bus->sprom.fem.ghz2.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+- SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
+- bus->sprom.fem.ghz2.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+- SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
+- bus->sprom.fem.ghz2.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+- SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
+- bus->sprom.fem.ghz2.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM2G)] &
+- SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
+-
+- bus->sprom.fem.ghz5.tssipos = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+- SSB_SROM8_FEM_TSSIPOS) >> SSB_SROM8_FEM_TSSIPOS_SHIFT;
+- bus->sprom.fem.ghz5.extpa_gain = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+- SSB_SROM8_FEM_EXTPA_GAIN) >> SSB_SROM8_FEM_EXTPA_GAIN_SHIFT;
+- bus->sprom.fem.ghz5.pdet_range = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+- SSB_SROM8_FEM_PDET_RANGE) >> SSB_SROM8_FEM_PDET_RANGE_SHIFT;
+- bus->sprom.fem.ghz5.tr_iso = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+- SSB_SROM8_FEM_TR_ISO) >> SSB_SROM8_FEM_TR_ISO_SHIFT;
+- bus->sprom.fem.ghz5.antswlut = (sprom[SPOFF(SSB_SPROM8_FEM5G)] &
+- SSB_SROM8_FEM_ANTSWLUT) >> SSB_SROM8_FEM_ANTSWLUT_SHIFT;
+ SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS,
+ SSB_SROM8_FEM_TSSIPOS_SHIFT);
+ SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN,
@@ -2673,7 +3290,11 @@
+ /* for these chips OTP is always available */
+ present = true;
+ break;
-+
++ case BCMA_CHIP_ID_BCM43227:
++ case BCMA_CHIP_ID_BCM43228:
++ case BCMA_CHIP_ID_BCM43428:
++ present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
++ break;
+ default:
+ present = false;
+ break;
@@ -2767,16 +3388,29 @@
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom);
+- if (err)
++ if (err) {
++ bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++ err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
+ goto out;
++ }
+
+ bcma_sprom_extract_r8(bus, sprom);
+
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
-@@ -7,6 +7,7 @@
+@@ -7,9 +7,10 @@
#include <linux/bcma/bcma_driver_chipcommon.h>
#include <linux/bcma/bcma_driver_pci.h>
#include <linux/bcma/bcma_driver_mips.h>
+#include <linux/bcma/bcma_driver_gmac_cmn.h>
#include <linux/ssb/ssb.h> /* SPROM sharing */
- #include "bcma_regs.h"
+-#include "bcma_regs.h"
++#include <linux/bcma/bcma_regs.h>
+
+ struct bcma_device;
+ struct bcma_bus;
@@ -26,6 +27,11 @@ struct bcma_chipinfo {
u8 pkg;
};
@@ -2877,7 +3511,8 @@
+ u8 num;
struct bcma_drv_cc drv_cc;
- struct bcma_drv_pci drv_pci;
+- struct bcma_drv_pci drv_pci;
++ struct bcma_drv_pci drv_pci[2];
struct bcma_drv_mips drv_mips;
+ struct bcma_drv_gmac_cmn drv_gmac_cmn;
@@ -2893,7 +3528,24 @@
extern int bcma_core_enable(struct bcma_device *core, u32 flags);
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
-@@ -56,6 +56,9 @@
+@@ -24,7 +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_NFLASH 0x00000200 /* NAND flash */
+ #define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */
+ #define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */
+ #define BCMA_PLLTYPE_NONE 0x00000000
+@@ -45,6 +45,7 @@
+ #define BCMA_CC_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
+ #define BCMA_CC_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
+ #define BCMA_CC_CAP_SPROM 0x40000000 /* SPROM present */
++#define BCMA_CC_CAP_NFLASH 0x80000000 /* NAND flash present (rev >= 35 or BCM4706?) */
+ #define BCMA_CC_CORECTL 0x0008
+ #define BCMA_CC_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
+ #define BCMA_CC_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
+@@ -56,6 +57,9 @@
#define BCMA_CC_OTPS_HW_PROTECT 0x00000001
#define BCMA_CC_OTPS_SW_PROTECT 0x00000002
#define BCMA_CC_OTPS_CID_PROTECT 0x00000004
@@ -2903,7 +3555,7 @@
#define BCMA_CC_OTPC 0x0014 /* OTP control */
#define BCMA_CC_OTPC_RECWAIT 0xFF000000
#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00
-@@ -72,6 +75,8 @@
+@@ -72,6 +76,8 @@
#define BCMA_CC_OTPP_READ 0x40000000
#define BCMA_CC_OTPP_START 0x80000000
#define BCMA_CC_OTPP_BUSY 0x80000000
@@ -2912,7 +3564,7 @@
#define BCMA_CC_IRQSTAT 0x0020
#define BCMA_CC_IRQMASK 0x0024
#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */
-@@ -79,6 +84,15 @@
+@@ -79,6 +85,22 @@
#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */
#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */
#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */
@@ -2920,15 +3572,81 @@
+#define BCMA_CC_CHIPST_4313_OTP_PRESENT 2
+#define BCMA_CC_CHIPST_4331_SPROM_PRESENT 2
+#define BCMA_CC_CHIPST_4331_OTP_PRESENT 4
++#define BCMA_CC_CHIPST_43228_ILP_DIV_EN 0x00000001
++#define BCMA_CC_CHIPST_43228_OTP_PRESENT 0x00000002
++#define BCMA_CC_CHIPST_43228_SERDES_REFCLK_PADSEL 0x00000004
++#define BCMA_CC_CHIPST_43228_SDIO_MODE 0x00000008
++#define BCMA_CC_CHIPST_43228_SDIO_OTP_PRESENT 0x00000010
++#define BCMA_CC_CHIPST_43228_SDIO_RESET 0x00000020
+#define BCMA_CC_CHIPST_4706_PKG_OPTION BIT(0) /* 0: full-featured package 1: low-cost package */
+#define BCMA_CC_CHIPST_4706_SFLASH_PRESENT BIT(1) /* 0: parallel, 1: serial flash is present */
+#define BCMA_CC_CHIPST_4706_SFLASH_TYPE BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
+#define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */
+#define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */
++#define BCMA_CC_CHIPST_5357_NAND_BOOT BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
#define BCMA_CC_JCMD_START 0x80000000
#define BCMA_CC_JCMD_BUSY 0x80000000
-@@ -181,6 +195,22 @@
+@@ -108,10 +130,58 @@
+ #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_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 */
+@@ -181,6 +251,45 @@
#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
@@ -2948,18 +3666,95 @@
+#define BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
+#define BCMA_CC_SROM_CONTROL_SIZE_SHIFT 1
+#define BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
++/* Block 0x140 - 0x190 registers are chipset specific */
++#define BCMA_CC_4706_FLASHSCFG 0x18C /* Flash struct configuration */
++#define BCMA_CC_4706_FLASHSCFG_MASK 0x000000ff
++#define BCMA_CC_4706_FLASHSCFG_SF1 0x00000001 /* 2nd serial flash present */
++#define BCMA_CC_4706_FLASHSCFG_PF1 0x00000002 /* 2nd parallel flash present */
++#define BCMA_CC_4706_FLASHSCFG_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */
++#define BCMA_CC_4706_FLASHSCFG_NF1 0x00000008 /* 2nd NAND flash present */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_MASK 0x000000f0
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */
++/* NAND flash registers for BCM4706 (corerev = 31) */
++#define BCMA_CC_NFLASH_CTL 0x01A0
++#define BCMA_CC_NFLASH_CTL_ERR 0x08000000
++#define BCMA_CC_NFLASH_CONF 0x01A4
++#define BCMA_CC_NFLASH_COL_ADDR 0x01A8
++#define BCMA_CC_NFLASH_ROW_ADDR 0x01AC
++#define BCMA_CC_NFLASH_DATA 0x01B0
++#define BCMA_CC_NFLASH_WAITCNT0 0x01B4
/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
#define BCMA_CC_UART0_DATA 0x0300
-@@ -240,7 +270,6 @@
+@@ -240,7 +349,60 @@
#define BCMA_CC_PLLCTL_ADDR 0x0660
#define BCMA_CC_PLLCTL_DATA 0x0664
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
-#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */
++/* NAND flash MLC controller registers (corerev >= 38) */
++#define BCMA_CC_NAND_REVISION 0x0C00
++#define BCMA_CC_NAND_CMD_START 0x0C04
++#define BCMA_CC_NAND_CMD_ADDR_X 0x0C08
++#define BCMA_CC_NAND_CMD_ADDR 0x0C0C
++#define BCMA_CC_NAND_CMD_END_ADDR 0x0C10
++#define BCMA_CC_NAND_CS_NAND_SELECT 0x0C14
++#define BCMA_CC_NAND_CS_NAND_XOR 0x0C18
++#define BCMA_CC_NAND_SPARE_RD0 0x0C20
++#define BCMA_CC_NAND_SPARE_RD4 0x0C24
++#define BCMA_CC_NAND_SPARE_RD8 0x0C28
++#define BCMA_CC_NAND_SPARE_RD12 0x0C2C
++#define BCMA_CC_NAND_SPARE_WR0 0x0C30
++#define BCMA_CC_NAND_SPARE_WR4 0x0C34
++#define BCMA_CC_NAND_SPARE_WR8 0x0C38
++#define BCMA_CC_NAND_SPARE_WR12 0x0C3C
++#define BCMA_CC_NAND_ACC_CONTROL 0x0C40
++#define BCMA_CC_NAND_CONFIG 0x0C48
++#define BCMA_CC_NAND_TIMING_1 0x0C50
++#define BCMA_CC_NAND_TIMING_2 0x0C54
++#define BCMA_CC_NAND_SEMAPHORE 0x0C58
++#define BCMA_CC_NAND_DEVID 0x0C60
++#define BCMA_CC_NAND_DEVID_X 0x0C64
++#define BCMA_CC_NAND_BLOCK_LOCK_STATUS 0x0C68
++#define BCMA_CC_NAND_INTFC_STATUS 0x0C6C
++#define BCMA_CC_NAND_ECC_CORR_ADDR_X 0x0C70
++#define BCMA_CC_NAND_ECC_CORR_ADDR 0x0C74
++#define BCMA_CC_NAND_ECC_UNC_ADDR_X 0x0C78
++#define BCMA_CC_NAND_ECC_UNC_ADDR 0x0C7C
++#define BCMA_CC_NAND_READ_ERROR_COUNT 0x0C80
++#define BCMA_CC_NAND_CORR_STAT_THRESHOLD 0x0C84
++#define BCMA_CC_NAND_READ_ADDR_X 0x0C90
++#define BCMA_CC_NAND_READ_ADDR 0x0C94
++#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR_X 0x0C98
++#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR 0x0C9C
++#define BCMA_CC_NAND_COPY_BACK_ADDR_X 0x0CA0
++#define BCMA_CC_NAND_COPY_BACK_ADDR 0x0CA4
++#define BCMA_CC_NAND_BLOCK_ERASE_ADDR_X 0x0CA8
++#define BCMA_CC_NAND_BLOCK_ERASE_ADDR 0x0CAC
++#define BCMA_CC_NAND_INV_READ_ADDR_X 0x0CB0
++#define BCMA_CC_NAND_INV_READ_ADDR 0x0CB4
++#define BCMA_CC_NAND_BLK_WR_PROTECT 0x0CC0
++#define BCMA_CC_NAND_ACC_CONTROL_CS1 0x0CD0
++#define BCMA_CC_NAND_CONFIG_CS1 0x0CD4
++#define BCMA_CC_NAND_TIMING_1_CS1 0x0CD8
++#define BCMA_CC_NAND_TIMING_2_CS1 0x0CDC
++#define BCMA_CC_NAND_SPARE_RD16 0x0D30
++#define BCMA_CC_NAND_SPARE_RD20 0x0D34
++#define BCMA_CC_NAND_SPARE_RD24 0x0D38
++#define BCMA_CC_NAND_SPARE_RD28 0x0D3C
++#define BCMA_CC_NAND_CACHE_ADDR 0x0D40
++#define BCMA_CC_NAND_CACHE_DATA 0x0D44
++#define BCMA_CC_NAND_CTRL_CONFIG 0x0D48
++#define BCMA_CC_NAND_CTRL_STATUS 0x0D4C
/* Divider allocation in 4716/47162/5356 */
#define BCMA_CC_PMU5_MAINPLL_CPU 1
-@@ -256,6 +285,15 @@
+@@ -256,6 +418,15 @@
/* 4706 PMU */
#define BCMA_CC_PMU4706_MAINPLL_PLL0 0
@@ -2975,7 +3770,7 @@
/* ALP clock on pre-PMU chips */
#define BCMA_CC_PMU_ALP_CLOCK 20000000
-@@ -284,6 +322,19 @@
+@@ -284,6 +455,19 @@
#define BCMA_CC_PPL_PCHI_OFF 5
#define BCMA_CC_PPL_PCHI_MASK 0x0000003f
@@ -2995,7 +3790,7 @@
/* BCM4331 ChipControl numbers. */
#define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */
#define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */
-@@ -297,9 +348,18 @@
+@@ -297,9 +481,25 @@
#define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN BIT(9) /* override core control on pipe_AuxPowerDown */
#define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN BIT(10) /* pcie_auxclkenable */
#define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN BIT(11) /* pcie_pipe_pllpowerdown */
@@ -3011,10 +3806,88 @@
+/* 4313 Chip specific ChipControl register bits */
+#define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
+
++/* BCM5357 ChipControl register bits */
++#define BCMA_CHIPCTL_5357_EXTPA BIT(14)
++#define BCMA_CHIPCTL_5357_ANT_MUX_2O3 BIT(15)
++#define BCMA_CHIPCTL_5357_NFLASH BIT(16)
++#define BCMA_CHIPCTL_5357_I2S_PINS_ENABLE BIT(18)
++#define BCMA_CHIPCTL_5357_I2CSPI_PINS_ENABLE BIT(19)
++
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/
-@@ -387,5 +447,6 @@ extern void bcma_chipco_chipctl_maskset(
+@@ -310,11 +510,35 @@ struct bcma_chipcommon_pmu {
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash {
++ bool present;
+ u8 buswidth;
+ u32 window;
+ u32 window_size;
+ };
+
++#ifdef CONFIG_BCMA_SFLASH
++struct bcma_sflash {
++ bool present;
++ u32 window;
++ u32 blocksize;
++ u16 numblocks;
++ u32 size;
++
++ struct mtd_info *mtd;
++};
++#endif
++
++#ifdef CONFIG_BCMA_NFLASH
++struct mtd_info;
++
++struct bcma_nflash {
++ bool present;
++ bool boot; /* This is the flash the SoC boots from */
++
++ struct mtd_info *mtd;
++};
++#endif
++
+ struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+@@ -330,11 +554,18 @@ struct bcma_drv_cc {
+ u32 capabilities;
+ u32 capabilities_ext;
+ u8 setup_done:1;
++ u8 early_setup_done:1;
+ /* Fast Powerup Delay constant */
+ u16 fast_pwrup_delay;
+ struct bcma_chipcommon_pmu pmu;
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash pflash;
++#ifdef CONFIG_BCMA_SFLASH
++ struct bcma_sflash sflash;
++#endif
++#ifdef CONFIG_BCMA_NFLASH
++ struct bcma_nflash nflash;
++#endif
+
+ int nr_serial_ports;
+ struct bcma_serial_port serial_ports[4];
+@@ -355,6 +586,7 @@ struct bcma_drv_cc {
+ bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+
+ extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
++extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+
+ extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
+@@ -378,6 +610,7 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+
+ /* PMU support */
+ extern void bcma_pmu_init(struct bcma_drv_cc *cc);
++extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
+
+ extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ u32 value);
+@@ -387,5 +620,6 @@ extern void bcma_chipco_chipctl_maskset(
u32 offset, u32 mask, u32 set);
extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
u32 offset, u32 mask, u32 set);
@@ -3124,6 +3997,25 @@
+#endif
+
+#endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */
+--- a/include/linux/bcma/bcma_driver_mips.h
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -35,13 +35,16 @@ struct bcma_device;
+ struct bcma_drv_mips {
+ struct bcma_device *core;
+ u8 setup_done:1;
++ u8 early_setup_done:1;
+ unsigned int assigned_irqs;
+ };
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
+ #else
+ static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
+ #endif
+
+ extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -53,11 +53,47 @@ struct pci_dev;
@@ -3296,7 +4188,21 @@
#endif /* LINUX_BCMA_DRIVER_PCI_H_ */
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
-@@ -56,4 +56,31 @@
+@@ -11,11 +11,13 @@
+ #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_EXTRESREQ_SHIFT 8
+ #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 */
++#define BCMA_CLKCTLST_EXTRESST_SHIFT 24
+ /* 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 */
+@@ -56,4 +58,36 @@
#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
@@ -3327,4 +4233,9 @@
+ * (2 ZettaBytes), high 32 bits
+ */
+
++#define BCMA_SOC_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
++#define BCMA_SOC_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
++#define BCMA_SOC_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
++#define BCMA_SOC_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
++
#endif /* LINUX_BCMA_REGS_H_ */
diff --git a/target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch b/target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch
deleted file mode 100644
index 35ca6b81e..000000000
--- a/target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/drivers/bcma/driver_chipcommon_pmu.c
-+++ b/drivers/bcma/driver_chipcommon_pmu.c
-@@ -110,7 +110,7 @@ void bcma_pmu_workarounds(struct bcma_dr
- /* enable 12 mA drive strenth for 4313 and set chipControl
- register bit 1 */
- bcma_chipco_chipctl_maskset(cc, 0,
-- BCMA_CCTRL_4313_12MA_LED_DRIVE,
-+ ~BCMA_CCTRL_4313_12MA_LED_DRIVE,
- BCMA_CCTRL_4313_12MA_LED_DRIVE);
- break;
- case BCMA_CHIP_ID_BCM4331:
-@@ -124,14 +124,14 @@ void bcma_pmu_workarounds(struct bcma_dr
- register bit 15 */
- if (bus->chipinfo.rev == 0) {
- bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
-- BCMA_CCTRL_43224_GPIO_TOGGLE,
-+ ~BCMA_CCTRL_43224_GPIO_TOGGLE,
- BCMA_CCTRL_43224_GPIO_TOGGLE);
- bcma_chipco_chipctl_maskset(cc, 0,
-- BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
-+ ~BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
- BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
- } else {
- bcma_chipco_chipctl_maskset(cc, 0,
-- BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
-+ ~BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
- BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
- }
- break;
diff --git a/target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch b/target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch
deleted file mode 100644
index dc8367b6c..000000000
--- a/target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch
+++ /dev/null
@@ -1,55 +0,0 @@
---- a/drivers/bcma/scan.c
-+++ b/drivers/bcma/scan.c
-@@ -462,8 +462,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
- while (eromptr < eromend) {
- struct bcma_device *other_core;
- struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
-- if (!core)
-- return -ENOMEM;
-+ if (!core) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
- INIT_LIST_HEAD(&core->list);
- core->bus = bus;
-
-@@ -478,7 +480,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
- } else if (err == -ESPIPE) {
- break;
- }
-- return err;
-+ goto out;
- }
-
- core->core_index = core_num++;
-@@ -494,10 +496,12 @@ int bcma_bus_scan(struct bcma_bus *bus)
- list_add_tail(&core->list, &bus->cores);
- }
-
-+ err = 0;
-+out:
- if (bus->hosttype == BCMA_HOSTTYPE_SOC)
- iounmap(eromptr);
-
-- return 0;
-+ return err;
- }
-
- int __init bcma_bus_scan_early(struct bcma_bus *bus,
-@@ -537,7 +541,7 @@ int __init bcma_bus_scan_early(struct bc
- else if (err == -ESPIPE)
- break;
- else if (err < 0)
-- return err;
-+ goto out;
-
- core->core_index = core_num++;
- bus->nr_cores++;
-@@ -551,6 +555,7 @@ int __init bcma_bus_scan_early(struct bc
- break;
- }
-
-+out:
- if (bus->hosttype == BCMA_HOSTTYPE_SOC)
- iounmap(eromptr);
-
diff --git a/target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch b/target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch
deleted file mode 100644
index 9386af29c..000000000
--- a/target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch
+++ /dev/null
@@ -1,29 +0,0 @@
---- a/drivers/bcma/driver_mips.c
-+++ b/drivers/bcma/driver_mips.c
-@@ -131,7 +131,7 @@ static void bcma_core_mips_set_irq(struc
- /* backplane irq line is in use, find out who uses
- * it and set user to irq 0
- */
-- list_for_each_entry_reverse(core, &bus->cores, list) {
-+ list_for_each_entry(core, &bus->cores, list) {
- if ((1 << bcma_core_mips_irqflag(core)) ==
- oldirqflag) {
- bcma_core_mips_set_irq(core, 0);
-@@ -161,7 +161,7 @@ static void bcma_core_mips_dump_irq(stru
- {
- struct bcma_device *core;
-
-- list_for_each_entry_reverse(core, &bus->cores, list) {
-+ list_for_each_entry(core, &bus->cores, list) {
- bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
- }
- }
-@@ -215,7 +215,7 @@ void bcma_core_mips_init(struct bcma_drv
- mcore->assigned_irqs = 1;
-
- /* Assign IRQs to all cores on the bus */
-- list_for_each_entry_reverse(core, &bus->cores, list) {
-+ list_for_each_entry(core, &bus->cores, list) {
- int mips_irq;
- if (core->irq)
- continue;
diff --git a/target/linux/generic/patches-3.3/029-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch b/target/linux/generic/patches-3.3/029-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch
deleted file mode 100644
index b6e648056..000000000
--- a/target/linux/generic/patches-3.3/029-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/drivers/bcma/sprom.c
-+++ b/drivers/bcma/sprom.c
-@@ -591,8 +591,11 @@ int bcma_sprom_get(struct bcma_bus *bus)
- bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
-
- err = bcma_sprom_valid(sprom);
-- if (err)
-+ if (err) {
-+ bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
-+ err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
- goto out;
-+ }
-
- bcma_sprom_extract_r8(bus, sprom);
-
diff --git a/target/linux/generic/patches-3.6/020-ssb_update.patch b/target/linux/generic/patches-3.6/020-ssb_update.patch
new file mode 100644
index 000000000..e61be82fe
--- /dev/null
+++ b/target/linux/generic/patches-3.6/020-ssb_update.patch
@@ -0,0 +1,82 @@
+--- a/drivers/ssb/driver_mipscore.c
++++ b/drivers/ssb/driver_mipscore.c
+@@ -190,16 +190,32 @@ static void ssb_mips_flash_detect(struct
+ {
+ struct ssb_bus *bus = mcore->dev->bus;
+
+- mcore->flash_buswidth = 2;
+- if (bus->chipco.dev) {
+- mcore->flash_window = 0x1c000000;
+- mcore->flash_window_size = 0x02000000;
++ /* When there is no chipcommon on the bus there is 4MB flash */
++ if (!bus->chipco.dev) {
++ mcore->pflash.present = true;
++ mcore->pflash.buswidth = 2;
++ mcore->pflash.window = SSB_FLASH1;
++ mcore->pflash.window_size = SSB_FLASH1_SZ;
++ return;
++ }
++
++ /* There is ChipCommon, so use it to read info about flash */
++ switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
++ case SSB_CHIPCO_FLASHT_STSER:
++ case SSB_CHIPCO_FLASHT_ATSER:
++ pr_err("Serial flash not supported\n");
++ break;
++ case SSB_CHIPCO_FLASHT_PARA:
++ pr_debug("Found parallel flash\n");
++ mcore->pflash.present = true;
++ mcore->pflash.window = SSB_FLASH2;
++ mcore->pflash.window_size = SSB_FLASH2_SZ;
+ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+ & SSB_CHIPCO_CFG_DS16) == 0)
+- mcore->flash_buswidth = 1;
+- } else {
+- mcore->flash_window = 0x1fc00000;
+- mcore->flash_window_size = 0x00400000;
++ mcore->pflash.buswidth = 1;
++ else
++ mcore->pflash.buswidth = 2;
++ break;
+ }
+ }
+
+--- a/include/linux/ssb/ssb_driver_chipcommon.h
++++ b/include/linux/ssb/ssb_driver_chipcommon.h
+@@ -504,7 +504,9 @@
+ #define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
+ #define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
+ #define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
+-#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
++#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
++#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
++#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
+
+ /* Status register bits for ST flashes */
+ #define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
+--- a/include/linux/ssb/ssb_driver_mips.h
++++ b/include/linux/ssb/ssb_driver_mips.h
+@@ -13,6 +13,12 @@ struct ssb_serial_port {
+ unsigned int reg_shift;
+ };
+
++struct ssb_pflash {
++ bool present;
++ u8 buswidth;
++ u32 window;
++ u32 window_size;
++};
+
+ struct ssb_mipscore {
+ struct ssb_device *dev;
+@@ -20,9 +26,7 @@ struct ssb_mipscore {
+ int nr_serial_ports;
+ struct ssb_serial_port serial_ports[4];
+
+- u8 flash_buswidth;
+- u32 flash_window;
+- u32 flash_window_size;
++ struct ssb_pflash pflash;
+ };
+
+ extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
diff --git a/target/linux/generic/patches-3.6/025-bcma_backport.patch b/target/linux/generic/patches-3.6/025-bcma_backport.patch
new file mode 100644
index 000000000..d791f16a0
--- /dev/null
+++ b/target/linux/generic/patches-3.6/025-bcma_backport.patch
@@ -0,0 +1,1035 @@
+--- a/drivers/bcma/Kconfig
++++ b/drivers/bcma/Kconfig
+@@ -48,12 +48,12 @@ config BCMA_DRIVER_MIPS
+
+ config BCMA_SFLASH
+ bool
+- depends on BCMA_DRIVER_MIPS && BROKEN
++ depends on BCMA_DRIVER_MIPS
+ default y
+
+ config BCMA_NFLASH
+ bool
+- depends on BCMA_DRIVER_MIPS && BROKEN
++ depends on BCMA_DRIVER_MIPS
+ default y
+
+ config BCMA_DRIVER_GMAC_CMN
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -54,6 +54,7 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr
+ #ifdef CONFIG_BCMA_SFLASH
+ /* driver_chipcommon_sflash.c */
+ int bcma_sflash_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_sflash_dev;
+ #else
+ static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
+ {
+@@ -65,6 +66,7 @@ static inline int bcma_sflash_init(struc
+ #ifdef CONFIG_BCMA_NFLASH
+ /* driver_chipcommon_nflash.c */
+ int bcma_nflash_init(struct bcma_drv_cc *cc);
++extern struct platform_device bcma_nflash_dev;
+ #else
+ static inline int bcma_nflash_init(struct bcma_drv_cc *cc)
+ {
+--- a/drivers/bcma/core.c
++++ b/drivers/bcma/core.c
+@@ -65,7 +65,7 @@ void bcma_core_set_clockmode(struct bcma
+ switch (clkmode) {
+ case BCMA_CLKMODE_FAST:
+ bcma_set32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT);
+- udelay(64);
++ usleep_range(64, 300);
+ for (i = 0; i < 1500; i++) {
+ if (bcma_read32(core, BCMA_CLKCTLST) &
+ BCMA_CLKCTLST_HAVEHT) {
+--- a/drivers/bcma/driver_chipcommon.c
++++ b/drivers/bcma/driver_chipcommon.c
+@@ -22,12 +22,9 @@ static inline u32 bcma_cc_write32_masked
+ return value;
+ }
+
+-void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
++void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
+ {
+- u32 leddc_on = 10;
+- u32 leddc_off = 90;
+-
+- if (cc->setup_done)
++ if (cc->early_setup_done)
+ return;
+
+ if (cc->core->id.rev >= 11)
+@@ -36,6 +33,22 @@ void bcma_core_chipcommon_init(struct bc
+ if (cc->core->id.rev >= 35)
+ cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
+
++ if (cc->capabilities & BCMA_CC_CAP_PMU)
++ bcma_pmu_early_init(cc);
++
++ cc->early_setup_done = true;
++}
++
++void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
++{
++ u32 leddc_on = 10;
++ u32 leddc_off = 90;
++
++ if (cc->setup_done)
++ return;
++
++ bcma_core_chipcommon_early_init(cc);
++
+ if (cc->core->id.rev >= 20) {
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
+--- a/drivers/bcma/driver_chipcommon_nflash.c
++++ b/drivers/bcma/driver_chipcommon_nflash.c
+@@ -5,15 +5,40 @@
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
++#include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+-#include <linux/bcma/bcma_driver_chipcommon.h>
+-#include <linux/delay.h>
+
+ #include "bcma_private.h"
+
++struct platform_device bcma_nflash_dev = {
++ .name = "bcma_nflash",
++ .num_resources = 0,
++};
++
+ /* Initialize NAND flash access */
+ int bcma_nflash_init(struct bcma_drv_cc *cc)
+ {
+- bcma_err(cc->core->bus, "NAND flash support is broken\n");
++ struct bcma_bus *bus = cc->core->bus;
++
++ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
++ cc->core->id.rev != 0x38) {
++ bcma_err(bus, "NAND flash on unsupported board!\n");
++ return -ENOTSUPP;
++ }
++
++ if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) {
++ bcma_err(bus, "NAND flash not present according to ChipCommon\n");
++ return -ENODEV;
++ }
++
++ cc->nflash.present = true;
++ if (cc->core->id.rev == 38 &&
++ (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT))
++ cc->nflash.boot = true;
++
++ /* Prepare platform device, but don't register it yet. It's too early,
++ * malloc (required by device_private_init) is not available yet. */
++ bcma_nflash_dev.dev.platform_data = &cc->nflash;
++
+ return 0;
+ }
+--- a/drivers/bcma/driver_chipcommon_pmu.c
++++ b/drivers/bcma/driver_chipcommon_pmu.c
+@@ -76,7 +76,10 @@ static void bcma_pmu_resources_init(stru
+ if (max_msk)
+ bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+
+- /* Add some delay; allow resources to come up and settle. */
++ /*
++ * Add some delay; allow resources to come up and settle.
++ * Delay is required for SoC (early init).
++ */
+ mdelay(2);
+ }
+
+@@ -101,7 +104,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ct
+ bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
+ }
+
+-void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
++static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+ {
+ struct bcma_bus *bus = cc->core->bus;
+
+@@ -141,7 +144,7 @@ void bcma_pmu_workarounds(struct bcma_dr
+ }
+ }
+
+-void bcma_pmu_init(struct bcma_drv_cc *cc)
++void bcma_pmu_early_init(struct bcma_drv_cc *cc)
+ {
+ u32 pmucap;
+
+@@ -150,7 +153,10 @@ void bcma_pmu_init(struct bcma_drv_cc *c
+
+ bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
+ cc->pmu.rev, pmucap);
++}
+
++void bcma_pmu_init(struct bcma_drv_cc *cc)
++{
+ if (cc->pmu.rev == 1)
+ bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
+ ~BCMA_CC_PMU_CTL_NOILPONW);
+@@ -257,7 +263,7 @@ static u32 bcma_pmu_clock_bcm4706(struct
+ }
+
+ /* query bus clock frequency for PMU-enabled chipcommon */
+-u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
++static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+ {
+ struct bcma_bus *bus = cc->core->bus;
+
+--- a/drivers/bcma/driver_chipcommon_sflash.c
++++ b/drivers/bcma/driver_chipcommon_sflash.c
+@@ -5,15 +5,161 @@
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
++#include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+-#include <linux/bcma/bcma_driver_chipcommon.h>
+-#include <linux/delay.h>
+
+ #include "bcma_private.h"
+
++static struct resource bcma_sflash_resource = {
++ .name = "bcma_sflash",
++ .start = BCMA_SOC_FLASH2,
++ .end = 0,
++ .flags = IORESOURCE_MEM | IORESOURCE_READONLY,
++};
++
++struct platform_device bcma_sflash_dev = {
++ .name = "bcma_sflash",
++ .resource = &bcma_sflash_resource,
++ .num_resources = 1,
++};
++
++struct bcma_sflash_tbl_e {
++ char *name;
++ u32 id;
++ u32 blocksize;
++ u16 numblocks;
++};
++
++static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
++ { "M25P20", 0x11, 0x10000, 4, },
++ { "M25P40", 0x12, 0x10000, 8, },
++
++ { "M25P16", 0x14, 0x10000, 32, },
++ { "M25P32", 0x14, 0x10000, 64, },
++ { "M25P64", 0x16, 0x10000, 128, },
++ { "M25FL128", 0x17, 0x10000, 256, },
++ { 0 },
++};
++
++static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
++ { "SST25WF512", 1, 0x1000, 16, },
++ { "SST25VF512", 0x48, 0x1000, 16, },
++ { "SST25WF010", 2, 0x1000, 32, },
++ { "SST25VF010", 0x49, 0x1000, 32, },
++ { "SST25WF020", 3, 0x1000, 64, },
++ { "SST25VF020", 0x43, 0x1000, 64, },
++ { "SST25WF040", 4, 0x1000, 128, },
++ { "SST25VF040", 0x44, 0x1000, 128, },
++ { "SST25VF040B", 0x8d, 0x1000, 128, },
++ { "SST25WF080", 5, 0x1000, 256, },
++ { "SST25VF080B", 0x8e, 0x1000, 256, },
++ { "SST25VF016", 0x41, 0x1000, 512, },
++ { "SST25VF032", 0x4a, 0x1000, 1024, },
++ { "SST25VF064", 0x4b, 0x1000, 2048, },
++ { 0 },
++};
++
++static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
++ { "AT45DB011", 0xc, 256, 512, },
++ { "AT45DB021", 0x14, 256, 1024, },
++ { "AT45DB041", 0x1c, 256, 2048, },
++ { "AT45DB081", 0x24, 256, 4096, },
++ { "AT45DB161", 0x2c, 512, 4096, },
++ { "AT45DB321", 0x34, 512, 8192, },
++ { "AT45DB642", 0x3c, 1024, 8192, },
++ { 0 },
++};
++
++static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
++{
++ int i;
++ bcma_cc_write32(cc, BCMA_CC_FLASHCTL,
++ BCMA_CC_FLASHCTL_START | opcode);
++ for (i = 0; i < 1000; i++) {
++ if (!(bcma_cc_read32(cc, BCMA_CC_FLASHCTL) &
++ BCMA_CC_FLASHCTL_BUSY))
++ return;
++ cpu_relax();
++ }
++ bcma_err(cc->core->bus, "SFLASH control command failed (timeout)!\n");
++}
++
+ /* Initialize serial flash access */
+ int bcma_sflash_init(struct bcma_drv_cc *cc)
+ {
+- bcma_err(cc->core->bus, "Serial flash support is broken\n");
++ struct bcma_bus *bus = cc->core->bus;
++ struct bcma_sflash *sflash = &cc->sflash;
++ struct bcma_sflash_tbl_e *e;
++ u32 id, id2;
++
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
++ case BCMA_CC_FLASHT_STSER:
++ 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);
++
++ 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 (id) {
++ case 0xbf:
++ for (e = bcma_sflash_sst_tbl; e->name; e++) {
++ if (e->id == id2)
++ break;
++ }
++ break;
++ case 0x13:
++ return -ENOTSUPP;
++ default:
++ for (e = bcma_sflash_st_tbl; e->name; e++) {
++ if (e->id == id)
++ break;
++ }
++ break;
++ }
++ if (!e->name) {
++ bcma_err(bus, "Unsupported ST serial flash (id: 0x%X, id2: 0x%X)\n", id, id2);
++ return -ENOTSUPP;
++ }
++
++ break;
++ case BCMA_CC_FLASHT_ATSER:
++ bcma_sflash_cmd(cc, BCMA_CC_FLASHCTL_AT_STATUS);
++ id = bcma_cc_read32(cc, BCMA_CC_FLASHDATA) & 0x3c;
++
++ for (e = bcma_sflash_at_tbl; e->name; e++) {
++ if (e->id == id)
++ break;
++ }
++ if (!e->name) {
++ bcma_err(bus, "Unsupported Atmel serial flash (id: 0x%X)\n", id);
++ return -ENOTSUPP;
++ }
++
++ break;
++ default:
++ bcma_err(bus, "Unsupported flash type\n");
++ return -ENOTSUPP;
++ }
++
++ sflash->window = BCMA_SOC_FLASH2;
++ sflash->blocksize = e->blocksize;
++ sflash->numblocks = e->numblocks;
++ sflash->size = sflash->blocksize * sflash->numblocks;
++ sflash->present = true;
++
++ bcma_info(bus, "Found %s serial flash (size: %dKiB, blocksize: 0x%X, blocks: %d)\n",
++ e->name, sflash->size / 1024, sflash->blocksize,
++ sflash->numblocks);
++
++ /* Prepare platform device, but don't register it yet. It's too early,
++ * malloc (required by device_private_init) is not available yet. */
++ bcma_sflash_dev.resource[0].end = bcma_sflash_dev.resource[0].start +
++ sflash->size;
++ bcma_sflash_dev.dev.platform_data = sflash;
++
+ return 0;
+ }
+--- a/drivers/bcma/driver_mips.c
++++ b/drivers/bcma/driver_mips.c
+@@ -181,47 +181,66 @@ EXPORT_SYMBOL(bcma_cpu_clock);
+ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+ {
+ struct bcma_bus *bus = mcore->core->bus;
++ struct bcma_drv_cc *cc = &bus->drv_cc;
+
+- switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
++ switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+ case BCMA_CC_FLASHT_STSER:
+ case BCMA_CC_FLASHT_ATSER:
+ bcma_debug(bus, "Found serial flash\n");
+- bcma_sflash_init(&bus->drv_cc);
++ bcma_sflash_init(cc);
+ break;
+ case BCMA_CC_FLASHT_PARA:
+ bcma_debug(bus, "Found parallel flash\n");
+- bus->drv_cc.pflash.window = 0x1c000000;
+- bus->drv_cc.pflash.window_size = 0x02000000;
++ cc->pflash.present = true;
++ cc->pflash.window = BCMA_SOC_FLASH2;
++ cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
+
+- if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
++ if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
+ BCMA_CC_FLASH_CFG_DS) == 0)
+- bus->drv_cc.pflash.buswidth = 1;
++ cc->pflash.buswidth = 1;
+ else
+- bus->drv_cc.pflash.buswidth = 2;
++ cc->pflash.buswidth = 2;
+ break;
+ default:
+ bcma_err(bus, "Flash type not supported\n");
+ }
+
+- if (bus->drv_cc.core->id.rev == 38 ||
++ if (cc->core->id.rev == 38 ||
+ bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+- if (bus->drv_cc.capabilities & BCMA_CC_CAP_NFLASH) {
++ if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
+ bcma_debug(bus, "Found NAND flash\n");
+- bcma_nflash_init(&bus->drv_cc);
++ bcma_nflash_init(cc);
+ }
+ }
+ }
+
++void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
++{
++ struct bcma_bus *bus = mcore->core->bus;
++
++ if (mcore->early_setup_done)
++ return;
++
++ bcma_chipco_serial_init(&bus->drv_cc);
++ bcma_core_mips_flash_detect(mcore);
++
++ mcore->early_setup_done = true;
++}
++
+ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
+ {
+ struct bcma_bus *bus;
+ struct bcma_device *core;
+ bus = mcore->core->bus;
+
++ if (mcore->setup_done)
++ return;
++
+ bcma_info(bus, "Initializing MIPS core...\n");
+
+- if (!mcore->setup_done)
+- mcore->assigned_irqs = 1;
++ bcma_core_mips_early_init(mcore);
++
++ mcore->assigned_irqs = 1;
+
+ /* Assign IRQs to all cores on the bus */
+ list_for_each_entry(core, &bus->cores, list) {
+@@ -256,10 +275,5 @@ void bcma_core_mips_init(struct bcma_drv
+ bcma_info(bus, "IRQ reconfiguration done\n");
+ bcma_core_mips_dump_irq(bus);
+
+- if (mcore->setup_done)
+- return;
+-
+- bcma_chipco_serial_init(&bus->drv_cc);
+- bcma_core_mips_flash_detect(mcore);
+ mcore->setup_done = true;
+ }
+--- a/drivers/bcma/driver_pci.c
++++ b/drivers/bcma/driver_pci.c
+@@ -51,7 +51,7 @@ static void bcma_pcie_mdio_set_phy(struc
+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
+ break;
+- msleep(1);
++ usleep_range(1000, 2000);
+ }
+ }
+
+@@ -92,7 +92,7 @@ static u16 bcma_pcie_mdio_read(struct bc
+ ret = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_DATA);
+ break;
+ }
+- msleep(1);
++ usleep_range(1000, 2000);
+ }
+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
+ return ret;
+@@ -132,7 +132,7 @@ static void bcma_pcie_mdio_write(struct
+ v = pcicore_read32(pc, BCMA_CORE_PCI_MDIO_CONTROL);
+ if (v & BCMA_CORE_PCI_MDIOCTL_ACCESS_DONE)
+ break;
+- msleep(1);
++ usleep_range(1000, 2000);
+ }
+ pcicore_write32(pc, BCMA_CORE_PCI_MDIO_CONTROL, 0);
+ }
+--- a/drivers/bcma/driver_pci_host.c
++++ b/drivers/bcma/driver_pci_host.c
+@@ -35,11 +35,6 @@ bool __devinit bcma_core_pci_is_in_hostm
+ chipid_top != 0x5300)
+ return false;
+
+- if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
+- bcma_info(bus, "This PCI core is disabled and not working\n");
+- return false;
+- }
+-
+ bcma_core_enable(pc->core, 0);
+
+ return !mips_busprobe32(tmp, pc->core->io_addr);
+@@ -396,6 +391,11 @@ void __devinit bcma_core_pci_hostmode_in
+
+ bcma_info(bus, "PCIEcore in host mode found\n");
+
++ if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
++ bcma_info(bus, "This PCIE core is disabled and not working\n");
++ return;
++ }
++
+ pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
+ if (!pc_host) {
+ bcma_err(bus, "can not allocate memory");
+@@ -425,9 +425,9 @@ void __devinit bcma_core_pci_hostmode_in
+ pc_host->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
+
+ /* Reset RC */
+- udelay(3000);
++ usleep_range(3000, 5000);
+ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST_OE);
+- udelay(1000);
++ usleep_range(1000, 2000);
+ pcicore_write32(pc, BCMA_CORE_PCI_CTL, BCMA_CORE_PCI_CTL_RST |
+ BCMA_CORE_PCI_CTL_RST_OE);
+
+@@ -452,6 +452,8 @@ void __devinit bcma_core_pci_hostmode_in
+ pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
+ pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
+ BCMA_SOC_PCI_MEM_SZ - 1;
++ pc_host->io_resource.start = 0x100;
++ pc_host->io_resource.end = 0x47F;
+ pci_membase_1G = BCMA_SOC_PCIE_DMA_H32;
+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+ tmp | BCMA_SOC_PCI_MEM);
+@@ -459,6 +461,8 @@ void __devinit bcma_core_pci_hostmode_in
+ pc_host->mem_resource.start = BCMA_SOC_PCI1_MEM;
+ pc_host->mem_resource.end = BCMA_SOC_PCI1_MEM +
+ BCMA_SOC_PCI_MEM_SZ - 1;
++ pc_host->io_resource.start = 0x480;
++ pc_host->io_resource.end = 0x7FF;
+ pci_membase_1G = BCMA_SOC_PCIE1_DMA_H32;
+ pc_host->host_cfg_addr = BCMA_SOC_PCI1_CFG;
+ pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
+@@ -481,7 +485,7 @@ void __devinit bcma_core_pci_hostmode_in
+ * before issuing configuration requests to PCI Express
+ * devices.
+ */
+- udelay(100000);
++ msleep(100);
+
+ bcma_core_pci_enable_crs(pc);
+
+@@ -501,7 +505,7 @@ void __devinit bcma_core_pci_hostmode_in
+ set_io_port_base(pc_host->pci_controller.io_map_base);
+ /* Give some time to the PCI controller to configure itself with the new
+ * values. Not waiting at this point causes crashes of the machine. */
+- mdelay(10);
++ usleep_range(10000, 15000);
+ register_pci_controller(&pc_host->pci_controller);
+ return;
+ }
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct
+ }
+
+ #ifdef CONFIG_BCMA_BLOCKIO
+-void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+- size_t count, u16 offset, u8 reg_width)
++static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
++ size_t count, u16 offset, u8 reg_width)
+ {
+ void __iomem *addr = core->bus->mmio + offset;
+ if (core->bus->mapped_core != core)
+@@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcm
+ }
+ }
+
+-void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
+- size_t count, u16 offset, u8 reg_width)
++static void bcma_host_pci_block_write(struct bcma_device *core,
++ const void *buffer, size_t count,
++ u16 offset, u8 reg_width)
+ {
+ void __iomem *addr = core->bus->mmio + offset;
+ if (core->bus->mapped_core != core)
+@@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struc
+ iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+ }
+
+-const struct bcma_host_ops bcma_host_pci_ops = {
++static const struct bcma_host_ops bcma_host_pci_ops = {
+ .read8 = bcma_host_pci_read8,
+ .read16 = bcma_host_pci_read16,
+ .read32 = bcma_host_pci_read32,
+@@ -272,6 +273,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
++ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ { 0, },
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struc
+ writel(value, core->io_wrap + offset);
+ }
+
+-const struct bcma_host_ops bcma_host_soc_ops = {
++static const struct bcma_host_ops bcma_host_soc_ops = {
+ .read8 = bcma_host_soc_read8,
+ .read16 = bcma_host_soc_read16,
+ .read32 = bcma_host_soc_read32,
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -7,6 +7,7 @@
+
+ #include "bcma_private.h"
+ #include <linux/module.h>
++#include <linux/platform_device.h>
+ #include <linux/bcma/bcma.h>
+ #include <linux/slab.h>
+
+@@ -80,6 +81,18 @@ struct bcma_device *bcma_find_core(struc
+ }
+ EXPORT_SYMBOL_GPL(bcma_find_core);
+
++static struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
++ u8 unit)
++{
++ struct bcma_device *core;
++
++ list_for_each_entry(core, &bus->cores, list) {
++ if (core->id.id == coreid && core->core_unit == unit)
++ return core;
++ }
++ return NULL;
++}
++
+ static void bcma_release_core_dev(struct device *dev)
+ {
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+@@ -136,14 +149,31 @@ static int bcma_register_cores(struct bc
+ dev_id++;
+ }
+
++#ifdef CONFIG_BCMA_SFLASH
++ if (bus->drv_cc.sflash.present) {
++ err = platform_device_register(&bcma_sflash_dev);
++ if (err)
++ bcma_err(bus, "Error registering serial flash\n");
++ }
++#endif
++
++#ifdef CONFIG_BCMA_NFLASH
++ if (bus->drv_cc.nflash.present) {
++ err = platform_device_register(&bcma_nflash_dev);
++ if (err)
++ bcma_err(bus, "Error registering NAND flash\n");
++ }
++#endif
++
+ return 0;
+ }
+
+ static void bcma_unregister_cores(struct bcma_bus *bus)
+ {
+- struct bcma_device *core;
++ struct bcma_device *core, *tmp;
+
+- list_for_each_entry(core, &bus->cores, list) {
++ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
++ list_del(&core->list);
+ if (core->dev_registered)
+ device_unregister(&core->dev);
+ }
+@@ -165,6 +195,20 @@ int __devinit bcma_bus_register(struct b
+ return -1;
+ }
+
++ /* Early init CC core */
++ core = bcma_find_core(bus, bcma_cc_core_id(bus));
++ if (core) {
++ bus->drv_cc.core = core;
++ bcma_core_chipcommon_early_init(&bus->drv_cc);
++ }
++
++ /* Try to get SPROM */
++ err = bcma_sprom_get(bus);
++ if (err == -ENOENT) {
++ bcma_err(bus, "No SPROM available\n");
++ } else if (err)
++ bcma_err(bus, "Failed to get SPROM: %d\n", err);
++
+ /* Init CC core */
+ core = bcma_find_core(bus, bcma_cc_core_id(bus));
+ if (core) {
+@@ -180,10 +224,17 @@ int __devinit bcma_bus_register(struct b
+ }
+
+ /* Init PCIE core */
+- core = bcma_find_core(bus, BCMA_CORE_PCIE);
++ core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 0);
+ if (core) {
+- bus->drv_pci.core = core;
+- bcma_core_pci_init(&bus->drv_pci);
++ bus->drv_pci[0].core = core;
++ bcma_core_pci_init(&bus->drv_pci[0]);
++ }
++
++ /* Init PCIE core */
++ core = bcma_find_core_unit(bus, BCMA_CORE_PCIE, 1);
++ if (core) {
++ bus->drv_pci[1].core = core;
++ bcma_core_pci_init(&bus->drv_pci[1]);
+ }
+
+ /* Init GBIT MAC COMMON core */
+@@ -193,13 +244,6 @@ int __devinit bcma_bus_register(struct b
+ bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn);
+ }
+
+- /* Try to get SPROM */
+- err = bcma_sprom_get(bus);
+- if (err == -ENOENT) {
+- bcma_err(bus, "No SPROM available\n");
+- } else if (err)
+- bcma_err(bus, "Failed to get SPROM: %d\n", err);
+-
+ /* Register found cores */
+ bcma_register_cores(bus);
+
+@@ -210,7 +254,17 @@ int __devinit bcma_bus_register(struct b
+
+ void bcma_bus_unregister(struct bcma_bus *bus)
+ {
++ struct bcma_device *cores[3];
++
++ cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
++ cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
++ cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
++
+ bcma_unregister_cores(bus);
++
++ kfree(cores[2]);
++ kfree(cores[1]);
++ kfree(cores[0]);
+ }
+
+ int __init bcma_bus_early_register(struct bcma_bus *bus,
+@@ -247,18 +301,18 @@ int __init bcma_bus_early_register(struc
+ return -1;
+ }
+
+- /* Init CC core */
++ /* Early init CC core */
+ core = bcma_find_core(bus, bcma_cc_core_id(bus));
+ if (core) {
+ bus->drv_cc.core = core;
+- bcma_core_chipcommon_init(&bus->drv_cc);
++ bcma_core_chipcommon_early_init(&bus->drv_cc);
+ }
+
+- /* Init MIPS core */
++ /* Early 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);
++ bcma_core_mips_early_init(&bus->drv_mips);
+ }
+
+ bcma_info(bus, "Early bus registered\n");
+--- a/drivers/bcma/sprom.c
++++ b/drivers/bcma/sprom.c
+@@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(
+ /* for these chips OTP is always available */
+ present = true;
+ break;
++ case BCMA_CHIP_ID_BCM43227:
+ case BCMA_CHIP_ID_BCM43228:
++ case BCMA_CHIP_ID_BCM43428:
+ present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
+ break;
+ default:
+@@ -593,8 +595,11 @@ int bcma_sprom_get(struct bcma_bus *bus)
+ bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
+
+ err = bcma_sprom_valid(sprom);
+- if (err)
++ if (err) {
++ bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
++ err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
+ goto out;
++ }
+
+ bcma_sprom_extract_r8(bus, sprom);
+
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -10,7 +10,7 @@
+ #include <linux/bcma/bcma_driver_gmac_cmn.h>
+ #include <linux/ssb/ssb.h> /* SPROM sharing */
+
+-#include "bcma_regs.h"
++#include <linux/bcma/bcma_regs.h>
+
+ struct bcma_device;
+ struct bcma_bus;
+@@ -251,7 +251,7 @@ struct bcma_bus {
+ u8 num;
+
+ struct bcma_drv_cc drv_cc;
+- struct bcma_drv_pci drv_pci;
++ struct bcma_drv_pci drv_pci[2];
+ struct bcma_drv_mips drv_mips;
+ struct bcma_drv_gmac_cmn drv_gmac_cmn;
+
+--- a/include/linux/bcma/bcma_driver_chipcommon.h
++++ b/include/linux/bcma/bcma_driver_chipcommon.h
+@@ -100,6 +100,7 @@
+ #define BCMA_CC_CHIPST_4706_SFLASH_TYPE BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
+ #define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */
+ #define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */
++#define BCMA_CC_CHIPST_5357_NAND_BOOT BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
+ #define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
+ #define BCMA_CC_JCMD_START 0x80000000
+ #define BCMA_CC_JCMD_BUSY 0x80000000
+@@ -266,6 +267,29 @@
+ #define BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
+ #define BCMA_CC_SROM_CONTROL_SIZE_SHIFT 1
+ #define BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
++/* Block 0x140 - 0x190 registers are chipset specific */
++#define BCMA_CC_4706_FLASHSCFG 0x18C /* Flash struct configuration */
++#define BCMA_CC_4706_FLASHSCFG_MASK 0x000000ff
++#define BCMA_CC_4706_FLASHSCFG_SF1 0x00000001 /* 2nd serial flash present */
++#define BCMA_CC_4706_FLASHSCFG_PF1 0x00000002 /* 2nd parallel flash present */
++#define BCMA_CC_4706_FLASHSCFG_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */
++#define BCMA_CC_4706_FLASHSCFG_NF1 0x00000008 /* 2nd NAND flash present */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_MASK 0x000000f0
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */
++#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */
++/* NAND flash registers for BCM4706 (corerev = 31) */
++#define BCMA_CC_NFLASH_CTL 0x01A0
++#define BCMA_CC_NFLASH_CTL_ERR 0x08000000
++#define BCMA_CC_NFLASH_CONF 0x01A4
++#define BCMA_CC_NFLASH_COL_ADDR 0x01A8
++#define BCMA_CC_NFLASH_ROW_ADDR 0x01AC
++#define BCMA_CC_NFLASH_DATA 0x01B0
++#define BCMA_CC_NFLASH_WAITCNT0 0x01B4
+ /* 0x1E0 is defined as shared BCMA_CLKCTLST */
+ #define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
+ #define BCMA_CC_UART0_DATA 0x0300
+@@ -325,6 +349,60 @@
+ #define BCMA_CC_PLLCTL_ADDR 0x0660
+ #define BCMA_CC_PLLCTL_DATA 0x0664
+ #define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
++/* NAND flash MLC controller registers (corerev >= 38) */
++#define BCMA_CC_NAND_REVISION 0x0C00
++#define BCMA_CC_NAND_CMD_START 0x0C04
++#define BCMA_CC_NAND_CMD_ADDR_X 0x0C08
++#define BCMA_CC_NAND_CMD_ADDR 0x0C0C
++#define BCMA_CC_NAND_CMD_END_ADDR 0x0C10
++#define BCMA_CC_NAND_CS_NAND_SELECT 0x0C14
++#define BCMA_CC_NAND_CS_NAND_XOR 0x0C18
++#define BCMA_CC_NAND_SPARE_RD0 0x0C20
++#define BCMA_CC_NAND_SPARE_RD4 0x0C24
++#define BCMA_CC_NAND_SPARE_RD8 0x0C28
++#define BCMA_CC_NAND_SPARE_RD12 0x0C2C
++#define BCMA_CC_NAND_SPARE_WR0 0x0C30
++#define BCMA_CC_NAND_SPARE_WR4 0x0C34
++#define BCMA_CC_NAND_SPARE_WR8 0x0C38
++#define BCMA_CC_NAND_SPARE_WR12 0x0C3C
++#define BCMA_CC_NAND_ACC_CONTROL 0x0C40
++#define BCMA_CC_NAND_CONFIG 0x0C48
++#define BCMA_CC_NAND_TIMING_1 0x0C50
++#define BCMA_CC_NAND_TIMING_2 0x0C54
++#define BCMA_CC_NAND_SEMAPHORE 0x0C58
++#define BCMA_CC_NAND_DEVID 0x0C60
++#define BCMA_CC_NAND_DEVID_X 0x0C64
++#define BCMA_CC_NAND_BLOCK_LOCK_STATUS 0x0C68
++#define BCMA_CC_NAND_INTFC_STATUS 0x0C6C
++#define BCMA_CC_NAND_ECC_CORR_ADDR_X 0x0C70
++#define BCMA_CC_NAND_ECC_CORR_ADDR 0x0C74
++#define BCMA_CC_NAND_ECC_UNC_ADDR_X 0x0C78
++#define BCMA_CC_NAND_ECC_UNC_ADDR 0x0C7C
++#define BCMA_CC_NAND_READ_ERROR_COUNT 0x0C80
++#define BCMA_CC_NAND_CORR_STAT_THRESHOLD 0x0C84
++#define BCMA_CC_NAND_READ_ADDR_X 0x0C90
++#define BCMA_CC_NAND_READ_ADDR 0x0C94
++#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR_X 0x0C98
++#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR 0x0C9C
++#define BCMA_CC_NAND_COPY_BACK_ADDR_X 0x0CA0
++#define BCMA_CC_NAND_COPY_BACK_ADDR 0x0CA4
++#define BCMA_CC_NAND_BLOCK_ERASE_ADDR_X 0x0CA8
++#define BCMA_CC_NAND_BLOCK_ERASE_ADDR 0x0CAC
++#define BCMA_CC_NAND_INV_READ_ADDR_X 0x0CB0
++#define BCMA_CC_NAND_INV_READ_ADDR 0x0CB4
++#define BCMA_CC_NAND_BLK_WR_PROTECT 0x0CC0
++#define BCMA_CC_NAND_ACC_CONTROL_CS1 0x0CD0
++#define BCMA_CC_NAND_CONFIG_CS1 0x0CD4
++#define BCMA_CC_NAND_TIMING_1_CS1 0x0CD8
++#define BCMA_CC_NAND_TIMING_2_CS1 0x0CDC
++#define BCMA_CC_NAND_SPARE_RD16 0x0D30
++#define BCMA_CC_NAND_SPARE_RD20 0x0D34
++#define BCMA_CC_NAND_SPARE_RD24 0x0D38
++#define BCMA_CC_NAND_SPARE_RD28 0x0D3C
++#define BCMA_CC_NAND_CACHE_ADDR 0x0D40
++#define BCMA_CC_NAND_CACHE_DATA 0x0D44
++#define BCMA_CC_NAND_CTRL_CONFIG 0x0D48
++#define BCMA_CC_NAND_CTRL_STATUS 0x0D4C
+
+ /* Divider allocation in 4716/47162/5356 */
+ #define BCMA_CC_PMU5_MAINPLL_CPU 1
+@@ -415,6 +493,13 @@
+ /* 4313 Chip specific ChipControl register bits */
+ #define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
+
++/* BCM5357 ChipControl register bits */
++#define BCMA_CHIPCTL_5357_EXTPA BIT(14)
++#define BCMA_CHIPCTL_5357_ANT_MUX_2O3 BIT(15)
++#define BCMA_CHIPCTL_5357_NFLASH BIT(16)
++#define BCMA_CHIPCTL_5357_I2S_PINS_ENABLE BIT(18)
++#define BCMA_CHIPCTL_5357_I2CSPI_PINS_ENABLE BIT(19)
++
+ /* Data for the PMU, if available.
+ * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+ */
+@@ -425,11 +510,35 @@ struct bcma_chipcommon_pmu {
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash {
++ bool present;
+ u8 buswidth;
+ u32 window;
+ u32 window_size;
+ };
+
++#ifdef CONFIG_BCMA_SFLASH
++struct bcma_sflash {
++ bool present;
++ u32 window;
++ u32 blocksize;
++ u16 numblocks;
++ u32 size;
++
++ struct mtd_info *mtd;
++};
++#endif
++
++#ifdef CONFIG_BCMA_NFLASH
++struct mtd_info;
++
++struct bcma_nflash {
++ bool present;
++ bool boot; /* This is the flash the SoC boots from */
++
++ struct mtd_info *mtd;
++};
++#endif
++
+ struct bcma_serial_port {
+ void *regs;
+ unsigned long clockspeed;
+@@ -445,11 +554,18 @@ struct bcma_drv_cc {
+ u32 capabilities;
+ u32 capabilities_ext;
+ u8 setup_done:1;
++ u8 early_setup_done:1;
+ /* Fast Powerup Delay constant */
+ u16 fast_pwrup_delay;
+ struct bcma_chipcommon_pmu pmu;
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ struct bcma_pflash pflash;
++#ifdef CONFIG_BCMA_SFLASH
++ struct bcma_sflash sflash;
++#endif
++#ifdef CONFIG_BCMA_NFLASH
++ struct bcma_nflash nflash;
++#endif
+
+ int nr_serial_ports;
+ struct bcma_serial_port serial_ports[4];
+@@ -470,6 +586,7 @@ struct bcma_drv_cc {
+ bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+
+ extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
++extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
+
+ extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+ extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
+@@ -493,6 +610,7 @@ u32 bcma_chipco_gpio_polarity(struct bcm
+
+ /* PMU support */
+ extern void bcma_pmu_init(struct bcma_drv_cc *cc);
++extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
+
+ extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
+ u32 value);
+--- a/include/linux/bcma/bcma_driver_mips.h
++++ b/include/linux/bcma/bcma_driver_mips.h
+@@ -35,13 +35,16 @@ struct bcma_device;
+ struct bcma_drv_mips {
+ struct bcma_device *core;
+ u8 setup_done:1;
++ u8 early_setup_done:1;
+ unsigned int assigned_irqs;
+ };
+
+ #ifdef CONFIG_BCMA_DRIVER_MIPS
+ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
++extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
+ #else
+ static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
++static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
+ #endif
+
+ extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
+--- a/include/linux/bcma/bcma_regs.h
++++ b/include/linux/bcma/bcma_regs.h
+@@ -11,11 +11,13 @@
+ #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_EXTRESREQ_SHIFT 8
+ #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 */
++#define BCMA_CLKCTLST_EXTRESST_SHIFT 24
+ /* 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 */
+@@ -83,4 +85,9 @@
+ * (2 ZettaBytes), high 32 bits
+ */
+
++#define BCMA_SOC_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
++#define BCMA_SOC_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
++#define BCMA_SOC_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
++#define BCMA_SOC_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
++
+ #endif /* LINUX_BCMA_REGS_H_ */