Browse Source

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

SVN-Revision: 33920
Hauke Mehrtens 13 years ago
parent
commit
dca633f1c8
41 changed files with 4072 additions and 3457 deletions
  1. 48 0
      package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch
  2. 0 129
      target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch
  3. 0 505
      target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch
  4. 0 151
      target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch
  5. 0 573
      target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch
  6. 0 168
      target/linux/brcm47xx/patches-3.3/024-brcm47xx-add-common-interface-for-sflash.patch
  7. 0 136
      target/linux/brcm47xx/patches-3.3/028-bcm47xx-register-flash-drivers.patch
  8. 0 143
      target/linux/brcm47xx/patches-3.3/029-bcm47xx-read-nvram-from-sflash.patch
  9. 0 1146
      target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch
  10. 0 0
      target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch
  11. 28 20
      target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch
  12. 52 8
      target/linux/brcm47xx/patches-3.3/052-mtd-add-serial-flash-driver.patch
  13. 710 0
      target/linux/brcm47xx/patches-3.3/053-mtd-add-nand-flash-driver.patch
  14. 527 0
      target/linux/brcm47xx/patches-3.3/060-ssb-add-serial-flash-driver.patch
  15. 76 0
      target/linux/brcm47xx/patches-3.3/061-ssb-register-parallel-flash-device.patch
  16. 345 0
      target/linux/brcm47xx/patches-3.3/070-bcma-add-functions-to-write-to-serial-flash.patch
  17. 232 0
      target/linux/brcm47xx/patches-3.3/071-bcma-add-functions-to-write-to-nand-flash.patch
  18. 67 0
      target/linux/brcm47xx/patches-3.3/072-bcma-register-parallel-flash-device.patch
  19. 183 0
      target/linux/brcm47xx/patches-3.3/080-MIPS-BCM47XX-rewrite-nvram-probing.patch
  20. 5 5
      target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch
  21. 1 1
      target/linux/brcm47xx/patches-3.3/194-MIPS-BCM47XX-read-sprom-without-prefix-if-no-ieee802.patch
  22. 3 3
      target/linux/brcm47xx/patches-3.3/195-MIPS-BCM47xx-sprom-read-values-without-prefix-as-fal.patch
  23. 0 181
      target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch
  24. 0 37
      target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch
  25. 0 26
      target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch
  26. 4 4
      target/linux/brcm47xx/patches-3.3/280-activate_ssb_support_in_usb.patch
  27. 1 1
      target/linux/brcm47xx/patches-3.3/400-arch-bcm47xx.patch
  28. 2 2
      target/linux/brcm47xx/patches-3.3/501-bcma-add-gpio-driver.patch
  29. 2 2
      target/linux/brcm47xx/patches-3.3/502-bcm47xx-rewrite-gpio-handling.patch
  30. 8 8
      target/linux/brcm47xx/patches-3.3/812-disable_wgt634u_crap.patch
  31. 13 13
      target/linux/brcm47xx/patches-3.3/820-wgt634u-nvram-fix.patch
  32. 1 1
      target/linux/brcm47xx/patches-3.3/980-wnr834b_no_cardbus_invariant.patch
  33. 3 3
      target/linux/brcm47xx/patches-3.3/999-wl_exports.patch
  34. 81 1
      target/linux/generic/patches-3.3/020-ssb_update.patch
  35. 563 62
      target/linux/generic/patches-3.3/025-bcma_backport.patch
  36. 0 29
      target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch
  37. 0 55
      target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch
  38. 0 29
      target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch
  39. 0 15
      target/linux/generic/patches-3.3/029-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch
  40. 82 0
      target/linux/generic/patches-3.6/020-ssb_update.patch
  41. 1035 0
      target/linux/generic/patches-3.6/025-bcma_backport.patch

+ 48 - 0
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);
+ 
+ 	/*

+ 0 - 129
target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch

@@ -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];

+ 0 - 505
target/linux/brcm47xx/patches-3.3/021-bcma-add-serial-flash-support-to-bcma.patch

@@ -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 <[email protected]>
-+ * Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
-+ * 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_ */

+ 0 - 151
target/linux/brcm47xx/patches-3.3/022-ssb-move-flash-to-chipcommon.patch

@@ -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);

+ 0 - 573
target/linux/brcm47xx/patches-3.3/023-ssb-add-serial-flash-support.patch

@@ -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 <[email protected]>
-+ * Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
-+ * 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);
- 

+ 0 - 168
target/linux/brcm47xx/patches-3.3/024-brcm47xx-add-common-interface-for-sflash.patch

@@ -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 <[email protected]>
-+ *
-+ * 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 <[email protected]>
-+ *
-+ * 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;

