[PATCH v2 5/6] nand: spi: add Micron spi nand support
Peter Pan
peterpandong at micron.com
Wed Mar 1 00:52:09 PST 2017
This commit is to add support for Micron MT29F2G01ABAGD
spi nand chip.
Signed-off-by: Peter Pan <peterpandong at micron.com>
---
drivers/mtd/nand/spi/Makefile | 1 +
drivers/mtd/nand/spi/spinand_ids.c | 5 ++
drivers/mtd/nand/spi/spinand_micron.c | 133 ++++++++++++++++++++++++++++++++++
3 files changed, 139 insertions(+)
create mode 100644 drivers/mtd/nand/spi/spinand_micron.c
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6f0d622..84b9bcc 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_MTD_SPI_NAND) += spinand_base.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand_ids.o
+obj-$(CONFIG_MTD_SPI_NAND) += spinand_micron.o
diff --git a/drivers/mtd/nand/spi/spinand_ids.c b/drivers/mtd/nand/spi/spinand_ids.c
index 7706ae3..10f74f1 100644
--- a/drivers/mtd/nand/spi/spinand_ids.c
+++ b/drivers/mtd/nand/spi/spinand_ids.c
@@ -18,11 +18,16 @@
#include <linux/mtd/spinand.h>
struct spinand_flash spinand_table[] = {
+ SPI_NAND_INFO("MT29F2G01ABAGD", 0x2C, 0x24, 2048, 128, 64, 2048,
+ 1, 8, SPINAND_OP_COMMON),
{.name = NULL},
};
+extern struct spinand_manufacturer_ops micron_spinand_manuf_ops;
+
struct spinand_manufacturer spinand_manuf_ids[] = {
+ {SPINAND_MFR_MICRON, "Micron", µn_spinand_manuf_ops},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/spi/spinand_micron.c b/drivers/mtd/nand/spi/spinand_micron.c
new file mode 100644
index 0000000..d978935
--- /dev/null
+++ b/drivers/mtd/nand/spi/spinand_micron.c
@@ -0,0 +1,133 @@
+/**
+* spi-nand-base.c
+*
+* Copyright (c) 2009-2017 Micron Technology, Inc.
+*
+* 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.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*/
+
+#include <linux/mtd/spinand.h>
+
+#define SPI_NAND_MT29F_ECC_MASK 0x70
+#define SPI_NAND_MT29F_ECC_0_BIT 0x00
+#define SPI_NAND_MT29F_ECC_1_3_BIT 0x10
+#define SPI_NAND_MT29F_ECC_4_6_BIT 0x30
+#define SPI_NAND_MT29F_ECC_7_8_BIT 0x50
+#define SPI_NAND_MT29F_ECC_UNCORR 0x20
+
+
+static int micron_ooblayout_ecc_128(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->length = 64;
+ oobregion->offset = 64;
+
+ return 0;
+}
+
+static int micron_ooblayout_free_128(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->length = 62;
+ oobregion->offset = 2;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_ooblayout_128_ops = {
+ .ecc = micron_ooblayout_ecc_128,
+ .free = micron_ooblayout_free_128,
+};
+
+static void mt29f_get_ecc_status(struct spinand_device *chip,
+ unsigned int status,
+ unsigned int *corrected,
+ unsigned int *ecc_error)
+{
+ unsigned int ecc_status = status & SPI_NAND_MT29F_ECC_MASK;
+
+ *ecc_error = (ecc_status == SPI_NAND_MT29F_ECC_UNCORR);
+ switch (ecc_status) {
+ case SPI_NAND_MT29F_ECC_0_BIT:
+ *corrected = 0;
+ break;
+ case SPI_NAND_MT29F_ECC_1_3_BIT:
+ *corrected = 3;
+ break;
+ case SPI_NAND_MT29F_ECC_4_6_BIT:
+ *corrected = 6;
+ break;
+ case SPI_NAND_MT29F_ECC_7_8_BIT:
+ *corrected = 8;
+ break;
+ }
+}
+
+static void mt29f_build_column_addr(struct spinand_device *chip,
+ struct spinand_op *op,
+ u32 page, u32 column)
+{
+ struct nand_device *nand = &chip->base;
+
+ op->n_addr = 2;
+ op->addr[0] = (u8)(column >> 8);
+ op->addr[0] |= (u8)((nand_page_to_eraseblock(nand, page)
+ & 0x1) << 4);
+ op->addr[1] = (u8)column;
+}
+
+static int micron_spinand_get_dummy(struct spinand_device *chip,
+ struct spinand_op *op)
+{
+ u8 opcode = op->cmd;
+
+ switch (opcode) {
+ case SPINAND_CMD_READ_FROM_CACHE:
+ case SPINAND_CMD_READ_FROM_CACHE_FAST:
+ case SPINAND_CMD_READ_FROM_CACHE_X2:
+ case SPINAND_CMD_READ_FROM_CACHE_DUAL_IO:
+ case SPINAND_CMD_READ_FROM_CACHE_X4:
+ case SPINAND_CMD_READ_ID:
+ return 1;
+ case SPINAND_CMD_READ_FROM_CACHE_QUAD_IO:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+static struct spinand_ecc_engine_ops generic_spi_ecc_engine_ops = {
+ .get_ecc_status = mt29f_get_ecc_status,
+};
+
+static int micron_spinand_init(struct spinand_device *chip)
+{
+ struct mtd_info *mtd = spinand_to_mtd(chip);
+ struct nand_device *nand = mtd_to_nand(mtd);
+
+ chip->ecc_engine.ops = &generic_spi_ecc_engine_ops;
+ if (nand_per_page_oobsize(nand) == 128)
+ mtd_set_ooblayout(mtd, µn_ooblayout_128_ops);
+
+ return 0;
+}
+
+const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
+ .init = micron_spinand_init,
+ .build_column_addr = mt29f_build_column_addr,
+ .get_dummy = micron_spinand_get_dummy,
+};
--
1.9.1
More information about the linux-mtd
mailing list