1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2017 Free Electrons 4 * Copyright (C) 2017 NextThing Co 5 * 6 * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19#include <linux/bug.h> 20#include <linux/mtd/rawnand.h> 21 22static void samsung_nand_decode_id(struct nand_chip *chip) 23{ 24 struct mtd_info *mtd = nand_to_mtd(chip); 25 26 /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */ 27 if (chip->id.len == 6 && !nand_is_slc(chip) && 28 chip->id.data[5] != 0x00) { 29 u8 extid = chip->id.data[3]; 30 31 /* Get pagesize */ 32 mtd->writesize = 2048 << (extid & 0x03); 33 34 extid >>= 2; 35 36 /* Get oobsize */ 37 switch (((extid >> 2) & 0x4) | (extid & 0x3)) { 38 case 1: 39 mtd->oobsize = 128; 40 break; 41 case 2: 42 mtd->oobsize = 218; 43 break; 44 case 3: 45 mtd->oobsize = 400; 46 break; 47 case 4: 48 mtd->oobsize = 436; 49 break; 50 case 5: 51 mtd->oobsize = 512; 52 break; 53 case 6: 54 mtd->oobsize = 640; 55 break; 56 case 7: 57 default: /* Other cases are "reserved" (unknown) */ 58 WARN(1, "Invalid OOB size value"); 59 mtd->oobsize = 1024; 60 break; 61 } 62 63 /* Get blocksize */ 64 extid >>= 2; 65 mtd->erasesize = (128 * 1024) << 66 (((extid >> 1) & 0x04) | (extid & 0x03)); 67 68 /* Extract ECC requirements from 5th id byte*/ 69 extid = (chip->id.data[4] >> 4) & 0x07; 70 if (extid < 5) { 71 chip->ecc_step_ds = 512; 72 chip->ecc_strength_ds = 1 << extid; 73 } else { 74 chip->ecc_step_ds = 1024; 75 switch (extid) { 76 case 5: 77 chip->ecc_strength_ds = 24; 78 break; 79 case 6: 80 chip->ecc_strength_ds = 40; 81 break; 82 case 7: 83 chip->ecc_strength_ds = 60; 84 break; 85 } 86 } 87 } else { 88 nand_decode_ext_id(chip); 89 } 90} 91 92static int samsung_nand_init(struct nand_chip *chip) 93{ 94 struct mtd_info *mtd = nand_to_mtd(chip); 95 96 if (mtd->writesize > 512) 97 chip->options |= NAND_SAMSUNG_LP_OPTIONS; 98 99 if (!nand_is_slc(chip)) 100 chip->bbt_options |= NAND_BBT_SCANLASTPAGE; 101 else 102 chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; 103 104 return 0; 105} 106 107const struct nand_manufacturer_ops samsung_nand_manuf_ops = { 108 .detect = samsung_nand_decode_id, 109 .init = samsung_nand_init, 110}; 111