+ 0 - 136
target/linux/brcm47xx/patches-3.3/028-bcm47xx-register-flash-drivers.patch

@@ -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);

+ 0 - 143
target/linux/brcm47xx/patches-3.3/029-bcm47xx-read-nvram-from-sflash.patch

@@ -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)

+ 0 - 1146
target/linux/brcm47xx/patches-3.3/030-bcm47xx-bcma-nandflash.patch

@@ -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 <[email protected]>
-+ * Copyright (C) 2011-2012 Tathagata Das <[email protected]>
-  *
-  * 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 <[email protected]>
-  * Copyright (C) 2010-2011 Hauke Mehrtens <[email protected]>
-+ * Copyright (C) 2011-2012 Tathagata Das <[email protected]>
-  *
-  * 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 <[email protected]>
-  *  Copyright (C) 2010 Waldemar Brodkorb <[email protected]>
-  *  Copyright (C) 2010-2012 Hauke Mehrtens <[email protected]>
-+ *  Copyright (C) 2011-2012 Tathagata Das <[email protected]>
-  *
-  *  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 <[email protected]>
-+ * Copyright (C) 2011-2012 Tathagata Das <[email protected]>
-  *
-  * 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 <[email protected]>
-+ * 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 <[email protected]>
-  * Copyright 2010, Bernhard Loos <[email protected]>
-  * Copyright 2011, Hauke Mehrtens <[email protected]>
-+ * Copyright (C) 2011-2012 Tathagata Das <[email protected]>
-  *
-  * 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 <[email protected]>
-+ * 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 <[email protected]>
-+ * 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_ */

+ 0 - 0
target/linux/brcm47xx/patches-3.3/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch → target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch


+ 28 - 20
target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch → 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 <[email protected]>
 + *  Copyright (C) 2005 Waldemar Brodkorb <[email protected]>
@@ -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");

+ 52 - 8
target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch → 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_ */

+ 710 - 0
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 <[email protected]>
++ * 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 <[email protected]>
++ * 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_ */

+ 527 - 0
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 <[email protected]>
++ * Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
++ * 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)

+ 76 - 0
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_ */

+ 345 - 0
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 <[email protected]>
++ * Copyright 2011, 2012, Hauke Mehrtens <[email protected]>
++ * 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;

+ 232 - 0
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 <[email protected]>
++ * 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_ */

+ 67 - 0
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);

+ 183 - 0
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 <[email protected]>
+- * Copyright (C) 2010-2011 Hauke Mehrtens <[email protected]>
++ * Copyright (C) 2010-2012 Hauke Mehrtens <[email protected]>
+  *
+  * 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;

+ 5 - 5
target/linux/brcm47xx/patches-3.3/114-MIPS-BCM47xx-Setup-and-register-serial-early.patch

@@ -15,16 +15,16 @@ Signed-off-by: Hauke Mehrtens <[email protected]>
 
 --- 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 <[email protected]>
  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 <[email protected]>
 +	bcm47xx_early_serial_setup(mcore);
 +#endif
  }
+ #endif
  
- static int __init bcm47xx_register_flash_ssb(void)

+ 1 - 1
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);

+ 3 - 3
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));

+ 0 - 181
target/linux/brcm47xx/patches-3.3/201-bcma-just-do-the-necessary-things-in-early-register.patch

@@ -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);

+ 0 - 37
target/linux/brcm47xx/patches-3.3/202-bcma-init-sprom-struct-earlier.patch

@@ -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);
- 

+ 0 - 26
target/linux/brcm47xx/patches-3.3/204-bcma-do-not-initialize-deactivated-PCIe-cores.patch

@@ -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");

+ 4 - 4
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

+ 1 - 1
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);

+ 2 - 2
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);
  

+ 2 - 2
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

+ 8 - 8
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));

+ 13 - 13
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();
  

+ 1 - 1
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);
  

+ 3 - 3
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];

+ 81 - 1
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 @@

File diff suppressed because it is too large
+ 563 - 62
target/linux/generic/patches-3.3/025-bcma_backport.patch


+ 0 - 29
target/linux/generic/patches-3.3/026-bcma_pmu_regression.patch

@@ -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;

+ 0 - 55
target/linux/generic/patches-3.3/027-bcma-add-missing-iounmap-on-error-path.patch

@@ -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);
- 

+ 0 - 29
target/linux/generic/patches-3.3/028-bcma-fix-regression-in-interrupt-assignment-on-mips.patch

@@ -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;

+ 0 - 15
target/linux/generic/patches-3.3/029-bcma-use-fallback-sprom-if-sprom-on-card-was-not-val.patch

@@ -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);
- 

+ 82 - 0
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);

+ 1035 - 0
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_ */

Some files were not shown because too many files changed in this diff