1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42#include <common.h>
43#include <command.h>
44#include <watchdog.h>
45#include <malloc.h>
46#include <div64.h>
47
48#include <asm/errno.h>
49#include <linux/mtd/mtd.h>
50#include <nand.h>
51#include <jffs2/jffs2.h>
52
53typedef struct erase_info erase_info_t;
54typedef struct mtd_info mtd_info_t;
55
56
57#define cpu_to_je16(x) (x)
58#define cpu_to_je32(x) (x)
59
60
61static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
62{
63 return 0;
64}
65
66
67
68
69
70
71
72
73
74
75
76
77int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
78{
79 struct jffs2_unknown_node cleanmarker;
80 erase_info_t erase;
81 unsigned long erase_length, erased_length;
82 int bbtest = 1;
83 int result;
84 int percent_complete = -1;
85 int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
86 const char *mtd_device = meminfo->name;
87 struct mtd_oob_ops oob_opts;
88 struct nand_chip *chip = meminfo->priv;
89
90 if ((opts->offset & (meminfo->writesize - 1)) != 0) {
91 printf("Attempt to erase non page aligned data\n");
92 return -1;
93 }
94
95 memset(&erase, 0, sizeof(erase));
96 memset(&oob_opts, 0, sizeof(oob_opts));
97
98 erase.mtd = meminfo;
99 erase.len = meminfo->erasesize;
100 erase.addr = opts->offset;
101 erase_length = lldiv(opts->length + meminfo->erasesize - 1,
102 meminfo->erasesize);
103
104 cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
105 cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
106 cleanmarker.totlen = cpu_to_je32(8);
107
108
109
110
111
112 if (opts->scrub) {
113 struct nand_chip *priv_nand = meminfo->priv;
114
115 nand_block_bad_old = priv_nand->block_bad;
116 priv_nand->block_bad = nand_block_bad_scrub;
117
118
119
120 if (priv_nand->bbt) {
121 kfree(priv_nand->bbt);
122 }
123 priv_nand->bbt = NULL;
124 }
125
126 for (erased_length = 0;
127 erased_length < erase_length;
128 erase.addr += meminfo->erasesize) {
129
130 WATCHDOG_RESET ();
131
132 if (!opts->scrub && bbtest) {
133 int ret = meminfo->block_isbad(meminfo, erase.addr);
134 if (ret > 0) {
135 if (!opts->quiet)
136 printf("\rSkipping bad block at "
137 "0x%08llx "
138 " \n",
139 erase.addr);
140
141 if (!opts->spread)
142 erased_length++;
143
144 continue;
145
146 } else if (ret < 0) {
147 printf("\n%s: MTD get bad block failed: %d\n",
148 mtd_device,
149 ret);
150 return -1;
151 }
152 }
153
154 erased_length++;
155
156 result = meminfo->erase(meminfo, &erase);
157 if (result != 0) {
158 printf("\n%s: MTD Erase failure: %d\n",
159 mtd_device, result);
160 continue;
161 }
162
163
164 if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) {
165 chip->ops.ooblen = 8;
166 chip->ops.datbuf = NULL;
167 chip->ops.oobbuf = (uint8_t *)&cleanmarker;
168 chip->ops.ooboffs = 0;
169 chip->ops.mode = MTD_OOB_AUTO;
170
171 result = meminfo->write_oob(meminfo,
172 erase.addr,
173 &chip->ops);
174 if (result != 0) {
175 printf("\n%s: MTD writeoob failure: %d\n",
176 mtd_device, result);
177 continue;
178 }
179 }
180
181 if (!opts->quiet) {
182 unsigned long long n = erased_length * 100ULL;
183 int percent;
184
185 do_div(n, erase_length);
186 percent = (int)n;
187
188
189
190
191
192 if (percent != percent_complete) {
193 percent_complete = percent;
194
195 printf("\rErasing at 0x%llx -- %3d%% complete.",
196 erase.addr, percent);
197
198 if (opts->jffs2 && result == 0)
199 printf(" Cleanmarker written at 0x%llx.",
200 erase.addr);
201 }
202 }
203 }
204 if (!opts->quiet)
205 printf("\n");
206
207 if (nand_block_bad_old) {
208 struct nand_chip *priv_nand = meminfo->priv;
209
210 priv_nand->block_bad = nand_block_bad_old;
211 priv_nand->scan_bbt(meminfo);
212 }
213
214 return 0;
215}
216
217#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
218
219
220
221
222
223#define NAND_CMD_LOCK 0x2a
224#define NAND_CMD_LOCK_TIGHT 0x2c
225#define NAND_CMD_UNLOCK1 0x23
226#define NAND_CMD_UNLOCK2 0x24
227#define NAND_CMD_LOCK_STATUS 0x7a
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250int nand_lock(struct mtd_info *mtd, int tight)
251{
252 int ret = 0;
253 int status;
254 struct nand_chip *chip = mtd->priv;
255
256
257 chip->select_chip(mtd, 0);
258
259 chip->cmdfunc(mtd,
260 (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
261 -1, -1);
262
263
264 status = chip->waitfunc(mtd, chip);
265
266
267 if (status & 0x01) {
268 ret = -1;
269 }
270
271
272 chip->select_chip(mtd, -1);
273 return ret;
274}
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
292{
293 int ret = 0;
294 int chipnr;
295 int page;
296 struct nand_chip *chip = mtd->priv;
297
298
299 chipnr = (int)(offset >> chip->chip_shift);
300 chip->select_chip(mtd, chipnr);
301
302
303 if ((offset & (mtd->writesize - 1)) != 0) {
304 printf ("nand_get_lock_status: "
305 "Start address must be beginning of "
306 "nand page!\n");
307 ret = -1;
308 goto out;
309 }
310
311
312 page = (int)(offset >> chip->page_shift);
313 chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask);
314
315 ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT
316 | NAND_LOCK_STATUS_LOCK
317 | NAND_LOCK_STATUS_UNLOCK);
318
319 out:
320
321 chip->select_chip(mtd, -1);
322 return ret;
323}
324
325
326
327
328
329
330
331
332
333
334
335
336int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
337{
338 int ret = 0;
339 int chipnr;
340 int status;
341 int page;
342 struct nand_chip *chip = mtd->priv;
343 printf ("nand_unlock: start: %08x, length: %d!\n",
344 (int)start, (int)length);
345
346
347 chipnr = (int)(start >> chip->chip_shift);
348 chip->select_chip(mtd, chipnr);
349
350
351 chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
352 if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) {
353 printf ("nand_unlock: Device is write protected!\n");
354 ret = -1;
355 goto out;
356 }
357
358 if ((start & (mtd->erasesize - 1)) != 0) {
359 printf ("nand_unlock: Start address must be beginning of "
360 "nand block!\n");
361 ret = -1;
362 goto out;
363 }
364
365 if (length == 0 || (length & (mtd->erasesize - 1)) != 0) {
366 printf ("nand_unlock: Length must be a multiple of nand block "
367 "size %08x!\n", mtd->erasesize);
368 ret = -1;
369 goto out;
370 }
371
372
373
374
375
376 length -= mtd->erasesize;
377
378
379 page = (int)(start >> chip->page_shift);
380 chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask);
381
382
383 page += (int)(length >> chip->page_shift);
384 chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);
385
386
387 status = chip->waitfunc(mtd, chip);
388
389 if (status & 0x01) {
390
391 ret = -1;
392 goto out;
393 }
394
395 out:
396
397 chip->select_chip(mtd, -1);
398 return ret;
399}
400#endif
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length)
416{
417 size_t len_excl_bad = 0;
418 int ret = 0;
419
420 while (len_excl_bad < length) {
421 size_t block_len, block_off;
422 loff_t block_start;
423
424 if (offset >= nand->size)
425 return -1;
426
427 block_start = offset & ~(loff_t)(nand->erasesize - 1);
428 block_off = offset & (nand->erasesize - 1);
429 block_len = nand->erasesize - block_off;
430
431 if (!nand_block_isbad(nand, block_start))
432 len_excl_bad += block_len;
433 else
434 ret = 1;
435
436 offset += block_len;
437 }
438
439 return ret;
440}
441
442#ifdef CONFIG_CMD_NAND_TRIMFFS
443static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
444 const size_t *len)
445{
446 size_t i, l = *len;
447
448 for (i = l - 1; i >= 0; i--)
449 if (buf[i] != 0xFF)
450 break;
451
452
453 l = i + 1;
454 l = (l + nand->writesize - 1) / nand->writesize;
455 l *= nand->writesize;
456
457
458
459
460
461 return min(l, *len);
462}
463#endif
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
481 u_char *buffer, int flags)
482{
483 int rval = 0, blocksize;
484 size_t left_to_write = *length;
485 u_char *p_buffer = buffer;
486 int need_skip;
487
488#ifdef CONFIG_CMD_NAND_YAFFS
489 if (flags & WITH_YAFFS_OOB) {
490 if (flags & ~WITH_YAFFS_OOB)
491 return -EINVAL;
492
493 int pages;
494 pages = nand->erasesize / nand->writesize;
495 blocksize = (pages * nand->oobsize) + nand->erasesize;
496 if (*length % (nand->writesize + nand->oobsize)) {
497 printf ("Attempt to write incomplete page"
498 " in yaffs mode\n");
499 return -EINVAL;
500 }
501 } else
502#endif
503 {
504 blocksize = nand->erasesize;
505 }
506
507
508
509
510
511
512
513
514
515
516
517
518 if ((offset & (nand->writesize - 1)) != 0) {
519 printf ("Attempt to write non page aligned data\n");
520 *length = 0;
521 return -EINVAL;
522 }
523
524 need_skip = check_skip_len(nand, offset, *length);
525 if (need_skip < 0) {
526 printf ("Attempt to write outside the flash area\n");
527 *length = 0;
528 return -EINVAL;
529 }
530
531 if (!need_skip && !(flags & WITH_DROP_FFS)) {
532 rval = nand_write (nand, offset, length, buffer);
533 if (rval == 0)
534 return 0;
535
536 *length = 0;
537 printf ("NAND write to offset %llx failed %d\n",
538 offset, rval);
539 return rval;
540 }
541
542 while (left_to_write > 0) {
543 size_t block_offset = offset & (nand->erasesize - 1);
544 size_t write_size, truncated_write_size;
545
546 WATCHDOG_RESET ();
547
548 if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
549 printf ("Skip bad block 0x%08llx\n",
550 offset & ~(nand->erasesize - 1));
551 offset += nand->erasesize - block_offset;
552 continue;
553 }
554
555 if (left_to_write < (blocksize - block_offset))
556 write_size = left_to_write;
557 else
558 write_size = blocksize - block_offset;
559
560#ifdef CONFIG_CMD_NAND_YAFFS
561 if (flags & WITH_YAFFS_OOB) {
562 int page, pages;
563 size_t pagesize = nand->writesize;
564 size_t pagesize_oob = pagesize + nand->oobsize;
565 struct mtd_oob_ops ops;
566
567 ops.len = pagesize;
568 ops.ooblen = nand->oobsize;
569 ops.mode = MTD_OOB_AUTO;
570 ops.ooboffs = 0;
571
572 pages = write_size / pagesize_oob;
573 for (page = 0; page < pages; page++) {
574 WATCHDOG_RESET();
575
576 ops.datbuf = p_buffer;
577 ops.oobbuf = ops.datbuf + pagesize;
578
579 rval = nand->write_oob(nand, offset, &ops);
580 if (!rval)
581 break;
582
583 offset += pagesize;
584 p_buffer += pagesize_oob;
585 }
586 }
587 else
588#endif
589 {
590 truncated_write_size = write_size;
591#ifdef CONFIG_CMD_NAND_TRIMFFS
592 if (flags & WITH_DROP_FFS)
593 truncated_write_size = drop_ffs(nand, p_buffer,
594 &write_size);
595#endif
596
597 rval = nand_write(nand, offset, &truncated_write_size,
598 p_buffer);
599 offset += write_size;
600 p_buffer += write_size;
601 }
602
603 if (rval != 0) {
604 printf ("NAND write to offset %llx failed %d\n",
605 offset, rval);
606 *length -= left_to_write;
607 return rval;
608 }
609
610 left_to_write -= write_size;
611 }
612
613 return 0;
614}
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
631 u_char *buffer)
632{
633 int rval;
634 size_t left_to_read = *length;
635 u_char *p_buffer = buffer;
636 int need_skip;
637
638 if ((offset & (nand->writesize - 1)) != 0) {
639 printf ("Attempt to read non page aligned data\n");
640 *length = 0;
641 return -EINVAL;
642 }
643
644 need_skip = check_skip_len(nand, offset, *length);
645 if (need_skip < 0) {
646 printf ("Attempt to read outside the flash area\n");
647 *length = 0;
648 return -EINVAL;
649 }
650
651 if (!need_skip) {
652 rval = nand_read (nand, offset, length, buffer);
653 if (!rval || rval == -EUCLEAN)
654 return 0;
655
656 *length = 0;
657 printf ("NAND read from offset %llx failed %d\n",
658 offset, rval);
659 return rval;
660 }
661
662 while (left_to_read > 0) {
663 size_t block_offset = offset & (nand->erasesize - 1);
664 size_t read_length;
665
666 WATCHDOG_RESET ();
667
668 if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
669 printf ("Skipping bad block 0x%08llx\n",
670 offset & ~(nand->erasesize - 1));
671 offset += nand->erasesize - block_offset;
672 continue;
673 }
674
675 if (left_to_read < (nand->erasesize - block_offset))
676 read_length = left_to_read;
677 else
678 read_length = nand->erasesize - block_offset;
679
680 rval = nand_read (nand, offset, &read_length, p_buffer);
681 if (rval && rval != -EUCLEAN) {
682 printf ("NAND read from offset %llx failed %d\n",
683 offset, rval);
684 *length -= left_to_read;
685 return rval;
686 }
687
688 left_to_read -= read_length;
689 offset += read_length;
690 p_buffer += read_length;
691 }
692
693 return 0;
694}
695