Blame view

common/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
25
26
27
28
29
30
31
32
  static struct mtd_info *mtd;
  
  static loff_t next_ofs;
  static loff_t skip_ofs;
  
  static inline int str2long(char *p, ulong *num)
  {
  	char *endptr;
  
  	*num = simple_strtoul(p, &endptr, 16);
  	return (*p != '\0' && *endptr == '\0') ? 1 : 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
33
  static int arg_off_size(int argc, char * const argv[], ulong *off, size_t *size)
c438ea175   Stefan Roese   OneNAND: Bad bloc...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  {
  	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...
56
57
  		printf("total chip size (0x%llx) exceeded!
  ", mtd->size);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  		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 ...
89
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  		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 ...
104
  		ret = mtd_read_oob(mtd, ofs, &ops);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  		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...
119
120
121
122
123
124
  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 ...
125
  		.mode = MTD_OPS_AUTO_OOB,
41c862405   Lei Wen   onenand: add yaff...
126
127
128
129
130
131
132
  	};
  	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 ...
133
  		ret = mtd_write_oob(mtd, to, &ops);
41c862405   Lei Wen   onenand: add yaff...
134
135
136
137
138
139
140
141
  		if (ret)
  			break;
  		to += mtd->writesize;
  	}
  
  	*retlen = (ret) ? 0 : mtd->erasesize;
  	return ret;
  }
c438ea175   Stefan Roese   OneNAND: Bad bloc...
142
  static int onenand_block_write(loff_t to, size_t len,
41c862405   Lei Wen   onenand: add yaff...
143
  			       size_t *retlen, const u_char * buf, int withoob)
c438ea175   Stefan Roese   OneNAND: Bad bloc...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  {
  	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;
  
  	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 ...
162
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
163
164
165
166
167
168
169
  		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...
170
  		if (!withoob)
dfe64e2c8   Sergey Lapin   mtd: resync with ...
171
  			ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf);
41c862405   Lei Wen   onenand: add yaff...
172
173
  		else
  			ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
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
199
200
  		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 ...
201
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
202
203
204
205
206
207
208
209
210
211
212
  		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 ...
213
  		ret = mtd_erase(mtd, &instr);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
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
268
269
  		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 ...
270
  		ret = mtd_block_isbad(mtd, ofs);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
271
272
273
274
275
276
277
278
279
  		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 ...
280
  		ret = mtd_erase(mtd, &instr);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
281
282
283
284
285
  		if (ret) {
  			printk("Erase failed 0x%x, %d
  ", (u32)ofs, ret);
  			goto next;
  		}
dfe64e2c8   Sergey Lapin   mtd: resync with ...
286
  		ret = mtd_write(mtd, ofs, blocksize, &retlen, buf);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
287
288
289
290
291
  		if (ret) {
  			printk("Write failed 0x%x, %d
  ", (u32)ofs, ret);
  			goto next;
  		}
dfe64e2c8   Sergey Lapin   mtd: resync with ...
292
  		ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
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
333
334
  		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 ...
335
  	ops.oobbuf = oobbuf;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
336
337
338
  	ops.len = mtd->writesize;
  	ops.ooblen = mtd->oobsize;
  	ops.retlen = 0;
dfe64e2c8   Sergey Lapin   mtd: resync with ...
339
  	i = mtd_read_oob(mtd, addr, &ops);
c438ea175   Stefan Roese   OneNAND: Bad bloc...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  	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 ...
365
  	p = oobbuf;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
366
367
368
369
370
371
372
373
374
375
376
  	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 (...
377

54841ab50   Wolfgang Denk   Make sure that ar...
378
  static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
d7e8ce101   Kyungmin Park   OneNAND support (...
379
  {
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
380
381
382
383
  	printf("%s
  ", mtd->name);
  	return 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
384
  static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
385
386
387
388
389
390
391
392
393
  {
  	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 ...
394
  		if (mtd_block_isbad(mtd, ofs))
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
395
396
397
398
399
400
  			printf("  %08x
  ", (u32)ofs);
  	}
  
  	return 0;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
401
  static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
402
403
404
  {
  	char *s;
  	int oob = 0;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
405
  	ulong addr, ofs;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
406
  	size_t len;
8360b66ba   Wolfgang Denk   nand/onenand: Fix...
407
  	int ret = 0;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
408
  	size_t retlen = 0;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
409

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

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

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

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
419
420
421
422
  	printf("
  OneNAND read: ");
  	if (arg_off_size(argc - 2, argv + 2, &ofs, &len) != 0)
  		return 1;
c438ea175   Stefan Roese   OneNAND: Bad bloc...
423

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

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

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

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

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

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

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

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

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
456
457
  	return ret == 0 ? 0 : 1;
  }
54841ab50   Wolfgang Denk   Make sure that ar...
458
  static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  {
  	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 (...
479
  		}
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
480
481
482
  	}
  	printf("
  OneNAND erase: ");
d7e8ce101   Kyungmin Park   OneNAND support (...
483

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
484
485
486
  	/* skip first two or three arguments, look for offset and size */
  	if (arg_off_size(argc, argv, &ofs, &len) != 0)
  		return 1;
bfd7f3861   Kyungmin Park   Fix OneNAND read_...
487

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

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

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

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

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

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

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
511
512
513
  	/* skip first two or three arguments, look for offset and size */
  	if (arg_off_size(argc - 1, argv + 1, &ofs, &len) != 0)
  		return 1;
d7e8ce101   Kyungmin Park   OneNAND support (...
514

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

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

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

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

8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
529
  	if (argc < 2)
4c12eeb8b   Simon Glass   Convert cmd_usage...
530
  		return CMD_RET_USAGE;
8cd852824   Frans Meulenbroeks   cmd_onenand.c: mo...
531
532
533
534
535
536
537
538
  
  	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 (...
539

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

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

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

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