blob: 4fd4e166e6ad6c36ed9d7ac9a8178b36e8ec6d9b [file] [log] [blame]
Stefan Roesed351b2b2006-10-10 12:36:02 +02001/*
2 * drivers/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
Jon Loeliger82ecaad2007-07-09 17:39:42 -050035#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
Stefan Roesed351b2b2006-10-10 12:36:02 +020036
37#include <command.h>
38#include <watchdog.h>
39#include <malloc.h>
Dirk Behme32d1f762007-08-02 17:42:08 +020040#include <div64.h>
Stefan Roesed351b2b2006-10-10 12:36:02 +020041
42#include <nand.h>
43#include <jffs2/jffs2.h>
44
45typedef struct erase_info erase_info_t;
46typedef struct mtd_info mtd_info_t;
47
48/* support only for native endian JFFS2 */
49#define cpu_to_je16(x) (x)
50#define cpu_to_je32(x) (x)
51
52/*****************************************************************************/
53static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
54{
55 return 0;
56}
57
58/**
59 * nand_erase_opts: - erase NAND flash with support for various options
60 * (jffs2 formating)
61 *
62 * @param meminfo NAND device to erase
63 * @param opts options, @see struct nand_erase_options
64 * @return 0 in case of success
65 *
66 * This code is ported from flash_eraseall.c from Linux mtd utils by
67 * Arcom Control System Ltd.
68 */
69int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
70{
71 struct jffs2_unknown_node cleanmarker;
72 int clmpos = 0;
73 int clmlen = 8;
74 erase_info_t erase;
75 ulong erase_length;
76 int isNAND;
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
83 memset(&erase, 0, sizeof(erase));
84
85 erase.mtd = meminfo;
86 erase.len = meminfo->erasesize;
Stefan Roese198b23e2006-10-28 15:55:52 +020087 erase.addr = opts->offset;
88 erase_length = opts->length;
Stefan Roesed351b2b2006-10-10 12:36:02 +020089
90 isNAND = meminfo->type == MTD_NANDFLASH ? 1 : 0;
91
92 if (opts->jffs2) {
93 cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
94 cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
95 if (isNAND) {
96 struct nand_oobinfo *oobinfo = &meminfo->oobinfo;
97
98 /* check for autoplacement */
99 if (oobinfo->useecc == MTD_NANDECC_AUTOPLACE) {
100 /* get the position of the free bytes */
101 if (!oobinfo->oobfree[0][1]) {
102 printf(" Eeep. Autoplacement selected "
103 "and no empty space in oob\n");
104 return -1;
105 }
106 clmpos = oobinfo->oobfree[0][0];
107 clmlen = oobinfo->oobfree[0][1];
108 if (clmlen > 8)
109 clmlen = 8;
110 } else {
111 /* legacy mode */
112 switch (meminfo->oobsize) {
113 case 8:
114 clmpos = 6;
115 clmlen = 2;
116 break;
117 case 16:
118 clmpos = 8;
119 clmlen = 8;
120 break;
121 case 64:
122 clmpos = 16;
123 clmlen = 8;
124 break;
125 }
126 }
127
128 cleanmarker.totlen = cpu_to_je32(8);
129 } else {
130 cleanmarker.totlen =
131 cpu_to_je32(sizeof(struct jffs2_unknown_node));
132 }
133 cleanmarker.hdr_crc = cpu_to_je32(
134 crc32_no_comp(0, (unsigned char *) &cleanmarker,
135 sizeof(struct jffs2_unknown_node) - 4));
136 }
137
138 /* scrub option allows to erase badblock. To prevent internal
139 * check from erase() method, set block check method to dummy
140 * and disable bad block table while erasing.
141 */
142 if (opts->scrub) {
143 struct nand_chip *priv_nand = meminfo->priv;
144
145 nand_block_bad_old = priv_nand->block_bad;
146 priv_nand->block_bad = nand_block_bad_scrub;
147 /* we don't need the bad block table anymore...
148 * after scrub, there are no bad blocks left!
149 */
150 if (priv_nand->bbt) {
151 kfree(priv_nand->bbt);
152 }
153 priv_nand->bbt = NULL;
154 }
155
156 for (;
157 erase.addr < opts->offset + erase_length;
158 erase.addr += meminfo->erasesize) {
159
160 WATCHDOG_RESET ();
161
162 if (!opts->scrub && bbtest) {
163 int ret = meminfo->block_isbad(meminfo, erase.addr);
164 if (ret > 0) {
165 if (!opts->quiet)
166 printf("\rSkipping bad block at "
Wolfgang Denkd5cf1a42006-10-12 11:43:47 +0200167 "0x%08x "
168 " \n",
169 erase.addr);
Stefan Roesed351b2b2006-10-10 12:36:02 +0200170 continue;
171
172 } else if (ret < 0) {
173 printf("\n%s: MTD get bad block failed: %d\n",
174 mtd_device,
175 ret);
176 return -1;
177 }
178 }
179
180 result = meminfo->erase(meminfo, &erase);
181 if (result != 0) {
182 printf("\n%s: MTD Erase failure: %d\n",
183 mtd_device, result);
184 continue;
185 }
186
187 /* format for JFFS2 ? */
188 if (opts->jffs2) {
189
190 /* write cleanmarker */
191 if (isNAND) {
192 size_t written;
193 result = meminfo->write_oob(meminfo,
194 erase.addr + clmpos,
195 clmlen,
196 &written,
197 (unsigned char *)
198 &cleanmarker);
199 if (result != 0) {
200 printf("\n%s: MTD writeoob failure: %d\n",
201 mtd_device, result);
202 continue;
203 }
204 } else {
205 printf("\n%s: this erase routine only supports"
206 " NAND devices!\n",
207 mtd_device);
208 }
209 }
210
211 if (!opts->quiet) {
Wolfgang Denk36882932007-08-13 21:57:53 +0200212 unsigned long long n =(unsigned long long)
Matthias Fuchs82714b92007-09-11 17:04:00 +0200213 (erase.addr + meminfo->erasesize - opts->offset)
214 * 100;
215 int percent;
216
217 do_div(n, erase_length);
218 percent = (int)n;
Stefan Roesed351b2b2006-10-10 12:36:02 +0200219
220 /* output progress message only at whole percent
221 * steps to reduce the number of messages printed
222 * on (slow) serial consoles
223 */
224 if (percent != percent_complete) {
225 percent_complete = percent;
226
227 printf("\rErasing at 0x%x -- %3d%% complete.",
228 erase.addr, percent);
229
230 if (opts->jffs2 && result == 0)
231 printf(" Cleanmarker written at 0x%x.",
232 erase.addr);
233 }
234 }
235 }
236 if (!opts->quiet)
237 printf("\n");
238
239 if (nand_block_bad_old) {
240 struct nand_chip *priv_nand = meminfo->priv;
241
242 priv_nand->block_bad = nand_block_bad_old;
243 priv_nand->scan_bbt(meminfo);
244 }
245
246 return 0;
247}
248
249#define MAX_PAGE_SIZE 2048
250#define MAX_OOB_SIZE 64
251
252/*
253 * buffer array used for writing data
254 */
255static unsigned char data_buf[MAX_PAGE_SIZE];
256static unsigned char oob_buf[MAX_OOB_SIZE];
257
258/* OOB layouts to pass into the kernel as default */
259static struct nand_oobinfo none_oobinfo = {
260 .useecc = MTD_NANDECC_OFF,
261};
262
263static struct nand_oobinfo jffs2_oobinfo = {
264 .useecc = MTD_NANDECC_PLACE,
265 .eccbytes = 6,
266 .eccpos = { 0, 1, 2, 3, 6, 7 }
267};
268
269static struct nand_oobinfo yaffs_oobinfo = {
270 .useecc = MTD_NANDECC_PLACE,
271 .eccbytes = 6,
272 .eccpos = { 8, 9, 10, 13, 14, 15}
273};
274
275static struct nand_oobinfo autoplace_oobinfo = {
276 .useecc = MTD_NANDECC_AUTOPLACE
277};
278
279/**
280 * nand_write_opts: - write image to NAND flash with support for various options
281 *
282 * @param meminfo NAND device to erase
283 * @param opts write options (@see nand_write_options)
284 * @return 0 in case of success
285 *
286 * This code is ported from nandwrite.c from Linux mtd utils by
287 * Steven J. Hill and Thomas Gleixner.
288 */
289int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
290{
291 int imglen = 0;
292 int pagelen;
293 int baderaseblock;
294 int blockstart = -1;
295 loff_t offs;
296 int readlen;
297 int oobinfochanged = 0;
298 int percent_complete = -1;
299 struct nand_oobinfo old_oobinfo;
300 ulong mtdoffset = opts->offset;
301 ulong erasesize_blockalign;
302 u_char *buffer = opts->buffer;
303 size_t written;
304 int result;
305
306 if (opts->pad && opts->writeoob) {
307 printf("Can't pad when oob data is present.\n");
308 return -1;
309 }
310
311 /* set erasesize to specified number of blocks - to match
312 * jffs2 (virtual) block size */
313 if (opts->blockalign == 0) {
314 erasesize_blockalign = meminfo->erasesize;
315 } else {
316 erasesize_blockalign = meminfo->erasesize * opts->blockalign;
317 }
318
319 /* make sure device page sizes are valid */
320 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
321 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
322 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
323 printf("Unknown flash (not normal NAND)\n");
324 return -1;
325 }
326
327 /* read the current oob info */
328 memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo));
329
330 /* write without ecc? */
331 if (opts->noecc) {
332 memcpy(&meminfo->oobinfo, &none_oobinfo,
333 sizeof(meminfo->oobinfo));
334 oobinfochanged = 1;
335 }
336
337 /* autoplace ECC? */
338 if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
339
340 memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
341 sizeof(meminfo->oobinfo));
342 oobinfochanged = 1;
343 }
344
345 /* force OOB layout for jffs2 or yaffs? */
346 if (opts->forcejffs2 || opts->forceyaffs) {
347 struct nand_oobinfo *oobsel =
348 opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
349
350 if (meminfo->oobsize == 8) {
351 if (opts->forceyaffs) {
352 printf("YAFSS cannot operate on "
353 "256 Byte page size\n");
354 goto restoreoob;
355 }
356 /* Adjust number of ecc bytes */
357 jffs2_oobinfo.eccbytes = 3;
358 }
359
360 memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo));
361 }
362
363 /* get image length */
364 imglen = opts->length;
365 pagelen = meminfo->oobblock
366 + ((opts->writeoob != 0) ? meminfo->oobsize : 0);
367
368 /* check, if file is pagealigned */
369 if ((!opts->pad) && ((imglen % pagelen) != 0)) {
370 printf("Input block length is not page aligned\n");
371 goto restoreoob;
372 }
373
374 /* check, if length fits into device */
375 if (((imglen / pagelen) * meminfo->oobblock)
376 > (meminfo->size - opts->offset)) {
377 printf("Image %d bytes, NAND page %d bytes, "
378 "OOB area %u bytes, device size %u bytes\n",
379 imglen, pagelen, meminfo->oobblock, meminfo->size);
380 printf("Input block does not fit into device\n");
381 goto restoreoob;
382 }
383
384 if (!opts->quiet)
385 printf("\n");
386
387 /* get data from input and write to the device */
388 while (imglen && (mtdoffset < meminfo->size)) {
389
390 WATCHDOG_RESET ();
391
392 /*
393 * new eraseblock, check for bad block(s). Stay in the
394 * loop to be sure if the offset changes because of
395 * a bad block, that the next block that will be
396 * written to is also checked. Thus avoiding errors if
397 * the block(s) after the skipped block(s) is also bad
398 * (number of blocks depending on the blockalign
399 */
400 while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
401 blockstart = mtdoffset & (~erasesize_blockalign+1);
402 offs = blockstart;
403 baderaseblock = 0;
404
405 /* check all the blocks in an erase block for
406 * bad blocks */
407 do {
408 int ret = meminfo->block_isbad(meminfo, offs);
409
410 if (ret < 0) {
411 printf("Bad block check failed\n");
412 goto restoreoob;
413 }
414 if (ret == 1) {
415 baderaseblock = 1;
416 if (!opts->quiet)
417 printf("\rBad block at 0x%lx "
418 "in erase block from "
419 "0x%x will be skipped\n",
420 (long) offs,
421 blockstart);
422 }
423
424 if (baderaseblock) {
425 mtdoffset = blockstart
426 + erasesize_blockalign;
427 }
428 offs += erasesize_blockalign
429 / opts->blockalign;
430 } while (offs < blockstart + erasesize_blockalign);
431 }
432
433 readlen = meminfo->oobblock;
434 if (opts->pad && (imglen < readlen)) {
435 readlen = imglen;
436 memset(data_buf + readlen, 0xff,
437 meminfo->oobblock - readlen);
438 }
439
440 /* read page data from input memory buffer */
441 memcpy(data_buf, buffer, readlen);
442 buffer += readlen;
443
444 if (opts->writeoob) {
445 /* read OOB data from input memory block, exit
446 * on failure */
447 memcpy(oob_buf, buffer, meminfo->oobsize);
448 buffer += meminfo->oobsize;
449
450 /* write OOB data first, as ecc will be placed
451 * in there*/
452 result = meminfo->write_oob(meminfo,
453 mtdoffset,
454 meminfo->oobsize,
455 &written,
456 (unsigned char *)
457 &oob_buf);
458
459 if (result != 0) {
460 printf("\nMTD writeoob failure: %d\n",
461 result);
462 goto restoreoob;
463 }
464 imglen -= meminfo->oobsize;
465 }
466
467 /* write out the page data */
468 result = meminfo->write(meminfo,
469 mtdoffset,
470 meminfo->oobblock,
471 &written,
472 (unsigned char *) &data_buf);
473
474 if (result != 0) {
475 printf("writing NAND page at offset 0x%lx failed\n",
476 mtdoffset);
477 goto restoreoob;
478 }
479 imglen -= readlen;
480
481 if (!opts->quiet) {
Wolfgang Denk36882932007-08-13 21:57:53 +0200482 unsigned long long n = (unsigned long long)
483 (opts->length-imglen) * 100;
Matthias Fuchs82714b92007-09-11 17:04:00 +0200484 int percent;
485
486 do_div(n, opts->length);
487 percent = (int)n;
488
Stefan Roesed351b2b2006-10-10 12:36:02 +0200489 /* output progress message only at whole percent
490 * steps to reduce the number of messages printed
491 * on (slow) serial consoles
492 */
493 if (percent != percent_complete) {
494 printf("\rWriting data at 0x%x "
495 "-- %3d%% complete.",
496 mtdoffset, percent);
497 percent_complete = percent;
498 }
499 }
500
501 mtdoffset += meminfo->oobblock;
502 }
503
504 if (!opts->quiet)
505 printf("\n");
506
507restoreoob:
508 if (oobinfochanged) {
509 memcpy(&meminfo->oobinfo, &old_oobinfo,
510 sizeof(meminfo->oobinfo));
511 }
512
513 if (imglen > 0) {
514 printf("Data did not fit into device, due to bad blocks\n");
515 return -1;
516 }
517
518 /* return happy */
519 return 0;
520}
521
522/**
523 * nand_read_opts: - read image from NAND flash with support for various options
524 *
525 * @param meminfo NAND device to erase
526 * @param opts read options (@see struct nand_read_options)
527 * @return 0 in case of success
528 *
529 */
530int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
531{
532 int imglen = opts->length;
533 int pagelen;
534 int baderaseblock;
535 int blockstart = -1;
536 int percent_complete = -1;
537 loff_t offs;
538 size_t readlen;
539 ulong mtdoffset = opts->offset;
540 u_char *buffer = opts->buffer;
541 int result;
542
543 /* make sure device page sizes are valid */
544 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
545 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
546 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
547 printf("Unknown flash (not normal NAND)\n");
548 return -1;
549 }
550
551 pagelen = meminfo->oobblock
552 + ((opts->readoob != 0) ? meminfo->oobsize : 0);
553
554 /* check, if length is not larger than device */
555 if (((imglen / pagelen) * meminfo->oobblock)
556 > (meminfo->size - opts->offset)) {
557 printf("Image %d bytes, NAND page %d bytes, "
558 "OOB area %u bytes, device size %u bytes\n",
559 imglen, pagelen, meminfo->oobblock, meminfo->size);
560 printf("Input block is larger than device\n");
561 return -1;
562 }
563
564 if (!opts->quiet)
565 printf("\n");
566
567 /* get data from input and write to the device */
568 while (imglen && (mtdoffset < meminfo->size)) {
569
570 WATCHDOG_RESET ();
571
572 /*
573 * new eraseblock, check for bad block(s). Stay in the
574 * loop to be sure if the offset changes because of
575 * a bad block, that the next block that will be
576 * written to is also checked. Thus avoiding errors if
577 * the block(s) after the skipped block(s) is also bad
578 * (number of blocks depending on the blockalign
579 */
580 while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {
581 blockstart = mtdoffset & (~meminfo->erasesize+1);
582 offs = blockstart;
583 baderaseblock = 0;
584
585 /* check all the blocks in an erase block for
586 * bad blocks */
587 do {
588 int ret = meminfo->block_isbad(meminfo, offs);
589
590 if (ret < 0) {
591 printf("Bad block check failed\n");
592 return -1;
593 }
594 if (ret == 1) {
595 baderaseblock = 1;
596 if (!opts->quiet)
597 printf("\rBad block at 0x%lx "
598 "in erase block from "
599 "0x%x will be skipped\n",
600 (long) offs,
601 blockstart);
602 }
603
604 if (baderaseblock) {
605 mtdoffset = blockstart
606 + meminfo->erasesize;
607 }
608 offs += meminfo->erasesize;
609
610 } while (offs < blockstart + meminfo->erasesize);
611 }
612
613
614 /* read page data to memory buffer */
615 result = meminfo->read(meminfo,
616 mtdoffset,
617 meminfo->oobblock,
618 &readlen,
619 (unsigned char *) &data_buf);
620
621 if (result != 0) {
622 printf("reading NAND page at offset 0x%lx failed\n",
623 mtdoffset);
624 return -1;
625 }
626
627 if (imglen < readlen) {
628 readlen = imglen;
629 }
630
631 memcpy(buffer, data_buf, readlen);
632 buffer += readlen;
633 imglen -= readlen;
634
635 if (opts->readoob) {
636 result = meminfo->read_oob(meminfo,
637 mtdoffset,
638 meminfo->oobsize,
639 &readlen,
640 (unsigned char *)
641 &oob_buf);
642
643 if (result != 0) {
644 printf("\nMTD readoob failure: %d\n",
645 result);
646 return -1;
647 }
648
649
650 if (imglen < readlen) {
651 readlen = imglen;
652 }
653
654 memcpy(buffer, oob_buf, readlen);
655
656 buffer += readlen;
657 imglen -= readlen;
658 }
659
660 if (!opts->quiet) {
Wolfgang Denk36882932007-08-13 21:57:53 +0200661 unsigned long long n = (unsigned long long)
662 (opts->length-imglen) * 100;
Matthias Fuchs82714b92007-09-11 17:04:00 +0200663 int percent;
664
665 do_div(n, opts->length);
666 percent = (int)n;
667
Stefan Roesed351b2b2006-10-10 12:36:02 +0200668 /* output progress message only at whole percent
669 * steps to reduce the number of messages printed
670 * on (slow) serial consoles
671 */
672 if (percent != percent_complete) {
673 if (!opts->quiet)
674 printf("\rReading data from 0x%x "
675 "-- %3d%% complete.",
676 mtdoffset, percent);
677 percent_complete = percent;
678 }
679 }
680
681 mtdoffset += meminfo->oobblock;
682 }
683
684 if (!opts->quiet)
685 printf("\n");
686
687 if (imglen > 0) {
688 printf("Could not read entire image due to bad blocks\n");
689 return -1;
690 }
691
692 /* return happy */
693 return 0;
694}
695
696/******************************************************************************
697 * Support for locking / unlocking operations of some NAND devices
698 *****************************************************************************/
699
700#define NAND_CMD_LOCK 0x2a
701#define NAND_CMD_LOCK_TIGHT 0x2c
702#define NAND_CMD_UNLOCK1 0x23
703#define NAND_CMD_UNLOCK2 0x24
704#define NAND_CMD_LOCK_STATUS 0x7a
705
706/**
707 * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
708 * state
709 *
710 * @param meminfo nand mtd instance
711 * @param tight bring device in lock tight mode
712 *
713 * @return 0 on success, -1 in case of error
714 *
715 * The lock / lock-tight command only applies to the whole chip. To get some
716 * parts of the chip lock and others unlocked use the following sequence:
717 *
718 * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin)
719 * - Call nand_unlock() once for each consecutive area to be unlocked
720 * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1)
721 *
722 * If the device is in lock-tight state software can't change the
723 * current active lock/unlock state of all pages. nand_lock() / nand_unlock()
724 * calls will fail. It is only posible to leave lock-tight state by
725 * an hardware signal (low pulse on _WP pin) or by power down.
726 */
727int nand_lock(nand_info_t *meminfo, int tight)
728{
729 int ret = 0;
730 int status;
731 struct nand_chip *this = meminfo->priv;
732
733 /* select the NAND device */
734 this->select_chip(meminfo, 0);
735
736 this->cmdfunc(meminfo,
737 (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
738 -1, -1);
739
740 /* call wait ready function */
741 status = this->waitfunc(meminfo, this, FL_WRITING);
742
743 /* see if device thinks it succeeded */
744 if (status & 0x01) {
745 ret = -1;
746 }
747
748 /* de-select the NAND device */
749 this->select_chip(meminfo, -1);
750 return ret;
751}
752
753/**
754 * nand_get_lock_status: - query current lock state from one page of NAND
755 * flash
756 *
757 * @param meminfo nand mtd instance
758 * @param offset page address to query (muss be page aligned!)
759 *
760 * @return -1 in case of error
761 * >0 lock status:
762 * bitfield with the following combinations:
763 * NAND_LOCK_STATUS_TIGHT: page in tight state
764 * NAND_LOCK_STATUS_LOCK: page locked
765 * NAND_LOCK_STATUS_UNLOCK: page unlocked
766 *
767 */
768int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
769{
770 int ret = 0;
771 int chipnr;
772 int page;
773 struct nand_chip *this = meminfo->priv;
774
775 /* select the NAND device */
776 chipnr = (int)(offset >> this->chip_shift);
777 this->select_chip(meminfo, chipnr);
778
779
780 if ((offset & (meminfo->oobblock - 1)) != 0) {
781 printf ("nand_get_lock_status: "
782 "Start address must be beginning of "
783 "nand page!\n");
784 ret = -1;
785 goto out;
786 }
787
788 /* check the Lock Status */
789 page = (int)(offset >> this->page_shift);
790 this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);
791
792 ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT
793 | NAND_LOCK_STATUS_LOCK
794 | NAND_LOCK_STATUS_UNLOCK);
795
796 out:
797 /* de-select the NAND device */
798 this->select_chip(meminfo, -1);
799 return ret;
800}
801
802/**
803 * nand_unlock: - Unlock area of NAND pages
804 * only one consecutive area can be unlocked at one time!
805 *
806 * @param meminfo nand mtd instance
807 * @param start start byte address
808 * @param length number of bytes to unlock (must be a multiple of
809 * page size nand->oobblock)
810 *
811 * @return 0 on success, -1 in case of error
812 */
813int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
814{
815 int ret = 0;
816 int chipnr;
817 int status;
818 int page;
819 struct nand_chip *this = meminfo->priv;
820 printf ("nand_unlock: start: %08x, length: %d!\n",
821 (int)start, (int)length);
822
823 /* select the NAND device */
824 chipnr = (int)(start >> this->chip_shift);
825 this->select_chip(meminfo, chipnr);
826
827 /* check the WP bit */
828 this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);
829 if ((this->read_byte(meminfo) & 0x80) == 0) {
830 printf ("nand_unlock: Device is write protected!\n");
831 ret = -1;
832 goto out;
833 }
834
835 if ((start & (meminfo->oobblock - 1)) != 0) {
836 printf ("nand_unlock: Start address must be beginning of "
837 "nand page!\n");
838 ret = -1;
839 goto out;
840 }
841
842 if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) {
843 printf ("nand_unlock: Length must be a multiple of nand page "
844 "size!\n");
845 ret = -1;
846 goto out;
847 }
848
849 /* submit address of first page to unlock */
850 page = (int)(start >> this->page_shift);
851 this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
852
853 /* submit ADDRESS of LAST page to unlock */
854 page += (int)(length >> this->page_shift) - 1;
855 this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
856
857 /* call wait ready function */
858 status = this->waitfunc(meminfo, this, FL_WRITING);
859 /* see if device thinks it succeeded */
860 if (status & 0x01) {
861 /* there was an error */
862 ret = -1;
863 goto out;
864 }
865
866 out:
867 /* de-select the NAND device */
868 this->select_chip(meminfo, -1);
869 return ret;
870}
871
Jon Loeliger82ecaad2007-07-09 17:39:42 -0500872#endif