brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · 0be6b75 Raw
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