]>
Commit | Line | Data |
---|---|---|
d25ce7d2 HS |
1 | /* |
2 | * SPI flash interface | |
3 | * | |
4 | * Copyright (C) 2008 Atmel Corporation | |
0d3fe2b1 RM |
5 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik |
6 | * | |
4166ee58 | 7 | * Licensed under the GPL-2 or later. |
d25ce7d2 | 8 | */ |
f773a1bb | 9 | |
d25ce7d2 HS |
10 | #include <common.h> |
11 | #include <malloc.h> | |
12 | #include <spi.h> | |
13 | #include <spi_flash.h> | |
14 | ||
15 | #include "spi_flash_internal.h" | |
16 | ||
e7b44edd MF |
17 | static void spi_flash_addr(u32 addr, u8 *cmd) |
18 | { | |
19 | /* cmd[0] is actual command */ | |
20 | cmd[1] = addr >> 16; | |
21 | cmd[2] = addr >> 8; | |
22 | cmd[3] = addr >> 0; | |
23 | } | |
24 | ||
000044d8 MF |
25 | static int spi_flash_read_write(struct spi_slave *spi, |
26 | const u8 *cmd, size_t cmd_len, | |
27 | const u8 *data_out, u8 *data_in, | |
28 | size_t data_len) | |
d25ce7d2 HS |
29 | { |
30 | unsigned long flags = SPI_XFER_BEGIN; | |
31 | int ret; | |
32 | ||
33 | if (data_len == 0) | |
34 | flags |= SPI_XFER_END; | |
35 | ||
36 | ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); | |
37 | if (ret) { | |
000044d8 | 38 | debug("SF: Failed to send command (%zu bytes): %d\n", |
d25ce7d2 HS |
39 | cmd_len, ret); |
40 | } else if (data_len != 0) { | |
000044d8 | 41 | ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_END); |
d25ce7d2 | 42 | if (ret) |
000044d8 | 43 | debug("SF: Failed to transfer %zu bytes of data: %d\n", |
d25ce7d2 HS |
44 | data_len, ret); |
45 | } | |
46 | ||
47 | return ret; | |
48 | } | |
49 | ||
000044d8 | 50 | int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) |
d25ce7d2 | 51 | { |
000044d8 MF |
52 | return spi_flash_cmd_read(spi, &cmd, 1, response, len); |
53 | } | |
d25ce7d2 | 54 | |
000044d8 MF |
55 | int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, |
56 | size_t cmd_len, void *data, size_t data_len) | |
57 | { | |
58 | return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); | |
d25ce7d2 HS |
59 | } |
60 | ||
000044d8 MF |
61 | int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, |
62 | const void *data, size_t data_len) | |
63 | { | |
64 | return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); | |
65 | } | |
d25ce7d2 HS |
66 | |
67 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | |
68 | size_t cmd_len, void *data, size_t data_len) | |
69 | { | |
70 | struct spi_slave *spi = flash->spi; | |
71 | int ret; | |
72 | ||
73 | spi_claim_bus(spi); | |
74 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); | |
75 | spi_release_bus(spi); | |
76 | ||
77 | return ret; | |
78 | } | |
79 | ||
6163045b MF |
80 | int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, |
81 | u8 cmd, u8 poll_bit) | |
82 | { | |
83 | struct spi_slave *spi = flash->spi; | |
84 | unsigned long timebase; | |
85 | int ret; | |
86 | u8 status; | |
87 | ||
88 | ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | |
89 | if (ret) { | |
90 | debug("SF: Failed to send command %02x: %d\n", cmd, ret); | |
91 | return ret; | |
92 | } | |
93 | ||
94 | timebase = get_timer(0); | |
95 | do { | |
96 | ret = spi_xfer(spi, 8, NULL, &status, 0); | |
97 | if (ret) | |
98 | return -1; | |
99 | ||
100 | if ((status & poll_bit) == 0) | |
101 | break; | |
102 | ||
103 | } while (get_timer(timebase) < timeout); | |
104 | ||
105 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); | |
106 | ||
107 | if ((status & poll_bit) == 0) | |
108 | return 0; | |
109 | ||
110 | /* Timed out */ | |
111 | debug("SF: time out!\n"); | |
112 | return -1; | |
113 | } | |
114 | ||
115 | int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | |
116 | { | |
117 | return spi_flash_cmd_poll_bit(flash, timeout, | |
118 | CMD_READ_STATUS, STATUS_WIP); | |
119 | } | |
120 | ||
e7b44edd MF |
121 | int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, |
122 | u32 erase_size, u32 offset, size_t len) | |
123 | { | |
124 | u32 start, end; | |
125 | int ret; | |
126 | u8 cmd[4]; | |
127 | ||
128 | if (offset % erase_size || len % erase_size) { | |
129 | debug("SF: Erase offset/length not multiple of erase size\n"); | |
130 | return -1; | |
131 | } | |
132 | ||
133 | ret = spi_claim_bus(flash->spi); | |
134 | if (ret) { | |
135 | debug("SF: Unable to claim SPI bus\n"); | |
136 | return ret; | |
137 | } | |
138 | ||
139 | cmd[0] = erase_cmd; | |
140 | start = offset; | |
141 | end = start + len; | |
142 | ||
143 | while (offset < end) { | |
144 | spi_flash_addr(offset, cmd); | |
145 | offset += erase_size; | |
146 | ||
147 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | |
148 | cmd[2], cmd[3], offset); | |
149 | ||
150 | ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); | |
151 | if (ret) | |
152 | goto out; | |
153 | ||
154 | ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); | |
155 | if (ret) | |
156 | goto out; | |
157 | ||
158 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); | |
159 | if (ret) | |
160 | goto out; | |
161 | } | |
162 | ||
163 | debug("SF: Successfully erased %lu bytes @ %#x\n", | |
164 | len * erase_size, start); | |
165 | ||
166 | out: | |
167 | spi_release_bus(flash->spi); | |
168 | return ret; | |
169 | } | |
170 | ||
0d3fe2b1 RM |
171 | /* |
172 | * The following table holds all device probe functions | |
173 | * | |
174 | * shift: number of continuation bytes before the ID | |
175 | * idcode: the expected IDCODE or 0xff for non JEDEC devices | |
176 | * probe: the function to call | |
177 | * | |
178 | * Non JEDEC devices should be ordered in the table such that | |
179 | * the probe functions with best detection algorithms come first. | |
180 | * | |
181 | * Several matching entries are permitted, they will be tried | |
182 | * in sequence until a probe function returns non NULL. | |
183 | * | |
184 | * IDCODE_CONT_LEN may be redefined if a device needs to declare a | |
185 | * larger "shift" value. IDCODE_PART_LEN generally shouldn't be | |
186 | * changed. This is the max number of bytes probe functions may | |
187 | * examine when looking up part-specific identification info. | |
188 | * | |
189 | * Probe functions will be given the idcode buffer starting at their | |
190 | * manu id byte (the "idcode" in the table below). In other words, | |
191 | * all of the continuation bytes will be skipped (the "shift" below). | |
192 | */ | |
193 | #define IDCODE_CONT_LEN 0 | |
194 | #define IDCODE_PART_LEN 5 | |
195 | static const struct { | |
196 | const u8 shift; | |
197 | const u8 idcode; | |
198 | struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); | |
199 | } flashes[] = { | |
200 | /* Keep it sorted by define name */ | |
201 | #ifdef CONFIG_SPI_FLASH_ATMEL | |
202 | { 0, 0x1f, spi_flash_probe_atmel, }, | |
203 | #endif | |
d1d90656 CH |
204 | #ifdef CONFIG_SPI_FLASH_EON |
205 | { 0, 0x1c, spi_flash_probe_eon, }, | |
206 | #endif | |
0d3fe2b1 RM |
207 | #ifdef CONFIG_SPI_FLASH_MACRONIX |
208 | { 0, 0xc2, spi_flash_probe_macronix, }, | |
209 | #endif | |
210 | #ifdef CONFIG_SPI_FLASH_SPANSION | |
211 | { 0, 0x01, spi_flash_probe_spansion, }, | |
212 | #endif | |
213 | #ifdef CONFIG_SPI_FLASH_SST | |
214 | { 0, 0xbf, spi_flash_probe_sst, }, | |
215 | #endif | |
216 | #ifdef CONFIG_SPI_FLASH_STMICRO | |
217 | { 0, 0x20, spi_flash_probe_stmicro, }, | |
218 | #endif | |
219 | #ifdef CONFIG_SPI_FLASH_WINBOND | |
220 | { 0, 0xef, spi_flash_probe_winbond, }, | |
e0987e25 RM |
221 | #endif |
222 | #ifdef CONFIG_SPI_FRAM_RAMTRON | |
223 | { 6, 0xc2, spi_fram_probe_ramtron, }, | |
224 | # undef IDCODE_CONT_LEN | |
225 | # define IDCODE_CONT_LEN 6 | |
0d3fe2b1 RM |
226 | #endif |
227 | /* Keep it sorted by best detection */ | |
228 | #ifdef CONFIG_SPI_FLASH_STMICRO | |
229 | { 0, 0xff, spi_flash_probe_stmicro, }, | |
230 | #endif | |
e0987e25 RM |
231 | #ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC |
232 | { 0, 0xff, spi_fram_probe_ramtron, }, | |
233 | #endif | |
0d3fe2b1 RM |
234 | }; |
235 | #define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) | |
236 | ||
d25ce7d2 HS |
237 | struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, |
238 | unsigned int max_hz, unsigned int spi_mode) | |
239 | { | |
240 | struct spi_slave *spi; | |
0d3fe2b1 RM |
241 | struct spi_flash *flash = NULL; |
242 | int ret, i, shift; | |
243 | u8 idcode[IDCODE_LEN], *idp; | |
d25ce7d2 HS |
244 | |
245 | spi = spi_setup_slave(bus, cs, max_hz, spi_mode); | |
246 | if (!spi) { | |
b376bbb4 | 247 | printf("SF: Failed to set up slave\n"); |
d25ce7d2 HS |
248 | return NULL; |
249 | } | |
250 | ||
251 | ret = spi_claim_bus(spi); | |
252 | if (ret) { | |
253 | debug("SF: Failed to claim SPI bus: %d\n", ret); | |
254 | goto err_claim_bus; | |
255 | } | |
256 | ||
257 | /* Read the ID codes */ | |
0d3fe2b1 | 258 | ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); |
d25ce7d2 HS |
259 | if (ret) |
260 | goto err_read_id; | |
261 | ||
0d3fe2b1 RM |
262 | #ifdef DEBUG |
263 | printf("SF: Got idcodes\n"); | |
264 | print_buffer(0, idcode, 1, sizeof(idcode), 0); | |
d25ce7d2 | 265 | #endif |
d25ce7d2 | 266 | |
0d3fe2b1 RM |
267 | /* count the number of continuation bytes */ |
268 | for (shift = 0, idp = idcode; | |
269 | shift < IDCODE_CONT_LEN && *idp == 0x7f; | |
270 | ++shift, ++idp) | |
271 | continue; | |
272 | ||
273 | /* search the table for matches in shift and id */ | |
274 | for (i = 0; i < ARRAY_SIZE(flashes); ++i) | |
275 | if (flashes[i].shift == shift && flashes[i].idcode == *idp) { | |
276 | /* we have a match, call probe */ | |
277 | flash = flashes[i].probe(spi, idp); | |
278 | if (flash) | |
279 | break; | |
280 | } | |
281 | ||
282 | if (!flash) { | |
283 | printf("SF: Unsupported manufacturer %02x\n", *idp); | |
d25ce7d2 | 284 | goto err_manufacturer_probe; |
0d3fe2b1 | 285 | } |
d25ce7d2 HS |
286 | |
287 | spi_release_bus(spi); | |
288 | ||
289 | return flash; | |
290 | ||
291 | err_manufacturer_probe: | |
292 | err_read_id: | |
293 | spi_release_bus(spi); | |
294 | err_claim_bus: | |
295 | spi_free_slave(spi); | |
296 | return NULL; | |
297 | } | |
298 | ||
299 | void spi_flash_free(struct spi_flash *flash) | |
300 | { | |
301 | spi_free_slave(flash->spi); | |
302 | free(flash); | |
303 | } |