linux/drivers/mtd/nand/raw/nand_samsung.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2017 Free Electrons
   4 * Copyright (C) 2017 NextThing Co
   5 *
   6 * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
   7 */
   8
   9#include "internals.h"
  10
  11static void samsung_nand_decode_id(struct nand_chip *chip)
  12{
  13        struct mtd_info *mtd = nand_to_mtd(chip);
  14        struct nand_memory_organization *memorg;
  15
  16        memorg = nanddev_get_memorg(&chip->base);
  17
  18        /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
  19        if (chip->id.len == 6 && !nand_is_slc(chip) &&
  20            chip->id.data[5] != 0x00) {
  21                u8 extid = chip->id.data[3];
  22
  23                /* Get pagesize */
  24                memorg->pagesize = 2048 << (extid & 0x03);
  25                mtd->writesize = memorg->pagesize;
  26
  27                extid >>= 2;
  28
  29                /* Get oobsize */
  30                switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
  31                case 1:
  32                        memorg->oobsize = 128;
  33                        break;
  34                case 2:
  35                        memorg->oobsize = 218;
  36                        break;
  37                case 3:
  38                        memorg->oobsize = 400;
  39                        break;
  40                case 4:
  41                        memorg->oobsize = 436;
  42                        break;
  43                case 5:
  44                        memorg->oobsize = 512;
  45                        break;
  46                case 6:
  47                        memorg->oobsize = 640;
  48                        break;
  49                default:
  50                        /*
  51                         * We should never reach this case, but if that
  52                         * happens, this probably means Samsung decided to use
  53                         * a different extended ID format, and we should find
  54                         * a way to support it.
  55                         */
  56                        WARN(1, "Invalid OOB size value");
  57                        break;
  58                }
  59
  60                mtd->oobsize = memorg->oobsize;
  61
  62                /* Get blocksize */
  63                extid >>= 2;
  64                memorg->pages_per_eraseblock = (128 * 1024) <<
  65                                               (((extid >> 1) & 0x04) |
  66                                                (extid & 0x03)) /
  67                                               memorg->pagesize;
  68                mtd->erasesize = (128 * 1024) <<
  69                                 (((extid >> 1) & 0x04) | (extid & 0x03));
  70
  71                /* Extract ECC requirements from 5th id byte*/
  72                extid = (chip->id.data[4] >> 4) & 0x07;
  73                if (extid < 5) {
  74                        chip->base.eccreq.step_size = 512;
  75                        chip->base.eccreq.strength = 1 << extid;
  76                } else {
  77                        chip->base.eccreq.step_size = 1024;
  78                        switch (extid) {
  79                        case 5:
  80                                chip->base.eccreq.strength = 24;
  81                                break;
  82                        case 6:
  83                                chip->base.eccreq.strength = 40;
  84                                break;
  85                        case 7:
  86                                chip->base.eccreq.strength = 60;
  87                                break;
  88                        default:
  89                                WARN(1, "Could not decode ECC info");
  90                                chip->base.eccreq.step_size = 0;
  91                        }
  92                }
  93        } else {
  94                nand_decode_ext_id(chip);
  95
  96                if (nand_is_slc(chip)) {
  97                        switch (chip->id.data[1]) {
  98                        /* K9F4G08U0D-S[I|C]B0(T00) */
  99                        case 0xDC:
 100                                chip->base.eccreq.step_size = 512;
 101                                chip->base.eccreq.strength = 1;
 102                                break;
 103
 104                        /* K9F1G08U0E 21nm chips do not support subpage write */
 105                        case 0xF1:
 106                                if (chip->id.len > 4 &&
 107                                    (chip->id.data[4] & GENMASK(1, 0)) == 0x1)
 108                                        chip->options |= NAND_NO_SUBPAGE_WRITE;
 109                                break;
 110                        default:
 111                                break;
 112                        }
 113                }
 114        }
 115}
 116
 117static int samsung_nand_init(struct nand_chip *chip)
 118{
 119        struct mtd_info *mtd = nand_to_mtd(chip);
 120
 121        if (mtd->writesize > 512)
 122                chip->options |= NAND_SAMSUNG_LP_OPTIONS;
 123
 124        if (!nand_is_slc(chip))
 125                chip->options |= NAND_BBM_LASTPAGE;
 126        else
 127                chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
 128
 129        return 0;
 130}
 131
 132const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
 133        .detect = samsung_nand_decode_id,
 134        .init = samsung_nand_init,
 135};
 136