Search Linux Wireless

[PATCH] bcma: add basic NAND flash driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is basic driver for NAND flash memory that allows reading it's
content. It was succesfully tested on Netgear WNDR4500 which is BCM4706
based router.

This driver has been written using specs at:
http://bcm-v4.sipsolutions.net/NAND_Flash

Signed-off-by: Rafał Miłecki <zajec5@xxxxxxxxx>
CC: Larry Finger <Larry.Finger@xxxxxxxxxxxx>
CC: Hauke Mehrtens <hauke@xxxxxxxxxx>
---
John: I think I've heard somewhere that new drivers can go into
currently developed release, skipping -next. Not sure if this is
correct [at all/still]. Please grab this patch to the tree you find
the best for it.

I've tested this patch by reading SQUASHFS header MAGIC from NAND flash
with the following code:

u8 tmpbuf[512];
int ret = bcma_nflash_read(cc, 0x141400, 512, tmpbuf);
if (ret != 512)
	pr_err("[ERR] NFLASH read failed. Function returned: %d\n", ret);
for (i = 0x120; i < 0x124; i++)
	pr_info("tmpbuf[%02d]: 0x%X\n", i, tmpbuf[i]);

(yeah, I had to figure out 0x141400 offset first).
---
 drivers/bcma/Kconfig                        |    4 +-
 drivers/bcma/bcma_private.h                 |    2 +-
 drivers/bcma/driver_chipcommon_nflash.c     |  377 ++++++++++++++++++++++++++-
 drivers/bcma/driver_chipcommon_pmu.c        |    2 +-
 include/linux/bcma/bcma_driver_chipcommon.h |   88 +++++++
 5 files changed, 466 insertions(+), 7 deletions(-)

diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 8d1f777..a58d7a9 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -53,8 +53,8 @@ config BCMA_SFLASH
 	default y
 
 config BCMA_NFLASH
-	bool
-	depends on BCMA_DRIVER_MIPS && BROKEN
+	bool "Support for NAND flash"
+	depends on BCMA_DRIVER_MIPS
 	default y
 
 config BCMA_DRIVER_GMAC_CMN
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 3cf9cc9..9895c7e 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -68,7 +68,7 @@ int bcma_nflash_init(struct bcma_drv_cc *cc);
 #else
 static inline int bcma_nflash_init(struct bcma_drv_cc *cc)
 {
-	bcma_err(cc->core->bus, "NAND flash not supported\n");
+	bcma_err(cc->core->bus, "NAND flash support not enabled\n");
 	return 0;
 }
 #endif /* CONFIG_BCMA_NFLASH */
diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c
index 574d624..54c7d81 100644
--- a/drivers/bcma/driver_chipcommon_nflash.c
+++ b/drivers/bcma/driver_chipcommon_nflash.c
@@ -11,9 +11,380 @@
 
 #include "bcma_private.h"
 
-/* Initialize NAND flash access */
-int bcma_nflash_init(struct bcma_drv_cc *cc)
+/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
+ * shown 6 retries were enough. */
+#define NFLASH_READY_RETRIES		100
+
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static inline u8 bcma_nflash_ns_to_cycle(u16 ns, u16 clock)
+{
+	return ((ns * 1000 * clock) / 1000000) + 1;
+}
+
+static void bcma_nflash_enable(struct bcma_drv_cc *cc, bool enable)
+{
+	if (cc->core->id.rev == 38) {
+		if (cc->status & BCMA_CC_CHIPST_REV38_NAND_BOOT)
+			return;
+		if (enable)
+			bcma_chipco_chipctl_maskset(cc, 1, ~0, 0x10000);
+		else
+			bcma_chipco_chipctl_maskset(cc, 1, ~0x10000, 0);
+	}
+}
+
+static int bcma_nflash_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
 {
-	bcma_err(cc->core->bus, "NAND flash support is broken\n");
+	int i = 0;
+
+	bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, 0x80000000 | code);
+	for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+		if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & 0x80000000)) {
+			i = 0;
+			break;
+		}
+	}
+	if (i) {
+		pr_err("NFLASH control command not ready!\n");
+		return -EBUSY;
+	}
 	return 0;
 }
