Commit c3c3b089adcee06df3afd4e8b00a3fea82263bcd

Authored by Jon Loeliger
Exists in master and in 55 other branches 8qm-imx_v2020.04_5.4.70_2.3.0, emb_lf_v2022.04, emb_lf_v2023.04, imx_v2015.04_4.1.15_1.0.0_ga, pitx_8mp_lf_v2020.04, smarc-8m-android-10.0.0_2.6.0, smarc-8m-android-11.0.0_2.0.0, smarc-8mp-android-11.0.0_2.0.0, smarc-emmc-imx_v2014.04_3.10.53_1.1.0_ga, smarc-emmc-imx_v2014.04_3.14.28_1.0.0_ga, smarc-imx-l5.0.0_1.0.0-ga, smarc-imx6_v2018.03_4.14.98_2.0.0_ga, smarc-imx7_v2017.03_4.9.11_1.0.0_ga, smarc-imx7_v2018.03_4.14.98_2.0.0_ga, smarc-imx_v2014.04_3.14.28_1.0.0_ga, smarc-imx_v2015.04_4.1.15_1.0.0_ga, smarc-imx_v2017.03_4.9.11_1.0.0_ga, smarc-imx_v2017.03_4.9.88_2.0.0_ga, smarc-imx_v2017.03_o8.1.0_1.3.0_8m, smarc-imx_v2018.03_4.14.78_1.0.0_ga, smarc-m6.0.1_2.1.0-ga, smarc-n7.1.2_2.0.0-ga, smarc-rel_imx_4.1.15_2.0.0_ga, smarc_8m-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8m-imx_v2019.04_4.19.35_1.1.0, smarc_8m_00d0-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8mm-imx_v2019.04_4.19.35_1.1.0, smarc_8mm-imx_v2020.04_5.4.24_2.1.0, smarc_8mp_lf_v2020.04, smarc_8mq-imx_v2020.04_5.4.24_2.1.0, smarc_8mq_lf_v2020.04, ti-u-boot-2015.07, u-boot-2013.01.y, v2013.10, v2013.10-smarct33, v2013.10-smartmen, v2014.01, v2014.04, v2014.04-smarct33, v2014.04-smarct33-emmc, v2014.04-smartmen, v2014.07, v2014.07-smarct33, v2014.07-smartmen, v2015.07-smarct33, v2015.07-smarct33-emmc, v2015.07-smarct4x, v2016.05-dlt, v2016.05-smarct3x, v2016.05-smarct3x-emmc, v2016.05-smarct4x, v2017.01-smarct3x, v2017.01-smarct3x-emmc, v2017.01-smarct4x

Merge branch 'master' of http://www.denx.de/git/u-boot

Showing 7 changed files Side-by-side Diff

... ... @@ -2,6 +2,14 @@
2 2 Changes since U-Boot 1.1.4:
3 3 ======================================================================
4 4  
  5 +* Several improvements to the new NAND subsystem:
  6 + - JFFS2 related commands implemented in mtd-utils style
  7 + - Support for bad blocks
  8 + - Bad block testing commands
  9 + - NAND lock commands
  10 + Please take a look at doc/README.nand for more details
  11 + Patch by Guido Classen, 10 Oct 2006
  12 +
5 13 * Define IH_CPU_AVR32
6 14 Make it possible to generate AVR32 uImage files with mkimage and
7 15 make cmd_bootm recognize them.
... ... @@ -135,11 +135,16 @@
135 135 ulong addr, off, size;
136 136 char *cmd, *s;
137 137 nand_info_t *nand;
  138 + int quiet = 0;
  139 + const char *quiet_str = getenv("quiet");
138 140  
139 141 /* at least two arguments please */
140 142 if (argc < 2)
141 143 goto usage;
142 144  
  145 + if (quiet_str)
  146 + quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
  147 +
143 148 cmd = argv[1];
144 149  
145 150 if (strcmp(cmd, "info") == 0) {
... ... @@ -178,7 +183,10 @@
178 183  
179 184 if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 &&
180 185 strncmp(cmd, "dump", 4) != 0 &&
181   - strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0)
  186 + strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
  187 + strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
  188 + strcmp(cmd, "biterr") != 0 &&
  189 + strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
