xref: /linux/drivers/mtd/nand/raw/nand_samsung.c (revision 2f4c53349961c8ca480193e47da4d44fdb8335a8)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c51d0ac5SBoris Brezillon /*
3c51d0ac5SBoris Brezillon  * Copyright (C) 2017 Free Electrons
4c51d0ac5SBoris Brezillon  * Copyright (C) 2017 NextThing Co
5c51d0ac5SBoris Brezillon  *
6c51d0ac5SBoris Brezillon  * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
7c51d0ac5SBoris Brezillon  */
8c51d0ac5SBoris Brezillon 
9348d56a8SBoris Brezillon #include "internals.h"
10c51d0ac5SBoris Brezillon 
11c51d0ac5SBoris Brezillon static void samsung_nand_decode_id(struct nand_chip *chip)
12c51d0ac5SBoris Brezillon {
13c51d0ac5SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
14629a442cSBoris Brezillon 	struct nand_memory_organization *memorg;
15629a442cSBoris Brezillon 
16629a442cSBoris Brezillon 	memorg = nanddev_get_memorg(&chip->base);
17c51d0ac5SBoris Brezillon 
18c51d0ac5SBoris Brezillon 	/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
19c51d0ac5SBoris Brezillon 	if (chip->id.len == 6 && !nand_is_slc(chip) &&
20c51d0ac5SBoris Brezillon 	    chip->id.data[5] != 0x00) {
21c51d0ac5SBoris Brezillon 		u8 extid = chip->id.data[3];
22c51d0ac5SBoris Brezillon 
23c51d0ac5SBoris Brezillon 		/* Get pagesize */
24629a442cSBoris Brezillon 		memorg->pagesize = 2048 << (extid & 0x03);
25629a442cSBoris Brezillon 		mtd->writesize = memorg->pagesize;
26c51d0ac5SBoris Brezillon 
27c51d0ac5SBoris Brezillon 		extid >>= 2;
28c51d0ac5SBoris Brezillon 
29c51d0ac5SBoris Brezillon 		/* Get oobsize */
30c51d0ac5SBoris Brezillon 		switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
31c51d0ac5SBoris Brezillon 		case 1:
32629a442cSBoris Brezillon 			memorg->oobsize = 128;
33c51d0ac5SBoris Brezillon 			break;
34c51d0ac5SBoris Brezillon 		case 2:
35629a442cSBoris Brezillon 			memorg->oobsize = 218;
36c51d0ac5SBoris Brezillon 			break;
37c51d0ac5SBoris Brezillon 		case 3:
38629a442cSBoris Brezillon 			memorg->oobsize = 400;
39c51d0ac5SBoris Brezillon 			break;
40c51d0ac5SBoris Brezillon 		case 4:
41629a442cSBoris Brezillon 			memorg->oobsize = 436;
42c51d0ac5SBoris Brezillon 			break;
43c51d0ac5SBoris Brezillon 		case 5:
44629a442cSBoris Brezillon 			memorg->oobsize = 512;
45c51d0ac5SBoris Brezillon 			break;
46c51d0ac5SBoris Brezillon 		case 6:
47629a442cSBoris Brezillon 			memorg->oobsize = 640;
48c51d0ac5SBoris Brezillon 			break;
49c51d0ac5SBoris Brezillon 		default:
50c51d0ac5SBoris Brezillon 			/*
51c51d0ac5SBoris Brezillon 			 * We should never reach this case, but if that
52c51d0ac5SBoris Brezillon 			 * happens, this probably means Samsung decided to use
53c51d0ac5SBoris Brezillon 			 * a different extended ID format, and we should find
54c51d0ac5SBoris Brezillon 			 * a way to support it.
55c51d0ac5SBoris Brezillon 			 */
56c51d0ac5SBoris Brezillon 			WARN(1, "Invalid OOB size value");
57c51d0ac5SBoris Brezillon 			break;
58c51d0ac5SBoris Brezillon 		}
59c51d0ac5SBoris Brezillon 
60629a442cSBoris Brezillon 		mtd->oobsize = memorg->oobsize;
61629a442cSBoris Brezillon 
62c51d0ac5SBoris Brezillon 		/* Get blocksize */
63c51d0ac5SBoris Brezillon 		extid >>= 2;
64629a442cSBoris Brezillon 		memorg->pages_per_eraseblock = (128 * 1024) <<
65629a442cSBoris Brezillon 					       (((extid >> 1) & 0x04) |
66629a442cSBoris Brezillon 						(extid & 0x03)) /
67629a442cSBoris Brezillon 					       memorg->pagesize;
68c51d0ac5SBoris Brezillon 		mtd->erasesize = (128 * 1024) <<
69c51d0ac5SBoris Brezillon 				 (((extid >> 1) & 0x04) | (extid & 0x03));
708fc82d45SHans de Goede 
718fc82d45SHans de Goede 		/* Extract ECC requirements from 5th id byte*/
728fc82d45SHans de Goede 		extid = (chip->id.data[4] >> 4) & 0x07;
738fc82d45SHans de Goede 		if (extid < 5) {
746a1b66d6SBoris Brezillon 			chip->base.eccreq.step_size = 512;
756a1b66d6SBoris Brezillon 			chip->base.eccreq.strength = 1 << extid;
768fc82d45SHans de Goede 		} else {
776a1b66d6SBoris Brezillon 			chip->base.eccreq.step_size = 1024;
788fc82d45SHans de Goede 			switch (extid) {
798fc82d45SHans de Goede 			case 5:
806a1b66d6SBoris Brezillon 				chip->base.eccreq.strength = 24;
818fc82d45SHans de Goede 				break;
828fc82d45SHans de Goede 			case 6:
836a1b66d6SBoris Brezillon 				chip->base.eccreq.strength = 40;
848fc82d45SHans de Goede 				break;
858fc82d45SHans de Goede 			case 7:
866a1b66d6SBoris Brezillon 				chip->base.eccreq.strength = 60;
878fc82d45SHans de Goede 				break;
88d2419790SBrian Norris 			default:
89d2419790SBrian Norris 				WARN(1, "Could not decode ECC info");
906a1b66d6SBoris Brezillon 				chip->base.eccreq.step_size = 0;
918fc82d45SHans de Goede 			}
928fc82d45SHans de Goede 		}
93c51d0ac5SBoris Brezillon 	} else {
94c51d0ac5SBoris Brezillon 		nand_decode_ext_id(chip);
95707d8154SMiquel Raynal 
9609ec417bSLadislav Michl 		if (nand_is_slc(chip)) {
9709ec417bSLadislav Michl 			switch (chip->id.data[1]) {
9809ec417bSLadislav Michl 			/* K9F4G08U0D-S[I|C]B0(T00) */
9909ec417bSLadislav Michl 			case 0xDC:
1006a1b66d6SBoris Brezillon 				chip->base.eccreq.step_size = 512;
1016a1b66d6SBoris Brezillon 				chip->base.eccreq.strength = 1;
10209ec417bSLadislav Michl 				break;
10309ec417bSLadislav Michl 
10409ec417bSLadislav Michl 			/* K9F1G08U0E 21nm chips do not support subpage write */
10509ec417bSLadislav Michl 			case 0xF1:
10609ec417bSLadislav Michl 				if (chip->id.len > 4 &&
10709ec417bSLadislav Michl 				    (chip->id.data[4] & GENMASK(1, 0)) == 0x1)
10809ec417bSLadislav Michl 					chip->options |= NAND_NO_SUBPAGE_WRITE;
10909ec417bSLadislav Michl 				break;
11009ec417bSLadislav Michl 			default:
11109ec417bSLadislav Michl 				break;
11209ec417bSLadislav Michl 			}
113707d8154SMiquel Raynal 		}
114c51d0ac5SBoris Brezillon 	}
115c51d0ac5SBoris Brezillon }
116c51d0ac5SBoris Brezillon 
117c51d0ac5SBoris Brezillon static int samsung_nand_init(struct nand_chip *chip)
118c51d0ac5SBoris Brezillon {
119c51d0ac5SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
120c51d0ac5SBoris Brezillon 
121c51d0ac5SBoris Brezillon 	if (mtd->writesize > 512)
122c51d0ac5SBoris Brezillon 		chip->options |= NAND_SAMSUNG_LP_OPTIONS;
123c51d0ac5SBoris Brezillon 
124c51d0ac5SBoris Brezillon 	if (!nand_is_slc(chip))
12504649ec1SFrieder Schrempf 		chip->options |= NAND_BBM_LASTPAGE;
126c51d0ac5SBoris Brezillon 	else
127bb592548SFrieder Schrempf 		chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
128c51d0ac5SBoris Brezillon 
129c51d0ac5SBoris Brezillon 	return 0;
130c51d0ac5SBoris Brezillon }
131c51d0ac5SBoris Brezillon 
132c51d0ac5SBoris Brezillon const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
133c51d0ac5SBoris Brezillon 	.detect = samsung_nand_decode_id,
134c51d0ac5SBoris Brezillon 	.init = samsung_nand_init,
135c51d0ac5SBoris Brezillon };
136