1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2c51d0ac5SBoris Brezillon /* 3c51d0ac5SBoris Brezillon * Copyright (C) 2017 Free Electrons 4c51d0ac5SBoris Brezillon * Copyright (C) 2017 NextThing Co 5c51d0ac5SBoris Brezillon * 6c51d0ac5SBoris Brezillon * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 7c51d0ac5SBoris Brezillon */ 8c51d0ac5SBoris Brezillon 9348d56a8SBoris Brezillon #include "internals.h" 10c51d0ac5SBoris Brezillon 11c51d0ac5SBoris Brezillon static void samsung_nand_decode_id(struct nand_chip *chip) 12c51d0ac5SBoris Brezillon { 13c51d0ac5SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 14629a442cSBoris Brezillon struct nand_memory_organization *memorg; 15629a442cSBoris Brezillon 16629a442cSBoris Brezillon memorg = nanddev_get_memorg(&chip->base); 17c51d0ac5SBoris Brezillon 18c51d0ac5SBoris Brezillon /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 19c51d0ac5SBoris Brezillon if (chip->id.len == 6 && !nand_is_slc(chip) && 20c51d0ac5SBoris Brezillon chip->id.data[5] != 0x00) { 21c51d0ac5SBoris Brezillon u8 extid = chip->id.data[3]; 22c51d0ac5SBoris Brezillon 23c51d0ac5SBoris Brezillon /* Get pagesize */ 24629a442cSBoris Brezillon memorg->pagesize = 2048 << (extid & 0x03); 25629a442cSBoris Brezillon mtd->writesize = memorg->pagesize; 26c51d0ac5SBoris Brezillon 27c51d0ac5SBoris Brezillon extid >>= 2; 28c51d0ac5SBoris Brezillon 29c51d0ac5SBoris Brezillon /* Get oobsize */ 30c51d0ac5SBoris Brezillon switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 31c51d0ac5SBoris Brezillon case 1: 32629a442cSBoris Brezillon memorg->oobsize = 128; 33c51d0ac5SBoris Brezillon break; 34c51d0ac5SBoris Brezillon case 2: 35629a442cSBoris Brezillon memorg->oobsize = 218; 36c51d0ac5SBoris Brezillon break; 37c51d0ac5SBoris Brezillon case 3: 38629a442cSBoris Brezillon memorg->oobsize = 400; 39c51d0ac5SBoris Brezillon break; 40c51d0ac5SBoris Brezillon case 4: 41629a442cSBoris Brezillon memorg->oobsize = 436; 42c51d0ac5SBoris Brezillon break; 43c51d0ac5SBoris Brezillon case 5: 44629a442cSBoris Brezillon memorg->oobsize = 512; 45c51d0ac5SBoris Brezillon break; 46c51d0ac5SBoris Brezillon case 6: 47629a442cSBoris Brezillon memorg->oobsize = 640; 48c51d0ac5SBoris Brezillon break; 49c51d0ac5SBoris Brezillon default: 50c51d0ac5SBoris Brezillon /* 51c51d0ac5SBoris Brezillon * We should never reach this case, but if that 52c51d0ac5SBoris Brezillon * happens, this probably means Samsung decided to use 53c51d0ac5SBoris Brezillon * a different extended ID format, and we should find 54c51d0ac5SBoris Brezillon * a way to support it. 55c51d0ac5SBoris Brezillon */ 56c51d0ac5SBoris Brezillon WARN(1, "Invalid OOB size value"); 57c51d0ac5SBoris Brezillon break; 58c51d0ac5SBoris Brezillon } 59c51d0ac5SBoris Brezillon 60629a442cSBoris Brezillon mtd->oobsize = memorg->oobsize; 61629a442cSBoris Brezillon 62c51d0ac5SBoris Brezillon /* Get blocksize */ 63c51d0ac5SBoris Brezillon extid >>= 2; 64629a442cSBoris Brezillon memorg->pages_per_eraseblock = (128 * 1024) << 65629a442cSBoris Brezillon (((extid >> 1) & 0x04) | 66629a442cSBoris Brezillon (extid & 0x03)) / 67629a442cSBoris Brezillon memorg->pagesize; 68c51d0ac5SBoris Brezillon mtd->erasesize = (128 * 1024) << 69c51d0ac5SBoris Brezillon (((extid >> 1) & 0x04) | (extid & 0x03)); 708fc82d45SHans de Goede 718fc82d45SHans de Goede /* Extract ECC requirements from 5th id byte*/ 728fc82d45SHans de Goede extid = (chip->id.data[4] >> 4) & 0x07; 738fc82d45SHans de Goede if (extid < 5) { 746a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 512; 756a1b66d6SBoris Brezillon chip->base.eccreq.strength = 1 << extid; 768fc82d45SHans de Goede } else { 776a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 1024; 788fc82d45SHans de Goede switch (extid) { 798fc82d45SHans de Goede case 5: 806a1b66d6SBoris Brezillon chip->base.eccreq.strength = 24; 818fc82d45SHans de Goede break; 828fc82d45SHans de Goede case 6: 836a1b66d6SBoris Brezillon chip->base.eccreq.strength = 40; 848fc82d45SHans de Goede break; 858fc82d45SHans de Goede case 7: 866a1b66d6SBoris Brezillon chip->base.eccreq.strength = 60; 878fc82d45SHans de Goede break; 88d2419790SBrian Norris default: 89d2419790SBrian Norris WARN(1, "Could not decode ECC info"); 906a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 0; 918fc82d45SHans de Goede } 928fc82d45SHans de Goede } 93c51d0ac5SBoris Brezillon } else { 94c51d0ac5SBoris Brezillon nand_decode_ext_id(chip); 95707d8154SMiquel Raynal 9609ec417bSLadislav Michl if (nand_is_slc(chip)) { 9709ec417bSLadislav Michl switch (chip->id.data[1]) { 9809ec417bSLadislav Michl /* K9F4G08U0D-S[I|C]B0(T00) */ 9909ec417bSLadislav Michl case 0xDC: 1006a1b66d6SBoris Brezillon chip->base.eccreq.step_size = 512; 1016a1b66d6SBoris Brezillon chip->base.eccreq.strength = 1; 10209ec417bSLadislav Michl break; 10309ec417bSLadislav Michl 10409ec417bSLadislav Michl /* K9F1G08U0E 21nm chips do not support subpage write */ 10509ec417bSLadislav Michl case 0xF1: 10609ec417bSLadislav Michl if (chip->id.len > 4 && 10709ec417bSLadislav Michl (chip->id.data[4] & GENMASK(1, 0)) == 0x1) 10809ec417bSLadislav Michl chip->options |= NAND_NO_SUBPAGE_WRITE; 10909ec417bSLadislav Michl break; 11009ec417bSLadislav Michl default: 11109ec417bSLadislav Michl break; 11209ec417bSLadislav Michl } 113707d8154SMiquel Raynal } 114c51d0ac5SBoris Brezillon } 115c51d0ac5SBoris Brezillon } 116c51d0ac5SBoris Brezillon 117c51d0ac5SBoris Brezillon static int samsung_nand_init(struct nand_chip *chip) 118c51d0ac5SBoris Brezillon { 119c51d0ac5SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 120c51d0ac5SBoris Brezillon 121c51d0ac5SBoris Brezillon if (mtd->writesize > 512) 122c51d0ac5SBoris Brezillon chip->options |= NAND_SAMSUNG_LP_OPTIONS; 123c51d0ac5SBoris Brezillon 124c51d0ac5SBoris Brezillon if (!nand_is_slc(chip)) 12504649ec1SFrieder Schrempf chip->options |= NAND_BBM_LASTPAGE; 126c51d0ac5SBoris Brezillon else 127bb592548SFrieder Schrempf chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; 128c51d0ac5SBoris Brezillon 129c51d0ac5SBoris Brezillon return 0; 130c51d0ac5SBoris Brezillon } 131c51d0ac5SBoris Brezillon 132c51d0ac5SBoris Brezillon const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 133c51d0ac5SBoris Brezillon .detect = samsung_nand_decode_id, 134c51d0ac5SBoris Brezillon .init = samsung_nand_init, 135c51d0ac5SBoris Brezillon }; 136