182 190 goto usage;
183 191  
184 192 /* the following commands operate on the current device */
185 193  
... ... @@ -197,14 +205,64 @@
197 205 return 0;
198 206 }
199 207  
200   - if (strcmp(cmd, "erase") == 0) {
201   - arg_off_size(argc - 2, argv + 2, &off, &size, nand->size);
202   - if (off == 0 && size == 0)
203   - return 1;
  208 + if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
  209 + nand_erase_options_t opts;
  210 + int clean = argc >= 3 && !strcmp("clean", argv[2]);
  211 + int rest_argc = argc - 2;
  212 + char **rest_argv = argv + 2;
  213 + int scrub = !strcmp(cmd, "scrub");
204 214  
205   - printf("\nNAND erase: device %d offset 0x%x, size 0x%x ",
206   - nand_curr_device, off, size);
207   - ret = nand_erase(nand, off, size);
  215 + if (clean) {
  216 + rest_argc--;
  217 + rest_argv++;
  218 + }
  219 +
  220 + if (rest_argc == 0) {
  221 +
  222 + printf("\nNAND %s: device %d whole chip\n",
  223 + cmd,
  224 + nand_curr_device);
  225 +
  226 + off = size = 0;
  227 + } else {
  228 + arg_off_size(rest_argc, rest_argv, &off, &size,
  229 + nand->size);
  230 +
  231 + if (off == 0 && size == 0)
  232 + return 1;
  233 +
  234 + printf("\nNAND %s: device %d offset 0x%x, size 0x%x\n",
  235 + cmd, nand_curr_device, off, size);
  236 + }
  237 +
  238 + memset(&opts, 0, sizeof(opts));
  239 + opts.offset = off;
  240 + opts.length = size;
  241 + opts.jffs2 = clean;
  242 + opts.quiet = quiet;
  243 +
  244 + if (scrub) {
  245 + printf("Warning: "
  246 + "scrub option will erase all factory set "
  247 + "bad blocks!\n"
  248 + " "
  249 + "There is no reliable way to recover them.\n"
  250 + " "
  251 + "Use this command only for testing purposes "
  252 + "if you\n"
  253 + " "
  254 + "are shure of what you are doing!\n"
  255 + "\nReally scrub this NAND flash? <y/N>\n"
  256 + );
  257 +
  258 + if (getc() == 'y' && getc() == '\r') {
  259 + opts.scrub = 1;
  260 + } else {
  261 + printf("scrub aborted\n");
  262 + return -1;
  263 + }
  264 + }
  265 + ret = nand_erase_opts(nand, &opts);
208 266 printf("%s\n", ret ? "ERROR" : "OK");
209 267  
210 268 return ret == 0 ? 0 : 1;
211 269  
212 270  
213 271  
214 272  
215 273  
216 274  
... ... @@ -228,37 +286,153 @@
228 286  
229 287 /* read write */
230 288 if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
  289 + int read;
  290 +
231 291 if (argc < 4)
232 292 goto usage;
233   -/*
234   - s = strchr(cmd, '.');
235   - clean = CLEAN_NONE;
236   - if (s != NULL) {
237   - if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0
238   - || strcmp(s, ".i"))
239   - clean = CLEAN_JFFS2;
240   - }
241   -*/
  293 +
242 294 addr = (ulong)simple_strtoul(argv[2], NULL, 16);
243 295  
244 296 arg_off_size(argc - 3, argv + 3, &off, &size, nand->size);
245 297 if (off == 0 && size == 0)
246 298 return 1;
247 299  
248   - i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
  300 + read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
249 301 printf("\nNAND %s: device %d offset %u, size %u ... ",
250   - i ? "read" : "write", nand_curr_device, off, size);
  302 + read ? "read" : "write", nand_curr_device, off, size);
251 303  
252   - if (i)
  304 + s = strchr(cmd, '.');
  305 + if (s != NULL &&
  306 + (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {
  307 + if (read) {
  308 + /* read */
  309 + nand_read_options_t opts;
  310 + memset(&opts, 0, sizeof(opts));
  311 + opts.buffer = (u_char*) addr;
  312 + opts.length = size;
  313 + opts.offset = off;
  314 + opts.quiet = quiet;
  315 + ret = nand_read_opts(nand, &opts);
  316 + } else {
  317 + /* write */
  318 + nand_write_options_t opts;
  319 + memset(&opts, 0, sizeof(opts));
  320 + opts.buffer = (u_char*) addr;
  321 + opts.length = size;
  322 + opts.offset = off;
  323 + /* opts.forcejffs2 = 1; */
  324 + opts.pad = 1;
  325 + opts.blockalign = 1;
  326 + opts.quiet = quiet;
  327 + ret = nand_write_opts(nand, &opts);
  328 + }
  329 + printf("%s\n", ret ? "ERROR" : "OK");
  330 + return ret == 0 ? 0 : 1;
  331 + }
  332 +
  333 + if (read)
253 334 ret = nand_read(nand, off, &size, (u_char *)addr);
254 335 else
255 336 ret = nand_write(nand, off, &size, (u_char *)addr);
256 337  
257 338 printf(" %d bytes %s: %s\n", size,
258   - i ? "read" : "written", ret ? "ERROR" : "OK");
  339 + read ? "read" : "written", ret ? "ERROR" : "OK");
259 340  
260 341 return ret == 0 ? 0 : 1;
261 342 }
  343 +
  344 + /* 2006-09-28 gc: implement missing commands */
  345 + if (strcmp(cmd, "markbad") == 0) {
  346 + addr = (ulong)simple_strtoul(argv[2], NULL, 16);
  347 +
  348 + int ret = nand->block_markbad(nand, addr);
  349 + if (ret == 0) {
  350 + printf("block 0x%08lx successfully marked as bad\n",
  351 + (ulong) addr);
  352 + return 0;
  353 + } else {
  354 + printf("block 0x%08lx NOT marked as bad! ERROR %d\n",
  355 + (ulong) addr, ret);
  356 + }
  357 + return 1;
  358 + }
  359 + if (strcmp(cmd, "biterr") == 0) {
  360 + /* todo */
  361 + return 1;
  362 + }
  363 +
  364 + if (strcmp(cmd, "lock") == 0) {
  365 + int tight = 0;
  366 + int status = 0;
  367 + if (argc == 3) {
  368 + if (!strcmp("tight", argv[2]))
  369 + tight = 1;
  370 + if (!strcmp("status", argv[2]))
  371 + status = 1;
  372 + }
  373 +
  374 + if (status) {
  375 + ulong block_start = 0;
  376 + ulong off;
  377 + int last_status = -1;
  378 +
  379 + struct nand_chip *nand_chip = nand->priv;
  380 + /* check the WP bit */
  381 + nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);
  382 + printf("device is %swrite protected\n",
  383 + (nand_chip->read_byte(nand) & 0x80 ?
  384 + "NOT " : "" ) );
  385 +
  386 + for (off = 0; off < nand->size; off += nand->oobblock) {
  387 + int s = nand_get_lock_status(nand, off);
  388 +
  389 + /* print message only if status has changed
  390 + * or at end of chip
  391 + */
  392 + if (off == nand->size - nand->oobblock
  393 + || (s != last_status && off != 0)) {
  394 +
  395 + printf("%08x - %08x: %8d pages %s%s%s\n",
  396 + block_start,
  397 + off-1,
  398 + (off-block_start)/nand->oobblock,
  399 + ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),
  400 + ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),
  401 + ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));
  402 + }
  403 +
  404 + last_status = s;
  405 + }
  406 + } else {
  407 + if (!nand_lock(nand, tight)) {
  408 + printf ("NAND flash successfully locked\n");
  409 + } else {
  410 + printf ("Error locking NAND flash. \n");
  411 + return 1;
  412 + }
  413 + }
  414 + return 0;
  415 + }
  416 +
  417 + if (strcmp(cmd, "unlock") == 0) {
  418 + if (argc == 2) {
  419 + off = 0;
  420 + size = nand->size;
  421 + } else {
  422 + arg_off_size(argc - 2, argv + 2, &off, &size,
  423 + nand->size);
  424 + }
  425 +
  426 + if (!nand_unlock(nand, off, size)) {
  427 + printf("NAND flash successfully unlocked\n");
  428 + } else {
  429 + printf("Error unlocking NAND flash. "
  430 + "Write and erase will probably fail\n");
  431 + return 1;
  432 + }
  433 + return 0;
  434 + }
  435 +
