It's using FSL UPM infrastructure. So far only 8 bit accessors
are implemented.
Signed-off-by: Anton Vorontsov <[EMAIL PROTECTED]>
---
drivers/mtd/nand/Kconfig |7 +
drivers/mtd/nand/Makefile |1 +
drivers/mtd/nand/fsl_upm.c | 313
3 files changed, 321 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/nand/fsl_upm.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 246d451..91b448f 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -306,4 +306,11 @@ config MTD_ALAUDA
These two (and possibly other) Alauda-based cardreaders for
SmartMedia and xD allow raw flash access.
+config MTD_NAND_FSL_UPM
+ tristate "MTD driver for NAND on Freescale UPM"
+ depends on MTD_NAND && FSL_UPM && GENERIC_GPIO
+ help
+ Enables support for NAND Flash wired to Freescale processors'
+ localbus with pre-programmed User-Programmable Machine.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 3ad6c01..d553ea3 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -29,5 +29,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270)+= cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PLATFORM)+= plat_nand.o
obj-$(CONFIG_MTD_ALAUDA) += alauda.o
+obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
new file mode 100644
index 000..ac26199
--- /dev/null
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -0,0 +1,313 @@
+/*
+ * Freescale UPM NAND driver.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc.
+ * Copyright (c) 2007 Anton Vorontsov <[EMAIL PROTECTED]>
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct upm_data {
+ struct device *dev;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int last_ctrl;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
+
+ struct fsl_upm upm;
+
+ int width;
+ int upm_addr_offset;
+ int upm_cmd_offset;
+ void __iomem *io_base;
+ int rnb_gpio;
+ const u32 *wait_pattern;
+ const u32 *wait_write;
+ int chip_delay;
+};
+
+#define to_upm_data(mtd) container_of(mtd, struct upm_data, mtd)
+
+static int upm_chip_ready(struct mtd_info *mtd)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+
+ if (gpio_get_value(ud->rnb_gpio))
+ return 1;
+
+ dev_vdbg(ud->dev, "busy\n");
+ return 0;
+}
+
+static void upm_wait_rnb(struct upm_data *ud)
+{
+ int cnt = 100;
+
+ if (ud->rnb_gpio >= 0) {
+ while (--cnt && !upm_chip_ready(&ud->mtd))
+ cpu_relax();
+ }
+
+ if (!cnt)
+ dev_err(ud->dev, "tired waiting for RNB\n");
+}
+
+static void upm_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+
+ if (!(ctrl & ud->last_ctrl)) {
+ fsl_upm_end_pattern(&ud->upm);
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ ud->last_ctrl = ctrl & (NAND_ALE | NAND_CLE);
+ }
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_ALE)
+ fsl_upm_start_pattern(&ud->upm, ud->upm_addr_offset);
+ else if (ctrl & NAND_CLE)
+ fsl_upm_start_pattern(&ud->upm, ud->upm_cmd_offset);
+ }
+
+ fsl_upm_run_pattern(&ud->upm, ud->io_base, ud->width, cmd);
+
+ if (ud->wait_pattern)
+ upm_wait_rnb(ud);
+}
+
+static uint8_t upm_read_byte(struct mtd_info *mtd)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+
+ return in_8(ud->chip.IO_ADDR_R);
+}
+
+static void upm_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+ int i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = in_8(ud->chip.IO_ADDR_R);
+}
+
+static void upm_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct upm_data *ud = to_upm_data(mtd);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ out_8(ud->chip.IO_ADDR_W, buf[i]);
+ if (ud->wait_write)
+ upm_wait_rnb(ud);
+ }
+}
+
+static int __devinit upm_chip_init(struct upm_data *ud)
+{
+ int ret;
+#ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_types[] = { "cmdlinepart", NULL, };
+#endif
+
+