+
+int bcma_nflash_poll(struct bcma_drv_cc *cc)
+{
+	int i;
+	u32 tmp;
+
+	if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+		for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+			if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
+			    0x04000000) {
+				if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
+				    BCMA_CC_NFLASH_CTL_ERR) {
+					pr_err("Error on polling\n");
+					return -EBUSY;
+				} else {
+					return 0;
+				}
+			}
+		}
+	} else {
+		for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+			tmp = bcma_cc_read32(cc, BCMA_CC_NAND_INTFC_STATUS);
+			if ((tmp & 0xC0000000) == 0xC0000000)
+				return 0;
+		}
+	}
+	pr_err("Polling timeout!\n");
+	return -EBUSY;
+}
+
+static void bcma_nflash_cmd(struct bcma_drv_cc *cc, u32 code)
+{
+	bcma_cc_write32(cc, BCMA_CC_NAND_CMD_START, code);
+	bcma_cc_read32(cc, BCMA_CC_NAND_CMD_START);
+}
+
+static char *bcma_nflash_check_id(u8 *id)
+{
+	switch (id[0]) {
+	case 0x01:
+		return "AMD";
+	case 0x20:
+		return "Numonyx";
+	case 0x2c:
+		return "Micron";
+	case 0x98:
+		return "Toshiba";
+	case 0xad:
+		return "Hynix";
+	case 0xec:
+		return "Samsung";
+	}
+	return NULL;
+}
+
+/**************************************************
+ * Initialize NAND flash access
+ **************************************************/
+
+static int bcma_nflash_init_bcm4706(struct bcma_drv_cc *cc)
+{
+	struct bcma_nflash *nflash = &cc->nflash;
+
+	u32 freq, code, val, tmp;
+	u16 clock;
+	u8 w0, w1, w2, w3, w4;
+	u8 cbits, tbits;
+	u8 csize, rbits, bsize;
+	char *name;
+	int i;
+
+	/* TODO: Set bit 0x8 in CC flashstrconfig Register */
+
+	if (cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
+		freq = 100000000;
+	} else {
+		freq = bcma_chipco_pll_read(cc, 4);
+		freq = (freq * 0xFFF) >> 3;
+		freq = (freq * 25000000) >> 3;
+	}
+	clock = freq / 1000000;
+	w0 = bcma_nflash_ns_to_cycle(15, clock);
+	w1 = bcma_nflash_ns_to_cycle(20, clock);
+	w2 = bcma_nflash_ns_to_cycle(10, clock);
+	w3 = bcma_nflash_ns_to_cycle(10, clock);
+	w4 = bcma_nflash_ns_to_cycle(100, clock);
+	bcma_cc_write32(cc, BCMA_CC_NFLASH_WAITCNT0,
+		(w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
+	if (bcma_nflash_ctl_cmd(cc, 0x40000000 | 0x01000000 | 0x00080000 |
+				    0x00010000 | 0x00000090))
+		return -EBUSY;
+
+	for (i = 0; i < 5; i++) {
+		/* Useless Broadcom condition dropped */
+		code = 0x40000000 | 0x00100000;
+		if (bcma_nflash_ctl_cmd(cc, code))
+			return -EBUSY;
+		else
+			nflash->id[i] =
+				bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xFF;
+	}
+
+	name = bcma_nflash_check_id(nflash->id);
+	if (name == NULL) {
+		pr_err("Invalid flash id: 0x%X\n", nflash->id[0]);
+		/* TODO: Clear bit 8 of Register flashstrconfig */
+		return -ENOTSUPP;
+	}
+
+	nflash->type = nflash->id[0];
+	nflash->pagesize = 1024 << (nflash->id[3] & 0x3);
+	nflash->blocksize = (64 * 1024) << ((nflash->id[3] >> 4) & 0x3);
+	tmp = (8 << ((nflash->id[3] >> 2) & 0x1));
+	nflash->oobsize = tmp * nflash->pagesize / 512;
+	nflash->size = (8 << ((nflash->id[4] >> 4) & 0x7)) *
+		       (1 << ((nflash->id[4] >> 2) & 0x3));
+
+	tbits = ffs(nflash->size); /* find first bit set */
+	if (!tbits || tbits != fls(nflash->size)) {
+		pr_err("Invalid flash size 0x%X\n", nflash->size);
+		return -ENOTSUPP;
+	}
+	tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
+
+	cbits = ffs(nflash->pagesize);
+	if (!cbits || cbits != fls(nflash->pagesize)) {
+		pr_err("Invalid flash pagesize 0x%X\n", nflash->pagesize);
+		return -ENOTSUPP;
+	}
+
+	nflash->col_mask = (1 << cbits) - 1;
+	nflash->row_shift = cbits;
+	csize = (cbits + 7) / 8;
+	rbits = tbits - cbits + 1;
+	bsize = (rbits + 7) / 8;
+	val = ((bsize - 1) << 6) | ((csize - 1) << 4) | 2;
+	bcma_cc_write32(cc, BCMA_CC_NFLASH_CONF, val);
+
+	pr_info("Found %s %dMiB NAND flash, pagesize: %dB, blocksize: %dKiB\n",
+		name, nflash->size, nflash->pagesize, nflash->blocksize / 1024);
+	nflash->present = true;
+	return 0;
+}
+
+static int bcma_nflash_init_default(struct bcma_drv_cc *cc)
+{
+	struct bcma_nflash *nflash = &cc->nflash;
+	u32 id, id2, ncfg, control, val;
+	char *name;
+	int i;
+
+	bcma_nflash_enable(cc, true);
+	bcma_nflash_cmd(cc, 7);
+	if (bcma_nflash_poll(cc) < 0) {
+		bcma_nflash_enable(cc, false);
+		return -EBUSY;
+	}
+	bcma_nflash_enable(cc, false);
+
+	id = bcma_cc_read32(cc, BCMA_CC_NAND_DEVID);
+	id2 = bcma_cc_read32(cc, BCMA_CC_NAND_DEVID_X);
+	for (i = 0; i < 5; i++) {
+		if (i < 4)
+			nflash->id[i] = (id >> (8 * i)) & 0xff;
+		else
+			nflash->id[i] = id2 & 0xff;
+	}
+
+	name = bcma_nflash_check_id(nflash->id);
+	if (name == NULL) {
+		pr_err("Invalid flash id: 0x%X\n", nflash->id[0]);
+		return -ENOTSUPP;
+	}
+
+	nflash->type = nflash->id[0];
+
+	ncfg = bcma_cc_read32(cc, BCMA_CC_NAND_CONFIG);
+	switch ((ncfg >> 20) & 3) {
+	case 0:
+		nflash->pagesize = 0x200;
+		break;
+	case 1:
+		nflash->pagesize = 0x800;
+		break;
+	case 2:
+		nflash->pagesize = 0x1000;
+		break;
+	default:
+		nflash->pagesize = 0x2000;
+		break;
+	}
+	val = (ncfg >> 28) & 7;
+	switch (val) {
+	case 0:
+		nflash->blocksize = 0x4000;
+		break;
+	case 1:
+		nflash->blocksize = 0x20000;
+		break;
+	case 2:
+		nflash->blocksize = 0x2000;
+		break;
+	case 3:
+		nflash->blocksize = 0x80000;
+		break;
+	case 4:
+		nflash->blocksize = 0x40000;
+		break;
+	default:
+		nflash->blocksize = 0;
+		pr_err("Unknown blocksize\n");
+		return -ENOTSUPP;
+	}
+	nflash->size = (1 << (val - 1)) * 8;
+
+	control = bcma_cc_read32(cc, BCMA_CC_NAND_ACC_CONTROL);
+	nflash->ecclevel = (control & 0x000f0000) >> 16;
+	nflash->ecclevel0 = (control & 0x00f00000) >> 20;
+	if (nflash->ecclevel != nflash->ecclevel0) {
+		control = control & ~(0x00ff0000);
+		control = control | (nflash->ecclevel0 << 20) |
+				(nflash->ecclevel0 << 16);
+		bcma_cc_write32(cc, BCMA_CC_NAND_ACC_CONTROL, control);
+		nflash->ecclevel = nflash->ecclevel0;
+	}
+	nflash->numblocks = (nflash->size * (1 << 10)) /
+			    (nflash->blocksize >> 10);
+	if (nflash->size == 0) {
+		pr_err("Invalid flash size\n");
+		return -ENOTSUPP;
+	}
+
+	pr_info("Found %s %dMiB NAND flash, pagesize: %dB, blocksize: %dKiB\n",
+		name, nflash->size, nflash->pagesize, nflash->blocksize / 1024);
+	nflash->present = true;
+	return 0;
+}
+
+int bcma_nflash_init(struct bcma_drv_cc *cc)
+{
+	if (cc->core->bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
+	    cc->core->id.rev != 0x38) {
+		pr_err("NAND flash on unsupported board!\n");
+		return -ENOTSUPP;
+	}
+
+	if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) {
+		pr_err("NAND flash not present according to ChipCommon\n");
+		return -ENODEV;
+	}
+
+	if (cc->nflash.present) {
+		pr_warn("NAND flash already initialized");
+		return 0;
+	}
+
+	if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
+		return bcma_nflash_init_bcm4706(cc);
+	else
+		return bcma_nflash_init_default(cc);
+}
+
+/**************************************************
+ * R/W ops
+ **************************************************/
+
+int bcma_nflash_read(struct bcma_drv_cc *cc, uint offset, uint len, u8 *buf)
+{
+	struct bcma_nflash *nflash = &cc->nflash;
+	u32 mask = 0x1FF;
+	u32 tmp, ctrlcode;
+	u32 page_offset, page_addr;
+	u32 *dest = (u32 *)buf;
+	uint remains;
+	int i;
+
+	if ((offset & mask) != 0 || (len & mask) != 0)
+		return 0;
+
+	tmp = (offset + len) >> 20;
+	if (tmp > nflash->size)
+		return 0;
+	if (tmp == nflash->size && ((offset + len) & ((1 << 20) - 1)) != 0)
+		return 0;
+
+	remains = len;
+	if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+		while (remains > 0) {
+			page_offset = offset & (nflash->pagesize - 1);
+			page_addr = (offset & ~(nflash->pagesize - 1)) *
+				    2 + page_offset;
+			bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
+					page_addr & nflash->col_mask);
+			bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+					page_addr >> nflash->row_shift);
+
+			ctrlcode = 0x40000000 | 0x00080000 | 0x00040000 |
+				   0x00020000 | 0x00010000 | 0x3000;
+			if (bcma_nflash_ctl_cmd(cc, ctrlcode))
+				break;
+			if (bcma_nflash_poll(cc) < 0)
+				break;
+			for (i = 0; i < 512; i += 4, dest++) {
+				if (i < 508)
+					ctrlcode = 0x40000000 | 0x30000000 |
+						   0x00100000;
+				else
+					ctrlcode = 0x30000000 | 0x00100000;
+				if (bcma_nflash_ctl_cmd(cc, ctrlcode))
+					return len - remains;
+				*dest = bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA);
+			}
+			remains -= 512;
+			offset += 512;
+		}
+	} else {
+		bcma_nflash_enable(cc, true);
+		while (remains > 0) {
+			bcma_cc_write32(cc, BCMA_CC_NAND_CMD_ADDR, offset);
+			bcma_nflash_cmd(cc, 1);
+			if (bcma_nflash_poll(cc) < 0)
+				break;
+			if (!(bcma_cc_read32(cc, BCMA_CC_NAND_INTFC_STATUS) &
+			      0x20000000))
+				break;
+			for (i = 0; i < 512; i += 4, dest++)
+				*dest = bcma_cc_read32(cc,
+						       BCMA_CC_NAND_CACHE_DATA);
+			remains -= 512;
+			offset += 512;
+		}
+		bcma_nflash_enable(cc, false);
+	}
+	return len - remains;
+}
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 4432617..fd6620e 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -13,7 +13,7 @@
 #include <linux/export.h>
 #include <linux/bcma/bcma.h>
 
