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); 23629a442cSBoris Brezillon struct nand_memory_organization *memorg; 24629a442cSBoris Brezillon 25629a442cSBoris Brezillon memorg = nanddev_get_memorg(&chip->base); 2693db446aSBoris Brezillon 2793db446aSBoris Brezillon /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 2893db446aSBoris Brezillon if (chip->id.len == 6 && !nand_is_slc(chip) && 2993db446aSBoris Brezillon chip->id.data[5] != 0x00) { 3093db446aSBoris Brezillon u8 extid = chip->id.data[3]; 3193db446aSBoris Brezillon 3293db446aSBoris Brezillon /* Get pagesize */ 33629a442cSBoris Brezillon memorg->pagesize = 2048 << (extid & 0x03); 34629a442cSBoris Brezillon mtd->writesize = memorg->pagesize; 3593db446aSBoris Brezillon 3693db446aSBoris Brezillon extid >>= 2; 3793db446aSBoris Brezillon 3893db446aSBoris Brezillon /* Get oobsize */ 3993db446aSBoris Brezillon switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 4093db446aSBoris Brezillon case 1: 41629a442cSBoris Brezillon memorg->oobsize = 128; 4293db446aSBoris Brezillon break; 4393db446aSBoris Brezillon case 2: 44629a442cSBoris Brezillon memorg->oobsize = 218; 4593db446aSBoris Brezillon break; 4693db446aSBoris Brezillon case 3: 47629a442cSBoris Brezillon memorg->oobsize = 400; 4893db446aSBoris Brezillon break; 4993db446aSBoris Brezillon case 4: 50629a442cSBoris Brezillon memorg->oobsize = 436; 5193db446aSBoris Brezillon break; 5293db446aSBoris Brezillon case 5: 53629a442cSBoris Brezillon memorg->oobsize = 512; 5493db446aSBoris Brezillon break; 5593db446aSBoris Brezillon case 6: 56629a442cSBoris Brezillon memorg->oobsize = 640; 5793db446aSBoris Brezillon break; 5893db446aSBoris Brezillon default: 5993db446aSBoris Brezillon /* 6093db446aSBoris Brezillon * We should never reach this case, but if that 6193db446aSBoris Brezillon * happens, this probably means Samsung decided to use 6293db446aSBoris Brezillon * a different extended ID format, and we should find 6393db446aSBoris Brezillon * a way to support it. 6493db446aSBoris Brezillon */ 6593db446aSBoris Brezillon WARN(1, "Invalid OOB size value"); 6693db446aSBoris Brezillon break; 6793db446aSBoris Brezillon } 6893db446aSBoris Brezillon 69629a442cSBoris Brezillon mtd->oobsize = memorg->oobsize; 70629a442cSBoris Brezillon 7193db446aSBoris Brezillon /* Get blocksize */ 7293db446aSBoris Brezillon extid >>= 2; 73629a442cSBoris Brezillon memorg->pages_per_eraseblock = (128 * 1024) << 74629a442cSBoris Brezillon (((extid >> 1) & 0x04) | 75629a442cSBoris Brezillon (extid & 0x03)) / 76629a442cSBoris Brezillon memorg->pagesize; 7793db446aSBoris Brezillon mtd->erasesize = (128 * 1024) << 7893db446aSBoris Brezillon (((extid >> 1) & 0x04) | (extid & 0x03)); 7993db446aSBoris Brezillon 8093db446aSBoris Brezillon /* Extract ECC requirements from 5th id byte*/ 8193db446aSBoris Brezillon extid = (chip->id.data[4] >> 4) & 0x07; 8293db446aSBoris Brezillon if (extid < 5) { 836a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 512; 846a1b66d6SBoris Brezillon chip->base.eccreq.strength = 1 << extid; 8593db446aSBoris Brezillon } else { 866a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 1024; 8793db446aSBoris Brezillon switch (extid) { 8893db446aSBoris Brezillon case 5: 896a1b66d6SBoris Brezillon chip->base.eccreq.strength = 24; 9093db446aSBoris Brezillon break; 9193db446aSBoris Brezillon case 6: 926a1b66d6SBoris Brezillon chip->base.eccreq.strength = 40; 9393db446aSBoris Brezillon break; 9493db446aSBoris Brezillon case 7: 956a1b66d6SBoris Brezillon chip->base.eccreq.strength = 60; 9693db446aSBoris Brezillon break; 9793db446aSBoris Brezillon default: 9893db446aSBoris Brezillon WARN(1, "Could not decode ECC info"); 996a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 0; 10093db446aSBoris Brezillon } 10193db446aSBoris Brezillon } 10293db446aSBoris Brezillon } else { 10393db446aSBoris Brezillon nand_decode_ext_id(chip); 10493db446aSBoris Brezillon 10593db446aSBoris Brezillon if (nand_is_slc(chip)) { 10693db446aSBoris Brezillon switch (chip->id.data[1]) { 10793db446aSBoris Brezillon /* K9F4G08U0D-S[I|C]B0(T00) */ 10893db446aSBoris Brezillon case 0xDC: 1096a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 512; 1106a1b66d6SBoris Brezillon chip->base.eccreq.strength = 1; 11193db446aSBoris Brezillon break; 11293db446aSBoris Brezillon 11393db446aSBoris Brezillon /* K9F1G08U0E 21nm chips do not support subpage write */ 11493db446aSBoris Brezillon case 0xF1: 11593db446aSBoris Brezillon if (chip->id.len > 4 && 11693db446aSBoris Brezillon (chip->id.data[4] & GENMASK(1, 0)) == 0x1) 11793db446aSBoris Brezillon chip->options |= NAND_NO_SUBPAGE_WRITE; 11893db446aSBoris Brezillon break; 11993db446aSBoris Brezillon default: 12093db446aSBoris Brezillon break; 12193db446aSBoris Brezillon } 12293db446aSBoris Brezillon } 12393db446aSBoris Brezillon } 12493db446aSBoris Brezillon } 12593db446aSBoris Brezillon 12693db446aSBoris Brezillon static int samsung_nand_init(struct nand_chip *chip) 12793db446aSBoris Brezillon { 12893db446aSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 12993db446aSBoris Brezillon 13093db446aSBoris Brezillon if (mtd->writesize > 512) 13193db446aSBoris Brezillon chip->options |= NAND_SAMSUNG_LP_OPTIONS; 13293db446aSBoris Brezillon 13393db446aSBoris Brezillon if (!nand_is_slc(chip)) 13404649ec1SFrieder Schrempf chip->options |= NAND_BBM_LASTPAGE; 13593db446aSBoris Brezillon else 136bb592548SFrieder Schrempf chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; 13793db446aSBoris Brezillon 13893db446aSBoris Brezillon return 0; 13993db446aSBoris Brezillon } 14093db446aSBoris Brezillon 14193db446aSBoris Brezillon const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 14293db446aSBoris Brezillon .detect = samsung_nand_decode_id, 14393db446aSBoris Brezillon .init = samsung_nand_init, 14493db446aSBoris Brezillon }; 145