uboot/drivers/mtd/nand/spi/micron.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2016-2017 Micron Technology, Inc.
   4 *
   5 * Authors:
   6 *      Peter Pan <peterpandong@micron.com>
   7 */
   8
   9#ifndef __UBOOT__
  10#include <malloc.h>
  11#include <linux/device.h>
  12#include <linux/kernel.h>
  13#endif
  14#include <linux/bitops.h>
  15#include <linux/mtd/spinand.h>
  16
  17#define SPINAND_MFR_MICRON              0x2c
  18
  19#define MICRON_STATUS_ECC_MASK          GENMASK(7, 4)
  20#define MICRON_STATUS_ECC_NO_BITFLIPS   (0 << 4)
  21#define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
  22#define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
  23#define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
  24
  25#define MICRON_CFG_CR                   BIT(0)
  26
  27/*
  28 * As per datasheet, die selection is done by the 6th bit of Die
  29 * Select Register (Address 0xD0).
  30 */
  31#define MICRON_DIE_SELECT_REG   0xD0
  32
  33#define MICRON_SELECT_DIE(x)    ((x) << 6)
  34
  35static SPINAND_OP_VARIANTS(read_cache_variants,
  36                SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
  37                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
  38                SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
  39                SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
  40                SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
  41                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
  42
  43static SPINAND_OP_VARIANTS(write_cache_variants,
  44                SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
  45                SPINAND_PROG_LOAD(true, 0, NULL, 0));
  46
  47static SPINAND_OP_VARIANTS(update_cache_variants,
  48                SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
  49                SPINAND_PROG_LOAD(false, 0, NULL, 0));
  50
  51static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
  52                                  struct mtd_oob_region *region)
  53{
  54        if (section)
  55                return -ERANGE;
  56
  57        region->offset = mtd->oobsize / 2;
  58        region->length = mtd->oobsize / 2;
  59
  60        return 0;
  61}
  62
  63static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
  64                                   struct mtd_oob_region *region)
  65{
  66        if (section)
  67                return -ERANGE;
  68
  69        /* Reserve 2 bytes for the BBM. */
  70        region->offset = 2;
  71        region->length = (mtd->oobsize / 2) - 2;
  72
  73        return 0;
  74}
  75
  76static const struct mtd_ooblayout_ops micron_8_ooblayout = {
  77        .ecc = micron_8_ooblayout_ecc,
  78        .rfree = micron_8_ooblayout_free,
  79};
  80
  81static int micron_select_target(struct spinand_device *spinand,
  82                                unsigned int target)
  83{
  84        struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
  85                                                      spinand->scratchbuf);
  86
  87        if (target > 1)
  88                return -EINVAL;
  89
  90        *spinand->scratchbuf = MICRON_SELECT_DIE(target);
  91
  92        return spi_mem_exec_op(spinand->slave, &op);
  93}
  94
  95static int micron_8_ecc_get_status(struct spinand_device *spinand,
  96                                   u8 status)
  97{
  98        switch (status & MICRON_STATUS_ECC_MASK) {
  99        case STATUS_ECC_NO_BITFLIPS:
 100                return 0;
 101
 102        case STATUS_ECC_UNCOR_ERROR:
 103                return -EBADMSG;
 104
 105        case MICRON_STATUS_ECC_1TO3_BITFLIPS:
 106                return 3;
 107
 108        case MICRON_STATUS_ECC_4TO6_BITFLIPS:
 109                return 6;
 110
 111        case MICRON_STATUS_ECC_7TO8_BITFLIPS:
 112                return 8;
 113
 114        default:
 115                break;
 116        }
 117
 118        return -EINVAL;
 119}
 120
 121static const struct spinand_info micron_spinand_table[] = {
 122        /* M79A 2Gb 3.3V */
 123        SPINAND_INFO("MT29F2G01ABAGD", 0x24,
 124                     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
 125                     NAND_ECCREQ(8, 512),
 126                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 127                                              &write_cache_variants,
 128                                              &update_cache_variants),
 129                     0,
 130                     SPINAND_ECCINFO(&micron_8_ooblayout,
 131                                     micron_8_ecc_get_status)),
 132        /* M79A 2Gb 1.8V */
 133        SPINAND_INFO("MT29F2G01ABBGD", 0x25,
 134                     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
 135                     NAND_ECCREQ(8, 512),
 136                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 137                                              &write_cache_variants,
 138                                              &update_cache_variants),
 139                     0,
 140                     SPINAND_ECCINFO(&micron_8_ooblayout,
 141                                     micron_8_ecc_get_status)),
 142        /* M78A 1Gb 3.3V */
 143        SPINAND_INFO("MT29F1G01ABAFD", 0x14,
 144                     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 145                     NAND_ECCREQ(8, 512),
 146                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 147                                              &write_cache_variants,
 148                                              &update_cache_variants),
 149                     0,
 150                     SPINAND_ECCINFO(&micron_8_ooblayout,
 151                                     micron_8_ecc_get_status)),
 152        /* M78A 1Gb 1.8V */
 153        SPINAND_INFO("MT29F1G01ABAFD", 0x15,
 154                     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
 155                     NAND_ECCREQ(8, 512),
 156                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 157                                              &write_cache_variants,
 158                                              &update_cache_variants),
 159                     0,
 160                     SPINAND_ECCINFO(&micron_8_ooblayout,
 161                                     micron_8_ecc_get_status)),
 162        /* M79A 4Gb 3.3V */
 163        SPINAND_INFO("MT29F4G01ADAGD", 0x36,
 164                     NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 2),
 165                     NAND_ECCREQ(8, 512),
 166                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 167                                              &write_cache_variants,
 168                                              &update_cache_variants),
 169                     0,
 170                     SPINAND_ECCINFO(&micron_8_ooblayout,
 171                                     micron_8_ecc_get_status),
 172                     SPINAND_SELECT_TARGET(micron_select_target)),
 173        /* M70A 4Gb 3.3V */
 174        SPINAND_INFO("MT29F4G01ABAFD", 0x34,
 175                     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 176                     NAND_ECCREQ(8, 512),
 177                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 178                                              &write_cache_variants,
 179                                              &update_cache_variants),
 180                     SPINAND_HAS_CR_FEAT_BIT,
 181                     SPINAND_ECCINFO(&micron_8_ooblayout,
 182                                     micron_8_ecc_get_status)),
 183        /* M70A 4Gb 1.8V */
 184        SPINAND_INFO("MT29F4G01ABBFD", 0x35,
 185                     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
 186                     NAND_ECCREQ(8, 512),
 187                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 188                                              &write_cache_variants,
 189                                              &update_cache_variants),
 190                     SPINAND_HAS_CR_FEAT_BIT,
 191                     SPINAND_ECCINFO(&micron_8_ooblayout,
 192                                     micron_8_ecc_get_status)),
 193        /* M70A 8Gb 3.3V */
 194        SPINAND_INFO("MT29F8G01ADAFD", 0x46,
 195                     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
 196                     NAND_ECCREQ(8, 512),
 197                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 198                                              &write_cache_variants,
 199                                              &update_cache_variants),
 200                     SPINAND_HAS_CR_FEAT_BIT,
 201                     SPINAND_ECCINFO(&micron_8_ooblayout,
 202                                     micron_8_ecc_get_status),
 203                     SPINAND_SELECT_TARGET(micron_select_target)),
 204        /* M70A 8Gb 1.8V */
 205        SPINAND_INFO("MT29F8G01ADBFD", 0x47,
 206                     NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 2),
 207                     NAND_ECCREQ(8, 512),
 208                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 209                                              &write_cache_variants,
 210                                              &update_cache_variants),
 211                     SPINAND_HAS_CR_FEAT_BIT,
 212                     SPINAND_ECCINFO(&micron_8_ooblayout,
 213                                     micron_8_ecc_get_status),
 214                     SPINAND_SELECT_TARGET(micron_select_target)),
 215};
 216
 217static int micron_spinand_detect(struct spinand_device *spinand)
 218{
 219        u8 *id = spinand->id.data;
 220        int ret;
 221
 222        /*
 223         * Micron SPI NAND read ID need a dummy byte,
 224         * so the first byte in raw_id is dummy.
 225         */
 226        if (id[1] != SPINAND_MFR_MICRON)
 227                return 0;
 228
 229        ret = spinand_match_and_init(spinand, micron_spinand_table,
 230                                     ARRAY_SIZE(micron_spinand_table), id[2]);
 231        if (ret)
 232                return ret;
 233
 234        return 1;
 235}
 236
 237static int micron_spinand_init(struct spinand_device *spinand)
 238{
 239        /*
 240         * M70A device series enable Continuous Read feature at Power-up,
 241         * which is not supported. Disable this bit to avoid any possible
 242         * failure.
 243         */
 244        if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
 245                return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
 246
 247        return 0;
 248}
 249
 250static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
 251        .detect = micron_spinand_detect,
 252        .init = micron_spinand_init,
 253};
 254
 255const struct spinand_manufacturer micron_spinand_manufacturer = {
 256        .id = SPINAND_MFR_MICRON,
 257        .name = "Micron",
 258        .ops = &micron_spinand_manuf_ops,
 259};
 260