]>
Commit | Line | Data |
---|---|---|
9ce7e53a MF |
1 | /* |
2 | * SPI flash driver | |
3 | * | |
4 | * Enter bugs at http://blackfin.uclinux.org/ | |
5 | * | |
6 | * Copyright (c) 2005-2007 Analog Devices Inc. | |
7 | * | |
8 | * Licensed under the GPL-2 or later. | |
9 | */ | |
10 | ||
11 | /* Configuration options: | |
12 | * CONFIG_SPI_BAUD - value to load into SPI_BAUD (divisor of SCLK to get SPI CLK) | |
13 | * CONFIG_SPI_FLASH_SLOW_READ - force usage of the slower read | |
14 | * WARNING: make sure your SCLK + SPI_BAUD is slow enough | |
15 | */ | |
16 | ||
17 | #include <common.h> | |
18 | #include <malloc.h> | |
19 | #include <asm/io.h> | |
20 | #include <asm/mach-common/bits/spi.h> | |
21 | ||
22 | /* Forcibly phase out these */ | |
23 | #ifdef CONFIG_SPI_FLASH_NUM_SECTORS | |
24 | # error do not set CONFIG_SPI_FLASH_NUM_SECTORS | |
25 | #endif | |
26 | #ifdef CONFIG_SPI_FLASH_SECTOR_SIZE | |
27 | # error do not set CONFIG_SPI_FLASH_SECTOR_SIZE | |
28 | #endif | |
29 | ||
30 | #if defined(CONFIG_SPI) | |
31 | ||
32 | struct flash_info { | |
33 | char *name; | |
34 | uint16_t id; | |
35 | unsigned sector_size; | |
36 | unsigned num_sectors; | |
37 | }; | |
38 | ||
39 | /* SPI Speeds: 50 MHz / 33 MHz */ | |
40 | static struct flash_info flash_spansion_serial_flash[] = { | |
41 | { "S25FL016", 0x0215, 64 * 1024, 32 }, | |
42 | { "S25FL032", 0x0216, 64 * 1024, 64 }, | |
43 | { "S25FL064", 0x0217, 64 * 1024, 128 }, | |
44 | { "S25FL0128", 0x0218, 256 * 1024, 64 }, | |
45 | { NULL, 0, 0, 0 } | |
46 | }; | |
47 | ||
48 | /* SPI Speeds: 50 MHz / 20 MHz */ | |
49 | static struct flash_info flash_st_serial_flash[] = { | |
50 | { "m25p05", 0x2010, 32 * 1024, 2 }, | |
51 | { "m25p10", 0x2011, 32 * 1024, 4 }, | |
52 | { "m25p20", 0x2012, 64 * 1024, 4 }, | |
53 | { "m25p40", 0x2013, 64 * 1024, 8 }, | |
54 | { "m25p16", 0x2015, 64 * 1024, 32 }, | |
55 | { "m25p32", 0x2016, 64 * 1024, 64 }, | |
56 | { "m25p64", 0x2017, 64 * 1024, 128 }, | |
57 | { "m25p128", 0x2018, 256 * 1024, 64 }, | |
58 | { NULL, 0, 0, 0 } | |
59 | }; | |
60 | ||
61 | /* SPI Speeds: 66 MHz / 33 MHz */ | |
62 | static struct flash_info flash_atmel_dataflash[] = { | |
63 | { "AT45DB011x", 0x0c, 264, 512 }, | |
64 | { "AT45DB021x", 0x14, 264, 1025 }, | |
65 | { "AT45DB041x", 0x1c, 264, 2048 }, | |
66 | { "AT45DB081x", 0x24, 264, 4096 }, | |
67 | { "AT45DB161x", 0x2c, 528, 4096 }, | |
68 | { "AT45DB321x", 0x34, 528, 8192 }, | |
69 | { "AT45DB642x", 0x3c, 1056, 8192 }, | |
70 | { NULL, 0, 0, 0 } | |
71 | }; | |
72 | ||
73 | /* SPI Speed: 50 MHz / 25 MHz or 40 MHz / 20 MHz */ | |
74 | static struct flash_info flash_winbond_serial_flash[] = { | |
75 | { "W25X10", 0x3011, 16 * 256, 32 }, | |
76 | { "W25X20", 0x3012, 16 * 256, 64 }, | |
77 | { "W25X40", 0x3013, 16 * 256, 128 }, | |
78 | { "W25X80", 0x3014, 16 * 256, 256 }, | |
79 | { "W25P80", 0x2014, 256 * 256, 16 }, | |
80 | { "W25P16", 0x2015, 256 * 256, 32 }, | |
81 | { NULL, 0, 0, 0 } | |
82 | }; | |
83 | ||
84 | struct flash_ops { | |
85 | uint8_t read, write, erase, status; | |
86 | }; | |
87 | ||
88 | #ifdef CONFIG_SPI_FLASH_SLOW_READ | |
89 | # define OP_READ 0x03 | |
90 | #else | |
91 | # define OP_READ 0x0B | |
92 | #endif | |
93 | static struct flash_ops flash_st_ops = { | |
94 | .read = OP_READ, | |
95 | .write = 0x02, | |
96 | .erase = 0xD8, | |
97 | .status = 0x05, | |
98 | }; | |
99 | ||
100 | static struct flash_ops flash_atmel_ops = { | |
101 | .read = OP_READ, | |
102 | .write = 0x82, | |
103 | .erase = 0x81, | |
104 | .status = 0xD7, | |
105 | }; | |
106 | ||
107 | static struct flash_ops flash_winbond_ops = { | |
108 | .read = OP_READ, | |
109 | .write = 0x02, | |
110 | .erase = 0x20, | |
111 | .status = 0x05, | |
112 | }; | |
113 | ||
114 | struct manufacturer_info { | |
115 | const char *name; | |
116 | uint8_t id; | |
117 | struct flash_info *flashes; | |
118 | struct flash_ops *ops; | |
119 | }; | |
120 | ||
121 | static struct { | |
122 | struct manufacturer_info *manufacturer; | |
123 | struct flash_info *flash; | |
124 | struct flash_ops *ops; | |
125 | uint8_t manufacturer_id, device_id1, device_id2; | |
126 | unsigned int write_length; | |
127 | unsigned long sector_size, num_sectors; | |
128 | } flash; | |
129 | ||
130 | enum { | |
131 | JED_MANU_SPANSION = 0x01, | |
132 | JED_MANU_ST = 0x20, | |
133 | JED_MANU_ATMEL = 0x1F, | |
134 | JED_MANU_WINBOND = 0xEF, | |
135 | }; | |
136 | ||
137 | static struct manufacturer_info flash_manufacturers[] = { | |
138 | { | |
139 | .name = "Spansion", | |
140 | .id = JED_MANU_SPANSION, | |
141 | .flashes = flash_spansion_serial_flash, | |
142 | .ops = &flash_st_ops, | |
143 | }, | |
144 | { | |
145 | .name = "ST", | |
146 | .id = JED_MANU_ST, | |
147 | .flashes = flash_st_serial_flash, | |
148 | .ops = &flash_st_ops, | |
149 | }, | |
150 | { | |
151 | .name = "Atmel", | |
152 | .id = JED_MANU_ATMEL, | |
153 | .flashes = flash_atmel_dataflash, | |
154 | .ops = &flash_atmel_ops, | |
155 | }, | |
156 | { | |
157 | .name = "Winbond", | |
158 | .id = JED_MANU_WINBOND, | |
159 | .flashes = flash_winbond_serial_flash, | |
160 | .ops = &flash_winbond_ops, | |
161 | }, | |
162 | }; | |
163 | ||
164 | #define TIMEOUT 5000 /* timeout of 5 seconds */ | |
165 | ||
166 | /* BF54x support */ | |
167 | #ifndef pSPI_CTL | |
168 | # define pSPI_CTL pSPI0_CTL | |
169 | # define pSPI_BAUD pSPI0_BAUD | |
170 | # define pSPI_FLG pSPI0_FLG | |
171 | # define pSPI_RDBR pSPI0_RDBR | |
172 | # define pSPI_STAT pSPI0_STAT | |
173 | # define pSPI_TDBR pSPI0_TDBR | |
174 | # define SPI0_SCK 0x0001 | |
175 | # define SPI0_MOSI 0x0004 | |
176 | # define SPI0_MISO 0x0002 | |
177 | # define SPI0_SEL1 0x0010 | |
178 | #endif | |
179 | ||
180 | /* Default to the SPI SSEL that we boot off of: | |
181 | * BF54x, BF537, (everything new?): SSEL1 | |
182 | * BF533, BF561: SSEL2 | |
183 | */ | |
184 | #ifndef CONFIG_SPI_FLASH_SSEL | |
185 | # if defined(__ADSPBF531__) || defined(__ADSPBF532__) || \ | |
186 | defined(__ADSPBF533__) || defined(__ADSPBF561__) | |
187 | # define CONFIG_SPI_FLASH_SSEL 2 | |
188 | # else | |
189 | # define CONFIG_SPI_FLASH_SSEL 1 | |
190 | # endif | |
191 | #endif | |
192 | #define SSEL_MASK (1 << CONFIG_SPI_FLASH_SSEL) | |
193 | ||
194 | static void SPI_INIT(void) | |
195 | { | |
196 | /* [#3541] This delay appears to be necessary, but not sure | |
197 | * exactly why as the history behind it is non-existant. | |
198 | */ | |
199 | udelay(CONFIG_CCLK_HZ / 25000000); | |
200 | ||
201 | /* enable SPI pins: SSEL, MOSI, MISO, SCK */ | |
202 | #ifdef __ADSPBF54x__ | |
203 | *pPORTE_FER |= (SPI0_SCK | SPI0_MOSI | SPI0_MISO | SPI0_SEL1); | |
204 | #elif defined(__ADSPBF534__) || defined(__ADSPBF536__) || defined(__ADSPBF537__) | |
205 | *pPORTF_FER |= (PF10 | PF11 | PF12 | PF13); | |
206 | #elif defined(__ADSPBF52x__) | |
207 | bfin_write_PORTG_MUX((bfin_read_PORTG_MUX() & ~PORT_x_MUX_0_MASK) | PORT_x_MUX_0_FUNC_3); | |
208 | bfin_write_PORTG_FER(bfin_read_PORTG_FER() | PG1 | PG2 | PG3 | PG4); | |
209 | #endif | |
210 | ||
211 | /* initate communication upon write of TDBR */ | |
212 | *pSPI_CTL = (SPE|MSTR|CPHA|CPOL|0x01); | |
213 | *pSPI_BAUD = CONFIG_SPI_BAUD; | |
214 | } | |
215 | ||
216 | static void SPI_DEINIT(void) | |
217 | { | |
218 | /* put SPI settings back to reset state */ | |
219 | *pSPI_CTL = 0x0400; | |
220 | *pSPI_BAUD = 0; | |
221 | SSYNC(); | |
222 | } | |
223 | ||
224 | static void SPI_ON(void) | |
225 | { | |
226 | /* toggle SSEL to reset the device so it'll take a new command */ | |
227 | *pSPI_FLG = 0xFF00 | SSEL_MASK; | |
228 | SSYNC(); | |
229 | ||
230 | *pSPI_FLG = ((0xFF & ~SSEL_MASK) << 8) | SSEL_MASK; | |
231 | SSYNC(); | |
232 | } | |
233 | ||
234 | static void SPI_OFF(void) | |
235 | { | |
236 | /* put SPI settings back to reset state */ | |
237 | *pSPI_FLG = 0xFF00; | |
238 | SSYNC(); | |
239 | } | |
240 | ||
241 | static uint8_t spi_write_read_byte(uint8_t transmit) | |
242 | { | |
243 | *pSPI_TDBR = transmit; | |
244 | SSYNC(); | |
245 | ||
246 | while ((*pSPI_STAT & TXS)) | |
247 | if (ctrlc()) | |
248 | break; | |
249 | while (!(*pSPI_STAT & SPIF)) | |
250 | if (ctrlc()) | |
251 | break; | |
252 | while (!(*pSPI_STAT & RXS)) | |
253 | if (ctrlc()) | |
254 | break; | |
255 | ||
256 | /* Read dummy to empty the receive register */ | |
257 | return *pSPI_RDBR; | |
258 | } | |
259 | ||
260 | static uint8_t read_status_register(void) | |
261 | { | |
262 | uint8_t status_register; | |
263 | ||
264 | /* send instruction to read status register */ | |
265 | SPI_ON(); | |
266 | spi_write_read_byte(flash.ops->status); | |
267 | /* send dummy to receive the status register */ | |
268 | status_register = spi_write_read_byte(0); | |
269 | SPI_OFF(); | |
270 | ||
271 | return status_register; | |
272 | } | |
273 | ||
274 | static int wait_for_ready_status(void) | |
275 | { | |
276 | ulong start = get_timer(0); | |
277 | ||
278 | while (get_timer(0) - start < TIMEOUT) { | |
279 | switch (flash.manufacturer_id) { | |
280 | case JED_MANU_SPANSION: | |
281 | case JED_MANU_ST: | |
282 | case JED_MANU_WINBOND: | |
283 | if (!(read_status_register() & 0x01)) | |
284 | return 0; | |
285 | break; | |
286 | ||
287 | case JED_MANU_ATMEL: | |
288 | if (read_status_register() & 0x80) | |
289 | return 0; | |
290 | break; | |
291 | } | |
292 | ||
293 | if (ctrlc()) { | |
294 | puts("\nAbort\n"); | |
295 | return -1; | |
296 | } | |
297 | } | |
298 | ||
299 | puts("Timeout\n"); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | /* Request and read the manufacturer and device id of parts which | |
304 | * are compatible with the JEDEC standard (JEP106) and use that to | |
305 | * setup other operating conditions. | |
306 | */ | |
307 | static int spi_detect_part(void) | |
308 | { | |
309 | uint16_t dev_id; | |
310 | size_t i; | |
311 | ||
312 | static char called_init; | |
313 | if (called_init) | |
314 | return 0; | |
315 | ||
316 | SPI_ON(); | |
317 | ||
318 | /* Send the request for the part identification */ | |
319 | spi_write_read_byte(0x9F); | |
320 | ||
321 | /* Now read in the manufacturer id bytes */ | |
322 | do { | |
323 | flash.manufacturer_id = spi_write_read_byte(0); | |
324 | if (flash.manufacturer_id == 0x7F) | |
325 | puts("Warning: unhandled manufacturer continuation byte!\n"); | |
326 | } while (flash.manufacturer_id == 0x7F); | |
327 | ||
328 | /* Now read in the first device id byte */ | |
329 | flash.device_id1 = spi_write_read_byte(0); | |
330 | ||
331 | /* Now read in the second device id byte */ | |
332 | flash.device_id2 = spi_write_read_byte(0); | |
333 | ||
334 | SPI_OFF(); | |
335 | ||
336 | dev_id = (flash.device_id1 << 8) | flash.device_id2; | |
337 | ||
338 | for (i = 0; i < ARRAY_SIZE(flash_manufacturers); ++i) { | |
339 | if (flash.manufacturer_id == flash_manufacturers[i].id) | |
340 | break; | |
341 | } | |
342 | if (i == ARRAY_SIZE(flash_manufacturers)) | |
343 | goto unknown; | |
344 | ||
345 | flash.manufacturer = &flash_manufacturers[i]; | |
346 | flash.ops = flash_manufacturers[i].ops; | |
347 | ||
348 | switch (flash.manufacturer_id) { | |
349 | case JED_MANU_SPANSION: | |
350 | case JED_MANU_ST: | |
351 | case JED_MANU_WINBOND: | |
352 | for (i = 0; flash.manufacturer->flashes[i].name; ++i) { | |
353 | if (dev_id == flash.manufacturer->flashes[i].id) | |
354 | break; | |
355 | } | |
356 | if (!flash.manufacturer->flashes[i].name) | |
357 | goto unknown; | |
358 | ||
359 | flash.flash = &flash.manufacturer->flashes[i]; | |
360 | flash.sector_size = flash.flash->sector_size; | |
361 | flash.num_sectors = flash.flash->num_sectors; | |
362 | flash.write_length = 256; | |
363 | break; | |
364 | ||
365 | case JED_MANU_ATMEL: { | |
366 | uint8_t status = read_status_register(); | |
367 | ||
368 | for (i = 0; flash.manufacturer->flashes[i].name; ++i) { | |
369 | if ((status & 0x3c) == flash.manufacturer->flashes[i].id) | |
370 | break; | |
371 | } | |
372 | if (!flash.manufacturer->flashes[i].name) | |
373 | goto unknown; | |
374 | ||
375 | flash.flash = &flash.manufacturer->flashes[i]; | |
376 | flash.sector_size = flash.flash->sector_size; | |
377 | flash.num_sectors = flash.flash->num_sectors; | |
378 | ||
379 | /* see if flash is in "power of 2" mode */ | |
380 | if (status & 0x1) | |
381 | flash.sector_size &= ~(1 << (ffs(flash.sector_size) - 1)); | |
382 | ||
383 | flash.write_length = flash.sector_size; | |
384 | break; | |
385 | } | |
386 | } | |
387 | ||
388 | called_init = 1; | |
389 | return 0; | |
390 | ||
391 | unknown: | |
392 | printf("Unknown SPI device: 0x%02X 0x%02X 0x%02X\n", | |
393 | flash.manufacturer_id, flash.device_id1, flash.device_id2); | |
394 | return 1; | |
395 | } | |
396 | ||
397 | /* | |
398 | * Function: spi_init_f | |
399 | * Description: Init SPI-Controller (ROM part) | |
400 | * return: --- | |
401 | */ | |
402 | void spi_init_f(void) | |
403 | { | |
404 | } | |
405 | ||
406 | /* | |
407 | * Function: spi_init_r | |
408 | * Description: Init SPI-Controller (RAM part) - | |
409 | * The malloc engine is ready and we can move our buffers to | |
410 | * normal RAM | |
411 | * return: --- | |
412 | */ | |
413 | void spi_init_r(void) | |
414 | { | |
6d0f6bcf | 415 | #if defined(CONFIG_POST) && (CONFIG_POST & CONFIG_SYS_POST_SPI) |
9ce7e53a MF |
416 | /* Our testing strategy here is pretty basic: |
417 | * - fill src memory with an 8-bit pattern | |
418 | * - write the src memory to the SPI flash | |
419 | * - read the SPI flash into the dst memory | |
420 | * - compare src and dst memory regions | |
421 | * - repeat a few times | |
422 | * The variations we test for: | |
423 | * - change the 8-bit pattern a bit | |
424 | * - change the read/write block size so we know: | |
425 | * - writes smaller/equal/larger than the buffer work | |
426 | * - writes smaller/equal/larger than the sector work | |
427 | * - change the SPI offsets so we know: | |
428 | * - writing partial sectors works | |
429 | */ | |
430 | uint8_t *mem_src, *mem_dst; | |
431 | size_t i, c, l, o; | |
432 | size_t test_count, errors; | |
433 | uint8_t pattern; | |
434 | ||
435 | SPI_INIT(); | |
436 | ||
437 | if (spi_detect_part()) | |
438 | goto out; | |
439 | eeprom_info(); | |
440 | ||
441 | ulong lengths[] = { | |
442 | flash.write_length, | |
443 | flash.write_length * 2, | |
444 | flash.write_length / 2, | |
445 | flash.sector_size, | |
446 | flash.sector_size * 2, | |
447 | flash.sector_size / 2 | |
448 | }; | |
449 | ulong offsets[] = { | |
450 | 0, | |
451 | flash.write_length, | |
452 | flash.write_length * 2, | |
453 | flash.write_length / 2, | |
454 | flash.write_length / 4, | |
455 | flash.sector_size, | |
456 | flash.sector_size * 2, | |
457 | flash.sector_size / 2, | |
458 | flash.sector_size / 4, | |
459 | }; | |
460 | ||
461 | /* the exact addresses are arbitrary ... they just need to not overlap */ | |
462 | mem_src = (void *)(0); | |
463 | mem_dst = (void *)(max(flash.write_length, flash.sector_size) * 2); | |
464 | ||
465 | test_count = 0; | |
466 | errors = 0; | |
467 | pattern = 0x00; | |
468 | ||
469 | for (i = 0; i < 16; ++i) { /* 16 = 8 bits * 2 iterations */ | |
470 | for (l = 0; l < ARRAY_SIZE(lengths); ++l) { | |
471 | for (o = 0; o < ARRAY_SIZE(offsets); ++o) { | |
472 | ulong len = lengths[l]; | |
473 | ulong off = offsets[o]; | |
474 | ||
475 | printf("Testing pattern 0x%02X of length %5lu and offset %5lu: ", pattern, len, off); | |
476 | ||
477 | /* setup the source memory region */ | |
478 | memset(mem_src, pattern, len); | |
479 | ||
480 | test_count += 4; | |
481 | for (c = 0; c < 4; ++c) { /* 4 is just a random repeat count */ | |
482 | if (ctrlc()) { | |
483 | puts("\nAbort\n"); | |
484 | goto out; | |
485 | } | |
486 | ||
487 | /* make sure background fill pattern != pattern */ | |
488 | memset(mem_dst, pattern ^ 0xFF, len); | |
489 | ||
490 | /* write out the source memory and then read it back and compare */ | |
491 | eeprom_write(0, off, mem_src, len); | |
492 | eeprom_read(0, off, mem_dst, len); | |
493 | ||
494 | if (memcmp(mem_src, mem_dst, len)) { | |
495 | for (c = 0; c < len; ++c) | |
496 | if (mem_src[c] != mem_dst[c]) | |
497 | break; | |
498 | printf(" FAIL @ offset %u, skipping repeats ", c); | |
499 | ++errors; | |
500 | break; | |
501 | } | |
502 | ||
503 | /* XXX: should shrink write region here to test with | |
504 | * leading/trailing canaries so we know surrounding | |
505 | * bytes don't get screwed. | |
506 | */ | |
507 | } | |
508 | puts("\n"); | |
509 | } | |
510 | } | |
511 | ||
512 | /* invert the pattern every other run and shift out bits slowly */ | |
513 | pattern ^= 0xFF; | |
514 | if (i % 2) | |
515 | pattern = (pattern | 0x01) << 1; | |
516 | } | |
517 | ||
518 | if (errors) | |
519 | printf("SPI FAIL: Out of %i tests, there were %i errors ;(\n", test_count, errors); | |
520 | else | |
521 | printf("SPI PASS: %i tests worked!\n", test_count); | |
522 | ||
523 | out: | |
524 | SPI_DEINIT(); | |
525 | ||
526 | #endif | |
527 | } | |
528 | ||
529 | static void transmit_address(uint32_t addr) | |
530 | { | |
531 | /* Send the highest byte of the 24 bit address at first */ | |
532 | spi_write_read_byte(addr >> 16); | |
533 | /* Send the middle byte of the 24 bit address at second */ | |
534 | spi_write_read_byte(addr >> 8); | |
535 | /* Send the lowest byte of the 24 bit address finally */ | |
536 | spi_write_read_byte(addr); | |
537 | } | |
538 | ||
539 | /* | |
540 | * Read a value from flash for verify purpose | |
541 | * Inputs: unsigned long ulStart - holds the SPI start address | |
542 | * int pnData - pointer to store value read from flash | |
543 | * long lCount - number of elements to read | |
544 | */ | |
545 | static int read_flash(unsigned long address, long count, uchar *buffer) | |
546 | { | |
547 | size_t i; | |
548 | ||
549 | /* Send the read command to SPI device */ | |
550 | SPI_ON(); | |
551 | spi_write_read_byte(flash.ops->read); | |
552 | transmit_address(address); | |
553 | ||
554 | #ifndef CONFIG_SPI_FLASH_SLOW_READ | |
555 | /* Send dummy byte when doing SPI fast reads */ | |
556 | spi_write_read_byte(0); | |
557 | #endif | |
558 | ||
559 | /* After the SPI device address has been placed on the MOSI pin the data can be */ | |
560 | /* received on the MISO pin. */ | |
561 | for (i = 1; i <= count; ++i) { | |
562 | *buffer++ = spi_write_read_byte(0); | |
563 | if (i % flash.sector_size == 0) | |
564 | puts("."); | |
565 | } | |
566 | ||
567 | SPI_OFF(); | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | static int enable_writing(void) | |
573 | { | |
574 | ulong start; | |
575 | ||
576 | if (flash.manufacturer_id == JED_MANU_ATMEL) | |
577 | return 0; | |
578 | ||
579 | /* A write enable instruction must previously have been executed */ | |
580 | SPI_ON(); | |
581 | spi_write_read_byte(0x06); | |
582 | SPI_OFF(); | |
583 | ||
584 | /* The status register will be polled to check the write enable latch "WREN" */ | |
585 | start = get_timer(0); | |
586 | while (get_timer(0) - start < TIMEOUT) { | |
587 | if (read_status_register() & 0x02) | |
588 | return 0; | |
589 | ||
590 | if (ctrlc()) { | |
591 | puts("\nAbort\n"); | |
592 | return -1; | |
593 | } | |
594 | } | |
595 | ||
596 | puts("Timeout\n"); | |
597 | return -1; | |
598 | } | |
599 | ||
600 | static long address_to_sector(unsigned long address) | |
601 | { | |
602 | if (address > (flash.num_sectors * flash.sector_size) - 1) | |
603 | return -1; | |
604 | return address / flash.sector_size; | |
605 | } | |
606 | ||
607 | static int erase_sector(int address) | |
608 | { | |
609 | /* sector gets checked in higher function, so assume it's valid | |
610 | * here and figure out the offset of the sector in flash | |
611 | */ | |
612 | if (enable_writing()) | |
613 | return -1; | |
614 | ||
615 | /* | |
616 | * Send the erase block command to the flash followed by the 24 address | |
617 | * to point to the start of a sector | |
618 | */ | |
619 | SPI_ON(); | |
620 | spi_write_read_byte(flash.ops->erase); | |
621 | transmit_address(address); | |
622 | SPI_OFF(); | |
623 | ||
624 | return wait_for_ready_status(); | |
625 | } | |
626 | ||
627 | /* Write [count] bytes out of [buffer] into the given SPI [address] */ | |
628 | static long write_flash(unsigned long address, long count, uchar *buffer) | |
629 | { | |
630 | long i, write_buffer_size; | |
631 | ||
632 | if (enable_writing()) | |
633 | return -1; | |
634 | ||
635 | /* Send write command followed by the 24 bit address */ | |
636 | SPI_ON(); | |
637 | spi_write_read_byte(flash.ops->write); | |
638 | transmit_address(address); | |
639 | ||
640 | /* Shoot out a single write buffer */ | |
641 | write_buffer_size = min(count, flash.write_length); | |
642 | for (i = 0; i < write_buffer_size; ++i) | |
643 | spi_write_read_byte(buffer[i]); | |
644 | ||
645 | SPI_OFF(); | |
646 | ||
647 | /* Wait for the flash to do its thing */ | |
648 | if (wait_for_ready_status()) { | |
649 | puts("SPI Program Time out! "); | |
650 | return -1; | |
651 | } | |
652 | ||
653 | return i; | |
654 | } | |
655 | ||
656 | /* Write [count] bytes out of [buffer] into the given SPI [address] */ | |
657 | static int write_sector(unsigned long address, long count, uchar *buffer) | |
658 | { | |
659 | long write_cnt; | |
660 | ||
661 | while (count != 0) { | |
662 | write_cnt = write_flash(address, count, buffer); | |
663 | if (write_cnt == -1) | |
664 | return -1; | |
665 | ||
666 | /* Now that we've sent some bytes out to the flash, update | |
667 | * our counters a bit | |
668 | */ | |
669 | count -= write_cnt; | |
670 | address += write_cnt; | |
671 | buffer += write_cnt; | |
672 | } | |
673 | ||
674 | /* return the appropriate error code */ | |
675 | return 0; | |
676 | } | |
677 | ||
678 | /* | |
679 | * Function: spi_write | |
680 | */ | |
681 | ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len) | |
682 | { | |
683 | unsigned long offset; | |
684 | int start_sector, end_sector; | |
685 | int start_byte, end_byte; | |
686 | uchar *temp = NULL; | |
687 | int num, ret = 0; | |
688 | ||
689 | SPI_INIT(); | |
690 | ||
691 | if (spi_detect_part()) | |
692 | goto out; | |
693 | ||
694 | offset = addr[0] << 16 | addr[1] << 8 | addr[2]; | |
695 | ||
696 | /* Get the start block number */ | |
697 | start_sector = address_to_sector(offset); | |
698 | if (start_sector == -1) { | |
699 | puts("Invalid sector! "); | |
700 | goto out; | |
701 | } | |
702 | end_sector = address_to_sector(offset + len - 1); | |
703 | if (end_sector == -1) { | |
704 | puts("Invalid sector! "); | |
705 | goto out; | |
706 | } | |
707 | ||
708 | /* Since flashes operate in sector units but the eeprom command | |
709 | * operates as a continuous stream of bytes, we need to emulate | |
710 | * the eeprom behavior. So here we read in the sector, overlay | |
711 | * any bytes we're actually modifying, erase the sector, and | |
712 | * then write back out the new sector. | |
713 | */ | |
714 | temp = malloc(flash.sector_size); | |
715 | if (!temp) { | |
716 | puts("Malloc for sector failed! "); | |
717 | goto out; | |
718 | } | |
719 | ||
720 | for (num = start_sector; num <= end_sector; num++) { | |
721 | unsigned long address = num * flash.sector_size; | |
722 | ||
723 | /* XXX: should add an optimization when spanning sectors: | |
724 | * No point in reading in a sector if we're going to be | |
725 | * clobbering the whole thing. Need to also add a test | |
726 | * case to make sure the optimization is correct. | |
727 | */ | |
728 | if (read_flash(address, flash.sector_size, temp)) { | |
729 | puts("Read sector failed! "); | |
730 | len = 0; | |
731 | break; | |
732 | } | |
733 | ||
734 | start_byte = max(address, offset); | |
735 | end_byte = address + flash.sector_size - 1; | |
736 | if (end_byte > (offset + len)) | |
737 | end_byte = (offset + len - 1); | |
738 | ||
739 | memcpy(temp + start_byte - address, | |
740 | buffer + start_byte - offset, | |
741 | end_byte - start_byte + 1); | |
742 | ||
743 | if (erase_sector(address)) { | |
744 | puts("Erase sector failed! "); | |
745 | goto out; | |
746 | } | |
747 | ||
748 | if (write_sector(address, flash.sector_size, temp)) { | |
749 | puts("Write sector failed! "); | |
750 | goto out; | |
751 | } | |
752 | ||
753 | puts("."); | |
754 | } | |
755 | ||
756 | ret = len; | |
757 | ||
758 | out: | |
759 | free(temp); | |
760 | ||
761 | SPI_DEINIT(); | |
762 | ||
763 | return ret; | |
764 | } | |
765 | ||
766 | /* | |
767 | * Function: spi_read | |
768 | */ | |
769 | ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len) | |
770 | { | |
771 | unsigned long offset; | |
772 | ||
773 | SPI_INIT(); | |
774 | ||
775 | if (spi_detect_part()) | |
776 | len = 0; | |
777 | else { | |
778 | offset = addr[0] << 16 | addr[1] << 8 | addr[2]; | |
779 | read_flash(offset, len, buffer); | |
780 | } | |
781 | ||
782 | SPI_DEINIT(); | |
783 | ||
784 | return len; | |
785 | } | |
786 | ||
787 | /* | |
788 | * Spit out some useful information about the SPI eeprom | |
789 | */ | |
790 | int eeprom_info(void) | |
791 | { | |
792 | int ret = 0; | |
793 | ||
794 | SPI_INIT(); | |
795 | ||
796 | if (spi_detect_part()) | |
797 | ret = 1; | |
798 | else | |
799 | printf("SPI Device: %s 0x%02X (%s) 0x%02X 0x%02X\n" | |
800 | "Parameters: num sectors = %i, sector size = %i, write size = %i\n" | |
801 | "Flash Size: %i mbit (%i mbyte)\n" | |
802 | "Status: 0x%02X\n", | |
803 | flash.flash->name, flash.manufacturer_id, flash.manufacturer->name, | |
804 | flash.device_id1, flash.device_id2, flash.num_sectors, | |
805 | flash.sector_size, flash.write_length, | |
806 | (flash.num_sectors * flash.sector_size) >> 17, | |
807 | (flash.num_sectors * flash.sector_size) >> 20, | |
808 | read_status_register()); | |
809 | ||
810 | SPI_DEINIT(); | |
811 | ||
812 | return ret; | |
813 | } | |
814 | ||
815 | #endif |