-static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 {
 	bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
 	bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 3c80885..c80d8f1 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -94,6 +94,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_REV38_NAND_BOOT		BIT(4) /* NAND boot, valid for CC rev 38 */
 #define BCMA_CC_JCMD			0x0030		/* Rev >= 10 only */
 #define  BCMA_CC_JCMD_START		0x80000000
 #define  BCMA_CC_JCMD_BUSY		0x80000000
@@ -260,6 +261,14 @@
 #define  BCMA_CC_SROM_CONTROL_SIZE_16K	0x00000004
 #define  BCMA_CC_SROM_CONTROL_SIZE_SHIFT	1
 #define  BCMA_CC_SROM_CONTROL_PRESENT	0x00000001
+/* 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
@@ -319,6 +328,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
@@ -424,6 +487,26 @@ struct bcma_pflash {
 	u32 window_size;
 };
 
+#ifdef CONFIG_BCMA_NFLASH
+struct bcma_nflash {
+	bool present;
+
+	uint blocksize; /* Block size */
+	uint pagesize; /* Page size */
+	uint oobsize; /* OOB size per page */
+	uint numblocks; /* Number of blocks */
+	u32 type; /* Type */
+	uint size; /* Total size */
+	u8 id[5];
+	uint ecclevel; /* ECC algorithm for blocks other than block 0 */
+	uint ecclevel0; /* ECC algorithm for blocks 0 */
+
+	/* BCM4706 specific */
+	u32 col_mask;
+	u32 row_shift;
+};
+#endif
+
 struct bcma_serial_port {
 	void *regs;
 	unsigned long clockspeed;
@@ -442,8 +525,12 @@ struct bcma_drv_cc {
 	/* 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_NFLASH
+	struct bcma_nflash nflash;
+#endif
 
 	int nr_serial_ports;
 	struct bcma_serial_port serial_ports[4];
@@ -488,6 +575,7 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
 /* PMU support */
 extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 
+u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset);
 extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
 				  u32 value);
 extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux