Commit 4d5e29a680fc68f02b069a0780d7c71063219b18
1 parent
f835c77fb7
Exists in
master
and in
53 other branches
sf: Divide spi_flash into multiple parts
Divided the spi_flash framework into mutiple parts for - spi_flash.c: spi flash core file, interaction for spi/qspi driver to spi_flash framework. - spi_flash_ops.c spi flash preffered operations, erase,write and read. - spi_flash_probe.c spi flash probing, easy to extend probing functionality. This change will support to extend the functionality in a proper manner. Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
Showing 4 changed files with 596 additions and 567 deletions Side-by-side Diff
drivers/mtd/spi/Makefile
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | COBJS-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o |
15 | 15 | endif |
16 | 16 | |
17 | -COBJS-$(CONFIG_SPI_FLASH) += spi_flash.o | |
17 | +COBJS-$(CONFIG_SPI_FLASH) += spi_flash_probe.o spi_flash_ops.o spi_flash.o | |
18 | 18 | COBJS-$(CONFIG_SPI_FLASH_ATMEL) += atmel.o |
19 | 19 | COBJS-$(CONFIG_SPI_FLASH_EON) += eon.o |
20 | 20 | COBJS-$(CONFIG_SPI_FLASH_GIGADEVICE) += gigadevice.o |
drivers/mtd/spi/spi_flash.c
... | ... | @@ -8,24 +8,8 @@ |
8 | 8 | */ |
9 | 9 | |
10 | 10 | #include <common.h> |
11 | -#include <fdtdec.h> | |
12 | -#include <malloc.h> | |
13 | 11 | #include <spi.h> |
14 | -#include <spi_flash.h> | |
15 | -#include <watchdog.h> | |
16 | 12 | |
17 | -#include "spi_flash_internal.h" | |
18 | - | |
19 | -DECLARE_GLOBAL_DATA_PTR; | |
20 | - | |
21 | -static void spi_flash_addr(u32 addr, u8 *cmd) | |
22 | -{ | |
23 | - /* cmd[0] is actual command */ | |
24 | - cmd[1] = addr >> 16; | |
25 | - cmd[2] = addr >> 8; | |
26 | - cmd[3] = addr >> 0; | |
27 | -} | |
28 | - | |
29 | 13 | static int spi_flash_read_write(struct spi_slave *spi, |
30 | 14 | const u8 *cmd, size_t cmd_len, |
31 | 15 | const u8 *data_out, u8 *data_in, |
32 | 16 | |
33 | 17 | |
34 | 18 | |
35 | 19 | |
... | ... | @@ -52,565 +36,20 @@ |
52 | 36 | return ret; |
53 | 37 | } |
54 | 38 | |
55 | -int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) | |
56 | -{ | |
57 | - return spi_flash_cmd_read(spi, &cmd, 1, response, len); | |
58 | -} | |
59 | - | |
60 | 39 | int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, |
61 | 40 | size_t cmd_len, void *data, size_t data_len) |
62 | 41 | { |
63 | 42 | return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); |
64 | 43 | } |
65 | 44 | |
66 | -int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, | |
67 | - const void *data, size_t data_len) | |
45 | +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) | |
68 | 46 | { |
69 | - return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); | |
47 | + return spi_flash_cmd_read(spi, &cmd, 1, response, len); | |
70 | 48 | } |
71 | 49 | |
72 | -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | |
50 | +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, | |
51 | + const void *data, size_t data_len) | |
73 | 52 | { |
74 | - struct spi_slave *spi = flash->spi; | |
75 | - unsigned long timebase; | |
76 | - int ret; | |
77 | - u8 status; | |
78 | - u8 check_status = 0x0; | |
79 | - u8 poll_bit = STATUS_WIP; | |
80 | - u8 cmd = flash->poll_cmd; | |
81 | - | |
82 | - if (cmd == CMD_FLAG_STATUS) { | |
83 | - poll_bit = STATUS_PEC; | |
84 | - check_status = poll_bit; | |
85 | - } | |
86 | - | |
87 | - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | |
88 | - if (ret) { | |
89 | - debug("SF: fail to read %s status register\n", | |
90 | - cmd == CMD_READ_STATUS ? "read" : "flag"); | |
91 | - return ret; | |
92 | - } | |
93 | - | |
94 | - timebase = get_timer(0); | |
95 | - do { | |
96 | - WATCHDOG_RESET(); | |
97 | - | |
98 | - ret = spi_xfer(spi, 8, NULL, &status, 0); | |
99 | - if (ret) | |
100 | - return -1; | |
101 | - | |
102 | - if ((status & poll_bit) == check_status) | |
103 | - break; | |
104 | - | |
105 | - } while (get_timer(timebase) < timeout); | |
106 | - | |
107 | - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); | |
108 | - | |
109 | - if ((status & poll_bit) == check_status) | |
110 | - return 0; | |
111 | - | |
112 | - /* Timed out */ | |
113 | - debug("SF: time out!\n"); | |
114 | - return -1; | |
115 | -} | |
116 | - | |
117 | -int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, | |
118 | - size_t cmd_len, const void *buf, size_t buf_len) | |
119 | -{ | |
120 | - struct spi_slave *spi = flash->spi; | |
121 | - unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; | |
122 | - int ret; | |
123 | - | |
124 | - if (buf == NULL) | |
125 | - timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; | |
126 | - | |
127 | - ret = spi_claim_bus(flash->spi); | |
128 | - if (ret) { | |
129 | - debug("SF: unable to claim SPI bus\n"); | |
130 | - return ret; | |
131 | - } | |
132 | - | |
133 | - ret = spi_flash_cmd_write_enable(flash); | |
134 | - if (ret < 0) { | |
135 | - debug("SF: enabling write failed\n"); | |
136 | - return ret; | |
137 | - } | |
138 | - | |
139 | - ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); | |
140 | - if (ret < 0) { | |
141 | - debug("SF: write cmd failed\n"); | |
142 | - return ret; | |
143 | - } | |
144 | - | |
145 | - ret = spi_flash_cmd_wait_ready(flash, timeout); | |
146 | - if (ret < 0) { | |
147 | - debug("SF: write %s timed out\n", | |
148 | - timeout == SPI_FLASH_PROG_TIMEOUT ? | |
149 | - "program" : "page erase"); | |
150 | - return ret; | |
151 | - } | |
152 | - | |
153 | - spi_release_bus(spi); | |
154 | - | |
155 | - return ret; | |
156 | -} | |
157 | - | |
158 | -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) | |
159 | -{ | |
160 | - u32 erase_size; | |
161 | - u8 cmd[4]; | |
162 | - int ret = -1; | |
163 | - | |
164 | - erase_size = flash->sector_size; | |
165 | - if (offset % erase_size || len % erase_size) { | |
166 | - debug("SF: Erase offset/length not multiple of erase size\n"); | |
167 | - return -1; | |
168 | - } | |
169 | - | |
170 | - if (erase_size == 4096) | |
171 | - cmd[0] = CMD_ERASE_4K; | |
172 | - else | |
173 | - cmd[0] = CMD_ERASE_64K; | |
174 | - | |
175 | - while (len) { | |
176 | -#ifdef CONFIG_SPI_FLASH_BAR | |
177 | - u8 bank_sel; | |
178 | - | |
179 | - bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
180 | - | |
181 | - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
182 | - if (ret) { | |
183 | - debug("SF: fail to set bank%d\n", bank_sel); | |
184 | - return ret; | |
185 | - } | |
186 | -#endif | |
187 | - spi_flash_addr(offset, cmd); | |
188 | - | |
189 | - debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | |
190 | - cmd[2], cmd[3], offset); | |
191 | - | |
192 | - ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | |
193 | - if (ret < 0) { | |
194 | - debug("SF: erase failed\n"); | |
195 | - break; | |
196 | - } | |
197 | - | |
198 | - offset += erase_size; | |
199 | - len -= erase_size; | |
200 | - } | |
201 | - | |
202 | - return ret; | |
203 | -} | |
204 | - | |
205 | -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, | |
206 | - size_t len, const void *buf) | |
207 | -{ | |
208 | - unsigned long byte_addr, page_size; | |
209 | - size_t chunk_len, actual; | |
210 | - u8 cmd[4]; | |
211 | - int ret = -1; | |
212 | - | |
213 | - page_size = flash->page_size; | |
214 | - | |
215 | - cmd[0] = CMD_PAGE_PROGRAM; | |
216 | - for (actual = 0; actual < len; actual += chunk_len) { | |
217 | -#ifdef CONFIG_SPI_FLASH_BAR | |
218 | - u8 bank_sel; | |
219 | - | |
220 | - bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
221 | - | |
222 | - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
223 | - if (ret) { | |
224 | - debug("SF: fail to set bank%d\n", bank_sel); | |
225 | - return ret; | |
226 | - } | |
227 | -#endif | |
228 | - byte_addr = offset % page_size; | |
229 | - chunk_len = min(len - actual, page_size - byte_addr); | |
230 | - | |
231 | - if (flash->spi->max_write_size) | |
232 | - chunk_len = min(chunk_len, flash->spi->max_write_size); | |
233 | - | |
234 | - spi_flash_addr(offset, cmd); | |
235 | - | |
236 | - debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | |
237 | - buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); | |
238 | - | |
239 | - ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | |
240 | - buf + actual, chunk_len); | |
241 | - if (ret < 0) { | |
242 | - debug("SF: write failed\n"); | |
243 | - break; | |
244 | - } | |
245 | - | |
246 | - offset += chunk_len; | |
247 | - } | |
248 | - | |
249 | - return ret; | |
250 | -} | |
251 | - | |
252 | -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | |
253 | - size_t cmd_len, void *data, size_t data_len) | |
254 | -{ | |
255 | - struct spi_slave *spi = flash->spi; | |
256 | - int ret; | |
257 | - | |
258 | - ret = spi_claim_bus(flash->spi); | |
259 | - if (ret) { | |
260 | - debug("SF: unable to claim SPI bus\n"); | |
261 | - return ret; | |
262 | - } | |
263 | - | |
264 | - ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); | |
265 | - if (ret < 0) { | |
266 | - debug("SF: read cmd failed\n"); | |
267 | - return ret; | |
268 | - } | |
269 | - | |
270 | - spi_release_bus(spi); | |
271 | - | |
272 | - return ret; | |
273 | -} | |
274 | - | |
275 | -int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, | |
276 | - size_t len, void *data) | |
277 | -{ | |
278 | - u8 cmd[5], bank_sel = 0; | |
279 | - u32 remain_len, read_len; | |
280 | - int ret = -1; | |
281 | - | |
282 | - /* Handle memory-mapped SPI */ | |
283 | - if (flash->memory_map) { | |
284 | - memcpy(data, flash->memory_map + offset, len); | |
285 | - return 0; | |
286 | - } | |
287 | - | |
288 | - cmd[0] = CMD_READ_ARRAY_FAST; | |
289 | - cmd[4] = 0x00; | |
290 | - | |
291 | - while (len) { | |
292 | -#ifdef CONFIG_SPI_FLASH_BAR | |
293 | - bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
294 | - | |
295 | - ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
296 | - if (ret) { | |
297 | - debug("SF: fail to set bank%d\n", bank_sel); | |
298 | - return ret; | |
299 | - } | |
300 | -#endif | |
301 | - remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); | |
302 | - if (len < remain_len) | |
303 | - read_len = len; | |
304 | - else | |
305 | - read_len = remain_len; | |
306 | - | |
307 | - spi_flash_addr(offset, cmd); | |
308 | - | |
309 | - ret = spi_flash_read_common(flash, cmd, sizeof(cmd), | |
310 | - data, read_len); | |
311 | - if (ret < 0) { | |
312 | - debug("SF: read failed\n"); | |
313 | - break; | |
314 | - } | |
315 | - | |
316 | - offset += read_len; | |
317 | - len -= read_len; | |
318 | - data += read_len; | |
319 | - } | |
320 | - | |
321 | - return ret; | |
322 | -} | |
323 | - | |
324 | -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) | |
325 | -{ | |
326 | - u8 cmd; | |
327 | - int ret; | |
328 | - | |
329 | - cmd = CMD_WRITE_STATUS; | |
330 | - ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); | |
331 | - if (ret < 0) { | |
332 | - debug("SF: fail to write status register\n"); | |
333 | - return ret; | |
334 | - } | |
335 | - | |
336 | - return 0; | |
337 | -} | |
338 | - | |
339 | -#ifdef CONFIG_SPI_FLASH_BAR | |
340 | -int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) | |
341 | -{ | |
342 | - u8 cmd; | |
343 | - int ret; | |
344 | - | |
345 | - if (flash->bank_curr == bank_sel) { | |
346 | - debug("SF: not require to enable bank%d\n", bank_sel); | |
347 | - return 0; | |
348 | - } | |
349 | - | |
350 | - cmd = flash->bank_write_cmd; | |
351 | - ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); | |
352 | - if (ret < 0) { | |
353 | - debug("SF: fail to write bank register\n"); | |
354 | - return ret; | |
355 | - } | |
356 | - flash->bank_curr = bank_sel; | |
357 | - | |
358 | - return 0; | |
359 | -} | |
360 | - | |
361 | -int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) | |
362 | -{ | |
363 | - u8 cmd; | |
364 | - u8 curr_bank = 0; | |
365 | - | |
366 | - /* discover bank cmds */ | |
367 | - switch (idcode0) { | |
368 | - case SPI_FLASH_SPANSION_IDCODE0: | |
369 | - flash->bank_read_cmd = CMD_BANKADDR_BRRD; | |
370 | - flash->bank_write_cmd = CMD_BANKADDR_BRWR; | |
371 | - break; | |
372 | - case SPI_FLASH_STMICRO_IDCODE0: | |
373 | - case SPI_FLASH_WINBOND_IDCODE0: | |
374 | - flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; | |
375 | - flash->bank_write_cmd = CMD_EXTNADDR_WREAR; | |
376 | - break; | |
377 | - default: | |
378 | - printf("SF: Unsupported bank commands %02x\n", idcode0); | |
379 | - return -1; | |
380 | - } | |
381 | - | |
382 | - /* read the bank reg - on which bank the flash is in currently */ | |
383 | - cmd = flash->bank_read_cmd; | |
384 | - if (flash->size > SPI_FLASH_16MB_BOUN) { | |
385 | - if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { | |
386 | - debug("SF: fail to read bank addr register\n"); | |
387 | - return -1; | |
388 | - } | |
389 | - flash->bank_curr = curr_bank; | |
390 | - } else { | |
391 | - flash->bank_curr = curr_bank; | |
392 | - } | |
393 | - | |
394 | - return 0; | |
395 | -} | |
396 | -#endif | |
397 | - | |
398 | -#ifdef CONFIG_OF_CONTROL | |
399 | -int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) | |
400 | -{ | |
401 | - fdt_addr_t addr; | |
402 | - fdt_size_t size; | |
403 | - int node; | |
404 | - | |
405 | - /* If there is no node, do nothing */ | |
406 | - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); | |
407 | - if (node < 0) | |
408 | - return 0; | |
409 | - | |
410 | - addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); | |
411 | - if (addr == FDT_ADDR_T_NONE) { | |
412 | - debug("%s: Cannot decode address\n", __func__); | |
413 | - return 0; | |
414 | - } | |
415 | - | |
416 | - if (flash->size != size) { | |
417 | - debug("%s: Memory map must cover entire device\n", __func__); | |
418 | - return -1; | |
419 | - } | |
420 | - flash->memory_map = (void *)addr; | |
421 | - | |
422 | - return 0; | |
423 | -} | |
424 | -#endif /* CONFIG_OF_CONTROL */ | |
425 | - | |
426 | -/* | |
427 | - * The following table holds all device probe functions | |
428 | - * | |
429 | - * shift: number of continuation bytes before the ID | |
430 | - * idcode: the expected IDCODE or 0xff for non JEDEC devices | |
431 | - * probe: the function to call | |
432 | - * | |
433 | - * Non JEDEC devices should be ordered in the table such that | |
434 | - * the probe functions with best detection algorithms come first. | |
435 | - * | |
436 | - * Several matching entries are permitted, they will be tried | |
437 | - * in sequence until a probe function returns non NULL. | |
438 | - * | |
439 | - * IDCODE_CONT_LEN may be redefined if a device needs to declare a | |
440 | - * larger "shift" value. IDCODE_PART_LEN generally shouldn't be | |
441 | - * changed. This is the max number of bytes probe functions may | |
442 | - * examine when looking up part-specific identification info. | |
443 | - * | |
444 | - * Probe functions will be given the idcode buffer starting at their | |
445 | - * manu id byte (the "idcode" in the table below). In other words, | |
446 | - * all of the continuation bytes will be skipped (the "shift" below). | |
447 | - */ | |
448 | -#define IDCODE_CONT_LEN 0 | |
449 | -#define IDCODE_PART_LEN 5 | |
450 | -static const struct { | |
451 | - const u8 shift; | |
452 | - const u8 idcode; | |
453 | - struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); | |
454 | -} flashes[] = { | |
455 | - /* Keep it sorted by define name */ | |
456 | -#ifdef CONFIG_SPI_FLASH_ATMEL | |
457 | - { 0, 0x1f, spi_flash_probe_atmel, }, | |
458 | -#endif | |
459 | -#ifdef CONFIG_SPI_FLASH_EON | |
460 | - { 0, 0x1c, spi_flash_probe_eon, }, | |
461 | -#endif | |
462 | -#ifdef CONFIG_SPI_FLASH_GIGADEVICE | |
463 | - { 0, 0xc8, spi_flash_probe_gigadevice, }, | |
464 | -#endif | |
465 | -#ifdef CONFIG_SPI_FLASH_MACRONIX | |
466 | - { 0, 0xc2, spi_flash_probe_macronix, }, | |
467 | -#endif | |
468 | -#ifdef CONFIG_SPI_FLASH_SPANSION | |
469 | - { 0, 0x01, spi_flash_probe_spansion, }, | |
470 | -#endif | |
471 | -#ifdef CONFIG_SPI_FLASH_SST | |
472 | - { 0, 0xbf, spi_flash_probe_sst, }, | |
473 | -#endif | |
474 | -#ifdef CONFIG_SPI_FLASH_STMICRO | |
475 | - { 0, 0x20, spi_flash_probe_stmicro, }, | |
476 | -#endif | |
477 | -#ifdef CONFIG_SPI_FLASH_WINBOND | |
478 | - { 0, 0xef, spi_flash_probe_winbond, }, | |
479 | -#endif | |
480 | -#ifdef CONFIG_SPI_FRAM_RAMTRON | |
481 | - { 6, 0xc2, spi_fram_probe_ramtron, }, | |
482 | -# undef IDCODE_CONT_LEN | |
483 | -# define IDCODE_CONT_LEN 6 | |
484 | -#endif | |
485 | - /* Keep it sorted by best detection */ | |
486 | -#ifdef CONFIG_SPI_FLASH_STMICRO | |
487 | - { 0, 0xff, spi_flash_probe_stmicro, }, | |
488 | -#endif | |
489 | -#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC | |
490 | - { 0, 0xff, spi_fram_probe_ramtron, }, | |
491 | -#endif | |
492 | -}; | |
493 | -#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) | |
494 | - | |
495 | -struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, | |
496 | - unsigned int max_hz, unsigned int spi_mode) | |
497 | -{ | |
498 | - struct spi_slave *spi; | |
499 | - struct spi_flash *flash = NULL; | |
500 | - int ret, i, shift; | |
501 | - u8 idcode[IDCODE_LEN], *idp; | |
502 | - | |
503 | - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); | |
504 | - if (!spi) { | |
505 | - printf("SF: Failed to set up slave\n"); | |
506 | - return NULL; | |
507 | - } | |
508 | - | |
509 | - ret = spi_claim_bus(spi); | |
510 | - if (ret) { | |
511 | - debug("SF: Failed to claim SPI bus: %d\n", ret); | |
512 | - goto err_claim_bus; | |
513 | - } | |
514 | - | |
515 | - /* Read the ID codes */ | |
516 | - ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); | |
517 | - if (ret) | |
518 | - goto err_read_id; | |
519 | - | |
520 | -#ifdef DEBUG | |
521 | - printf("SF: Got idcodes\n"); | |
522 | - print_buffer(0, idcode, 1, sizeof(idcode), 0); | |
523 | -#endif | |
524 | - | |
525 | - /* count the number of continuation bytes */ | |
526 | - for (shift = 0, idp = idcode; | |
527 | - shift < IDCODE_CONT_LEN && *idp == 0x7f; | |
528 | - ++shift, ++idp) | |
529 | - continue; | |
530 | - | |
531 | - /* search the table for matches in shift and id */ | |
532 | - for (i = 0; i < ARRAY_SIZE(flashes); ++i) | |
533 | - if (flashes[i].shift == shift && flashes[i].idcode == *idp) { | |
534 | - /* we have a match, call probe */ | |
535 | - flash = flashes[i].probe(spi, idp); | |
536 | - if (flash) | |
537 | - break; | |
538 | - } | |
539 | - | |
540 | - if (!flash) { | |
541 | - printf("SF: Unsupported manufacturer %02x\n", *idp); | |
542 | - goto err_manufacturer_probe; | |
543 | - } | |
544 | - | |
545 | -#ifdef CONFIG_SPI_FLASH_BAR | |
546 | - /* Configure the BAR - disover bank cmds and read current bank */ | |
547 | - ret = spi_flash_bank_config(flash, *idp); | |
548 | - if (ret < 0) | |
549 | - goto err_manufacturer_probe; | |
550 | -#endif | |
551 | - | |
552 | -#ifdef CONFIG_OF_CONTROL | |
553 | - if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { | |
554 | - debug("SF: FDT decode error\n"); | |
555 | - goto err_manufacturer_probe; | |
556 | - } | |
557 | -#endif | |
558 | -#ifndef CONFIG_SPL_BUILD | |
559 | - printf("SF: Detected %s with page size ", flash->name); | |
560 | - print_size(flash->sector_size, ", total "); | |
561 | - print_size(flash->size, ""); | |
562 | - if (flash->memory_map) | |
563 | - printf(", mapped at %p", flash->memory_map); | |
564 | - puts("\n"); | |
565 | -#endif | |
566 | -#ifndef CONFIG_SPI_FLASH_BAR | |
567 | - if (flash->size > SPI_FLASH_16MB_BOUN) { | |
568 | - puts("SF: Warning - Only lower 16MiB accessible,"); | |
569 | - puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | |
570 | - } | |
571 | -#endif | |
572 | - | |
573 | - spi_release_bus(spi); | |
574 | - | |
575 | - return flash; | |
576 | - | |
577 | -err_manufacturer_probe: | |
578 | -err_read_id: | |
579 | - spi_release_bus(spi); | |
580 | -err_claim_bus: | |
581 | - spi_free_slave(spi); | |
582 | - return NULL; | |
583 | -} | |
584 | - | |
585 | -void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, | |
586 | - const char *name) | |
587 | -{ | |
588 | - struct spi_flash *flash; | |
589 | - void *ptr; | |
590 | - | |
591 | - ptr = malloc(size); | |
592 | - if (!ptr) { | |
593 | - debug("SF: Failed to allocate memory\n"); | |
594 | - return NULL; | |
595 | - } | |
596 | - memset(ptr, '\0', size); | |
597 | - flash = (struct spi_flash *)(ptr + offset); | |
598 | - | |
599 | - /* Set up some basic fields - caller will sort out sizes */ | |
600 | - flash->spi = spi; | |
601 | - flash->name = name; | |
602 | - flash->poll_cmd = CMD_READ_STATUS; | |
603 | - | |
604 | - flash->read = spi_flash_cmd_read_fast; | |
605 | - flash->write = spi_flash_cmd_write_multi; | |
606 | - flash->erase = spi_flash_cmd_erase; | |
607 | - | |
608 | - return flash; | |
609 | -} | |
610 | - | |
611 | -void spi_flash_free(struct spi_flash *flash) | |
612 | -{ | |
613 | - spi_free_slave(flash->spi); | |
614 | - free(flash); | |
53 | + return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); | |
615 | 54 | } |
drivers/mtd/spi/spi_flash_ops.c
1 | +/* | |
2 | + * SPI flash operations | |
3 | + * | |
4 | + * Copyright (C) 2008 Atmel Corporation | |
5 | + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik | |
6 | + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | |
7 | + * | |
8 | + * Licensed under the GPL-2 or later. | |
9 | + */ | |
10 | + | |
11 | +#include <common.h> | |
12 | +#include <spi.h> | |
13 | +#include <spi_flash.h> | |
14 | +#include <watchdog.h> | |
15 | + | |
16 | +#include "spi_flash_internal.h" | |
17 | + | |
18 | +static void spi_flash_addr(u32 addr, u8 *cmd) | |
19 | +{ | |
20 | + /* cmd[0] is actual command */ | |
21 | + cmd[1] = addr >> 16; | |
22 | + cmd[2] = addr >> 8; | |
23 | + cmd[3] = addr >> 0; | |
24 | +} | |
25 | + | |
26 | +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) | |
27 | +{ | |
28 | + u8 cmd; | |
29 | + int ret; | |
30 | + | |
31 | + cmd = CMD_WRITE_STATUS; | |
32 | + ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); | |
33 | + if (ret < 0) { | |
34 | + debug("SF: fail to write status register\n"); | |
35 | + return ret; | |
36 | + } | |
37 | + | |
38 | + return 0; | |
39 | +} | |
40 | + | |
41 | +#ifdef CONFIG_SPI_FLASH_BAR | |
42 | +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) | |
43 | +{ | |
44 | + u8 cmd; | |
45 | + int ret; | |
46 | + | |
47 | + if (flash->bank_curr == bank_sel) { | |
48 | + debug("SF: not require to enable bank%d\n", bank_sel); | |
49 | + return 0; | |
50 | + } | |
51 | + | |
52 | + cmd = flash->bank_write_cmd; | |
53 | + ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); | |
54 | + if (ret < 0) { | |
55 | + debug("SF: fail to write bank register\n"); | |
56 | + return ret; | |
57 | + } | |
58 | + flash->bank_curr = bank_sel; | |
59 | + | |
60 | + return 0; | |
61 | +} | |
62 | +#endif | |
63 | + | |
64 | +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) | |
65 | +{ | |
66 | + struct spi_slave *spi = flash->spi; | |
67 | + unsigned long timebase; | |
68 | + int ret; | |
69 | + u8 status; | |
70 | + u8 check_status = 0x0; | |
71 | + u8 poll_bit = STATUS_WIP; | |
72 | + u8 cmd = flash->poll_cmd; | |
73 | + | |
74 | + if (cmd == CMD_FLAG_STATUS) { | |
75 | + poll_bit = STATUS_PEC; | |
76 | + check_status = poll_bit; | |
77 | + } | |
78 | + | |
79 | + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); | |
80 | + if (ret) { | |
81 | + debug("SF: fail to read %s status register\n", | |
82 | + cmd == CMD_READ_STATUS ? "read" : "flag"); | |
83 | + return ret; | |
84 | + } | |
85 | + | |
86 | + timebase = get_timer(0); | |
87 | + do { | |
88 | + WATCHDOG_RESET(); | |
89 | + | |
90 | + ret = spi_xfer(spi, 8, NULL, &status, 0); | |
91 | + if (ret) | |
92 | + return -1; | |
93 | + | |
94 | + if ((status & poll_bit) == check_status) | |
95 | + break; | |
96 | + | |
97 | + } while (get_timer(timebase) < timeout); | |
98 | + | |
99 | + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); | |
100 | + | |
101 | + if ((status & poll_bit) == check_status) | |
102 | + return 0; | |
103 | + | |
104 | + /* Timed out */ | |
105 | + debug("SF: time out!\n"); | |
106 | + return -1; | |
107 | +} | |
108 | + | |
109 | +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, | |
110 | + size_t cmd_len, const void *buf, size_t buf_len) | |
111 | +{ | |
112 | + struct spi_slave *spi = flash->spi; | |
113 | + unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; | |
114 | + int ret; | |
115 | + | |
116 | + if (buf == NULL) | |
117 | + timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; | |
118 | + | |
119 | + ret = spi_claim_bus(flash->spi); | |
120 | + if (ret) { | |
121 | + debug("SF: unable to claim SPI bus\n"); | |
122 | + return ret; | |
123 | + } | |
124 | + | |
125 | + ret = spi_flash_cmd_write_enable(flash); | |
126 | + if (ret < 0) { | |
127 | + debug("SF: enabling write failed\n"); | |
128 | + return ret; | |
129 | + } | |
130 | + | |
131 | + ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); | |
132 | + if (ret < 0) { | |
133 | + debug("SF: write cmd failed\n"); | |
134 | + return ret; | |
135 | + } | |
136 | + | |
137 | + ret = spi_flash_cmd_wait_ready(flash, timeout); | |
138 | + if (ret < 0) { | |
139 | + debug("SF: write %s timed out\n", | |
140 | + timeout == SPI_FLASH_PROG_TIMEOUT ? | |
141 | + "program" : "page erase"); | |
142 | + return ret; | |
143 | + } | |
144 | + | |
145 | + spi_release_bus(spi); | |
146 | + | |
147 | + return ret; | |
148 | +} | |
149 | + | |
150 | +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) | |
151 | +{ | |
152 | + u32 erase_size; | |
153 | + u8 cmd[4]; | |
154 | + int ret = -1; | |
155 | + | |
156 | + erase_size = flash->sector_size; | |
157 | + if (offset % erase_size || len % erase_size) { | |
158 | + debug("SF: Erase offset/length not multiple of erase size\n"); | |
159 | + return -1; | |
160 | + } | |
161 | + | |
162 | + if (erase_size == 4096) | |
163 | + cmd[0] = CMD_ERASE_4K; | |
164 | + else | |
165 | + cmd[0] = CMD_ERASE_64K; | |
166 | + | |
167 | + while (len) { | |
168 | +#ifdef CONFIG_SPI_FLASH_BAR | |
169 | + u8 bank_sel; | |
170 | + | |
171 | + bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
172 | + | |
173 | + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
174 | + if (ret) { | |
175 | + debug("SF: fail to set bank%d\n", bank_sel); | |
176 | + return ret; | |
177 | + } | |
178 | +#endif | |
179 | + spi_flash_addr(offset, cmd); | |
180 | + | |
181 | + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | |
182 | + cmd[2], cmd[3], offset); | |
183 | + | |
184 | + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | |
185 | + if (ret < 0) { | |
186 | + debug("SF: erase failed\n"); | |
187 | + break; | |
188 | + } | |
189 | + | |
190 | + offset += erase_size; | |
191 | + len -= erase_size; | |
192 | + } | |
193 | + | |
194 | + return ret; | |
195 | +} | |
196 | + | |
197 | +int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, | |
198 | + size_t len, const void *buf) | |
199 | +{ | |
200 | + unsigned long byte_addr, page_size; | |
201 | + size_t chunk_len, actual; | |
202 | + u8 cmd[4]; | |
203 | + int ret = -1; | |
204 | + | |
205 | + page_size = flash->page_size; | |
206 | + | |
207 | + cmd[0] = CMD_PAGE_PROGRAM; | |
208 | + for (actual = 0; actual < len; actual += chunk_len) { | |
209 | +#ifdef CONFIG_SPI_FLASH_BAR | |
210 | + u8 bank_sel; | |
211 | + | |
212 | + bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
213 | + | |
214 | + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
215 | + if (ret) { | |
216 | + debug("SF: fail to set bank%d\n", bank_sel); | |
217 | + return ret; | |
218 | + } | |
219 | +#endif | |
220 | + byte_addr = offset % page_size; | |
221 | + chunk_len = min(len - actual, page_size - byte_addr); | |
222 | + | |
223 | + if (flash->spi->max_write_size) | |
224 | + chunk_len = min(chunk_len, flash->spi->max_write_size); | |
225 | + | |
226 | + spi_flash_addr(offset, cmd); | |
227 | + | |
228 | + debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", | |
229 | + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); | |
230 | + | |
231 | + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | |
232 | + buf + actual, chunk_len); | |
233 | + if (ret < 0) { | |
234 | + debug("SF: write failed\n"); | |
235 | + break; | |
236 | + } | |
237 | + | |
238 | + offset += chunk_len; | |
239 | + } | |
240 | + | |
241 | + return ret; | |
242 | +} | |
243 | + | |
244 | +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | |
245 | + size_t cmd_len, void *data, size_t data_len) | |
246 | +{ | |
247 | + struct spi_slave *spi = flash->spi; | |
248 | + int ret; | |
249 | + | |
250 | + ret = spi_claim_bus(flash->spi); | |
251 | + if (ret) { | |
252 | + debug("SF: unable to claim SPI bus\n"); | |
253 | + return ret; | |
254 | + } | |
255 | + | |
256 | + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); | |
257 | + if (ret < 0) { | |
258 | + debug("SF: read cmd failed\n"); | |
259 | + return ret; | |
260 | + } | |
261 | + | |
262 | + spi_release_bus(spi); | |
263 | + | |
264 | + return ret; | |
265 | +} | |
266 | + | |
267 | +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, | |
268 | + size_t len, void *data) | |
269 | +{ | |
270 | + u8 cmd[5], bank_sel = 0; | |
271 | + u32 remain_len, read_len; | |
272 | + int ret = -1; | |
273 | + | |
274 | + /* Handle memory-mapped SPI */ | |
275 | + if (flash->memory_map) { | |
276 | + memcpy(data, flash->memory_map + offset, len); | |
277 | + return 0; | |
278 | + } | |
279 | + | |
280 | + cmd[0] = CMD_READ_ARRAY_FAST; | |
281 | + cmd[4] = 0x00; | |
282 | + | |
283 | + while (len) { | |
284 | +#ifdef CONFIG_SPI_FLASH_BAR | |
285 | + bank_sel = offset / SPI_FLASH_16MB_BOUN; | |
286 | + | |
287 | + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); | |
288 | + if (ret) { | |
289 | + debug("SF: fail to set bank%d\n", bank_sel); | |
290 | + return ret; | |
291 | + } | |
292 | +#endif | |
293 | + remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); | |
294 | + if (len < remain_len) | |
295 | + read_len = len; | |
296 | + else | |
297 | + read_len = remain_len; | |
298 | + | |
299 | + spi_flash_addr(offset, cmd); | |
300 | + | |
301 | + ret = spi_flash_read_common(flash, cmd, sizeof(cmd), | |
302 | + data, read_len); | |
303 | + if (ret < 0) { | |
304 | + debug("SF: read failed\n"); | |
305 | + break; | |
306 | + } | |
307 | + | |
308 | + offset += read_len; | |
309 | + len -= read_len; | |
310 | + data += read_len; | |
311 | + } | |
312 | + | |
313 | + return ret; | |
314 | +} |
drivers/mtd/spi/spi_flash_probe.c
1 | +/* | |
2 | + * SPI flash probing | |
3 | + * | |
4 | + * Copyright (C) 2008 Atmel Corporation | |
5 | + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik | |
6 | + * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. | |
7 | + * | |
8 | + * Licensed under the GPL-2 or later. | |
9 | + */ | |
10 | + | |
11 | +#include <common.h> | |
12 | +#include <fdtdec.h> | |
13 | +#include <malloc.h> | |
14 | +#include <spi.h> | |
15 | +#include <spi_flash.h> | |
16 | + | |
17 | +#include "spi_flash_internal.h" | |
18 | + | |
19 | +DECLARE_GLOBAL_DATA_PTR; | |
20 | + | |
21 | +#ifdef CONFIG_SPI_FLASH_BAR | |
22 | +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) | |
23 | +{ | |
24 | + u8 cmd; | |
25 | + u8 curr_bank = 0; | |
26 | + | |
27 | + /* discover bank cmds */ | |
28 | + switch (idcode0) { | |
29 | + case SPI_FLASH_SPANSION_IDCODE0: | |
30 | + flash->bank_read_cmd = CMD_BANKADDR_BRRD; | |
31 | + flash->bank_write_cmd = CMD_BANKADDR_BRWR; | |
32 | + break; | |
33 | + case SPI_FLASH_STMICRO_IDCODE0: | |
34 | + case SPI_FLASH_WINBOND_IDCODE0: | |
35 | + flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; | |
36 | + flash->bank_write_cmd = CMD_EXTNADDR_WREAR; | |
37 | + break; | |
38 | + default: | |
39 | + printf("SF: Unsupported bank commands %02x\n", idcode0); | |
40 | + return -1; | |
41 | + } | |
42 | + | |
43 | + /* read the bank reg - on which bank the flash is in currently */ | |
44 | + cmd = flash->bank_read_cmd; | |
45 | + if (flash->size > SPI_FLASH_16MB_BOUN) { | |
46 | + if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { | |
47 | + debug("SF: fail to read bank addr register\n"); | |
48 | + return -1; | |
49 | + } | |
50 | + flash->bank_curr = curr_bank; | |
51 | + } else { | |
52 | + flash->bank_curr = curr_bank; | |
53 | + } | |
54 | + | |
55 | + return 0; | |
56 | +} | |
57 | +#endif | |
58 | + | |
59 | +#ifdef CONFIG_OF_CONTROL | |
60 | +int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) | |
61 | +{ | |
62 | + fdt_addr_t addr; | |
63 | + fdt_size_t size; | |
64 | + int node; | |
65 | + | |
66 | + /* If there is no node, do nothing */ | |
67 | + node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); | |
68 | + if (node < 0) | |
69 | + return 0; | |
70 | + | |
71 | + addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); | |
72 | + if (addr == FDT_ADDR_T_NONE) { | |
73 | + debug("%s: Cannot decode address\n", __func__); | |
74 | + return 0; | |
75 | + } | |
76 | + | |
77 | + if (flash->size != size) { | |
78 | + debug("%s: Memory map must cover entire device\n", __func__); | |
79 | + return -1; | |
80 | + } | |
81 | + flash->memory_map = (void *)addr; | |
82 | + | |
83 | + return 0; | |
84 | +} | |
85 | +#endif /* CONFIG_OF_CONTROL */ | |
86 | + | |
87 | +/* | |
88 | + * The following table holds all device probe functions | |
89 | + * | |
90 | + * shift: number of continuation bytes before the ID | |
91 | + * idcode: the expected IDCODE or 0xff for non JEDEC devices | |
92 | + * probe: the function to call | |
93 | + * | |
94 | + * Non JEDEC devices should be ordered in the table such that | |
95 | + * the probe functions with best detection algorithms come first. | |
96 | + * | |
97 | + * Several matching entries are permitted, they will be tried | |
98 | + * in sequence until a probe function returns non NULL. | |
99 | + * | |
100 | + * IDCODE_CONT_LEN may be redefined if a device needs to declare a | |
101 | + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be | |
102 | + * changed. This is the max number of bytes probe functions may | |
103 | + * examine when looking up part-specific identification info. | |
104 | + * | |
105 | + * Probe functions will be given the idcode buffer starting at their | |
106 | + * manu id byte (the "idcode" in the table below). In other words, | |
107 | + * all of the continuation bytes will be skipped (the "shift" below). | |
108 | + */ | |
109 | +#define IDCODE_CONT_LEN 0 | |
110 | +#define IDCODE_PART_LEN 5 | |
111 | +static const struct { | |
112 | + const u8 shift; | |
113 | + const u8 idcode; | |
114 | + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); | |
115 | +} flashes[] = { | |
116 | + /* Keep it sorted by define name */ | |
117 | +#ifdef CONFIG_SPI_FLASH_ATMEL | |
118 | + { 0, 0x1f, spi_flash_probe_atmel, }, | |
119 | +#endif | |
120 | +#ifdef CONFIG_SPI_FLASH_EON | |
121 | + { 0, 0x1c, spi_flash_probe_eon, }, | |
122 | +#endif | |
123 | +#ifdef CONFIG_SPI_FLASH_GIGADEVICE | |
124 | + { 0, 0xc8, spi_flash_probe_gigadevice, }, | |
125 | +#endif | |
126 | +#ifdef CONFIG_SPI_FLASH_MACRONIX | |
127 | + { 0, 0xc2, spi_flash_probe_macronix, }, | |
128 | +#endif | |
129 | +#ifdef CONFIG_SPI_FLASH_SPANSION | |
130 | + { 0, 0x01, spi_flash_probe_spansion, }, | |
131 | +#endif | |
132 | +#ifdef CONFIG_SPI_FLASH_SST | |
133 | + { 0, 0xbf, spi_flash_probe_sst, }, | |
134 | +#endif | |
135 | +#ifdef CONFIG_SPI_FLASH_STMICRO | |
136 | + { 0, 0x20, spi_flash_probe_stmicro, }, | |
137 | +#endif | |
138 | +#ifdef CONFIG_SPI_FLASH_WINBOND | |
139 | + { 0, 0xef, spi_flash_probe_winbond, }, | |
140 | +#endif | |
141 | +#ifdef CONFIG_SPI_FRAM_RAMTRON | |
142 | + { 6, 0xc2, spi_fram_probe_ramtron, }, | |
143 | +# undef IDCODE_CONT_LEN | |
144 | +# define IDCODE_CONT_LEN 6 | |
145 | +#endif | |
146 | + /* Keep it sorted by best detection */ | |
147 | +#ifdef CONFIG_SPI_FLASH_STMICRO | |
148 | + { 0, 0xff, spi_flash_probe_stmicro, }, | |
149 | +#endif | |
150 | +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC | |
151 | + { 0, 0xff, spi_fram_probe_ramtron, }, | |
152 | +#endif | |
153 | +}; | |
154 | +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) | |
155 | + | |
156 | +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, | |
157 | + unsigned int max_hz, unsigned int spi_mode) | |
158 | +{ | |
159 | + struct spi_slave *spi; | |
160 | + struct spi_flash *flash = NULL; | |
161 | + int ret, i, shift; | |
162 | + u8 idcode[IDCODE_LEN], *idp; | |
163 | + | |
164 | + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); | |
165 | + if (!spi) { | |
166 | + printf("SF: Failed to set up slave\n"); | |
167 | + return NULL; | |
168 | + } | |
169 | + | |
170 | + ret = spi_claim_bus(spi); | |
171 | + if (ret) { | |
172 | + debug("SF: Failed to claim SPI bus: %d\n", ret); | |
173 | + goto err_claim_bus; | |
174 | + } | |
175 | + | |
176 | + /* Read the ID codes */ | |
177 | + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); | |
178 | + if (ret) | |
179 | + goto err_read_id; | |
180 | + | |
181 | +#ifdef DEBUG | |
182 | + printf("SF: Got idcodes\n"); | |
183 | + print_buffer(0, idcode, 1, sizeof(idcode), 0); | |
184 | +#endif | |
185 | + | |
186 | + /* count the number of continuation bytes */ | |
187 | + for (shift = 0, idp = idcode; | |
188 | + shift < IDCODE_CONT_LEN && *idp == 0x7f; | |
189 | + ++shift, ++idp) | |
190 | + continue; | |
191 | + | |
192 | + /* search the table for matches in shift and id */ | |
193 | + for (i = 0; i < ARRAY_SIZE(flashes); ++i) | |
194 | + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { | |
195 | + /* we have a match, call probe */ | |
196 | + flash = flashes[i].probe(spi, idp); | |
197 | + if (flash) | |
198 | + break; | |
199 | + } | |
200 | + | |
201 | + if (!flash) { | |
202 | + printf("SF: Unsupported manufacturer %02x\n", *idp); | |
203 | + goto err_manufacturer_probe; | |
204 | + } | |
205 | + | |
206 | +#ifdef CONFIG_SPI_FLASH_BAR | |
207 | + /* Configure the BAR - disover bank cmds and read current bank */ | |
208 | + ret = spi_flash_bank_config(flash, *idp); | |
209 | + if (ret < 0) | |
210 | + goto err_manufacturer_probe; | |
211 | +#endif | |
212 | + | |
213 | +#ifdef CONFIG_OF_CONTROL | |
214 | + if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { | |
215 | + debug("SF: FDT decode error\n"); | |
216 | + goto err_manufacturer_probe; | |
217 | + } | |
218 | +#endif | |
219 | +#ifndef CONFIG_SPL_BUILD | |
220 | + printf("SF: Detected %s with page size ", flash->name); | |
221 | + print_size(flash->sector_size, ", total "); | |
222 | + print_size(flash->size, ""); | |
223 | + if (flash->memory_map) | |
224 | + printf(", mapped at %p", flash->memory_map); | |
225 | + puts("\n"); | |
226 | +#endif | |
227 | +#ifndef CONFIG_SPI_FLASH_BAR | |
228 | + if (flash->size > SPI_FLASH_16MB_BOUN) { | |
229 | + puts("SF: Warning - Only lower 16MiB accessible,"); | |
230 | + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | |
231 | + } | |
232 | +#endif | |
233 | + | |
234 | + spi_release_bus(spi); | |
235 | + | |
236 | + return flash; | |
237 | + | |
238 | +err_manufacturer_probe: | |
239 | +err_read_id: | |
240 | + spi_release_bus(spi); | |
241 | +err_claim_bus: | |
242 | + spi_free_slave(spi); | |
243 | + return NULL; | |
244 | +} | |
245 | + | |
246 | +void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, | |
247 | + const char *name) | |
248 | +{ | |
249 | + struct spi_flash *flash; | |
250 | + void *ptr; | |
251 | + | |
252 | + ptr = malloc(size); | |
253 | + if (!ptr) { | |
254 | + debug("SF: Failed to allocate memory\n"); | |
255 | + return NULL; | |
256 | + } | |
257 | + memset(ptr, '\0', size); | |
258 | + flash = (struct spi_flash *)(ptr + offset); | |
259 | + | |
260 | + /* Set up some basic fields - caller will sort out sizes */ | |
261 | + flash->spi = spi; | |
262 | + flash->name = name; | |
263 | + flash->poll_cmd = CMD_READ_STATUS; | |
264 | + | |
265 | + flash->read = spi_flash_cmd_read_fast; | |
266 | + flash->write = spi_flash_cmd_write_multi; | |
267 | + flash->erase = spi_flash_cmd_erase; | |
268 | + | |
269 | + return flash; | |
270 | +} | |
271 | + | |
272 | +void spi_flash_free(struct spi_flash *flash) | |
273 | +{ | |
274 | + spi_free_slave(flash->spi); | |
275 | + free(flash); | |
276 | +} |