blob: 8d87b787f0facbfc0b646cf2f0c9bdb93c304b95 [file] [log] [blame]
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +09001/*
2 * U-Boot command for OneNAND support
3 *
4 * Copyright (C) 2005-2007 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <common.h>
13#include <command.h>
14
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090015#include <linux/mtd/compat.h>
16#include <linux/mtd/mtd.h>
17#include <linux/mtd/onenand.h>
18
19#include <asm/io.h>
20
21extern struct mtd_info onenand_mtd;
22extern struct onenand_chip onenand_chip;
23
24int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
25{
26 int ret = 0;
27
28 switch (argc) {
29 case 0:
30 case 1:
31 printf("Usage:\n%s\n", cmdtp->usage);
32 return 1;
33
34 case 2:
35 if (strncmp(argv[1], "open", 4) == 0) {
36 onenand_init();
37 return 0;
38 }
Fathi BOUDRA195ccfc2008-08-06 10:06:20 +020039 printf("%s\n", onenand_mtd.name);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090040 return 0;
41
42 default:
43 /* At least 4 args */
44 if (strncmp(argv[1], "erase", 5) == 0) {
Kyungmin Parka9da2b42008-03-31 10:40:19 +090045 struct erase_info instr = {
46 .callback = NULL,
47 };
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090048 ulong start, end;
49 ulong block;
Kyungmin Parka9da2b42008-03-31 10:40:19 +090050 char *endtail;
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090051
Kyungmin Parka9da2b42008-03-31 10:40:19 +090052 if (strncmp(argv[2], "block", 5) == 0) {
53 start = simple_strtoul(argv[3], NULL, 10);
54 endtail = strchr(argv[3], '-');
55 end = simple_strtoul(endtail + 1, NULL, 10);
56 } else {
57 start = simple_strtoul(argv[2], NULL, 10);
58 end = simple_strtoul(argv[3], NULL, 10);
Kyungmin Parka9da2b42008-03-31 10:40:19 +090059
60 start >>= onenand_chip.erase_shift;
61 end >>= onenand_chip.erase_shift;
62 /* Don't include the end block */
63 end--;
64 }
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090065
66 if (!end || end < 0)
67 end = start;
68
Jean-Christophe PLAGNIOL-VILLARD0a5676b2008-07-12 14:36:34 +020069 printf("Erase block from %lu to %lu\n", start, end);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090070
71 for (block = start; block <= end; block++) {
72 instr.addr = block << onenand_chip.erase_shift;
73 instr.len = 1 << onenand_chip.erase_shift;
74 ret = onenand_erase(&onenand_mtd, &instr);
75 if (ret) {
Jean-Christophe PLAGNIOL-VILLARD0a5676b2008-07-12 14:36:34 +020076 printf("erase failed %lu\n", block);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090077 break;
78 }
79 }
80
81 return 0;
82 }
83
84 if (strncmp(argv[1], "read", 4) == 0) {
85 ulong addr = simple_strtoul(argv[2], NULL, 16);
86 ulong ofs = simple_strtoul(argv[3], NULL, 16);
87 size_t len = simple_strtoul(argv[4], NULL, 16);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090088 int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +090089 struct mtd_oob_ops ops;
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +090090
Kyungmin Parkbfd7f382008-08-19 08:42:53 +090091 ops.mode = MTD_OOB_PLACE;
92
93 if (oob) {
94 ops.len = 0;
95 ops.datbuf = NULL;
96 ops.ooblen = len;
97 ops.oobbuf = (u_char *) addr;
98 } else {
99 ops.len = len;
100 ops.datbuf = (u_char *) addr;
101 ops.ooblen = 0;
102 ops.oobbuf = NULL;
103 }
104 ops.retlen = ops.oobretlen = 0;
105
106 onenand_mtd.read_oob(&onenand_mtd, ofs, &ops);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900107 printf("Done\n");
108
109 return 0;
110 }
111
112 if (strncmp(argv[1], "write", 5) == 0) {
113 ulong addr = simple_strtoul(argv[2], NULL, 16);
114 ulong ofs = simple_strtoul(argv[3], NULL, 16);
115 size_t len = simple_strtoul(argv[4], NULL, 16);
116 size_t retlen = 0;
117
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900118 onenand_write(&onenand_mtd, ofs, len, &retlen,
119 (u_char *) addr);
120 printf("Done\n");
121
122 return 0;
123 }
124
125 if (strncmp(argv[1], "block", 5) == 0) {
126 ulong addr = simple_strtoul(argv[2], NULL, 16);
127 ulong block = simple_strtoul(argv[3], NULL, 10);
128 ulong page = simple_strtoul(argv[4], NULL, 10);
129 size_t len = simple_strtol(argv[5], NULL, 10);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900130 ulong ofs;
131 int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1;
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900132 struct mtd_oob_ops ops;
133
134 ops.mode = MTD_OOB_PLACE;
135
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900136
137 ofs = block << onenand_chip.erase_shift;
138 if (page)
139 ofs += page << onenand_chip.page_shift;
140
141 if (!len) {
142 if (oob)
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900143 ops.ooblen = 64;
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900144 else
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900145 ops.len = 512;
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900146 }
147
Kyungmin Parkbfd7f382008-08-19 08:42:53 +0900148 if (oob) {
149 ops.datbuf = NULL;
150 ops.oobbuf = (u_char *) addr;
151 } else {
152 ops.datbuf = (u_char *) addr;
153 ops.oobbuf = NULL;
154 }
155 ops.retlen = ops.oobretlen = 0;
156
157 onenand_read_oob(&onenand_mtd, ofs, &ops);
Kyungmin Parkd7e8ce12007-09-10 17:15:14 +0900158 return 0;
159 }
160
161 break;
162 }
163
164 return 0;
165}
166
167U_BOOT_CMD(
168 onenand, 6, 1, do_onenand,
169 "onenand - OneNAND sub-system\n",
170 "info - show available OneNAND devices\n"
171 "onenand read[.oob] addr ofs len - read data at ofs with len to addr\n"
172 "onenand write addr ofs len - write data at ofs with len from addr\n"
173 "onenand erase saddr eaddr - erase block start addr to end addr\n"
174 "onenand block[.oob] addr block [page] [len] - "
175 "read data with (block [, page]) to addr"
176);