diff options
Diffstat (limited to 'target/linux/brcm47xx/patches-3.2/030-bcm47xx-bcma-nandflash.patch')
| -rw-r--r-- | target/linux/brcm47xx/patches-3.2/030-bcm47xx-bcma-nandflash.patch | 1157 | 
1 files changed, 0 insertions, 1157 deletions
diff --git a/target/linux/brcm47xx/patches-3.2/030-bcm47xx-bcma-nandflash.patch b/target/linux/brcm47xx/patches-3.2/030-bcm47xx-bcma-nandflash.patch deleted file mode 100644 index 6336f41f5..000000000 --- a/target/linux/brcm47xx/patches-3.2/030-bcm47xx-bcma-nandflash.patch +++ /dev/null @@ -1,1157 +0,0 @@ ---- a/arch/mips/bcm47xx/Kconfig -+++ b/arch/mips/bcm47xx/Kconfig -@@ -24,6 +24,7 @@ config BCM47XX_BCMA - 	select BCMA_DRIVER_MIPS - 	select BCMA_DRIVER_PCI_HOSTMODE if PCI - 	select BCMA_SFLASH -+	select BCMA_NFLASH - 	default y - 	help - 	 Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus. ---- a/arch/mips/bcm47xx/bus.c -+++ b/arch/mips/bcm47xx/bus.c -@@ -2,6 +2,7 @@ -  * BCM947xx nvram variable access -  * -  * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de> -+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -  * -  * This program is free software; you can redistribute  it and/or modify it -  * under  the terms of  the GNU General  Public License as published by the -@@ -80,3 +81,9 @@ void bcm47xx_sflash_struct_ssb_init(stru - 	sflash->numblocks = scc->sflash.numblocks; - 	sflash->size = scc->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; -+} ---- a/arch/mips/bcm47xx/nvram.c -+++ b/arch/mips/bcm47xx/nvram.c -@@ -4,6 +4,7 @@ -  * Copyright (C) 2005 Broadcom Corporation -  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> -  * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de> -+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -  * -  * This program is free software; you can redistribute  it and/or modify it -  * under  the terms of  the GNU General  Public License as published by the -@@ -21,6 +22,7 @@ - #include <asm/mach-bcm47xx/nvram.h> - #include <asm/mach-bcm47xx/bcm47xx.h> - #include <asm/mach-bcm47xx/bus.h> -+#include <linux/mtd/bcm47xx_nand.h> -  - static char nvram_buf[NVRAM_SPACE]; -  -@@ -134,6 +136,51 @@ found: - 	return 0; - } -  -+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; -+} -+ - #ifdef CONFIG_BCM47XX_SSB - static void early_nvram_init_ssb(void) - { -@@ -168,6 +215,11 @@ static void early_nvram_init_bcma(void) - 		if (err < 0) - 			printk(KERN_WARNING "can not read from flash: %i\n", err); - 		break; -+	case BCMA_NFLASH: -+		err = early_nvram_init_nflash(); -+		if (err < 0) -+			printk(KERN_WARNING "can not read from nflash: %i\n", err); -+		break; - 	default: - 		printk(KERN_WARNING "unknow flash type\n"); - 	} ---- a/arch/mips/bcm47xx/setup.c -+++ b/arch/mips/bcm47xx/setup.c -@@ -4,6 +4,7 @@ -  *  Copyright (C) 2006 Michael Buesch <m@bues.ch> -  *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org> -  *  Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.de> -+ *  Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -  * -  *  This program is free software; you can redistribute  it and/or modify it -  *  under  the terms of  the GNU General  Public License as published by the -@@ -46,6 +47,7 @@ enum bcm47xx_bus_type bcm47xx_bus_type; - EXPORT_SYMBOL(bcm47xx_bus_type); -  - struct bcm47xx_sflash bcm47xx_sflash; -+struct bcm47xx_nflash bcm47xx_nflash; -  - static struct resource bcm47xx_pflash_resource = { - 	.name	= "bcm47xx_pflash", -@@ -73,6 +75,19 @@ static struct platform_device bcm47xx_sf - 	.num_resources	= 1, - }; -  -+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 bcm47xx_machine_restart(char *command) - { - 	printk(KERN_ALERT "Please stand by while rebooting the system...\n"); -@@ -369,6 +384,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); - } -  - static int __init bcm47xx_register_flash_bcma(void) -@@ -383,6 +401,9 @@ static int __init bcm47xx_register_flash - 	case BCMA_SFLASH: - 		bcm47xx_sflash_dev.dev.platform_data = &bcm47xx_sflash; - 		return platform_device_register(&bcm47xx_sflash_dev); -+	case BCMA_NFLASH: -+		bcm47xx_nflash_dev.dev.platform_data = &bcm47xx_nflash; -+		return platform_device_register(&bcm47xx_nflash_dev); - 	default: - 		printk(KERN_ERR "No flash device found\n"); - 		return -1; ---- a/arch/mips/include/asm/mach-bcm47xx/bus.h -+++ b/arch/mips/include/asm/mach-bcm47xx/bus.h -@@ -2,6 +2,7 @@ -  * BCM947xx nvram variable access -  * -  * Copyright (C) 2011 Hauke Mehrtens <hauke@hauke-m.de> -+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -  * -  * This program is free software; you can redistribute  it and/or modify it -  * under  the terms of  the GNU General  Public License as published by the -@@ -13,6 +14,7 @@ - #include <linux/bcma/bcma.h> - #include <linux/mtd/mtd.h> - #include <bcm47xx.h> -+#include <linux/mtd/nand.h> -  - struct bcm47xx_sflash { - 	enum bcm47xx_bus_type sflash_type; -@@ -29,11 +31,24 @@ struct bcm47xx_sflash { - 	u32 blocksize;		/* Block size */ - 	u32 numblocks;		/* Number of blocks */ - 	u32 size;		/* Total size in bytes */ -- --	struct mtd_info *mtd; - }; -  - 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; -+ -+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 -@@ -47,6 +47,11 @@ u32 bcma_pmu_get_clockcpu(struct bcma_dr - int bcma_sflash_init(struct bcma_drv_cc *cc); - #endif /* CONFIG_BCMA_SFLASH */ -  -+#ifdef CONFIG_BCMA_NFLASH -+/* driver_chipcommon_nflash.c */ -+int bcma_nflash_init(struct bcma_drv_cc *cc); -+#endif /* CONFIG_BCMA_NFLASH */ -+ - #ifdef CONFIG_BCMA_HOST_PCI - /* host_pci.c */ - extern int __init bcma_host_pci_init(void); ---- /dev/null -+++ b/drivers/bcma/driver_chipcommon_nflash.c -@@ -0,0 +1,154 @@ -+/* -+ * BCMA nand flash interface -+ * -+ * Copyright 2011, Tathagata Das <tathagata@alumnux.com> -+ * Copyright 2010, Broadcom Corporation -+ * -+ * Licensed under the GNU/GPL. See COPYING for details. -+ */ -+ -+#include <linux/bcma/bcma.h> -+#include <linux/bcma/bcma_driver_chipcommon.h> -+#include <linux/delay.h> -+#include <linux/mtd/bcm47xx_nand.h> -+#include <linux/mtd/nand.h> -+ -+#include "bcma_private.h" -+ -+/* Issue a nand flash command */ -+static inline void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode) -+{ -+	bcma_cc_write32(cc, NAND_CMD_START, opcode); -+	bcma_cc_read32(cc,  NAND_CMD_START); -+} -+ -+/* Check offset and length */ -+static int bcma_nflash_offset_is_valid(struct bcma_drv_cc *cc, u32 offset, u32 len, u32 mask) -+{ -+	if ((offset & mask) != 0 || (len & mask) != 0) { -+		pr_err("%s(): Address is not aligned. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask); -+		return 1; -+	} -+ -+	if ((((offset + len) >> 20) >= cc->nflash.size) && -+		(((offset + len) & ((1 << 20) - 1)) != 0)) { -+		pr_err("%s(): Address is outside Flash memory region. offset: %x, len: %x, mask: %x\n", __func__, offset, len, mask); -+		return 1; -+	} -+ -+	return 0; -+} -+ -+/* Read len bytes starting at offset into buf. Returns number of bytes read. */ -+int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf) -+{ -+	u32 mask; -+	int i; -+	u32 *to, val, res; -+ -+	mask = NFL_SECTOR_SIZE - 1; -+	if (bcma_nflash_offset_is_valid(cc, offset, len, mask)) -+		return 0; -+ -+	to = (u32 *)buf; -+	res = len; -+	while (res > 0) { -+		bcma_cc_write32(cc, NAND_CMD_ADDR, offset); -+		bcma_nflash_cmd(cc, NCMD_PAGE_RD); -+		if (bcma_nflash_poll(cc) < 0) -+			break; -+		val = bcma_cc_read32(cc, NAND_INTFC_STATUS); -+		if ((val & NIST_CACHE_VALID) == 0) -+			break; -+		bcma_cc_write32(cc, NAND_CACHE_ADDR, 0); -+		for (i = 0; i < NFL_SECTOR_SIZE; i += 4, to++) { -+			*to = bcma_cc_read32(cc, NAND_CACHE_DATA); -+		} -+		res -= NFL_SECTOR_SIZE; -+		offset += NFL_SECTOR_SIZE; -+	} -+	return (len - res); -+} -+ -+#define NF_RETRIES   1000000 -+ -+/* Poll for command completion. Returns zero when complete. */ -+int bcma_nflash_poll(struct bcma_drv_cc *cc) -+{ -+	u32 retries = NF_RETRIES; -+	u32 pollmask = NIST_CTRL_READY|NIST_FLASH_READY; -+	u32 mask; -+ -+	while (retries--) { -+		mask = bcma_cc_read32(cc, NAND_INTFC_STATUS) & pollmask; -+		if (mask == pollmask) -+			return 0; -+		cpu_relax(); -+	} -+ -+	if (!retries) { -+		pr_err("bcma_nflash_poll: not ready\n"); -+		return -1; -+	} -+ -+	return 0; -+} -+ -+/* Write len bytes starting at offset into buf. Returns success (0) or failure (!0). -+ * Should poll for completion. -+ */ -+int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, -+			    const u8 *buf) -+{ -+	u32 mask; -+	int i; -+	u32 *from, res, reg; -+ -+	mask = cc->nflash.pagesize - 1; -+	if (bcma_nflash_offset_is_valid(cc, offset, len, mask)) -+		return 1; -+ -+	/* disable partial page enable */ -+	reg = bcma_cc_read32(cc, NAND_ACC_CONTROL); -+	reg &= ~NAC_PARTIAL_PAGE_EN; -+	bcma_cc_write32(cc, NAND_ACC_CONTROL, reg); -+ -+	from = (u32 *)buf; -+	res = len; -+	while (res > 0) { -+		bcma_cc_write32(cc, NAND_CACHE_ADDR, 0); -+		for (i = 0; i < cc->nflash.pagesize; i += 4, from++) { -+			if (i % 512 == 0) -+				bcma_cc_write32(cc, NAND_CMD_ADDR, i); -+			bcma_cc_write32(cc, NAND_CACHE_DATA, *from); -+		} -+		bcma_cc_write32(cc, NAND_CMD_ADDR, offset + cc->nflash.pagesize - 512); -+		bcma_nflash_cmd(cc, NCMD_PAGE_PROG); -+		if (bcma_nflash_poll(cc) < 0) -+			break; -+		res -= cc->nflash.pagesize; -+		offset += cc->nflash.pagesize; -+	} -+ -+	if (res <= 0) -+		return 0; -+	else -+		return (len - res); -+} -+ -+/* Erase a region. Returns success (0) or failure (-1). -+ * Poll for completion. -+ */ -+int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset) -+{ -+	if ((offset >> 20) >= cc->nflash.size) -+		return -1; -+	if ((offset & (cc->nflash.blocksize - 1)) != 0) -+		return -1; -+ -+	bcma_cc_write32(cc, NAND_CMD_ADDR, offset); -+	bcma_nflash_cmd(cc, NCMD_BLOCK_ERASE); -+	if (bcma_nflash_poll(cc) < 0) -+		return -1; -+	return 0; -+} ---- a/drivers/bcma/driver_mips.c -+++ b/drivers/bcma/driver_mips.c -@@ -6,6 +6,7 @@ -  * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de> -  * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com> -  * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de> -+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -  * -  * Licensed under the GNU/GPL. See COPYING for details. -  */ -@@ -182,6 +183,17 @@ static void bcma_core_mips_flash_detect( - { - 	struct bcma_bus *bus = mcore->core->bus; -  -+	if (bus->drv_cc.core->id.rev == 38  -+		&& (bus->drv_cc.status & (1 << 4)) != 0) { -+#ifdef CONFIG_BCMA_NFLASH -+		pr_info("found nand flash.\n"); -+		bus->drv_cc.flash_type = BCMA_NFLASH; -+#else -+		pr_info("NAND flash not supported.\n"); -+#endif -+		return; -+	} -+ - 	switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { - 	case BCMA_CC_FLASHT_STSER: - 	case BCMA_CC_FLASHT_ATSER: ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -537,4 +537,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 -+	select MTD_PARTITIONS -+	help -+	  Support for bcm47xx nand flash -+ - endif # MTD_NAND ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mp - obj-$(CONFIG_MTD_NAND_RICOH)		+= r852.o - obj-$(CONFIG_MTD_NAND_JZ4740)		+= jz4740_nand.o - obj-$(CONFIG_MTD_NAND_GPMI_NAND)	+= gpmi-nand/ -+obj-$(CONFIG_MTD_NAND_BCM47XX)		+= bcm47xx_nand.o -  - nand-objs := nand_base.o nand_bbt.o ---- /dev/null -+++ b/drivers/mtd/nand/bcm47xx_nand.c -@@ -0,0 +1,506 @@ -+/* -+ * BCMA nand flash interface -+ * -+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -+ * Copyright 2010, Broadcom Corporation -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ */ -+ -+#define pr_fmt(fmt) "bcm47xx_nflash: " fmt -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/ioport.h> -+#include <linux/sched.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <linux/errno.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <bcm47xx.h> -+#include <bus.h> -+#include <linux/cramfs_fs.h> -+#include <linux/romfs_fs.h> -+#include <linux/magic.h> -+#include <linux/byteorder/generic.h> -+#include <linux/mtd/bcm47xx_nand.h> -+#include <linux/mtd/nand.h> -+ -+static int bcm47xx_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip); -+static int bcm47xx_erase(struct mtd_info *mtd, unsigned int addr, unsigned int len); -+ -+/* Private Global variable */ -+static u32 read_offset = 0; -+static u32 write_offset; -+ -+static int -+nflash_mtd_poll(struct bcm47xx_nflash *nflash, unsigned int offset, int timeout) -+{ -+	unsigned long now = jiffies; -+	int ret = 0; -+ -+	for (;;) { -+		if (!bcma_nflash_poll(nflash->bcc)) { -+			ret = 0; -+			break; -+		} -+		if (time_after(jiffies, now + timeout)) { -+			pr_err("timeout while polling\n"); -+			ret = -ETIMEDOUT; -+			break; -+		} -+		udelay(1); -+	} -+ -+	return ret; -+} -+ -+static int -+bcm47xx_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -+{ -+	struct nand_chip *nchip = (struct nand_chip *)mtd->priv; -+	struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; -+	int bytes, ret = 0; -+	u32 extra = 0; -+	u8 *tmpbuf = NULL; -+	int size; -+	u32 offset, blocksize, mask, off; -+	u32 skip_bytes = 0; -+	int need_copy = 0; -+	u8 *ptr = NULL; -+ -+	/* Check address range */ -+	if (!len) -+		return 0; -+	if ((from + len) > mtd->size) -+		return -EINVAL; -+	offset = from; -+	if ((offset & (NFL_SECTOR_SIZE - 1)) != 0) { -+		extra = offset & (NFL_SECTOR_SIZE - 1); -+		offset -= extra; -+		len += extra; -+		need_copy = 1; -+	} -+	size = (len + (NFL_SECTOR_SIZE - 1)) & ~(NFL_SECTOR_SIZE - 1); -+	if (size != len) { -+		need_copy = 1; -+	} -+	if (!need_copy) { -+		ptr = buf; -+	} else { -+		tmpbuf = (u8 *)kmalloc(size, GFP_KERNEL); -+		ptr = tmpbuf; -+	} -+ -+	blocksize = mtd->erasesize; -+	mask = blocksize - 1; -+	*retlen = 0; -+	while (len > 0) { -+		off = offset + skip_bytes; -+		if ((bytes = bcma_nflash_read(nflash->bcc, off, NFL_SECTOR_SIZE, ptr)) < 0) { -+			ret = bytes; -+			goto done; -+		} -+		if (bytes > len) -+			bytes = len; -+		offset += bytes; -+		len -= bytes; -+		ptr += bytes; -+		*retlen += bytes; -+	} -+ -+done: -+	if (tmpbuf) { -+		*retlen -= extra; -+		memcpy(buf, tmpbuf+extra, *retlen); -+		kfree(tmpbuf); -+	} -+ -+	return ret; -+} -+ -+static void bcm47xx_write(struct mtd_info *mtd, u32 to, const u_char *buf, u32 len) -+{ -+	struct nand_chip *nchip = (struct nand_chip *)mtd->priv; -+	struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; -+	u32 offset, blocksize, mask, off; -+	int read_len; -+	u32 copy_len, write_len, from; -+	u_char *write_ptr, *block; -+	const u_char *ptr; -+	int ret, bytes; -+ -+	/* Check address range */ -+	if (!len) { -+		pr_err("Error: Attempted to write too small data\n"); -+		return; -+	} -+ -+	if (!to) -+		return; -+ -+	if ((to + len) > mtd->size) { -+		pr_err("Error: Attempted to write too large data\n"); -+		return; -+	} -+ -+	ptr = buf; -+	block = NULL; -+	offset = to; -+	blocksize = mtd->erasesize; -+	if (!(block = kmalloc(blocksize, GFP_KERNEL))) -+		return; -+	mask = blocksize - 1; -+	while (len) { -+		/* Align offset */ -+		from = offset & ~mask; -+		/* Copy existing data into holding block if necessary */ -+		if (((offset & (blocksize-1)) != 0) || (len < blocksize)) { -+			if ((ret = bcm47xx_read(mtd, from, blocksize, &read_len, block))) -+				goto done; -+			if (read_len != blocksize) { -+				ret = -EINVAL; -+				goto done; -+			} -+		} -+ -+		/* Copy input data into holding block */ -+		copy_len = min(len, blocksize - (offset & mask)); -+		memcpy(block + (offset & mask), ptr, copy_len); -+		off = (uint) from; -+		/* Erase block */ -+		if ((ret = bcm47xx_erase(mtd, off, blocksize)) < 0) -+			goto done; -+		/* Write holding block */ -+		write_ptr = block; -+		write_len = blocksize; -+		if ((bytes = bcma_nflash_write(nflash->bcc, (uint)from, (uint)write_len, (u8 *) write_ptr)) != 0) { -+			ret = bytes; -+			goto done; -+		} -+		offset += copy_len; -+		if (len < copy_len) -+			len = 0; -+		else -+			len -= copy_len; -+		ptr += copy_len; -+	} -+ -+done: -+	if (block) -+		kfree(block); -+	return; -+} -+ -+static int bcm47xx_erase(struct mtd_info *mtd, unsigned int addr, unsigned int len) -+{ -+	struct nand_chip *nchip = (struct nand_chip *)mtd->priv; -+	struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; -+ -+	/* Check address range */ -+	if (!len) -+		return 1; -+	if ((addr + len) > mtd->size) -+		return 1; -+ -+	if (bcma_nflash_erase(nflash->bcc, addr)) { -+		pr_err("ERASE: nflash erase error\n"); -+		return 1; -+	} -+ -+	if (nflash_mtd_poll(nflash, addr, 10 * HZ)) { -+		pr_err("ERASE: nflash_mtd_poll error\n"); -+		return 1; -+	} -+ -+	return 0; -+} -+ -+/* This functions is used by upper layer to checks if device is ready */ -+static int bcm47xx_dev_ready(struct mtd_info *mtd) -+{ -+	return 1; -+} -+ -+/* Issue a nand flash command */ -+static inline void bcm47xx_nflash_cmd(struct bcma_drv_cc *cc, u32 opcode) -+{ -+	bcma_cc_write32(cc, NAND_CMD_START, opcode); -+	bcma_cc_read32(cc,  NAND_CMD_START); -+} -+ -+static void bcm47xx_command(struct mtd_info *mtd, unsigned command, -+				int column, int page_addr) -+{ -+	struct nand_chip *nchip = (struct nand_chip *)mtd->priv; -+	struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; -+	u32 pagesize = 1 << nchip->page_shift; -+ -+	/* Command pre-processing step */ -+	switch (command) { -+	case NAND_CMD_RESET: -+		bcm47xx_nflash_cmd(nflash->bcc, NCMD_FLASH_RESET); -+		break; -+ -+	case NAND_CMD_STATUS: -+		nflash->next_opcode = NAND_CMD_STATUS; -+		read_offset = 0; -+		write_offset = 0; -+		break; -+ -+	case NAND_CMD_READ0: -+		read_offset = page_addr * pagesize; -+		nflash->next_opcode = 0; -+		break; -+ -+	case NAND_CMD_READOOB: -+		read_offset = page_addr * pagesize; -+		nflash->next_opcode = 0; -+		break; -+ -+	case NAND_CMD_SEQIN: -+		write_offset = page_addr * pagesize; -+		nflash->next_opcode = 0; -+		break; -+ -+	case NAND_CMD_PAGEPROG: -+		nflash->next_opcode = 0; -+		break; -+ -+	case NAND_CMD_READID: -+		read_offset = column; -+		bcm47xx_nflash_cmd(nflash->bcc, NCMD_ID_RD); -+		nflash->next_opcode = NAND_DEVID; -+		break; -+ -+	case NAND_CMD_ERASE1: -+		nflash->next_opcode = 0; -+		bcm47xx_erase(mtd, page_addr*pagesize, pagesize); -+		break; -+ -+	case NAND_CMD_ERASE2: -+		break; -+ -+	case NAND_CMD_RNDOUT: -+		if (column > mtd->writesize) -+			read_offset += (column - mtd->writesize); -+		else -+			read_offset += column; -+		break; -+ -+	default: -+		pr_err("COMMAND not supported %x\n", command); -+		nflash->next_opcode = 0; -+		break; -+	} -+} -+ -+/* This function is used by upper layer for select and -+ * deselect of the NAND chip. -+ * It is dummy function. */ -+static void bcm47xx_select_chip(struct mtd_info *mtd, int chip) -+{ -+} -+ -+static u_char bcm47xx_read_byte(struct mtd_info *mtd) -+{ -+	struct nand_chip *nchip = mtd->priv; -+	struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; -+	uint8_t ret = 0; -+	static u32 id; -+ -+	if (nflash->next_opcode == 0) -+		return ret; -+ -+	if (nflash->next_opcode == NAND_CMD_STATUS) -+		return NAND_STATUS_WP; -+ -+	id = bcma_cc_read32(nflash->bcc, nflash->next_opcode); -+ -+	if (nflash->next_opcode == NAND_DEVID) { -+		ret = (id >> (8*read_offset)) & 0xff; -+		read_offset++; -+	} -+ -+	return ret; -+} -+ -+static uint16_t bcm47xx_read_word(struct mtd_info *mtd) -+{ -+	loff_t from = read_offset; -+	uint16_t buf = 0; -+	int bytes; -+ -+	bcm47xx_read(mtd, from, sizeof(buf), &bytes, (u_char *)&buf); -+	return buf; -+} -+ -+/* Write data of length len to buffer buf. The data to be -+ * written on NAND Flash is first copied to RAMbuffer. After the Data Input -+ * Operation by the NFC, the data is written to NAND Flash */ -+static void bcm47xx_write_buf(struct mtd_info *mtd, -+				const u_char *buf, int len) -+{ -+	bcm47xx_write(mtd, write_offset, buf, len); -+} -+ -+/* Read the data buffer from the NAND Flash. To read the data from NAND -+ * Flash first the data output cycle is initiated by the NFC, which copies -+ * the data to RAMbuffer. This data of length len is then copied to buffer buf. -+ */ -+static void bcm47xx_read_buf(struct mtd_info *mtd, u_char *buf, int len) -+{ -+	loff_t from = read_offset; -+	int bytes; -+ -+	bcm47xx_read(mtd, from, len, &bytes, buf); -+} -+ -+/* Used by the upper layer to verify the data in NAND Flash -+ * with the data in the buf. */ -+static int bcm47xx_verify_buf(struct mtd_info *mtd, -+				const u_char *buf, int len) -+{ -+	return -EFAULT; -+} -+ -+static int bcm47xx_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) -+{ -+	struct nand_chip *nchip = mtd->priv; -+	struct bcm47xx_nflash *nflash = (struct bcm47xx_nflash *)nchip->priv; -+	int i; -+	uint off; -+	u32 pagesize = 1 << nchip->page_shift; -+	u32 blocksize = mtd->erasesize; -+ -+	if ((ofs >> 20) >= nflash->size) -+		return 1; -+	if ((ofs & (blocksize - 1)) != 0) -+		return 1; -+ -+	for (i = 0; i < 2; i++) { -+		off = ofs + pagesize; -+		bcma_cc_write32(nflash->bcc, NAND_CMD_ADDR, off); -+		bcm47xx_nflash_cmd(nflash->bcc, NCMD_SPARE_RD); -+		if (bcma_nflash_poll(nflash->bcc) < 0) -+			break; -+		if ((bcma_cc_read32(nflash->bcc, NAND_INTFC_STATUS) & NIST_SPARE_VALID) != NIST_SPARE_VALID) -+			return 1; -+		if ((bcma_cc_read32(nflash->bcc, NAND_SPARE_RD0) & 0xff) != 0xff) -+			return 1; -+	} -+	return 0; -+} -+ -+const char *part_probes[] = { "cmdlinepart", NULL }; -+static int bcm47xx_probe(struct platform_device *pdev) -+{ -+	struct nand_chip *nchip; -+	struct mtd_info *mtd; -+	struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev); -+	int ret = 0; -+ -+	mtd = &nflash->mtd; -+	nchip = &nflash->nand; -+ -+	/* Register with MTD */ -+	mtd->priv = nchip; -+	mtd->owner = THIS_MODULE; -+	mtd->dev.parent = &pdev->dev; -+ -+	/* 50 us command delay time */ -+	nchip->chip_delay = 50; -+ -+	nchip->priv = nflash; -+	nchip->dev_ready = bcm47xx_dev_ready; -+	nchip->cmdfunc = bcm47xx_command; -+	nchip->select_chip = bcm47xx_select_chip; -+	nchip->read_byte = bcm47xx_read_byte; -+	nchip->read_word = bcm47xx_read_word; -+	nchip->write_buf = bcm47xx_write_buf; -+	nchip->read_buf = bcm47xx_read_buf; -+	nchip->verify_buf = bcm47xx_verify_buf; -+	nchip->block_bad = bcm47xx_block_bad; -+	nchip->options = NAND_SKIP_BBTSCAN; -+ -+	/* Not known */ -+	nchip->ecc.mode = NAND_ECC_NONE; -+ -+	/* first scan to find the device and get the page size */ -+	if (nand_scan_ident(mtd, 1, NULL)) { -+		pr_err("nand_scan_ident failed\n"); -+		ret = -ENXIO; -+		goto done; -+	} -+	nflash->bcc->nflash.size = mtd->size; -+	nflash->bcc->nflash.pagesize = 1 << nchip->page_shift; -+	nflash->bcc->nflash.blocksize = mtd->erasesize; -+	bcm47xx_nflash.size = mtd->size; -+ -+	/* second phase scan */ -+	if (nand_scan_tail(mtd)) { -+		pr_err("nand_scan_tail failed\n"); -+		ret = -ENXIO; -+		goto done; -+	} -+ -+	mtd->name = "bcm47xx-nflash"; -+	mtd->flags |= MTD_WRITEABLE; -+	ret = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0); -+ -+	if (ret) { -+		pr_err("mtd_device_register failed\n"); -+		return ret; -+	} -+ -+	return 0; -+ -+done: -+	return ret; -+} -+ -+static int __devexit bcm47xx_remove(struct platform_device *pdev) -+{ -+	struct bcm47xx_nflash *nflash = dev_get_platdata(&pdev->dev); -+	struct mtd_info *mtd = &nflash->mtd; -+ -+	if (nflash) { -+		/* Release resources, unregister device */ -+		nand_release(mtd); -+	} -+ -+	return 0; -+} -+ -+static struct platform_driver bcm47xx_driver = { -+	.remove = __devexit_p(bcm47xx_remove), -+	.driver = { -+		.name = "bcm47xx_nflash", -+		.owner = THIS_MODULE, -+	}, -+}; -+ -+static int __init init_bcm47xx_nflash(void) -+{ -+	int ret = platform_driver_probe(&bcm47xx_driver, bcm47xx_probe); -+ -+	if (ret) -+		pr_err("error registering platform driver: %i\n", ret); -+	return ret; -+} -+ -+static void __exit exit_bcm47xx_nflash(void) -+{ -+	platform_driver_unregister(&bcm47xx_driver); -+} -+ -+module_init(init_bcm47xx_nflash); -+module_exit(exit_bcm47xx_nflash); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("BCM47XX NAND flash driver"); ---- a/include/linux/bcma/bcma_driver_chipcommon.h -+++ b/include/linux/bcma/bcma_driver_chipcommon.h -@@ -400,6 +400,7 @@ struct bcma_chipcommon_pmu { - enum bcma_flash_type { - 	BCMA_PFLASH, - 	BCMA_SFLASH, -+	BCMA_NFLASH, - }; -  - struct bcma_pflash { -@@ -416,6 +417,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; -@@ -441,6 +450,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; -@@ -505,4 +517,13 @@ int bcma_sflash_write(struct bcma_drv_cc - int bcma_sflash_erase(struct bcma_drv_cc *cc, u32 offset); - #endif /* CONFIG_BCMA_SFLASH */ -  -+#ifdef CONFIG_BCMA_NFLASH -+/* Chipcommon nflash support. */ -+int bcma_nflash_read(struct bcma_drv_cc *cc, u32 offset, u32 len, u8 *buf); -+int bcma_nflash_poll(struct bcma_drv_cc *cc); -+int bcma_nflash_write(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf); -+int bcma_nflash_erase(struct bcma_drv_cc *cc, u32 offset); -+int bcma_nflash_commit(struct bcma_drv_cc *cc, u32 offset, u32 len, const u8 *buf); -+#endif -+ - #endif /* LINUX_BCMA_DRIVER_CC_H_ */ ---- /dev/null -+++ b/include/linux/mtd/bcm47xx_nand.h -@@ -0,0 +1,134 @@ -+/* -+ * Broadcom chipcommon NAND flash interface -+ * -+ * Copyright (C) 2011-2012 Tathagata Das <tathagata@alumnux.com> -+ * Copyright (C) 2009, Broadcom Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ */ -+ -+#ifndef _nflash_h_ -+#define _nflash_h_ -+ -+#define  NAND_FLASH1						0x1fc00000  /* MIPS Flash Region 1 */ -+ -+/* nand_cmd_start commands */ -+#define	NCMD_NULL						0 -+#define	NCMD_PAGE_RD					1 -+#define	NCMD_SPARE_RD					2 -+#define	NCMD_STATUS_RD					3 -+#define	NCMD_PAGE_PROG					4 -+#define	NCMD_SPARE_PROG				5 -+#define	NCMD_COPY_BACK					6 -+#define	NCMD_ID_RD						7 -+#define	NCMD_BLOCK_ERASE				8 -+#define	NCMD_FLASH_RESET				9 -+#define	NCMD_LOCK						0xa -+#define	NCMD_LOCK_DOWN					0xb -+#define	NCMD_UNLOCK						0xc -+#define	NCMD_LOCK_STATUS				0xd -+ -+/* nand_acc_control */ -+#define	NAC_RD_ECC_EN					0x80000000 -+#define	NAC_WR_ECC_EN					0x40000000 -+#define	NAC_RD_ECC_BLK0_EN			0x20000000 -+#define	NAC_FAST_PGM_RDIN				0x10000000 -+#define	NAC_RD_ERASED_ECC_EN			0x08000000 -+#define	NAC_PARTIAL_PAGE_EN			0x04000000 -+#define	NAC_PAGE_HIT_EN				0x01000000 -+#define	NAC_ECC_LEVEL0					0x00f00000 -+#define	NAC_ECC_LEVEL					0x000f0000 -+#define	NAC_SPARE_SIZE0				0x00003f00 -+#define	NAC_SPARE_SIZE					0x0000003f -+ -+/* nand_config */ -+#define	NCF_CONFIG_LOCK				0x80000000 -+#define	NCF_BLOCK_SIZE_MASK			0x70000000 -+#define	NCF_BLOCK_SIZE_SHIFT			28 -+#define	NCF_DEVICE_SIZE_MASK			0x0f000000 -+#define	NCF_DEVICE_SIZE_SHIFT		24 -+#define	NCF_DEVICE_WIDTH				0x00800000 -+#define	NCF_PAGE_SIZE_MASK			0x00300000 -+#define	NCF_PAGE_SIZE_SHIFT			20 -+#define	NCF_FULL_ADDR_BYTES_MASK	0x00070000 -+#define	NCF_FULL_ADDR_BYTES_SHIFT	16 -+#define	NCF_COL_ADDR_BYTES_MASK		0x00007000 -+#define	NCF_COL_ADDR_BYTES_SHIFT	12 -+#define	NCF_BLK_ADDR_BYTES_MASK		0x00000700 -+#define	NCF_BLK_ADDR_BYTES_SHIFT	8 -+ -+/* nand_intfc_status */ -+#define	NIST_CTRL_READY				0x80000000 -+#define	NIST_FLASH_READY				0x40000000 -+#define	NIST_CACHE_VALID				0x20000000 -+#define	NIST_SPARE_VALID				0x10000000 -+#define	NIST_ERASED						0x08000000 -+#define	NIST_STATUS						0x000000ff -+ -+#define	NFL_SECTOR_SIZE				512 -+ -+#define	NFL_TABLE_END					0xffffffff -+#define	NFL_BOOT_SIZE					0x200000 -+#define	NFL_BOOT_OS_SIZE				0x2000000 -+ -+/* Nand flash MLC controller registers (corerev >= 38) */ -+#define	NAND_REVISION					0xC00 -+#define	NAND_CMD_START					0xC04 -+#define	NAND_CMD_ADDR_X				0xC08 -+#define	NAND_CMD_ADDR					0xC0C -+#define	NAND_CMD_END_ADDR				0xC10 -+#define	NAND_CS_NAND_SELECT			0xC14 -+#define	NAND_CS_NAND_XOR				0xC18 -+#define	NAND_SPARE_RD0					0xC20 -+#define	NAND_SPARE_RD4					0xC24 -+#define	NAND_SPARE_RD8					0xC28 -+#define	NAND_SPARE_RD12				0xC2C -+#define	NAND_SPARE_WR0					0xC30 -+#define	NAND_SPARE_WR4					0xC34 -+#define	NAND_SPARE_WR8					0xC38 -+#define	NAND_SPARE_WR12				0xC3C -+#define	NAND_ACC_CONTROL				0xC40 -+#define	NAND_CONFIG						0xC48 -+#define	NAND_TIMING_1					0xC50 -+#define	NAND_TIMING_2					0xC54 -+#define	NAND_SEMAPHORE					0xC58 -+#define	NAND_DEVID						0xC60 -+#define	NAND_DEVID_X					0xC64 -+#define	NAND_BLOCK_LOCK_STATUS		0xC68 -+#define	NAND_INTFC_STATUS				0xC6C -+#define	NAND_ECC_CORR_ADDR_X			0xC70 -+#define	NAND_ECC_CORR_ADDR			0xC74 -+#define	NAND_ECC_UNC_ADDR_X			0xC78 -+#define	NAND_ECC_UNC_ADDR				0xC7C -+#define	NAND_READ_ERROR_COUNT		0xC80 -+#define	NAND_CORR_STAT_THRESHOLD	0xC84 -+#define	NAND_READ_ADDR_X				0xC90 -+#define	NAND_READ_ADDR					0xC94 -+#define	NAND_PAGE_PROGRAM_ADDR_X	0xC98 -+#define	NAND_PAGE_PROGRAM_ADDR		0xC9C -+#define	NAND_COPY_BACK_ADDR_X		0xCA0 -+#define	NAND_COPY_BACK_ADDR			0xCA4 -+#define	NAND_BLOCK_ERASE_ADDR_X		0xCA8 -+#define	NAND_BLOCK_ERASE_ADDR		0xCAC -+#define	NAND_INV_READ_ADDR_X			0xCB0 -+#define	NAND_INV_READ_ADDR			0xCB4 -+#define	NAND_BLK_WR_PROTECT			0xCC0 -+#define	NAND_ACC_CONTROL_CS1			0xCD0 -+#define	NAND_CONFIG_CS1				0xCD4 -+#define	NAND_TIMING_1_CS1				0xCD8 -+#define	NAND_TIMING_2_CS1				0xCDC -+#define	NAND_SPARE_RD16				0xD30 -+#define	NAND_SPARE_RD20				0xD34 -+#define	NAND_SPARE_RD24				0xD38 -+#define	NAND_SPARE_RD28				0xD3C -+#define	NAND_CACHE_ADDR				0xD40 -+#define	NAND_CACHE_DATA				0xD44 -+#define	NAND_CTRL_CONFIG				0xD48 -+#define	NAND_CTRL_STATUS				0xD4C -+ -+#endif /* _nflash_h_ */  | 
