140 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017 Free Electrons4 * Copyright (C) 2017 NextThing Co5 *6 * Author: Boris Brezillon <boris.brezillon@free-electrons.com>7 */8 9#include "internals.h"10 11static void samsung_nand_decode_id(struct nand_chip *chip)12{13 struct nand_device *base = &chip->base;14 struct nand_ecc_props requirements = {};15 struct mtd_info *mtd = nand_to_mtd(chip);16 struct nand_memory_organization *memorg;17 18 memorg = nanddev_get_memorg(&chip->base);19 20 /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */21 if (chip->id.len == 6 && !nand_is_slc(chip) &&22 chip->id.data[5] != 0x00) {23 u8 extid = chip->id.data[3];24 25 /* Get pagesize */26 memorg->pagesize = 2048 << (extid & 0x03);27 mtd->writesize = memorg->pagesize;28 29 extid >>= 2;30 31 /* Get oobsize */32 switch (((extid >> 2) & 0x4) | (extid & 0x3)) {33 case 1:34 memorg->oobsize = 128;35 break;36 case 2:37 memorg->oobsize = 218;38 break;39 case 3:40 memorg->oobsize = 400;41 break;42 case 4:43 memorg->oobsize = 436;44 break;45 case 5:46 memorg->oobsize = 512;47 break;48 case 6:49 memorg->oobsize = 640;50 break;51 default:52 /*53 * We should never reach this case, but if that54 * happens, this probably means Samsung decided to use55 * a different extended ID format, and we should find56 * a way to support it.57 */58 WARN(1, "Invalid OOB size value");59 break;60 }61 62 mtd->oobsize = memorg->oobsize;63 64 /* Get blocksize */65 extid >>= 2;66 memorg->pages_per_eraseblock = (128 * 1024) <<67 (((extid >> 1) & 0x04) |68 (extid & 0x03)) /69 memorg->pagesize;70 mtd->erasesize = (128 * 1024) <<71 (((extid >> 1) & 0x04) | (extid & 0x03));72 73 /* Extract ECC requirements from 5th id byte*/74 extid = (chip->id.data[4] >> 4) & 0x07;75 if (extid < 5) {76 requirements.step_size = 512;77 requirements.strength = 1 << extid;78 } else {79 requirements.step_size = 1024;80 switch (extid) {81 case 5:82 requirements.strength = 24;83 break;84 case 6:85 requirements.strength = 40;86 break;87 case 7:88 requirements.strength = 60;89 break;90 default:91 WARN(1, "Could not decode ECC info");92 requirements.step_size = 0;93 }94 }95 } else {96 nand_decode_ext_id(chip);97 98 if (nand_is_slc(chip)) {99 switch (chip->id.data[1]) {100 /* K9F4G08U0D-S[I|C]B0(T00) */101 case 0xDC:102 requirements.step_size = 512;103 requirements.strength = 1;104 break;105 106 /* K9F1G08U0E 21nm chips do not support subpage write */107 case 0xF1:108 if (chip->id.len > 4 &&109 (chip->id.data[4] & GENMASK(1, 0)) == 0x1)110 chip->options |= NAND_NO_SUBPAGE_WRITE;111 break;112 default:113 break;114 }115 }116 }117 118 nanddev_set_ecc_requirements(base, &requirements);119}120 121static int samsung_nand_init(struct nand_chip *chip)122{123 struct mtd_info *mtd = nand_to_mtd(chip);124 125 if (mtd->writesize > 512)126 chip->options |= NAND_SAMSUNG_LP_OPTIONS;127 128 if (!nand_is_slc(chip))129 chip->options |= NAND_BBM_LASTPAGE;130 else131 chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;132 133 return 0;134}135 136const struct nand_manufacturer_ops samsung_nand_manuf_ops = {137 .detect = samsung_nand_decode_id,138 .init = samsung_nand_init,139};140