uboot/drivers/mtd/nand/spi/macronix.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2018 Macronix
   4 *
   5 * Author: Boris Brezillon <boris.brezillon@bootlin.com>
   6 */
   7
   8#ifndef __UBOOT__
   9#include <malloc.h>
  10#include <linux/device.h>
  11#include <linux/kernel.h>
  12#endif
  13#include <linux/bug.h>
  14#include <linux/mtd/spinand.h>
  15
  16#define SPINAND_MFR_MACRONIX            0xC2
  17
  18static SPINAND_OP_VARIANTS(read_cache_variants,
  19                SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
  20                SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
  21                SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
  22                SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
  23
  24static SPINAND_OP_VARIANTS(write_cache_variants,
  25                SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
  26                SPINAND_PROG_LOAD(true, 0, NULL, 0));
  27
  28static SPINAND_OP_VARIANTS(update_cache_variants,
  29                SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
  30                SPINAND_PROG_LOAD(false, 0, NULL, 0));
  31
  32static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section,
  33                                      struct mtd_oob_region *region)
  34{
  35        return -ERANGE;
  36}
  37
  38static int mx35lfxge4ab_ooblayout_free(struct mtd_info *mtd, int section,
  39                                       struct mtd_oob_region *region)
  40{
  41        if (section)
  42                return -ERANGE;
  43
  44        region->offset = 2;
  45        region->length = mtd->oobsize - 2;
  46
  47        return 0;
  48}
  49
  50static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = {
  51        .ecc = mx35lfxge4ab_ooblayout_ecc,
  52        .rfree = mx35lfxge4ab_ooblayout_free,
  53};
  54
  55static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
  56{
  57        struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1),
  58                                          SPI_MEM_OP_NO_ADDR,
  59                                          SPI_MEM_OP_DUMMY(1, 1),
  60                                          SPI_MEM_OP_DATA_IN(1, eccsr, 1));
  61
  62        return spi_mem_exec_op(spinand->slave, &op);
  63}
  64
  65static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
  66                                       u8 status)
  67{
  68        struct nand_device *nand = spinand_to_nand(spinand);
  69        u8 eccsr;
  70
  71        switch (status & STATUS_ECC_MASK) {
  72        case STATUS_ECC_NO_BITFLIPS:
  73                return 0;
  74
  75        case STATUS_ECC_UNCOR_ERROR:
  76                return -EBADMSG;
  77
  78        case STATUS_ECC_HAS_BITFLIPS:
  79                /*
  80                 * Let's try to retrieve the real maximum number of bitflips
  81                 * in order to avoid forcing the wear-leveling layer to move
  82                 * data around if it's not necessary.
  83                 */
  84                if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr))
  85                        return nand->eccreq.strength;
  86
  87                if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr))
  88                        return nand->eccreq.strength;
  89
  90                return eccsr;
  91
  92        default:
  93                break;
  94        }
  95
  96        return -EINVAL;
  97}
  98
  99static const struct spinand_info macronix_spinand_table[] = {
 100        SPINAND_INFO("MX35LF1GE4AB", 0x12,
 101                     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
 102                     NAND_ECCREQ(4, 512),
 103                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 104                                              &write_cache_variants,
 105                                              &update_cache_variants),
 106                     SPINAND_HAS_QE_BIT,
 107                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
 108                                     mx35lf1ge4ab_ecc_get_status)),
 109        SPINAND_INFO("MX35LF2GE4AB", 0x22,
 110                     NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
 111                     NAND_ECCREQ(4, 512),
 112                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
 113                                              &write_cache_variants,
 114                                              &update_cache_variants),
 115                     SPINAND_HAS_QE_BIT,
 116                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
 117};
 118
 119static int macronix_spinand_detect(struct spinand_device *spinand)
 120{
 121        u8 *id = spinand->id.data;
 122        int ret;
 123
 124        /*
 125         * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
 126         * raw_id is garbage.
 127         */
 128        if (id[1] != SPINAND_MFR_MACRONIX)
 129                return 0;
 130
 131        ret = spinand_match_and_init(spinand, macronix_spinand_table,
 132                                     ARRAY_SIZE(macronix_spinand_table),
 133                                     id[2]);
 134        if (ret)
 135                return ret;
 136
 137        return 1;
 138}
 139
 140static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
 141        .detect = macronix_spinand_detect,
 142};
 143
 144const struct spinand_manufacturer macronix_spinand_manufacturer = {
 145        .id = SPINAND_MFR_MACRONIX,
 146        .name = "Macronix",
 147        .ops = &macronix_spinand_manuf_ops,
 148};
 149