Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2016-2017 Micron Technology, Inc.
0004  *
0005  * Authors:
0006  *  Peter Pan <peterpandong@micron.com>
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/kernel.h>
0011 #include <linux/mtd/spinand.h>
0012 
0013 #define SPINAND_MFR_MICRON      0x2c
0014 
0015 #define MICRON_STATUS_ECC_MASK      GENMASK(7, 4)
0016 #define MICRON_STATUS_ECC_NO_BITFLIPS   (0 << 4)
0017 #define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
0018 #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
0019 #define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
0020 
0021 #define MICRON_CFG_CR           BIT(0)
0022 
0023 /*
0024  * As per datasheet, die selection is done by the 6th bit of Die
0025  * Select Register (Address 0xD0).
0026  */
0027 #define MICRON_DIE_SELECT_REG   0xD0
0028 
0029 #define MICRON_SELECT_DIE(x)    ((x) << 6)
0030 
0031 static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
0032         SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
0033         SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
0034         SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
0035         SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
0036         SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
0037         SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
0038 
0039 static SPINAND_OP_VARIANTS(x4_write_cache_variants,
0040         SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
0041         SPINAND_PROG_LOAD(true, 0, NULL, 0));
0042 
0043 static SPINAND_OP_VARIANTS(x4_update_cache_variants,
0044         SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
0045         SPINAND_PROG_LOAD(false, 0, NULL, 0));
0046 
0047 /* Micron  MT29F2G01AAAED Device */
0048 static SPINAND_OP_VARIANTS(x4_read_cache_variants,
0049                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
0050                SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
0051                SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
0052                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
0053 
0054 static SPINAND_OP_VARIANTS(x1_write_cache_variants,
0055                SPINAND_PROG_LOAD(true, 0, NULL, 0));
0056 
0057 static SPINAND_OP_VARIANTS(x1_update_cache_variants,
0058                SPINAND_PROG_LOAD(false, 0, NULL, 0));
0059 
0060 static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
0061                   struct mtd_oob_region *region)
0062 {
0063     if (section)
0064         return -ERANGE;
0065 
0066     region->offset = mtd->oobsize / 2;
0067     region->length = mtd->oobsize / 2;
0068 
0069     return 0;
0070 }
0071 
0072 static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
0073                    struct mtd_oob_region *region)
0074 {
0075     if (section)
0076         return -ERANGE;
0077 
0078     /* Reserve 2 bytes for the BBM. */
0079     region->offset = 2;
0080     region->length = (mtd->oobsize / 2) - 2;
0081 
0082     return 0;
0083 }
0084 
0085 static const struct mtd_ooblayout_ops micron_8_ooblayout = {
0086     .ecc = micron_8_ooblayout_ecc,
0087     .free = micron_8_ooblayout_free,
0088 };
0089 
0090 static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
0091                   struct mtd_oob_region *region)
0092 {
0093     struct spinand_device *spinand = mtd_to_spinand(mtd);
0094 
0095     if (section >= spinand->base.memorg.pagesize /
0096             mtd->ecc_step_size)
0097         return -ERANGE;
0098 
0099     region->offset = (section * 16) + 8;
0100     region->length = 8;
0101 
0102     return 0;
0103 }
0104 
0105 static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
0106                    struct mtd_oob_region *region)
0107 {
0108     struct spinand_device *spinand = mtd_to_spinand(mtd);
0109 
0110     if (section >= spinand->base.memorg.pagesize /
0111             mtd->ecc_step_size)
0112         return -ERANGE;
0113 
0114     if (section) {
0115         region->offset = 16 * section;
0116         region->length = 8;
0117     } else {
0118         /* section 0 has two bytes reserved for the BBM */
0119         region->offset = 2;
0120         region->length = 6;
0121     }
0122 
0123     return 0;
0124 }
0125 
0126 static const struct mtd_ooblayout_ops micron_4_ooblayout = {
0127     .ecc = micron_4_ooblayout_ecc,
0128     .free = micron_4_ooblayout_free,
0129 };
0130 
0131 static int micron_select_target(struct spinand_device *spinand,
0132                 unsigned int target)
0133 {
0134     struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
0135                               spinand->scratchbuf);
0136 
0137     if (target > 1)
0138         return -EINVAL;
0139 
0140     *spinand->scratchbuf = MICRON_SELECT_DIE(target);
0141 
0142     return spi_mem_exec_op(spinand->spimem, &op);
0143 }
0144 
0145 static int micron_8_ecc_get_status(struct spinand_device *spinand,
0146                    u8 status)
0147 {
0148     switch (status & MICRON_STATUS_ECC_MASK) {
0149     case STATUS_ECC_NO_BITFLIPS:
0150         return 0;
0151 
0152     case STATUS_ECC_UNCOR_ERROR:
0153         return -EBADMSG;
0154 
0155     case MICRON_STATUS_ECC_1TO3_BITFLIPS:
0156         return 3;
0157 
0158     case MICRON_STATUS_ECC_4TO6_BITFLIPS:
0159         return 6;
0160 
0161     case MICRON_STATUS_ECC_7TO8_BITFLIPS:
0162         return 8;
0163 
0164     default:
0165         break;
0166     }
0167 
0168     return -EINVAL;
0169 }
0170 
0171 static const struct spinand_info micron_spinand_table[] = {
0172     /* M79A 2Gb 3.3V */
0173     SPINAND_INFO("MT29F2G01ABAGD",
0174              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
0175              NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
0176              NAND_ECCREQ(8, 512),
0177              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0178                           &x4_write_cache_variants,
0179                           &x4_update_cache_variants),
0180              0,
0181              SPINAND_ECCINFO(&micron_8_ooblayout,
0182                      micron_8_ecc_get_status)),
0183     /* M79A 2Gb 1.8V */
0184     SPINAND_INFO("MT29F2G01ABBGD",
0185              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
0186              NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
0187              NAND_ECCREQ(8, 512),
0188              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0189                           &x4_write_cache_variants,
0190                           &x4_update_cache_variants),
0191              0,
0192              SPINAND_ECCINFO(&micron_8_ooblayout,
0193                      micron_8_ecc_get_status)),
0194     /* M78A 1Gb 3.3V */
0195     SPINAND_INFO("MT29F1G01ABAFD",
0196              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
0197              NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
0198              NAND_ECCREQ(8, 512),
0199              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0200                           &x4_write_cache_variants,
0201                           &x4_update_cache_variants),
0202              0,
0203              SPINAND_ECCINFO(&micron_8_ooblayout,
0204                      micron_8_ecc_get_status)),
0205     /* M78A 1Gb 1.8V */
0206     SPINAND_INFO("MT29F1G01ABAFD",
0207              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
0208              NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
0209              NAND_ECCREQ(8, 512),
0210              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0211                           &x4_write_cache_variants,
0212                           &x4_update_cache_variants),
0213              0,
0214              SPINAND_ECCINFO(&micron_8_ooblayout,
0215                      micron_8_ecc_get_status)),
0216     /* M79A 4Gb 3.3V */
0217     SPINAND_INFO("MT29F4G01ADAGD",
0218              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
0219              NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
0220              NAND_ECCREQ(8, 512),
0221              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0222                           &x4_write_cache_variants,
0223                           &x4_update_cache_variants),
0224              0,
0225              SPINAND_ECCINFO(&micron_8_ooblayout,
0226                      micron_8_ecc_get_status),
0227              SPINAND_SELECT_TARGET(micron_select_target)),
0228     /* M70A 4Gb 3.3V */
0229     SPINAND_INFO("MT29F4G01ABAFD",
0230              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
0231              NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
0232              NAND_ECCREQ(8, 512),
0233              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0234                           &x4_write_cache_variants,
0235                           &x4_update_cache_variants),
0236              SPINAND_HAS_CR_FEAT_BIT,
0237              SPINAND_ECCINFO(&micron_8_ooblayout,
0238                      micron_8_ecc_get_status)),
0239     /* M70A 4Gb 1.8V */
0240     SPINAND_INFO("MT29F4G01ABBFD",
0241              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
0242              NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
0243              NAND_ECCREQ(8, 512),
0244              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0245                           &x4_write_cache_variants,
0246                           &x4_update_cache_variants),
0247              SPINAND_HAS_CR_FEAT_BIT,
0248              SPINAND_ECCINFO(&micron_8_ooblayout,
0249                      micron_8_ecc_get_status)),
0250     /* M70A 8Gb 3.3V */
0251     SPINAND_INFO("MT29F8G01ADAFD",
0252              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
0253              NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
0254              NAND_ECCREQ(8, 512),
0255              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0256                           &x4_write_cache_variants,
0257                           &x4_update_cache_variants),
0258              SPINAND_HAS_CR_FEAT_BIT,
0259              SPINAND_ECCINFO(&micron_8_ooblayout,
0260                      micron_8_ecc_get_status),
0261              SPINAND_SELECT_TARGET(micron_select_target)),
0262     /* M70A 8Gb 1.8V */
0263     SPINAND_INFO("MT29F8G01ADBFD",
0264              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
0265              NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
0266              NAND_ECCREQ(8, 512),
0267              SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
0268                           &x4_write_cache_variants,
0269                           &x4_update_cache_variants),
0270              SPINAND_HAS_CR_FEAT_BIT,
0271              SPINAND_ECCINFO(&micron_8_ooblayout,
0272                      micron_8_ecc_get_status),
0273              SPINAND_SELECT_TARGET(micron_select_target)),
0274     /* M69A 2Gb 3.3V */
0275     SPINAND_INFO("MT29F2G01AAAED",
0276              SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
0277              NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
0278              NAND_ECCREQ(4, 512),
0279              SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
0280                           &x1_write_cache_variants,
0281                           &x1_update_cache_variants),
0282              0,
0283              SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
0284 };
0285 
0286 static int micron_spinand_init(struct spinand_device *spinand)
0287 {
0288     /*
0289      * M70A device series enable Continuous Read feature at Power-up,
0290      * which is not supported. Disable this bit to avoid any possible
0291      * failure.
0292      */
0293     if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
0294         return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
0295 
0296     return 0;
0297 }
0298 
0299 static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
0300     .init = micron_spinand_init,
0301 };
0302 
0303 const struct spinand_manufacturer micron_spinand_manufacturer = {
0304     .id = SPINAND_MFR_MICRON,
0305     .name = "Micron",
0306     .chips = micron_spinand_table,
0307     .nchips = ARRAY_SIZE(micron_spinand_table),
0308     .ops = &micron_spinand_manuf_ops,
0309 };