193db446aSBoris Brezillon /* 293db446aSBoris Brezillon * Copyright (C) 2017 Free Electrons 393db446aSBoris Brezillon * Copyright (C) 2017 NextThing Co 493db446aSBoris Brezillon * 593db446aSBoris Brezillon * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 693db446aSBoris Brezillon * 793db446aSBoris Brezillon * This program is free software; you can redistribute it and/or modify 893db446aSBoris Brezillon * it under the terms of the GNU General Public License as published by 993db446aSBoris Brezillon * the Free Software Foundation; either version 2 of the License, or 1093db446aSBoris Brezillon * (at your option) any later version. 1193db446aSBoris Brezillon * 1293db446aSBoris Brezillon * This program is distributed in the hope that it will be useful, 1393db446aSBoris Brezillon * but WITHOUT ANY WARRANTY; without even the implied warranty of 1493db446aSBoris Brezillon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1593db446aSBoris Brezillon * GNU General Public License for more details. 1693db446aSBoris Brezillon */ 1793db446aSBoris Brezillon 18348d56a8SBoris Brezillon #include "internals.h" 1993db446aSBoris Brezillon 2093db446aSBoris Brezillon static void samsung_nand_decode_id(struct nand_chip *chip) 2193db446aSBoris Brezillon { 2293db446aSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 2393db446aSBoris Brezillon 2493db446aSBoris Brezillon /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 2593db446aSBoris Brezillon if (chip->id.len == 6 && !nand_is_slc(chip) && 2693db446aSBoris Brezillon chip->id.data[5] != 0x00) { 2793db446aSBoris Brezillon u8 extid = chip->id.data[3]; 2893db446aSBoris Brezillon 2993db446aSBoris Brezillon /* Get pagesize */ 3093db446aSBoris Brezillon mtd->writesize = 2048 << (extid & 0x03); 3193db446aSBoris Brezillon 3293db446aSBoris Brezillon extid >>= 2; 3393db446aSBoris Brezillon 3493db446aSBoris Brezillon /* Get oobsize */ 3593db446aSBoris Brezillon switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 3693db446aSBoris Brezillon case 1: 3793db446aSBoris Brezillon mtd->oobsize = 128; 3893db446aSBoris Brezillon break; 3993db446aSBoris Brezillon case 2: 4093db446aSBoris Brezillon mtd->oobsize = 218; 4193db446aSBoris Brezillon break; 4293db446aSBoris Brezillon case 3: 4393db446aSBoris Brezillon mtd->oobsize = 400; 4493db446aSBoris Brezillon break; 4593db446aSBoris Brezillon case 4: 4693db446aSBoris Brezillon mtd->oobsize = 436; 4793db446aSBoris Brezillon break; 4893db446aSBoris Brezillon case 5: 4993db446aSBoris Brezillon mtd->oobsize = 512; 5093db446aSBoris Brezillon break; 5193db446aSBoris Brezillon case 6: 5293db446aSBoris Brezillon mtd->oobsize = 640; 5393db446aSBoris Brezillon break; 5493db446aSBoris Brezillon default: 5593db446aSBoris Brezillon /* 5693db446aSBoris Brezillon * We should never reach this case, but if that 5793db446aSBoris Brezillon * happens, this probably means Samsung decided to use 5893db446aSBoris Brezillon * a different extended ID format, and we should find 5993db446aSBoris Brezillon * a way to support it. 6093db446aSBoris Brezillon */ 6193db446aSBoris Brezillon WARN(1, "Invalid OOB size value"); 6293db446aSBoris Brezillon break; 6393db446aSBoris Brezillon } 6493db446aSBoris Brezillon 6593db446aSBoris Brezillon /* Get blocksize */ 6693db446aSBoris Brezillon extid >>= 2; 6793db446aSBoris Brezillon mtd->erasesize = (128 * 1024) << 6893db446aSBoris Brezillon (((extid >> 1) & 0x04) | (extid & 0x03)); 6993db446aSBoris Brezillon 7093db446aSBoris Brezillon /* Extract ECC requirements from 5th id byte*/ 7193db446aSBoris Brezillon extid = (chip->id.data[4] >> 4) & 0x07; 7293db446aSBoris Brezillon if (extid < 5) { 7393db446aSBoris Brezillon chip->ecc_step_ds = 512; 7493db446aSBoris Brezillon chip->ecc_strength_ds = 1 << extid; 7593db446aSBoris Brezillon } else { 7693db446aSBoris Brezillon chip->ecc_step_ds = 1024; 7793db446aSBoris Brezillon switch (extid) { 7893db446aSBoris Brezillon case 5: 7993db446aSBoris Brezillon chip->ecc_strength_ds = 24; 8093db446aSBoris Brezillon break; 8193db446aSBoris Brezillon case 6: 8293db446aSBoris Brezillon chip->ecc_strength_ds = 40; 8393db446aSBoris Brezillon break; 8493db446aSBoris Brezillon case 7: 8593db446aSBoris Brezillon chip->ecc_strength_ds = 60; 8693db446aSBoris Brezillon break; 8793db446aSBoris Brezillon default: 8893db446aSBoris Brezillon WARN(1, "Could not decode ECC info"); 8993db446aSBoris Brezillon chip->ecc_step_ds = 0; 9093db446aSBoris Brezillon } 9193db446aSBoris Brezillon } 9293db446aSBoris Brezillon } else { 9393db446aSBoris Brezillon nand_decode_ext_id(chip); 9493db446aSBoris Brezillon 9593db446aSBoris Brezillon if (nand_is_slc(chip)) { 9693db446aSBoris Brezillon switch (chip->id.data[1]) { 9793db446aSBoris Brezillon /* K9F4G08U0D-S[I|C]B0(T00) */ 9893db446aSBoris Brezillon case 0xDC: 9993db446aSBoris Brezillon chip->ecc_step_ds = 512; 10093db446aSBoris Brezillon chip->ecc_strength_ds = 1; 10193db446aSBoris Brezillon break; 10293db446aSBoris Brezillon 10393db446aSBoris Brezillon /* K9F1G08U0E 21nm chips do not support subpage write */ 10493db446aSBoris Brezillon case 0xF1: 10593db446aSBoris Brezillon if (chip->id.len > 4 && 10693db446aSBoris Brezillon (chip->id.data[4] & GENMASK(1, 0)) == 0x1) 10793db446aSBoris Brezillon chip->options |= NAND_NO_SUBPAGE_WRITE; 10893db446aSBoris Brezillon break; 10993db446aSBoris Brezillon default: 11093db446aSBoris Brezillon break; 11193db446aSBoris Brezillon } 11293db446aSBoris Brezillon } 11393db446aSBoris Brezillon } 11493db446aSBoris Brezillon } 11593db446aSBoris Brezillon 11693db446aSBoris Brezillon static int samsung_nand_init(struct nand_chip *chip) 11793db446aSBoris Brezillon { 11893db446aSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 11993db446aSBoris Brezillon 12093db446aSBoris Brezillon if (mtd->writesize > 512) 12193db446aSBoris Brezillon chip->options |= NAND_SAMSUNG_LP_OPTIONS; 12293db446aSBoris Brezillon 12393db446aSBoris Brezillon if (!nand_is_slc(chip)) 12493db446aSBoris Brezillon chip->bbt_options |= NAND_BBT_SCANLASTPAGE; 12593db446aSBoris Brezillon else 12693db446aSBoris Brezillon chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; 12793db446aSBoris Brezillon 12893db446aSBoris Brezillon return 0; 12993db446aSBoris Brezillon } 13093db446aSBoris Brezillon 13193db446aSBoris Brezillon const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 13293db446aSBoris Brezillon .detect = samsung_nand_decode_id, 13393db446aSBoris Brezillon .init = samsung_nand_init, 13493db446aSBoris Brezillon }; 135