262 436 usage:
263 437 printf("Usage:\n%s\n", cmdtp->usage);
264 438 return 1;
... ... @@ -277,7 +451,9 @@
277 451 "nand dump[.oob] off - dump page\n"
278 452 "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
279 453 "nand markbad off - mark bad block at offset (UNSAFE)\n"
280   - "nand biterr off - make a bit error at offset (UNSAFE)\n");
  454 + "nand biterr off - make a bit error at offset (UNSAFE)\n"
  455 + "nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
  456 + "nand unlock [offset] [size] - unlock section\n");
281 457  
282 458 int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
283 459 {
... ... @@ -596,7 +772,7 @@
596 772 return 1;
597 773 }
598 774  
599   - printf ("\nNAND %s: device %d offset %ld, size %ld ... ",
  775 + printf ("\nNAND %s: device %d offset %ld, size %ld ...\n",
600 776 (cmd & NANDRW_READ) ? "read" : "write",
601 777 curr_device, off, size);
602 778  
... ... @@ -615,7 +791,7 @@
615 791 ulong size = simple_strtoul(argv[3 + clean], NULL, 16);
616 792 int ret;
617 793  
618   - printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
  794 + printf ("\nNAND erase: device %d offset %ld, size %ld ...\n",
619 795 curr_device, off, size);
620 796  
621 797 ret = nand_legacy_erase (nand_dev_desc + curr_device,
... ... @@ -635,7 +811,7 @@
635 811  
636 812 U_BOOT_CMD(
637 813 nand, 5, 1, do_nand,
638   - "nand - NAND sub-system\n",
  814 + "nand - legacy NAND sub-system\n",
639 815 "info - show available NAND devices\n"
640 816 "nand device [dev] - show or set current device\n"
641 817 "nand read[.jffs2[s]] addr off size\n"
... ... @@ -207,4 +207,48 @@
207 207 The consequence of this is that the legacy NAND can't be removed from
208 208 the tree until the DoC is ported to use the new NAND support (or boards
209 209 with DoC will break).
  210 +
  211 +
  212 +
  213 +Additional improvements to the NAND subsystem by Guido Classen, 10-10-2006
  214 +
  215 +JFFS2 related commands:
  216 +
  217 + implement "nand erase clean" and old "nand erase"
  218 + using both the new code which is able to skip bad blocks
  219 + "nand erase clean" additionally writes JFFS2-cleanmarkers in the oob.
  220 +
  221 + "nand write.jffs2"
  222 + like "nand write" but skip found bad eraseblocks
  223 +
  224 + "nand read.jffs2"
  225 + like "nand read" but skip found bad eraseblocks
  226 +
  227 +Miscellaneous and testing commands:
  228 + "markbad [offset]"
  229 + create an artificial bad block (for testing bad block handling)
  230 +
  231 + "scrub [offset length]"
  232 + like "erase" but don't skip bad block. Instead erase them.
  233 + DANGEROUS!!! Factory set bad blocks will be lost. Use only
  234 + to remove artificial bad blocks created with the "markbad" command.
  235 +
  236 +
  237 +NAND locking command (for chips with active LOCKPRE pin)
  238 +
  239 + "nand lock"
  240 + set NAND chip to lock state (all pages locked)
  241 +
  242 + "nand lock tight"
  243 + set NAND chip to lock tight state (software can't change locking anymore)
  244 +
  245 + "nand lock status"
  246 + displays current locking status of all pages
  247 +
  248 + "nand unlock [offset] [size]"
  249 + unlock consecutive area (can be called multiple times for different areas)
  250 +
  251 +
  252 +I have tested the code with board containing 128MiB NAND large page chips
  253 +and 32MiB small page chips.
drivers/nand/Makefile
... ... @@ -25,7 +25,7 @@
25 25  
26 26 LIB := $(obj)libnand.a
27 27  
28   -COBJS := nand.o nand_base.o nand_ids.o nand_ecc.o nand_bbt.o
  28 +COBJS := nand.o nand_base.o nand_ids.o nand_ecc.o nand_bbt.o nand_util.o
29 29  
30 30 SRCS := $(COBJS:.o=.c)
31 31 OBJS := $(addprefix $(obj),$(COBJS))
drivers/nand/nand_util.c
  1 +/*
  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 +
  35 +#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
  36 +
  37 +#include <command.h>
  38 +#include <watchdog.h>
  39 +#include <malloc.h>
  40 +
  41 +#include <nand.h>
  42 +#include <jffs2/jffs2.h>
  43 +
  44 +typedef struct erase_info erase_info_t;
  45 +typedef struct mtd_info mtd_info_t;
  46 +
  47 +/* support only for native endian JFFS2 */
  48 +#define cpu_to_je16(x) (x)
  49 +#define cpu_to_je32(x) (x)
  50 +
  51 +/*****************************************************************************/
  52 +static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
  53 +{
  54 + return 0;
  55 +}
  56 +
  57 +/**
  58 + * nand_erase_opts: - erase NAND flash with support for various options
  59 + * (jffs2 formating)
  60 + *
  61 + * @param meminfo NAND device to erase
  62 + * @param opts options, @see struct nand_erase_options
  63 + * @return 0 in case of success
  64 + *
  65 + * This code is ported from flash_eraseall.c from Linux mtd utils by
  66 + * Arcom Control System Ltd.
  67 + */
  68 +int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
  69 +{
  70 + struct jffs2_unknown_node cleanmarker;
  71 + int clmpos = 0;
  72 + int clmlen = 8;
  73 + erase_info_t erase;
  74 + ulong erase_length;
  75 + int isNAND;
  76 + int bbtest = 1;
  77 + int result;
  78 + int percent_complete = -1;
  79 + int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
  80 + const char *mtd_device = meminfo->name;
  81 +
  82 + memset(&erase, 0, sizeof(erase));
  83 +
  84 + erase.mtd = meminfo;
  85 + erase.len = meminfo->erasesize;
  86 + if (opts->offset == 0 && opts->length == 0) {
  87 + /* erase complete chip */
  88 + erase.addr = 0;
  89 + erase_length = meminfo->size;
  90 + } else {
  91 + /* erase specified region */
  92 + erase.addr = opts->offset;
  93 + erase_length = opts->length;
  94 + }
  95 +
  96 + isNAND = meminfo->type == MTD_NANDFLASH ? 1 : 0;
  97 +
  98 + if (opts->jffs2) {
  99 + cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
  100 + cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
  101 + if (isNAND) {
  102 + struct nand_oobinfo *oobinfo = &meminfo->oobinfo;
  103 +
  104 + /* check for autoplacement */
  105 + if (oobinfo->useecc == MTD_NANDECC_AUTOPLACE) {
  106 + /* get the position of the free bytes */
  107 + if (!oobinfo->oobfree[0][1]) {
  108 + printf(" Eeep. Autoplacement selected "
  109 + "and no empty space in oob\n");
  110 + return -1;
  111 + }
  112 + clmpos = oobinfo->oobfree[0][0];
  113 + clmlen = oobinfo->oobfree[0][1];
  114 + if (clmlen > 8)
  115 + clmlen = 8;
  116 + } else {
  117 + /* legacy mode */
  118 + switch (meminfo->oobsize) {
  119 + case 8:
  120 + clmpos = 6;
  121 + clmlen = 2;
  122 + break;
  123 + case 16:
  124 + clmpos = 8;
  125 + clmlen = 8;
  126 + break;
  127 + case 64:
  128 + clmpos = 16;
  129 + clmlen = 8;
  130 + break;
  131 + }
  132 + }
  133 +
  134 + cleanmarker.totlen = cpu_to_je32(8);
  135 + } else {
  136 + cleanmarker.totlen =
  137 + cpu_to_je32(sizeof(struct jffs2_unknown_node));
  138 + }
  139 + cleanmarker.hdr_crc = cpu_to_je32(
  140 + crc32_no_comp(0, (unsigned char *) &cleanmarker,
  141 + sizeof(struct jffs2_unknown_node) - 4));
  142 + }
  143 +
  144 + /* scrub option allows to erase badblock. To prevent internal
  145 + * check from erase() method, set block check method to dummy
  146 + * and disable bad block table while erasing.
  147 + */
  148 + if (opts->scrub) {
  149 + struct nand_chip *priv_nand = meminfo->priv;
  150 +
  151 + nand_block_bad_old = priv_nand->block_bad;
  152 + priv_nand->block_bad = nand_block_bad_scrub;
  153 + /* we don't need the bad block table anymore...
  154 + * after scrub, there are no bad blocks left!
  155 + */
  156 + if (priv_nand->bbt) {
  157 + kfree(priv_nand->bbt);
  158 + }
  159 + priv_nand->bbt = NULL;
  160 + }
  161 +
  162 + for (;
  163 + erase.addr < opts->offset + erase_length;
  164 + erase.addr += meminfo->erasesize) {
  165 +
  166 + WATCHDOG_RESET ();
  167 +
  168 + if (!opts->scrub && bbtest) {
  169 + int ret = meminfo->block_isbad(meminfo, erase.addr);
  170 + if (ret > 0) {
  171 + if (!opts->quiet)
  172 + printf("\rSkipping bad block at "
  173 + "0x%08x "
  174 + " \n",
  175 + erase.addr);
  176 + continue;
  177 +
  178 + } else if (ret < 0) {
  179 + printf("\n%s: MTD get bad block failed: %d\n",
  180 + mtd_device,
  181 + ret);
  182 + return -1;
  183 + }
  184 + }
  185 +
  186 + result = meminfo->erase(meminfo, &erase);
  187 + if (result != 0) {
  188 + printf("\n%s: MTD Erase failure: %d\n",
  189 + mtd_device, result);
  190 + continue;
  191 + }
  192 +
  193 + /* format for JFFS2 ? */
  194 + if (opts->jffs2) {
  195 +
  196 + /* write cleanmarker */
  197 + if (isNAND) {
  198 + size_t written;
  199 + result = meminfo->write_oob(meminfo,
  200 + erase.addr + clmpos,
  201 + clmlen,
  202 + &written,
  203 + (unsigned char *)
  204 + &cleanmarker);
  205 + if (result != 0) {
  206 + printf("\n%s: MTD writeoob failure: %d\n",
  207 + mtd_device, result);
  208 + continue;
  209 + }
  210 + } else {
  211 + printf("\n%s: this erase routine only supports"
  212 + " NAND devices!\n",
  213 + mtd_device);
  214 + }
  215 + }
  216 +
  217 + if (!opts->quiet) {
  218 + int percent = (int)
  219 + ((unsigned long long)
  220 + (erase.addr+meminfo->erasesize-opts->offset)
  221 + * 100 / erase_length);
  222 +
  223 + /* output progress message only at whole percent
  224 + * steps to reduce the number of messages printed
  225 + * on (slow) serial consoles
  226 + */
  227 + if (percent != percent_complete) {
  228 + percent_complete = percent;
  229 +
  230 + printf("\rErasing at 0x%x -- %3d%% complete.",
  231 + erase.addr, percent);
  232 +
  233 + if (opts->jffs2 && result == 0)
  234 + printf(" Cleanmarker written at 0x%x.",
  235 + erase.addr);
  236 + }
  237 + }
  238 + }
  239 + if (!opts->quiet)
  240 + printf("\n");
  241 +
  242 + if (nand_block_bad_old) {
  243 + struct nand_chip *priv_nand = meminfo->priv;
  244 +
  245 + priv_nand->block_bad = nand_block_bad_old;
  246 + priv_nand->scan_bbt(meminfo);
  247 + }
  248 +
  249 + return 0;
  250 +}
  251 +
  252 +#define MAX_PAGE_SIZE 2048
  253 +#define MAX_OOB_SIZE 64
  254 +
  255 +/*
  256 + * buffer array used for writing data
  257 + */
  258 +static unsigned char data_buf[MAX_PAGE_SIZE];
  259 +static unsigned char oob_buf[MAX_OOB_SIZE];
  260 +
  261 +/* OOB layouts to pass into the kernel as default */
  262 +static struct nand_oobinfo none_oobinfo = {
  263 + .useecc = MTD_NANDECC_OFF,
  264 +};
  265 +
  266 +static struct nand_oobinfo jffs2_oobinfo = {
  267 + .useecc = MTD_NANDECC_PLACE,
  268 + .eccbytes = 6,
  269 + .eccpos = { 0, 1, 2, 3, 6, 7 }
  270 +};
  271 +
  272 +static struct nand_oobinfo yaffs_oobinfo = {
  273 + .useecc = MTD_NANDECC_PLACE,
  274 + .eccbytes = 6,
  275 + .eccpos = { 8, 9, 10, 13, 14, 15}
  276 +};
  277 +
  278 +static struct nand_oobinfo autoplace_oobinfo = {
  279 + .useecc = MTD_NANDECC_AUTOPLACE
  280 +};
  281 +
  282 +/**
  283 + * nand_write_opts: - write image to NAND flash with support for various options
  284 + *
  285 + * @param meminfo NAND device to erase
  286 + * @param opts write options (@see nand_write_options)
  287 + * @return 0 in case of success
  288 + *
  289 + * This code is ported from nandwrite.c from Linux mtd utils by
  290 + * Steven J. Hill and Thomas Gleixner.
  291 + */
  292 +int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
  293 +{
  294 + int imglen = 0;
  295 + int pagelen;
  296 + int baderaseblock;
  297 + int blockstart = -1;
  298 + loff_t offs;
  299 + int readlen;
  300 + int oobinfochanged = 0;
  301 + int percent_complete = -1;
  302 + struct nand_oobinfo old_oobinfo;
  303 + ulong mtdoffset = opts->offset;
  304 + ulong erasesize_blockalign;
  305 + u_char *buffer = opts->buffer;
  306 + size_t written;
  307 + int result;
  308 +
  309 + if (opts->pad && opts->writeoob) {
  310 + printf("Can't pad when oob data is present.\n");
  311 + return -1;
  312 + }
  313 +
  314 + /* set erasesize to specified number of blocks - to match
  315 + * jffs2 (virtual) block size */
  316 + if (opts->blockalign == 0) {
  317 + erasesize_blockalign = meminfo->erasesize;
  318 + } else {
  319 + erasesize_blockalign = meminfo->erasesize * opts->blockalign;
  320 + }
  321 +
  322 + /* make sure device page sizes are valid */
  323 + if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
  324 + && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
  325 + && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
  326 + printf("Unknown flash (not normal NAND)\n");
  327 + return -1;
  328 + }
  329 +
  330 + /* read the current oob info */
  331 + memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo));
  332 +
  333 + /* write without ecc? */
  334 + if (opts->noecc) {
  335 + memcpy(&meminfo->oobinfo, &none_oobinfo,
  336 + sizeof(meminfo->oobinfo));
  337 + oobinfochanged = 1;
  338 + }
  339 +
  340 + /* autoplace ECC? */
  341 + if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
  342 +
  343 + memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
  344 + sizeof(meminfo->oobinfo));
  345 + oobinfochanged = 1;
  346 + }
  347 +
  348 + /* force OOB layout for jffs2 or yaffs? */
  349 + if (opts->forcejffs2 || opts->forceyaffs) {
  350 + struct nand_oobinfo *oobsel =
  351 + opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
  352 +
  353 + if (meminfo->oobsize == 8) {
  354 + if (opts->forceyaffs) {
  355 + printf("YAFSS cannot operate on "
  356 + "256 Byte page size\n");
  357 + goto restoreoob;
  358 + }
  359 + /* Adjust number of ecc bytes */
  360 + jffs2_oobinfo.eccbytes = 3;
  361 + }
  362 +
  363 + memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo));
  364 + }
  365 +
  366 + /* get image length */
  367 + imglen = opts->length;
  368 + pagelen = meminfo->oobblock
  369 + + ((opts->writeoob != 0) ? meminfo->oobsize : 0);
  370 +
  371 + /* check, if file is pagealigned */
  372 + if ((!opts->pad) && ((imglen % pagelen) != 0)) {
  373 + printf("Input block length is not page aligned\n");
  374 + goto restoreoob;
  375 + }
  376 +
  377 + /* check, if length fits into device */
  378 + if (((imglen / pagelen) * meminfo->oobblock)
  379 + > (meminfo->size - opts->offset)) {
  380 + printf("Image %d bytes, NAND page %d bytes, "
  381 + "OOB area %u bytes, device size %u bytes\n",
  382 + imglen, pagelen, meminfo->oobblock, meminfo->size);
  383 + printf("Input block does not fit into device\n");
  384 + goto restoreoob;
  385 + }
  386 +
  387 + if (!opts->quiet)
  388 + printf("\n");
  389 +
  390 + /* get data from input and write to the device */
  391 + while (imglen && (mtdoffset < meminfo->size)) {
  392 +
  393 + WATCHDOG_RESET ();
  394 +
  395 + /*
  396 + * new eraseblock, check for bad block(s). Stay in the
  397 + * loop to be sure if the offset changes because of
  398 + * a bad block, that the next block that will be
  399 + * written to is also checked. Thus avoiding errors if
  400 + * the block(s) after the skipped block(s) is also bad
  401 + * (number of blocks depending on the blockalign
  402 + */
  403 + while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
  404 + blockstart = mtdoffset & (~erasesize_blockalign+1);
  405 + offs = blockstart;
  406 + baderaseblock = 0;
  407 +
  408 + /* check all the blocks in an erase block for
  409 + * bad blocks */
  410 + do {
  411 + int ret = meminfo->block_isbad(meminfo, offs);
  412 +
  413 + if (ret < 0) {
  414 + printf("Bad block check failed\n");
  415 + goto restoreoob;
  416 + }
  417 + if (ret == 1) {
  418 + baderaseblock = 1;
  419 + if (!opts->quiet)
  420 + printf("\rBad block at 0x%lx "
  421 + "in erase block from "
  422 + "0x%x will be skipped\n",
  423 + (long) offs,
  424 + blockstart);
  425 + }
  426 +
  427 + if (baderaseblock) {
  428 + mtdoffset = blockstart
  429 + + erasesize_blockalign;
  430 + }
  431 + offs += erasesize_blockalign
  432 + / opts->blockalign;
  433 + } while (offs < blockstart + erasesize_blockalign);
  434 + }
  435 +
  436 + readlen = meminfo->oobblock;
  437 + if (opts->pad && (imglen < readlen)) {
  438 + readlen = imglen;
  439 + memset(data_buf + readlen, 0xff,
  440 + meminfo->oobblock - readlen);
  441 + }
  442 +
  443 + /* read page data from input memory buffer */
  444 + memcpy(data_buf, buffer, readlen);
  445 + buffer += readlen;
  446 +
  447 + if (opts->writeoob) {
  448 + /* read OOB data from input memory block, exit
  449 + * on failure */
  450 + memcpy(oob_buf, buffer, meminfo->oobsize);
  451 + buffer += meminfo->oobsize;
  452 +
  453 + /* write OOB data first, as ecc will be placed
  454 + * in there*/
  455 + result = meminfo->write_oob(meminfo,
  456 + mtdoffset,
  457 + meminfo->oobsize,
  458 + &written,
  459 + (unsigned char *)
  460 + &oob_buf);
  461 +
  462 + if (result != 0) {
  463 + printf("\nMTD writeoob failure: %d\n",
  464 + result);
  465 + goto restoreoob;
  466 + }
  467 + imglen -= meminfo->oobsize;
  468 + }
  469 +
  470 + /* write out the page data */
  471 + result = meminfo->write(meminfo,
  472 + mtdoffset,
  473 + meminfo->oobblock,
  474 + &written,
  475 + (unsigned char *) &data_buf);
  476 +
  477 + if (result != 0) {
  478 + printf("writing NAND page at offset 0x%lx failed\n",
  479 + mtdoffset);
  480 + goto restoreoob;
  481 + }
  482 + imglen -= readlen;
  483 +
  484 + if (!opts->quiet) {
  485 + int percent = (int)
  486 + ((unsigned long long)
  487 + (opts->length-imglen) * 100
  488 + / opts->length);
  489 + /* 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 +
  507 +restoreoob:
  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 + */
  530 +int 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) {
  661 + int percent = (int)
  662 + ((unsigned long long)
  663 + (opts->length-imglen) * 100
  664 + / opts->length);
  665 + /* output progress message only at whole percent
  666 + * steps to reduce the number of messages printed
  667 + * on (slow) serial consoles
  668 + */
  669 + if (percent != percent_complete) {
  670 + if (!opts->quiet)
  671 + printf("\rReading data from 0x%x "
  672 + "-- %3d%% complete.",
  673 + mtdoffset, percent);
  674 + percent_complete = percent;
  675 + }
  676 + }
  677 +
  678 + mtdoffset += meminfo->oobblock;
  679 + }
  680 +
  681 + if (!opts->quiet)
  682 + printf("\n");
  683 +
  684 + if (imglen > 0) {
  685 + printf("Could not read entire image due to bad blocks\n");
  686 + return -1;
  687 + }
  688 +
  689 + /* return happy */
  690 + return 0;
  691 +}
  692 +
  693 +/******************************************************************************
  694 + * Support for locking / unlocking operations of some NAND devices
  695 + *****************************************************************************/
  696 +
  697 +#define NAND_CMD_LOCK 0x2a
  698 +#define NAND_CMD_LOCK_TIGHT 0x2c
  699 +#define NAND_CMD_UNLOCK1 0x23
  700 +#define NAND_CMD_UNLOCK2 0x24
  701 +#define NAND_CMD_LOCK_STATUS 0x7a
  702 +
  703 +/**
  704 + * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
  705 + * state
  706 + *
  707 + * @param meminfo nand mtd instance
  708 + * @param tight bring device in lock tight mode
  709 + *
  710 + * @return 0 on success, -1 in case of error
  711 + *
  712 + * The lock / lock-tight command only applies to the whole chip. To get some
  713 + * parts of the chip lock and others unlocked use the following sequence:
  714 + *
  715 + * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin)
  716 + * - Call nand_unlock() once for each consecutive area to be unlocked
  717 + * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1)
  718 + *
  719 + * If the device is in lock-tight state software can't change the
  720 + * current active lock/unlock state of all pages. nand_lock() / nand_unlock()
  721 + * calls will fail. It is only posible to leave lock-tight state by
  722 + * an hardware signal (low pulse on _WP pin) or by power down.
  723 + */
  724 +int nand_lock(nand_info_t *meminfo, int tight)
  725 +{
  726 + int ret = 0;
  727 + int status;
  728 + struct nand_chip *this = meminfo->priv;
  729 +
  730 + /* select the NAND device */
  731 + this->select_chip(meminfo, 0);
  732 +
  733 + this->cmdfunc(meminfo,
  734 + (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
  735 + -1, -1);
  736 +
  737 + /* call wait ready function */
  738 + status = this->waitfunc(meminfo, this, FL_WRITING);
  739 +
  740 + /* see if device thinks it succeeded */
  741 + if (status & 0x01) {
  742 + ret = -1;
  743 + }
  744 +
  745 + /* de-select the NAND device */
  746 + this->select_chip(meminfo, -1);
  747 + return ret;
  748 +}
  749 +
  750 +/**
  751 + * nand_get_lock_status: - query current lock state from one page of NAND
  752 + * flash
  753 + *
  754 + * @param meminfo nand mtd instance
  755 + * @param offset page address to query (muss be page aligned!)
  756 + *
  757 + * @return -1 in case of error
  758 + * >0 lock status:
  759 + * bitfield with the following combinations:
  760 + * NAND_LOCK_STATUS_TIGHT: page in tight state
  761 + * NAND_LOCK_STATUS_LOCK: page locked
  762 + * NAND_LOCK_STATUS_UNLOCK: page unlocked
  763 + *
  764 + */
  765 +int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
  766 +{
  767 + int ret = 0;
  768 + int chipnr;
  769 + int page;
  770 + struct nand_chip *this = meminfo->priv;
  771 +
  772 + /* select the NAND device */
  773 + chipnr = (int)(offset >> this->chip_shift);
  774 + this->select_chip(meminfo, chipnr);
  775 +
  776 +
  777 + if ((offset & (meminfo->oobblock - 1)) != 0) {
  778 + printf ("nand_get_lock_status: "
  779 + "Start address must be beginning of "
  780 + "nand page!\n");
  781 + ret = -1;
  782 + goto out;
  783 + }
  784 +
  785 + /* check the Lock Status */
  786 + page = (int)(offset >> this->page_shift);
  787 + this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);
  788 +
  789 + ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT
  790 + | NAND_LOCK_STATUS_LOCK
  791 + | NAND_LOCK_STATUS_UNLOCK);
  792 +
  793 + out:
  794 + /* de-select the NAND device */
  795 + this->select_chip(meminfo, -1);
  796 + return ret;
  797 +}
  798 +
  799 +/**
  800 + * nand_unlock: - Unlock area of NAND pages
  801 + * only one consecutive area can be unlocked at one time!
  802 + *
  803 + * @param meminfo nand mtd instance
  804 + * @param start start byte address
  805 + * @param length number of bytes to unlock (must be a multiple of
  806 + * page size nand->oobblock)
  807 + *
  808 + * @return 0 on success, -1 in case of error
  809 + */
  810 +int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
  811 +{
  812 + int ret = 0;
  813 + int chipnr;
  814 + int status;
  815 + int page;
  816 + struct nand_chip *this = meminfo->priv;
  817 + printf ("nand_unlock: start: %08x, length: %d!\n",
  818 + (int)start, (int)length);
  819 +
  820 + /* select the NAND device */
  821 + chipnr = (int)(start >> this->chip_shift);
  822 + this->select_chip(meminfo, chipnr);
  823 +
  824 + /* check the WP bit */
  825 + this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);
  826 + if ((this->read_byte(meminfo) & 0x80) == 0) {
  827 + printf ("nand_unlock: Device is write protected!\n");
  828 + ret = -1;
  829 + goto out;
  830 + }
  831 +
  832 + if ((start & (meminfo->oobblock - 1)) != 0) {
  833 + printf ("nand_unlock: Start address must be beginning of "
  834 + "nand page!\n");
  835 + ret = -1;
  836 + goto out;
  837 + }
  838 +
  839 + if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) {
  840 + printf ("nand_unlock: Length must be a multiple of nand page "
  841 + "size!\n");
  842 + ret = -1;
  843 + goto out;
  844 + }
  845 +
  846 + /* submit address of first page to unlock */
  847 + page = (int)(start >> this->page_shift);
  848 + this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
  849 +
  850 + /* submit ADDRESS of LAST page to unlock */
  851 + page += (int)(length >> this->page_shift) - 1;
  852 + this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
  853 +
  854 + /* call wait ready function */
  855 + status = this->waitfunc(meminfo, this, FL_WRITING);
  856 + /* see if device thinks it succeeded */
  857 + if (status & 0x01) {
  858 + /* there was an error */
  859 + ret = -1;
  860 + goto out;
  861 + }
  862 +
  863 + out:
  864 + /* de-select the NAND device */
  865 + this->select_chip(meminfo, -1);
  866 + return ret;
  867 +}
  868 +
  869 +#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) */
