]>
Commit | Line | Data |
---|---|---|
10d4e75c BB |
1 | /* |
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 | ||
d4092d76 | 18 | #include <linux/mtd/rawnand.h> |
10d4e75c | 19 | |
9748e1d8 TP |
20 | /* |
21 | * Special Micron status bit that indicates when the block has been | |
22 | * corrected by on-die ECC and should be rewritten | |
23 | */ | |
24 | #define NAND_STATUS_WRITE_RECOMMENDED BIT(3) | |
25 | ||
10d4e75c BB |
26 | struct nand_onfi_vendor_micron { |
27 | u8 two_plane_read; | |
28 | u8 read_cache; | |
29 | u8 read_unique_id; | |
30 | u8 dq_imped; | |
31 | u8 dq_imped_num_settings; | |
32 | u8 dq_imped_feat_addr; | |
33 | u8 rb_pulldown_strength; | |
34 | u8 rb_pulldown_strength_feat_addr; | |
35 | u8 rb_pulldown_strength_num_settings; | |
36 | u8 otp_mode; | |
37 | u8 otp_page_start; | |
38 | u8 otp_data_prot_addr; | |
39 | u8 otp_num_pages; | |
40 | u8 otp_feat_addr; | |
41 | u8 read_retry_options; | |
42 | u8 reserved[72]; | |
43 | u8 param_revision; | |
44 | } __packed; | |
45 | ||
46 | static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) | |
47 | { | |
48 | struct nand_chip *chip = mtd_to_nand(mtd); | |
49 | u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; | |
50 | ||
51 | return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, | |
52 | feature); | |
53 | } | |
54 | ||
55 | /* | |
56 | * Configure chip properties from Micron vendor-specific ONFI table | |
57 | */ | |
58 | static int micron_nand_onfi_init(struct nand_chip *chip) | |
59 | { | |
60 | struct nand_onfi_params *p = &chip->onfi_params; | |
61 | struct nand_onfi_vendor_micron *micron = (void *)p->vendor; | |
62 | ||
63 | if (!chip->onfi_version) | |
64 | return 0; | |
65 | ||
66 | if (le16_to_cpu(p->vendor_revision) < 1) | |
67 | return 0; | |
68 | ||
69 | chip->read_retries = micron->read_retry_options; | |
70 | chip->setup_read_retry = micron_nand_setup_read_retry; | |
71 | ||
72 | return 0; | |
73 | } | |
74 | ||
9748e1d8 TP |
75 | static int micron_nand_on_die_ooblayout_ecc(struct mtd_info *mtd, int section, |
76 | struct mtd_oob_region *oobregion) | |
77 | { | |
78 | if (section >= 4) | |
79 | return -ERANGE; | |
80 | ||
81 | oobregion->offset = (section * 16) + 8; | |
82 | oobregion->length = 8; | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | static int micron_nand_on_die_ooblayout_free(struct mtd_info *mtd, int section, | |
88 | struct mtd_oob_region *oobregion) | |
89 | { | |
90 | if (section >= 4) | |
91 | return -ERANGE; | |
92 | ||
93 | oobregion->offset = (section * 16) + 2; | |
94 | oobregion->length = 6; | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | static const struct mtd_ooblayout_ops micron_nand_on_die_ooblayout_ops = { | |
100 | .ecc = micron_nand_on_die_ooblayout_ecc, | |
101 | .free = micron_nand_on_die_ooblayout_free, | |
102 | }; | |
103 | ||
104 | static int micron_nand_on_die_ecc_setup(struct nand_chip *chip, bool enable) | |
105 | { | |
106 | u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, }; | |
107 | ||
108 | if (enable) | |
109 | feature[0] |= ONFI_FEATURE_ON_DIE_ECC_EN; | |
110 | ||
111 | return chip->onfi_set_features(nand_to_mtd(chip), chip, | |
112 | ONFI_FEATURE_ON_DIE_ECC, feature); | |
113 | } | |
114 | ||
115 | static int | |
116 | micron_nand_read_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, | |
117 | uint8_t *buf, int oob_required, | |
118 | int page) | |
119 | { | |
97d90da8 BB |
120 | u8 status; |
121 | int ret, max_bitflips = 0; | |
9748e1d8 | 122 | |
97d90da8 BB |
123 | ret = micron_nand_on_die_ecc_setup(chip, true); |
124 | if (ret) | |
125 | return ret; | |
126 | ||
127 | ret = nand_read_page_op(chip, page, 0, NULL, 0); | |
128 | if (ret) | |
129 | goto out; | |
130 | ||
131 | ret = nand_status_op(chip, &status); | |
132 | if (ret) | |
133 | goto out; | |
134 | ||
135 | ret = nand_exit_status_op(chip); | |
136 | if (ret) | |
137 | goto out; | |
9748e1d8 | 138 | |
9748e1d8 TP |
139 | if (status & NAND_STATUS_FAIL) |
140 | mtd->ecc_stats.failed++; | |
97d90da8 | 141 | |
9748e1d8 TP |
142 | /* |
143 | * The internal ECC doesn't tell us the number of bitflips | |
144 | * that have been corrected, but tells us if it recommends to | |
145 | * rewrite the block. If it's the case, then we pretend we had | |
146 | * a number of bitflips equal to the ECC strength, which will | |
147 | * hint the NAND core to rewrite the block. | |
148 | */ | |
149 | else if (status & NAND_STATUS_WRITE_RECOMMENDED) | |
150 | max_bitflips = chip->ecc.strength; | |
151 | ||
25f815f6 BB |
152 | ret = nand_read_data_op(chip, buf, mtd->writesize, false); |
153 | if (!ret && oob_required) | |
154 | ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, | |
155 | false); | |
9748e1d8 | 156 | |
97d90da8 | 157 | out: |
9748e1d8 TP |
158 | micron_nand_on_die_ecc_setup(chip, false); |
159 | ||
97d90da8 | 160 | return ret ? ret : max_bitflips; |
9748e1d8 TP |
161 | } |
162 | ||
163 | static int | |
164 | micron_nand_write_page_on_die_ecc(struct mtd_info *mtd, struct nand_chip *chip, | |
165 | const uint8_t *buf, int oob_required, | |
166 | int page) | |
167 | { | |
97d90da8 BB |
168 | int ret; |
169 | ||
170 | ret = micron_nand_on_die_ecc_setup(chip, true); | |
171 | if (ret) | |
172 | return ret; | |
41145649 | 173 | |
97d90da8 | 174 | ret = nand_write_page_raw(mtd, chip, buf, oob_required, page); |
9748e1d8 TP |
175 | micron_nand_on_die_ecc_setup(chip, false); |
176 | ||
97d90da8 | 177 | return ret; |
9748e1d8 TP |
178 | } |
179 | ||
9748e1d8 TP |
180 | enum { |
181 | /* The NAND flash doesn't support on-die ECC */ | |
182 | MICRON_ON_DIE_UNSUPPORTED, | |
183 | ||
184 | /* | |
185 | * The NAND flash supports on-die ECC and it can be | |
186 | * enabled/disabled by a set features command. | |
187 | */ | |
188 | MICRON_ON_DIE_SUPPORTED, | |
189 | ||
190 | /* | |
191 | * The NAND flash supports on-die ECC, and it cannot be | |
192 | * disabled. | |
193 | */ | |
194 | MICRON_ON_DIE_MANDATORY, | |
195 | }; | |
196 | ||
197 | /* | |
198 | * Try to detect if the NAND support on-die ECC. To do this, we enable | |
199 | * the feature, and read back if it has been enabled as expected. We | |
200 | * also check if it can be disabled, because some Micron NANDs do not | |
201 | * allow disabling the on-die ECC and we don't support such NANDs for | |
202 | * now. | |
203 | * | |
204 | * This function also has the side effect of disabling on-die ECC if | |
205 | * it had been left enabled by the firmware/bootloader. | |
206 | */ | |
207 | static int micron_supports_on_die_ecc(struct nand_chip *chip) | |
208 | { | |
209 | u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = { 0, }; | |
210 | int ret; | |
211 | ||
212 | if (chip->onfi_version == 0) | |
213 | return MICRON_ON_DIE_UNSUPPORTED; | |
214 | ||
215 | if (chip->bits_per_cell != 1) | |
216 | return MICRON_ON_DIE_UNSUPPORTED; | |
217 | ||
218 | ret = micron_nand_on_die_ecc_setup(chip, true); | |
219 | if (ret) | |
220 | return MICRON_ON_DIE_UNSUPPORTED; | |
221 | ||
222 | chip->onfi_get_features(nand_to_mtd(chip), chip, | |
223 | ONFI_FEATURE_ON_DIE_ECC, feature); | |
224 | if ((feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) == 0) | |
225 | return MICRON_ON_DIE_UNSUPPORTED; | |
226 | ||
227 | ret = micron_nand_on_die_ecc_setup(chip, false); | |
228 | if (ret) | |
229 | return MICRON_ON_DIE_UNSUPPORTED; | |
230 | ||
231 | chip->onfi_get_features(nand_to_mtd(chip), chip, | |
232 | ONFI_FEATURE_ON_DIE_ECC, feature); | |
233 | if (feature[0] & ONFI_FEATURE_ON_DIE_ECC_EN) | |
234 | return MICRON_ON_DIE_MANDATORY; | |
235 | ||
236 | /* | |
237 | * Some Micron NANDs have an on-die ECC of 4/512, some other | |
238 | * 8/512. We only support the former. | |
239 | */ | |
240 | if (chip->onfi_params.ecc_bits != 4) | |
241 | return MICRON_ON_DIE_UNSUPPORTED; | |
242 | ||
243 | return MICRON_ON_DIE_SUPPORTED; | |
244 | } | |
245 | ||
10d4e75c BB |
246 | static int micron_nand_init(struct nand_chip *chip) |
247 | { | |
248 | struct mtd_info *mtd = nand_to_mtd(chip); | |
9748e1d8 | 249 | int ondie; |
10d4e75c BB |
250 | int ret; |
251 | ||
252 | ret = micron_nand_onfi_init(chip); | |
253 | if (ret) | |
254 | return ret; | |
255 | ||
256 | if (mtd->writesize == 2048) | |
257 | chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; | |
258 | ||
9748e1d8 TP |
259 | ondie = micron_supports_on_die_ecc(chip); |
260 | ||
261 | if (ondie == MICRON_ON_DIE_MANDATORY) { | |
262 | pr_err("On-die ECC forcefully enabled, not supported\n"); | |
263 | return -EINVAL; | |
264 | } | |
265 | ||
266 | if (chip->ecc.mode == NAND_ECC_ON_DIE) { | |
267 | if (ondie == MICRON_ON_DIE_UNSUPPORTED) { | |
268 | pr_err("On-die ECC selected but not supported\n"); | |
269 | return -EINVAL; | |
270 | } | |
271 | ||
9748e1d8 TP |
272 | chip->ecc.bytes = 8; |
273 | chip->ecc.size = 512; | |
274 | chip->ecc.strength = 4; | |
275 | chip->ecc.algo = NAND_ECC_BCH; | |
276 | chip->ecc.read_page = micron_nand_read_page_on_die_ecc; | |
277 | chip->ecc.write_page = micron_nand_write_page_on_die_ecc; | |
25f815f6 BB |
278 | chip->ecc.read_page_raw = nand_read_page_raw; |
279 | chip->ecc.write_page_raw = nand_write_page_raw; | |
9748e1d8 TP |
280 | |
281 | mtd_set_ooblayout(mtd, µn_nand_on_die_ooblayout_ops); | |
282 | } | |
283 | ||
10d4e75c BB |
284 | return 0; |
285 | } | |
286 | ||
287 | const struct nand_manufacturer_ops micron_nand_manuf_ops = { | |
288 | .init = micron_nand_init, | |
289 | }; |