Blame view

common/cmd_nand.c 25 KB
dc7c9a1a5   wdenk   * Patch by Rick B...
1
2
3
4
5
  /*
   * Driver for NAND support, Rick Bronson
   * borrowed heavily from:
   * (c) 1999 Machine Vision Holdings, Inc.
   * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
384cc6874   wdenk   Patches by Josef ...
6
   *
c9f7351b5   Ben Gardiner   NAND: environment...
7
8
9
10
   * Ported 'dynenv' to 'nand env.oob' command
   * (C) 2010 Nanometrics, Inc.
   * 'dynenv' -- Dynamic environment offset in NAND OOB
   * (C) Copyright 2006-2007 OpenMoko, Inc.
384cc6874   wdenk   Patches by Josef ...
11
12
   * Added 16-bit nand support
   * (C) 2004 Texas Instruments
ea533c260   Scott Wood   cmd_nand: some in...
13
   *
418396e21   Scott Wood   nand: extend .raw...
14
   * Copyright 2010, 2012 Freescale Semiconductor
ea533c260   Scott Wood   cmd_nand: some in...
15
16
17
18
19
   * The portions of this file whose copyright is held by Freescale and which
   * are not considered a derived work of GPL v2-only code may be distributed
   * and/or modified under the terms of the GNU General Public License as
   * published by the Free Software Foundation; either version 2 of the
   * License, or (at your option) any later version.
dc7c9a1a5   wdenk   * Patch by Rick B...
20
21
22
   */
  
  #include <common.h>
cfa460adf   William Juul   Update MTD to tha...
23
  #include <linux/mtd/mtd.h>
addb2e165   Bartlomiej Sieka   Re-factoring the ...
24
25
26
27
  #include <command.h>
  #include <watchdog.h>
  #include <malloc.h>
  #include <asm/byteorder.h>
addb2e165   Bartlomiej Sieka   Re-factoring the ...
28
29
  #include <jffs2/jffs2.h>
  #include <nand.h>
0c8a84916   Ladislav Michl   Separate mtdparts...
30
  #if defined(CONFIG_CMD_MTDPARTS)
856f05441   Stefan Roese   [PATCH] NAND: Par...
31

445093d17   Wolfgang Denk   Fix "par[t]ition"...
32
  /* partition handling routines */
856f05441   Stefan Roese   [PATCH] NAND: Par...
33
34
35
  int mtdparts_init(void);
  int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num);
  int find_dev_and_part(const char *id, struct mtd_device **dev,
4b0708093   Wolfgang Denk   Coding Style clea...
36
  		      u8 *part_num, struct part_info **part);
856f05441   Stefan Roese   [PATCH] NAND: Par...
37
  #endif
8c5659a6d   Scott Wood   nand commands: ma...
38
  static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
