1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
4 | * 2002-2006 Thomas Gleixner (tglx@linutronix.de) |
5 | * |
6 | * Credits: |
7 | * David Woodhouse for adding multichip support |
8 | * |
9 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the |
10 | * rework for 2K page size chips |
11 | * |
12 | * This file contains all ONFI helpers. |
13 | */ |
14 | |
15 | #include <linux/slab.h> |
16 | |
17 | #include "internals.h" |
18 | |
19 | #define ONFI_PARAM_PAGES 3 |
20 | |
21 | u16 onfi_crc16(u16 crc, u8 const *p, size_t len) |
22 | { |
23 | int i; |
24 | while (len--) { |
25 | crc ^= *p++ << 8; |
26 | for (i = 0; i < 8; i++) |
27 | crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); |
28 | } |
29 | |
30 | return crc; |
31 | } |
32 | |
33 | /* Parse the Extended Parameter Page. */ |
34 | static int nand_flash_detect_ext_param_page(struct nand_chip *chip, |
35 | struct nand_onfi_params *p) |
36 | { |
37 | struct nand_device *base = &chip->base; |
38 | struct nand_ecc_props requirements; |
39 | struct onfi_ext_param_page *ep; |
40 | struct onfi_ext_section *s; |
41 | struct onfi_ext_ecc_info *ecc; |
42 | uint8_t *cursor; |
43 | int ret; |
44 | int len; |
45 | int i; |
46 | |
47 | len = le16_to_cpu(p->ext_param_page_length) * 16; |
48 | ep = kmalloc(size: len, GFP_KERNEL); |
49 | if (!ep) |
50 | return -ENOMEM; |
51 | |
52 | /* |
53 | * Use the Change Read Column command to skip the ONFI param pages and |
54 | * ensure we read at the right location. |
55 | */ |
56 | ret = nand_change_read_column_op(chip, |
57 | offset_in_page: sizeof(*p) * p->num_of_param_pages, |
58 | buf: ep, len, force_8bit: true); |
59 | if (ret) |
60 | goto ext_out; |
61 | |
62 | ret = -EINVAL; |
63 | if ((onfi_crc16(ONFI_CRC_BASE, p: ((uint8_t *)ep) + 2, len: len - 2) |
64 | != le16_to_cpu(ep->crc))) { |
65 | pr_debug("fail in the CRC.\n" ); |
66 | goto ext_out; |
67 | } |
68 | |
69 | /* |
70 | * Check the signature. |
71 | * Do not strictly follow the ONFI spec, maybe changed in future. |
72 | */ |
73 | if (strncmp(ep->sig, "EPPS" , 4)) { |
74 | pr_debug("The signature is invalid.\n" ); |
75 | goto ext_out; |
76 | } |
77 | |
78 | /* find the ECC section. */ |
79 | cursor = (uint8_t *)(ep + 1); |
80 | for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { |
81 | s = ep->sections + i; |
82 | if (s->type == ONFI_SECTION_TYPE_2) |
83 | break; |
84 | cursor += s->length * 16; |
85 | } |
86 | if (i == ONFI_EXT_SECTION_MAX) { |
87 | pr_debug("We can not find the ECC section.\n" ); |
88 | goto ext_out; |
89 | } |
90 | |
91 | /* get the info we want. */ |
92 | ecc = (struct onfi_ext_ecc_info *)cursor; |
93 | |
94 | if (!ecc->codeword_size) { |
95 | pr_debug("Invalid codeword size\n" ); |
96 | goto ext_out; |
97 | } |
98 | |
99 | requirements.strength = ecc->ecc_bits; |
100 | requirements.step_size = 1 << ecc->codeword_size; |
101 | nanddev_set_ecc_requirements(nand: base, reqs: &requirements); |
102 | |
103 | ret = 0; |
104 | |
105 | ext_out: |
106 | kfree(objp: ep); |
107 | return ret; |
108 | } |
109 | |
110 | /* |
111 | * Recover data with bit-wise majority |
112 | */ |
113 | static void nand_bit_wise_majority(const void **srcbufs, |
114 | unsigned int nsrcbufs, |
115 | void *dstbuf, |
116 | unsigned int bufsize) |
117 | { |
118 | int i, j, k; |
119 | |
120 | for (i = 0; i < bufsize; i++) { |
121 | u8 val = 0; |
122 | |
123 | for (j = 0; j < 8; j++) { |
124 | unsigned int cnt = 0; |
125 | |
126 | for (k = 0; k < nsrcbufs; k++) { |
127 | const u8 *srcbuf = srcbufs[k]; |
128 | |
129 | if (srcbuf[i] & BIT(j)) |
130 | cnt++; |
131 | } |
132 | |
133 | if (cnt > nsrcbufs / 2) |
134 | val |= BIT(j); |
135 | } |
136 | |
137 | ((u8 *)dstbuf)[i] = val; |
138 | } |
139 | } |
140 | |
141 | /* |
142 | * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. |
143 | */ |
144 | int nand_onfi_detect(struct nand_chip *chip) |
145 | { |
146 | struct nand_device *base = &chip->base; |
147 | struct mtd_info *mtd = nand_to_mtd(chip); |
148 | struct nand_memory_organization *memorg; |
149 | struct nand_onfi_params *p = NULL, *pbuf; |
150 | struct onfi_params *onfi; |
151 | bool use_datain = false; |
152 | int onfi_version = 0; |
153 | char id[4]; |
154 | int i, ret, val; |
155 | u16 crc; |
156 | |
157 | memorg = nanddev_get_memorg(nand: &chip->base); |
158 | |
159 | /* Try ONFI for unknown chip or LP */ |
160 | ret = nand_readid_op(chip, addr: 0x20, buf: id, len: sizeof(id)); |
161 | if (ret || strncmp(id, "ONFI" , 4)) |
162 | return 0; |
163 | |
164 | /* ONFI chip: allocate a buffer to hold its parameter page */ |
165 | pbuf = kzalloc(size: (sizeof(*pbuf) * ONFI_PARAM_PAGES), GFP_KERNEL); |
166 | if (!pbuf) |
167 | return -ENOMEM; |
168 | |
169 | if (!nand_has_exec_op(chip) || chip->controller->supported_op.data_only_read) |
170 | use_datain = true; |
171 | |
172 | for (i = 0; i < ONFI_PARAM_PAGES; i++) { |
173 | if (!i) |
174 | ret = nand_read_param_page_op(chip, page: 0, buf: &pbuf[i], |
175 | len: sizeof(*pbuf)); |
176 | else if (use_datain) |
177 | ret = nand_read_data_op(chip, buf: &pbuf[i], len: sizeof(*pbuf), |
178 | force_8bit: true, check_only: false); |
179 | else |
180 | ret = nand_change_read_column_op(chip, offset_in_page: sizeof(*pbuf) * i, |
181 | buf: &pbuf[i], len: sizeof(*pbuf), |
182 | force_8bit: true); |
183 | if (ret) { |
184 | ret = 0; |
185 | goto free_onfi_param_page; |
186 | } |
187 | |
188 | crc = onfi_crc16(ONFI_CRC_BASE, p: (u8 *)&pbuf[i], len: 254); |
189 | if (crc == le16_to_cpu(pbuf[i].crc)) { |
190 | p = &pbuf[i]; |
191 | break; |
192 | } |
193 | } |
194 | |
195 | if (i == ONFI_PARAM_PAGES) { |
196 | const void *srcbufs[ONFI_PARAM_PAGES]; |
197 | unsigned int j; |
198 | |
199 | for (j = 0; j < ONFI_PARAM_PAGES; j++) |
200 | srcbufs[j] = pbuf + j; |
201 | |
202 | pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n" ); |
203 | nand_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, dstbuf: pbuf, |
204 | bufsize: sizeof(*pbuf)); |
205 | |
206 | crc = onfi_crc16(ONFI_CRC_BASE, p: (u8 *)pbuf, len: 254); |
207 | if (crc != le16_to_cpu(pbuf->crc)) { |
208 | pr_err("ONFI parameter recovery failed, aborting\n" ); |
209 | goto free_onfi_param_page; |
210 | } |
211 | p = pbuf; |
212 | } |
213 | |
214 | if (chip->manufacturer.desc && chip->manufacturer.desc->ops && |
215 | chip->manufacturer.desc->ops->fixup_onfi_param_page) |
216 | chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p); |
217 | |
218 | /* Check version */ |
219 | val = le16_to_cpu(p->revision); |
220 | if (val & ONFI_VERSION_2_3) |
221 | onfi_version = 23; |
222 | else if (val & ONFI_VERSION_2_2) |
223 | onfi_version = 22; |
224 | else if (val & ONFI_VERSION_2_1) |
225 | onfi_version = 21; |
226 | else if (val & ONFI_VERSION_2_0) |
227 | onfi_version = 20; |
228 | else if (val & ONFI_VERSION_1_0) |
229 | onfi_version = 10; |
230 | |
231 | if (!onfi_version) { |
232 | pr_info("unsupported ONFI version: %d\n" , val); |
233 | goto free_onfi_param_page; |
234 | } |
235 | |
236 | sanitize_string(s: p->manufacturer, len: sizeof(p->manufacturer)); |
237 | sanitize_string(s: p->model, len: sizeof(p->model)); |
238 | chip->parameters.model = kstrdup(s: p->model, GFP_KERNEL); |
239 | if (!chip->parameters.model) { |
240 | ret = -ENOMEM; |
241 | goto free_onfi_param_page; |
242 | } |
243 | |
244 | memorg->pagesize = le32_to_cpu(p->byte_per_page); |
245 | mtd->writesize = memorg->pagesize; |
246 | |
247 | /* |
248 | * pages_per_block and blocks_per_lun may not be a power-of-2 size |
249 | * (don't ask me who thought of this...). MTD assumes that these |
250 | * dimensions will be power-of-2, so just truncate the remaining area. |
251 | */ |
252 | memorg->pages_per_eraseblock = |
253 | 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1); |
254 | mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize; |
255 | |
256 | memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page); |
257 | mtd->oobsize = memorg->oobsize; |
258 | |
259 | memorg->luns_per_target = p->lun_count; |
260 | memorg->planes_per_lun = 1 << p->interleaved_bits; |
261 | |
262 | /* See erasesize comment */ |
263 | memorg->eraseblocks_per_lun = |
264 | 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1); |
265 | memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun); |
266 | memorg->bits_per_cell = p->bits_per_cell; |
267 | |
268 | if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS) |
269 | chip->options |= NAND_BUSWIDTH_16; |
270 | |
271 | if (p->ecc_bits != 0xff) { |
272 | struct nand_ecc_props requirements = { |
273 | .strength = p->ecc_bits, |
274 | .step_size = 512, |
275 | }; |
276 | |
277 | nanddev_set_ecc_requirements(nand: base, reqs: &requirements); |
278 | } else if (onfi_version >= 21 && |
279 | (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { |
280 | |
281 | /* |
282 | * The nand_flash_detect_ext_param_page() uses the |
283 | * Change Read Column command which maybe not supported |
284 | * by the chip->legacy.cmdfunc. So try to update the |
285 | * chip->legacy.cmdfunc now. We do not replace user supplied |
286 | * command function. |
287 | */ |
288 | nand_legacy_adjust_cmdfunc(chip); |
289 | |
290 | /* The Extended Parameter Page is supported since ONFI 2.1. */ |
291 | if (nand_flash_detect_ext_param_page(chip, p)) |
292 | pr_warn("Failed to detect ONFI extended param page\n" ); |
293 | } else { |
294 | pr_warn("Could not retrieve ONFI ECC requirements\n" ); |
295 | } |
296 | |
297 | /* Save some parameters from the parameter page for future use */ |
298 | if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) { |
299 | chip->parameters.supports_set_get_features = true; |
300 | bitmap_set(map: chip->parameters.get_feature_list, |
301 | ONFI_FEATURE_ADDR_TIMING_MODE, nbits: 1); |
302 | bitmap_set(map: chip->parameters.set_feature_list, |
303 | ONFI_FEATURE_ADDR_TIMING_MODE, nbits: 1); |
304 | } |
305 | |
306 | if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_READ_CACHE) |
307 | chip->parameters.supports_read_cache = true; |
308 | |
309 | onfi = kzalloc(size: sizeof(*onfi), GFP_KERNEL); |
310 | if (!onfi) { |
311 | ret = -ENOMEM; |
312 | goto free_model; |
313 | } |
314 | |
315 | onfi->version = onfi_version; |
316 | onfi->tPROG = le16_to_cpu(p->t_prog); |
317 | onfi->tBERS = le16_to_cpu(p->t_bers); |
318 | onfi->tR = le16_to_cpu(p->t_r); |
319 | onfi->tCCS = le16_to_cpu(p->t_ccs); |
320 | onfi->fast_tCAD = le16_to_cpu(p->nvddr_nvddr2_features) & BIT(0); |
321 | onfi->sdr_timing_modes = le16_to_cpu(p->sdr_timing_modes); |
322 | if (le16_to_cpu(p->features) & ONFI_FEATURE_NV_DDR) |
323 | onfi->nvddr_timing_modes = le16_to_cpu(p->nvddr_timing_modes); |
324 | onfi->vendor_revision = le16_to_cpu(p->vendor_revision); |
325 | memcpy(onfi->vendor, p->vendor, sizeof(p->vendor)); |
326 | chip->parameters.onfi = onfi; |
327 | |
328 | /* Identification done, free the full ONFI parameter page and exit */ |
329 | kfree(objp: pbuf); |
330 | |
331 | return 1; |
332 | |
333 | free_model: |
334 | kfree(objp: chip->parameters.model); |
335 | free_onfi_param_page: |
336 | kfree(objp: pbuf); |
337 | |
338 | return ret; |
339 | } |
340 | |