1 /* 2 * Copyright (C) 2017 Free Electrons 3 * Copyright (C) 2017 NextThing Co 4 * 5 * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18 #include "internals.h" 19 20 static void samsung_nand_decode_id(struct nand_chip *chip) 21 { 22 struct mtd_info *mtd = nand_to_mtd(chip); 23 24 /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 25 if (chip->id.len == 6 && !nand_is_slc(chip) && 26 chip->id.data[5] != 0x00) { 27 u8 extid = chip->id.data[3]; 28 29 /* Get pagesize */ 30 mtd->writesize = 2048 << (extid & 0x03); 31 32 extid >>= 2; 33 34 /* Get oobsize */ 35 switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 36 case 1: 37 mtd->oobsize = 128; 38 break; 39 case 2: 40 mtd->oobsize = 218; 41 break; 42 case 3: 43 mtd->oobsize = 400; 44 break; 45 case 4: 46 mtd->oobsize = 436; 47 break; 48 case 5: 49 mtd->oobsize = 512; 50 break; 51 case 6: 52 mtd->oobsize = 640; 53 break; 54 default: 55 /* 56 * We should never reach this case, but if that 57 * happens, this probably means Samsung decided to use 58 * a different extended ID format, and we should find 59 * a way to support it. 60 */ 61 WARN(1, "Invalid OOB size value"); 62 break; 63 } 64 65 /* Get blocksize */ 66 extid >>= 2; 67 mtd->erasesize = (128 * 1024) << 68 (((extid >> 1) & 0x04) | (extid & 0x03)); 69 70 /* Extract ECC requirements from 5th id byte*/ 71 extid = (chip->id.data[4] >> 4) & 0x07; 72 if (extid < 5) { 73 chip->ecc_step_ds = 512; 74 chip->ecc_strength_ds = 1 << extid; 75 } else { 76 chip->ecc_step_ds = 1024; 77 switch (extid) { 78 case 5: 79 chip->ecc_strength_ds = 24; 80 break; 81 case 6: 82 chip->ecc_strength_ds = 40; 83 break; 84 case 7: 85 chip->ecc_strength_ds = 60; 86 break; 87 default: 88 WARN(1, "Could not decode ECC info"); 89 chip->ecc_step_ds = 0; 90 } 91 } 92 } else { 93 nand_decode_ext_id(chip); 94 95 if (nand_is_slc(chip)) { 96 switch (chip->id.data[1]) { 97 /* K9F4G08U0D-S[I|C]B0(T00) */ 98 case 0xDC: 99 chip->ecc_step_ds = 512; 100 chip->ecc_strength_ds = 1; 101 break; 102 103 /* K9F1G08U0E 21nm chips do not support subpage write */ 104 case 0xF1: 105 if (chip->id.len > 4 && 106 (chip->id.data[4] & GENMASK(1, 0)) == 0x1) 107 chip->options |= NAND_NO_SUBPAGE_WRITE; 108 break; 109 default: 110 break; 111 } 112 } 113 } 114 } 115 116 static int samsung_nand_init(struct nand_chip *chip) 117 { 118 struct mtd_info *mtd = nand_to_mtd(chip); 119 120 if (mtd->writesize > 512) 121 chip->options |= NAND_SAMSUNG_LP_OPTIONS; 122 123 if (!nand_is_slc(chip)) 124 chip->bbt_options |= NAND_BBT_SCANLASTPAGE; 125 else 126 chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; 127 128 return 0; 129 } 130 131 const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 132 .detect = samsung_nand_decode_id, 133 .init = samsung_nand_init, 134 }; 135