cmd_sf: drop device status message when probing
[kernel/u-boot.git] / common / cmd_sf.c
1 /*
2  * Command for accessing SPI flash.
3  *
4  * Copyright (C) 2008 Atmel Corporation
5  * Licensed under the GPL-2 or later.
6  */
7
8 #include <common.h>
9 #include <spi_flash.h>
10
11 #include <asm/io.h>
12
13 #ifndef CONFIG_SF_DEFAULT_SPEED
14 # define CONFIG_SF_DEFAULT_SPEED        1000000
15 #endif
16 #ifndef CONFIG_SF_DEFAULT_MODE
17 # define CONFIG_SF_DEFAULT_MODE         SPI_MODE_3
18 #endif
19
20 static struct spi_flash *flash;
21
22
23 /*
24  * This function computes the length argument for the erase command.
25  * The length on which the command is to operate can be given in two forms:
26  * 1. <cmd> offset len  - operate on <'offset',  'len')
27  * 2. <cmd> offset +len - operate on <'offset',  'round_up(len)')
28  * If the second form is used and the length doesn't fall on the
29  * sector boundary, than it will be adjusted to the next sector boundary.
30  * If it isn't in the flash, the function will fail (return -1).
31  * Input:
32  *    arg: length specification (i.e. both command arguments)
33  * Output:
34  *    len: computed length for operation
35  * Return:
36  *    1: success
37  *   -1: failure (bad format, bad address).
38  */
39 static int sf_parse_len_arg(char *arg, ulong *len)
40 {
41         char *ep;
42         char round_up_len; /* indicates if the "+length" form used */
43         ulong len_arg;
44
45         round_up_len = 0;
46         if (*arg == '+') {
47                 round_up_len = 1;
48                 ++arg;
49         }
50
51         len_arg = simple_strtoul(arg, &ep, 16);
52         if (ep == arg || *ep != '\0')
53                 return -1;
54
55         if (round_up_len && flash->sector_size > 0)
56                 *len = ROUND(len_arg - 1, flash->sector_size);
57         else
58                 *len = len_arg;
59
60         return 1;
61 }
62
63 static int do_spi_flash_probe(int argc, char * const argv[])
64 {
65         unsigned int bus = 0;
66         unsigned int cs;
67         unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
68         unsigned int mode = CONFIG_SF_DEFAULT_MODE;
69         char *endp;
70         struct spi_flash *new;
71
72         if (argc < 2)
73                 goto usage;
74
75         cs = simple_strtoul(argv[1], &endp, 0);
76         if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
77                 goto usage;
78         if (*endp == ':') {
79                 if (endp[1] == 0)
80                         goto usage;
81
82                 bus = cs;
83                 cs = simple_strtoul(endp + 1, &endp, 0);
84                 if (*endp != 0)
85                         goto usage;
86         }
87
88         if (argc >= 3) {
89                 speed = simple_strtoul(argv[2], &endp, 0);
90                 if (*argv[2] == 0 || *endp != 0)
91                         goto usage;
92         }
93         if (argc >= 4) {
94                 mode = simple_strtoul(argv[3], &endp, 16);
95                 if (*argv[3] == 0 || *endp != 0)
96                         goto usage;
97         }
98
99         new = spi_flash_probe(bus, cs, speed, mode);
100         if (!new) {
101                 printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
102                 return 1;
103         }
104
105         if (flash)
106                 spi_flash_free(flash);
107         flash = new;
108
109         return 0;
110
111 usage:
112         puts("Usage: sf probe [bus:]cs [hz] [mode]\n");
113         return 1;
114 }
115
116 static int do_spi_flash_read_write(int argc, char * const argv[])
117 {
118         unsigned long addr;
119         unsigned long offset;
120         unsigned long len;
121         void *buf;
122         char *endp;
123         int ret;
124
125         if (argc < 4)
126                 goto usage;
127
128         addr = simple_strtoul(argv[1], &endp, 16);
129         if (*argv[1] == 0 || *endp != 0)
130                 goto usage;
131         offset = simple_strtoul(argv[2], &endp, 16);
132         if (*argv[2] == 0 || *endp != 0)
133                 goto usage;
134         len = simple_strtoul(argv[3], &endp, 16);
135         if (*argv[3] == 0 || *endp != 0)
136                 goto usage;
137
138         buf = map_physmem(addr, len, MAP_WRBACK);
139         if (!buf) {
140                 puts("Failed to map physical memory\n");
141                 return 1;
142         }
143
144         if (strcmp(argv[0], "read") == 0)
145                 ret = spi_flash_read(flash, offset, len, buf);
146         else
147                 ret = spi_flash_write(flash, offset, len, buf);
148
149         unmap_physmem(buf, len);
150
151         if (ret) {
152                 printf("SPI flash %s failed\n", argv[0]);
153                 return 1;
154         }
155
156         return 0;
157
158 usage:
159         printf("Usage: sf %s addr offset len\n", argv[0]);
160         return 1;
161 }
162
163 static int do_spi_flash_erase(int argc, char * const argv[])
164 {
165         unsigned long offset;
166         unsigned long len;
167         char *endp;
168         int ret;
169
170         if (argc < 3)
171                 goto usage;
172
173         offset = simple_strtoul(argv[1], &endp, 16);
174         if (*argv[1] == 0 || *endp != 0)
175                 goto usage;
176
177         ret = sf_parse_len_arg(argv[2], &len);
178         if (ret != 1)
179                 goto usage;
180
181         ret = spi_flash_erase(flash, offset, len);
182         if (ret) {
183                 printf("SPI flash %s failed\n", argv[0]);
184                 return 1;
185         }
186
187         return 0;
188
189 usage:
190         puts("Usage: sf erase offset [+]len\n");
191         return 1;
192 }
193
194 static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
195 {
196         const char *cmd;
197
198         /* need at least two arguments */
199         if (argc < 2)
200                 goto usage;
201
202         cmd = argv[1];
203
204         if (strcmp(cmd, "probe") == 0)
205                 return do_spi_flash_probe(argc - 1, argv + 1);
206
207         /* The remaining commands require a selected device */
208         if (!flash) {
209                 puts("No SPI flash selected. Please run `sf probe'\n");
210                 return 1;
211         }
212
213         if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
214                 return do_spi_flash_read_write(argc - 1, argv + 1);
215         if (strcmp(cmd, "erase") == 0)
216                 return do_spi_flash_erase(argc - 1, argv + 1);
217
218 usage:
219         return cmd_usage(cmdtp);
220 }
221
222 U_BOOT_CMD(
223         sf,     5,      1,      do_spi_flash,
224         "SPI flash sub-system",
225         "probe [bus:]cs [hz] [mode]     - init flash device on given SPI bus\n"
226         "                                 and chip select\n"
227         "sf read addr offset len        - read `len' bytes starting at\n"
228         "                                 `offset' to memory at `addr'\n"
229         "sf write addr offset len       - write `len' bytes from memory\n"
230         "                                 at `addr' to flash at `offset'\n"
231         "sf erase offset [+]len         - erase `len' bytes from `offset'\n"
232         "                                 `+len' round up `len' to block size"
233 );