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