addb2e165   Bartlomiej Sieka   Re-factoring the ...
39
40
  {
  	int i;
9ad754fef   William Juul   make nand dump an...
41
  	u_char *datbuf, *oobbuf, *p;
8c5659a6d   Scott Wood   nand commands: ma...
42
  	static loff_t last;
e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
43
  	int ret = 0;
8c5659a6d   Scott Wood   nand commands: ma...
44
45
46
47
48
  
  	if (repeat)
  		off = last + nand->writesize;
  
  	last = off;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
49

62fd66f3d   Thierry Reding   cmd_nand: dump: A...
50
  	datbuf = memalign(ARCH_DMA_MINALIGN, nand->writesize);
e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
51
  	if (!datbuf) {
addb2e165   Bartlomiej Sieka   Re-factoring the ...
52
53
54
55
  		puts("No memory for page buffer
  ");
  		return 1;
  	}
e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
56
57
58
59
60
61
62
63
  
  	oobbuf = memalign(ARCH_DMA_MINALIGN, nand->oobsize);
  	if (!oobbuf) {
  		puts("No memory for page buffer
  ");
  		ret = 1;
  		goto free_dat;
  	}
cfa460adf   William Juul   Update MTD to tha...
64
  	off &= ~(nand->writesize - 1);
cfa460adf   William Juul   Update MTD to tha...
65
  	loff_t addr = (loff_t) off;
9ad754fef   William Juul   make nand dump an...
66
67
68
  	struct mtd_oob_ops ops;
  	memset(&ops, 0, sizeof(ops));
  	ops.datbuf = datbuf;
cfdae12f3   Tom Rini   cmd_nand.c: Fix '...
69
  	ops.oobbuf = oobbuf;
9ad754fef   William Juul   make nand dump an...
70
71
  	ops.len = nand->writesize;
  	ops.ooblen = nand->oobsize;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
72
73
  	ops.mode = MTD_OPS_RAW;
  	i = mtd_read_oob(nand, addr, &ops);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
74
  	if (i < 0) {
e870690bd   Stefan Roese   MTD/NAND: Fix pri...
75
76
  		printf("Error (%d) reading page %08lx
  ", i, off);
e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
77
78
  		ret = 1;
  		goto free_all;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
79
  	}
e870690bd   Stefan Roese   MTD/NAND: Fix pri...
80
81
  	printf("Page %08lx dump:
  ", off);
4b0708093   Wolfgang Denk   Coding Style clea...
82

7d25cd34e   Masahiro Yamada   cmd_nand: slight ...
83
84
85
86
87
  	if (!only_oob) {
  		i = nand->writesize >> 4;
  		p = datbuf;
  
  		while (i--) {
9ad754fef   William Juul   make nand dump an...
88
89
90
91
  			printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
  			       "  %02x %02x %02x %02x %02x %02x %02x %02x
  ",
  			       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
dfbf617ff   Scott Wood   NAND read/write fix
92
93
  			       p[8], p[9], p[10], p[11], p[12], p[13], p[14],
  			       p[15]);
7d25cd34e   Masahiro Yamada   cmd_nand: slight ...
94
95
  			p += 16;
  		}
addb2e165   Bartlomiej Sieka   Re-factoring the ...
96
  	}
7d25cd34e   Masahiro Yamada   cmd_nand: slight ...
97

addb2e165   Bartlomiej Sieka   Re-factoring the ...
98
99
100
  	puts("OOB:
  ");
  	i = nand->oobsize >> 3;
cfdae12f3   Tom Rini   cmd_nand.c: Fix '...
101
  	p = oobbuf;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
102
  	while (i--) {
cfa460adf   William Juul   Update MTD to tha...
103
104
105
  		printf("\t%02x %02x %02x %02x %02x %02x %02x %02x
  ",
  		       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
106
107
  		p += 8;
  	}
e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
108
109
  
  free_all:
9ad754fef   William Juul   make nand dump an...
110
  	free(oobbuf);
e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
111
112
  free_dat:
  	free(datbuf);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
113

e40520b5b   Masahiro Yamada   cmd_nand: fix a m...
114
  	return ret;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
115
116
117
  }
  
  /* ------------------------------------------------------------------------- */
ea533c260   Scott Wood   cmd_nand: some in...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  static int set_dev(int dev)
  {
  	if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
  	    !nand_info[dev].name) {
  		puts("No such device
  ");
  		return -1;
  	}
  
  	if (nand_curr_device == dev)
  		return 0;
  
  	printf("Device %d: %s", dev, nand_info[dev].name);
  	puts("... is now current device
  ");
  	nand_curr_device = dev;
  
  #ifdef CONFIG_SYS_NAND_SELECT_DEVICE
  	board_nand_select_device(nand_info[dev].priv, dev);
  #endif
  
  	return 0;
  }
  
  static inline int str2off(const char *p, loff_t *num)
  {
  	char *endptr;
  
  	*num = simple_strtoull(p, &endptr, 16);
  	return *p != '\0' && *endptr == '\0';
  }
  
  static inline int str2long(const char *p, ulong *num)
addb2e165   Bartlomiej Sieka   Re-factoring the ...
151
  {
856f05441   Stefan Roese   [PATCH] NAND: Par...
152
  	char *endptr;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
153

856f05441   Stefan Roese   [PATCH] NAND: Par...
154
  	*num = simple_strtoul(p, &endptr, 16);
ea533c260   Scott Wood   cmd_nand: some in...
155
  	return *p != '\0' && *endptr == '\0';
856f05441   Stefan Roese   [PATCH] NAND: Par...
156
  }
addb2e165   Bartlomiej Sieka   Re-factoring the ...
157

c39d6a0ea   Tom Rini   nand: Extend nand...
158
159
  static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
  		loff_t *maxsize)
856f05441   Stefan Roese   [PATCH] NAND: Par...
160
  {
ea533c260   Scott Wood   cmd_nand: some in...
161
  #ifdef CONFIG_CMD_MTDPARTS
856f05441   Stefan Roese   [PATCH] NAND: Par...
162
163
164
  	struct mtd_device *dev;
  	struct part_info *part;
  	u8 pnum;
ea533c260   Scott Wood   cmd_nand: some in...
165
  	int ret;
856f05441   Stefan Roese   [PATCH] NAND: Par...
166

ea533c260   Scott Wood   cmd_nand: some in...
167
168
169
170
171
172
173
174
175
176
177
178
  	ret = mtdparts_init();
  	if (ret)
  		return ret;
  
  	ret = find_dev_and_part(partname, &dev, &pnum, &part);
  	if (ret)
  		return ret;
  
  	if (dev->id->type != MTD_DEV_TYPE_NAND) {
  		puts("not a NAND device
  ");
  		return -1;
856f05441   Stefan Roese   [PATCH] NAND: Par...
179
  	}
ea533c260   Scott Wood   cmd_nand: some in...
180
181
182
  
  	*off = part->offset;
  	*size = part->size;
c39d6a0ea   Tom Rini   nand: Extend nand...
183
  	*maxsize = part->size;
ea533c260   Scott Wood   cmd_nand: some in...
184
185
186
187
188
189
190
191
192
193
194
  	*idx = dev->id->num;
  
  	ret = set_dev(*idx);
  	if (ret)
  		return ret;
  
  	return 0;
  #else
  	puts("offset is not a number
  ");
  	return -1;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
195
  #endif
ea533c260   Scott Wood   cmd_nand: some in...
196
  }
addb2e165   Bartlomiej Sieka   Re-factoring the ...
197

c39d6a0ea   Tom Rini   nand: Extend nand...
198
199
  static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size,
  		loff_t *maxsize)
ea533c260   Scott Wood   cmd_nand: some in...
200
201
  {
  	if (!str2off(arg, off))
c39d6a0ea   Tom Rini   nand: Extend nand...
202
  		return get_part(arg, idx, off, size, maxsize);
ea533c260   Scott Wood   cmd_nand: some in...
203
204
205
206
207
208
209
210
  
  	if (*off >= nand_info[*idx].size) {
  		puts("Offset exceeds device limit
  ");
  		return -1;
  	}
  
  	*maxsize = nand_info[*idx].size - *off;
c39d6a0ea   Tom Rini   nand: Extend nand...
211
  	*size = *maxsize;
ea533c260   Scott Wood   cmd_nand: some in...
212
213
214
215
  	return 0;
  }
  
  static int arg_off_size(int argc, char *const argv[], int *idx,
c39d6a0ea   Tom Rini   nand: Extend nand...
216
  			loff_t *off, loff_t *size, loff_t *maxsize)
ea533c260   Scott Wood   cmd_nand: some in...
217
218
  {
  	int ret;
ea533c260   Scott Wood   cmd_nand: some in...
219
220
  
  	if (argc == 0) {
856f05441   Stefan Roese   [PATCH] NAND: Par...
221
  		*off = 0;
ea533c260   Scott Wood   cmd_nand: some in...
222
  		*size = nand_info[*idx].size;
c39d6a0ea   Tom Rini   nand: Extend nand...
223
  		*maxsize = *size;
ea533c260   Scott Wood   cmd_nand: some in...
224
  		goto print;
856f05441   Stefan Roese   [PATCH] NAND: Par...
225
  	}
addb2e165   Bartlomiej Sieka   Re-factoring the ...
226

c39d6a0ea   Tom Rini   nand: Extend nand...
227
  	ret = arg_off(argv[0], idx, off, size, maxsize);
ea533c260   Scott Wood   cmd_nand: some in...
228
229
  	if (ret)
  		return ret;
c39d6a0ea   Tom Rini   nand: Extend nand...
230
  	if (argc == 1)
ea533c260   Scott Wood   cmd_nand: some in...
231
  		goto print;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
232

ea533c260   Scott Wood   cmd_nand: some in...
233
234
235
236
237
  	if (!str2off(argv[1], size)) {
  		printf("'%s' is not a number
  ", argv[1]);
  		return -1;
  	}
c39d6a0ea   Tom Rini   nand: Extend nand...
238
  	if (*size > *maxsize) {
ea533c260   Scott Wood   cmd_nand: some in...
239
240
241
242
243
244
245
246
  		puts("Size exceeds partition or device limit
  ");
  		return -1;
  	}
  
  print:
  	printf("device %d ", *idx);
  	if (*size == nand_info[*idx].size)
856f05441   Stefan Roese   [PATCH] NAND: Par...
247
248
249
  		puts("whole chip
  ");
  	else
ea533c260   Scott Wood   cmd_nand: some in...
250
251
252
  		printf("offset 0x%llx, size 0x%llx
  ",
  		       (unsigned long long)*off, (unsigned long long)*size);
856f05441   Stefan Roese   [PATCH] NAND: Par...
253
  	return 0;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
254
  }
50657c273   Nishanth Menon   NAND: Enable nand...
255
256
257
  #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
  static void print_status(ulong start, ulong end, ulong erasesize, int status)
  {
e70bfa298   Joe Hershberger   nand: Make NAND l...
258
259
260
261
262
263
  	/*
  	 * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is
  	 * not the same as others.  Instead of bit 1 being lock, it is
  	 * #lock_tight. To make the driver support either format, ignore bit 1
  	 * and use only bit 0 and bit 2.
  	 */
50657c273   Nishanth Menon   NAND: Enable nand...
264
265
266
267
268
269
  	printf("%08lx - %08lx: %08lx blocks %s%s%s
  ",
  		start,
  		end - 1,
  		(end - start) / erasesize,
  		((status & NAND_LOCK_STATUS_TIGHT) ?  "TIGHT " : ""),
e70bfa298   Joe Hershberger   nand: Make NAND l...
270
  		(!(status & NAND_LOCK_STATUS_UNLOCK) ?  "LOCK " : ""),
50657c273   Nishanth Menon   NAND: Enable nand...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  		((status & NAND_LOCK_STATUS_UNLOCK) ?  "UNLOCK " : ""));
  }
  
  static void do_nand_status(nand_info_t *nand)
  {
  	ulong block_start = 0;
  	ulong off;
  	int last_status = -1;
  
  	struct nand_chip *nand_chip = nand->priv;
  	/* check the WP bit */
  	nand_chip->cmdfunc(nand, NAND_CMD_STATUS, -1, -1);
  	printf("device is %swrite protected
  ",
  		(nand_chip->read_byte(nand) & 0x80 ?
  		"NOT " : ""));
  
  	for (off = 0; off < nand->size; off += nand->erasesize) {
  		int s = nand_get_lock_status(nand, off);
  
  		/* print message only if status has changed */
  		if (s != last_status && off != 0) {
  			print_status(block_start, off, nand->erasesize,
  					last_status);
  			block_start = off;
  		}
  		last_status = s;
  	}
  	/* Print the last block info */
  	print_status(block_start, off, nand->erasesize, last_status);
  }
  #endif
c9f7351b5   Ben Gardiner   NAND: environment...
303
304
  #ifdef CONFIG_ENV_OFFSET_OOB
  unsigned long nand_env_oob_offset;
ea533c260   Scott Wood   cmd_nand: some in...
305
  int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])
c9f7351b5   Ben Gardiner   NAND: environment...
306
307
308
  {
  	int ret;
  	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
ea533c260   Scott Wood   cmd_nand: some in...
309
  	nand_info_t *nand = &nand_info[0];
c9f7351b5   Ben Gardiner   NAND: environment...
310
  	char *cmd = argv[1];
ea533c260   Scott Wood   cmd_nand: some in...
311
312
313
314
315
316
317
  	if (CONFIG_SYS_MAX_NAND_DEVICE == 0 || !nand->name) {
  		puts("no devices available
  ");
  		return 1;
  	}
  
  	set_dev(0);
c9f7351b5   Ben Gardiner   NAND: environment...
318
319
  	if (!strcmp(cmd, "get")) {
  		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
53504a278   Scott Wood   NAND: formatting ...
320
  		if (ret)
c9f7351b5   Ben Gardiner   NAND: environment...
321
  			return 1;
53504a278   Scott Wood   NAND: formatting ...
322
323
324
  
  		printf("0x%08lx
  ", nand_env_oob_offset);
c9f7351b5   Ben Gardiner   NAND: environment...
325
  	} else if (!strcmp(cmd, "set")) {
ea533c260   Scott Wood   cmd_nand: some in...
326
327
  		loff_t addr;
  		loff_t maxsize;
c9f7351b5   Ben Gardiner   NAND: environment...
328
  		struct mtd_oob_ops ops;
ea533c260   Scott Wood   cmd_nand: some in...
329
  		int idx = 0;
c9f7351b5   Ben Gardiner   NAND: environment...
330
331
332
  
  		if (argc < 3)
  			goto usage;
c39d6a0ea   Tom Rini   nand: Extend nand...
333
334
  		/* We don't care about size, or maxsize. */
  		if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) {
ea533c260   Scott Wood   cmd_nand: some in...
335
336
337
338
339
340
341
342
  			puts("Offset or partition name expected
  ");
  			return 1;
  		}
  
  		if (idx != 0) {
  			puts("Partition not on first NAND device
  ");
c9f7351b5   Ben Gardiner   NAND: environment...
343
344
345
346
  			return 1;
  		}
  
  		if (nand->oobavail < ENV_OFFSET_SIZE) {
53504a278   Scott Wood   NAND: formatting ...
347
348
349
350
351
352
  			printf("Insufficient available OOB bytes:
  "
  			       "%d OOB bytes available but %d required for "
  			       "env.oob support
  ",
  			       nand->oobavail, ENV_OFFSET_SIZE);
c9f7351b5   Ben Gardiner   NAND: environment...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  			return 1;
  		}
  
  		if ((addr & (nand->erasesize - 1)) != 0) {
  			printf("Environment offset must be block-aligned
  ");
  			return 1;
  		}
  
  		ops.datbuf = NULL;
  		ops.mode = MTD_OOB_AUTO;
  		ops.ooboffs = 0;
  		ops.ooblen = ENV_OFFSET_SIZE;
  		ops.oobbuf = (void *) oob_buf;
  
  		oob_buf[0] = ENV_OOB_MARKER;
  		oob_buf[1] = addr / nand->erasesize;
  
  		ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
53504a278   Scott Wood   NAND: formatting ...
372
  		if (ret) {
c9f7351b5   Ben Gardiner   NAND: environment...
373
374
375
376
  			printf("Error writing OOB block 0
  ");
  			return ret;
  		}
53504a278   Scott Wood   NAND: formatting ...
377
378
379
380
381
382
383
384
385
386
  
  		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
  		if (ret) {
  			printf("Error reading env offset in OOB
  ");
  			return ret;
  		}
  
  		if (addr != nand_env_oob_offset) {
  			printf("Verification of env offset in OOB failed: "
ea533c260   Scott Wood   cmd_nand: some in...
387
388
389
  			       "0x%08llx expected but got 0x%08lx
  ",
  			       (unsigned long long)addr, nand_env_oob_offset);
53504a278   Scott Wood   NAND: formatting ...
390
391
  			return 1;
  		}
c9f7351b5   Ben Gardiner   NAND: environment...
392
393
394
395
396
397
398
  	} else {
  		goto usage;
  	}
  
  	return ret;
  
  usage:
4c12eeb8b   Simon Glass   Convert cmd_usage...
399
  	return CMD_RET_USAGE;
c9f7351b5   Ben Gardiner   NAND: environment...
400
401
402
  }
  
  #endif
ce80ddc18   Marek Vasut   NAND: Make page, ...
403
  static void nand_print_and_set_info(int idx)
672ed2aee   Wolfgang Grandegger   Enable multi chip...
404
405
406
  {
  	nand_info_t *nand = &nand_info[idx];
  	struct nand_chip *chip = nand->priv;
ce80ddc18   Marek Vasut   NAND: Make page, ...
407

672ed2aee   Wolfgang Grandegger   Enable multi chip...
408
409
410
411
412
413
  	printf("Device %d: ", idx);
  	if (chip->numchips > 1)
  		printf("%dx ", chip->numchips);
  	printf("%s, sector size %u KiB
  ",
  	       nand->name, nand->erasesize >> 10);
ce80ddc18   Marek Vasut   NAND: Make page, ...
414
415
416
417
418
419
420
421
  	printf("  Page size  %8d b
  ", nand->writesize);
  	printf("  OOB size   %8d b
  ", nand->oobsize);
  	printf("  Erase size %8d b
  ", nand->erasesize);
  
  	/* Set geometry info */
41ef372c1   Simon Glass   common: Use new n...
422
423
424
  	setenv_hex("nand_writesize", nand->writesize);
  	setenv_hex("nand_oobsize", nand->oobsize);
  	setenv_hex("nand_erasesize", nand->erasesize);
672ed2aee   Wolfgang Grandegger   Enable multi chip...
425
  }
418396e21   Scott Wood   nand: extend .raw...
426
427
428
429
  static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
  			int read)
  {
  	int ret = 0;
418396e21   Scott Wood   nand: extend .raw...
430
431
432
433
434
435
436
437
  
  	while (count--) {
  		/* Raw access */
  		mtd_oob_ops_t ops = {
  			.datbuf = (u8 *)addr,
  			.oobbuf = ((u8 *)addr) + nand->writesize,
  			.len = nand->writesize,
  			.ooblen = nand->oobsize,
dfe64e2c8   Sergey Lapin   mtd: resync with ...
438
  			.mode = MTD_OPS_RAW
418396e21   Scott Wood   nand: extend .raw...
439
  		};
418396e21   Scott Wood   nand: extend .raw...
440
  		if (read)
dfe64e2c8   Sergey Lapin   mtd: resync with ...
441
  			ret = mtd_read_oob(nand, off, &ops);
418396e21   Scott Wood   nand: extend .raw...
442
  		else
dfe64e2c8   Sergey Lapin   mtd: resync with ...
443
  			ret = mtd_write_oob(nand, off, &ops);
418396e21   Scott Wood   nand: extend .raw...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  
  		if (ret) {
  			printf("%s: error at offset %llx, ret %d
  ",
  				__func__, (long long)off, ret);
  			break;
  		}
  
  		addr += nand->writesize + nand->oobsize;
  		off += nand->writesize;
  	}
  
  	return ret;
  }
e834402fa   Harvey Chapman   nand: adjust eras...
458
  /* Adjust a chip/partition size down for bad blocks so we don't
9b80aa8ec   Scott Wood   nand: Don't call ...
459
   * read/write past the end of a chip/partition by accident.
e834402fa   Harvey Chapman   nand: adjust eras...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
   */
  static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev)
  {
  	/* We grab the nand info object here fresh because this is usually
  	 * called after arg_off_size() which can change the value of dev.
  	 */
  	nand_info_t *nand = &nand_info[dev];
  	loff_t maxoffset = offset + *size;
  	int badblocks = 0;
  
  	/* count badblocks in NAND from offset to offset + size */
  	for (; offset < maxoffset; offset += nand->erasesize) {
  		if (nand_block_isbad(nand, offset))
  			badblocks++;
  	}
  	/* adjust size if any bad blocks found */
  	if (badblocks) {
  		*size -= badblocks * nand->erasesize;
  		printf("size adjusted to 0x%llx (%d bad blocks)
  ",
  		       (unsigned long long)*size, badblocks);
  	}
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
483
  static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
addb2e165   Bartlomiej Sieka   Re-factoring the ...
484
  {
ea533c260   Scott Wood   cmd_nand: some in...
485
486
  	int i, ret = 0;
  	ulong addr;
c39d6a0ea   Tom Rini   nand: Extend nand...
487
  	loff_t off, size, maxsize;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
488
489
  	char *cmd, *s;
  	nand_info_t *nand;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
490
491
  #ifdef CONFIG_SYS_NAND_QUIET
  	int quiet = CONFIG_SYS_NAND_QUIET;
c750d2e66   Matthias Fuchs   NAND: Add CFG_NAN...
492
  #else
2255b2d20   Stefan Roese   * Several improve...
493
  	int quiet = 0;
c750d2e66   Matthias Fuchs   NAND: Add CFG_NAN...
494
  #endif
2255b2d20   Stefan Roese   * Several improve...
495
  	const char *quiet_str = getenv("quiet");
ea533c260   Scott Wood   cmd_nand: some in...
496
  	int dev = nand_curr_device;
8c5659a6d   Scott Wood   nand commands: ma...
497
  	int repeat = flag & CMD_FLAG_REPEAT;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
498
499
500
501
  
  	/* at least two arguments please */
  	if (argc < 2)
  		goto usage;
2255b2d20   Stefan Roese   * Several improve...
502
503
  	if (quiet_str)
  		quiet = simple_strtoul(quiet_str, NULL, 0) != 0;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
504
  	cmd = argv[1];
8c5659a6d   Scott Wood   nand commands: ma...
505
506
507
  	/* Only "dump" is repeatable. */
  	if (repeat && strcmp(cmd, "dump"))
  		return 0;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
508
509
510
511
  	if (strcmp(cmd, "info") == 0) {
  
  		putc('
  ');
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
512
  		for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
addb2e165   Bartlomiej Sieka   Re-factoring the ...
513
  			if (nand_info[i].name)
ce80ddc18   Marek Vasut   NAND: Make page, ...
514
  				nand_print_and_set_info(i);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
515
516
517
518
519
  		}
  		return 0;
  	}
  
  	if (strcmp(cmd, "device") == 0) {
addb2e165   Bartlomiej Sieka   Re-factoring the ...
520
  		if (argc < 3) {
672ed2aee   Wolfgang Grandegger   Enable multi chip...
521
522
  			putc('
  ');
ea533c260   Scott Wood   cmd_nand: some in...
523
  			if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
672ed2aee   Wolfgang Grandegger   Enable multi chip...
524
525
  				puts("no devices available
  ");
addb2e165   Bartlomiej Sieka   Re-factoring the ...
526
  			else
ce80ddc18   Marek Vasut   NAND: Make page, ...
527
  				nand_print_and_set_info(dev);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
528
529
  			return 0;
  		}
43a2b0e76   Stefan Roese   Add board/cpu spe...
530

ea533c260   Scott Wood   cmd_nand: some in...
531
532
  		dev = (int)simple_strtoul(argv[2], NULL, 10);
  		set_dev(dev);
43a2b0e76   Stefan Roese   Add board/cpu spe...
533

addb2e165   Bartlomiej Sieka   Re-factoring the ...
534
535
  		return 0;
  	}
c9f7351b5   Ben Gardiner   NAND: environment...
536
537
  #ifdef CONFIG_ENV_OFFSET_OOB
  	/* this command operates only on the first nand device */
ea533c260   Scott Wood   cmd_nand: some in...
538
539
  	if (strcmp(cmd, "env.oob") == 0)
  		return do_nand_env_oob(cmdtp, argc - 1, argv + 1);
c9f7351b5   Ben Gardiner   NAND: environment...
540
  #endif
ea533c260   Scott Wood   cmd_nand: some in...
541
542
543
544
545
546
547
548
  	/* The following commands operate on the current device, unless
  	 * overridden by a partition specifier.  Note that if somehow the
  	 * current device is invalid, it will have to be changed to a valid
  	 * one before these commands can run, even if a partition specifier
  	 * for another device is to be used.
  	 */
  	if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
  	    !nand_info[dev].name) {
addb2e165   Bartlomiej Sieka   Re-factoring the ...
549
550
551
552
553
  		puts("
  no devices available
  ");
  		return 1;
  	}
ea533c260   Scott Wood   cmd_nand: some in...
554
  	nand = &nand_info[dev];
addb2e165   Bartlomiej Sieka   Re-factoring the ...
555
556
  
  	if (strcmp(cmd, "bad") == 0) {
ea533c260   Scott Wood   cmd_nand: some in...
557
558
559
  		printf("
  Device %d bad blocks:
  ", dev);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
560
561
  		for (off = 0; off < nand->size; off += nand->erasesize)
  			if (nand_block_isbad(nand, off))
ea533c260   Scott Wood   cmd_nand: some in...
562
563
  				printf("  %08llx
  ", (unsigned long long)off);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
564
565
  		return 0;
  	}
856f05441   Stefan Roese   [PATCH] NAND: Par...
566
567
568
569
570
  	/*
  	 * Syntax is:
  	 *   0    1     2       3    4
  	 *   nand erase [clean] [off size]
  	 */
304863225   Scott Wood   nand erase: .spre...
571
  	if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) {
2255b2d20   Stefan Roese   * Several improve...
572
  		nand_erase_options_t opts;
856f05441   Stefan Roese   [PATCH] NAND: Par...
573
  		/* "clean" at index 2 means request to write cleanmarker */
3043c045d   William Juul   Whitespace cleanu...
574
  		int clean = argc > 2 && !strcmp("clean", argv[2]);
608998166   Marek Vasut   NAND: Add -y opti...
575
576
  		int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
  		int o = (clean || scrub_yes) ? 3 : 2;
304863225   Scott Wood   nand erase: .spre...
577
  		int scrub = !strncmp(cmd, "scrub", 5);
304863225   Scott Wood   nand erase: .spre...
578
579
  		int spread = 0;
  		int args = 2;
608998166   Marek Vasut   NAND: Add -y opti...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  		const char *scrub_warn =
  			"Warning: "
  			"scrub option will erase all factory set bad blocks!
  "
  			"         "
  			"There is no reliable way to recover them.
  "
  			"         "
  			"Use this command only for testing purposes if you
  "
  			"         "
  			"are sure of what you are doing!
  "
  			"
  Really scrub this NAND flash? <y/N>
  ";
304863225   Scott Wood   nand erase: .spre...
596
597
598
599
600
  
  		if (cmd[5] != 0) {
  			if (!strcmp(&cmd[5], ".spread")) {
  				spread = 1;
  			} else if (!strcmp(&cmd[5], ".part")) {
304863225   Scott Wood   nand erase: .spre...
601
602
  				args = 1;
  			} else if (!strcmp(&cmd[5], ".chip")) {
304863225   Scott Wood   nand erase: .spre...
603
604
605
606
607
608
609
610
611
612
613
614
615
  				args = 0;
  			} else {
  				goto usage;
  			}
  		}
  
  		/*
  		 * Don't allow missing arguments to cause full chip/partition
  		 * erases -- easy to do accidentally, e.g. with a misspelled
  		 * variable name.
  		 */
  		if (argc != o + args)
  			goto usage;
2255b2d20   Stefan Roese   * Several improve...
616

304863225   Scott Wood   nand erase: .spre...
617
618
  		printf("
  NAND %s: ", cmd);
856f05441   Stefan Roese   [PATCH] NAND: Par...
619
  		/* skip first two or three arguments, look for offset and size */
c39d6a0ea   Tom Rini   nand: Extend nand...
620
621
  		if (arg_off_size(argc - o, argv + o, &dev, &off, &size,
  				 &maxsize) != 0)
856f05441   Stefan Roese   [PATCH] NAND: Par...
622
  			return 1;
2255b2d20   Stefan Roese   * Several improve...
623

ea533c260   Scott Wood   cmd_nand: some in...
624
  		nand = &nand_info[dev];
2255b2d20   Stefan Roese   * Several improve...
625
626
627
628
629
  		memset(&opts, 0, sizeof(opts));
  		opts.offset = off;
  		opts.length = size;
  		opts.jffs2  = clean;
  		opts.quiet  = quiet;
304863225   Scott Wood   nand erase: .spre...
630
  		opts.spread = spread;
2255b2d20   Stefan Roese   * Several improve...
631
632
  
  		if (scrub) {
608998166   Marek Vasut   NAND: Add -y opti...
633
634
635
636
637
638
  			if (!scrub_yes)
  				puts(scrub_warn);
  
  			if (scrub_yes)
  				opts.scrub = 1;
  			else if (getc() == 'y') {
6b94b4962   Florian Fainelli   cmd_nand: show na...
639
640
641
642
643
644
  				puts("y");
  				if (getc() == '\r')
  					opts.scrub = 1;
  				else {
  					puts("scrub aborted
  ");
46aabcc44   Masahiro Yamada   cmd_nand: Do not ...
645
  					return 1;
6b94b4962   Florian Fainelli   cmd_nand: show na...
646
  				}
2255b2d20   Stefan Roese   * Several improve...
647
  			} else {
856f05441   Stefan Roese   [PATCH] NAND: Par...
648
649
  				puts("scrub aborted
  ");
46aabcc44   Masahiro Yamada   cmd_nand: Do not ...
650
  				return 1;
2255b2d20   Stefan Roese   * Several improve...
651
652
653
  			}
  		}
  		ret = nand_erase_opts(nand, &opts);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
654
655
656
657
658
659
660
661
662
  		printf("%s
  ", ret ? "ERROR" : "OK");
  
  		return ret == 0 ? 0 : 1;
  	}
  
  	if (strncmp(cmd, "dump", 4) == 0) {
  		if (argc < 3)
  			goto usage;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
663
  		off = (int)simple_strtoul(argv[2], NULL, 16);
8c5659a6d   Scott Wood   nand commands: ma...
664
  		ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
665
666
  
  		return ret == 0 ? 1 : 0;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
667
  	}
addb2e165   Bartlomiej Sieka   Re-factoring the ...
668
  	if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
ea533c260   Scott Wood   cmd_nand: some in...
669
  		size_t rwsize;
418396e21   Scott Wood   nand: extend .raw...
670
  		ulong pagecount = 1;
2255b2d20   Stefan Roese   * Several improve...
671
  		int read;
ced199dc8   Harvey Chapman   nand: fix nand re...
672
  		int raw = 0;
2255b2d20   Stefan Roese   * Several improve...
673

addb2e165   Bartlomiej Sieka   Re-factoring the ...
674
675
  		if (argc < 4)
  			goto usage;
2255b2d20   Stefan Roese   * Several improve...
676

addb2e165   Bartlomiej Sieka   Re-factoring the ...
677
  		addr = (ulong)simple_strtoul(argv[2], NULL, 16);
2255b2d20   Stefan Roese   * Several improve...
678
  		read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
856f05441   Stefan Roese   [PATCH] NAND: Par...
679
680
  		printf("
  NAND %s: ", read ? "read" : "write");
4cbb651b2   William Juul   Remove white spac...
681

ea533c260   Scott Wood   cmd_nand: some in...
682
  		nand = &nand_info[dev];
ea533c260   Scott Wood   cmd_nand: some in...
683

2255b2d20   Stefan Roese   * Several improve...
684
  		s = strchr(cmd, '.');
418396e21   Scott Wood   nand: extend .raw...
685

8d75c8964   Steve Sakoman   cmd_nand: fix cra...
686
  		if (s && !strcmp(s, ".raw")) {
418396e21   Scott Wood   nand: extend .raw...
687
  			raw = 1;
c39d6a0ea   Tom Rini   nand: Extend nand...
688
  			if (arg_off(argv[3], &dev, &off, &size, &maxsize))
418396e21   Scott Wood   nand: extend .raw...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  				return 1;
  
  			if (argc > 4 && !str2long(argv[4], &pagecount)) {
  				printf("'%s' is not a number
  ", argv[4]);
  				return 1;
  			}
  
  			if (pagecount * nand->writesize > size) {
  				puts("Size exceeds partition or device limit
  ");
  				return -1;
  			}
  
  			rwsize = pagecount * (nand->writesize + nand->oobsize);
  		} else {
  			if (arg_off_size(argc - 3, argv + 3, &dev,
c39d6a0ea   Tom Rini   nand: Extend nand...
706
  						&off, &size, &maxsize) != 0)
418396e21   Scott Wood   nand: extend .raw...
707
  				return 1;
e834402fa   Harvey Chapman   nand: adjust eras...
708
709
710
  			/* size is unspecified */
  			if (argc < 5)
  				adjust_size_for_badblocks(&size, off, dev);
418396e21   Scott Wood   nand: extend .raw...
711
712
  			rwsize = size;
  		}
984e03cdf   Scott Wood   NAND: Always skip...
713
714
  		if (!s || !strcmp(s, ".jffs2") ||
  		    !strcmp(s, ".e") || !strcmp(s, ".i")) {
dfbf617ff   Scott Wood   NAND read/write fix
715
  			if (read)
ea533c260   Scott Wood   cmd_nand: some in...
716
  				ret = nand_read_skip_bad(nand, off, &rwsize,
c39d6a0ea   Tom Rini   nand: Extend nand...
717
  							 NULL, maxsize,
4b0708093   Wolfgang Denk   Coding Style clea...
718
  							 (u_char *)addr);
dfbf617ff   Scott Wood   NAND read/write fix
719
  			else
ea533c260   Scott Wood   cmd_nand: some in...
720
  				ret = nand_write_skip_bad(nand, off, &rwsize,
c39d6a0ea   Tom Rini   nand: Extend nand...
721
  							  NULL, maxsize,
47fc18f1e   Lei Wen   NAND: add the abi...
722
  							  (u_char *)addr, 0);
c9494866d   Ben Gardiner   cmd_nand: add nan...
723
724
725
726
727
728
729
  #ifdef CONFIG_CMD_NAND_TRIMFFS
  		} else if (!strcmp(s, ".trimffs")) {
  			if (read) {
  				printf("Unknown nand command suffix '%s'
  ", s);
  				return 1;
  			}
c39d6a0ea   Tom Rini   nand: Extend nand...
730
731
  			ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
  						maxsize, (u_char *)addr,
c9494866d   Ben Gardiner   cmd_nand: add nan...
732
733
  						WITH_DROP_FFS);
  #endif
47fc18f1e   Lei Wen   NAND: add the abi...
734
735
736
737
738
739
740
  #ifdef CONFIG_CMD_NAND_YAFFS
  		} else if (!strcmp(s, ".yaffs")) {
  			if (read) {
  				printf("Unknown nand command suffix '%s'.
  ", s);
  				return 1;
  			}
c39d6a0ea   Tom Rini   nand: Extend nand...
741
742
  			ret = nand_write_skip_bad(nand, off, &rwsize, NULL,
  						maxsize, (u_char *)addr,
c4df2f410   Tom Rini   cmd_nand.c: Fix C...
743
  						WITH_YAFFS_OOB);
47fc18f1e   Lei Wen   NAND: add the abi...
744
  #endif
dfc99e143   Mike Frysinger   cmd_nand: drop du...
745
  		} else if (!strcmp(s, ".oob")) {
cfa460adf   William Juul   Update MTD to tha...
746
747
748
  			/* out-of-band data */
  			mtd_oob_ops_t ops = {
  				.oobbuf = (u8 *)addr,
ea533c260   Scott Wood   cmd_nand: some in...
749
  				.ooblen = rwsize,
dfe64e2c8   Sergey Lapin   mtd: resync with ...
750
  				.mode = MTD_OPS_RAW
cfa460adf   William Juul   Update MTD to tha...
751
  			};
62d4f4365   Harald Welte   Re-introduce the ...
752
  			if (read)
dfe64e2c8   Sergey Lapin   mtd: resync with ...
753
  				ret = mtd_read_oob(nand, off, &ops);
62d4f4365   Harald Welte   Re-introduce the ...
754
  			else
dfe64e2c8   Sergey Lapin   mtd: resync with ...
755
  				ret = mtd_write_oob(nand, off, &ops);
418396e21   Scott Wood   nand: extend .raw...
756
757
  		} else if (raw) {
  			ret = raw_access(nand, addr, off, pagecount, read);
856f05441   Stefan Roese   [PATCH] NAND: Par...
758
  		} else {
984e03cdf   Scott Wood   NAND: Always skip...
759
760
761
  			printf("Unknown nand command suffix '%s'.
  ", s);
  			return 1;
2255b2d20   Stefan Roese   * Several improve...
762
  		}
ea533c260   Scott Wood   cmd_nand: some in...
763
764
  		printf(" %zu bytes %s: %s
  ", rwsize,
2255b2d20   Stefan Roese   * Several improve...
765
  		       read ? "read" : "written", ret ? "ERROR" : "OK");
addb2e165   Bartlomiej Sieka   Re-factoring the ...
766
767
768
  
  		return ret == 0 ? 0 : 1;
  	}
2255b2d20   Stefan Roese   * Several improve...
769

3287f6d38   Benoît Thébaudeau   nand: Add torture...
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
  #ifdef CONFIG_CMD_NAND_TORTURE
  	if (strcmp(cmd, "torture") == 0) {
  		if (argc < 3)
  			goto usage;
  
  		if (!str2off(argv[2], &off)) {
  			puts("Offset is not a valid number
  ");
  			return 1;
  		}
  
  		printf("
  NAND torture: device %d offset 0x%llx size 0x%x
  ",
  			dev, off, nand->erasesize);
  		ret = nand_torture(nand, off);
  		printf(" %s
  ", ret ? "Failed" : "Passed");
  
  		return ret == 0 ? 0 : 1;
  	}
  #endif
2255b2d20   Stefan Roese   * Several improve...
792
  	if (strcmp(cmd, "markbad") == 0) {
8360b66ba   Wolfgang Denk   nand/onenand: Fix...
793
794
  		argc -= 2;
  		argv += 2;
2255b2d20   Stefan Roese   * Several improve...
795

8360b66ba   Wolfgang Denk   nand/onenand: Fix...
796
797
798
799
800
  		if (argc <= 0)
  			goto usage;
  
  		while (argc > 0) {
  			addr = simple_strtoul(*argv, NULL, 16);
dfe64e2c8   Sergey Lapin   mtd: resync with ...
801
  			if (mtd_block_markbad(nand, addr)) {
8360b66ba   Wolfgang Denk   nand/onenand: Fix...
802
803
804
805
806
807
808
809
810
811
812
813
814
  				printf("block 0x%08lx NOT marked "
  					"as bad! ERROR %d
  ",
  					addr, ret);
  				ret = 1;
  			} else {
  				printf("block 0x%08lx successfully "
  					"marked as bad
  ",
  					addr);
  			}
  			--argc;
  			++argv;
2255b2d20   Stefan Roese   * Several improve...
815
  		}
8360b66ba   Wolfgang Denk   nand/onenand: Fix...
816
  		return ret;
2255b2d20   Stefan Roese   * Several improve...
817
  	}
dfbf617ff   Scott Wood   NAND read/write fix
818

2255b2d20   Stefan Roese   * Several improve...
819
820
821
822
  	if (strcmp(cmd, "biterr") == 0) {
  		/* todo */
  		return 1;
  	}
50657c273   Nishanth Menon   NAND: Enable nand...
823
  #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
2255b2d20   Stefan Roese   * Several improve...
824
  	if (strcmp(cmd, "lock") == 0) {
50657c273   Nishanth Menon   NAND: Enable nand...
825
  		int tight = 0;
2255b2d20   Stefan Roese   * Several improve...
826
827
828
829
830
831
832
  		int status = 0;
  		if (argc == 3) {
  			if (!strcmp("tight", argv[2]))
  				tight = 1;
  			if (!strcmp("status", argv[2]))
  				status = 1;
  		}
2255b2d20   Stefan Roese   * Several improve...
833
  		if (status) {
50657c273   Nishanth Menon   NAND: Enable nand...
834
  			do_nand_status(nand);
cfa460adf   William Juul   Update MTD to tha...
835
  		} else {
5e1dae5c3   William Juul   Fixing coding sty...
836
837
838
839
840
841
842
843
  			if (!nand_lock(nand, tight)) {
  				puts("NAND flash successfully locked
  ");
  			} else {
  				puts("Error locking NAND flash
  ");
  				return 1;
  			}
2255b2d20   Stefan Roese   * Several improve...
844
845
846
  		}
  		return 0;
  	}
eee623a50   Joe Hershberger   nand: Add support...
847
848
849
850
851
852
853
  	if (strncmp(cmd, "unlock", 5) == 0) {
  		int allexcept = 0;
  
  		s = strchr(cmd, '.');
  
  		if (s && !strcmp(s, ".allexcept"))
  			allexcept = 1;
c39d6a0ea   Tom Rini   nand: Extend nand...
854
855
  		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size,
  				 &maxsize) < 0)
856f05441   Stefan Roese   [PATCH] NAND: Par...
856
  			return 1;
2255b2d20   Stefan Roese   * Several improve...
857

eee623a50   Joe Hershberger   nand: Add support...
858
  		if (!nand_unlock(&nand_info[dev], off, size, allexcept)) {
5e1dae5c3   William Juul   Fixing coding sty...
859
860
861
862
  			puts("NAND flash successfully unlocked
  ");
  		} else {
  			puts("Error unlocking NAND flash, "
3043c045d   William Juul   Whitespace cleanu...
863
864
  			     "write and erase will probably fail
  ");
5e1dae5c3   William Juul   Fixing coding sty...
865
866
  			return 1;
  		}
2255b2d20   Stefan Roese   * Several improve...
867
868
  		return 0;
  	}
50657c273   Nishanth Menon   NAND: Enable nand...
869
  #endif
2255b2d20   Stefan Roese   * Several improve...
870

addb2e165   Bartlomiej Sieka   Re-factoring the ...
871
  usage:
4c12eeb8b   Simon Glass   Convert cmd_usage...
872
  	return CMD_RET_USAGE;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
873
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
874
875
  #ifdef CONFIG_SYS_LONGHELP
  static char nand_help_text[] =
a89c33db9   Wolfgang Denk   General help mess...
876
877
878
879
880
881
882
883
884
885
886
887
  	"info - show available NAND devices
  "
  	"nand device [dev] - show or set current device
  "
  	"nand read - addr off|partition size
  "
  	"nand write - addr off|partition size
  "
  	"    read/write 'size' bytes starting at offset 'off'
  "
  	"    to/from memory address 'addr', skipping bad blocks.
  "
418396e21   Scott Wood   nand: extend .raw...
888
889
890
891
892
893
  	"nand read.raw - addr off|partition [count]
  "
  	"nand write.raw - addr off|partition [count]
  "
  	"    Use read.raw/write.raw to avoid ECC and access the flash as-is.
  "
c9494866d   Ben Gardiner   cmd_nand: add nan...
894
895
896
897
898
899
900
901
902
903
  #ifdef CONFIG_CMD_NAND_TRIMFFS
  	"nand write.trimffs - addr off|partition size
  "
  	"    write 'size' bytes starting at offset 'off' from memory address
  "
  	"    'addr', skipping bad blocks and dropping any pages at the end
  "
  	"    of eraseblocks that contain only 0xFF
  "
  #endif
47fc18f1e   Lei Wen   NAND: add the abi...
904
905
906
907
908
909
910
911
  #ifdef CONFIG_CMD_NAND_YAFFS
  	"nand write.yaffs - addr off|partition size
  "
  	"    write 'size' bytes starting at offset 'off' with yaffs format
  "
  	"    from memory address 'addr', skipping bad blocks.
  "
  #endif
eb3abce89   Daniel Hobi   cmd_nand: fix hel...
912
  	"nand erase[.spread] [clean] off size - erase 'size' bytes "
304863225   Scott Wood   nand erase: .spre...
913
914
915
916
917
918
919
920
921
922
  	"from offset 'off'
  "
  	"    With '.spread', erase enough for given file size, otherwise,
  "
  	"    'size' includes skipped bad blocks.
  "
  	"nand erase.part [clean] partition - erase entire mtd partition'
  "
  	"nand erase.chip [clean] - erase entire chip'
  "
a89c33db9   Wolfgang Denk   General help mess...
923
924
925
926
  	"nand bad - show bad blocks
  "
  	"nand dump[.oob] off - dump page
  "
3287f6d38   Benoît Thébaudeau   nand: Add torture...
927
928
929
930
  #ifdef CONFIG_CMD_NAND_TORTURE
  	"nand torture off - torture block at offset
  "
  #endif
608998166   Marek Vasut   NAND: Add -y opti...
931
932
  	"nand scrub [-y] off size | scrub.part partition | scrub.chip
  "
304863225   Scott Wood   nand erase: .spre...
933
934
  	"    really clean NAND erasing bad blocks (UNSAFE)
  "
a89c33db9   Wolfgang Denk   General help mess...
935
936
937
  	"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)
  "
  	"nand biterr off - make a bit error at offset (UNSAFE)"
50657c273   Nishanth Menon   NAND: Enable nand...
938
  #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
a89c33db9   Wolfgang Denk   General help mess...
939
940
941
942
943
944
  	"
  "
  	"nand lock [tight] [status]
  "
  	"    bring nand to lock state or display locked pages
  "
eee623a50   Joe Hershberger   nand: Add support...
945
  	"nand unlock[.allexcept] [offset] [size] - unlock section"
50657c273   Nishanth Menon   NAND: Enable nand...
946
  #endif
c9f7351b5   Ben Gardiner   NAND: environment...
947
948
949
950
951
952
953
954
955
956
  #ifdef CONFIG_ENV_OFFSET_OOB
  	"
  "
  	"nand env.oob - environment offset in OOB of block 0 of"
  	"    first device.
  "
  	"nand env.oob set off|partition - set enviromnent offset
  "
  	"nand env.oob get - get environment offset"
  #endif
088f1b199   Kim Phillips   common/cmd_*.c: s...
957
958
959
960
961
962
  	"";
  #endif
  
  U_BOOT_CMD(
  	nand, CONFIG_SYS_MAXARGS, 1, do_nand,
  	"NAND sub-system", nand_help_text
50657c273   Nishanth Menon   NAND: Enable nand...
963
  );
addb2e165   Bartlomiej Sieka   Re-factoring the ...
964

856f05441   Stefan Roese   [PATCH] NAND: Par...
965
  static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
4b0708093   Wolfgang Denk   Coding Style clea...
966
  			   ulong offset, ulong addr, char *cmd)
addb2e165   Bartlomiej Sieka   Re-factoring the ...
967
  {
addb2e165   Bartlomiej Sieka   Re-factoring the ...
968
  	int r;
67d668bf9   Mike Frysinger   autostart: unify ...
969
  	char *s;
4ca79f477   Wolfgang Denk   NAND: fix some st...
970
  	size_t cnt;
addb2e165   Bartlomiej Sieka   Re-factoring the ...
971
  	image_header_t *hdr;
09475f752   Marian Balakowicz   [new uImage] Add ...
972
  #if defined(CONFIG_FIT)
3bab76a26   Marian Balakowicz   Delay FIT format ...
973
  	const void *fit_hdr = NULL;
09475f752   Marian Balakowicz   [new uImage] Add ...
974
  #endif
10e038932   Thomas Knobloch   [NAND] Bad block ...
975
976
977
  
  	s = strchr(cmd, '.');
  	if (s != NULL &&
65d8bc94d   Scott Wood   NAND: Have nboot ...
978
  	    (strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
984e03cdf   Scott Wood   NAND: Always skip...
979
980
  		printf("Unknown nand load suffix '%s'
  ", s);
770605e4f   Simon Glass   bootstage: Replac...
981
  		bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
984e03cdf   Scott Wood   NAND: Always skip...
982
983
  		return 1;
  	}
addb2e165   Bartlomiej Sieka   Re-factoring the ...
984

856f05441   Stefan Roese   [PATCH] NAND: Par...
985
986
987
  	printf("
  Loading from %s, offset 0x%lx
  ", nand->name, offset);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
988

cfa460adf   William Juul   Update MTD to tha...
989
  	cnt = nand->writesize;
c39d6a0ea   Tom Rini   nand: Extend nand...
990
991
  	r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size,
  			(u_char *)addr);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
992
  	if (r) {
856f05441   Stefan Roese   [PATCH] NAND: Par...
993
994
  		puts("** Read error
  ");
770605e4f   Simon Glass   bootstage: Replac...
995
  		bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
996
997
  		return 1;
  	}
770605e4f   Simon Glass   bootstage: Replac...
998
  	bootstage_mark(BOOTSTAGE_ID_NAND_HDR_READ);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
999

9a4daad0a   Marian Balakowicz   [new uImage] Upda...
1000
  	switch (genimg_get_format ((void *)addr)) {
d5934ad77   Marian Balakowicz   [new uImage] Add ...
1001
1002
  	case IMAGE_FORMAT_LEGACY:
  		hdr = (image_header_t *)addr;
770605e4f   Simon Glass   bootstage: Replac...
1003
  		bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
d5934ad77   Marian Balakowicz   [new uImage] Add ...
1004
  		image_print_contents (hdr);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1005

d5934ad77   Marian Balakowicz   [new uImage] Add ...
1006
1007
1008
1009
  		cnt = image_get_image_size (hdr);
  		break;
  #if defined(CONFIG_FIT)
  	case IMAGE_FORMAT_FIT:
09475f752   Marian Balakowicz   [new uImage] Add ...
1010
  		fit_hdr = (const void *)addr;
09475f752   Marian Balakowicz   [new uImage] Add ...
1011
1012
1013
1014
1015
  		puts ("Fit image detected...
  ");
  
  		cnt = fit_get_size (fit_hdr);
  		break;
d5934ad77   Marian Balakowicz   [new uImage] Add ...
1016
1017
  #endif
  	default:
770605e4f   Simon Glass   bootstage: Replac...
1018
  		bootstage_error(BOOTSTAGE_ID_NAND_TYPE);
d5934ad77   Marian Balakowicz   [new uImage] Add ...
1019
1020
  		puts ("** Unknown image type
  ");
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1021
1022
  		return 1;
  	}
770605e4f   Simon Glass   bootstage: Replac...
1023
  	bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1024

c39d6a0ea   Tom Rini   nand: Extend nand...
1025
1026
  	r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size,
  			(u_char *)addr);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1027
  	if (r) {
856f05441   Stefan Roese   [PATCH] NAND: Par...
1028
1029
  		puts("** Read error
  ");
770605e4f   Simon Glass   bootstage: Replac...
1030
  		bootstage_error(BOOTSTAGE_ID_NAND_READ);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1031
1032
  		return 1;
  	}
770605e4f   Simon Glass   bootstage: Replac...
1033
  	bootstage_mark(BOOTSTAGE_ID_NAND_READ);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1034

09475f752   Marian Balakowicz   [new uImage] Add ...
1035
1036
  #if defined(CONFIG_FIT)
  	/* This cannot be done earlier, we need complete FIT image in RAM first */
3bab76a26   Marian Balakowicz   Delay FIT format ...
1037
1038
  	if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
  		if (!fit_check_format (fit_hdr)) {
770605e4f   Simon Glass   bootstage: Replac...
1039
  			bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ);
3bab76a26   Marian Balakowicz   Delay FIT format ...
1040
1041
1042
1043
  			puts ("** Bad FIT image format
  ");
  			return 1;
  		}
770605e4f   Simon Glass   bootstage: Replac...
1044
  		bootstage_mark(BOOTSTAGE_ID_NAND_FIT_READ_OK);
3bab76a26   Marian Balakowicz   Delay FIT format ...
1045
1046
  		fit_print_contents (fit_hdr);
  	}
09475f752   Marian Balakowicz   [new uImage] Add ...
1047
  #endif
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1048
1049
1050
  	/* Loading ok, update default load address */
  
  	load_addr = addr;
67d668bf9   Mike Frysinger   autostart: unify ...
1051
  	return bootm_maybe_autostart(cmdtp, cmd);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1052
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
1053
1054
  static int do_nandboot(cmd_tbl_t *cmdtp, int flag, int argc,
  		       char * const argv[])
856f05441   Stefan Roese   [PATCH] NAND: Par...
1055
1056
1057
1058
  {
  	char *boot_device = NULL;
  	int idx;
  	ulong addr, offset = 0;
0c8a84916   Ladislav Michl   Separate mtdparts...
1059
  #if defined(CONFIG_CMD_MTDPARTS)
856f05441   Stefan Roese   [PATCH] NAND: Par...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	struct mtd_device *dev;
  	struct part_info *part;
  	u8 pnum;
  
  	if (argc >= 2) {
  		char *p = (argc == 2) ? argv[1] : argv[2];
  		if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
  		    (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
  			if (dev->id->type != MTD_DEV_TYPE_NAND) {
  				puts("Not a NAND device
  ");
  				return 1;
  			}
  			if (argc > 3)
  				goto usage;
  			if (argc == 3)
10e038932   Thomas Knobloch   [NAND] Bad block ...
1076
  				addr = simple_strtoul(argv[1], NULL, 16);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1077
  			else
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1078
  				addr = CONFIG_SYS_LOAD_ADDR;
856f05441   Stefan Roese   [PATCH] NAND: Par...
1079
  			return nand_load_image(cmdtp, &nand_info[dev->id->num],
4b0708093   Wolfgang Denk   Coding Style clea...
1080
  					       part->offset, addr, argv[0]);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1081
1082
1083
  		}
  	}
  #endif
770605e4f   Simon Glass   bootstage: Replac...
1084
  	bootstage_mark(BOOTSTAGE_ID_NAND_PART);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1085
1086
  	switch (argc) {
  	case 1:
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1087
  		addr = CONFIG_SYS_LOAD_ADDR;
856f05441   Stefan Roese   [PATCH] NAND: Par...
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  		boot_device = getenv("bootdevice");
  		break;
  	case 2:
  		addr = simple_strtoul(argv[1], NULL, 16);
  		boot_device = getenv("bootdevice");
  		break;
  	case 3:
  		addr = simple_strtoul(argv[1], NULL, 16);
  		boot_device = argv[2];
  		break;
  	case 4:
  		addr = simple_strtoul(argv[1], NULL, 16);
  		boot_device = argv[2];
  		offset = simple_strtoul(argv[3], NULL, 16);
  		break;
  	default:
0c8a84916   Ladislav Michl   Separate mtdparts...
1104
  #if defined(CONFIG_CMD_MTDPARTS)
856f05441   Stefan Roese   [PATCH] NAND: Par...
1105
1106
  usage:
  #endif
770605e4f   Simon Glass   bootstage: Replac...
1107
  		bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
4c12eeb8b   Simon Glass   Convert cmd_usage...
1108
  		return CMD_RET_USAGE;
856f05441   Stefan Roese   [PATCH] NAND: Par...
1109
  	}
770605e4f   Simon Glass   bootstage: Replac...
1110
  	bootstage_mark(BOOTSTAGE_ID_NAND_SUFFIX);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1111
1112
1113
1114
1115
  
  	if (!boot_device) {
  		puts("
  ** No boot device **
  ");
770605e4f   Simon Glass   bootstage: Replac...
1116
  		bootstage_error(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1117
1118
  		return 1;
  	}
770605e4f   Simon Glass   bootstage: Replac...
1119
  	bootstage_mark(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
addb2e165   Bartlomiej Sieka   Re-factoring the ...
1120

856f05441   Stefan Roese   [PATCH] NAND: Par...
1121
  	idx = simple_strtoul(boot_device, NULL, 16);
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1122
  	if (idx < 0 || idx >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[idx].name) {
856f05441   Stefan Roese   [PATCH] NAND: Par...
1123
1124
1125
  		printf("
  ** Device %d not available
  ", idx);
770605e4f   Simon Glass   bootstage: Replac...
1126
  		bootstage_error(BOOTSTAGE_ID_NAND_AVAILABLE);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1127
1128
  		return 1;
  	}
770605e4f   Simon Glass   bootstage: Replac...
1129
  	bootstage_mark(BOOTSTAGE_ID_NAND_AVAILABLE);
856f05441   Stefan Roese   [PATCH] NAND: Par...
1130
1131
1132
1133
1134
  
  	return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
  }
  
  U_BOOT_CMD(nboot, 4, 1, do_nandboot,
2fb2604d5   Peter Tyser   Command usage cle...
1135
  	"boot from NAND device",
a89c33db9   Wolfgang Denk   General help mess...
1136
1137
  	"[partition] | [[[loadAddr] dev] offset]"
  );