]>
Commit | Line | Data |
---|---|---|
bc8e8a4b SA |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) Sean Anderson <seanga2@gmail.com> | |
4 | */ | |
5 | ||
6 | #define LOG_CATEGORY UCLASS_MTD | |
7 | #include <errno.h> | |
8 | #include <hexdump.h> | |
9 | #include <log.h> | |
10 | #include <nand.h> | |
11 | #include <os.h> | |
12 | #include <rand.h> | |
8502b5bf SA |
13 | #include <spl.h> |
14 | #include <system-constants.h> | |
bc8e8a4b SA |
15 | #include <dm/device_compat.h> |
16 | #include <dm/read.h> | |
17 | #include <dm/uclass.h> | |
18 | #include <asm/bitops.h> | |
19 | #include <linux/bitmap.h> | |
20 | #include <linux/mtd/rawnand.h> | |
21 | #include <linux/sizes.h> | |
22 | ||
23 | enum sand_nand_state { | |
24 | STATE_READY, | |
25 | STATE_IDLE, | |
26 | STATE_READ, | |
27 | STATE_READ_ID, | |
28 | STATE_READ_ONFI, | |
29 | STATE_PARAM_ONFI, | |
30 | STATE_STATUS, | |
31 | STATE_PROG, | |
32 | STATE_ERASE, | |
33 | }; | |
34 | ||
35 | static const char *const state_name[] = { | |
36 | [STATE_READY] = "READY", | |
37 | [STATE_IDLE] = "IDLE", | |
38 | [STATE_READ] = "READ", | |
39 | [STATE_READ_ID] = "READ_ID", | |
40 | [STATE_READ_ONFI] = "READ_ONFI", | |
41 | [STATE_PARAM_ONFI] = "PARAM_ONFI", | |
42 | [STATE_STATUS] = "STATUS", | |
43 | [STATE_PROG] = "PROG", | |
44 | [STATE_ERASE] = "ERASE", | |
45 | }; | |
46 | ||
47 | /** | |
48 | * struct sand_nand_chip - Per-device private data | |
49 | * @nand: The nand chip | |
50 | * @node: The next device in this controller | |
51 | * @programmed: Bitmap of whether sectors are programmed | |
52 | * @id: ID to report for NAND_CMD_READID | |
53 | * @id_len: Length of @id | |
54 | * @onfi: Three copies of ONFI parameter page | |
55 | * @status: Status to report for NAND_CMD_STATUS | |
56 | * @chunksize: Size of one "chunk" (page + oob) in bytes | |
57 | * @pageize: Size of one page in bytes | |
58 | * @pages: Total number of pages | |
59 | * @pages_per_erase: Number of pages per eraseblock | |
60 | * @err_count: Number of errors to inject per @err_step_bits of data | |
61 | * @err_step_bits: Number of data bits per error "step" | |
62 | * @err_steps: Number of err steps in a page | |
63 | * @cs: Chip select for this device | |
64 | * @state: Current state of the device | |
65 | * @column: Column of the most-recent command | |
66 | * @page_addr: Page address of the most-recent command | |
67 | * @fd: File descriptor for the backing data | |
68 | * @fd_page_addr: Page address that @fd is seek'd to | |
69 | * @selected: Whether this device is selected | |
70 | * @tmp: "Cache" buffer used to store transferred data before committing it | |
71 | * @tmp_dirty: Whether @tmp is dirty (modified) or clean (all ones) | |
72 | * | |
73 | * Data is stored with the OOB area in-line. For example, with 512-byte pages | |
74 | * and and 16-byte OOB areas, the first page would start at offset 0, the second | |
75 | * at offset 528, the third at offset 1056, and so on | |
76 | */ | |
77 | struct sand_nand_chip { | |
78 | struct nand_chip nand; | |
79 | struct list_head node; | |
80 | long *programmed; | |
81 | const u8 *id; | |
82 | u32 chunksize, pagesize, pages, pages_per_erase; | |
83 | u32 err_count, err_step_bits, err_steps, ecc_bits; | |
84 | unsigned int cs; | |
85 | enum sand_nand_state state; | |
86 | int column, page_addr, fd, fd_page_addr; | |
87 | bool selected, tmp_dirty; | |
88 | u8 status; | |
89 | u8 id_len; | |
90 | u8 tmp[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE]; | |
91 | u8 onfi[sizeof(struct nand_onfi_params) * 3]; | |
92 | }; | |
93 | ||
94 | #define SAND_DEBUG(chip, fmt, ...) \ | |
95 | dev_dbg((chip)->nand.mtd.dev, "%u (%s): " fmt, (chip)->cs, \ | |
96 | state_name[(chip)->state], ##__VA_ARGS__) | |
97 | ||
98 | static inline void to_state(struct sand_nand_chip *chip, | |
99 | enum sand_nand_state new_state) | |
100 | { | |
101 | if (new_state != chip->state) | |
102 | SAND_DEBUG(chip, "to state %s\n", state_name[new_state]); | |
103 | chip->state = new_state; | |
104 | } | |
105 | ||
106 | static inline struct sand_nand_chip *to_sand_nand(struct nand_chip *nand) | |
107 | { | |
108 | return container_of(nand, struct sand_nand_chip, nand); | |
109 | } | |
110 | ||
111 | struct sand_nand_priv { | |
112 | struct list_head chips; | |
113 | }; | |
114 | ||
115 | static int sand_nand_dev_ready(struct mtd_info *mtd) | |
116 | { | |
117 | return 1; | |
118 | } | |
119 | ||
120 | static int sand_nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | |
121 | { | |
122 | u8 status; | |
123 | ||
124 | return nand_status_op(chip, &status) ?: status; | |
125 | } | |
126 | ||
127 | static int sand_nand_seek(struct sand_nand_chip *chip) | |
128 | { | |
129 | if (chip->fd_page_addr == chip->page_addr) | |
130 | return 0; | |
131 | ||
132 | if (os_lseek(chip->fd, (off_t)chip->page_addr * chip->chunksize, | |
133 | OS_SEEK_SET) < 0) { | |
134 | SAND_DEBUG(chip, "could not seek: %d\n", errno); | |
135 | return -EIO; | |
136 | } | |
137 | ||
138 | chip->fd_page_addr = chip->page_addr; | |
139 | return 0; | |
140 | } | |
141 | ||
142 | static void sand_nand_inject_error(struct sand_nand_chip *chip, | |
143 | unsigned int step, unsigned int pos) | |
144 | { | |
145 | int byte, index; | |
146 | ||
147 | if (pos < chip->err_step_bits) { | |
148 | __change_bit(step * chip->err_step_bits + pos, chip->tmp); | |
149 | return; | |
150 | } | |
151 | ||
152 | /* | |
153 | * Only ECC bytes are covered in the OOB area, so | |
154 | * pretend that those are the only bytes which can have | |
155 | * errors. | |
156 | */ | |
157 | byte = (pos - chip->err_step_bits + step * chip->ecc_bits) / 8; | |
158 | index = chip->nand.ecc.layout->eccpos[byte]; | |
159 | /* Avoid endianness issues by working with bytes */ | |
160 | chip->tmp[chip->pagesize + index] ^= BIT(pos & 0x7); | |
161 | } | |
162 | ||
163 | static int sand_nand_read(struct sand_nand_chip *chip) | |
164 | { | |
165 | unsigned int i, stop = 0; | |
166 | ||
167 | if (chip->column == chip->pagesize) | |
168 | stop = chip->err_step_bits; | |
169 | ||
170 | if (test_bit(chip->page_addr, chip->programmed)) { | |
171 | if (sand_nand_seek(chip)) | |
172 | return -EIO; | |
173 | ||
174 | if (os_read(chip->fd, chip->tmp, chip->chunksize) != | |
175 | chip->chunksize) { | |
176 | SAND_DEBUG(chip, "could not read: %d\n", errno); | |
177 | return -EIO; | |
178 | } | |
179 | chip->fd_page_addr++; | |
180 | } else if (chip->tmp_dirty) { | |
181 | memset(chip->tmp + chip->column, 0xff, | |
182 | chip->chunksize - chip->column); | |
183 | } | |
184 | ||
185 | /* | |
186 | * Inject some errors; this is Method A from "An Efficient Algorithm for | |
187 | * Sequential Random Sampling" (Vitter 87). This is still slow when | |
188 | * generating a lot (dozens) of ECC errors. | |
189 | * | |
190 | * To avoid generating too many errors in any one ECC step, we separate | |
191 | * our error generation by ECC step. | |
192 | */ | |
193 | chip->tmp_dirty = true; | |
194 | for (i = 0; i < chip->err_steps; i++) { | |
195 | u32 bit_errors = chip->err_count; | |
196 | unsigned int j = chip->err_step_bits + chip->ecc_bits; | |
197 | ||
198 | while (bit_errors) { | |
199 | unsigned int u = rand(); | |
200 | float quot = 1ULL << 32; | |
201 | ||
202 | do { | |
203 | quot *= j - bit_errors; | |
204 | quot /= j; | |
205 | j--; | |
206 | ||
207 | if (j < stop) | |
208 | goto next; | |
209 | } while (u < quot); | |
210 | ||
211 | sand_nand_inject_error(chip, i, j); | |
212 | bit_errors--; | |
213 | } | |
214 | next: | |
215 | ; | |
216 | } | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | static void sand_nand_command(struct mtd_info *mtd, unsigned int command, | |
222 | int column, int page_addr) | |
223 | { | |
224 | struct nand_chip *nand = mtd_to_nand(mtd); | |
225 | struct sand_nand_chip *chip = to_sand_nand(nand); | |
226 | enum sand_nand_state new_state = chip->state; | |
227 | ||
228 | SAND_DEBUG(chip, "command=%02x column=%d page_addr=%d\n", command, | |
229 | column, page_addr); | |
230 | ||
231 | if (!chip->selected) | |
232 | return; | |
233 | ||
234 | switch (chip->state) { | |
235 | case STATE_READY: | |
236 | if (command == NAND_CMD_RESET) | |
237 | goto reset; | |
238 | break; | |
239 | case STATE_PROG: | |
240 | new_state = STATE_IDLE; | |
241 | if (command != NAND_CMD_PAGEPROG || | |
242 | test_and_set_bit(chip->page_addr, chip->programmed)) { | |
243 | chip->status |= NAND_STATUS_FAIL; | |
244 | break; | |
245 | } | |
246 | ||
247 | if (sand_nand_seek(chip)) { | |
248 | chip->status |= NAND_STATUS_FAIL; | |
249 | break; | |
250 | } | |
251 | ||
252 | if (os_write(chip->fd, chip->tmp, chip->chunksize) != | |
253 | chip->chunksize) { | |
254 | SAND_DEBUG(chip, "could not write: %d\n", errno); | |
255 | chip->status |= NAND_STATUS_FAIL; | |
256 | break; | |
257 | } | |
258 | ||
259 | chip->fd_page_addr++; | |
260 | break; | |
261 | case STATE_ERASE: | |
262 | new_state = STATE_IDLE; | |
263 | if (command != NAND_CMD_ERASE2) { | |
264 | chip->status |= NAND_STATUS_FAIL; | |
265 | break; | |
266 | } | |
267 | ||
268 | if (chip->page_addr < 0 || | |
269 | chip->page_addr >= chip->pages || | |
270 | chip->page_addr % chip->pages_per_erase) | |
271 | chip->status |= NAND_STATUS_FAIL; | |
272 | else | |
273 | bitmap_clear(chip->programmed, chip->page_addr, | |
274 | chip->pages_per_erase); | |
275 | break; | |
276 | default: | |
277 | chip->column = column; | |
278 | chip->page_addr = page_addr; | |
279 | switch (command) { | |
280 | case NAND_CMD_READOOB: | |
281 | if (column >= 0) | |
282 | chip->column += chip->pagesize; | |
283 | fallthrough; | |
284 | case NAND_CMD_READ0: | |
285 | new_state = STATE_IDLE; | |
286 | if (page_addr < 0 || page_addr >= chip->pages) | |
287 | break; | |
288 | ||
289 | if (chip->column < 0 || chip->column >= chip->chunksize) | |
290 | break; | |
291 | ||
292 | if (sand_nand_read(chip)) | |
293 | break; | |
294 | ||
295 | chip->page_addr = page_addr; | |
296 | new_state = STATE_READ; | |
297 | break; | |
298 | case NAND_CMD_ERASE1: | |
299 | new_state = STATE_ERASE; | |
300 | chip->status = ~NAND_STATUS_FAIL; | |
301 | break; | |
302 | case NAND_CMD_STATUS: | |
303 | new_state = STATE_STATUS; | |
304 | chip->column = 0; | |
305 | break; | |
306 | case NAND_CMD_SEQIN: | |
307 | new_state = STATE_PROG; | |
308 | chip->status = ~NAND_STATUS_FAIL; | |
309 | if (page_addr < 0 || page_addr >= chip->pages || | |
310 | chip->column < 0 || | |
311 | chip->column >= chip->chunksize) { | |
312 | chip->status |= NAND_STATUS_FAIL; | |
313 | } else if (chip->tmp_dirty) { | |
314 | memset(chip->tmp, 0xff, chip->chunksize); | |
315 | chip->tmp_dirty = false; | |
316 | } | |
317 | break; | |
318 | case NAND_CMD_READID: | |
319 | if (chip->onfi[0] && column == 0x20) | |
320 | new_state = STATE_READ_ONFI; | |
321 | else | |
322 | new_state = STATE_READ_ID; | |
323 | chip->column = 0; | |
324 | break; | |
325 | case NAND_CMD_PARAM: | |
326 | if (chip->onfi[0] && !column) | |
327 | new_state = STATE_PARAM_ONFI; | |
328 | else | |
329 | new_state = STATE_IDLE; | |
330 | break; | |
331 | case NAND_CMD_RESET: | |
332 | reset: | |
333 | new_state = STATE_IDLE; | |
334 | chip->column = -1; | |
335 | chip->page_addr = -1; | |
336 | chip->status = ~NAND_STATUS_FAIL; | |
337 | break; | |
338 | default: | |
339 | new_state = STATE_IDLE; | |
340 | SAND_DEBUG(chip, "Unsupported command %02x\n", command); | |
341 | } | |
342 | } | |
343 | ||
344 | to_state(chip, new_state); | |
345 | } | |
346 | ||
347 | static void sand_nand_select_chip(struct mtd_info *mtd, int n) | |
348 | { | |
349 | struct nand_chip *nand = mtd_to_nand(mtd); | |
350 | struct sand_nand_chip *chip = to_sand_nand(nand); | |
351 | ||
352 | chip->selected = !n; | |
353 | } | |
354 | ||
355 | static void sand_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) | |
356 | { | |
357 | struct nand_chip *nand = mtd_to_nand(mtd); | |
358 | struct sand_nand_chip *chip = to_sand_nand(nand); | |
359 | unsigned int to_copy; | |
360 | int src_len = 0; | |
361 | const u8 *src = NULL; | |
362 | ||
363 | if (!chip->selected) | |
364 | goto copy; | |
365 | ||
366 | switch (chip->state) { | |
367 | case STATE_READ: | |
368 | src = chip->tmp; | |
369 | src_len = chip->chunksize; | |
370 | break; | |
371 | case STATE_READ_ID: | |
372 | src = chip->id; | |
373 | src_len = chip->id_len; | |
374 | break; | |
375 | case STATE_READ_ONFI: | |
376 | src = "ONFI"; | |
377 | src_len = 4; | |
378 | break; | |
379 | case STATE_PARAM_ONFI: | |
380 | src = chip->onfi; | |
381 | src_len = sizeof(chip->onfi); | |
382 | break; | |
383 | case STATE_STATUS: | |
384 | src = &chip->status; | |
385 | src_len = 1; | |
386 | break; | |
387 | default: | |
388 | break; | |
389 | } | |
390 | ||
391 | copy: | |
392 | if (chip->column >= 0) | |
393 | to_copy = max(min(len, src_len - chip->column), 0); | |
394 | else | |
395 | to_copy = 0; | |
396 | memcpy(buf, src + chip->column, to_copy); | |
397 | memset(buf + to_copy, 0xff, len - to_copy); | |
398 | chip->column += to_copy; | |
399 | ||
400 | if (len == 1) { | |
401 | SAND_DEBUG(chip, "read [ %02x ]\n", buf[0]); | |
402 | } else if (src_len) { | |
403 | SAND_DEBUG(chip, "read %d bytes\n", len); | |
404 | #ifdef VERBOSE_DEBUG | |
405 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); | |
406 | #endif | |
407 | } | |
408 | ||
409 | if (src_len && chip->column == src_len) | |
410 | to_state(chip, STATE_IDLE); | |
411 | } | |
412 | ||
413 | static u8 sand_nand_read_byte(struct mtd_info *mtd) | |
414 | { | |
415 | u8 ret; | |
416 | ||
417 | sand_nand_read_buf(mtd, &ret, 1); | |
418 | return ret; | |
419 | } | |
420 | ||
421 | static u16 sand_nand_read_word(struct mtd_info *mtd) | |
422 | { | |
423 | struct nand_chip *nand = mtd_to_nand(mtd); | |
424 | struct sand_nand_chip *chip = to_sand_nand(nand); | |
425 | ||
426 | SAND_DEBUG(chip, "16-bit access unsupported\n"); | |
427 | return sand_nand_read_byte(mtd) | 0xff00; | |
428 | } | |
429 | ||
430 | static void sand_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |
431 | { | |
432 | struct nand_chip *nand = mtd_to_nand(mtd); | |
433 | struct sand_nand_chip *chip = to_sand_nand(nand); | |
434 | ||
435 | SAND_DEBUG(chip, "write %d bytes\n", len); | |
436 | #ifdef VERBOSE_DEBUG | |
437 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); | |
438 | #endif | |
439 | ||
440 | if (chip->state != STATE_PROG || chip->status & NAND_STATUS_FAIL) | |
441 | return; | |
442 | ||
443 | chip->tmp_dirty = true; | |
444 | len = min((unsigned int)len, chip->chunksize - chip->column); | |
445 | memcpy(chip->tmp + chip->column, buf, len); | |
446 | chip->column += len; | |
447 | } | |
448 | ||
449 | static struct nand_chip *nand_chip; | |
450 | ||
451 | int sand_nand_remove(struct udevice *dev) | |
452 | { | |
453 | struct sand_nand_priv *priv = dev_get_priv(dev); | |
454 | struct sand_nand_chip *chip; | |
455 | ||
456 | list_for_each_entry(chip, &priv->chips, node) { | |
457 | struct nand_chip *nand = &chip->nand; | |
458 | ||
459 | if (nand_chip == nand) | |
460 | nand_chip = NULL; | |
461 | ||
462 | nand_unregister(nand_to_mtd(nand)); | |
463 | free(chip->programmed); | |
464 | os_close(chip->fd); | |
465 | free(chip); | |
466 | } | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
471 | static int sand_nand_probe(struct udevice *dev) | |
472 | { | |
473 | struct sand_nand_priv *priv = dev_get_priv(dev); | |
474 | struct sand_nand_chip *chip; | |
475 | int ret, devnum = 0; | |
476 | ofnode np; | |
477 | ||
478 | INIT_LIST_HEAD(&priv->chips); | |
479 | ||
480 | dev_for_each_subnode(np, dev) { | |
481 | struct nand_chip *nand; | |
482 | struct mtd_info *mtd; | |
483 | u32 erasesize, oobsize, pagesize, pages; | |
484 | u32 err_count, err_step_size; | |
485 | off_t expected_size; | |
486 | char filename[30]; | |
487 | fdt_addr_t cs; | |
488 | const u8 *id, *onfi; | |
489 | int id_len, onfi_len; | |
490 | ||
491 | cs = ofnode_get_addr_size_index_notrans(np, 0, NULL); | |
492 | if (cs == FDT_ADDR_T_NONE) { | |
493 | dev_dbg(dev, "Invalid cs for chip %s\n", | |
494 | ofnode_get_name(np)); | |
495 | ret = -ENOENT; | |
496 | goto err; | |
497 | } | |
498 | ||
499 | id = ofnode_read_prop(np, "sandbox,id", &id_len); | |
500 | if (!id) { | |
501 | dev_dbg(dev, "No sandbox,id property for chip %s\n", | |
502 | ofnode_get_name(np)); | |
503 | ret = -EINVAL; | |
504 | goto err; | |
505 | } | |
506 | ||
507 | onfi = ofnode_read_prop(np, "sandbox,onfi", &onfi_len); | |
508 | if (onfi && onfi_len != sizeof(struct nand_onfi_params)) { | |
509 | dev_dbg(dev, "Invalid length %d for onfi params\n", | |
510 | onfi_len); | |
511 | ret = -EINVAL; | |
512 | goto err; | |
513 | } | |
514 | ||
515 | ret = ofnode_read_u32(np, "sandbox,erasesize", &erasesize); | |
516 | if (ret) { | |
517 | dev_dbg(dev, "No sandbox,erasesize property for chip %s", | |
518 | ofnode_get_name(np)); | |
519 | goto err; | |
520 | } | |
521 | ||
522 | ret = ofnode_read_u32(np, "sandbox,oobsize", &oobsize); | |
523 | if (ret) { | |
524 | dev_dbg(dev, "No sandbox,oobsize property for chip %s", | |
525 | ofnode_get_name(np)); | |
526 | goto err; | |
527 | } | |
528 | ||
529 | ret = ofnode_read_u32(np, "sandbox,pagesize", &pagesize); | |
530 | if (ret) { | |
531 | dev_dbg(dev, "No sandbox,pagesize property for chip %s", | |
532 | ofnode_get_name(np)); | |
533 | goto err; | |
534 | } | |
535 | ||
536 | ret = ofnode_read_u32(np, "sandbox,pages", &pages); | |
537 | if (ret) { | |
538 | dev_dbg(dev, "No sandbox,pages property for chip %s", | |
539 | ofnode_get_name(np)); | |
540 | goto err; | |
541 | } | |
542 | ||
543 | ret = ofnode_read_u32(np, "sandbox,err-count", &err_count); | |
544 | if (ret) { | |
545 | dev_dbg(dev, | |
546 | "No sandbox,err-count property for chip %s", | |
547 | ofnode_get_name(np)); | |
548 | goto err; | |
549 | } | |
550 | ||
551 | ret = ofnode_read_u32(np, "sandbox,err-step-size", | |
552 | &err_step_size); | |
553 | if (ret) { | |
554 | dev_dbg(dev, | |
555 | "No sandbox,err-step-size property for chip %s", | |
556 | ofnode_get_name(np)); | |
557 | goto err; | |
558 | } | |
559 | ||
560 | chip = calloc(sizeof(*chip), 1); | |
561 | if (!chip) { | |
562 | ret = -ENOMEM; | |
563 | goto err; | |
564 | } | |
565 | ||
566 | chip->cs = cs; | |
567 | chip->id = id; | |
568 | chip->id_len = id_len; | |
569 | chip->chunksize = pagesize + oobsize; | |
570 | chip->pagesize = pagesize; | |
571 | chip->pages = pages; | |
572 | chip->pages_per_erase = erasesize / pagesize; | |
573 | memset(chip->tmp, 0xff, chip->chunksize); | |
574 | ||
575 | chip->err_count = err_count; | |
576 | chip->err_step_bits = err_step_size * 8; | |
577 | chip->err_steps = pagesize / err_step_size; | |
578 | ||
579 | expected_size = (off_t)pages * chip->chunksize; | |
580 | snprintf(filename, sizeof(filename), | |
581 | "/tmp/u-boot.nand%d.XXXXXX", devnum); | |
582 | chip->fd = os_mktemp(filename, expected_size); | |
583 | if (chip->fd < 0) { | |
584 | dev_dbg(dev, "Could not create temp file %s\n", | |
585 | filename); | |
586 | ret = chip->fd; | |
587 | goto err_chip; | |
588 | } | |
589 | ||
590 | chip->programmed = calloc(sizeof(long), | |
591 | BITS_TO_LONGS(pages)); | |
592 | if (!chip->programmed) { | |
593 | ret = -ENOMEM; | |
594 | goto err_fd; | |
595 | } | |
596 | ||
597 | if (onfi) { | |
598 | memcpy(chip->onfi, onfi, onfi_len); | |
599 | memcpy(chip->onfi + onfi_len, onfi, onfi_len); | |
600 | memcpy(chip->onfi + 2 * onfi_len, onfi, onfi_len); | |
601 | } | |
602 | ||
603 | nand = &chip->nand; | |
8502b5bf | 604 | nand->options = spl_in_proper() ? 0 : NAND_SKIP_BBTSCAN; |
bc8e8a4b SA |
605 | nand->flash_node = np; |
606 | nand->dev_ready = sand_nand_dev_ready; | |
607 | nand->cmdfunc = sand_nand_command; | |
608 | nand->waitfunc = sand_nand_wait; | |
609 | nand->select_chip = sand_nand_select_chip; | |
610 | nand->read_byte = sand_nand_read_byte; | |
611 | nand->read_word = sand_nand_read_word; | |
612 | nand->read_buf = sand_nand_read_buf; | |
613 | nand->write_buf = sand_nand_write_buf; | |
614 | nand->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; | |
615 | ||
616 | mtd = nand_to_mtd(nand); | |
617 | mtd->dev = dev; | |
618 | ||
619 | ret = nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS); | |
620 | if (ret) { | |
621 | dev_dbg(dev, "Could not scan chip %s: %d\n", | |
622 | ofnode_get_name(np), ret); | |
623 | goto err_prog; | |
624 | } | |
625 | chip->ecc_bits = nand->ecc.layout->eccbytes * 8 / | |
626 | chip->err_steps; | |
627 | ||
628 | ret = nand_register(devnum, mtd); | |
629 | if (ret) { | |
630 | dev_dbg(dev, "Could not register nand %d: %d\n", devnum, | |
631 | ret); | |
632 | goto err_prog; | |
633 | } | |
634 | ||
635 | if (!nand_chip) | |
636 | nand_chip = nand; | |
637 | ||
638 | list_add_tail(&chip->node, &priv->chips); | |
639 | devnum++; | |
640 | continue; | |
641 | ||
642 | err_prog: | |
643 | free(chip->programmed); | |
644 | err_fd: | |
645 | os_close(chip->fd); | |
646 | err_chip: | |
647 | free(chip); | |
648 | goto err; | |
649 | } | |
650 | ||
651 | return 0; | |
652 | ||
653 | err: | |
654 | sand_nand_remove(dev); | |
655 | return ret; | |
656 | } | |
657 | ||
658 | static const struct udevice_id sand_nand_ids[] = { | |
659 | { .compatible = "sandbox,nand" }, | |
660 | { } | |
661 | }; | |
662 | ||
663 | U_BOOT_DRIVER(sand_nand) = { | |
664 | .name = "sand-nand", | |
665 | .id = UCLASS_MTD, | |
666 | .of_match = sand_nand_ids, | |
667 | .probe = sand_nand_probe, | |
668 | .remove = sand_nand_remove, | |
669 | .priv_auto = sizeof(struct sand_nand_priv), | |
670 | }; | |
671 | ||
672 | void board_nand_init(void) | |
673 | { | |
674 | struct udevice *dev; | |
675 | int err; | |
676 | ||
677 | err = uclass_get_device_by_driver(UCLASS_MTD, DM_DRIVER_REF(sand_nand), | |
678 | &dev); | |
679 | if (err && err != -ENODEV) | |
680 | log_info("Failed to get sandbox NAND: %d\n", err); | |
681 | } | |
8502b5bf SA |
682 | |
683 | #if IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_SPL_NAND_INIT) | |
684 | void nand_deselect(void) | |
685 | { | |
686 | nand_chip->select_chip(nand_to_mtd(nand_chip), -1); | |
687 | } | |
688 | ||
689 | static int nand_is_bad_block(int block) | |
690 | { | |
691 | struct mtd_info *mtd = nand_to_mtd(nand_chip); | |
692 | ||
693 | return mtd_block_isbad(mtd, block << mtd->erasesize_shift); | |
694 | } | |
695 | ||
696 | static int nand_read_page(int block, int page, uchar *dst) | |
697 | { | |
698 | struct mtd_info *mtd = nand_to_mtd(nand_chip); | |
699 | loff_t ofs = ((loff_t)block << mtd->erasesize_shift) + | |
700 | ((loff_t)page << mtd->writesize_shift); | |
701 | size_t len = mtd->writesize; | |
702 | ||
703 | return nand_read(mtd, ofs, &len, dst); | |
704 | } | |
705 | ||
706 | #include "nand_spl_loaders.c" | |
707 | #endif /* CONFIG_SPL_NAND_INIT */ |