From: Hauke Mehrtens Date: Thu, 25 Oct 2012 14:33:47 +0000 (+0000) Subject: kernel: update bcma and ssb to master-2012-10-18 from wireless-testing X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=dca633f1c8441e0c3f47662c1dc51e29f0c0fa94;p=openwrt%2Fstaging%2Fkaloz.git 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 --- diff --git a/package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch b/package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch new file mode 100644 index 0000000000..6d4c1d8b8b --- /dev/null +++ b/package/mac80211/patches/840-b43-brcmsmac-use-pcie-core-arry.patch @@ -0,0 +1,48 @@ +diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c +index 73730e9..7358ea2 100644 +--- a/drivers/net/wireless/b43/main.c ++++ b/drivers/net/wireless/b43/main.c +@@ -4652,7 +4652,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) + switch (dev->dev->bus_type) { + #ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: +- bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci, ++ bcma_core_pci_irq_ctl(&dev->dev->bdev->bus->drv_pci[0], + dev->dev->bdev, true); + break; + #endif +diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +index b89f127..de96290 100644 +--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +@@ -692,7 +692,7 @@ void ai_pci_up(struct si_pub *sih) + sii = container_of(sih, struct si_info, pub); + + if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) +- bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true); ++ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], true); + } + + /* Unconfigure and/or apply various WARs when going down */ +@@ -703,7 +703,7 @@ void ai_pci_down(struct si_pub *sih) + sii = container_of(sih, struct si_info, pub); + + if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) +- bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false); ++ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci[0], false); + } + + /* Enable BT-COEX & Ex-PA for 4313 */ +diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c +index 75086b3..565c15a 100644 +--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c ++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c +@@ -5077,7 +5077,7 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) + * Configure pci/pcmcia here instead of in brcms_c_attach() + * to allow mfg hotswap: down, hotswap (chip power cycle), up. + */ +- bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core, ++ bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci[0], wlc_hw->d11core, + true); + + /* diff --git a/target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch b/target/linux/brcm47xx/patches-3.3/020-bcma-move-parallel-flash-into-a-union.patch deleted file mode 100644 index 98c855fbd8..0000000000 --- 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 7382636b3d..0000000000 --- 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 -+ * Copyright 2011, 2012, Hauke Mehrtens -+ * Copyright 2010, Broadcom Corporation -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#include -+#include -+#include -+ -+#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 12055bff03..0000000000 --- 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 ba5a5c2d1b..0000000000 --- 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 -+ * Copyright 2011, 2012, Hauke Mehrtens -+ * Copyright 2010, Broadcom Corporation -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#include -+#include -+#include -+ -+#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 fd4befcfae..0000000000 --- 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 -+ * -+ * 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 -+ -+#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 -+ * -+ * 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 -+#include -+#include -+ -+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/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch b/target/linux/brcm47xx/patches-3.3/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch deleted file mode 100644 index 5381e2f6cc..0000000000 --- a/target/linux/brcm47xx/patches-3.3/025-mtd-bcm47xx-add-bcm47xx-part-parser.patch +++ /dev/null @@ -1,571 +0,0 @@ ---- a/drivers/mtd/Kconfig -+++ b/drivers/mtd/Kconfig -@@ -172,6 +172,13 @@ config MTD_MYLOADER_PARTS - You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. - -+config MTD_BCM47XX_PARTS -+ tristate "BCM47XX partitioning support" -+ default y -+ depends on BCM47XX -+ ---help--- -+ bcm47XX partitioning support -+ - comment "User Modules And Translation Layers" - - config MTD_CHAR ---- a/drivers/mtd/Makefile -+++ b/drivers/mtd/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o - obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o - obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o -+obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o - - # 'Users' - code which presents functionality to userspace. - obj-$(CONFIG_MTD_CHAR) += mtdchar.o ---- /dev/null -+++ b/drivers/mtd/bcm47xxpart.c -@@ -0,0 +1,542 @@ -+/* -+ * Copyright (C) 2006 Felix Fietkau -+ * Copyright (C) 2005 Waldemar Brodkorb -+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) -+ * -+ * original functions for finding root filesystem from Mike Baker -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Copyright 2001-2003, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * Flash mapping for BCM947XX boards -+ */ -+ -+#define pr_fmt(fmt) "bcm47xx_part: " fmt -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define TRX_MAGIC 0x30524448 /* "HDR0" */ -+#define TRX_VERSION 1 -+#define TRX_MAX_LEN 0x3A0000 -+#define TRX_NO_HEADER 1 /* Do not write TRX header */ -+#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ -+#define TRX_MAX_OFFSET 3 -+ -+struct trx_header { -+ u32 magic; /* "HDR0" */ -+ u32 len; /* Length of file including header */ -+ u32 crc32; /* 32-bit CRC from flag_version to end of file */ -+ u32 flag_version; /* 0:15 flags, 16:31 version */ -+ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ -+}; -+ -+/* for Edimax Print servers which use an additional header -+ * then the firmware on flash looks like : -+ * EDIMAX HEADER | TRX HEADER -+ * As this header is 12 bytes long we have to handle it -+ * and skip it to find the TRX header -+ */ -+#define EDIMAX_PS_HEADER_MAGIC 0x36315350 /* "PS16" */ -+#define EDIMAX_PS_HEADER_LEN 0xc /* 12 bytes long for edimax header */ -+ -+#define NVRAM_SPACE 0x8000 -+ -+#define ROUTER_NETGEAR_WGR614L 1 -+#define ROUTER_NETGEAR_WNR834B 2 -+#define ROUTER_NETGEAR_WNDR3300 3 -+#define ROUTER_NETGEAR_WNR3500L 4 -+#define ROUTER_SIMPLETECH_SIMPLESHARE 5 -+#define ROUTER_NETGEAR_WNDR3400 6 -+ -+static int -+find_cfe_size(struct mtd_info *mtd) -+{ -+ struct trx_header *trx; -+ unsigned char buf[512]; -+ int off; -+ size_t len; -+ int blocksize; -+ -+ trx = (struct trx_header *) buf; -+ -+ blocksize = mtd->erasesize; -+ if (blocksize < 0x10000) -+ blocksize = 0x10000; -+ -+ for (off = (128*1024); off < mtd->size; off += blocksize) { -+ memset(buf, 0xe5, sizeof(buf)); -+ -+ /* -+ * Read into buffer -+ */ -+ if (mtd->read(mtd, off, sizeof(buf), &len, buf) || -+ len != sizeof(buf)) -+ continue; -+ -+ if (le32_to_cpu(trx->magic) == EDIMAX_PS_HEADER_MAGIC) { -+ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN, -+ sizeof(buf), &len, buf) || len != sizeof(buf)) { -+ continue; -+ } else { -+ pr_notice("Found edimax header\n"); -+ } -+ } -+ -+ /* found a TRX header */ -+ if (le32_to_cpu(trx->magic) == TRX_MAGIC) -+ goto found; -+ } -+ -+ pr_notice("%s: Couldn't find bootloader size\n", mtd->name); -+ return -1; -+ -+ found: -+ pr_notice("bootloader size: %d\n", off); -+ return off; -+ -+} -+ -+/* -+ * Copied from mtdblock.c -+ * -+ * Cache stuff... -+ * -+ * Since typical flash erasable sectors are much larger than what Linux's -+ * buffer cache can handle, we must implement read-modify-write on flash -+ * sectors for each block write requests. To avoid over-erasing flash sectors -+ * and to speed things up, we locally cache a whole flash sector while it is -+ * being written to until a different sector is required. -+ */ -+ -+static void erase_callback(struct erase_info *done) -+{ -+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; -+ wake_up(wait_q); -+} -+ -+static int erase_write(struct mtd_info *mtd, unsigned long pos, -+ int len, const char *buf) -+{ -+ struct erase_info erase; -+ DECLARE_WAITQUEUE(wait, current); -+ wait_queue_head_t wait_q; -+ size_t retlen; -+ int ret; -+ -+ /* -+ * First, let's erase the flash block. -+ */ -+ -+ init_waitqueue_head(&wait_q); -+ erase.mtd = mtd; -+ erase.callback = erase_callback; -+ erase.addr = pos; -+ erase.len = len; -+ erase.priv = (u_long)&wait_q; -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ add_wait_queue(&wait_q, &wait); -+ -+ ret = mtd->erase(mtd, &erase); -+ if (ret) { -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&wait_q, &wait); -+ pr_warn("erase of region [0x%lx, 0x%x] on \"%s\" failed\n", -+ pos, len, mtd->name); -+ return ret; -+ } -+ -+ schedule(); /* Wait for erase to finish. */ -+ remove_wait_queue(&wait_q, &wait); -+ -+ /* -+ * Next, write data to flash. -+ */ -+ -+ ret = mtd->write(mtd, pos, len, &retlen, buf); -+ if (ret) -+ return ret; -+ if (retlen != len) -+ return -EIO; -+ return 0; -+} -+ -+ -+static int -+find_dual_image_off(struct mtd_info *mtd) -+{ -+ struct trx_header trx; -+ int off, blocksize; -+ size_t len; -+ -+ blocksize = mtd->erasesize; -+ if (blocksize < 0x10000) -+ blocksize = 0x10000; -+ -+ for (off = (128*1024); off < mtd->size; off += blocksize) { -+ memset(&trx, 0xe5, sizeof(trx)); -+ /* -+ * Read into buffer -+ */ -+ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || -+ len != sizeof(trx)) -+ continue; -+ /* found last TRX header */ -+ if (le32_to_cpu(trx.magic) == TRX_MAGIC) { -+ if (le32_to_cpu(trx.flag_version >> 16) == 2) { -+ pr_notice("dual image TRX header found\n"); -+ return mtd->size / 2; -+ } else { -+ return 0; -+ } -+ } -+ } -+ return 0; -+} -+ -+ -+static int -+find_root(struct mtd_info *mtd, struct mtd_partition *part) -+{ -+ struct trx_header trx, *trx2; -+ unsigned char buf[512], *block; -+ int off, blocksize, trxoff = 0; -+ u32 i, crc = ~0; -+ size_t len; -+ bool edimax = false; -+ -+ blocksize = mtd->erasesize; -+ if (blocksize < 0x10000) -+ blocksize = 0x10000; -+ -+ for (off = (128*1024); off < mtd->size; off += blocksize) { -+ memset(&trx, 0xe5, sizeof(trx)); -+ -+ /* -+ * Read into buffer -+ */ -+ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || -+ len != sizeof(trx)) -+ continue; -+ -+ /* found an edimax header */ -+ if (le32_to_cpu(trx.magic) == EDIMAX_PS_HEADER_MAGIC) { -+ /* read the correct trx header */ -+ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN, -+ sizeof(trx), &len, (char *) &trx) || -+ len != sizeof(trx)) { -+ continue; -+ } else { -+ pr_notice("Found an edimax ps header\n"); -+ edimax = true; -+ } -+ } -+ -+ /* found a TRX header */ -+ if (le32_to_cpu(trx.magic) == TRX_MAGIC) { -+ part->offset = le32_to_cpu(trx.offsets[2]) ? : -+ le32_to_cpu(trx.offsets[1]); -+ part->size = le32_to_cpu(trx.len); -+ -+ part->size -= part->offset; -+ part->offset += off; -+ if (edimax) { -+ off += EDIMAX_PS_HEADER_LEN; -+ trxoff = EDIMAX_PS_HEADER_LEN; -+ } -+ -+ goto found; -+ } -+ } -+ -+ pr_warn("%s: Couldn't find root filesystem\n", -+ mtd->name); -+ return -1; -+ -+ found: -+ pr_notice("TRX offset : %x\n", trxoff); -+ if (part->size == 0) -+ return 0; -+ -+ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) -+ return 0; -+ -+ /* Move the fs outside of the trx */ -+ part->size = 0; -+ -+ if (trx.len != part->offset + part->size - off) { -+ /* Update the trx offsets and length */ -+ trx.len = part->offset + part->size - off; -+ -+ /* Update the trx crc32 */ -+ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { -+ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) -+ return 0; -+ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); -+ } -+ trx.crc32 = crc; -+ -+ /* read first eraseblock from the trx */ -+ block = kmalloc(mtd->erasesize, GFP_KERNEL); -+ trx2 = (struct trx_header *) block; -+ if (mtd->read(mtd, off - trxoff, mtd->erasesize, &len, block) || len != mtd->erasesize) { -+ pr_err("Error accessing the first trx eraseblock\n"); -+ return 0; -+ } -+ -+ pr_notice("Updating TRX offsets and length:\n"); -+ pr_notice("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); -+ pr_notice("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); -+ -+ /* Write updated trx header to the flash */ -+ memcpy(block + trxoff, &trx, sizeof(trx)); -+ if (mtd->unlock) -+ mtd->unlock(mtd, off - trxoff, mtd->erasesize); -+ erase_write(mtd, off - trxoff, mtd->erasesize, block); -+ if (mtd->sync) -+ mtd->sync(mtd); -+ kfree(block); -+ pr_notice("Done\n"); -+ } -+ -+ return part->size; -+} -+ -+static int get_router(void) -+{ -+ char buf[20]; -+ u32 boardnum = 0; -+ u16 boardtype = 0; -+ u16 boardrev = 0; -+ u32 boardflags = 0; -+ u16 sdram_init = 0; -+ u16 cardbus = 0; -+ u16 strev = 0; -+ -+ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0) -+ boardnum = simple_strtoul(buf, NULL, 0); -+ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) -+ boardtype = simple_strtoul(buf, NULL, 0); -+ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) -+ boardrev = simple_strtoul(buf, NULL, 0); -+ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) -+ boardflags = simple_strtoul(buf, NULL, 0); -+ if (nvram_getenv("sdram_init", buf, sizeof(buf)) >= 0) -+ sdram_init = simple_strtoul(buf, NULL, 0); -+ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) -+ cardbus = simple_strtoul(buf, NULL, 0); -+ if (nvram_getenv("st_rev", buf, sizeof(buf)) >= 0) -+ strev = simple_strtoul(buf, NULL, 0); -+ -+ if ((boardnum == 8 || boardnum == 01) -+ && boardtype == 0x0472 && cardbus == 1) { -+ /* Netgear WNR834B, Netgear WNR834Bv2 */ -+ return ROUTER_NETGEAR_WNR834B; -+ } -+ -+ if (boardnum == 01 && boardtype == 0x0472 && boardrev == 0x23) { -+ /* Netgear WNDR-3300 */ -+ return ROUTER_NETGEAR_WNDR3300; -+ } -+ -+ if ((boardnum == 83258 || boardnum == 01) -+ && boardtype == 0x048e -+ && (boardrev == 0x11 || boardrev == 0x10) -+ && boardflags == 0x750 -+ && sdram_init == 0x000A) { -+ /* Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5 */ -+ return ROUTER_NETGEAR_WGR614L; -+ } -+ -+ if ((boardnum == 1 || boardnum == 3500) -+ && boardtype == 0x04CF -+ && (boardrev == 0x1213 || boardrev == 02)) { -+ /* Netgear WNR3500v2/U/L */ -+ return ROUTER_NETGEAR_WNR3500L; -+ } -+ -+ if (boardnum == 1 && boardtype == 0xb4cf && boardrev == 0x1100) { -+ /* Netgear WNDR3400 */ -+ return ROUTER_NETGEAR_WNDR3400; -+ } -+ -+ if (boardtype == 0x042f -+ && boardrev == 0x10 -+ && boardflags == 0 -+ && strev == 0x11) { -+ /* Simpletech Simpleshare */ -+ return ROUTER_SIMPLETECH_SIMPLESHARE; -+ } -+ -+ return 0; -+} -+ -+static int parse_bcm47xx_partitions(struct mtd_info *mtd, -+ struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ int cfe_size; -+ int dual_image_offset = 0; -+ /* e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this -+ * part from our mapping to prevent overwriting len/checksum on e.g. -+ * Netgear WGR614v8/L/WW -+ */ -+ int custom_data_size = 0; -+ struct mtd_partition *bcm47xx_parts; -+ -+ cfe_size = find_cfe_size(mtd); -+ if (cfe_size < 0) -+ return 0; -+ -+ bcm47xx_parts = kzalloc(sizeof(struct mtd_partition) * 6, GFP_KERNEL); -+ -+ bcm47xx_parts[0].name = "cfe"; -+ bcm47xx_parts[1].name = "linux"; -+ bcm47xx_parts[2].name = "rootfs"; -+ bcm47xx_parts[3].name = "nvram"; -+ -+ /* boot loader */ -+ bcm47xx_parts[0].mask_flags = MTD_WRITEABLE; -+ bcm47xx_parts[0].offset = 0; -+ bcm47xx_parts[0].size = cfe_size; -+ -+ /* nvram */ -+ if (cfe_size != 384 * 1024) { -+ -+ switch (get_router()) { -+ case ROUTER_NETGEAR_WGR614L: -+ case ROUTER_NETGEAR_WNR834B: -+ case ROUTER_NETGEAR_WNDR3300: -+ case ROUTER_NETGEAR_WNR3500L: -+ case ROUTER_NETGEAR_WNDR3400: -+ /* Netgear: checksum is @ 0x003AFFF8 for 4M flash or checksum -+ * is @ 0x007AFFF8 for 8M flash -+ */ -+ custom_data_size = mtd->erasesize; -+ -+ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); -+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); -+ -+ /* Place CFE board_data into a partition */ -+ bcm47xx_parts[4].name = "board_data"; -+ bcm47xx_parts[4].offset = bcm47xx_parts[3].offset - custom_data_size; -+ bcm47xx_parts[4].size = custom_data_size; -+ break; -+ -+ case ROUTER_SIMPLETECH_SIMPLESHARE: -+ /* Fixup Simpletech Simple share nvram */ -+ -+ pr_notice("Setting up simpletech nvram\n"); -+ custom_data_size = mtd->erasesize; -+ -+ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize) * 2; -+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); -+ -+ /* Place backup nvram into a partition */ -+ bcm47xx_parts[4].name = "nvram_copy"; -+ bcm47xx_parts[4].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); -+ bcm47xx_parts[4].size = roundup(NVRAM_SPACE, mtd->erasesize); -+ break; -+ -+ default: -+ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); -+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); -+ } -+ -+ } else { -+ /* nvram (old 128kb config partition on netgear wgt634u) */ -+ bcm47xx_parts[3].offset = bcm47xx_parts[0].size; -+ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); -+ } -+ -+ /* dual image offset*/ -+ pr_notice("Looking for dual image\n"); -+ dual_image_offset = find_dual_image_off(mtd); -+ /* linux (kernel and rootfs) */ -+ if (cfe_size != 384 * 1024) { -+ if (get_router() == ROUTER_SIMPLETECH_SIMPLESHARE) { -+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size; -+ bcm47xx_parts[1].size = bcm47xx_parts[4].offset - dual_image_offset - -+ bcm47xx_parts[1].offset - custom_data_size; -+ } else { -+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size; -+ bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - -+ bcm47xx_parts[1].offset - custom_data_size; -+ } -+ } else { -+ /* do not count the elf loader, which is on one block */ -+ bcm47xx_parts[1].offset = bcm47xx_parts[0].size + -+ bcm47xx_parts[3].size + mtd->erasesize; -+ bcm47xx_parts[1].size = mtd->size - -+ bcm47xx_parts[0].size - -+ (2*bcm47xx_parts[3].size) - -+ mtd->erasesize - custom_data_size; -+ } -+ -+ /* find and size rootfs */ -+ find_root(mtd, &bcm47xx_parts[2]); -+ bcm47xx_parts[2].size = mtd->size - dual_image_offset - -+ bcm47xx_parts[2].offset - -+ bcm47xx_parts[3].size - custom_data_size; -+ *pparts = bcm47xx_parts; -+ return bcm47xx_parts[4].name == NULL ? 4 : 5; -+} -+ -+static struct mtd_part_parser bcm47xx_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_bcm47xx_partitions, -+ .name = "bcm47xx", -+}; -+ -+static int __init bcm47xx_parser_init(void) -+{ -+ return register_mtd_parser(&bcm47xx_parser); -+} -+ -+static void __exit bcm47xx_parser_exit(void) -+{ -+ deregister_mtd_parser(&bcm47xx_parser); -+} -+ -+module_init(bcm47xx_parser_init); -+module_exit(bcm47xx_parser_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Parsing code for flash partitions on bcm47xx SoCs"); diff --git a/target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch deleted file mode 100644 index 7f8f64f28c..0000000000 --- a/target/linux/brcm47xx/patches-3.3/026-mtd-bcm47xx-add-parallel-flash-driver.patch +++ /dev/null @@ -1,216 +0,0 @@ ---- a/drivers/mtd/maps/Kconfig -+++ b/drivers/mtd/maps/Kconfig -@@ -248,6 +248,15 @@ config MTD_LANTIQ - help - Support for NOR flash attached to the Lantiq SoC's External Bus Unit. - -+config MTD_BCM47XX_PFLASH -+ tristate "bcm47xx parallel flash support" -+ default y -+ depends on BCM47XX -+ select MTD_PARTITIONS -+ select MTD_BCM47XX_PARTS -+ help -+ Support for bcm47xx parallel flash -+ - config MTD_DILNETPC - tristate "CFI Flash device mapped on DIL/Net PC" - depends on X86 && MTD_CFI_INTELEXT && BROKEN ---- a/drivers/mtd/maps/Makefile -+++ b/drivers/mtd/maps/Makefile -@@ -57,3 +57,4 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o - obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o - obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o - obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o -+obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o ---- /dev/null -+++ b/drivers/mtd/maps/bcm47xx-pflash.c -@@ -0,0 +1,188 @@ -+/* -+ * Copyright (C) 2006 Felix Fietkau -+ * Copyright (C) 2005 Waldemar Brodkorb -+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) -+ * -+ * original functions for finding root filesystem from Mike Baker -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Copyright 2001-2003, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ * Flash mapping for BCM947XX boards -+ */ -+ -+#define pr_fmt(fmt) "bcm47xx_pflash: " fmt -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define WINDOW_ADDR 0x1fc00000 -+#define WINDOW_SIZE 0x400000 -+#define BUSWIDTH 2 -+ -+static struct mtd_info *bcm47xx_mtd; -+ -+static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+{ -+ if (len == 1) { -+ memcpy_fromio(to, map->virt + from, len); -+ } else { -+ int i; -+ u16 *dest = (u16 *) to; -+ u16 *src = (u16 *) (map->virt + from); -+ for (i = 0; i < (len / 2); i++) -+ dest[i] = src[i]; -+ if (len & 1) -+ *((u8 *)dest+len-1) = src[i] & 0xff; -+ } -+} -+ -+static struct map_info bcm47xx_map = { -+ name: "Physically mapped flash", -+ size : WINDOW_SIZE, -+ bankwidth : BUSWIDTH, -+ phys : WINDOW_ADDR, -+}; -+ -+static const char *probes[] = { "bcm47xx", NULL }; -+ -+static int bcm47xx_mtd_probe(struct platform_device *pdev) -+{ -+#ifdef CONFIG_BCM47XX_SSB -+ struct ssb_chipcommon *ssb_cc; -+#endif -+#ifdef CONFIG_BCM47XX_BCMA -+ struct bcma_drv_cc *bcma_cc; -+#endif -+ int ret = 0; -+ -+ 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) -+ return -ENODEV; -+ -+ bcm47xx_map.phys = ssb_cc->pflash.window; -+ bcm47xx_map.size = ssb_cc->pflash.window_size; -+ bcm47xx_map.bankwidth = ssb_cc->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) -+ return -ENODEV; -+ -+ bcm47xx_map.phys = bcma_cc->pflash.window; -+ bcm47xx_map.size = bcma_cc->pflash.window_size; -+ bcm47xx_map.bankwidth = bcma_cc->pflash.buswidth; -+ break; -+#endif -+ } -+ -+ pr_notice("flash init: 0x%08x 0x%08lx\n", bcm47xx_map.phys, bcm47xx_map.size); -+ bcm47xx_map.virt = ioremap_nocache(bcm47xx_map.phys, bcm47xx_map.size); -+ -+ if (!bcm47xx_map.virt) { -+ pr_err("Failed to ioremap\n"); -+ return -EIO; -+ } -+ -+ simple_map_init(&bcm47xx_map); -+ /* override copy_from routine */ -+ bcm47xx_map.copy_from = bcm47xx_map_copy_from; -+ -+ bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map); -+ if (!bcm47xx_mtd) { -+ pr_err("Failed to do_map_probe\n"); -+ ret = -ENXIO; -+ goto err_unmap; -+ } -+ bcm47xx_mtd->owner = THIS_MODULE; -+ -+ pr_notice("Flash device: 0x%lx at 0x%x\n", bcm47xx_map.size, WINDOW_ADDR); -+ -+ ret = mtd_device_parse_register(bcm47xx_mtd, probes, NULL, NULL, 0); -+ -+ if (ret) { -+ pr_err("Flash: mtd_device_register failed\n"); -+ goto err_destroy; -+ } -+ return 0; -+ -+err_destroy: -+ map_destroy(bcm47xx_mtd); -+err_unmap: -+ iounmap(bcm47xx_map.virt); -+ return ret; -+} -+ -+static int __devexit bcm47xx_mtd_remove(struct platform_device *pdev) -+{ -+ mtd_device_unregister(bcm47xx_mtd); -+ map_destroy(bcm47xx_mtd); -+ iounmap(bcm47xx_map.virt); -+ return 0; -+} -+ -+static struct platform_driver bcm47xx_mtd_driver = { -+ .remove = __devexit_p(bcm47xx_mtd_remove), -+ .driver = { -+ .name = "bcm47xx_pflash", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init init_bcm47xx_mtd(void) -+{ -+ int ret = platform_driver_probe(&bcm47xx_mtd_driver, bcm47xx_mtd_probe); -+ -+ if (ret) -+ pr_err("error registering platform driver: %i\n", ret); -+ return ret; -+} -+ -+static void __exit exit_bcm47xx_mtd(void) -+{ -+ platform_driver_unregister(&bcm47xx_mtd_driver); -+} -+ -+module_init(init_bcm47xx_mtd); -+module_exit(exit_bcm47xx_mtd); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("BCM47XX parallel flash driver"); diff --git a/target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch deleted file mode 100644 index 3aec60c11e..0000000000 --- a/target/linux/brcm47xx/patches-3.3/027-mtd-bcm47xx-add-serial-flash-driver.patch +++ /dev/null @@ -1,291 +0,0 @@ ---- a/drivers/mtd/maps/Kconfig -+++ b/drivers/mtd/maps/Kconfig -@@ -257,6 +257,15 @@ config MTD_BCM47XX_PFLASH - help - Support for bcm47xx parallel flash - -+config MTD_BCM47XX_SFLASH -+ tristate "bcm47xx serial flash support" -+ default y -+ depends on BCM47XX -+ select MTD_PARTITIONS -+ select MTD_BCM47XX_PARTS -+ help -+ Support for bcm47xx parallel flash -+ - config MTD_DILNETPC - tristate "CFI Flash device mapped on DIL/Net PC" - depends on X86 && MTD_CFI_INTELEXT && BROKEN ---- a/drivers/mtd/maps/Makefile -+++ b/drivers/mtd/maps/Makefile -@@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr - obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o - obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o - obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o -+obj-$(CONFIG_MTD_BCM47XX_SFLASH)+= bcm47xx-sflash.o ---- /dev/null -+++ b/drivers/mtd/maps/bcm47xx-sflash.c -@@ -0,0 +1,263 @@ -+/* -+ * Broadcom SiliconBackplane chipcommon serial flash interface -+ * -+ * Copyright 2011, 2012, Hauke Mehrtens -+ * Copyright 2006, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#define pr_fmt(fmt) "bcm47xx_sflash: " fmt -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int -+sflash_mtd_poll(struct bcm47xx_sflash *sflash, unsigned int offset, int timeout) -+{ -+ unsigned long now = jiffies; -+ -+ for (;;) { -+ if (!sflash->poll(sflash, offset)) { -+ break; -+ } -+ if (time_after(jiffies, now + timeout)) { -+ pr_err("timeout while polling\n"); -+ return -ETIMEDOUT; -+ -+ } -+ cpu_relax(); -+ udelay(1); -+ } -+ -+ return 0; -+} -+ -+static int -+sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -+{ -+ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *)mtd->priv; -+ -+ /* Check address range */ -+ if (!len) -+ return 0; -+ -+ if ((from + len) > mtd->size) -+ return -EINVAL; -+ -+ *retlen = 0; -+ while (len) { -+ int ret = sflash->read(sflash, from, len, buf); -+ if (ret < 0) -+ return ret; -+ -+ from += (loff_t) ret; -+ len -= ret; -+ buf += ret; -+ *retlen += ret; -+ } -+ -+ return 0; -+} -+ -+static int -+sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) -+{ -+ int bytes; -+ int ret; -+ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *)mtd->priv; -+ -+ /* Check address range */ -+ if (!len) -+ return 0; -+ -+ if ((to + len) > mtd->size) -+ return -EINVAL; -+ -+ *retlen = 0; -+ while (len) { -+ ret = sflash->write(sflash, to, len, buf); -+ if (ret < 0) -+ return ret; -+ -+ bytes = ret; -+ -+ ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10); -+ if (ret) -+ return ret; -+ -+ to += (loff_t) bytes; -+ len -= bytes; -+ buf += bytes; -+ *retlen += bytes; -+ } -+ -+ return 0; -+} -+ -+static int -+sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) -+{ -+ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv; -+ int i, j, ret = 0; -+ unsigned int addr, len; -+ -+ /* Check address range */ -+ if (!erase->len) -+ return 0; -+ if ((erase->addr + erase->len) > mtd->size) -+ return -EINVAL; -+ -+ addr = erase->addr; -+ len = erase->len; -+ -+ /* Ensure that requested regions are aligned */ -+ for (i = 0; i < mtd->numeraseregions; i++) { -+ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { -+ if (addr == mtd->eraseregions[i].offset + -+ mtd->eraseregions[i].erasesize * j && -+ len >= mtd->eraseregions[i].erasesize) { -+ ret = sflash->erase(sflash, addr); -+ if (ret < 0) -+ break; -+ ret = sflash_mtd_poll(sflash, addr, 10 * HZ); -+ if (ret) -+ break; -+ addr += mtd->eraseregions[i].erasesize; -+ len -= mtd->eraseregions[i].erasesize; -+ } -+ } -+ if (ret) -+ break; -+ } -+ -+ /* Set erase status */ -+ if (ret) -+ erase->state = MTD_ERASE_FAILED; -+ else -+ erase->state = MTD_ERASE_DONE; -+ -+ /* Call erase callback */ -+ if (erase->callback) -+ erase->callback(erase); -+ -+ return ret; -+} -+ -+static const char *probes[] = { "bcm47xx", NULL }; -+ -+static int bcm47xx_sflash_probe(struct platform_device *pdev) -+{ -+ struct bcm47xx_sflash *sflash = dev_get_platdata(&pdev->dev); -+ struct mtd_info *mtd; -+ struct mtd_erase_region_info *eraseregions; -+ int ret = 0; -+ -+ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!mtd){ -+ ret = -ENOMEM; -+ goto err_out; -+ } -+ -+ eraseregions = kzalloc(sizeof(struct mtd_erase_region_info), GFP_KERNEL); -+ if (!eraseregions) { -+ ret = -ENOMEM; -+ goto err_free_mtd; -+ } -+ -+ pr_info("found serial flash: blocksize=%dKB, numblocks=%d, size=%dKB\n", -+ sflash->blocksize / 1024, sflash->numblocks, sflash->size / 1024); -+ -+ /* Setup region info */ -+ eraseregions->offset = 0; -+ eraseregions->erasesize = sflash->blocksize; -+ eraseregions->numblocks = sflash->numblocks; -+ if (eraseregions->erasesize > mtd->erasesize) -+ mtd->erasesize = eraseregions->erasesize; -+ mtd->size = sflash->size; -+ mtd->numeraseregions = 1; -+ -+ /* Register with MTD */ -+ mtd->name = "bcm47xx-sflash"; -+ mtd->type = MTD_NORFLASH; -+ mtd->flags = MTD_CAP_NORFLASH; -+ mtd->eraseregions = eraseregions; -+ mtd->erase = sflash_mtd_erase; -+ mtd->read = sflash_mtd_read; -+ mtd->write = sflash_mtd_write; -+ mtd->writesize = 1; -+ mtd->priv = sflash; -+ ret = dev_set_drvdata(&pdev->dev, mtd); -+ mtd->owner = THIS_MODULE; -+ if (ret) { -+ pr_err("adding private data failed\n"); -+ goto err_free_eraseregions; -+ } -+ -+ ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0); -+ -+ if (ret) { -+ pr_err("mtd_device_register failed\n"); -+ goto err_free_eraseregions; -+ } -+ return 0; -+ -+err_free_eraseregions: -+ kfree(eraseregions); -+err_free_mtd: -+ kfree(mtd); -+err_out: -+ return ret; -+} -+ -+static int __devexit bcm47xx_sflash_remove(struct platform_device *pdev) -+{ -+ struct mtd_info *mtd = dev_get_drvdata(&pdev->dev); -+ -+ if (mtd) { -+ mtd_device_unregister(mtd); -+ map_destroy(mtd); -+ kfree(mtd->eraseregions); -+ kfree(mtd); -+ dev_set_drvdata(&pdev->dev, NULL); -+ } -+ return 0; -+} -+ -+static struct platform_driver bcm47xx_sflash_driver = { -+ .remove = __devexit_p(bcm47xx_sflash_remove), -+ .driver = { -+ .name = "bcm47xx_sflash", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init init_bcm47xx_sflash(void) -+{ -+ int ret = platform_driver_probe(&bcm47xx_sflash_driver, bcm47xx_sflash_probe); -+ -+ if (ret) -+ pr_err("error registering platform driver: %i\n", ret); -+ return ret; -+} -+ -+static void __exit exit_bcm47xx_sflash(void) -+{ -+ platform_driver_unregister(&bcm47xx_sflash_driver); -+} -+ -+module_init(init_bcm47xx_sflash); -+module_exit(exit_bcm47xx_sflash); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("BCM47XX parallel flash driver"); 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 7de051dad9..0000000000 --- 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 - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - - 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 1a994d9037..0000000000 --- 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 - #include - #include -+#include - - 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 53f6e98d15..0000000000 --- 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 -+ * Copyright (C) 2011-2012 Tathagata Das - * - * 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 - * Copyright (C) 2010-2011 Hauke Mehrtens -+ * Copyright (C) 2011-2012 Tathagata Das - * - * 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 - #include - #include -+#include - - 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 - * Copyright (C) 2010 Waldemar Brodkorb - * Copyright (C) 2010-2012 Hauke Mehrtens -+ * Copyright (C) 2011-2012 Tathagata Das - * - * 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 -+ * Copyright (C) 2011-2012 Tathagata Das - * - * 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 - #include - #include -+#include - - 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 -+ * Copyright 2010, Broadcom Corporation -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#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 - * Copyright 2010, Bernhard Loos - * Copyright 2011, Hauke Mehrtens -+ * Copyright (C) 2011-2012 Tathagata Das - * - * 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 -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 -+ * 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/050-mtd-add-bcm47xx-part-parser.patch b/target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch new file mode 100644 index 0000000000..5381e2f6cc --- /dev/null +++ b/target/linux/brcm47xx/patches-3.3/050-mtd-add-bcm47xx-part-parser.patch @@ -0,0 +1,571 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -172,6 +172,13 @@ config MTD_MYLOADER_PARTS + You will still need the parsing functions to be called by the driver + for your particular device. It won't happen automatically. + ++config MTD_BCM47XX_PARTS ++ tristate "BCM47XX partitioning support" ++ default y ++ depends on BCM47XX ++ ---help--- ++ bcm47XX partitioning support ++ + comment "User Modules And Translation Layers" + + config MTD_CHAR +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o ++obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o + + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_CHAR) += mtdchar.o +--- /dev/null ++++ b/drivers/mtd/bcm47xxpart.c +@@ -0,0 +1,542 @@ ++/* ++ * Copyright (C) 2006 Felix Fietkau ++ * Copyright (C) 2005 Waldemar Brodkorb ++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) ++ * ++ * original functions for finding root filesystem from Mike Baker ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Copyright 2001-2003, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * Flash mapping for BCM947XX boards ++ */ ++ ++#define pr_fmt(fmt) "bcm47xx_part: " fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define TRX_MAGIC 0x30524448 /* "HDR0" */ ++#define TRX_VERSION 1 ++#define TRX_MAX_LEN 0x3A0000 ++#define TRX_NO_HEADER 1 /* Do not write TRX header */ ++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */ ++#define TRX_MAX_OFFSET 3 ++ ++struct trx_header { ++ u32 magic; /* "HDR0" */ ++ u32 len; /* Length of file including header */ ++ u32 crc32; /* 32-bit CRC from flag_version to end of file */ ++ u32 flag_version; /* 0:15 flags, 16:31 version */ ++ u32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */ ++}; ++ ++/* for Edimax Print servers which use an additional header ++ * then the firmware on flash looks like : ++ * EDIMAX HEADER | TRX HEADER ++ * As this header is 12 bytes long we have to handle it ++ * and skip it to find the TRX header ++ */ ++#define EDIMAX_PS_HEADER_MAGIC 0x36315350 /* "PS16" */ ++#define EDIMAX_PS_HEADER_LEN 0xc /* 12 bytes long for edimax header */ ++ ++#define NVRAM_SPACE 0x8000 ++ ++#define ROUTER_NETGEAR_WGR614L 1 ++#define ROUTER_NETGEAR_WNR834B 2 ++#define ROUTER_NETGEAR_WNDR3300 3 ++#define ROUTER_NETGEAR_WNR3500L 4 ++#define ROUTER_SIMPLETECH_SIMPLESHARE 5 ++#define ROUTER_NETGEAR_WNDR3400 6 ++ ++static int ++find_cfe_size(struct mtd_info *mtd) ++{ ++ struct trx_header *trx; ++ unsigned char buf[512]; ++ int off; ++ size_t len; ++ int blocksize; ++ ++ trx = (struct trx_header *) buf; ++ ++ blocksize = mtd->erasesize; ++ if (blocksize < 0x10000) ++ blocksize = 0x10000; ++ ++ for (off = (128*1024); off < mtd->size; off += blocksize) { ++ memset(buf, 0xe5, sizeof(buf)); ++ ++ /* ++ * Read into buffer ++ */ ++ if (mtd->read(mtd, off, sizeof(buf), &len, buf) || ++ len != sizeof(buf)) ++ continue; ++ ++ if (le32_to_cpu(trx->magic) == EDIMAX_PS_HEADER_MAGIC) { ++ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN, ++ sizeof(buf), &len, buf) || len != sizeof(buf)) { ++ continue; ++ } else { ++ pr_notice("Found edimax header\n"); ++ } ++ } ++ ++ /* found a TRX header */ ++ if (le32_to_cpu(trx->magic) == TRX_MAGIC) ++ goto found; ++ } ++ ++ pr_notice("%s: Couldn't find bootloader size\n", mtd->name); ++ return -1; ++ ++ found: ++ pr_notice("bootloader size: %d\n", off); ++ return off; ++ ++} ++ ++/* ++ * Copied from mtdblock.c ++ * ++ * Cache stuff... ++ * ++ * Since typical flash erasable sectors are much larger than what Linux's ++ * buffer cache can handle, we must implement read-modify-write on flash ++ * sectors for each block write requests. To avoid over-erasing flash sectors ++ * and to speed things up, we locally cache a whole flash sector while it is ++ * being written to until a different sector is required. ++ */ ++ ++static void erase_callback(struct erase_info *done) ++{ ++ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; ++ wake_up(wait_q); ++} ++ ++static int erase_write(struct mtd_info *mtd, unsigned long pos, ++ int len, const char *buf) ++{ ++ struct erase_info erase; ++ DECLARE_WAITQUEUE(wait, current); ++ wait_queue_head_t wait_q; ++ size_t retlen; ++ int ret; ++ ++ /* ++ * First, let's erase the flash block. ++ */ ++ ++ init_waitqueue_head(&wait_q); ++ erase.mtd = mtd; ++ erase.callback = erase_callback; ++ erase.addr = pos; ++ erase.len = len; ++ erase.priv = (u_long)&wait_q; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ add_wait_queue(&wait_q, &wait); ++ ++ ret = mtd->erase(mtd, &erase); ++ if (ret) { ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&wait_q, &wait); ++ pr_warn("erase of region [0x%lx, 0x%x] on \"%s\" failed\n", ++ pos, len, mtd->name); ++ return ret; ++ } ++ ++ schedule(); /* Wait for erase to finish. */ ++ remove_wait_queue(&wait_q, &wait); ++ ++ /* ++ * Next, write data to flash. ++ */ ++ ++ ret = mtd->write(mtd, pos, len, &retlen, buf); ++ if (ret) ++ return ret; ++ if (retlen != len) ++ return -EIO; ++ return 0; ++} ++ ++ ++static int ++find_dual_image_off(struct mtd_info *mtd) ++{ ++ struct trx_header trx; ++ int off, blocksize; ++ size_t len; ++ ++ blocksize = mtd->erasesize; ++ if (blocksize < 0x10000) ++ blocksize = 0x10000; ++ ++ for (off = (128*1024); off < mtd->size; off += blocksize) { ++ memset(&trx, 0xe5, sizeof(trx)); ++ /* ++ * Read into buffer ++ */ ++ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || ++ len != sizeof(trx)) ++ continue; ++ /* found last TRX header */ ++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) { ++ if (le32_to_cpu(trx.flag_version >> 16) == 2) { ++ pr_notice("dual image TRX header found\n"); ++ return mtd->size / 2; ++ } else { ++ return 0; ++ } ++ } ++ } ++ return 0; ++} ++ ++ ++static int ++find_root(struct mtd_info *mtd, struct mtd_partition *part) ++{ ++ struct trx_header trx, *trx2; ++ unsigned char buf[512], *block; ++ int off, blocksize, trxoff = 0; ++ u32 i, crc = ~0; ++ size_t len; ++ bool edimax = false; ++ ++ blocksize = mtd->erasesize; ++ if (blocksize < 0x10000) ++ blocksize = 0x10000; ++ ++ for (off = (128*1024); off < mtd->size; off += blocksize) { ++ memset(&trx, 0xe5, sizeof(trx)); ++ ++ /* ++ * Read into buffer ++ */ ++ if (mtd->read(mtd, off, sizeof(trx), &len, (char *) &trx) || ++ len != sizeof(trx)) ++ continue; ++ ++ /* found an edimax header */ ++ if (le32_to_cpu(trx.magic) == EDIMAX_PS_HEADER_MAGIC) { ++ /* read the correct trx header */ ++ if (mtd->read(mtd, off + EDIMAX_PS_HEADER_LEN, ++ sizeof(trx), &len, (char *) &trx) || ++ len != sizeof(trx)) { ++ continue; ++ } else { ++ pr_notice("Found an edimax ps header\n"); ++ edimax = true; ++ } ++ } ++ ++ /* found a TRX header */ ++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) { ++ part->offset = le32_to_cpu(trx.offsets[2]) ? : ++ le32_to_cpu(trx.offsets[1]); ++ part->size = le32_to_cpu(trx.len); ++ ++ part->size -= part->offset; ++ part->offset += off; ++ if (edimax) { ++ off += EDIMAX_PS_HEADER_LEN; ++ trxoff = EDIMAX_PS_HEADER_LEN; ++ } ++ ++ goto found; ++ } ++ } ++ ++ pr_warn("%s: Couldn't find root filesystem\n", ++ mtd->name); ++ return -1; ++ ++ found: ++ pr_notice("TRX offset : %x\n", trxoff); ++ if (part->size == 0) ++ return 0; ++ ++ if (mtd->read(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf)) ++ return 0; ++ ++ /* Move the fs outside of the trx */ ++ part->size = 0; ++ ++ if (trx.len != part->offset + part->size - off) { ++ /* Update the trx offsets and length */ ++ trx.len = part->offset + part->size - off; ++ ++ /* Update the trx crc32 */ ++ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) { ++ if (mtd->read(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf)) ++ return 0; ++ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i)); ++ } ++ trx.crc32 = crc; ++ ++ /* read first eraseblock from the trx */ ++ block = kmalloc(mtd->erasesize, GFP_KERNEL); ++ trx2 = (struct trx_header *) block; ++ if (mtd->read(mtd, off - trxoff, mtd->erasesize, &len, block) || len != mtd->erasesize) { ++ pr_err("Error accessing the first trx eraseblock\n"); ++ return 0; ++ } ++ ++ pr_notice("Updating TRX offsets and length:\n"); ++ pr_notice("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32); ++ pr_notice("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32); ++ ++ /* Write updated trx header to the flash */ ++ memcpy(block + trxoff, &trx, sizeof(trx)); ++ if (mtd->unlock) ++ mtd->unlock(mtd, off - trxoff, mtd->erasesize); ++ erase_write(mtd, off - trxoff, mtd->erasesize, block); ++ if (mtd->sync) ++ mtd->sync(mtd); ++ kfree(block); ++ pr_notice("Done\n"); ++ } ++ ++ return part->size; ++} ++ ++static int get_router(void) ++{ ++ char buf[20]; ++ u32 boardnum = 0; ++ u16 boardtype = 0; ++ u16 boardrev = 0; ++ u32 boardflags = 0; ++ u16 sdram_init = 0; ++ u16 cardbus = 0; ++ u16 strev = 0; ++ ++ if (nvram_getenv("boardnum", buf, sizeof(buf)) >= 0) ++ boardnum = simple_strtoul(buf, NULL, 0); ++ if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) ++ boardtype = simple_strtoul(buf, NULL, 0); ++ if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) ++ boardrev = simple_strtoul(buf, NULL, 0); ++ if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) ++ boardflags = simple_strtoul(buf, NULL, 0); ++ if (nvram_getenv("sdram_init", buf, sizeof(buf)) >= 0) ++ sdram_init = simple_strtoul(buf, NULL, 0); ++ if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) ++ cardbus = simple_strtoul(buf, NULL, 0); ++ if (nvram_getenv("st_rev", buf, sizeof(buf)) >= 0) ++ strev = simple_strtoul(buf, NULL, 0); ++ ++ if ((boardnum == 8 || boardnum == 01) ++ && boardtype == 0x0472 && cardbus == 1) { ++ /* Netgear WNR834B, Netgear WNR834Bv2 */ ++ return ROUTER_NETGEAR_WNR834B; ++ } ++ ++ if (boardnum == 01 && boardtype == 0x0472 && boardrev == 0x23) { ++ /* Netgear WNDR-3300 */ ++ return ROUTER_NETGEAR_WNDR3300; ++ } ++ ++ if ((boardnum == 83258 || boardnum == 01) ++ && boardtype == 0x048e ++ && (boardrev == 0x11 || boardrev == 0x10) ++ && boardflags == 0x750 ++ && sdram_init == 0x000A) { ++ /* Netgear WGR614v8/L/WW 16MB ram, cfe v1.3 or v1.5 */ ++ return ROUTER_NETGEAR_WGR614L; ++ } ++ ++ if ((boardnum == 1 || boardnum == 3500) ++ && boardtype == 0x04CF ++ && (boardrev == 0x1213 || boardrev == 02)) { ++ /* Netgear WNR3500v2/U/L */ ++ return ROUTER_NETGEAR_WNR3500L; ++ } ++ ++ if (boardnum == 1 && boardtype == 0xb4cf && boardrev == 0x1100) { ++ /* Netgear WNDR3400 */ ++ return ROUTER_NETGEAR_WNDR3400; ++ } ++ ++ if (boardtype == 0x042f ++ && boardrev == 0x10 ++ && boardflags == 0 ++ && strev == 0x11) { ++ /* Simpletech Simpleshare */ ++ return ROUTER_SIMPLETECH_SIMPLESHARE; ++ } ++ ++ return 0; ++} ++ ++static int parse_bcm47xx_partitions(struct mtd_info *mtd, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ int cfe_size; ++ int dual_image_offset = 0; ++ /* e.g Netgear 0x003e0000-0x003f0000 : "board_data", we exclude this ++ * part from our mapping to prevent overwriting len/checksum on e.g. ++ * Netgear WGR614v8/L/WW ++ */ ++ int custom_data_size = 0; ++ struct mtd_partition *bcm47xx_parts; ++ ++ cfe_size = find_cfe_size(mtd); ++ if (cfe_size < 0) ++ return 0; ++ ++ bcm47xx_parts = kzalloc(sizeof(struct mtd_partition) * 6, GFP_KERNEL); ++ ++ bcm47xx_parts[0].name = "cfe"; ++ bcm47xx_parts[1].name = "linux"; ++ bcm47xx_parts[2].name = "rootfs"; ++ bcm47xx_parts[3].name = "nvram"; ++ ++ /* boot loader */ ++ bcm47xx_parts[0].mask_flags = MTD_WRITEABLE; ++ bcm47xx_parts[0].offset = 0; ++ bcm47xx_parts[0].size = cfe_size; ++ ++ /* nvram */ ++ if (cfe_size != 384 * 1024) { ++ ++ switch (get_router()) { ++ case ROUTER_NETGEAR_WGR614L: ++ case ROUTER_NETGEAR_WNR834B: ++ case ROUTER_NETGEAR_WNDR3300: ++ case ROUTER_NETGEAR_WNR3500L: ++ case ROUTER_NETGEAR_WNDR3400: ++ /* Netgear: checksum is @ 0x003AFFF8 for 4M flash or checksum ++ * is @ 0x007AFFF8 for 8M flash ++ */ ++ custom_data_size = mtd->erasesize; ++ ++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); ++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); ++ ++ /* Place CFE board_data into a partition */ ++ bcm47xx_parts[4].name = "board_data"; ++ bcm47xx_parts[4].offset = bcm47xx_parts[3].offset - custom_data_size; ++ bcm47xx_parts[4].size = custom_data_size; ++ break; ++ ++ case ROUTER_SIMPLETECH_SIMPLESHARE: ++ /* Fixup Simpletech Simple share nvram */ ++ ++ pr_notice("Setting up simpletech nvram\n"); ++ custom_data_size = mtd->erasesize; ++ ++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize) * 2; ++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); ++ ++ /* Place backup nvram into a partition */ ++ bcm47xx_parts[4].name = "nvram_copy"; ++ bcm47xx_parts[4].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); ++ bcm47xx_parts[4].size = roundup(NVRAM_SPACE, mtd->erasesize); ++ break; ++ ++ default: ++ bcm47xx_parts[3].offset = mtd->size - roundup(NVRAM_SPACE, mtd->erasesize); ++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); ++ } ++ ++ } else { ++ /* nvram (old 128kb config partition on netgear wgt634u) */ ++ bcm47xx_parts[3].offset = bcm47xx_parts[0].size; ++ bcm47xx_parts[3].size = roundup(NVRAM_SPACE, mtd->erasesize); ++ } ++ ++ /* dual image offset*/ ++ pr_notice("Looking for dual image\n"); ++ dual_image_offset = find_dual_image_off(mtd); ++ /* linux (kernel and rootfs) */ ++ if (cfe_size != 384 * 1024) { ++ if (get_router() == ROUTER_SIMPLETECH_SIMPLESHARE) { ++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size; ++ bcm47xx_parts[1].size = bcm47xx_parts[4].offset - dual_image_offset - ++ bcm47xx_parts[1].offset - custom_data_size; ++ } else { ++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size; ++ bcm47xx_parts[1].size = bcm47xx_parts[3].offset - dual_image_offset - ++ bcm47xx_parts[1].offset - custom_data_size; ++ } ++ } else { ++ /* do not count the elf loader, which is on one block */ ++ bcm47xx_parts[1].offset = bcm47xx_parts[0].size + ++ bcm47xx_parts[3].size + mtd->erasesize; ++ bcm47xx_parts[1].size = mtd->size - ++ bcm47xx_parts[0].size - ++ (2*bcm47xx_parts[3].size) - ++ mtd->erasesize - custom_data_size; ++ } ++ ++ /* find and size rootfs */ ++ find_root(mtd, &bcm47xx_parts[2]); ++ bcm47xx_parts[2].size = mtd->size - dual_image_offset - ++ bcm47xx_parts[2].offset - ++ bcm47xx_parts[3].size - custom_data_size; ++ *pparts = bcm47xx_parts; ++ return bcm47xx_parts[4].name == NULL ? 4 : 5; ++} ++ ++static struct mtd_part_parser bcm47xx_parser = { ++ .owner = THIS_MODULE, ++ .parse_fn = parse_bcm47xx_partitions, ++ .name = "bcm47xx", ++}; ++ ++static int __init bcm47xx_parser_init(void) ++{ ++ return register_mtd_parser(&bcm47xx_parser); ++} ++ ++static void __exit bcm47xx_parser_exit(void) ++{ ++ deregister_mtd_parser(&bcm47xx_parser); ++} ++ ++module_init(bcm47xx_parser_init); ++module_exit(bcm47xx_parser_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Parsing code for flash partitions on bcm47xx SoCs"); diff --git a/target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch new file mode 100644 index 0000000000..86336ed571 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.3/051-mtd-add-parallel-flash-driver.patch @@ -0,0 +1,224 @@ +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -248,6 +248,15 @@ config MTD_LANTIQ + help + Support for NOR flash attached to the Lantiq SoC's External Bus Unit. + ++config MTD_BCM47XX_PFLASH ++ tristate "bcm47xx parallel flash support" ++ default y ++ depends on BCM47XX ++ select MTD_PARTITIONS ++ select MTD_BCM47XX_PARTS ++ help ++ Support for bcm47xx parallel flash ++ + config MTD_DILNETPC + tristate "CFI Flash device mapped on DIL/Net PC" + depends on X86 && MTD_CFI_INTELEXT && BROKEN +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -57,3 +57,4 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o + obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o + obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o + obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o ++obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o +--- /dev/null ++++ b/drivers/mtd/maps/bcm47xx-pflash.c +@@ -0,0 +1,196 @@ ++/* ++ * Copyright (C) 2006 Felix Fietkau ++ * Copyright (C) 2005 Waldemar Brodkorb ++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) ++ * ++ * original functions for finding root filesystem from Mike Baker ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * Copyright 2001-2003, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ * Flash mapping for BCM947XX boards ++ */ ++ ++#define pr_fmt(fmt) "bcm47xx_pflash: " fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define WINDOW_ADDR 0x1fc00000 ++#define WINDOW_SIZE 0x400000 ++#define BUSWIDTH 2 ++ ++static struct mtd_info *bcm47xx_mtd; ++ ++static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) ++{ ++ if (len == 1) { ++ memcpy_fromio(to, map->virt + from, len); ++ } else { ++ int i; ++ u16 *dest = (u16 *) to; ++ u16 *src = (u16 *) (map->virt + from); ++ for (i = 0; i < (len / 2); i++) ++ dest[i] = src[i]; ++ if (len & 1) ++ *((u8 *)dest+len-1) = src[i] & 0xff; ++ } ++} ++ ++static struct map_info bcm47xx_map = { ++ name: "Physically mapped flash", ++ size : WINDOW_SIZE, ++ bankwidth : BUSWIDTH, ++ phys : WINDOW_ADDR, ++}; ++ ++static const char *probes[] = { "bcm47xx", NULL }; ++ ++static int bcm47xx_pflash_probe(struct platform_device *pdev) ++{ ++#ifdef CONFIG_BCM47XX_SSB ++ struct ssb_mipscore *ssb_mcore; ++#endif ++#ifdef CONFIG_BCM47XX_BCMA ++ struct bcma_drv_cc *bcma_cc; ++#endif ++ int ret = 0; ++ ++ switch (bcm47xx_bus_type) { ++#ifdef CONFIG_BCM47XX_SSB ++ case BCM47XX_BUS_TYPE_SSB: ++ ssb_mcore = &bcm47xx_bus.ssb.mipscore; ++ if (!ssb_mcore->pflash.present) ++ return -ENODEV; ++ ++ 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->pflash.present) ++ return -ENODEV; ++ ++ bcm47xx_map.phys = bcma_cc->pflash.window; ++ bcm47xx_map.size = bcma_cc->pflash.window_size; ++ bcm47xx_map.bankwidth = bcma_cc->pflash.buswidth; ++ break; ++#endif ++ } ++ ++ pr_notice("flash init: 0x%08x 0x%08lx\n", bcm47xx_map.phys, bcm47xx_map.size); ++ bcm47xx_map.virt = ioremap_nocache(bcm47xx_map.phys, bcm47xx_map.size); ++ ++ if (!bcm47xx_map.virt) { ++ pr_err("Failed to ioremap\n"); ++ return -EIO; ++ } ++ ++ simple_map_init(&bcm47xx_map); ++ /* override copy_from routine */ ++ bcm47xx_map.copy_from = bcm47xx_map_copy_from; ++ ++ bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map); ++ if (!bcm47xx_mtd) { ++ pr_err("Failed to do_map_probe\n"); ++ ret = -ENXIO; ++ goto err_unmap; ++ } ++ bcm47xx_mtd->owner = THIS_MODULE; ++ ++ pr_notice("Flash device: 0x%lx at 0x%x\n", bcm47xx_map.size, WINDOW_ADDR); ++ ++ ret = mtd_device_parse_register(bcm47xx_mtd, probes, NULL, NULL, 0); ++ ++ if (ret) { ++ pr_err("Flash: mtd_device_register failed\n"); ++ goto err_destroy; ++ } ++ return 0; ++ ++err_destroy: ++ map_destroy(bcm47xx_mtd); ++err_unmap: ++ iounmap(bcm47xx_map.virt); ++ return ret; ++} ++ ++static int __devexit bcm47xx_pflash_remove(struct platform_device *pdev) ++{ ++ mtd_device_unregister(bcm47xx_mtd); ++ map_destroy(bcm47xx_mtd); ++ iounmap(bcm47xx_map.virt); ++ return 0; ++} ++ ++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_pflash(void) ++{ ++ 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_pflash(void) ++{ ++ platform_driver_unregister(&bcm47xx_pflash_driver); ++} ++ ++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/052-mtd-add-serial-flash-driver.patch b/target/linux/brcm47xx/patches-3.3/052-mtd-add-serial-flash-driver.patch new file mode 100644 index 0000000000..1e408fa707 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.3/052-mtd-add-serial-flash-driver.patch @@ -0,0 +1,335 @@ +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -257,6 +257,15 @@ config MTD_BCM47XX_PFLASH + help + Support for bcm47xx parallel flash + ++config MTD_BCM47XX_SFLASH ++ tristate "bcm47xx serial flash support" ++ default y ++ depends on BCM47XX ++ select MTD_PARTITIONS ++ select MTD_BCM47XX_PARTS ++ help ++ Support for bcm47xx parallel flash ++ + config MTD_DILNETPC + tristate "CFI Flash device mapped on DIL/Net PC" + depends on X86 && MTD_CFI_INTELEXT && BROKEN +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -58,3 +58,4 @@ obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr + obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o + obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o + obj-$(CONFIG_MTD_BCM47XX_PFLASH)+= bcm47xx-pflash.o ++obj-$(CONFIG_MTD_BCM47XX_SFLASH)+= bcm47xx-sflash.o +--- /dev/null ++++ b/drivers/mtd/maps/bcm47xx-sflash.c +@@ -0,0 +1,270 @@ ++/* ++ * Broadcom SiliconBackplane chipcommon serial flash interface ++ * ++ * Copyright 2011, 2012, Hauke Mehrtens ++ * Copyright 2006, Broadcom Corporation ++ * All Rights Reserved. ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#define pr_fmt(fmt) "bcm47xx_sflash: " fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++sflash_mtd_poll(struct bcm47xx_sflash *sflash, unsigned int offset, int timeout) ++{ ++ unsigned long now = jiffies; ++ ++ for (;;) { ++ if (!sflash->poll(sflash, offset)) { ++ break; ++ } ++ if (time_after(jiffies, now + timeout)) { ++ pr_err("timeout while polling\n"); ++ return -ETIMEDOUT; ++ ++ } ++ cpu_relax(); ++ udelay(1); ++ } ++ ++ return 0; ++} ++ ++static int ++sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) ++{ ++ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *)mtd->priv; ++ ++ /* Check address range */ ++ if (!len) ++ return 0; ++ ++ if ((from + len) > mtd->size) ++ return -EINVAL; ++ ++ *retlen = 0; ++ while (len) { ++ int ret = sflash->read(sflash, from, len, buf); ++ if (ret < 0) ++ return ret; ++ ++ from += (loff_t) ret; ++ len -= ret; ++ buf += ret; ++ *retlen += ret; ++ } ++ ++ return 0; ++} ++ ++static int ++sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) ++{ ++ int bytes; ++ int ret; ++ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *)mtd->priv; ++ ++ /* Check address range */ ++ if (!len) ++ return 0; ++ ++ if ((to + len) > mtd->size) ++ return -EINVAL; ++ ++ *retlen = 0; ++ while (len) { ++ ret = sflash->write(sflash, to, len, buf); ++ if (ret < 0) ++ return ret; ++ ++ bytes = ret; ++ ++ ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10); ++ if (ret) ++ return ret; ++ ++ to += (loff_t) bytes; ++ len -= bytes; ++ buf += bytes; ++ *retlen += bytes; ++ } ++ ++ return 0; ++} ++ ++static int ++sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) ++{ ++ struct bcm47xx_sflash *sflash = (struct bcm47xx_sflash *) mtd->priv; ++ int i, j, ret = 0; ++ unsigned int addr, len; ++ ++ /* Check address range */ ++ if (!erase->len) ++ return 0; ++ if ((erase->addr + erase->len) > mtd->size) ++ return -EINVAL; ++ ++ addr = erase->addr; ++ len = erase->len; ++ ++ /* Ensure that requested regions are aligned */ ++ for (i = 0; i < mtd->numeraseregions; i++) { ++ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) { ++ if (addr == mtd->eraseregions[i].offset + ++ mtd->eraseregions[i].erasesize * j && ++ len >= mtd->eraseregions[i].erasesize) { ++ ret = sflash->erase(sflash, addr); ++ if (ret < 0) ++ break; ++ ret = sflash_mtd_poll(sflash, addr, 10 * HZ); ++ if (ret) ++ break; ++ addr += mtd->eraseregions[i].erasesize; ++ len -= mtd->eraseregions[i].erasesize; ++ } ++ } ++ if (ret) ++ break; ++ } ++ ++ /* Set erase status */ ++ if (ret) ++ erase->state = MTD_ERASE_FAILED; ++ else ++ erase->state = MTD_ERASE_DONE; ++ ++ /* Call erase callback */ ++ if (erase->callback) ++ erase->callback(erase); ++ ++ return ret; ++} ++ ++static const char *probes[] = { "bcm47xx", NULL }; ++ ++static int bcm47xx_sflash_probe(struct platform_device *pdev) ++{ ++ struct bcm47xx_sflash *sflash = dev_get_platdata(&pdev->dev); ++ struct mtd_info *mtd; ++ struct mtd_erase_region_info *eraseregions; ++ int ret = 0; ++ ++ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); ++ if (!mtd){ ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ eraseregions = kzalloc(sizeof(struct mtd_erase_region_info), GFP_KERNEL); ++ if (!eraseregions) { ++ ret = -ENOMEM; ++ goto err_free_mtd; ++ } ++ ++ pr_info("found serial flash: blocksize=%dKB, numblocks=%d, size=%dKB\n", ++ sflash->blocksize / 1024, sflash->numblocks, sflash->size / 1024); ++ ++ /* Setup region info */ ++ eraseregions->offset = 0; ++ eraseregions->erasesize = sflash->blocksize; ++ eraseregions->numblocks = sflash->numblocks; ++ if (eraseregions->erasesize > mtd->erasesize) ++ mtd->erasesize = eraseregions->erasesize; ++ mtd->size = sflash->size; ++ mtd->numeraseregions = 1; ++ ++ /* Register with MTD */ ++ mtd->name = "bcm47xx-sflash"; ++ mtd->type = MTD_NORFLASH; ++ mtd->flags = MTD_CAP_NORFLASH; ++ mtd->eraseregions = eraseregions; ++ mtd->erase = sflash_mtd_erase; ++ mtd->read = sflash_mtd_read; ++ mtd->write = sflash_mtd_write; ++ mtd->writesize = 1; ++ mtd->priv = sflash; ++ ret = dev_set_drvdata(&pdev->dev, mtd); ++ mtd->owner = THIS_MODULE; ++ if (ret) { ++ pr_err("adding private data failed\n"); ++ goto err_free_eraseregions; ++ } ++ ++ ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0); ++ ++ if (ret) { ++ pr_err("mtd_device_register failed\n"); ++ goto err_free_eraseregions; ++ } ++ return 0; ++ ++err_free_eraseregions: ++ kfree(eraseregions); ++err_free_mtd: ++ kfree(mtd); ++err_out: ++ return ret; ++} ++ ++static int __devexit bcm47xx_sflash_remove(struct platform_device *pdev) ++{ ++ struct mtd_info *mtd = dev_get_drvdata(&pdev->dev); ++ ++ if (mtd) { ++ mtd_device_unregister(mtd); ++ map_destroy(mtd); ++ kfree(mtd->eraseregions); ++ kfree(mtd); ++ dev_set_drvdata(&pdev->dev, NULL); ++ } ++ 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 = { ++ .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_register(&bcm47xx_sflash_driver); ++ ++ if (ret) ++ pr_err("error registering platform driver: %i\n", ret); ++ return ret; ++} ++ ++static void __exit exit_bcm47xx_sflash(void) ++{ ++ platform_driver_unregister(&bcm47xx_sflash_driver); ++} ++ ++module_init(init_bcm47xx_sflash); ++module_exit(exit_bcm47xx_sflash); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("BCM47XX 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 ++ ++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 0000000000..7635d424de --- /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 ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 ++ * 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 ++ ++#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 0000000000..d65fc0a5b4 --- /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 ++ * Copyright 2011, 2012, Hauke Mehrtens ++ * Copyright 2010, Broadcom Corporation ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#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 + #include + #include ++#include + #include + #include + +@@ -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 ++ + /** 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 0000000000..6e0d491842 --- /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 + #include + #include ++#include + + #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 0000000000..8fb70d68f4 --- /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 ++ * Copyright 2011, 2012, Hauke Mehrtens ++ * Copyright 2010, Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + + #include ++#include + #include ++#include + + #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 ++ + /** 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 0000000000..27c6677209 --- /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 ++ * Copyright 2010, Broadcom Corporation ++ * + * Licensed under the GNU/GPL. See COPYING for details. + */ + ++#include ++#include ++#include + #include + #include ++#include + + #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 ++#include + + /** 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 0000000000..cacb903430 --- /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 + #include + #include ++#include + + /* 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 0000000000..a271876fa9 --- /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 +- * Copyright (C) 2010-2011 Hauke Mehrtens ++ * Copyright (C) 2010-2012 Hauke Mehrtens + * + * 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 9013972375..5e324e473b 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 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c -@@ -33,6 +33,8 @@ +@@ -31,6 +31,8 @@ + #include #include #include - #include +#include +#include #include #include #include -@@ -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 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 + 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 69d034ccaf..9487d301f2 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 c486e68c00..6b1db25805 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 6ef5ecd51d..0000000000 --- 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 03540f04cc..0000000000 --- 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 302ac8d954..0000000000 --- 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 c535c05db5..8b858e11ba 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 a232bff91c..bdd2c040dc 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 951c6d40e9..b8f72a12c6 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 2f62728d6e..187e64e875 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 a2902e7c72..2819ca1739 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 457958a9d9..0aef7952d1 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 +@@ -22,6 +22,8 @@ + #include 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 7626c62abc..1c0c6195e8 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 e45b402426..1bf09f36b0 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 - #include +@@ -21,7 +21,8 @@ + #include + #include -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 e427574f77..10c70abbbb 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 #include +--- 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 29aaa29582..824c4455cd 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 ++#include ++ ++#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 ++#include ++ ++#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 ++#include + #include + #include + 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 #include #include +#include #include /* SPROM sharing */ - #include "bcma_regs.h" +-#include "bcma_regs.h" ++#include + + 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 */ @@ -3010,11 +3805,89 @@ + +/* 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 */ @@ -3326,5 +4232,10 @@ +#define BCMA_SOC_PCIE1_DMA_H32 0xc0000000U /* PCIE Client Mode sb2pcitranslation2 + * (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 35ca6b81e3..0000000000 --- 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 dc8367b6c5..0000000000 --- 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 9386af29cf..0000000000 --- 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 b6e6480567..0000000000 --- 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 0000000000..e61be82fe1 --- /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 0000000000..d791f16a0f --- /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 + #include +-#include +-#include + + #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 + #include +-#include +-#include + + #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 ++#include + #include + #include + +@@ -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 + #include /* SPROM sharing */ + +-#include "bcma_regs.h" ++#include + + 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_ */