blob: fd3f68e0909fbcc70f54323644f32d6e7c81e3cd [file] [log] [blame]
Boris Brezillon10d4e752016-06-08 10:38:57 +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 Brezillond4092d72017-08-04 17:29:10 +020018#include <linux/mtd/rawnand.h>
Boris Brezillon10d4e752016-06-08 10:38:57 +020019
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +020020/*
Chris Packham3ec7cb32018-07-18 10:42:16 +020021 * Special Micron status bit 3 indicates that the block has been
22 * corrected by on-die ECC and should be rewritten.
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +020023 */
Chris Packham3ec7cb32018-07-18 10:42:16 +020024#define NAND_ECC_STATUS_WRITE_RECOMMENDED BIT(3)
25
26/*
27 * On chips with 8-bit ECC and additional bit can be used to distinguish
28 * cases where a errors were corrected without needing a rewrite
29 *
30 * Bit 4 Bit 3 Bit 0 Description
31 * ----- ----- ----- -----------
32 * 0 0 0 No Errors
33 * 0 0 1 Multiple uncorrected errors
34 * 0 1 0 4 - 6 errors corrected, recommend rewrite
35 * 0 1 1 Reserved
36 * 1 0 0 1 - 3 errors corrected
37 * 1 0 1 Reserved
38 * 1 1 0 7 - 8 errors corrected, recommend rewrite
39 */
40#define NAND_ECC_STATUS_MASK (BIT(4) | BIT(3) | BIT(0))
41#define NAND_ECC_STATUS_UNCORRECTABLE BIT(0)
42#define NAND_ECC_STATUS_4_6_CORRECTED BIT(3)
43#define NAND_ECC_STATUS_1_3_CORRECTED BIT(4)
44#define NAND_ECC_STATUS_7_8_CORRECTED (BIT(4) | BIT(3))
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +020045
Boris Brezillon10d4e752016-06-08 10:38:57 +020046struct nand_onfi_vendor_micron {
47 u8 two_plane_read;
48 u8 read_cache;
49 u8 read_unique_id;
50 u8 dq_imped;
51 u8 dq_imped_num_settings;
52 u8 dq_imped_feat_addr;
53 u8 rb_pulldown_strength;
54 u8 rb_pulldown_strength_feat_addr;
55 u8 rb_pulldown_strength_num_settings;
56 u8 otp_mode;
57 u8 otp_page_start;
58 u8 otp_data_prot_addr;
59 u8 otp_num_pages;
60 u8 otp_feat_addr;
61 u8 read_retry_options;
62 u8 reserved[72];
63 u8 param_revision;
64} __packed;
65
66static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
67{
68 struct nand_chip *chip = mtd_to_nand(mtd);
69 u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
70
Miquel Raynal97baea12018-03-19 14:47:20 +010071 return nand_set_features(chip, ONFI_FEATURE_ADDR_READ_RETRY, feature);
Boris Brezillon10d4e752016-06-08 10:38:57 +020072}
73
74/*
75 * Configure chip properties from Micron vendor-specific ONFI table
76 */
77static int micron_nand_onfi_init(struct nand_chip *chip)
78{
Miquel Raynala97421c2018-03-19 14:47:27 +010079 struct nand_parameters *p = &chip->parameters;
80 struct nand_onfi_vendor_micron *micron = (void *)p->onfi.vendor;
Boris Brezillon10d4e752016-06-08 10:38:57 +020081
Miquel Raynala97421c2018-03-19 14:47:27 +010082 if (chip->parameters.onfi.version && p->onfi.vendor_revision) {
83 chip->read_retries = micron->read_retry_options;
84 chip->setup_read_retry = micron_nand_setup_read_retry;
85 }
Boris Brezillon10d4e752016-06-08 10:38:57 +020086
Miquel Raynal789157e2018-03-19 14:47:28 +010087 if (p->supports_set_get_features) {
88 set_bit(ONFI_FEATURE_ADDR_READ_RETRY, p->set_feature_list);
Chris Packham12baf772018-06-19 17:31:24 +120089 set_bit(ONFI_FEATURE_ON_DIE_ECC, p->set_feature_list);
Miquel Raynal789157e2018-03-19 14:47:28 +010090 set_bit(ONFI_FEATURE_ADDR_READ_RETRY, p->get_feature_list);
Chris Packham12baf772018-06-19 17:31:24 +120091 set_bit(ONFI_FEATURE_ON_DIE_ECC, p->get_feature_list);
Miquel Raynal789157e2018-03-19 14:47:28 +010092 }
Boris Brezillon10d4e752016-06-08 10:38:57 +020093
94 return 0;
95}
96
Chris Packham3ec7cb32018-07-18 10:42:16 +020097static int micron_nand_on_die_4_ooblayout_ecc(struct mtd_info *mtd,
98 int section,
99 struct mtd_oob_region *oobregion)
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200100{
101 if (section >= 4)
102 return -ERANGE;
103
104 oobregion->offset = (section * 16) + 8;
105 oobregion->length = 8;
106
107 return 0;
108}
109
Chris Packham3ec7cb32018-07-18 10:42:16 +0200110static int micron_nand_on_die_4_ooblayout_free(struct mtd_info *mtd,
111 int section,
112 struct mtd_oob_region *oobregion)
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200113{
114 if (section >= 4)
115 return -ERANGE;
116
117 oobregion->offset = (section * 16) + 2;
118 oobregion->length = 6;
119
120 return 0;
121}
122
Chris Packham3ec7cb32018-07-18 10:42:16 +0200123static const struct mtd_ooblayout_ops micron_nand_on_die_4_ooblayout_ops = {
124 .ecc = micron_nand_on_die_4_ooblayout_ecc,
125 .free = micron_nand_on_die_4_ooblayout_free,
126};
127
128static int micron_nand_on_die_8_ooblayout_ecc(struct mtd_info *mtd,
129 int section,
130 struct mtd_oob_region *oobregion)
131{
132 struct nand_chip *chip = mtd_to_nand(mtd);
133
134 if (section)
135 return -ERANGE;
136
137 oobregion->offset = mtd->oobsize - chip->ecc.total;
138 oobregion->length = chip->ecc.total;
139
140 return 0;
141}
142
143static int micron_nand_on_die_8_ooblayout_free(struct mtd_info *mtd,
144 int section,
145 struct mtd_oob_region *oobregion)
146{
147 struct nand_chip *chip = mtd_to_nand(mtd);
148
149 if (section)
150 return -ERANGE;
151
152 oobregion->offset = 2;
153 oobregion->length = mtd->oobsize - chip->ecc.total - 2;
154
155 return 0;
156}
157
158static const struct mtd_ooblayout_ops micron_nand_on_die_8_ooblayout_ops = {
159 .ecc = micron_nand_on_die_8_ooblayout_ecc,
160 .free = micron_nand_on_die_8_ooblayout_free,
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200161};
162
163static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable)
164{
165 u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, };
166
167 if (enable)
168 feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN;
169
Miquel Raynal97baea12018-03-19 14:47:20 +0100170 return nand_set_features(chip, ONFI_FEATURE_ON_DIE_ECC, feature);
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200171}
172
Chris Packham3ec7cb32018-07-18 10:42:16 +0200173static int micron_nand_on_die_ecc_status_4(struct nand_chip *chip, u8 status)
174{
175 struct mtd_info *mtd = nand_to_mtd(chip);
176
177 /*
178 * The internal ECC doesn't tell us the number of bitflips
179 * that have been corrected, but tells us if it recommends to
180 * rewrite the block. If it's the case, then we pretend we had
181 * a number of bitflips equal to the ECC strength, which will
182 * hint the NAND core to rewrite the block.
183 */
184 if (status & NAND_STATUS_FAIL) {
185 mtd->ecc_stats.failed++;
186 } else if (status & NAND_ECC_STATUS_WRITE_RECOMMENDED) {
187 mtd->ecc_stats.corrected += chip->ecc.strength;
188 return chip->ecc.strength;
189 }
190
191 return 0;
192}
193
194static int micron_nand_on_die_ecc_status_8(struct nand_chip *chip, u8 status)
195{
196 struct mtd_info *mtd = nand_to_mtd(chip);
197
198 /*
199 * With 8/512 we have more information but still don't know precisely
200 * how many bit-flips were seen.
201 */
202 switch (status & NAND_ECC_STATUS_MASK) {
203 case NAND_ECC_STATUS_UNCORRECTABLE:
204 mtd->ecc_stats.failed++;
205 return 0;
206 case NAND_ECC_STATUS_1_3_CORRECTED:
207 mtd->ecc_stats.corrected += 3;
208 return 3;
209 case NAND_ECC_STATUS_4_6_CORRECTED:
210 mtd->ecc_stats.corrected += 6;
211 /* rewrite recommended */
212 return 6;
213 case NAND_ECC_STATUS_7_8_CORRECTED:
214 mtd->ecc_stats.corrected += 8;
215 /* rewrite recommended */
216 return 8;
217 default:
218 return 0;
219 }
220}
221
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200222static int
223micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
224 uint8_t *buf, int oob_required,
225 int page)
226{
Boris Brezillon97d90da2017-11-30 18:01:29 +0100227 u8 status;
228 int ret, max_bitflips = 0;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200229
Boris Brezillon97d90da2017-11-30 18:01:29 +0100230 ret = micron_nand_on_die_ecc_setup(chip, true);
231 if (ret)
232 return ret;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200233
Boris Brezillon97d90da2017-11-30 18:01:29 +0100234 ret = nand_read_page_op(chip, page, 0, NULL, 0);
235 if (ret)
236 goto out;
237
238 ret = nand_status_op(chip, &status);
239 if (ret)
240 goto out;
241
242 ret = nand_exit_status_op(chip);
243 if (ret)
244 goto out;
245
Chris Packham3ec7cb32018-07-18 10:42:16 +0200246 if (chip->ecc.strength == 4)
247 max_bitflips = micron_nand_on_die_ecc_status_4(chip, status);
248 else
249 max_bitflips = micron_nand_on_die_ecc_status_8(chip, status);
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200250
Boris Brezillon25f815f2017-11-30 18:01:30 +0100251 ret = nand_read_data_op(chip, buf, mtd->writesize, false);
252 if (!ret && oob_required)
253 ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize,
254 false);
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200255
Boris Brezillon97d90da2017-11-30 18:01:29 +0100256out:
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200257 micron_nand_on_die_ecc_setup(chip, false);
258
Boris Brezillon97d90da2017-11-30 18:01:29 +0100259 return ret ? ret : max_bitflips;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200260}
261
262static int
263micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip,
264 const uint8_t *buf, int oob_required,
265 int page)
266{
Boris Brezillon97d90da2017-11-30 18:01:29 +0100267 int ret;
Boris Brezillon41145642017-05-16 18:27:49 +0200268
Boris Brezillon97d90da2017-11-30 18:01:29 +0100269 ret = micron_nand_on_die_ecc_setup(chip, true);
270 if (ret)
271 return ret;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200272
Boris Brezillon97d90da2017-11-30 18:01:29 +0100273 ret = nand_write_page_raw(mtd, chip, buf, oob_required, page);
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200274 micron_nand_on_die_ecc_setup(chip, false);
275
Boris Brezillon97d90da2017-11-30 18:01:29 +0100276 return ret;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200277}
278
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200279enum {
280 /* The NAND flash doesn't support on-die ECC */
281 MICRON_ON_DIE_UNSUPPORTED,
282
283 /*
284 * The NAND flash supports on-die ECC and it can be
285 * enabled/disabled by a set features command.
286 */
287 MICRON_ON_DIE_SUPPORTED,
288
289 /*
290 * The NAND flash supports on-die ECC, and it cannot be
291 * disabled.
292 */
293 MICRON_ON_DIE_MANDATORY,
294};
295
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200296#define MICRON_ID_INTERNAL_ECC_MASK GENMASK(1, 0)
297#define MICRON_ID_ECC_ENABLED BIT(7)
298
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200299/*
300 * Try to detect if the NAND support on-die ECC. To do this, we enable
301 * the feature, and read back if it has been enabled as expected. We
302 * also check if it can be disabled, because some Micron NANDs do not
303 * allow disabling the on-die ECC and we don't support such NANDs for
304 * now.
305 *
306 * This function also has the side effect of disabling on-die ECC if
307 * it had been left enabled by the firmware/bootloader.
308 */
309static int micron_supports_on_die_ecc(struct nand_chip *chip)
310{
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200311 u8 id[5];
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200312 int ret;
313
Miquel Raynala97421c2018-03-19 14:47:27 +0100314 if (!chip->parameters.onfi.version)
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200315 return MICRON_ON_DIE_UNSUPPORTED;
316
317 if (chip->bits_per_cell != 1)
318 return MICRON_ON_DIE_UNSUPPORTED;
319
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200320 /*
321 * We only support on-die ECC of 4/512 or 8/512
322 */
323 if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
324 return MICRON_ON_DIE_UNSUPPORTED;
325
326 /* 0x2 means on-die ECC is available. */
327 if (chip->id.len != 5 ||
328 (chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2)
329 return MICRON_ON_DIE_UNSUPPORTED;
330
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200331 ret = micron_nand_on_die_ecc_setup(chip, true);
332 if (ret)
333 return MICRON_ON_DIE_UNSUPPORTED;
334
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200335 ret = nand_readid_op(chip, 0, id, sizeof(id));
336 if (ret)
337 return MICRON_ON_DIE_UNSUPPORTED;
Miquel Raynal97baea12018-03-19 14:47:20 +0100338
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200339 if (!(id[4] & MICRON_ID_ECC_ENABLED))
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200340 return MICRON_ON_DIE_UNSUPPORTED;
341
342 ret = micron_nand_on_die_ecc_setup(chip, false);
343 if (ret)
344 return MICRON_ON_DIE_UNSUPPORTED;
345
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200346 ret = nand_readid_op(chip, 0, id, sizeof(id));
347 if (ret)
348 return MICRON_ON_DIE_UNSUPPORTED;
Miquel Raynal97baea12018-03-19 14:47:20 +0100349
Boris Brezillondbc44ed2018-07-18 10:42:15 +0200350 if (id[4] & MICRON_ID_ECC_ENABLED)
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200351 return MICRON_ON_DIE_MANDATORY;
352
353 /*
Chris Packham3ec7cb32018-07-18 10:42:16 +0200354 * We only support on-die ECC of 4/512 or 8/512
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200355 */
Chris Packham3ec7cb32018-07-18 10:42:16 +0200356 if (chip->ecc_strength_ds != 4 && chip->ecc_strength_ds != 8)
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200357 return MICRON_ON_DIE_UNSUPPORTED;
358
359 return MICRON_ON_DIE_SUPPORTED;
360}
361
Boris Brezillon10d4e752016-06-08 10:38:57 +0200362static int micron_nand_init(struct nand_chip *chip)
363{
364 struct mtd_info *mtd = nand_to_mtd(chip);
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200365 int ondie;
Boris Brezillon10d4e752016-06-08 10:38:57 +0200366 int ret;
367
368 ret = micron_nand_onfi_init(chip);
369 if (ret)
370 return ret;
371
372 if (mtd->writesize == 2048)
373 chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
374
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200375 ondie = micron_supports_on_die_ecc(chip);
376
Chris Packhamcb2bf402018-07-18 10:42:18 +0200377 if (ondie == MICRON_ON_DIE_MANDATORY &&
378 chip->ecc.mode != NAND_ECC_ON_DIE) {
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200379 pr_err("On-die ECC forcefully enabled, not supported\n");
380 return -EINVAL;
381 }
382
383 if (chip->ecc.mode == NAND_ECC_ON_DIE) {
384 if (ondie == MICRON_ON_DIE_UNSUPPORTED) {
385 pr_err("On-die ECC selected but not supported\n");
386 return -EINVAL;
387 }
388
Chris Packham3ec7cb32018-07-18 10:42:16 +0200389 if (chip->ecc_strength_ds == 4)
390 mtd_set_ooblayout(mtd,
391 &micron_nand_on_die_4_ooblayout_ops);
392 else
393 mtd_set_ooblayout(mtd,
394 &micron_nand_on_die_8_ooblayout_ops);
395
396 chip->ecc.bytes = chip->ecc_strength_ds * 2;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200397 chip->ecc.size = 512;
Chris Packham3ec7cb32018-07-18 10:42:16 +0200398 chip->ecc.strength = chip->ecc_strength_ds;
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200399 chip->ecc.algo = NAND_ECC_BCH;
400 chip->ecc.read_page = micron_nand_read_page_on_die_ecc;
401 chip->ecc.write_page = micron_nand_write_page_on_die_ecc;
Chris Packhamcb2bf402018-07-18 10:42:18 +0200402
403 if (ondie == MICRON_ON_DIE_MANDATORY) {
404 chip->ecc.read_page_raw = nand_read_page_raw_notsupp;
405 chip->ecc.write_page_raw = nand_write_page_raw_notsupp;
406 } else {
407 chip->ecc.read_page_raw = nand_read_page_raw;
408 chip->ecc.write_page_raw = nand_write_page_raw;
409 }
Thomas Petazzoni9748e1d2017-04-29 11:06:45 +0200410 }
411
Boris Brezillon10d4e752016-06-08 10:38:57 +0200412 return 0;
413}
414
Chris Packham243f37c2018-06-25 10:44:46 +1200415static void micron_fixup_onfi_param_page(struct nand_chip *chip,
416 struct nand_onfi_params *p)
417{
418 /*
419 * MT29F1G08ABAFAWP-ITE:F and possibly others report 00 00 for the
420 * revision number field of the ONFI parameter page. Assume ONFI
421 * version 1.0 if the revision number is 00 00.
422 */
423 if (le16_to_cpu(p->revision) == 0)
424 p->revision = cpu_to_le16(ONFI_VERSION_1_0);
425}
426
Boris Brezillon10d4e752016-06-08 10:38:57 +0200427const struct nand_manufacturer_ops micron_nand_manuf_ops = {
428 .init = micron_nand_init,
Chris Packham243f37c2018-06-25 10:44:46 +1200429 .fixup_onfi_param_page = micron_fixup_onfi_param_page,
Boris Brezillon10d4e752016-06-08 10:38:57 +0200430};