18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Free Electrons 48c2ecf20Sopenharmony_ci * Copyright (C) 2017 NextThing Co 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "internals.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic void samsung_nand_decode_id(struct nand_chip *chip) 128c2ecf20Sopenharmony_ci{ 138c2ecf20Sopenharmony_ci struct nand_device *base = &chip->base; 148c2ecf20Sopenharmony_ci struct nand_ecc_props requirements = {}; 158c2ecf20Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 168c2ecf20Sopenharmony_ci struct nand_memory_organization *memorg; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci memorg = nanddev_get_memorg(&chip->base); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 218c2ecf20Sopenharmony_ci if (chip->id.len == 6 && !nand_is_slc(chip) && 228c2ecf20Sopenharmony_ci chip->id.data[5] != 0x00) { 238c2ecf20Sopenharmony_ci u8 extid = chip->id.data[3]; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci /* Get pagesize */ 268c2ecf20Sopenharmony_ci memorg->pagesize = 2048 << (extid & 0x03); 278c2ecf20Sopenharmony_ci mtd->writesize = memorg->pagesize; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci extid >>= 2; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* Get oobsize */ 328c2ecf20Sopenharmony_ci switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 338c2ecf20Sopenharmony_ci case 1: 348c2ecf20Sopenharmony_ci memorg->oobsize = 128; 358c2ecf20Sopenharmony_ci break; 368c2ecf20Sopenharmony_ci case 2: 378c2ecf20Sopenharmony_ci memorg->oobsize = 218; 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci case 3: 408c2ecf20Sopenharmony_ci memorg->oobsize = 400; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci case 4: 438c2ecf20Sopenharmony_ci memorg->oobsize = 436; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case 5: 468c2ecf20Sopenharmony_ci memorg->oobsize = 512; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci case 6: 498c2ecf20Sopenharmony_ci memorg->oobsize = 640; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci default: 528c2ecf20Sopenharmony_ci /* 538c2ecf20Sopenharmony_ci * We should never reach this case, but if that 548c2ecf20Sopenharmony_ci * happens, this probably means Samsung decided to use 558c2ecf20Sopenharmony_ci * a different extended ID format, and we should find 568c2ecf20Sopenharmony_ci * a way to support it. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci WARN(1, "Invalid OOB size value"); 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci mtd->oobsize = memorg->oobsize; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Get blocksize */ 658c2ecf20Sopenharmony_ci extid >>= 2; 668c2ecf20Sopenharmony_ci memorg->pages_per_eraseblock = (128 * 1024) << 678c2ecf20Sopenharmony_ci (((extid >> 1) & 0x04) | 688c2ecf20Sopenharmony_ci (extid & 0x03)) / 698c2ecf20Sopenharmony_ci memorg->pagesize; 708c2ecf20Sopenharmony_ci mtd->erasesize = (128 * 1024) << 718c2ecf20Sopenharmony_ci (((extid >> 1) & 0x04) | (extid & 0x03)); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Extract ECC requirements from 5th id byte*/ 748c2ecf20Sopenharmony_ci extid = (chip->id.data[4] >> 4) & 0x07; 758c2ecf20Sopenharmony_ci if (extid < 5) { 768c2ecf20Sopenharmony_ci requirements.step_size = 512; 778c2ecf20Sopenharmony_ci requirements.strength = 1 << extid; 788c2ecf20Sopenharmony_ci } else { 798c2ecf20Sopenharmony_ci requirements.step_size = 1024; 808c2ecf20Sopenharmony_ci switch (extid) { 818c2ecf20Sopenharmony_ci case 5: 828c2ecf20Sopenharmony_ci requirements.strength = 24; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case 6: 858c2ecf20Sopenharmony_ci requirements.strength = 40; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci case 7: 888c2ecf20Sopenharmony_ci requirements.strength = 60; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci default: 918c2ecf20Sopenharmony_ci WARN(1, "Could not decode ECC info"); 928c2ecf20Sopenharmony_ci requirements.step_size = 0; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci } else { 968c2ecf20Sopenharmony_ci nand_decode_ext_id(chip); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (nand_is_slc(chip)) { 998c2ecf20Sopenharmony_ci switch (chip->id.data[1]) { 1008c2ecf20Sopenharmony_ci /* K9F4G08U0D-S[I|C]B0(T00) */ 1018c2ecf20Sopenharmony_ci case 0xDC: 1028c2ecf20Sopenharmony_ci requirements.step_size = 512; 1038c2ecf20Sopenharmony_ci requirements.strength = 1; 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* K9F1G08U0E 21nm chips do not support subpage write */ 1078c2ecf20Sopenharmony_ci case 0xF1: 1088c2ecf20Sopenharmony_ci if (chip->id.len > 4 && 1098c2ecf20Sopenharmony_ci (chip->id.data[4] & GENMASK(1, 0)) == 0x1) 1108c2ecf20Sopenharmony_ci chip->options |= NAND_NO_SUBPAGE_WRITE; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci default: 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci nanddev_set_ecc_requirements(base, &requirements); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int samsung_nand_init(struct nand_chip *chip) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (mtd->writesize > 512) 1268c2ecf20Sopenharmony_ci chip->options |= NAND_SAMSUNG_LP_OPTIONS; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (!nand_is_slc(chip)) 1298c2ecf20Sopenharmony_ci chip->options |= NAND_BBM_LASTPAGE; 1308c2ecf20Sopenharmony_ci else 1318c2ecf20Sopenharmony_ci chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciconst struct nand_manufacturer_ops samsung_nand_manuf_ops = { 1378c2ecf20Sopenharmony_ci .detect = samsung_nand_decode_id, 1388c2ecf20Sopenharmony_ci .init = samsung_nand_init, 1398c2ecf20Sopenharmony_ci}; 140