summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>2023-01-10 12:58:40 +0100
committerDario Binacchi <dario.binacchi@amarulasolutions.com>2023-10-13 10:49:07 +0200
commit8acaec923be2d8deeab0b32e07beaed366e82696 (patch)
treeb94f06b35a5eac78be513de4379584e9ada06d00
parent2572470c8935d18ca4ddb8f65465e9b48f41e1e3 (diff)
downloadu-boot-8acaec923be2d8deeab0b32e07beaed366e82696.tar.gz
u-boot-8acaec923be2d8deeab0b32e07beaed366e82696.tar.bz2
u-boot-8acaec923be2d8deeab0b32e07beaed366e82696.zip
mtd/spinand: sync supported devices with linux-5.15.43
This adds more supported spinand devices from the Linux kernel implementation. This does not include the latest kernel implementation as this would require a substantial amount of extra work due to the missing ECC engine abstraction layer in U-Boot. Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de> (commit message) Link: https://lore.kernel.org/all/20230110115843.391630-3-frieder@fris.de Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
-rw-r--r--drivers/mtd/nand/spi/Makefile2
-rw-r--r--drivers/mtd/nand/spi/core.c1
-rw-r--r--drivers/mtd/nand/spi/gigadevice.c223
-rw-r--r--drivers/mtd/nand/spi/macronix.c145
-rw-r--r--drivers/mtd/nand/spi/micron.c144
-rw-r--r--drivers/mtd/nand/spi/paragon.c133
-rw-r--r--drivers/mtd/nand/spi/toshiba.c38
-rw-r--r--drivers/mtd/nand/spi/winbond.c6
-rw-r--r--include/linux/mtd/nand.h5
-rw-r--r--include/linux/mtd/spinand.h31
10 files changed, 626 insertions, 102 deletions
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 6c65b187e8..3051de4f7e 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index b3f21ba022..597b088ca7 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -825,6 +825,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
+ &paragon_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
};
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index 43b353a3e7..f2ecf47f8d 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -7,13 +7,13 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_GIGADEVICE 0xC8
+
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
@@ -22,8 +22,12 @@
#define GD5FXGQXXEXXG_REG_STATUS2 0xf0
-/* Q4 devices, QUADIO: Dummy bytes valid for 1 and 2 GBit variants */
-static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
+#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -31,14 +35,13 @@ static SPINAND_OP_VARIANTS(gd5fxgq4_read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
-static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
- SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+static SPINAND_OP_VARIANTS(read_cache_variants_f,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
@@ -48,7 +51,65 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
-static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
+static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = (16 * section) + 8;
+ region->length = 8;
+
+ return 0;
+}
+
+static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ if (section) {
+ region->offset = 16 * section;
+ region->length = 8;
+ } else {
+ /* section 0 has one byte reserved for bad block mark */
+ region->offset = 1;
+ region->length = 7;
+ }
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+ .ecc = gd5fxgq4xa_ooblayout_ecc,
+ .rfree = gd5fxgq4xa_ooblayout_free,
+};
+
+static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
+ /* 1-7 bits are flipped. return the maximum. */
+ return 7;
+
+ case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
+ return 8;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
@@ -60,7 +121,7 @@ static int gd5fxgqxxexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
return 0;
}
-static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
+static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
@@ -73,7 +134,42 @@ static int gd5fxgqxxexxg_ooblayout_free(struct mtd_info *mtd, int section,
return 0;
}
-static int gd5fxgq4xexxg_ecc_get_status(struct spinand_device *spinand,
+/* Valid for Q4/Q5 and Q6 (untested) devices */
+static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
+ .ecc = gd5fxgqx_variant2_ooblayout_ecc,
+ .rfree = gd5fxgqx_variant2_ooblayout_free,
+};
+
+static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = 128;
+ oobregion->length = 128;
+
+ return 0;
+}
+
+static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = 1;
+ oobregion->length = 127;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
+ .ecc = gd5fxgq4xc_ooblayout_256_ecc,
+ .rfree = gd5fxgq4xc_ooblayout_256_free,
+};
+
+static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
@@ -152,31 +248,106 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
-static const struct mtd_ooblayout_ops gd5fxgqxxexxg_ooblayout = {
- .ecc = gd5fxgqxxexxg_ooblayout_ecc,
- .rfree = gd5fxgqxxexxg_ooblayout_free,
-};
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
+ case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
+ return 3;
+
+ case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
+ return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
+ }
+
+ return -EINVAL;
+}
static const struct spinand_info gigadevice_spinand_table[] = {
+ SPINAND_INFO("GD5F1GQ4xA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F2GQ4xA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F4GQ4xA",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
+ NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F4GQ4RC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+ gd5fxgq4ufxxg_ecc_get_status)),
+ SPINAND_INFO("GD5F4GQ4UC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
+ gd5fxgq4ufxxg_ecc_get_status)),
SPINAND_INFO("GD5F1GQ4UExxG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ gd5fxgq4uexxg_ecc_get_status)),
+ SPINAND_INFO("GD5F1GQ4UFxxG",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&gd5fxgq4_read_cache_variants,
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
&write_cache_variants,
&update_cache_variants),
- 0,
- SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
- gd5fxgq4xexxg_ecc_get_status)),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ gd5fxgq4ufxxg_ecc_get_status)),
SPINAND_INFO("GD5F1GQ5UExxG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
- SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
- 0,
- SPINAND_ECCINFO(&gd5fxgqxxexxg_ooblayout,
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq5xexxg_ecc_get_status)),
};
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 08f7d69d8c..86bffc2800 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -6,7 +6,6 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
@@ -16,7 +15,6 @@
#define SPINAND_MFR_MACRONIX 0xC2
#define MACRONIX_ECCSR_MASK 0x0F
-
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -62,7 +60,6 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
SPI_MEM_OP_DATA_IN(1, eccsr, 1));
int ret = spi_mem_exec_op(spinand->slave, &op);
-
if (ret)
return ret;
@@ -107,7 +104,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
static const struct spinand_info macronix_spinand_table[] = {
SPINAND_INFO("MX35LF1GE4AB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -117,16 +114,124 @@ static const struct spinand_info macronix_spinand_table[] = {
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35LF2GE4AB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
- NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX35LF2GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35LF4GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
+ NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35LF1G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX35LF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX35LF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX31LF1GE4BC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX31UF1GE4BC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+
+ SPINAND_INFO("MX35LF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF4GE4AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -136,7 +241,7 @@ static const struct spinand_info macronix_spinand_table[] = {
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF2GE4AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -146,7 +251,17 @@ static const struct spinand_info macronix_spinand_table[] = {
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF2GE4AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
- NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -154,9 +269,19 @@ static const struct spinand_info macronix_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35UF1G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF1GE4AD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -166,7 +291,7 @@ static const struct spinand_info macronix_spinand_table[] = {
mx35lf1ge4ab_ecc_get_status)),
SPINAND_INFO("MX35UF1GE4AC",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index cecd3db958..b538213ed8 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -7,11 +7,9 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
-#include <linux/bitops.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_MICRON 0x2c
@@ -32,7 +30,7 @@
#define MICRON_SELECT_DIE(x) ((x) << 6)
-static SPINAND_OP_VARIANTS(read_cache_variants,
+static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
@@ -40,14 +38,27 @@ static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-static SPINAND_OP_VARIANTS(write_cache_variants,
+static SPINAND_OP_VARIANTS(x4_write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
-static SPINAND_OP_VARIANTS(update_cache_variants,
+static SPINAND_OP_VARIANTS(x4_update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
+/* Micron MT29F2G01AAAED Device */
+static SPINAND_OP_VARIANTS(x4_read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(x1_write_cache_variants,
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(x1_update_cache_variants,
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
@@ -78,6 +89,47 @@ static const struct mtd_ooblayout_ops micron_8_ooblayout = {
.rfree = micron_8_ooblayout_free,
};
+static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+ if (section >= spinand->base.memorg.pagesize /
+ mtd->ecc_step_size)
+ return -ERANGE;
+
+ region->offset = (section * 16) + 8;
+ region->length = 8;
+
+ return 0;
+}
+
+static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ struct spinand_device *spinand = mtd_to_spinand(mtd);
+
+ if (section >= spinand->base.memorg.pagesize /
+ mtd->ecc_step_size)
+ return -ERANGE;
+
+ if (section) {
+ region->offset = 16 * section;
+ region->length = 8;
+ } else {
+ /* section 0 has two bytes reserved for the BBM */
+ region->offset = 2;
+ region->length = 6;
+ }
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops micron_4_ooblayout = {
+ .ecc = micron_4_ooblayout_ecc,
+ .rfree = micron_4_ooblayout_free,
+};
+
static int micron_select_target(struct spinand_device *spinand,
unsigned int target)
{
@@ -122,55 +174,55 @@ static const struct spinand_info micron_spinand_table[] = {
/* M79A 2Gb 3.3V */
SPINAND_INFO("MT29F2G01ABAGD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M79A 2Gb 1.8V */
SPINAND_INFO("MT29F2G01ABBGD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M78A 1Gb 3.3V */
SPINAND_INFO("MT29F1G01ABAFD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M78A 1Gb 1.8V */
SPINAND_INFO("MT29F1G01ABAFD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M79A 4Gb 3.3V */
SPINAND_INFO("MT29F4G01ADAGD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
0,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status),
@@ -178,33 +230,33 @@ static const struct spinand_info micron_spinand_table[] = {
/* M70A 4Gb 3.3V */
SPINAND_INFO("MT29F4G01ABAFD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M70A 4Gb 1.8V */
SPINAND_INFO("MT29F4G01ABBFD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status)),
/* M70A 8Gb 3.3V */
SPINAND_INFO("MT29F8G01ADAFD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status),
@@ -212,15 +264,25 @@ static const struct spinand_info micron_spinand_table[] = {
/* M70A 8Gb 1.8V */
SPINAND_INFO("MT29F8G01ADBFD",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
NAND_ECCREQ(8, 512),
- SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- &write_cache_variants,
- &update_cache_variants),
+ SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
+ &x4_write_cache_variants,
+ &x4_update_cache_variants),
SPINAND_HAS_CR_FEAT_BIT,
SPINAND_ECCINFO(&micron_8_ooblayout,
micron_8_ecc_get_status),
SPINAND_SELECT_TARGET(micron_select_target)),
+ /* M69A 2Gb 3.3V */
+ SPINAND_INFO("MT29F2G01AAAED",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
+ &x1_write_cache_variants,
+ &x1_update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
};
static int micron_spinand_init(struct spinand_device *spinand)
diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
new file mode 100644
index 0000000000..0c123930f1
--- /dev/null
+++ b/drivers/mtd/nand/spi/paragon.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Jeff Kletsky
+ *
+ * Author: Jeff Kletsky <git-commits@allycomm.com>
+ */
+
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+
+#define SPINAND_MFR_PARAGON 0xa1
+
+
+#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4)
+
+#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4)
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED (1 << 4)
+#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4)
+#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 3)
+ return -ERANGE;
+
+ region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
+ region->length = 13;
+
+ return 0;
+}
+
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section > 4)
+ return -ERANGE;
+
+ if (section == 4) {
+ region->offset = 64;
+ region->length = 64;
+ } else {
+ region->offset = 4 + (15 * section);
+ region->length = 2;
+ }
+
+ return 0;
+}
+
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
+ case PN26G0XA_STATUS_ECC_NONE_DETECTED:
+ return 0;
+
+ case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
+ return 7; /* Return upper limit by convention */
+
+ case PN26G0XA_STATUS_ECC_8_CORRECTED:
+ return 8;
+
+ case PN26G0XA_STATUS_ECC_ERRORED:
+ return -EBADMSG;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
+ .ecc = pn26g0xa_ooblayout_ecc,
+ .rfree = pn26g0xa_ooblayout_free,
+};
+
+
+static const struct spinand_info paragon_spinand_table[] = {
+ SPINAND_INFO("PN26G01A",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+ pn26g0xa_ecc_get_status)),
+ SPINAND_INFO("PN26G02A",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe2),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
+ pn26g0xa_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
+ .id = SPINAND_MFR_PARAGON,
+ .name = "Paragon",
+ .chips = paragon_spinand_table,
+ .nchips = ARRAY_SIZE(paragon_spinand_table),
+ .ops = &paragon_spinand_manuf_ops,
+};
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index e057b08c70..b9908e7927 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -7,13 +7,13 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
#include <linux/bug.h>
#include <linux/mtd/spinand.h>
+/* Kioxia is new name of Toshiba memory. */
#define SPINAND_MFR_TOSHIBA 0x98
#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
@@ -31,7 +31,7 @@ static SPINAND_OP_VARIANTS(update_cache_x4_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
-/**
+/*
* Backward compatibility for 1st generation Serial NAND devices
* which don't support Quad Program Load operation.
*/
@@ -42,7 +42,7 @@ static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+ struct mtd_oob_region *region)
{
if (section > 0)
return -ERANGE;
@@ -54,7 +54,7 @@ static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
}
static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
- struct mtd_oob_region *region)
+ struct mtd_oob_region *region)
{
if (section > 0)
return -ERANGE;
@@ -72,7 +72,7 @@ static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {
};
static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
- u8 status)
+ u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
u8 mbf = 0;
@@ -113,7 +113,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 1Gb (1st generation) */
SPINAND_INFO("TC58CVG0S3HRAIG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -124,7 +124,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 2Gb (1st generation) */
SPINAND_INFO("TC58CVG1S3HRAIG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -135,7 +135,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 4Gb (1st generation) */
SPINAND_INFO("TC58CVG2S0HRAIG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -146,7 +146,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 1Gb (1st generation) */
SPINAND_INFO("TC58CYG0S3HRAIG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -157,7 +157,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 2Gb (1st generation) */
SPINAND_INFO("TC58CYG1S3HRAIG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -168,7 +168,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 4Gb (1st generation) */
SPINAND_INFO("TC58CYG2S0HRAIG",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -184,7 +184,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 1Gb (2nd generation) */
SPINAND_INFO("TC58CVG0S3HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -195,7 +195,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 2Gb (2nd generation) */
SPINAND_INFO("TC58CVG1S3HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -206,7 +206,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 4Gb (2nd generation) */
SPINAND_INFO("TC58CVG2S0HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -217,7 +217,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 3.3V 8Gb (2nd generation) */
SPINAND_INFO("TH58CVG3S0HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
- NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -228,7 +228,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 1Gb (2nd generation) */
SPINAND_INFO("TC58CYG0S3HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
- NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -239,7 +239,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 2Gb (2nd generation) */
SPINAND_INFO("TC58CYG1S3HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
- NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -250,7 +250,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 4Gb (2nd generation) */
SPINAND_INFO("TC58CYG2S0HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
- NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
@@ -261,7 +261,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
/* 1.8V 8Gb (2nd generation) */
SPINAND_INFO("TH58CYG3S0HRAIJ",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
- NAND_MEMORG(1, 4096, 256, 64, 4096, 1, 1, 1),
+ NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 66ed0a51d2..4e5a6eaecd 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -8,11 +8,9 @@
*/
#ifndef __UBOOT__
-#include <malloc.h>
#include <linux/device.h>
#include <linux/kernel.h>
#endif
-#include <linux/bitops.h>
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_WINBOND 0xEF
@@ -81,7 +79,7 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
static const struct spinand_info winbond_spinand_table[] = {
SPINAND_INFO("W25M02GV",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -91,7 +89,7 @@ static const struct spinand_info winbond_spinand_table[] = {
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
SPINAND_INFO("W25N01GV",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
- NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index aeb38dec2e..651f8706df 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -19,6 +19,7 @@
* @oobsize: OOB area size
* @pages_per_eraseblock: number of pages per eraseblock
* @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN
* @planes_per_lun: number of planes per LUN
* @luns_per_target: number of LUN per target (target is a synonym for die)
* @ntargets: total number of targets exposed by the NAND device
@@ -29,18 +30,20 @@ struct nand_memory_organization {
unsigned int oobsize;
unsigned int pages_per_eraseblock;
unsigned int eraseblocks_per_lun;
+ unsigned int max_bad_eraseblocks_per_lun;
unsigned int planes_per_lun;
unsigned int luns_per_target;
unsigned int ntargets;
};
-#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt) \
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt) \
{ \
.bits_per_cell = (bpc), \
.pagesize = (ps), \
.oobsize = (os), \
.pages_per_eraseblock = (ppe), \
.eraseblocks_per_lun = (epl), \
+ .max_bad_eraseblocks_per_lun = (mbb), \
.planes_per_lun = (ppl), \
.luns_per_target = (lpt), \
.ntargets = (nt), \
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 1ae4dc6b15..e8d6feb970 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -75,30 +75,60 @@
SPI_MEM_OP_DUMMY(ndummy, 1), \
SPI_MEM_OP_DATA_IN(len, buf, 1))
+#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
+ SPI_MEM_OP_ADDR(3, addr, 1), \
+ SPI_MEM_OP_DUMMY(ndummy, 1), \
+ SPI_MEM_OP_DATA_IN(len, buf, 1))
+
#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
SPI_MEM_OP_ADDR(2, addr, 1), \
SPI_MEM_OP_DUMMY(ndummy, 1), \
SPI_MEM_OP_DATA_IN(len, buf, 2))
+#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
+ SPI_MEM_OP_ADDR(3, addr, 1), \
+ SPI_MEM_OP_DUMMY(ndummy, 1), \
+ SPI_MEM_OP_DATA_IN(len, buf, 2))
+
#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
SPI_MEM_OP_ADDR(2, addr, 1), \
SPI_MEM_OP_DUMMY(ndummy, 1), \
SPI_MEM_OP_DATA_IN(len, buf, 4))
+#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
+ SPI_MEM_OP_ADDR(3, addr, 1), \
+ SPI_MEM_OP_DUMMY(ndummy, 1), \
+ SPI_MEM_OP_DATA_IN(len, buf, 4))
+
#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
SPI_MEM_OP_ADDR(2, addr, 2), \
SPI_MEM_OP_DUMMY(ndummy, 2), \
SPI_MEM_OP_DATA_IN(len, buf, 2))
+#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
+ SPI_MEM_OP_ADDR(3, addr, 2), \
+ SPI_MEM_OP_DUMMY(ndummy, 2), \
+ SPI_MEM_OP_DATA_IN(len, buf, 2))
+
#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
SPI_MEM_OP_ADDR(2, addr, 4), \
SPI_MEM_OP_DUMMY(ndummy, 4), \
SPI_MEM_OP_DATA_IN(len, buf, 4))
+#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
+ SPI_MEM_OP_ADDR(3, addr, 4), \
+ SPI_MEM_OP_DUMMY(ndummy, 4), \
+ SPI_MEM_OP_DATA_IN(len, buf, 4))
+
#define SPINAND_PROG_EXEC_OP(addr) \
SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \
SPI_MEM_OP_ADDR(3, addr, 1), \
@@ -218,6 +248,7 @@ struct spinand_manufacturer {
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
extern const struct spinand_manufacturer micron_spinand_manufacturer;
+extern const struct spinand_manufacturer paragon_spinand_manufacturer;
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
extern const struct spinand_manufacturer winbond_spinand_manufacturer;