... ... @@ -60,5 +60,62 @@
60 60 return info->erase(info, &instr);
61 61 }
62 62  
  63 +
  64 +/*****************************************************************************
  65 + * declarations from nand_util.c
  66 + ****************************************************************************/
  67 +
  68 +struct nand_write_options {
  69 + u_char *buffer; /* memory block containing image to write */
  70 + ulong length; /* number of bytes to write */
  71 + ulong offset; /* start address in NAND */
  72 + int quiet; /* don't display progress messages */
  73 + int autoplace; /* if true use auto oob layout */
  74 + int forcejffs2; /* force jffs2 oob layout */
  75 + int forceyaffs; /* force yaffs oob layout */
  76 + int noecc; /* write without ecc */
  77 + int writeoob; /* image contains oob data */
  78 + int pad; /* pad to page size */
  79 + int blockalign; /* 1|2|4 set multiple of eraseblocks
  80 + * to align to */
  81 +};
  82 +
  83 +typedef struct nand_write_options nand_write_options_t;
  84 +
  85 +struct nand_read_options {
  86 + u_char *buffer; /* memory block in which read image is written*/
  87 + ulong length; /* number of bytes to read */
  88 + ulong offset; /* start address in NAND */
  89 + int quiet; /* don't display progress messages */
  90 + int readoob; /* put oob data in image */
  91 +};
  92 +
  93 +typedef struct nand_read_options nand_read_options_t;
  94 +
  95 +struct nand_erase_options {
  96 + ulong length; /* number of bytes to erase */
  97 + ulong offset; /* first address in NAND to erase */
  98 + int quiet; /* don't display progress messages */
  99 + int jffs2; /* if true: format for jffs2 usage
  100 + * (write appropriate cleanmarker blocks) */
  101 + int scrub; /* if true, really clean NAND by erasing
  102 + * bad blocks (UNSAFE) */
  103 +};
  104 +
  105 +typedef struct nand_erase_options nand_erase_options_t;
  106 +
  107 +int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts);
  108 +
  109 +int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts);
  110 +int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
  111 +
  112 +#define NAND_LOCK_STATUS_TIGHT 0x01
  113 +#define NAND_LOCK_STATUS_LOCK 0x02
  114 +#define NAND_LOCK_STATUS_UNLOCK 0x04
  115 +
  116 +int nand_lock( nand_info_t *meminfo, int tight );
  117 +int nand_unlock( nand_info_t *meminfo, ulong start, ulong length );
  118 +int nand_get_lock_status(nand_info_t *meminfo, ulong offset);
  119 +
63 120 #endif
... ... @@ -171,7 +171,9 @@
171 171 return crc ^ 0xffffffffL;
172 172 }
173 173  
174   -#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
  174 +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) \
  175 + || (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
  176 +
175 177  
176 178 /* No ones complement version. JFFS2 (and other things ?)
177 179 * don't use ones compliment in their CRC calculations.