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 struct nand_memory_organization *memorg; 24 25 memorg = nanddev_get_memorg(&chip->base); 26 27 /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 28 if (chip->id.len == 6 && !nand_is_slc(chip) && 29 chip->id.data[5] != 0x00) { 30 u8 extid = chip->id.data[3]; 31 32 /* Get pagesize */ 33 memorg->pagesize = 2048 << (extid & 0x03); 34 mtd->writesize = memorg->pagesize; 35 36 extid >>= 2; 37 38 /* Get oobsize */ 39 switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 40 case 1: 41 memorg->oobsize = 128; 42 break; 43 case 2: 44 memorg->oobsize = 218; 45 break; 46 case 3: 47 memorg->oobsize = 400; 48 break; 49 case 4: 50 memorg->oobsize = 436; 51 break; 52 case 5: 53 memorg->oobsize = 512; 54 break; 55 case 6: 56 memorg->oobsize = 640; 57 break; 58 default: 59 /* 60 * We should never reach this case, but if that 61 * happens, this probably means Samsung decided to use 62 * a different extended ID format, and we should find 63 * a way to support it. 64 */ 65 WARN(1, "Invalid OOB size value"); 66 break; 67 } 68 69 mtd->oobsize = memorg->oobsize; 70 71 /* Get blocksize */ 72 extid >>= 2; 73 memorg->pages_per_eraseblock = (128 * 1024) << 74 (((extid >> 1) & 0x04) | 75 (extid & 0x03)) / 76 memorg->pagesize; 77 mtd->erasesize = (128 * 1024) << 78 (((extid >> 1) & 0x04) | (extid & 0x03)); 79 80 /* Extract ECC requirements from 5th id byte*/ 81 extid = (chip->id.data[4] >> 4) & 0x07; 82 if (extid < 5) { 83 chip->base.eccreq.step_size = 512; 84 chip->base.eccreq.strength = 1 << extid; 85 } else { 86 chip->base.eccreq.step_size = 1024; 87 switch (extid) { 88 case 5: 89 chip->base.eccreq.strength = 24; 90 break; 91 case 6: 92 chip->base.eccreq.strength = 40; 93 break; 94 case 7: 95 chip->base.eccreq.strength = 60; 96 break; 97 default: 98 WARN(1, "Could not decode ECC info"); 99 chip->base.eccreq.step_size = 0; 100 } 101 } 102 } else { 103 nand_decode_ext_id(chip); 104 105 if (nand_is_slc(chip)) { 106 switch (chip->id.data[1]) { 107 /* K9F4G08U0D-S[I|C]B0(T00) */ 108 case 0xDC: 109 chip->base.eccreq.step_size = 512; 110 chip->base.eccreq.strength = 1; 111 break; 112 113 /* K9F1G08U0E 21nm chips do not support subpage write */ 114 case 0xF1: 115 if (chip->id.len > 4 && 116 (chip->id.data[4] & GENMASK(1, 0)) == 0x1) 117 chip->options |= NAND_NO_SUBPAGE_WRITE; 118 break; 119 default: 120 break; 121 } 122 } 123 } 124 } 125 126 static int samsung_nand_init(struct nand_chip *chip) 127 { 128 struct mtd_info *mtd = nand_to_mtd(chip); 129 130 if (mtd->writesize > 512) 131 chip->options |= NAND_SAMSUNG_LP_OPTIONS; 132 133 if (!nand_is_slc(chip)) 134 chip->options |= NAND_BBM_LASTPAGE; 135 else 136 chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE; 137 138 return 0; 139 } 140 141 const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 142 .detect = samsung_nand_decode_id, 143 .init = samsung_nand_init, 144 }; 145