* [READY][PATCH 1/2] bcma: detect and register NAND flash device
@ 2012-08-12 11:08 Rafał Miłecki
2012-08-12 11:08 ` [BROKEN][PROOF][DONT APPLY][PATCH 2/2] bcm47nflash driver (WIP, BROKEN) Rafał Miłecki
2012-08-12 11:09 ` [READY][PATCH 1/2] bcma: detect and register NAND flash device Rafał Miłecki
0 siblings, 2 replies; 3+ messages in thread
From: Rafał Miłecki @ 2012-08-12 11:08 UTC (permalink / raw)
To: linux-wireless, John W. Linville
Cc: Hauke Mehrtens, Florian Fainelli, Rafał Miłecki
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
drivers/bcma/Kconfig | 2 +-
drivers/bcma/bcma_private.h | 1 +
drivers/bcma/driver_chipcommon_nflash.c | 28 ++++++++++++++++++++++++--
drivers/bcma/main.c | 8 +++++++
include/linux/bcma/bcma_driver_chipcommon.h | 13 ++++++++++++
5 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index c4252c4..0d5b425 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -54,7 +54,7 @@ config BCMA_SFLASH
config BCMA_NFLASH
bool
- depends on BCMA_DRIVER_MIPS && BROKEN
+ 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 94bf07c..169fc58 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -66,6 +66,7 @@ static inline int bcma_sflash_init(struct bcma_drv_cc *cc)
#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)
{
diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c
index 574d624..9042781 100644
--- a/drivers/bcma/driver_chipcommon_nflash.c
+++ b/drivers/bcma/driver_chipcommon_nflash.c
@@ -5,15 +5,37 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
-#include <linux/bcma/bcma_driver_chipcommon.h>
-#include <linux/delay.h>
#include "bcma_private.h"
+struct platform_device bcma_nflash_dev = {
+ .name = "bcma_nflash",
+ .num_resources = 0,
+};
+
/* Initialize NAND flash access */
int bcma_nflash_init(struct bcma_drv_cc *cc)
{
- bcma_err(cc->core->bus, "NAND flash support is broken\n");
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
+ cc->core->id.rev != 0x38) {
+ bcma_err(bus, "NAND flash on unsupported board!\n");
+ return -ENOTSUPP;
+ }
+
+ if (!(cc->capabilities & BCMA_CC_CAP_NFLASH)) {
+ bcma_err(bus, "NAND flash not present according to ChipCommon\n");
+ return -ENODEV;
+ }
+
+ cc->nflash.present = true;
+
+ /* 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;
}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 648688a..a3736f5 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -145,6 +145,14 @@ static int bcma_register_cores(struct bcma_bus *bus)
}
#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;
}
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 799e4200..b9d7eeb 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -526,6 +526,16 @@ struct bcma_sflash {
};
#endif
+#ifdef CONFIG_BCMA_NFLASH
+struct mtd_info;
+
+struct bcma_nflash {
+ bool present;
+
+ struct mtd_info *mtd;
+};
+#endif
+
struct bcma_serial_port {
void *regs;
unsigned long clockspeed;
@@ -549,6 +559,9 @@ struct bcma_drv_cc {
#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];
--
1.7.7
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [BROKEN][PROOF][DONT APPLY][PATCH 2/2] bcm47nflash driver (WIP, BROKEN)
2012-08-12 11:08 [READY][PATCH 1/2] bcma: detect and register NAND flash device Rafał Miłecki
@ 2012-08-12 11:08 ` Rafał Miłecki
2012-08-12 11:09 ` [READY][PATCH 1/2] bcma: detect and register NAND flash device Rafał Miłecki
1 sibling, 0 replies; 3+ messages in thread
From: Rafał Miłecki @ 2012-08-12 11:08 UTC (permalink / raw)
To: linux-wireless, John W. Linville
Cc: Hauke Mehrtens, Florian Fainelli, Rafał Miłecki
This is proof of concept for BCMA NAND flash driver. With that patch I
get:
NAND device: Manufacturer ID: 0xec, Chip ID: 0xf1 (Samsung NAND 128MiB
3,3V 8-bit), page size: 2048, OOB size: 64
---
drivers/bcma/driver_chipcommon_pmu.c | 2 +-
drivers/mtd/nand/Kconfig | 4 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/bcm47nflash.c | 293 +++++++++++++++++++++++++++
include/linux/bcma/bcma_driver_chipcommon.h | 1 +
5 files changed, 300 insertions(+), 1 deletions(-)
create mode 100644 drivers/mtd/nand/bcm47nflash.c
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 8b8f2f3..da8b8e7 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/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 31bb7e5..4b8ae37 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -607,4 +607,8 @@ config MTD_NAND_FSMC
Enables support for NAND Flash chips on the ST Microelectronics
Flexible Static Memory Controller (FSMC)
+config MTD_NAND_BCM47NFLASH
+ bool "Broadcom NAND flash driver"
+ depends on BCMA && BCMA_NFLASH
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d4b4d87..879681f 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
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_BCM47NFLASH) += bcm47nflash.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/bcm47nflash.c b/drivers/mtd/nand/bcm47nflash.c
new file mode 100644
index 0000000..df7f373
--- /dev/null
+++ b/drivers/mtd/nand/bcm47nflash.c
@@ -0,0 +1,293 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/platform_device.h>
+#include <linux/bcma/bcma.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Broadcom NAND flash driver");
+
+/* 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
+
+int devid_column = 0;
+unsigned curr_command = 0;
+
+/**************************************************
+ * 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_5357_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)
+{
+ 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;
+}
+
+static 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);
+}
+
+/**************************************************
+ * MTD ops
+ **************************************************/
+
+static void bcma_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+ return;
+}
+
+static void bcma_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+ struct bcma_nflash *nflash = (struct bcma_nflash *)nand_chip->priv;
+ struct bcma_drv_cc *cc = container_of(nflash, struct bcma_drv_cc, nflash);
+
+ switch (command) {
+ case NAND_CMD_RESET:
+ break;
+ case NAND_CMD_READID:
+ if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+ if (bcma_nflash_ctl_cmd(cc, 0x40000000 | 0x01000000 |
+ 0x00080000 | 0x00010000 | 0x00000090) < 0)
+ pr_err("READID error\n");
+ } else {
+ bcma_nflash_enable(cc, true);
+ bcma_nflash_cmd(cc, 7);
+ if (bcma_nflash_poll(cc) < 0) {
+ bcma_nflash_enable(cc, false);
+ pr_err("READID error\n");
+ }
+ bcma_nflash_enable(cc, false);
+ }
+ devid_column = 0;
+ break;
+ default:
+ pr_err("Command 0x%X unsupported\n", command);
+ break;
+ }
+ curr_command = command;
+ pr_info("Set curr_command to 0x%X\n", curr_command);
+}
+
+static u8 bcma_nand_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+ struct bcma_nflash *nflash = (struct bcma_nflash *)nand_chip->priv;
+ struct bcma_drv_cc *cc = container_of(nflash, struct bcma_drv_cc, nflash);
+ u32 code;
+
+ switch (curr_command) {
+ case NAND_CMD_READID:
+ if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+ u32 tmp;
+ if (devid_column <= 4)
+ code = 0x40000000 | 0x00100000;
+ else
+ code = 0x00100000;
+ if (bcma_nflash_ctl_cmd(cc, code))
+ return 0xff;
+ else
+ tmp = bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xFF;
+ pr_info("Returning 0x%X\n", tmp);
+ return tmp;
+ } else {
+ u32 tmp = 0;
+ if (devid_column < 4)
+ tmp = bcma_cc_read32(cc, BCMA_CC_NAND_DEVID);
+ else if (devid_column < 8)
+ tmp = bcma_cc_read32(cc, BCMA_CC_NAND_DEVID_X);
+ else
+ WARN_ON(1);
+ tmp = (tmp >> (8 * curr_command)) & 0xff;
+ devid_column++;
+ return tmp;
+ }
+ break;
+ }
+
+ pr_err("Invalid curr_command: 0x%X\n", curr_command);
+ return 0;
+}
+
+/**************************************************
+ * Init & exit
+ **************************************************/
+
+static int bcma_nflash_init_bcm4706(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+ struct bcma_nflash *nflash = (struct bcma_nflash *)nand_chip->priv;
+ struct bcma_drv_cc *cc = container_of(nflash, struct bcma_drv_cc, nflash);
+
+ u32 freq;
+ u16 clock;
+ u8 w0, w1, w2, w3, w4;
+
+ /* 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));
+
+ pr_info("Scanning: %d\n", nand_scan_ident(mtd, 1, NULL));
+ pr_info("pagemask: 0x%X\n", nand_chip->pagemask);
+ pr_info("page_shift: %d\n", nand_chip->page_shift);
+ pr_info("tail: %d\n", nand_scan_tail(mtd));
+
+ /* TODO: bcma_cc_write32(cc, BCMA_CC_NFLASH_CONF, val); */
+
+ return 0;
+}
+
+static int bcm47nflash_probe(struct platform_device *pdev)
+{
+ struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+ struct bcma_drv_cc *cc = container_of(nflash, struct bcma_drv_cc, nflash);
+ struct mtd_info *mtd = nflash->mtd;
+ struct nand_chip *nand_chip;
+
+ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (!mtd)
+ return -ENOMEM;
+
+ nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
+ if (!nand_chip)
+ return -ENOMEM;
+
+ nand_chip->priv = nflash;
+ nand_chip->select_chip = bcma_nand_select_chip;
+ nand_chip->cmdfunc = bcma_nand_cmdfunc;
+ nand_chip->read_byte = bcma_nand_read_byte;
+ nand_chip->options = NAND_SKIP_BBTSCAN;
+
+ mtd->priv = nand_chip;
+ mtd->owner = THIS_MODULE;
+
+ if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
+ bcma_nflash_init_bcm4706(mtd);
+ //else
+ // bcma_nflash_init_default(mtd);
+
+#if 0
+ err = mtd_device_parse_register(nflash->mtd, probes, NULL, NULL, 0);
+ if (err) {
+ pr_err("Failed to register MTD device: %d\n", err);
+ return err;
+ }
+#endif
+
+ return 0;
+}
+
+static int __devexit bcm47nflash_remove(struct platform_device *pdev)
+{
+ struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+
+ if (nflash->mtd)
+ mtd_device_unregister(nflash->mtd);
+
+ return 0;
+}
+
+static struct platform_driver bcma_nflash_driver = {
+ .remove = __devexit_p(bcm47nflash_remove),
+ .driver = {
+ .name = "bcma_nflash",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init init_bcm47nflash(void)
+{
+ int err;
+
+ err = platform_driver_probe(&bcma_nflash_driver, bcm47nflash_probe);
+ if (err)
+ pr_err("Failed to register serial flash driver: %d\n", err);
+
+ return err;
+}
+
+static void __exit exit_bcm47nflash(void)
+{
+ platform_driver_unregister(&bcma_nflash_driver);
+}
+
+module_init(init_bcm47nflash);
+module_exit(exit_bcm47nflash);
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index b9d7eeb..8507f51 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -606,6 +606,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);
+extern 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
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [READY][PATCH 1/2] bcma: detect and register NAND flash device
2012-08-12 11:08 [READY][PATCH 1/2] bcma: detect and register NAND flash device Rafał Miłecki
2012-08-12 11:08 ` [BROKEN][PROOF][DONT APPLY][PATCH 2/2] bcm47nflash driver (WIP, BROKEN) Rafał Miłecki
@ 2012-08-12 11:09 ` Rafał Miłecki
1 sibling, 0 replies; 3+ messages in thread
From: Rafał Miłecki @ 2012-08-12 11:09 UTC (permalink / raw)
To: linux-wireless, John W. Linville
Cc: Hauke Mehrtens, Florian Fainelli, Rafał Miłecki
2012/8/12 Rafał Miłecki <zajec5@gmail.com>:
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
This will apply cleanly on top of:
[PATCH V2] bcma: detect and register serial flash device
--
Rafał
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-08-12 11:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-12 11:08 [READY][PATCH 1/2] bcma: detect and register NAND flash device Rafał Miłecki
2012-08-12 11:08 ` [BROKEN][PROOF][DONT APPLY][PATCH 2/2] bcm47nflash driver (WIP, BROKEN) Rafał Miłecki
2012-08-12 11:09 ` [READY][PATCH 1/2] bcma: detect and register NAND flash device Rafał Miłecki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).