Blame view

cmd/onenand.c 12.7 KB
d7e8ce101   Kyungmin Park   OneNAND support (...
1
2
3
  /*
   *  U-Boot command for OneNAND support
   *
c438ea175   Stefan Roese   OneNAND: Bad bloc...
4
   *  Copyright (C) 2005-2008 Samsung Electronics
d7e8ce101   Kyungmin Park   OneNAND support (...
5
6
7
8
9
10
11
12
13
   *  Kyungmin Park <kyungmin.park@samsung.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <common.h>
  #include <command.h>
c438ea175   Stefan Roese   OneNAND: Bad bloc...
14
  #include <malloc.h>
d7e8ce101   Kyungmin Park   OneNAND support (...
15

7b15e2bb9   Mike Frysinger   linux/compat.h: r...
16
  #include <linux/compat.h>
d7e8ce101   Kyungmin Park   OneNAND support (...
17
18
19
20
  #include <linux/mtd/mtd.h>
  #include <linux/mtd/onenand.h>
  
  #include <asm/io.h>
c438ea175   Stefan Roese   OneNAND: Bad bloc...
21
22
23
24
  static struct mtd_info *mtd;
  
  static loff_t next_ofs;
  static loff_t skip_ofs;
09c328075   Heiko Schocher   mtd, nand: Move c...
25
26
  static int arg_off_size_onenand(int argc, char * const argv[], ulong *off,
  				size_t *size)
c438ea175   Stefan Roese   OneNAND: Bad bloc...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  {
  	if (argc >= 1) {
  		if (!(str2long(argv[0], off))) {
  			printf("'%s' is not a number
  ", argv[0]);
  			return -1;
  		}
  	} else {
  		*off = 0;
  	}
  
  	if (argc >= 2) {
  		if (!(str2long(argv[1], (ulong *)size))) {
  			printf("'%s' is not a number
  ", argv[1]);
  			return -1;
  		}
  	} else {
  		*size = mtd->size - *off;
  	}
  
  	if ((*off + *size) > mtd->size) {
8d2effea2   Stefan Roese   mtd: Update MTD i...
49
50
  		printf("total chip size (0x%llx) exceeded!
  ", mtd->size);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  		return -1;
  	}
  
  	if (*size == mtd->size)
  		puts("whole chip
  ");
  	else
  		printf("offset 0x%lx, size 0x%x
  ", *off, *size);
  
  	return 0;
  }
  
  static int onenand_block_read(loff_t from, size_t len,
  			      size_t *retlen, u_char *buf, int oob)
  {
  	struct onenand_chip *this = mtd->priv;
  	int blocks = (int) len >> this->erase_shift;
  	int blocksize = (1 << this->erase_shift);
  	loff_t ofs = from;
  	struct mtd_oob_ops ops = {
  		.retlen		= 0,
  	};
  	int ret;
  
  	if (oob)
  		ops.ooblen = blocksize;
  	else
  		ops.len = blocksize;
  
  	while (blocks) {
dfe64e2c8   Sergey Lapin   mtd: resync with ...
82
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  		if (ret) {
  			printk("Bad blocks %d at 0x%x
  ",
  			       (u32)(ofs >> this->erase_shift), (u32)ofs);
  			ofs += blocksize;
  			continue;
  		}
  
  		if (oob)
  			ops.oobbuf = buf;
  		else
  			ops.datbuf = buf;
  
  		ops.retlen = 0;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
97
  		ret = mtd_read_oob(mtd, ofs, &ops);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  		if (ret) {
  			printk("Read failed 0x%x, %d
  ", (u32)ofs, ret);
  			ofs += blocksize;
  			continue;
  		}
  		ofs += blocksize;
  		buf += blocksize;
  		blocks--;
  		*retlen += ops.retlen;
  	}
  
  	return 0;
  }
41c862405   Lei Wen   onenand: add yaff...
112
113
114
115
116
117
  static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf,
  					  size_t *retlen)
  {
  	struct mtd_oob_ops ops = {
  		.len = mtd->writesize,
  		.ooblen = mtd->oobsize,
dfe64e2c8   Sergey Lapin   mtd: resync with ...
118
  		.mode = MTD_OPS_AUTO_OOB,
41c862405   Lei Wen   onenand: add yaff...
119
120
121
122
123
124
125
  	};
  	int page, ret = 0;
  	for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) {
  		ops.datbuf = (u_char *)buf;
  		buf += mtd->writesize;
  		ops.oobbuf = (u_char *)buf;
  		buf += mtd->oobsize;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
126
  		ret = mtd_write_oob(mtd, to, &ops);
41c862405   Lei Wen   onenand: add yaff...
127
128
129
130
131
132
133
134
  		if (ret)
  			break;
  		to += mtd->writesize;
  	}
  
  	*retlen = (ret) ? 0 : mtd->erasesize;
  	return ret;
  }
c438ea175   Stefan Roese   OneNAND: Bad bloc...
135
  static int onenand_block_write(loff_t to, size_t len,
41c862405   Lei Wen   onenand: add yaff...
136
  			       size_t *retlen, const u_char * buf, int withoob)
c438ea175   Stefan Roese   OneNAND: Bad bloc...
137
138
139
140
141
142
143
  {
  	struct onenand_chip *this = mtd->priv;
  	int blocks = len >> this->erase_shift;
  	int blocksize = (1 << this->erase_shift);
  	loff_t ofs;
  	size_t _retlen = 0;
  	int ret;
9c00d982f   Ladislav Michl   cmd/onenand.c: bl...
144
145
146
147
148
149
  	if ((to & (mtd->writesize - 1)) != 0) {
  		printf("Attempt to write non block-aligned data
  ");
  		*retlen = 0;
  		return 1;
  	}
c438ea175   Stefan Roese   OneNAND: Bad bloc...
150
151
152
153
154
155
156
157
158
159
  	if (to == next_ofs) {
  		next_ofs = to + len;
  		to += skip_ofs;
  	} else {
  		next_ofs = to + len;
  		skip_ofs = 0;
  	}
  	ofs = to;
  
  	while (blocks) {
dfe64e2c8   Sergey Lapin   mtd: resync with ...
160
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
161
162
163
164
165
166
167
  		if (ret) {
  			printk("Bad blocks %d at 0x%x
  ",
  			       (u32)(ofs >> this->erase_shift), (u32)ofs);
  			skip_ofs += blocksize;
  			goto next;
  		}
41c862405   Lei Wen   onenand: add yaff...
168
  		if (!withoob)
dfe64e2c8   Sergey Lapin   mtd: resync with ...
169
  			ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf);
41c862405   Lei Wen   onenand: add yaff...
170
171
  		else
  			ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  		if (ret) {
  			printk("Write failed 0x%x, %d", (u32)ofs, ret);
  			skip_ofs += blocksize;
  			goto next;
  		}
  
  		buf += blocksize;
  		blocks--;
  		*retlen += _retlen;
  next:
  		ofs += blocksize;
  	}
  
  	return 0;
  }
  
  static int onenand_block_erase(u32 start, u32 size, int force)
  {
  	struct onenand_chip *this = mtd->priv;
  	struct erase_info instr = {
  		.callback	= NULL,
  	};
  	loff_t ofs;
  	int ret;
  	int blocksize = 1 << this->erase_shift;
  
  	for (ofs = start; ofs < (start + size); ofs += blocksize) {
dfe64e2c8   Sergey Lapin   mtd: resync with ...
199
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
200
201
202
203
204
205
206
207
208
209
210
  		if (ret && !force) {
  			printf("Skip erase bad block %d at 0x%x
  ",
  			       (u32)(ofs >> this->erase_shift), (u32)ofs);
  			continue;
  		}
  
  		instr.addr = ofs;
  		instr.len = blocksize;
  		instr.priv = force;
  		instr.mtd = mtd;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
211
  		ret = mtd_erase(mtd, &instr);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  		if (ret) {
  			printf("erase failed block %d at 0x%x
  ",
  			       (u32)(ofs >> this->erase_shift), (u32)ofs);
  			continue;
  		}
  	}
  
  	return 0;
  }
  
  static int onenand_block_test(u32 start, u32 size)
  {
  	struct onenand_chip *this = mtd->priv;
  	struct erase_info instr = {
  		.callback	= NULL,
  		.priv		= 0,
  	};
  
  	int blocks;
  	loff_t ofs;
  	int blocksize = 1 << this->erase_shift;
  	int start_block, end_block;
  	size_t retlen;
  	u_char *buf;
  	u_char *verify_buf;
  	int ret;
  
  	buf = malloc(blocksize);
  	if (!buf) {
  		printf("Not enough malloc space available!
  ");
  		return -1;
  	}
  
  	verify_buf = malloc(blocksize);
  	if (!verify_buf) {
  		printf("Not enough malloc space available!
  ");
  		return -1;
  	}
  
  	start_block = start >> this->erase_shift;
  	end_block = (start + size) >> this->erase_shift;
  
  	/* Protect boot-loader from badblock testing */
  	if (start_block < 2)
  		start_block = 2;
  
  	if (end_block > (mtd->size >> this->erase_shift))
  		end_block = mtd->size >> this->erase_shift;
  
  	blocks = start_block;
  	ofs = start;
  	while (blocks < end_block) {
  		printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs);
dfe64e2c8   Sergey Lapin   mtd: resync with ...
268
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
269
270
271
272
273
274
275
276
277
  		if (ret) {
  			printf("Skip erase bad block %d at 0x%x
  ",
  			       (u32)(ofs >> this->erase_shift), (u32)ofs);
  			goto next;
  		}
  
  		instr.addr = ofs;
  		instr.len = blocksize;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
278
  		ret = mtd_erase(mtd, &instr);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
279
280
281
282
283
  		if (ret) {
  			printk("Erase failed 0x%x, %d
  ", (u32)ofs, ret);
  			goto next;
  		}
dfe64e2c8   Sergey Lapin   mtd: resync with ...
284
  		ret = mtd_write(mtd, ofs, blocksize, &retlen, buf);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
285
286
287
288
289
  		if (ret) {
  			printk("Write failed 0x%x, %d
  ", (u32)ofs, ret);
  			goto next;
  		}
dfe64e2c8   Sergey Lapin   mtd: resync with ...
290
  		ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  		if (ret) {
  			printk("Read failed 0x%x, %d
  ", (u32)ofs, ret);
  			goto next;
  		}
  
  		if (memcmp(buf, verify_buf, blocksize))
  			printk("
  Read/Write test failed at 0x%x
  ", (u32)ofs);
  
  next:
  		ofs += blocksize;
  		blocks++;
  	}
  	printf("...Done
  ");
  
  	free(buf);
  	free(verify_buf);
  
  	return 0;
  }
  
  static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob)
  {
  	int i;
  	u_char *datbuf, *oobbuf, *p;
  	struct mtd_oob_ops ops;
  	loff_t addr;
  
  	datbuf = malloc(mtd->writesize + mtd->oobsize);
  	oobbuf = malloc(mtd->oobsize);
  	if (!datbuf || !oobbuf) {
  		puts("No memory for page buffer
  ");
  		return 1;
  	}
  	off &= ~(mtd->writesize - 1);
  	addr = (loff_t) off;
  	memset(&ops, 0, sizeof(ops));
  	ops.datbuf = datbuf;
a430b137e   Lei Wen   onenand: fix oob ...
333
  	ops.oobbuf = oobbuf;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
334
335
336
  	ops.len = mtd->writesize;
  	ops.ooblen = mtd->oobsize;
  	ops.retlen = 0;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
337
  	i = mtd_read_oob(mtd, addr, &ops);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  	if (i < 0) {
  		printf("Error (%d) reading page %08lx
  ", i, off);
  		free(datbuf);
  		free(oobbuf);
  		return 1;
  	}
  	printf("Page %08lx dump:
  ", off);
  	i = mtd->writesize >> 4;
  	p = datbuf;
  
  	while (i--) {
  		if (!only_oob)
  			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],
  			       p[8], p[9], p[10], p[11], p[12], p[13], p[14],
  			       p[15]);
  		p += 16;
  	}
  	puts("OOB:
  ");
  	i = mtd->oobsize >> 3;
a430b137e   Lei Wen   onenand: fix oob ...
363
  	p = oobbuf;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
364
365
366
367
368
369
370
371
372
373
374
  	while (i--) {
  		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]);
  		p += 8;
  	}
  	free(datbuf);
  	free(oobbuf);
  
  	return 0;
  }
d7e8ce101   Kyungmin Park   OneNAND support (...
375

54841ab50   Wolfgang Denk   Make sure that ar...
376
  static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
d7e8ce101   Kyungmin Park   OneNAND support (...
377
  {
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
378
379
380
381
  	printf("%s
  ", mtd->name);
  	return 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
382
  static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
383
384
385
386
387
388
389
390
391
  {
  	ulong ofs;
  
  	mtd = &onenand_mtd;
  	/* Currently only one OneNAND device is supported */
  	printf("
  Device %d bad blocks:
  ", 0);
  	for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) {
dfe64e2c8   Sergey Lapin   mtd: resync with ...
392
  		if (mtd_block_isbad(mtd, ofs))
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
393
394
395
396
397
398
  			printf("  %08x
  ", (u32)ofs);
  	}
  
  	return 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
399
  static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
400
401
402
  {
  	char *s;
  	int oob = 0;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
403
  	ulong addr, ofs;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
404
  	size_t len;
8360b66ba   Wolfgang Denk   nand/onenand: Fix...
405
  	int ret = 0;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
406
  	size_t retlen = 0;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
407

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
408
  	if (argc < 3)
4c12eeb8b   Simon Glass   Convert cmd_usage...
409
  		return CMD_RET_USAGE;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
410

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
411
412
413
  	s = strchr(argv[0], '.');
  	if ((s != NULL) && (!strcmp(s, ".oob")))
  		oob = 1;
d7e8ce101   Kyungmin Park   OneNAND support (...
414

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
415
  	addr = (ulong)simple_strtoul(argv[1], NULL, 16);
d7e8ce101   Kyungmin Park   OneNAND support (...
416

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
417
418
  	printf("
  OneNAND read: ");
09c328075   Heiko Schocher   mtd, nand: Move c...
419
  	if (arg_off_size_onenand(argc - 2, argv + 2, &ofs, &len) != 0)
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
420
  		return 1;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
421

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
422
  	ret = onenand_block_read(ofs, len, &retlen, (u8 *)addr, oob);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
423

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
424
425
  	printf(" %d bytes read: %s
  ", retlen, ret ? "ERROR" : "OK");
d7e8ce101   Kyungmin Park   OneNAND support (...
426

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
427
428
  	return ret == 0 ? 0 : 1;
  }
a9da2b410   Kyungmin Park   Fix OneNAND erase...
429

54841ab50   Wolfgang Denk   Make sure that ar...
430
  static int do_onenand_write(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
431
432
433
  {
  	ulong addr, ofs;
  	size_t len;
41c862405   Lei Wen   onenand: add yaff...
434
  	int ret = 0, withoob = 0;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
435
  	size_t retlen = 0;
d7e8ce101   Kyungmin Park   OneNAND support (...
436

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
437
  	if (argc < 3)
4c12eeb8b   Simon Glass   Convert cmd_usage...
438
  		return CMD_RET_USAGE;
d7e8ce101   Kyungmin Park   OneNAND support (...
439

41c862405   Lei Wen   onenand: add yaff...
440
441
  	if (strncmp(argv[0] + 6, "yaffs", 5) == 0)
  		withoob = 1;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
442
443
444
445
  	addr = (ulong)simple_strtoul(argv[1], NULL, 16);
  
  	printf("
  OneNAND write: ");
09c328075   Heiko Schocher   mtd, nand: Move c...
446
  	if (arg_off_size_onenand(argc - 2, argv + 2, &ofs, &len) != 0)
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
447
  		return 1;
d7e8ce101   Kyungmin Park   OneNAND support (...
448

41c862405   Lei Wen   onenand: add yaff...
449
  	ret = onenand_block_write(ofs, len, &retlen, (u8 *)addr, withoob);
d7e8ce101   Kyungmin Park   OneNAND support (...
450

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
451
452
  	printf(" %d bytes written: %s
  ", retlen, ret ? "ERROR" : "OK");
c438ea175   Stefan Roese   OneNAND: Bad bloc...
453

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
454
455
  	return ret == 0 ? 0 : 1;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
456
  static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  {
  	ulong ofs;
  	int ret = 0;
  	size_t len;
  	int force;
  
  	/*
  	 * Syntax is:
  	 *   0       1     2       3    4
  	 *   onenand erase [force] [off size]
  	 */
  	argc--;
  	argv++;
  	if (argc)
  	{
  		if (!strcmp("force", argv[0]))
  		{
  			force = 1;
  			argc--;
  			argv++;
d7e8ce101   Kyungmin Park   OneNAND support (...
477
  		}
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
478
479
480
  	}
  	printf("
  OneNAND erase: ");
d7e8ce101   Kyungmin Park   OneNAND support (...
481

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
482
  	/* skip first two or three arguments, look for offset and size */
09c328075   Heiko Schocher   mtd, nand: Move c...
483
  	if (arg_off_size_onenand(argc, argv, &ofs, &len) != 0)
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
484
  		return 1;
bfd7f3861   Kyungmin Park   Fix OneNAND read_...
485

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
486
  	ret = onenand_block_erase(ofs, len, force);
bfd7f3861   Kyungmin Park   Fix OneNAND read_...
487

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
488
489
  	printf("%s
  ", ret ? "ERROR" : "OK");
d7e8ce101   Kyungmin Park   OneNAND support (...
490

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
491
492
  	return ret == 0 ? 0 : 1;
  }
d7e8ce101   Kyungmin Park   OneNAND support (...
493

54841ab50   Wolfgang Denk   Make sure that ar...
494
  static int do_onenand_test(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
495
496
497
498
  {
  	ulong ofs;
  	int ret = 0;
  	size_t len;
d7e8ce101   Kyungmin Park   OneNAND support (...
499

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
500
501
502
503
504
  	/*
  	 * Syntax is:
  	 *   0       1     2       3    4
  	 *   onenand test [force] [off size]
  	 */
d7e8ce101   Kyungmin Park   OneNAND support (...
505

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
506
507
  	printf("
  OneNAND test: ");
d7e8ce101   Kyungmin Park   OneNAND support (...
508

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
509
  	/* skip first two or three arguments, look for offset and size */
09c328075   Heiko Schocher   mtd, nand: Move c...
510
  	if (arg_off_size_onenand(argc - 1, argv + 1, &ofs, &len) != 0)
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
511
  		return 1;
d7e8ce101   Kyungmin Park   OneNAND support (...
512

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
513
  	ret = onenand_block_test(ofs, len);
d7e8ce101   Kyungmin Park   OneNAND support (...
514

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
515
516
  	printf("%s
  ", ret ? "ERROR" : "OK");
d7e8ce101   Kyungmin Park   OneNAND support (...
517

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
518
519
  	return ret == 0 ? 0 : 1;
  }
bfd7f3861   Kyungmin Park   Fix OneNAND read_...
520

54841ab50   Wolfgang Denk   Make sure that ar...
521
  static int do_onenand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
522
523
524
525
  {
  	ulong ofs;
  	int ret = 0;
  	char *s;
d7e8ce101   Kyungmin Park   OneNAND support (...
526

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
527
  	if (argc < 2)
4c12eeb8b   Simon Glass   Convert cmd_usage...
528
  		return CMD_RET_USAGE;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
529
530
531
532
533
534
535
536
  
  	s = strchr(argv[0], '.');
  	ofs = (int)simple_strtoul(argv[1], NULL, 16);
  
  	if (s != NULL && strcmp(s, ".oob") == 0)
  		ret = onenand_dump(mtd, ofs, 1);
  	else
  		ret = onenand_dump(mtd, ofs, 0);
d7e8ce101   Kyungmin Park   OneNAND support (...
537

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
538
539
  	return ret == 0 ? 1 : 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
540
  static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
541
542
543
544
545
546
547
548
  {
  	int ret = 0;
  	ulong addr;
  
  	argc -= 2;
  	argv += 2;
  
  	if (argc <= 0)
4c12eeb8b   Simon Glass   Convert cmd_usage...
549
  		return CMD_RET_USAGE;
d7e8ce101   Kyungmin Park   OneNAND support (...
550

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
551
552
  	while (argc > 0) {
  		addr = simple_strtoul(*argv, NULL, 16);
dfe64e2c8   Sergey Lapin   mtd: resync with ...
553
  		if (mtd_block_markbad(mtd, addr)) {
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  			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;
  	}
  	return ret;
  }
  
  static cmd_tbl_t cmd_onenand_sub[] = {
  	U_BOOT_CMD_MKENT(info, 1, 0, do_onenand_info, "", ""),
  	U_BOOT_CMD_MKENT(bad, 1, 0, do_onenand_bad, "", ""),
  	U_BOOT_CMD_MKENT(read, 4, 0, do_onenand_read, "", ""),
  	U_BOOT_CMD_MKENT(write, 4, 0, do_onenand_write, "", ""),
41c862405   Lei Wen   onenand: add yaff...
576
  	U_BOOT_CMD_MKENT(write.yaffs, 4, 0, do_onenand_write, "", ""),
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
577
578
579
580
581
  	U_BOOT_CMD_MKENT(erase, 3, 0, do_onenand_erase, "", ""),
  	U_BOOT_CMD_MKENT(test, 3, 0, do_onenand_test, "", ""),
  	U_BOOT_CMD_MKENT(dump, 2, 0, do_onenand_dump, "", ""),
  	U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 0, do_onenand_markbad, "", ""),
  };
2e5167cca   Wolfgang Denk   Replace CONFIG_RE...
582
  #ifdef CONFIG_NEEDS_MANUAL_RELOC
cdb1d4f97   Enric Balletbo i Serra   ARM: fix relocati...
583
584
585
586
  void onenand_reloc(void) {
  	fixup_cmdtable(cmd_onenand_sub, ARRAY_SIZE(cmd_onenand_sub));
  }
  #endif
54841ab50   Wolfgang Denk   Make sure that ar...
587
  static int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
588
589
  {
  	cmd_tbl_t *c;
57ff9f242   Enric Balletbo i Serra   cmd_onenand.c: Fi...
590
  	if (argc < 2)
4c12eeb8b   Simon Glass   Convert cmd_usage...
591
  		return CMD_RET_USAGE;
57ff9f242   Enric Balletbo i Serra   cmd_onenand.c: Fi...
592

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
593
594
595
596
597
  	mtd = &onenand_mtd;
  
  	/* Strip off leading 'onenand' command argument */
  	argc--;
  	argv++;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
598

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
599
  	c = find_cmd_tbl(argv[0], &cmd_onenand_sub[0], ARRAY_SIZE(cmd_onenand_sub));
47e26b1bf   Wolfgang Denk   cmd_usage(): simp...
600
601
602
  	if (c)
  		return c->cmd(cmdtp, flag, argc, argv);
  	else
4c12eeb8b   Simon Glass   Convert cmd_usage...
603
  		return CMD_RET_USAGE;
d7e8ce101   Kyungmin Park   OneNAND support (...
604
605
606
  }
  
  U_BOOT_CMD(
8360b66ba   Wolfgang Denk   nand/onenand: Fix...
607
  	onenand,	CONFIG_SYS_MAXARGS,	1,	do_onenand,
2fb2604d5   Peter Tyser   Command usage cle...
608
  	"OneNAND sub-system",
c438ea175   Stefan Roese   OneNAND: Bad bloc...
609
610
611
612
613
614
  	"info - show available OneNAND devices
  "
  	"onenand bad - show bad blocks
  "
  	"onenand read[.oob] addr off size
  "
41c862405   Lei Wen   onenand: add yaff...
615
616
  	"onenand write[.yaffs] addr off size
  "
c438ea175   Stefan Roese   OneNAND: Bad bloc...
617
618
619
620
621
622
623
624
625
626
627
628
  	"    read/write 'size' bytes starting at offset 'off'
  "
  	"    to/from memory address 'addr', skipping bad blocks.
  "
  	"onenand erase [force] [off size] - erase 'size' bytes from
  "
  	"onenand test [off size] - test 'size' bytes from
  "
  	"    offset 'off' (entire device if not specified)
  "
  	"onenand dump[.oob] off - dump page
  "
a89c33db9   Wolfgang Denk   General help mess...
629
  	"onenand markbad off [...] - mark bad block(s) at offset (UNSAFE)"
d7e8ce101   Kyungmin Park   OneNAND support (...
630
  );