File Index
Files and directories
Sign in
FILE

nand_samsung.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mtd/nand/raw/nand_samsung.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  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
  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 that
 54			 * happens, this probably means Samsung decided to use
 55			 * a different extended ID format, and we should find
 56			 * 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	else
131		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};
~/ Read-only file preview.