Update MTD to that of Linux 2.6.22.1
[platform/kernel/u-boot.git] / drivers / mtd / nand / nand_util.c
1 /*
2  * drivers/mtd/nand/nand_util.c
3  *
4  * Copyright (C) 2006 by Weiss-Electronic GmbH.
5  * All rights reserved.
6  *
7  * @author:     Guido Classen <clagix@gmail.com>
8  * @descr:      NAND Flash support
9  * @references: borrowed heavily from Linux mtd-utils code:
10  *              flash_eraseall.c by Arcom Control System Ltd
11  *              nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com)
12  *                             and Thomas Gleixner (tglx@linutronix.de)
13  *
14  * See file CREDITS for list of people who contributed to this
15  * project.
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License version
19  * 2 as published by the Free Software Foundation.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29  * MA 02111-1307 USA
30  *
31  */
32
33 #include <common.h>
34
35 #if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
36
37 #include <command.h>
38 #include <watchdog.h>
39 #include <malloc.h>
40 #include <div64.h>
41
42
43 #include <asm/errno.h>
44 #include <linux/mtd/mtd.h>
45 #include <nand.h>
46 #include <jffs2/jffs2.h>
47
48 typedef struct erase_info erase_info_t;
49 typedef struct mtd_info   mtd_info_t;
50
51 /* support only for native endian JFFS2 */
52 #define cpu_to_je16(x) (x)
53 #define cpu_to_je32(x) (x)
54
55 /*****************************************************************************/
56 static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
57 {
58         return 0;
59 }
60
61 /**
62  * nand_erase_opts: - erase NAND flash with support for various options
63  *                    (jffs2 formating)
64  *
65  * @param meminfo       NAND device to erase
66  * @param opts          options,  @see struct nand_erase_options
67  * @return              0 in case of success
68  *
69  * This code is ported from flash_eraseall.c from Linux mtd utils by
70  * Arcom Control System Ltd.
71  */
72 int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
73 {
74         struct jffs2_unknown_node cleanmarker;
75         erase_info_t erase;
76         ulong erase_length;
77         int bbtest = 1;
78         int result;
79         int percent_complete = -1;
80         int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
81         const char *mtd_device = meminfo->name;
82         struct mtd_oob_ops oob_opts;
83         struct nand_chip *chip = meminfo->priv;
84         uint8_t buf[64];
85
86         memset(buf, 0, sizeof(buf));
87         memset(&erase, 0, sizeof(erase));
88         memset(&oob_opts, 0, sizeof(oob_opts));
89
90         erase.mtd = meminfo;
91         erase.len  = meminfo->erasesize;
92         erase.addr = opts->offset;
93         erase_length = opts->length;
94
95
96         cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
97         cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
98         cleanmarker.totlen = cpu_to_je32(8);
99         cleanmarker.hdr_crc = cpu_to_je32(
100         crc32_no_comp(0, (unsigned char *) &cleanmarker,
101         sizeof(struct jffs2_unknown_node) - 4));
102
103         /* scrub option allows to erase badblock. To prevent internal
104          * check from erase() method, set block check method to dummy
105          * and disable bad block table while erasing.
106          */
107         if (opts->scrub) {
108                 struct nand_chip *priv_nand = meminfo->priv;
109
110                 nand_block_bad_old = priv_nand->block_bad;
111                 priv_nand->block_bad = nand_block_bad_scrub;
112                 /* we don't need the bad block table anymore...
113                  * after scrub, there are no bad blocks left!
114                  */
115                 if (priv_nand->bbt) {
116                         kfree(priv_nand->bbt);
117                 }
118                 priv_nand->bbt = NULL;
119         }
120
121         if (erase_length < meminfo->erasesize) {
122                 printf("Warning: Erase size 0x%08lx smaller than one "  \
123                        "erase block 0x%08x\n",erase_length, meminfo->erasesize);
124                 printf("         Erasing 0x%08x instead\n", meminfo->erasesize);
125                 erase_length = meminfo->erasesize;
126         }
127
128         for (;
129              erase.addr < opts->offset + erase_length;
130              erase.addr += meminfo->erasesize) {
131                 
132                 WATCHDOG_RESET ();
133
134                 if (!opts->scrub && bbtest) {
135                         int ret = meminfo->block_isbad(meminfo, erase.addr);
136                         if (ret > 0) {
137                                 if (!opts->quiet)
138                                         printf("\rSkipping bad block at  "
139                                                "0x%08x                   "
140                                                "                         \n",
141                                                erase.addr);
142                                 continue;
143
144                         } else if (ret < 0) {
145                                 printf("\n%s: MTD get bad block failed: %d\n",
146                                        mtd_device,
147                                        ret);
148                                 return -1;
149                         }
150                 }
151
152                 result = meminfo->erase(meminfo, &erase);
153                 if (result != 0) {
154                         printf("\n%s: MTD Erase failure: %d\n",
155                                mtd_device, result);
156                         continue;
157                 }
158
159                 /* format for JFFS2 ? */
160                 if (opts->jffs2) {
161
162                         chip->ops.len = chip->ops.ooblen = 64;
163                         chip->ops.datbuf = NULL;
164                         chip->ops.oobbuf = buf;
165                         chip->ops.ooboffs = chip->badblockpos & ~0x01;
166                         
167                         result = meminfo->write_oob(meminfo,
168                                                         erase.addr + meminfo->oobsize,
169                                                         &chip->ops);
170                         if (result != 0) {
171                                 printf("\n%s: MTD writeoob failure: %d\n",
172                                 mtd_device, result);
173                                 continue;
174                         }
175                         else
176                                 printf("%s: MTD writeoob at 0x%08x\n",mtd_device, erase.addr + meminfo->oobsize );
177                 }
178
179                 if (!opts->quiet) {
180                         unsigned long long n =(unsigned long long)
181                                 (erase.addr + meminfo->erasesize - opts->offset)
182                                 * 100;
183                         int percent;
184
185                         do_div(n, erase_length);
186                         percent = (int)n;
187
188                         /* output progress message only at whole percent
189                          * steps to reduce the number of messages printed
190                          * on (slow) serial consoles
191                          */
192                         if (percent != percent_complete) {
193                                 percent_complete = percent;
194
195                                 printf("\rErasing at 0x%x -- %3d%% complete.",
196                                 erase.addr, percent);
197
198                                 if (opts->jffs2 && result == 0)
199                                 printf(" Cleanmarker written at 0x%x.",
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 /* XXX U-BOOT XXX */
218 #if 0
219
220 #define MAX_PAGE_SIZE   2048
221 #define MAX_OOB_SIZE    64
222
223 /*
224  * buffer array used for writing data
225  */
226 static unsigned char data_buf[MAX_PAGE_SIZE];
227 static unsigned char oob_buf[MAX_OOB_SIZE];
228
229 /* OOB layouts to pass into the kernel as default */
230 static struct nand_ecclayout none_ecclayout = {
231         .useecc = MTD_NANDECC_OFF,
232 };
233
234 static struct nand_ecclayout jffs2_ecclayout = {
235         .useecc = MTD_NANDECC_PLACE,
236         .eccbytes = 6,
237         .eccpos = { 0, 1, 2, 3, 6, 7 }
238 };
239
240 static struct nand_ecclayout yaffs_ecclayout = {
241         .useecc = MTD_NANDECC_PLACE,
242         .eccbytes = 6,
243         .eccpos = { 8, 9, 10, 13, 14, 15}
244 };
245
246 static struct nand_ecclayout autoplace_ecclayout = {
247         .useecc = MTD_NANDECC_AUTOPLACE
248 };
249 #endif
250
251
252 /**
253  * nand_fill_oob - [Internal] Transfer client buffer to oob
254  * @chip:       nand chip structure
255  * @oob:        oob data buffer
256  * @ops:        oob ops structure
257  * 
258  * Copied from nand_base.c
259  */
260 static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
261                                   struct mtd_oob_ops *ops)
262 {
263         size_t len = ops->ooblen;
264
265         switch(ops->mode) {
266
267         case MTD_OOB_PLACE:
268         case MTD_OOB_RAW:
269                 memcpy(chip->oob_poi + ops->ooboffs, oob, len);
270                 return oob + len;
271
272         case MTD_OOB_AUTO: {
273                 struct nand_oobfree *free = chip->ecc.layout->oobfree;
274                 uint32_t boffs = 0, woffs = ops->ooboffs;
275                 size_t bytes = 0;
276
277                 for(; free->length && len; free++, len -= bytes) {
278                         /* Write request not from offset 0 ? */
279                         if (unlikely(woffs)) {
280                                 if (woffs >= free->length) {
281                                         woffs -= free->length;
282                                         continue;
283                                 }
284                                 boffs = free->offset + woffs;
285                                 bytes = min_t(size_t, len,
286                                               (free->length - woffs));
287                                 woffs = 0;
288                         } else {
289                                 bytes = min_t(size_t, len, free->length);
290                                 boffs = free->offset;
291                         }
292                         memcpy(chip->oob_poi + boffs, oob, bytes);
293                         oob += bytes;
294                 }
295                 return oob;
296         }
297         default:
298                 BUG();
299         }
300         return NULL;
301 }
302
303 #define NOTALIGNED(x)   (x & (chip->subpagesize - 1)) != 0
304
305
306 /* copied from nand_base.c: nand_do_write_ops()
307  * Only very small changes
308  */
309 int nand_write_opts(nand_info_t *mtd, loff_t to, mtd_oob_ops_t *ops)
310 {
311         int chipnr, realpage, page, blockmask, column;
312         struct nand_chip *chip = mtd->priv;
313         uint32_t writelen = ops->len;
314         uint8_t *oob = ops->oobbuf;
315         uint8_t *buf = ops->datbuf;
316         int ret, subpage;
317         
318         ops->retlen = 0;
319         if (!writelen)
320                 return 0;
321
322         printk("nand_write_opts: to: 0x%08x, ops->len: 0x%08x\n", to, ops->len);
323         
324         /* reject writes, which are not page aligned */
325         if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
326                 printk(KERN_NOTICE "nand_write: "
327                        "Attempt to write not page aligned data\n");
328                 return -EINVAL;
329         }
330
331         column = to & (mtd->writesize - 1);
332         subpage = column || (writelen & (mtd->writesize - 1));
333
334         if (subpage && oob) {
335                 printk(KERN_NOTICE "nand_write: "
336                        "Attempt to write oob to subpage\n");
337                 return -EINVAL;
338         }
339
340         chipnr = (int)(to >> chip->chip_shift);
341         chip->select_chip(mtd, chipnr);
342
343         /* XXX U-BOOT XXX */
344 #if 0
345         /* Check, if it is write protected */
346         if (nand_check_wp(mtd))
347                 return -EIO;
348 #endif
349
350         realpage = (int)(to >> chip->page_shift);
351         page = realpage & chip->pagemask;
352         blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
353
354         /* Invalidate the page cache, when we write to the cached page */
355         if (to <= (chip->pagebuf << chip->page_shift) &&
356             (chip->pagebuf << chip->page_shift) < (to + ops->len))
357                 chip->pagebuf = -1;
358
359         /* If we're not given explicit OOB data, let it be 0xFF */
360         if (likely(!oob)) {
361                 printf("!oob, writing %d bytes with 0xff to chip->oob_poi (0x%08x)\n", mtd->oobsize, chip->oob_poi);
362                 memset(chip->oob_poi, 0xff, mtd->oobsize);
363         }
364
365         while(1) {
366                 int bytes = mtd->writesize;
367                 int cached = writelen > bytes && page != blockmask;
368                 uint8_t *wbuf = buf;
369
370                 /* Partial page write ? */
371                 if (unlikely(column || writelen < (mtd->writesize - 1))) {
372                         cached = 0;
373                         bytes = min_t(int, bytes - column, (int) writelen);
374                         chip->pagebuf = -1;
375                         memset(chip->buffers->databuf, 0xff, mtd->writesize);
376                         memcpy(&chip->buffers->databuf[column], buf, bytes);
377                         wbuf = chip->buffers->databuf;
378                 }
379
380                 if (unlikely(oob))
381                         oob = nand_fill_oob(chip, oob, ops);
382
383                 ret = chip->write_page(mtd, chip, wbuf, page, cached,
384                                        (ops->mode == MTD_OOB_RAW));
385                 if (ret)
386                         break;
387
388                 writelen -= bytes;
389                 if (!writelen)
390                         break;
391
392                 column = 0;
393                 buf += bytes;
394                 realpage++;
395
396                 page = realpage & chip->pagemask;
397                 /* Check, if we cross a chip boundary */
398                 if (!page) {
399                         chipnr++;
400                         chip->select_chip(mtd, -1);
401                         chip->select_chip(mtd, chipnr);
402                 }
403         }
404
405         ops->retlen = ops->len - writelen;
406         if (unlikely(oob))
407                 ops->oobretlen = ops->ooblen;
408         return ret;
409 }
410
411 /* XXX U-BOOT XXX */
412 #if 0
413 /**
414  * nand_write_opts: - write image to NAND flash with support for various options
415  *
416  * @param meminfo       NAND device to erase
417  * @param opts          write options (@see nand_write_options)
418  * @return              0 in case of success
419  *
420  * This code is ported from nandwrite.c from Linux mtd utils by
421  * Steven J. Hill and Thomas Gleixner.
422  */
423 int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
424 {
425         int imglen = 0;
426         int pagelen;
427         int baderaseblock;
428         int blockstart = -1;
429         loff_t offs;
430         int readlen;
431         int ecclayoutchanged = 0;
432         int percent_complete = -1;
433         struct nand_ecclayout old_ecclayout;
434         ulong mtdoffset = opts->offset;
435         ulong erasesize_blockalign;
436         u_char *buffer = opts->buffer;
437         size_t written;
438         int result;
439
440         if (opts->pad && opts->writeoob) {
441                 printf("Can't pad when oob data is present.\n");
442                 return -1;
443         }
444
445         /* set erasesize to specified number of blocks - to match
446          * jffs2 (virtual) block size */
447         if (opts->blockalign == 0) {
448                 erasesize_blockalign = meminfo->erasesize;
449         } else {
450                 erasesize_blockalign = meminfo->erasesize * opts->blockalign;
451         }
452
453         /* make sure device page sizes are valid */
454         if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
455             && !(meminfo->oobsize == 8 && meminfo->writesize == 256)
456             && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {
457                 printf("Unknown flash (not normal NAND)\n");
458                 return -1;
459         }
460
461         /* read the current oob info */
462         memcpy(&old_ecclayout, &meminfo->ecclayout, sizeof(old_ecclayout));
463
464         /* write without ecc? */
465         if (opts->noecc) {
466                 memcpy(&meminfo->ecclayout, &none_ecclayout,
467                        sizeof(meminfo->ecclayout));
468                 ecclayoutchanged = 1;
469         }
470
471         /* autoplace ECC? */
472         if (opts->autoplace && (old_ecclayout.useecc != MTD_NANDECC_AUTOPLACE)) {
473
474                 memcpy(&meminfo->ecclayout, &autoplace_ecclayout,
475                        sizeof(meminfo->ecclayout));
476                 ecclayoutchanged = 1;
477         }
478
479         /* force OOB layout for jffs2 or yaffs? */
480         if (opts->forcejffs2 || opts->forceyaffs) {
481                 struct nand_ecclayout *oobsel =
482                         opts->forcejffs2 ? &jffs2_ecclayout : &yaffs_ecclayout;
483
484                 if (meminfo->oobsize == 8) {
485                         if (opts->forceyaffs) {
486                                 printf("YAFSS cannot operate on "
487                                        "256 Byte page size\n");
488                                 goto restoreoob;
489                         }
490                         /* Adjust number of ecc bytes */
491                         jffs2_ecclayout.eccbytes = 3;
492                 }
493
494                 memcpy(&meminfo->ecclayout, oobsel, sizeof(meminfo->ecclayout));
495         }
496
497         /* get image length */
498         imglen = opts->length;
499         pagelen = meminfo->writesize
500                 + ((opts->writeoob != 0) ? meminfo->oobsize : 0);
501
502         /* check, if file is pagealigned */
503         if ((!opts->pad) && ((imglen % pagelen) != 0)) {
504                 printf("Input block length is not page aligned\n");
505                 goto restoreoob;
506         }
507
508         /* check, if length fits into device */
509         if (((imglen / pagelen) * meminfo->writesize)
510              > (meminfo->size - opts->offset)) {
511                 printf("Image %d bytes, NAND page %d bytes, "
512                        "OOB area %u bytes, device size %u bytes\n",
513                        imglen, pagelen, meminfo->writesize, meminfo->size);
514                 printf("Input block does not fit into device\n");
515                 goto restoreoob;
516         }
517
518         if (!opts->quiet)
519                 printf("\n");
520
521         /* get data from input and write to the device */
522         while (imglen && (mtdoffset < meminfo->size)) {
523
524                 WATCHDOG_RESET ();
525
526                 /*
527                  * new eraseblock, check for bad block(s). Stay in the
528                  * loop to be sure if the offset changes because of
529                  * a bad block, that the next block that will be
530                  * written to is also checked. Thus avoiding errors if
531                  * the block(s) after the skipped block(s) is also bad
532                  * (number of blocks depending on the blockalign
533                  */
534                 while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
535                         blockstart = mtdoffset & (~erasesize_blockalign+1);
536                         offs = blockstart;
537                         baderaseblock = 0;
538
539                         /* check all the blocks in an erase block for
540                          * bad blocks */
541                         do {
542                                 int ret = meminfo->block_isbad(meminfo, offs);
543
544                                 if (ret < 0) {
545                                         printf("Bad block check failed\n");
546                                         goto restoreoob;
547                                 }
548                                 if (ret == 1) {
549                                         baderaseblock = 1;
550                                         if (!opts->quiet)
551                                                 printf("\rBad block at 0x%lx "
552                                                        "in erase block from "
553                                                        "0x%x will be skipped\n",
554                                                        (long) offs,
555                                                        blockstart);
556                                 }
557
558                                 if (baderaseblock) {
559                                         mtdoffset = blockstart
560                                                 + erasesize_blockalign;
561                                 }
562                                 offs +=  erasesize_blockalign
563                                         / opts->blockalign;
564                         } while (offs < blockstart + erasesize_blockalign);
565                 }
566
567                 readlen = meminfo->writesize;
568                 if (opts->pad && (imglen < readlen)) {
569                         readlen = imglen;
570                         memset(data_buf + readlen, 0xff,
571                                meminfo->writesize - readlen);
572                 }
573
574                 /* read page data from input memory buffer */
575                 memcpy(data_buf, buffer, readlen);
576                 buffer += readlen;
577
578                 if (opts->writeoob) {
579                         /* read OOB data from input memory block, exit
580                          * on failure */
581                         memcpy(oob_buf, buffer, meminfo->oobsize);
582                         buffer += meminfo->oobsize;
583
584                         /* write OOB data first, as ecc will be placed
585                          * in there*/
586                         result = meminfo->write_oob(meminfo,
587                                                     mtdoffset,
588                                                     meminfo->oobsize,
589                                                     &written,
590                                                     (unsigned char *)
591                                                     &oob_buf);
592
593                         if (result != 0) {
594                                 printf("\nMTD writeoob failure: %d\n",
595                                        result);
596                                 goto restoreoob;
597                         }
598                         imglen -= meminfo->oobsize;
599                 }
600
601                 /* write out the page data */
602                 result = meminfo->write(meminfo,
603                                         mtdoffset,
604                                         meminfo->writesize,
605                                         &written,
606                                         (unsigned char *) &data_buf);
607
608                 if (result != 0) {
609                         printf("writing NAND page at offset 0x%lx failed\n",
610                                mtdoffset);
611                         goto restoreoob;
612                 }
613                 imglen -= readlen;
614
615                 if (!opts->quiet) {
616                         unsigned long long n = (unsigned long long)
617                                  (opts->length-imglen) * 100;
618                         int percent;
619
620                         do_div(n, opts->length);
621                         percent = (int)n;
622
623                         /* output progress message only at whole percent
624                          * steps to reduce the number of messages printed
625                          * on (slow) serial consoles
626                          */
627                         if (percent != percent_complete) {
628                                 printf("\rWriting data at 0x%lx "
629                                        "-- %3d%% complete.",
630                                        mtdoffset, percent);
631                                 percent_complete = percent;
632                         }
633                 }
634
635                 mtdoffset += meminfo->writesize;
636         }
637
638         if (!opts->quiet)
639                 printf("\n");
640
641 restoreoob:
642         if (ecclayoutchanged) {
643                 memcpy(&meminfo->ecclayout, &old_ecclayout,
644                        sizeof(meminfo->ecclayout));
645         }
646
647         if (imglen > 0) {
648                 printf("Data did not fit into device, due to bad blocks\n");
649                 return -1;
650         }
651
652         /* return happy */
653         return 0;
654 }
655
656 /**
657  * nand_read_opts: - read image from NAND flash with support for various options
658  *
659  * @param meminfo       NAND device to erase
660  * @param opts          read options (@see struct nand_read_options)
661  * @return              0 in case of success
662  *
663  */
664 int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
665 {
666         int imglen = opts->length;
667         int pagelen;
668         int baderaseblock;
669         int blockstart = -1;
670         int percent_complete = -1;
671         loff_t offs;
672         size_t readlen;
673         ulong mtdoffset = opts->offset;
674         u_char *buffer = opts->buffer;
675         int result;
676
677         /* make sure device page sizes are valid */
678         if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
679             && !(meminfo->oobsize == 8 && meminfo->writesize == 256)
680             && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {
681                 printf("Unknown flash (not normal NAND)\n");
682                 return -1;
683         }
684
685         pagelen = meminfo->writesize
686                 + ((opts->readoob != 0) ? meminfo->oobsize : 0);
687
688         /* check, if length is not larger than device */
689         if (((imglen / pagelen) * meminfo->writesize)
690              > (meminfo->size - opts->offset)) {
691                 printf("Image %d bytes, NAND page %d bytes, "
692                        "OOB area %u bytes, device size %u bytes\n",
693                        imglen, pagelen, meminfo->writesize, meminfo->size);
694                 printf("Input block is larger than device\n");
695                 return -1;
696         }
697
698         if (!opts->quiet)
699                 printf("\n");
700
701         /* get data from input and write to the device */
702         while (imglen && (mtdoffset < meminfo->size)) {
703
704                 WATCHDOG_RESET ();
705
706                 /*
707                  * new eraseblock, check for bad block(s). Stay in the
708                  * loop to be sure if the offset changes because of
709                  * a bad block, that the next block that will be
710                  * written to is also checked. Thus avoiding errors if
711                  * the block(s) after the skipped block(s) is also bad
712                  * (number of blocks depending on the blockalign
713                  */
714                 while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {
715                         blockstart = mtdoffset & (~meminfo->erasesize+1);
716                         offs = blockstart;
717                         baderaseblock = 0;
718
719                         /* check all the blocks in an erase block for
720                          * bad blocks */
721                         do {
722                                 int ret = meminfo->block_isbad(meminfo, offs);
723
724                                 if (ret < 0) {
725                                         printf("Bad block check failed\n");
726                                         return -1;
727                                 }
728                                 if (ret == 1) {
729                                         baderaseblock = 1;
730                                         if (!opts->quiet)
731                                                 printf("\rBad block at 0x%lx "
732                                                        "in erase block from "
733                                                        "0x%x will be skipped\n",
734                                                        (long) offs,
735                                                        blockstart);
736                                 }
737
738                                 if (baderaseblock) {
739                                         mtdoffset = blockstart
740                                                 + meminfo->erasesize;
741                                 }
742                                 offs +=  meminfo->erasesize;
743
744                         } while (offs < blockstart + meminfo->erasesize);
745                 }
746
747
748                 /* read page data to memory buffer */
749                 result = meminfo->read(meminfo,
750                                        mtdoffset,
751                                        meminfo->writesize,
752                                        &readlen,
753                                        (unsigned char *) &data_buf);
754
755                 if (result != 0) {
756                         printf("reading NAND page at offset 0x%lx failed\n",
757                                mtdoffset);
758                         return -1;
759                 }
760
761                 if (imglen < readlen) {
762                         readlen = imglen;
763                 }
764
765                 memcpy(buffer, data_buf, readlen);
766                 buffer += readlen;
767                 imglen -= readlen;
768
769                 if (opts->readoob) {
770                         result = meminfo->read_oob(meminfo,
771                                                    mtdoffset,
772                                                    meminfo->oobsize,
773                                                    &readlen,
774                                                    (unsigned char *)
775                                                    &oob_buf);
776
777                         if (result != 0) {
778                                 printf("\nMTD readoob failure: %d\n",
779                                        result);
780                                 return -1;
781                         }
782
783
784                         if (imglen < readlen) {
785                                 readlen = imglen;
786                         }
787
788                         memcpy(buffer, oob_buf, readlen);
789
790                         buffer += readlen;
791                         imglen -= readlen;
792                 }
793
794                 if (!opts->quiet) {
795                         unsigned long long n = (unsigned long long)
796                                  (opts->length-imglen) * 100;
797                         int percent;
798
799                         do_div(n, opts->length);
800                         percent = (int)n;
801
802                         /* output progress message only at whole percent
803                          * steps to reduce the number of messages printed
804                          * on (slow) serial consoles
805                          */
806                         if (percent != percent_complete) {
807                         if (!opts->quiet)
808                                 printf("\rReading data from 0x%lx "
809                                        "-- %3d%% complete.",
810                                        mtdoffset, percent);
811                                 percent_complete = percent;
812                         }
813                 }
814
815                 mtdoffset += meminfo->writesize;
816         }
817
818         if (!opts->quiet)
819                 printf("\n");
820
821         if (imglen > 0) {
822                 printf("Could not read entire image due to bad blocks\n");
823                 return -1;
824         }
825
826         /* return happy */
827         return 0;
828 }
829 #endif
830
831 /* XXX U-BOOT XXX */
832 #if 0
833 /******************************************************************************
834  * Support for locking / unlocking operations of some NAND devices
835  *****************************************************************************/
836
837 #define NAND_CMD_LOCK           0x2a
838 #define NAND_CMD_LOCK_TIGHT     0x2c
839 #define NAND_CMD_UNLOCK1        0x23
840 #define NAND_CMD_UNLOCK2        0x24
841 #define NAND_CMD_LOCK_STATUS    0x7a
842
843 /**
844  * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
845  *            state
846  *
847  * @param meminfo       nand mtd instance
848  * @param tight         bring device in lock tight mode
849  *
850  * @return              0 on success, -1 in case of error
851  *
852  * The lock / lock-tight command only applies to the whole chip. To get some
853  * parts of the chip lock and others unlocked use the following sequence:
854  *
855  * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin)
856  * - Call nand_unlock() once for each consecutive area to be unlocked
857  * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1)
858  *
859  *   If the device is in lock-tight state software can't change the
860  *   current active lock/unlock state of all pages. nand_lock() / nand_unlock()
861  *   calls will fail. It is only posible to leave lock-tight state by
862  *   an hardware signal (low pulse on _WP pin) or by power down.
863  */
864 int nand_lock(nand_info_t *meminfo, int tight)
865 {
866         int ret = 0;
867         int status;
868         struct nand_chip *this = meminfo->priv;
869
870         /* select the NAND device */
871         this->select_chip(meminfo, 0);
872
873         this->cmdfunc(meminfo,
874                       (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
875                       -1, -1);
876
877         /* call wait ready function */
878         status = this->waitfunc(meminfo, this, FL_WRITING);
879
880         /* see if device thinks it succeeded */
881         if (status & 0x01) {
882                 ret = -1;
883         }
884
885         /* de-select the NAND device */
886         this->select_chip(meminfo, -1);
887         return ret;
888 }
889
890 /**
891  * nand_get_lock_status: - query current lock state from one page of NAND
892  *                         flash
893  *
894  * @param meminfo       nand mtd instance
895  * @param offset        page address to query (muss be page aligned!)
896  *
897  * @return              -1 in case of error
898  *                      >0 lock status:
899  *                        bitfield with the following combinations:
900  *                        NAND_LOCK_STATUS_TIGHT: page in tight state
901  *                        NAND_LOCK_STATUS_LOCK:  page locked
902  *                        NAND_LOCK_STATUS_UNLOCK: page unlocked
903  *
904  */
905 int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
906 {
907         int ret = 0;
908         int chipnr;
909         int page;
910         struct nand_chip *this = meminfo->priv;
911
912         /* select the NAND device */
913         chipnr = (int)(offset >> this->chip_shift);
914         this->select_chip(meminfo, chipnr);
915
916
917         if ((offset & (meminfo->writesize - 1)) != 0) {
918                 printf ("nand_get_lock_status: "
919                         "Start address must be beginning of "
920                         "nand page!\n");
921                 ret = -1;
922                 goto out;
923         }
924
925         /* check the Lock Status */
926         page = (int)(offset >> this->page_shift);
927         this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);
928
929         ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT
930                                           | NAND_LOCK_STATUS_LOCK
931                                           | NAND_LOCK_STATUS_UNLOCK);
932
933  out:
934         /* de-select the NAND device */
935         this->select_chip(meminfo, -1);
936         return ret;
937 }
938
939 /**
940  * nand_unlock: - Unlock area of NAND pages
941  *                only one consecutive area can be unlocked at one time!
942  *
943  * @param meminfo       nand mtd instance
944  * @param start         start byte address
945  * @param length        number of bytes to unlock (must be a multiple of
946  *                      page size nand->writesize)
947  *
948  * @return              0 on success, -1 in case of error
949  */
950 int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
951 {
952         int ret = 0;
953         int chipnr;
954         int status;
955         int page;
956         struct nand_chip *this = meminfo->priv;
957         printf ("nand_unlock: start: %08x, length: %d!\n",
958                 (int)start, (int)length);
959
960         /* select the NAND device */
961         chipnr = (int)(start >> this->chip_shift);
962         this->select_chip(meminfo, chipnr);
963
964         /* check the WP bit */
965         this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);
966         if ((this->read_byte(meminfo) & 0x80) == 0) {
967                 printf ("nand_unlock: Device is write protected!\n");
968                 ret = -1;
969                 goto out;
970         }
971
972         if ((start & (meminfo->writesize - 1)) != 0) {
973                 printf ("nand_unlock: Start address must be beginning of "
974                         "nand page!\n");
975                 ret = -1;
976                 goto out;
977         }
978
979         if (length == 0 || (length & (meminfo->writesize - 1)) != 0) {
980                 printf ("nand_unlock: Length must be a multiple of nand page "
981                         "size!\n");
982                 ret = -1;
983                 goto out;
984         }
985
986         /* submit address of first page to unlock */
987         page = (int)(start >> this->page_shift);
988         this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
989
990         /* submit ADDRESS of LAST page to unlock */
991         page += (int)(length >> this->page_shift) - 1;
992         this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
993
994         /* call wait ready function */
995         status = this->waitfunc(meminfo, this, FL_WRITING);
996         /* see if device thinks it succeeded */
997         if (status & 0x01) {
998                 /* there was an error */
999                 ret = -1;
1000                 goto out;
1001         }
1002
1003  out:
1004         /* de-select the NAND device */
1005         this->select_chip(meminfo, -1);
1006         return ret;
1007 }
1008 #endif
1009
1010 #endif