* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.