blob: 78e70cc807d92cf60d35d48194a7fd317e0c91c7 [file] [log] [blame]
Stefan Roese2255b2d2006-10-10 12:36:02 +02001/*
Marcel Ziswiler7817cb22007-12-30 03:30:46 +01002 * drivers/mtd/nand/nand_util.c
Stefan Roese2255b2d2006-10-10 12:36:02 +02003 *
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 Loeligercb51c0b2007-07-09 17:39:42 -050035#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
Stefan Roese2255b2d2006-10-10 12:36:02 +020036
37#include <command.h>
38#include <watchdog.h>
39#include <malloc.h>
Dirk Behme3a6d56c2007-08-02 17:42:08 +020040#include <div64.h>
Stefan Roese2255b2d2006-10-10 12:36:02 +020041
William Juulcfa460a2007-10-31 13:53:06 +010042
43#include <asm/errno.h>
44#include <linux/mtd/mtd.h>
Stefan Roese2255b2d2006-10-10 12:36:02 +020045#include <nand.h>
46#include <jffs2/jffs2.h>
47
48typedef struct erase_info erase_info_t;
49typedef 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/*****************************************************************************/
56static 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 */
72int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
73{
74 struct jffs2_unknown_node cleanmarker;
Stefan Roese2255b2d2006-10-10 12:36:02 +020075 erase_info_t erase;
76 ulong erase_length;
Stefan Roese2255b2d2006-10-10 12:36:02 +020077 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;
William Juulcfa460a2007-10-31 13:53:06 +010082 struct mtd_oob_ops oob_opts;
83 struct nand_chip *chip = meminfo->priv;
84 uint8_t buf[64];
Stefan Roese2255b2d2006-10-10 12:36:02 +020085
William Juulcfa460a2007-10-31 13:53:06 +010086 memset(buf, 0, sizeof(buf));
Stefan Roese2255b2d2006-10-10 12:36:02 +020087 memset(&erase, 0, sizeof(erase));
William Juulcfa460a2007-10-31 13:53:06 +010088 memset(&oob_opts, 0, sizeof(oob_opts));
Stefan Roese2255b2d2006-10-10 12:36:02 +020089
90 erase.mtd = meminfo;
91 erase.len = meminfo->erasesize;
Stefan Roese856f0542006-10-28 15:55:52 +020092 erase.addr = opts->offset;
93 erase_length = opts->length;
Stefan Roese2255b2d2006-10-10 12:36:02 +020094
Stefan Roese2255b2d2006-10-10 12:36:02 +020095
William Juulcfa460a2007-10-31 13:53:06 +010096 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));
Stefan Roese2255b2d2006-10-10 12:36:02 +0200102
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
Dirk Behme9723bbb2008-01-16 14:26:59 +0100121 if (erase_length < meminfo->erasesize) {
Stefan Roesee8706902008-07-10 10:10:54 +0200122 printf("Warning: Erase size 0x%08lx smaller than one " \
Dirk Behme9723bbb2008-01-16 14:26:59 +0100123 "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
Stefan Roese2255b2d2006-10-10 12:36:02 +0200128 for (;
129 erase.addr < opts->offset + erase_length;
130 erase.addr += meminfo->erasesize) {
William Juulcfa460a2007-10-31 13:53:06 +0100131
Stefan Roese2255b2d2006-10-10 12:36:02 +0200132 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 "
Wolfgang Denk87621bc2006-10-12 11:43:47 +0200139 "0x%08x "
140 " \n",
141 erase.addr);
Stefan Roese2255b2d2006-10-10 12:36:02 +0200142 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
William Juulcfa460a2007-10-31 13:53:06 +0100162 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;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200174 }
William Juulcfa460a2007-10-31 13:53:06 +0100175 else
176 printf("%s: MTD writeoob at 0x%08x\n",mtd_device, erase.addr + meminfo->oobsize );
Stefan Roese2255b2d2006-10-10 12:36:02 +0200177 }
178
179 if (!opts->quiet) {
Wolfgang Denkbe5d72d2007-08-13 21:57:53 +0200180 unsigned long long n =(unsigned long long)
Matthias Fuchs5bd7fe92007-09-11 17:04:00 +0200181 (erase.addr + meminfo->erasesize - opts->offset)
182 * 100;
183 int percent;
184
185 do_div(n, erase_length);
186 percent = (int)n;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200187
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.",
William Juulcfa460a2007-10-31 13:53:06 +0100196 erase.addr, percent);
Stefan Roese2255b2d2006-10-10 12:36:02 +0200197
198 if (opts->jffs2 && result == 0)
William Juulcfa460a2007-10-31 13:53:06 +0100199 printf(" Cleanmarker written at 0x%x.",
200 erase.addr);
Stefan Roese2255b2d2006-10-10 12:36:02 +0200201 }
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
William Juulcfa460a2007-10-31 13:53:06 +0100217/* XXX U-BOOT XXX */
218#if 0
219
Stefan Roese2255b2d2006-10-10 12:36:02 +0200220#define MAX_PAGE_SIZE 2048
221#define MAX_OOB_SIZE 64
222
223/*
224 * buffer array used for writing data
225 */
226static unsigned char data_buf[MAX_PAGE_SIZE];
227static unsigned char oob_buf[MAX_OOB_SIZE];
228
229/* OOB layouts to pass into the kernel as default */
William Juulcfa460a2007-10-31 13:53:06 +0100230static struct nand_ecclayout none_ecclayout = {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200231 .useecc = MTD_NANDECC_OFF,
232};
233
William Juulcfa460a2007-10-31 13:53:06 +0100234static struct nand_ecclayout jffs2_ecclayout = {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200235 .useecc = MTD_NANDECC_PLACE,
236 .eccbytes = 6,
237 .eccpos = { 0, 1, 2, 3, 6, 7 }
238};
239
William Juulcfa460a2007-10-31 13:53:06 +0100240static struct nand_ecclayout yaffs_ecclayout = {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200241 .useecc = MTD_NANDECC_PLACE,
242 .eccbytes = 6,
243 .eccpos = { 8, 9, 10, 13, 14, 15}
244};
245
William Juulcfa460a2007-10-31 13:53:06 +0100246static struct nand_ecclayout autoplace_ecclayout = {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200247 .useecc = MTD_NANDECC_AUTOPLACE
248};
William Juulcfa460a2007-10-31 13:53:06 +0100249#endif
Stefan Roese2255b2d2006-10-10 12:36:02 +0200250
William Juulcfa460a2007-10-31 13:53:06 +0100251
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 */
260static 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 */
309int 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
Stefan Roese2255b2d2006-10-10 12:36:02 +0200413/**
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 */
423int 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;
William Juulcfa460a2007-10-31 13:53:06 +0100431 int ecclayoutchanged = 0;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200432 int percent_complete = -1;
William Juulcfa460a2007-10-31 13:53:06 +0100433 struct nand_ecclayout old_ecclayout;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200434 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 */
William Juulcfa460a2007-10-31 13:53:06 +0100454 if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
455 && !(meminfo->oobsize == 8 && meminfo->writesize == 256)
456 && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200457 printf("Unknown flash (not normal NAND)\n");
458 return -1;
459 }
460
461 /* read the current oob info */
William Juulcfa460a2007-10-31 13:53:06 +0100462 memcpy(&old_ecclayout, &meminfo->ecclayout, sizeof(old_ecclayout));
Stefan Roese2255b2d2006-10-10 12:36:02 +0200463
464 /* write without ecc? */
465 if (opts->noecc) {
William Juulcfa460a2007-10-31 13:53:06 +0100466 memcpy(&meminfo->ecclayout, &none_ecclayout,
467 sizeof(meminfo->ecclayout));
468 ecclayoutchanged = 1;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200469 }
470
471 /* autoplace ECC? */
William Juulcfa460a2007-10-31 13:53:06 +0100472 if (opts->autoplace && (old_ecclayout.useecc != MTD_NANDECC_AUTOPLACE)) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200473
William Juulcfa460a2007-10-31 13:53:06 +0100474 memcpy(&meminfo->ecclayout, &autoplace_ecclayout,
475 sizeof(meminfo->ecclayout));
476 ecclayoutchanged = 1;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200477 }
478
479 /* force OOB layout for jffs2 or yaffs? */
480 if (opts->forcejffs2 || opts->forceyaffs) {
William Juulcfa460a2007-10-31 13:53:06 +0100481 struct nand_ecclayout *oobsel =
482 opts->forcejffs2 ? &jffs2_ecclayout : &yaffs_ecclayout;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200483
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 */
William Juulcfa460a2007-10-31 13:53:06 +0100491 jffs2_ecclayout.eccbytes = 3;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200492 }
493
William Juulcfa460a2007-10-31 13:53:06 +0100494 memcpy(&meminfo->ecclayout, oobsel, sizeof(meminfo->ecclayout));
Stefan Roese2255b2d2006-10-10 12:36:02 +0200495 }
496
497 /* get image length */
498 imglen = opts->length;
William Juulcfa460a2007-10-31 13:53:06 +0100499 pagelen = meminfo->writesize
Stefan Roese2255b2d2006-10-10 12:36:02 +0200500 + ((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 */
William Juulcfa460a2007-10-31 13:53:06 +0100509 if (((imglen / pagelen) * meminfo->writesize)
Stefan Roese2255b2d2006-10-10 12:36:02 +0200510 > (meminfo->size - opts->offset)) {
511 printf("Image %d bytes, NAND page %d bytes, "
512 "OOB area %u bytes, device size %u bytes\n",
William Juulcfa460a2007-10-31 13:53:06 +0100513 imglen, pagelen, meminfo->writesize, meminfo->size);
Stefan Roese2255b2d2006-10-10 12:36:02 +0200514 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
William Juulcfa460a2007-10-31 13:53:06 +0100567 readlen = meminfo->writesize;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200568 if (opts->pad && (imglen < readlen)) {
569 readlen = imglen;
570 memset(data_buf + readlen, 0xff,
William Juulcfa460a2007-10-31 13:53:06 +0100571 meminfo->writesize - readlen);
Stefan Roese2255b2d2006-10-10 12:36:02 +0200572 }
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,
William Juulcfa460a2007-10-31 13:53:06 +0100604 meminfo->writesize,
Stefan Roese2255b2d2006-10-10 12:36:02 +0200605 &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) {
Wolfgang Denkbe5d72d2007-08-13 21:57:53 +0200616 unsigned long long n = (unsigned long long)
617 (opts->length-imglen) * 100;
Matthias Fuchs5bd7fe92007-09-11 17:04:00 +0200618 int percent;
619
620 do_div(n, opts->length);
621 percent = (int)n;
622
Stefan Roese2255b2d2006-10-10 12:36:02 +0200623 /* 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) {
Stefan Roesee8706902008-07-10 10:10:54 +0200628 printf("\rWriting data at 0x%lx "
Stefan Roese2255b2d2006-10-10 12:36:02 +0200629 "-- %3d%% complete.",
630 mtdoffset, percent);
631 percent_complete = percent;
632 }
633 }
634
William Juulcfa460a2007-10-31 13:53:06 +0100635 mtdoffset += meminfo->writesize;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200636 }
637
638 if (!opts->quiet)
639 printf("\n");
640
641restoreoob:
William Juulcfa460a2007-10-31 13:53:06 +0100642 if (ecclayoutchanged) {
643 memcpy(&meminfo->ecclayout, &old_ecclayout,
644 sizeof(meminfo->ecclayout));
Stefan Roese2255b2d2006-10-10 12:36:02 +0200645 }
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 */
664int 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 */
William Juulcfa460a2007-10-31 13:53:06 +0100678 if (!(meminfo->oobsize == 16 && meminfo->writesize == 512)
679 && !(meminfo->oobsize == 8 && meminfo->writesize == 256)
680 && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200681 printf("Unknown flash (not normal NAND)\n");
682 return -1;
683 }
684
William Juulcfa460a2007-10-31 13:53:06 +0100685 pagelen = meminfo->writesize
Stefan Roese2255b2d2006-10-10 12:36:02 +0200686 + ((opts->readoob != 0) ? meminfo->oobsize : 0);
687
688 /* check, if length is not larger than device */
William Juulcfa460a2007-10-31 13:53:06 +0100689 if (((imglen / pagelen) * meminfo->writesize)
Stefan Roese2255b2d2006-10-10 12:36:02 +0200690 > (meminfo->size - opts->offset)) {
691 printf("Image %d bytes, NAND page %d bytes, "
692 "OOB area %u bytes, device size %u bytes\n",
William Juulcfa460a2007-10-31 13:53:06 +0100693 imglen, pagelen, meminfo->writesize, meminfo->size);
Stefan Roese2255b2d2006-10-10 12:36:02 +0200694 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,
William Juulcfa460a2007-10-31 13:53:06 +0100751 meminfo->writesize,
Stefan Roese2255b2d2006-10-10 12:36:02 +0200752 &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) {
Wolfgang Denkbe5d72d2007-08-13 21:57:53 +0200795 unsigned long long n = (unsigned long long)
796 (opts->length-imglen) * 100;
Matthias Fuchs5bd7fe92007-09-11 17:04:00 +0200797 int percent;
798
799 do_div(n, opts->length);
800 percent = (int)n;
801
Stefan Roese2255b2d2006-10-10 12:36:02 +0200802 /* 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)
Stefan Roesee8706902008-07-10 10:10:54 +0200808 printf("\rReading data from 0x%lx "
Stefan Roese2255b2d2006-10-10 12:36:02 +0200809 "-- %3d%% complete.",
810 mtdoffset, percent);
811 percent_complete = percent;
812 }
813 }
814
William Juulcfa460a2007-10-31 13:53:06 +0100815 mtdoffset += meminfo->writesize;
Stefan Roese2255b2d2006-10-10 12:36:02 +0200816 }
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}
William Juulcfa460a2007-10-31 13:53:06 +0100829#endif
Stefan Roese2255b2d2006-10-10 12:36:02 +0200830
William Juulcfa460a2007-10-31 13:53:06 +0100831/* XXX U-BOOT XXX */
832#if 0
Stefan Roese2255b2d2006-10-10 12:36:02 +0200833/******************************************************************************
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 */
864int 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 */
905int 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
William Juulcfa460a2007-10-31 13:53:06 +0100917 if ((offset & (meminfo->writesize - 1)) != 0) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200918 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
William Juulcfa460a2007-10-31 13:53:06 +0100946 * page size nand->writesize)
Stefan Roese2255b2d2006-10-10 12:36:02 +0200947 *
948 * @return 0 on success, -1 in case of error
949 */
950int 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
William Juulcfa460a2007-10-31 13:53:06 +0100972 if ((start & (meminfo->writesize - 1)) != 0) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200973 printf ("nand_unlock: Start address must be beginning of "
974 "nand page!\n");
975 ret = -1;
976 goto out;
977 }
978
William Juulcfa460a2007-10-31 13:53:06 +0100979 if (length == 0 || (length & (meminfo->writesize - 1)) != 0) {
Stefan Roese2255b2d2006-10-10 12:36:02 +0200980 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}
William Juulcfa460a2007-10-31 13:53:06 +01001008#endif
Stefan Roese2255b2d2006-10-10 12:36:02 +02001009
Jon Loeligercb51c0b2007-07-09 17:39:42 -05001010#endif