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 <linux/mtd/rawnand.h> 19 samsung_nand_decode_id(struct nand_chip * chip)20static 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 } 96 samsung_nand_init(struct nand_chip * chip)97static int samsung_nand_init(struct nand_chip *chip) 98 { 99 struct mtd_info *mtd = nand_to_mtd(chip); 100 101 if (mtd->writesize > 512) 102 chip->options |= NAND_SAMSUNG_LP_OPTIONS; 103 104 if (!nand_is_slc(chip)) 105 chip->bbt_options |= NAND_BBT_SCANLASTPAGE; 106 else 107 chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; 108 109 return 0; 110 } 111 112 const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 113 .detect = samsung_nand_decode_id, 114 .init = samsung_nand_init, 115 }; 116