blob: 5552ce20ede034d05ab33fa94a62efe0bc967c1a [file] [log] [blame]
Boris Brezillonc51d0ac2016-06-08 10:22:19 +02001/*
2 * Copyright (C) 2017 Free Electrons
3 * Copyright (C) 2017 NextThing Co
4 *
5 * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
Boris Brezillon348d56a2018-09-07 00:38:48 +020018#include "internals.h"
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020019
20static void samsung_nand_decode_id(struct nand_chip *chip)
21{
22 struct mtd_info *mtd = nand_to_mtd(chip);
Boris Brezillon629a4422018-10-25 17:10:37 +020023 struct nand_memory_organization *memorg;
24
25 memorg = nanddev_get_memorg(&chip->base);
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020026
27 /* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
28 if (chip->id.len == 6 && !nand_is_slc(chip) &&
29 chip->id.data[5] != 0x00) {
30 u8 extid = chip->id.data[3];
31
32 /* Get pagesize */
Boris Brezillon629a4422018-10-25 17:10:37 +020033 memorg->pagesize = 2048 << (extid & 0x03);
34 mtd->writesize = memorg->pagesize;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020035
36 extid >>= 2;
37
38 /* Get oobsize */
39 switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
40 case 1:
Boris Brezillon629a4422018-10-25 17:10:37 +020041 memorg->oobsize = 128;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020042 break;
43 case 2:
Boris Brezillon629a4422018-10-25 17:10:37 +020044 memorg->oobsize = 218;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020045 break;
46 case 3:
Boris Brezillon629a4422018-10-25 17:10:37 +020047 memorg->oobsize = 400;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020048 break;
49 case 4:
Boris Brezillon629a4422018-10-25 17:10:37 +020050 memorg->oobsize = 436;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020051 break;
52 case 5:
Boris Brezillon629a4422018-10-25 17:10:37 +020053 memorg->oobsize = 512;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020054 break;
55 case 6:
Boris Brezillon629a4422018-10-25 17:10:37 +020056 memorg->oobsize = 640;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020057 break;
58 default:
59 /*
60 * We should never reach this case, but if that
61 * happens, this probably means Samsung decided to use
62 * a different extended ID format, and we should find
63 * a way to support it.
64 */
65 WARN(1, "Invalid OOB size value");
66 break;
67 }
68
Boris Brezillon629a4422018-10-25 17:10:37 +020069 mtd->oobsize = memorg->oobsize;
70
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020071 /* Get blocksize */
72 extid >>= 2;
Boris Brezillon629a4422018-10-25 17:10:37 +020073 memorg->pages_per_eraseblock = (128 * 1024) <<
74 (((extid >> 1) & 0x04) |
75 (extid & 0x03)) /
76 memorg->pagesize;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +020077 mtd->erasesize = (128 * 1024) <<
78 (((extid >> 1) & 0x04) | (extid & 0x03));
Hans de Goede8fc82d42016-06-08 10:45:28 +020079
80 /* Extract ECC requirements from 5th id byte*/
81 extid = (chip->id.data[4] >> 4) & 0x07;
82 if (extid < 5) {
Boris Brezillon6a1b66d2018-11-04 16:09:42 +010083 chip->base.eccreq.step_size = 512;
84 chip->base.eccreq.strength = 1 << extid;
Hans de Goede8fc82d42016-06-08 10:45:28 +020085 } else {
Boris Brezillon6a1b66d2018-11-04 16:09:42 +010086 chip->base.eccreq.step_size = 1024;
Hans de Goede8fc82d42016-06-08 10:45:28 +020087 switch (extid) {
88 case 5:
Boris Brezillon6a1b66d2018-11-04 16:09:42 +010089 chip->base.eccreq.strength = 24;
Hans de Goede8fc82d42016-06-08 10:45:28 +020090 break;
91 case 6:
Boris Brezillon6a1b66d2018-11-04 16:09:42 +010092 chip->base.eccreq.strength = 40;
Hans de Goede8fc82d42016-06-08 10:45:28 +020093 break;
94 case 7:
Boris Brezillon6a1b66d2018-11-04 16:09:42 +010095 chip->base.eccreq.strength = 60;
Hans de Goede8fc82d42016-06-08 10:45:28 +020096 break;
Brian Norrisd2419792017-05-01 17:04:55 -070097 default:
98 WARN(1, "Could not decode ECC info");
Boris Brezillon6a1b66d2018-11-04 16:09:42 +010099 chip->base.eccreq.step_size = 0;
Hans de Goede8fc82d42016-06-08 10:45:28 +0200100 }
101 }
Boris Brezillonc51d0ac2016-06-08 10:22:19 +0200102 } else {
103 nand_decode_ext_id(chip);
Miquel Raynal707d8152017-12-07 10:33:58 +0100104
Ladislav Michl09ec4172018-01-09 14:19:11 +0100105 if (nand_is_slc(chip)) {
106 switch (chip->id.data[1]) {
107 /* K9F4G08U0D-S[I|C]B0(T00) */
108 case 0xDC:
Boris Brezillon6a1b66d2018-11-04 16:09:42 +0100109 chip->base.eccreq.step_size = 512;
110 chip->base.eccreq.strength = 1;
Ladislav Michl09ec4172018-01-09 14:19:11 +0100111 break;
112
113 /* K9F1G08U0E 21nm chips do not support subpage write */
114 case 0xF1:
115 if (chip->id.len > 4 &&
116 (chip->id.data[4] & GENMASK(1, 0)) == 0x1)
117 chip->options |= NAND_NO_SUBPAGE_WRITE;
118 break;
119 default:
120 break;
121 }
Miquel Raynal707d8152017-12-07 10:33:58 +0100122 }
Boris Brezillonc51d0ac2016-06-08 10:22:19 +0200123 }
124}
125
126static int samsung_nand_init(struct nand_chip *chip)
127{
128 struct mtd_info *mtd = nand_to_mtd(chip);
129
130 if (mtd->writesize > 512)
131 chip->options |= NAND_SAMSUNG_LP_OPTIONS;
132
133 if (!nand_is_slc(chip))
Frieder Schrempf04649ec2019-04-17 12:36:34 +0000134 chip->options |= NAND_BBM_LASTPAGE;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +0200135 else
Frieder Schrempfbb592542019-04-17 12:36:36 +0000136 chip->options |= NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE;
Boris Brezillonc51d0ac2016-06-08 10:22:19 +0200137
138 return 0;
139}
140
141const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
142 .detect = samsung_nand_decode_id,
143 .init = samsung_nand_init,
144};