Add Support XTX Technology XT26G01DXXXXX, XT26G11DXXXXX, XT26Q01DXXXXX, XT26G02DXXXXX, XT26G12DXXXXX, XT26Q02DXXXXX, XT26G04DXXXXX, and XT26Q04DXXXXX SPI NAND.
These are 3V/1.8V 1G/2G/4Gbit serial SLC NAND flash device with on-die ECC(8bit strength per 512bytes). Datasheet Links: - http://www.xtxtech.com/download/?AId=458 - http://www.xtxtech.com/download/?AId=495 Signed-off-by: Bruce Suen <bruce_s...@163.com> --- drivers/mtd/nand/spi/Makefile | 1 + drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/xtx.c | 180 ++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 183 insertions(+) create mode 100644 drivers/mtd/nand/spi/xtx.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 3051de4f7e..e46cfed446 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o +spinand-objs += xtx.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 597b088ca7..0b4c067425 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -828,6 +828,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { ¶gon_spinand_manufacturer, &toshiba_spinand_manufacturer, &winbond_spinand_manufacturer, + &xtx_spinand_manufacturer, }; static int spinand_manufacturer_match(struct spinand_device *spinand, diff --git a/drivers/mtd/nand/spi/xtx.c b/drivers/mtd/nand/spi/xtx.c new file mode 100644 index 0000000000..ced05b5895 --- /dev/null +++ b/drivers/mtd/nand/spi/xtx.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Stefan Roese <s...@denx.de> + * + * Derived from drivers/mtd/nand/spi/micron.c + * Copyright (c) 2016-2017 Micron Technology, Inc. + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/bitfield.h> +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_XTX 0x0B + +#define XT26XXXD_STATUS_ECC3_ECC2_MASK GENMASK(7, 6) +#define XT26XXXD_STATUS_ECC_NO_DETECTED (0) +#define XT26XXXD_STATUS_ECC_1_7_CORRECTED (1) +#define XT26XXXD_STATUS_ECC_8_CORRECTED (3) +#define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2) + +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), + 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 xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = mtd->oobsize / 2; + region->length = mtd->oobsize / 2; + + return 0; +} + +static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 2; + region->length = mtd->oobsize / 2 - 2; + + return 0; +} + +static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = { + .ecc = xt26xxxd_ooblayout_ecc, + .rfree = xt26xxxd_ooblayout_free, +}; + +static int xt26xxxd_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (FIELD_GET(STATUS_ECC_MASK, status)) { + case XT26XXXD_STATUS_ECC_NO_DETECTED: + return 0; + case XT26XXXD_STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + case XT26XXXD_STATUS_ECC_1_7_CORRECTED: + return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK, status); + case XT26XXXD_STATUS_ECC_8_CORRECTED: + return 8; + default: + break; + } + + return -EINVAL; +} + +static const struct spinand_info xtx_spinand_table[] = { + SPINAND_INFO("XT26G01D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x31), + 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), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26G11D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x34), + 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), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26Q01D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51), + 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), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26G02D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x32), + 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, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26G12D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x35), + 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, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26Q02D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52), + 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, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26G04D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x33), + 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), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), + SPINAND_INFO("XT26Q04D", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x53), + 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), + 0, + SPINAND_ECCINFO(&xt26xxxd_ooblayout, + xt26xxxd_ecc_get_status)), +}; + +static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer xtx_spinand_manufacturer = { + .id = SPINAND_MFR_XTX, + .name = "XTX", + .chips = xtx_spinand_table, + .nchips = ARRAY_SIZE(xtx_spinand_table), + .ops = &xtx_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index e8d6feb970..bf7696a981 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -251,6 +251,7 @@ 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; +extern const struct spinand_manufacturer xtx_spinand_manufacturer; /** * struct spinand_op_variants - SPI NAND operation variants -- 2.34.1