FreeCalypso > hg > fc-tourmaline
comparison src/cs/drivers/drv_app/ffs/board/drv.c @ 0:4e78acac3d88
src/{condat,cs,gpf,nucleus}: import from Selenite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:23:26 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4e78acac3d88 |
---|---|
1 /****************************************************************************** | |
2 * Flash File System (ffs) | |
3 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com | |
4 * | |
5 * ffs low level flash driver | |
6 * | |
7 * $Id: drv.c 1.30.1.6.1.51.1.1.1.13.1.11 Tue, 06 Jan 2004 14:36:52 +0100 tsj $ | |
8 * | |
9 ******************************************************************************/ | |
10 | |
11 #ifndef TARGET | |
12 #include "ffs.cfg" | |
13 #endif | |
14 | |
15 #include "fc-target.h" | |
16 | |
17 #include "ffs/ffs.h" | |
18 #include "ffs/board/drv.h" | |
19 #include "ffs/board/ffstrace.h" | |
20 | |
21 #if (TARGET == 0) | |
22 | |
23 #ifdef WIN32 | |
24 #include "windows.h" | |
25 #else //WIN32 | |
26 #include "sys/mman.h" | |
27 #include "unistd.h" | |
28 #endif //WIN32 | |
29 | |
30 #include "stdio.h" | |
31 #include "sys/types.h" | |
32 #include "sys/stat.h" | |
33 #include "fcntl.h" | |
34 #else | |
35 #include "nucleus.h" | |
36 | |
37 #endif | |
38 | |
39 | |
40 // Note that all code notes and comments pertaining to single-bank flash | |
41 // drivers are located in the AMD SB driver (amdsbdrv.c). Consider this as | |
42 // the reference. | |
43 | |
44 | |
45 /****************************************************************************** | |
46 * Globals | |
47 ******************************************************************************/ | |
48 | |
49 #if (TARGET == 1) | |
50 // NOTE: This is the size in bytes of the single-bank driver code that is | |
51 // copied to RAM. The only way to determine the amount of memory needed is | |
52 // to look into the linker output file (.map) or the assembler output of | |
53 // both amdsbdrv.obj and intelsbdrv.obj files. | |
54 #define FFSDRV_CODE_SIZE (0x200) | |
55 | |
56 uint8 ffsdrv_code[FFSDRV_CODE_SIZE]; | |
57 | |
58 #endif | |
59 | |
60 #define INTEL_UNLOCK_SLOW 1 | |
61 | |
62 struct dev_s dev; | |
63 struct ffsdrv_s ffsdrv; | |
64 | |
65 uint32 int_disable(void); | |
66 void int_enable(uint32 tmp); | |
67 | |
68 /****************************************************************************** | |
69 * Macros | |
70 ******************************************************************************/ | |
71 | |
72 #define addr2offset(address) ( (int) (address) - (int) dev.base ) | |
73 | |
74 | |
75 /****************************************************************************** | |
76 * Generic Driver Functions | |
77 ******************************************************************************/ | |
78 | |
79 void ffsdrv_generic_write(void *dst, const void *src, uint16 size) | |
80 { | |
81 uint8 *mydst = dst; | |
82 const uint8 *mysrc = src; | |
83 | |
84 if (size > 0) | |
85 { | |
86 if ((unsigned int) mydst & 1) { | |
87 ffsdrv_write_byte(mydst++, *mysrc++); | |
88 size--; | |
89 } | |
90 while (size >= 2) { | |
91 ffsdrv.write_halfword((uint16 *) mydst, | |
92 mysrc[0] | (mysrc[1] << 8)); | |
93 size -= 2; | |
94 mysrc += 2; | |
95 mydst += 2; | |
96 } | |
97 if (size == 1) | |
98 ffsdrv_write_byte(mydst++, *mysrc++); | |
99 } | |
100 } | |
101 | |
102 | |
103 /****************************************************************************** | |
104 * AMD Single Bank Driver Functions | |
105 ******************************************************************************/ | |
106 | |
107 #if (TARGET == 1) | |
108 | |
109 // Forward declaration of functions in file amdsbdrv.c | |
110 void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value); | |
111 void ffsdrv_ram_amd_sb_erase(uint8 block); | |
112 | |
113 #else // (TARGET == 0) | |
114 | |
115 // On PC these functions are empty | |
116 void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value) {} | |
117 void ffsdrv_ram_amd_sb_erase(uint8 block) {} | |
118 | |
119 #endif // (TARGET == 1) | |
120 | |
121 | |
122 /****************************************************************************** | |
123 * AMD Pseudo Single Bank Driver Functions | |
124 ******************************************************************************/ | |
125 | |
126 // This is a pseudo single-bank flash driver. It simulates a single-bank | |
127 // flash device on a dual-bank device. | |
128 | |
129 #if (TARGET == 1) | |
130 | |
131 void ffsdrv_amd_pseudo_sb_write_halfword(volatile uint16 *addr, uint16 value) | |
132 { | |
133 volatile char *flash = dev.base; | |
134 uint32 cpsr, i, x; | |
135 | |
136 ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); | |
137 | |
138 if (~*addr & value) { | |
139 ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); | |
140 return; | |
141 } | |
142 | |
143 cpsr = int_disable(); | |
144 tlw(led_on(LED_WRITE)); | |
145 | |
146 flash[0xAAAA] = 0xAA; // unlock cycle 1 | |
147 flash[0x5555] = 0x55; // unlock cycle 2 | |
148 flash[0xAAAA] = 0xA0; | |
149 *addr = value; | |
150 | |
151 while ((*dev.addr ^ dev.data) & 0x80) | |
152 ; | |
153 | |
154 tlw(led_off(LED_WRITE)); | |
155 int_enable(cpsr); | |
156 } | |
157 | |
158 // This VERY simple way of erase suspending only works because we run under | |
159 // a pre-emptive operating system, so whenever an interrupt occurs, another | |
160 // task takes the CPU, and at the end of the interrupt, FFS gets the CPU | |
161 // again. | |
162 void ffsdrv_amd_pseudo_sb_erase(uint8 block) | |
163 { | |
164 volatile char *flash = dev.base; | |
165 volatile char *addr; | |
166 uint32 cpsr; | |
167 uint16 flashpoll; | |
168 | |
169 addr = block2addr(block); | |
170 | |
171 ttw(ttr(TTrDrvErase, "e(%d)" NL, block)); | |
172 | |
173 cpsr = int_disable(); | |
174 tlw(led_on(LED_ERASE)); | |
175 | |
176 flash[0xAAAA] = 0xAA; // unlock cycle 1 | |
177 flash[0x5555] = 0x55; // unlock cycle 2 | |
178 flash[0xAAAA] = 0x80; | |
179 flash[0xAAAA] = 0xAA; // unlock cycle 1 | |
180 flash[0x5555] = 0x55; // unlock cycle 2 | |
181 *addr = 0x30; // AMD erase sector command | |
182 | |
183 // Wait for erase to finish. | |
184 while ((*addr & 0x80) == 0) { | |
185 tlw(led_toggle(LED_ERASE)); | |
186 // Poll interrupts, taking interrupt mask into account. | |
187 if (INT_REQUESTED) | |
188 { | |
189 // 1. suspend erase | |
190 // 2. enable interrupts | |
191 // .. now the interrupt code executes | |
192 // 3. disable interrupts | |
193 // 4. resume erase | |
194 | |
195 tlw(led_on(LED_ERASE_SUSPEND)); | |
196 *addr = 0xB0; | |
197 | |
198 // wait for erase suspend to finish | |
199 while ((*addr & 0x80) == 0) | |
200 ; | |
201 | |
202 tlw(led_off(LED_ERASE_SUSPEND)); | |
203 int_enable(cpsr); | |
204 | |
205 // Other interrupts and tasks run now... | |
206 | |
207 cpsr = int_disable(); | |
208 tlw(led_on(LED_ERASE_SUSPEND)); | |
209 | |
210 // Before resuming erase we must? check if the erase is really | |
211 // suspended or if it did finish | |
212 flashpoll = *addr; | |
213 *addr = 0x30; | |
214 | |
215 tlw(led_off(LED_ERASE_SUSPEND)); | |
216 } | |
217 } | |
218 | |
219 tlw(led_on(LED_ERASE)); | |
220 tlw(led_off(LED_ERASE)); | |
221 int_enable(cpsr); | |
222 } | |
223 | |
224 #else // (TARGET == 0) | |
225 | |
226 void ffsdrv_amd_pseudo_sb_write_halfword(volatile uint16 *addr, uint16 value) {} | |
227 void ffsdrv_amd_pseudo_sb_erase(uint8 block) {} | |
228 | |
229 #endif // (TARGET == 1) | |
230 | |
231 | |
232 /****************************************************************************** | |
233 * AMD Dual/Multi Bank Driver Functions | |
234 ******************************************************************************/ | |
235 | |
236 // All erase and write operations are performed atomically (interrupts | |
237 // disabled). Otherwise we cannot trust the value of dev.state and we cannot | |
238 // determine exactly how many of the command words have already been | |
239 // written. | |
240 | |
241 // in ffs_end() when we resume an erasure that was previously suspended, how | |
242 // does that affect multiple tasks doing that simultaneously? | |
243 | |
244 void ffsdrv_amd_write_end(void); | |
245 void ffsdrv_amd_erase_end(void); | |
246 | |
247 void ffsdrv_amd_write_halfword(volatile uint16 *addr, uint16 value) | |
248 { | |
249 volatile uint16 *flash = (volatile uint16 *)dev.base; | |
250 uint32 cpsr; | |
251 | |
252 tlw(led_on(LED_WRITE)); | |
253 ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); | |
254 | |
255 dev.addr = addr; | |
256 dev.data = value; | |
257 | |
258 if (~*addr & value) { | |
259 ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); | |
260 return; | |
261 } | |
262 | |
263 cpsr = int_disable(); | |
264 tlw(led_toggle(LED_WRITE_SUSPEND)); | |
265 dev.state = DEV_WRITE; | |
266 flash[0x555] = 0xAA; // unlock cycle 1 | |
267 flash[0x2AA] = 0x55; // unlock cycle 2 | |
268 flash[0x555] = 0xA0; | |
269 *addr = value; | |
270 int_enable(cpsr); | |
271 tlw(led_toggle(LED_WRITE_SUSPEND)); | |
272 | |
273 ffsdrv_amd_write_end(); | |
274 } | |
275 | |
276 void ffsdrv_amd_write(void *dst, const void *src, uint16 size) | |
277 { | |
278 uint8 *mydst = dst; | |
279 const uint8 *mysrc = src; | |
280 | |
281 if (size > 0) | |
282 { | |
283 if ((unsigned int) mydst & 1) { | |
284 ffsdrv_write_byte(mydst++, *mysrc++); | |
285 size--; | |
286 } | |
287 while (size >= 2) { | |
288 ffsdrv_amd_write_halfword((uint16 *) mydst, | |
289 mysrc[0] | (mysrc[1] << 8)); | |
290 size -= 2; | |
291 mysrc += 2; | |
292 mydst += 2; | |
293 } | |
294 if (size == 1) | |
295 ffsdrv_write_byte(mydst++, *mysrc++); | |
296 } | |
297 } | |
298 | |
299 void ffsdrv_amd_write_end(void) | |
300 { | |
301 while ((*dev.addr ^ dev.data) & 0x80) | |
302 tlw(led_toggle(LED_WRITE_SUSPEND)); | |
303 | |
304 dev.state = DEV_READ; | |
305 | |
306 tlw(led_off(LED_WRITE)); | |
307 } | |
308 | |
309 void ffsdrv_amd_erase(uint8 block) | |
310 { | |
311 volatile uint16 *flash = (volatile uint16 *)dev.base; | |
312 uint32 cpsr; | |
313 | |
314 tlw(led_on(LED_ERASE)); | |
315 ttw(ttr(TTrDrvErase, "e(%d)" NL, block)); | |
316 | |
317 dev.addr = (uint16 *) block2addr(block); | |
318 | |
319 cpsr = int_disable(); | |
320 dev.state = DEV_ERASE; | |
321 flash[0x555] = 0xAA; // unlock cycle 1 | |
322 flash[0x2AA] = 0x55; // unlock cycle 2 | |
323 flash[0x555] = 0x80; | |
324 flash[0x555] = 0xAA; // unlock cycle 1 | |
325 flash[0x2AA] = 0x55; // unlock cycle 2 | |
326 *dev.addr = 0x30; // AMD erase sector command | |
327 int_enable(cpsr); | |
328 | |
329 ffsdrv_amd_erase_end(); | |
330 } | |
331 | |
332 void ffsdrv_amd_erase_end(void) | |
333 { | |
334 while ((*dev.addr & 0x80) == 0) | |
335 ; | |
336 | |
337 dev.state = DEV_READ; | |
338 | |
339 tlw(led_off(LED_ERASE)); | |
340 } | |
341 | |
342 void ffsdrv_amd_erase_suspend(void) | |
343 { | |
344 uint32 cpsr; | |
345 | |
346 tlw(led_on(LED_ERASE_SUSPEND)); | |
347 ttw(str(TTrDrvErase, "es" NL)); | |
348 | |
349 // if erase has finished then all is ok | |
350 if (*dev.addr & 0x80) { | |
351 ffsdrv_amd_erase_end(); | |
352 tlw(led_off(LED_ERASE_SUSPEND)); | |
353 return; | |
354 } | |
355 | |
356 // NOTEME: As there is no way to be absolutely certain that erase | |
357 // doesn't finish between last poll and the following erase suspend | |
358 // command, we assume that the erase suspend is safe even though the | |
359 // erase IS actually already finished. | |
360 | |
361 cpsr = int_disable(); | |
362 dev.state = DEV_ERASE_SUSPEND; | |
363 *dev.addr = 0xB0; | |
364 | |
365 // Wait for erase suspend to finish | |
366 while ((*dev.addr & 0x80) == 0) | |
367 ; | |
368 | |
369 int_enable(cpsr); | |
370 } | |
371 | |
372 void ffsdrv_amd_erase_resume(void) | |
373 { | |
374 uint32 cpsr; | |
375 | |
376 ttw(str(TTrDrvErase, "er" NL)); | |
377 | |
378 // NOTEME: See note in erase_suspend()... We assume that the erase | |
379 // resume is safe even though the erase IS actually already finished. | |
380 cpsr = int_disable(); | |
381 dev.state = DEV_ERASE; | |
382 *dev.addr = 0x30; | |
383 int_enable(cpsr); | |
384 | |
385 tlw(led_off(LED_ERASE_SUSPEND)); | |
386 } | |
387 | |
388 | |
389 /****************************************************************************** | |
390 * SST Dual/Multi Bank Driver Functions | |
391 ******************************************************************************/ | |
392 | |
393 // SST flashes use almost same command set as AMD flashes. Only the command | |
394 // addresses (4 more bits) and erase command data (0x50 instead of 0x30) are | |
395 // different. SST flashes have no erase suspend/resume commands because they | |
396 // are so fast at erasing! | |
397 | |
398 void ffsdrv_sst_write_end(void); | |
399 void ffsdrv_sst_erase_end(void); | |
400 | |
401 void ffsdrv_sst_write(void *dst, const void *src, uint16 size) | |
402 { | |
403 uint8 *mydst = dst; | |
404 const uint8 *mysrc = src; | |
405 | |
406 if (size > 0) | |
407 { | |
408 if ((unsigned int) mydst & 1) { | |
409 ffsdrv_write_byte(mydst++, *mysrc++); | |
410 size--; | |
411 } | |
412 while (size >= 2) { | |
413 ffsdrv_amd_write_halfword((uint16 *) mydst, | |
414 mysrc[0] | (mysrc[1] << 8)); | |
415 size -= 2; | |
416 mysrc += 2; | |
417 mydst += 2; | |
418 } | |
419 if (size == 1) | |
420 ffsdrv_write_byte(mydst++, *mysrc++); | |
421 } | |
422 } | |
423 | |
424 // Note that SST flashes have smaller sectors than other flash families. | |
425 // Fortunately they support erasure of several of these sectors in a logical | |
426 // unit called a "block". | |
427 void ffsdrv_sst_erase(uint8 block) | |
428 { | |
429 volatile char *flash = dev.base; | |
430 uint32 cpsr; | |
431 | |
432 tlw(led_on(LED_ERASE)); | |
433 ttw(ttr(TTrDrvErase, "e(%d)" NL, block)); | |
434 | |
435 dev.addr = (uint16 *) block2addr(block); | |
436 | |
437 cpsr = int_disable(); | |
438 dev.state = DEV_ERASE; | |
439 flash[0xAAAA] = 0xAA; // unlock cycle 1 | |
440 flash[0x5555] = 0x55; // unlock cycle 2 | |
441 flash[0xAAAA] = 0x80; | |
442 flash[0xAAAA] = 0xAA; // unlock cycle 1 | |
443 flash[0x5555] = 0x55; // unlock cycle 2 | |
444 *dev.addr = 0x50; // SST erase block command | |
445 int_enable(cpsr); | |
446 | |
447 ffsdrv_sst_erase_end(); | |
448 } | |
449 | |
450 void ffsdrv_sst_erase_end(void) | |
451 { | |
452 // Wait for erase end | |
453 while ((*dev.addr & 0x80) == 0) | |
454 ; | |
455 | |
456 dev.state = DEV_READ; | |
457 | |
458 tlw(led_off(LED_ERASE)); | |
459 } | |
460 | |
461 // Erase suspend/resume commands do not exist for SST flashes, so we just | |
462 // poll for the end of the erase operation... | |
463 | |
464 void ffsdrv_sst_erase_suspend(void) | |
465 { | |
466 ttw(str(TTrDrvErase, "es" NL)); | |
467 | |
468 ffsdrv_sst_erase_end(); | |
469 } | |
470 | |
471 | |
472 /****************************************************************************** | |
473 * Intel Single Bank Driver Functions | |
474 ******************************************************************************/ | |
475 | |
476 #if (TARGET == 1) | |
477 | |
478 // Forward declaration of functions in file intelsbdrv.c | |
479 int ffsdrv_ram_intel_sb_init(void); | |
480 void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value); | |
481 void ffsdrv_ram_intel_sb_erase(uint8 block); | |
482 void ffsdrv_ram_intel_erase(uint8 block); | |
483 | |
484 #else // (TARGET == 0) | |
485 | |
486 // On PC these functions are empty | |
487 void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value) {} | |
488 void ffsdrv_ram_intel_sb_erase(uint8 block) {} | |
489 void ffsdrv_ram_intel_erase(uint8 block) {} | |
490 | |
491 #endif // (TARGET == 1) | |
492 | |
493 | |
494 /****************************************************************************** | |
495 * Intel Dual/Multi Bank Driver Functions | |
496 ******************************************************************************/ | |
497 | |
498 void ffsdrv_intel_write_end(void); | |
499 void ffsdrv_intel_erase_end(void); | |
500 | |
501 | |
502 // ffsdrv_intel_write_halfword and ffsdrv_intel_write_end is not used | |
503 // because of the bug in the intel flash device. Instead is the functions | |
504 // ffsdrv_ram_intel_sb_write_halfword and ffsdrv_ram_intel_erase used. | |
505 void ffsdrv_intel_write_halfword(volatile uint16 *addr, uint16 value) | |
506 { | |
507 uint32 cpsr; | |
508 | |
509 tlw(led_on(LED_WRITE)); | |
510 ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); | |
511 | |
512 dev.addr = addr; | |
513 | |
514 if (~*addr & value) { | |
515 ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); | |
516 return; | |
517 } | |
518 | |
519 cpsr = int_disable(); | |
520 dev.state = DEV_WRITE; | |
521 | |
522 #if (INTEL_UNLOCK_SLOW == 1) | |
523 *addr = 0x60; // Intel Config setup | |
524 *addr = 0xD0; // Intel Unlock block | |
525 *addr = 0x50; // Intel Clear Status Register | |
526 #endif | |
527 | |
528 *addr = 0x40; // Intel program byte/word | |
529 *addr = value; | |
530 | |
531 int_enable(cpsr); | |
532 | |
533 ffsdrv_intel_write_end(); | |
534 } | |
535 | |
536 void ffsdrv_intel_write(void *dst, const void *src, uint16 size) | |
537 { | |
538 uint8 *mydst = dst; | |
539 const uint8 *mysrc = src; | |
540 | |
541 if (size > 0) | |
542 { | |
543 if ((unsigned int) mydst & 1) { | |
544 ffsdrv_write_byte(mydst++, *mysrc++); | |
545 size--; | |
546 } | |
547 while (size >= 2) { | |
548 ffsdrv_intel_write_halfword((uint16 *) mydst, | |
549 mysrc[0] | (mysrc[1] << 8)); | |
550 size -= 2; | |
551 mysrc += 2; | |
552 mydst += 2; | |
553 } | |
554 if (size == 1) | |
555 ffsdrv_write_byte(mydst++, *mysrc++); | |
556 } | |
557 } | |
558 | |
559 void ffsdrv_intel_write_end(void) | |
560 { | |
561 uint32 cpsr; | |
562 // We can be interrupted and reentered thus the state can have been changed. | |
563 while ((*dev.addr & 0x80) == 0 && dev.state == DEV_WRITE) | |
564 ; | |
565 | |
566 // The flash state and dev.state must be in sync thus the stat changes | |
567 // must be protect from being interrupted | |
568 cpsr = int_disable(); | |
569 *dev.addr = 0xFF; // Intel read array | |
570 dev.state = DEV_READ; | |
571 int_enable(cpsr); | |
572 | |
573 tlw(led_off(LED_WRITE)); | |
574 } | |
575 | |
576 | |
577 void ffsdrv_intel_erase(uint8 block) | |
578 { | |
579 uint32 cpsr; | |
580 | |
581 ttw(ttr(TTrDrvErase, "e(%d)" NL, block)); | |
582 tlw(led_on(LED_ERASE)); | |
583 | |
584 dev.addr = (uint16 *) block2addr(block); | |
585 | |
586 cpsr = int_disable(); | |
587 dev.state = DEV_ERASE; | |
588 | |
589 #if (INTEL_UNLOCK_SLOW == 1) | |
590 *dev.addr = 0x60; // Intel Config setup | |
591 *dev.addr = 0xD0; // Intel Unlock block | |
592 #endif | |
593 | |
594 *dev.addr = 0x50; // Intel clear status register (not really necessary) | |
595 *dev.addr = 0x20; // Intel erase setup | |
596 *dev.addr = 0xD0; // Intel erase confirm | |
597 | |
598 int_enable(cpsr); | |
599 | |
600 ffsdrv_intel_erase_end(); | |
601 } | |
602 | |
603 void ffsdrv_intel_erase_end(void) | |
604 { | |
605 while ((*dev.addr & 0x80) == 0 && dev.state == DEV_ERASE) | |
606 ; | |
607 | |
608 *dev.addr = 0xFF; // Intel read array | |
609 | |
610 dev.state = DEV_READ; | |
611 tlw(led_off(LED_ERASE)); | |
612 } | |
613 | |
614 void ffsdrv_intel_erase_suspend(void) | |
615 { | |
616 uint32 cpsr; | |
617 uint16 poll; | |
618 | |
619 ttw(str(TTrDrvErase, "es" NL)); | |
620 tlw(led_on(LED_ERASE_SUSPEND)); | |
621 | |
622 cpsr = int_disable(); | |
623 dev.state = DEV_ERASE_SUSPEND; | |
624 *dev.addr = 0xB0; // Intel Erase Suspend | |
625 *dev.addr = 0x70; // Intel Read Status Register | |
626 while (((poll = *dev.addr) & 0x80) == 0) | |
627 ; | |
628 | |
629 if ((poll & 0x40) == 0) { | |
630 // Block erase has completed | |
631 tlw(led_off(LED_ERASE_SUSPEND)); | |
632 dev.state = DEV_READ; | |
633 tlw(led_off(LED_ERASE)); | |
634 } | |
635 *dev.addr = 0xFF; // Intel read array | |
636 int_enable(cpsr); | |
637 } | |
638 | |
639 void ffsdrv_intel_erase_resume(void) | |
640 { | |
641 uint32 cpsr; | |
642 | |
643 ttw(str(TTrDrvErase, "er" NL)); | |
644 | |
645 cpsr = int_disable(); | |
646 dev.state = DEV_ERASE; | |
647 *dev.addr = 0xD0; // Intel erase resume | |
648 | |
649 // The following "extra" Read Status command is required because Intel | |
650 // has changed the specification of the W30 flash! (See "1.8 Volt Intel® | |
651 // Wireless Flash Memory with 3 Volt I/O 28F6408W30, 28F640W30, | |
652 // 28F320W30 Specification Update") | |
653 *dev.addr = 0x70; // Intel Read Status Register | |
654 | |
655 int_enable(cpsr); | |
656 | |
657 tlw(led_off(LED_ERASE_SUSPEND)); | |
658 } | |
659 | |
660 | |
661 /****************************************************************************** | |
662 * RAM Family Functions | |
663 ******************************************************************************/ | |
664 | |
665 void ffsdrv_ram_write_halfword(volatile uint16 *dst, uint16 value) | |
666 { | |
667 *dst = value; | |
668 } | |
669 | |
670 void ffsdrv_ram_write(void *dst, const void *src, uint16 size) | |
671 { | |
672 uint8 *mydst = dst; | |
673 const uint8 *mysrc = src; | |
674 | |
675 if (size == 0) | |
676 return; | |
677 else if (size == 1) | |
678 ffsdrv_write_byte(mydst, *mysrc); | |
679 else { | |
680 if ((int) mydst & 1) { | |
681 ffsdrv_write_byte(mydst++, *mysrc++); | |
682 size--; | |
683 } | |
684 while (size >= 2) { | |
685 ffsdrv_ram_write_halfword((uint16 *) mydst, mysrc[0]|(mysrc[1] << 8)); | |
686 size -= 2; | |
687 mysrc += 2; | |
688 mydst += 2; | |
689 } | |
690 if (size == 1) | |
691 ffsdrv_write_byte(mydst++, *mysrc++); | |
692 } | |
693 } | |
694 | |
695 void ffsdrv_ram_erase(uint8 block) | |
696 { | |
697 int i; | |
698 char *addr; | |
699 | |
700 addr = block2addr(block); | |
701 | |
702 for (i = 0; i < (1 << dev.binfo[block].size_ld); i++) { | |
703 *addr++ = 0xFF; | |
704 } | |
705 } | |
706 | |
707 /****************************************************************************** | |
708 * Void Functions | |
709 ******************************************************************************/ | |
710 | |
711 int ffsdrv_null_init(void) | |
712 { | |
713 ttw(ttr(TTrDrvOther, "ffsdrv_null_init()" NL)); | |
714 | |
715 return 0; | |
716 } | |
717 | |
718 void ffsdrv_null_erase(uint8 block) | |
719 { | |
720 ttw(ttr(TTrDrvErase, "ffsdrv_null_erase(%d)" NL, block)); | |
721 } | |
722 | |
723 void ffsdrv_null_write_halfword(volatile uint16 *addr, uint16 value) | |
724 { | |
725 ttw(ttr(TTrDrvWrite, "ffsdrv_null_write_halfword(0x%x, 0x%x)" NL, addr, value)); | |
726 } | |
727 | |
728 void ffsdrv_null_write(void *dst, const void *src, uint16 size) | |
729 { | |
730 ttw(ttr(TTrDrvWrite, "ffsdrv_null_write(0x%x, 0x%x, %d)" NL, dst, src, size)); | |
731 } | |
732 | |
733 void ffsdrv_null_erase_suspend(void) | |
734 { | |
735 ttw(str(TTrDrvErase, "ffsdrv_null_erase_suspend()" NL)); | |
736 } | |
737 | |
738 void ffsdrv_null_erase_resume(void) | |
739 { | |
740 ttw(str(TTrDrvErase, "ffsdrv_null_erase_resume()" NL)); | |
741 } | |
742 | |
743 void ffsdrv_null_write_end(void) | |
744 { | |
745 ttw(str(TTrDrvWrite, "ffsdrv_null_write_end()" NL)); | |
746 } | |
747 | |
748 void ffsdrv_null_erase_end(void) | |
749 { | |
750 ttw(str(TTrDrvErase, "ffsdrv_null_erase_end()" NL)); | |
751 } | |
752 | |
753 | |
754 /****************************************************************************** | |
755 * Test Driver Functions | |
756 ******************************************************************************/ | |
757 | |
758 #if (TARGET == 0) | |
759 | |
760 static char *image_addr = 0; | |
761 static int image_size = 0; | |
762 #ifdef WIN32 | |
763 HANDLE image_fd, map_fd; | |
764 #else //WIN32 | |
765 static int image_fd = 0; | |
766 #endif //WIN32 | |
767 | |
768 extern int arg_removeimage; | |
769 extern char *arg_imagename; | |
770 | |
771 extern void test_fatal_printf(char *format, ...); | |
772 | |
773 void ffsdrv_write_check(char *addr, int size) | |
774 { | |
775 offset_t offset, last; | |
776 | |
777 offset = addr2offset(addr); | |
778 last = dev.binfo[dev.numblocks-1].offset | |
779 + (1 << dev.binfo[dev.numblocks-1].size_ld); | |
780 | |
781 if (offset < 0 || (offset + size) > last) { | |
782 fprintf(stderr, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)\n", | |
783 (int) addr, size); | |
784 fprintf(stdout, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)\n", | |
785 (int) addr, size); | |
786 exit (1); | |
787 } | |
788 } | |
789 | |
790 | |
791 void ffsdrv_write_error(uint16 old, uint16 new) | |
792 { | |
793 test_fatal_printf("FATAL: Attempt to rewrite 0 to 1 bit " | |
794 "(old:0x%x/%c new:0x%x/%c)\n", | |
795 old, (old < ' ' ? '?' : old), | |
796 new, (new < ' ' ? '?' : new)); | |
797 } | |
798 | |
799 void ffsdrv_test_write_halfword(volatile uint16 *addr, uint16 value) | |
800 { | |
801 tw(tr(TR_FUNC, TrDrvWrite, "test_write_halfword(0x%05x, 0x%x)\n", | |
802 addr2offset(addr), value)); | |
803 | |
804 ffsdrv_write_check((uint8 *) addr, 2); | |
805 | |
806 if (~*addr & value) | |
807 ffsdrv_write_error(*addr, value); | |
808 | |
809 *addr = value; | |
810 } | |
811 | |
812 void ffsdrv_test_write(void *dst, const void *src, uint16 size) | |
813 { | |
814 uint8 *mydst = dst; | |
815 const uint8 *mysrc = src; | |
816 | |
817 tw(tr(TR_FUNC, TrDrvWrite, "test_write(0x%05x, 0x%x, %d)\n", | |
818 addr2offset(mydst), mysrc, size)); | |
819 | |
820 if (size > 0) | |
821 { | |
822 if ((int) mydst & 1) { | |
823 ffsdrv_write_byte(mydst++, *mysrc++); | |
824 size--; | |
825 } | |
826 while (size >= 2) { | |
827 ffsdrv_test_write_halfword((uint16 *) mydst, mysrc[0]|(mysrc[1] << 8)); | |
828 size -= 2; | |
829 mysrc += 2; | |
830 mydst += 2; | |
831 } | |
832 if (size == 1) | |
833 ffsdrv_write_byte(mydst++, *mysrc++); | |
834 } | |
835 } | |
836 | |
837 void ffsdrv_test_erase(uint8 block) | |
838 { | |
839 int i; | |
840 uint8 *addr; | |
841 | |
842 addr = block2addr(block); | |
843 | |
844 tw(tr(TR_FUNC, TrDrvErase, "ffsdrv_test_erase(%d)\n", block)); | |
845 | |
846 for (i = 0; i < 1 << dev.binfo[block].size_ld; i++) { | |
847 *addr++ = 0xFF; | |
848 } | |
849 } | |
850 | |
851 char *ffsdrv_test_create(void) | |
852 { | |
853 // If flash image file already exists, open the file, and mmap it. | |
854 // Otherwise, create file, fill file with 1's, then mmap it. | |
855 | |
856 int i; | |
857 struct stat statbuf; | |
858 #ifdef WIN32 | |
859 OFSTRUCT lpReOpenBuff; | |
860 DWORD last_error; | |
861 SECURITY_ATTRIBUTES lpAttributes; | |
862 | |
863 lpAttributes.nLength = sizeof (lpAttributes); | |
864 lpAttributes.lpSecurityDescriptor = NULL; | |
865 lpAttributes.bInheritHandle = TRUE; | |
866 #endif | |
867 image_size = (int) dev.binfo[dev.numblocks - 1].offset + | |
868 (1 << dev.binfo[dev.numblocks - 1].size_ld); | |
869 | |
870 tw(tr(TR_BEGIN, TrDrvInit, "ffsdrv_test_create() {\n")); | |
871 tw(tr(TR_FUNC, TrDrvInit, "%s image: '%s', size = %d\n", | |
872 arg_removeimage ? "new" : "current", arg_imagename, image_size)); | |
873 | |
874 // create file if it does not exist | |
875 #ifdef WIN32 | |
876 if( arg_removeimage || OpenFile( arg_imagename, &lpReOpenBuff, OF_EXIST) == HFILE_ERROR ) | |
877 #else | |
878 if (arg_removeimage || lstat(arg_imagename, &statbuf) == -1) | |
879 #endif | |
880 { | |
881 char data[64]; | |
882 #ifdef WIN32 | |
883 DWORD bwritten; | |
884 #endif | |
885 // only the first run should remove the flash image file | |
886 arg_removeimage = 0; | |
887 | |
888 tw(tr(TR_FUNC, TrDrvInit, "creating new flash image file '%s'\n", | |
889 arg_imagename)); | |
890 #ifdef WIN32 | |
891 image_fd = CreateFile(arg_imagename, | |
892 GENERIC_WRITE | GENERIC_READ, | |
893 0, | |
894 NULL, | |
895 OPEN_ALWAYS, | |
896 FILE_ATTRIBUTE_NORMAL, | |
897 NULL ); | |
898 #else | |
899 image_fd = open(arg_imagename , O_RDWR|O_CREAT, | |
900 (S_IRWXU & ~S_IXUSR) | | |
901 ( S_IRWXG & ~S_IXGRP) | (S_IRWXO & ~S_IXOTH)); | |
902 #endif | |
903 if (image_fd == -1) { | |
904 perror("Failed to create flash image"); | |
905 exit(1); | |
906 } | |
907 | |
908 // write 1's to the file. | |
909 for (i = 0; i < 64; i++) | |
910 data[i] = 0xff; | |
911 | |
912 #ifdef WIN32 | |
913 for (i = 0; i < image_size/64; i++) | |
914 WriteFile(image_fd, data, 64, &bwritten, NULL); | |
915 CloseHandle(image_fd); | |
916 #else | |
917 for (i = 0; i < image_size/64; i++) | |
918 write(image_fd, data, 64); | |
919 | |
920 close(image_fd); | |
921 #endif | |
922 image_fd = 0; | |
923 tw(tr(TR_FUNC, TrDrvInit, "flash image file created\n")); | |
924 } | |
925 | |
926 // only open image file if this is the first initialization. | |
927 if (image_fd > 0) { | |
928 tw(tr(TR_FUNC, TrDrvInit, "re-opening '%s' file of size %d\n", | |
929 arg_imagename, image_size)); | |
930 } | |
931 else { | |
932 tw(tr(TR_FUNC, TrDrvInit, "opening '%s' file of size %d\n", | |
933 arg_imagename, image_size)); | |
934 | |
935 #ifdef WIN32 | |
936 image_fd = OpenFile( arg_imagename, &lpReOpenBuff, OF_READWRITE); | |
937 map_fd = CreateFileMapping (image_fd, | |
938 &lpAttributes, | |
939 PAGE_READWRITE, | |
940 0, | |
941 0, | |
942 arg_imagename); | |
943 #else | |
944 image_fd = open(arg_imagename, O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO); | |
945 #endif | |
946 if (image_fd == -1) { | |
947 perror("Failed to open flash image"); | |
948 exit(1); | |
949 } | |
950 | |
951 // memory map the file and update block addresses of binfo array | |
952 #ifdef WIN32 | |
953 image_addr = MapViewOfFile( map_fd, | |
954 FILE_MAP_ALL_ACCESS, | |
955 0, | |
956 0, | |
957 0); | |
958 #else | |
959 image_addr = mmap(0, image_size, PROT_READ|PROT_WRITE, | |
960 MAP_FILE|MAP_SHARED, image_fd, 0); | |
961 #endif | |
962 } | |
963 | |
964 tw(tr(TR_END, TrDrvInit, "}\n")); | |
965 | |
966 return image_addr; | |
967 } | |
968 | |
969 #endif // (TARGET == 0) | |
970 | |
971 | |
972 /****************************************************************************** | |
973 * Device Detection and Copying of Driver to RAM | |
974 ******************************************************************************/ | |
975 | |
976 #if (TARGET == 1) | |
977 | |
978 // Note that this function reads device code of any of the three known flash | |
979 // families; Intel, AMD and SST. This works because Intel and AMD use | |
980 // the same command data for entering READ_IDENTIFIER mode (0x90). | |
981 // The function should be copied and executed from RAM! | |
982 void ffsdrv_device_id_read(uint16 *manufact, uint16 *device) | |
983 { | |
984 #if defined(CONFIG_TARGET_FCFAM) || defined(CONFIG_TARGET_PIRELLI) || \ | |
985 defined(__GNUC__) | |
986 /* | |
987 * This new FreeCalypso version of the device ID read function | |
988 * should work for all current targets, but we are being conservative | |
989 * and only enabling it for those targets for which it is required, | |
990 * i.e., where TI's original version does not work. | |
991 * | |
992 * Selenite change: for the gcc version we need to use this new | |
993 * autodetect code for all targets, TI's original version won't work | |
994 * because we run with the Calypso boot ROM at 0. | |
995 */ | |
996 | |
997 int addr, half, base, i; | |
998 | |
999 /* | |
1000 * We operate at a non-zero erase block boundary so that this ID read | |
1001 * operation will still work in our newer FreeCalypso environments | |
1002 * where we have the Calypso boot ROM mapped at 0. | |
1003 */ | |
1004 base = 0x40000; | |
1005 | |
1006 /* | |
1007 * muckery similar to TI's original to avoid literal pool loads, | |
1008 * but we produce and use 0xAAA and 0x554 offsets instead of TI's | |
1009 * original 0xAAAA and 0x5555. | |
1010 */ | |
1011 for (i = 0, addr = 0; i < 3; i++) | |
1012 addr = addr << 4 | 0xA; | |
1013 half = (addr >> 1) & ~1; | |
1014 | |
1015 FLASH_WRITE_HALFWORD (base + addr, 0xAA); | |
1016 FLASH_WRITE_HALFWORD (base + half, 0x55); | |
1017 FLASH_WRITE_HALFWORD (base + addr, 0x90); // Intel/AMD read id command | |
1018 | |
1019 *manufact = FLASH_READ_HALFWORD (base + 0); // flash a0 = 0 | |
1020 *device = FLASH_READ_HALFWORD (base + 2); // flash a0 = 1 | |
1021 | |
1022 // Read extended id | |
1023 device[1] = FLASH_READ_HALFWORD (base + (0xE << 1)); | |
1024 device[2] = FLASH_READ_HALFWORD (base + (0xF << 1)); | |
1025 FLASH_WRITE_HALFWORD (base, 0xFF); // Intel read-array command | |
1026 | |
1027 // AMD devices do not need the two unlock cycles but SST devices do, | |
1028 // even though the SST datasheets states otherwise ;-) | |
1029 FLASH_WRITE_HALFWORD (base + addr, 0xAA); | |
1030 FLASH_WRITE_HALFWORD (base + half, 0x55); | |
1031 FLASH_WRITE_HALFWORD (base + addr, 0xF0); // AMD read-array/reset command | |
1032 #else | |
1033 /* TI's original version */ | |
1034 int addr, i; | |
1035 | |
1036 // This silly looking code has one purpose; to set addr = 0xAAAA. It is | |
1037 // necessary in order to force the compiler NOT to produce code that | |
1038 // uses LDR opcode(s) with PC-relative addressing. The assember code | |
1039 // produced from this C code is completely relocatable! | |
1040 for (i = 0, addr = 0; i < 2; i++) | |
1041 addr |= addr << 8 | 0xAA; | |
1042 | |
1043 FLASH_WRITE_HALFWORD (addr, 0xAA); | |
1044 FLASH_WRITE_HALFWORD (addr >> 1, 0x55); | |
1045 FLASH_WRITE_HALFWORD (addr, 0x90); // Intel/AMD read id command | |
1046 | |
1047 *manufact = FLASH_READ_HALFWORD (0); // flash a0 = 0 | |
1048 *device = FLASH_READ_HALFWORD (2); // flash a0 = 1 | |
1049 | |
1050 // Read extended id | |
1051 device[1] = FLASH_READ_HALFWORD (0xE << 1); | |
1052 device[2] = FLASH_READ_HALFWORD (0xF << 1); | |
1053 FLASH_WRITE_HALFWORD (0, 0xFF); // Intel read-array command | |
1054 | |
1055 // AMD devices do not need the two unlock cycles but SST devices do, | |
1056 // even though the SST datasheets states otherwise ;-) | |
1057 FLASH_WRITE_HALFWORD (addr, 0xAA); | |
1058 FLASH_WRITE_HALFWORD (addr >> 1, 0x55); | |
1059 FLASH_WRITE_HALFWORD (addr, 0xF0); // AMD read-array/reset command | |
1060 #endif | |
1061 } | |
1062 | |
1063 // Copy ffsdrv_device_id_read() function code to RAM. The only known way to | |
1064 // determine the size of the code is to look either in the linker-generated | |
1065 // map file or in the assember output file. | |
1066 void ffsdrv_device_id_read_copy_to_ram(uint16 *dst, int size) | |
1067 { | |
1068 uint16 *src = (uint16 *) &ffsdrv_device_id_read; | |
1069 | |
1070 // The ARM7TDMI compiler sets bit 0 for thumb mode function pointers, so | |
1071 // we need to clear this in order to copy *all* bytes. Otherwise we | |
1072 // exclude first byte and the resulting copy becomes garbage | |
1073 src = (uint16 *) (~1 & (int) src); | |
1074 size /= 2; | |
1075 | |
1076 while (size--) | |
1077 *dst++ = *src++; | |
1078 } | |
1079 | |
1080 // Copy ffsdrv_xxx_sb_erase() and ffsdrv_xxx_sb_write_halfword() functions | |
1081 // to RAM. The only known way to determine the size of the code is to look | |
1082 // either in the linker-generated map file or in the assember output file. | |
1083 int ffsdrv_driver_copy_to_ram(int type) | |
1084 { | |
1085 int size; | |
1086 uint16 *src, *dst; | |
1087 extern uint16 ffsdrv_ram_amd_begin[]; | |
1088 extern uint16 ffsdrv_ram_intel_begin[]; | |
1089 uint32 offset_of_init; | |
1090 uint32 offset_of_erase; | |
1091 uint32 offset_of_write_halfword; | |
1092 | |
1093 ttw(ttr(TTrDrvOther, "ffsdrv_driver_copy_to_ram() {" NL)); | |
1094 | |
1095 switch (type) { | |
1096 case FFS_DRIVER_AMD: | |
1097 case FFS_DRIVER_AMD_SB: | |
1098 src = ffsdrv_ram_amd_begin; | |
1099 offset_of_erase = | |
1100 (uint32) ffsdrv_ram_amd_sb_erase - (uint32) src; | |
1101 offset_of_write_halfword = | |
1102 (uint32) ffsdrv_ram_amd_sb_write_halfword - (uint32) src; | |
1103 break; | |
1104 case FFS_DRIVER_INTEL_SB: | |
1105 src = ffsdrv_ram_intel_begin; | |
1106 offset_of_init = | |
1107 (uint32) ffsdrv_ram_intel_sb_init - (uint32) src; | |
1108 offset_of_erase = | |
1109 (uint32) ffsdrv_ram_intel_sb_erase - (uint32) src; | |
1110 offset_of_write_halfword = | |
1111 (uint32) ffsdrv_ram_intel_sb_write_halfword - (uint32) src; | |
1112 break; | |
1113 case FFS_DRIVER_INTEL: | |
1114 src = ffsdrv_ram_intel_begin; | |
1115 offset_of_init = | |
1116 (uint32) ffsdrv_ram_intel_sb_init - (uint32) src; | |
1117 offset_of_erase = | |
1118 (uint32) ffsdrv_ram_intel_erase - (uint32) src; | |
1119 offset_of_write_halfword = | |
1120 (uint32) ffsdrv_ram_intel_sb_write_halfword - (uint32) src; | |
1121 break; | |
1122 default: | |
1123 ttw(ttr(TTrDrvOther, "}" NL)); | |
1124 return 0; | |
1125 } | |
1126 | |
1127 // Make sure we are handling a half-word aligned address (Thumb mode | |
1128 // function pointers have lsb set!) | |
1129 src = (uint16 *) (~1 & (int) src); | |
1130 | |
1131 // If we detect that the linker allocated the driver to RUN in RAM, the | |
1132 // user has obviously NOT removed those linker lines and we bail out! | |
1133 if (offset_of_erase > FFSDRV_CODE_SIZE) | |
1134 return EFFS_DRIVER; | |
1135 | |
1136 dst = (uint16 *) &ffsdrv_code; | |
1137 | |
1138 // Code size in halfwords | |
1139 size = FFSDRV_CODE_SIZE / 2; | |
1140 | |
1141 // Rebind the two changed driver functions | |
1142 if (type == FFS_DRIVER_AMD_SB || type == FFS_DRIVER_INTEL_SB) { | |
1143 ffsdrv.erase = | |
1144 (void (*)(uint8)) | |
1145 (offset_of_erase + (uint32) dst); | |
1146 ffsdrv.write_halfword = | |
1147 (void (*)(volatile uint16 *, uint16)) | |
1148 (offset_of_write_halfword + (uint32) dst); | |
1149 } | |
1150 if (type == FFS_DRIVER_INTEL_SB) { | |
1151 ffsdrv.init = | |
1152 (int (*)(void)) | |
1153 (offset_of_init + (uint32) dst); | |
1154 } | |
1155 | |
1156 ttw(ttr(TTrDrvOther, "ffsdrv_code, init, write, erase = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL, | |
1157 dst, (uint32) ffsdrv.init, | |
1158 (uint32) ffsdrv.write_halfword, (uint32) ffsdrv.erase)); | |
1159 | |
1160 ttw(ttr(TTrDrvOther, "amd_begin, init, write, erase = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL, | |
1161 ffsdrv_ram_amd_begin, ffsdrv_null_init, | |
1162 ffsdrv_ram_amd_sb_write_halfword, ffsdrv_ram_amd_sb_erase)); | |
1163 | |
1164 ttw(ttr(TTrDrvOther, "intel_begin, init, write, erase = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL, | |
1165 ffsdrv_ram_intel_begin, ffsdrv_ram_intel_sb_init, | |
1166 ffsdrv_ram_intel_sb_write_halfword, ffsdrv_ram_intel_sb_erase)); | |
1167 | |
1168 // Copy the code to RAM | |
1169 while (size--) | |
1170 *dst++ = *src++; | |
1171 | |
1172 ttw(ttr(TTrDrvOther, "}" NL)); | |
1173 | |
1174 return 0; | |
1175 } | |
1176 | |
1177 #if defined(CONFIG_TARGET_PIRELLI) || defined(CONFIG_TARGET_FCFAM) | |
1178 | |
1179 #ifdef CONFIG_TARGET_FCFAM | |
1180 #define FLASH2_BASE_ADDR 0x01800000 | |
1181 #elif defined(CONFIG_TARGET_PIRELLI) | |
1182 #define FLASH2_BASE_ADDR 0x02000000 | |
1183 #endif | |
1184 | |
1185 int ffsdrv_is_new_spansion_flash(void) | |
1186 { | |
1187 uint16 cfi_hi, cfi_lo, cfi_ver; | |
1188 | |
1189 /* CFI query */ | |
1190 FLASH_WRITE_HALFWORD(FLASH2_BASE_ADDR + 0xAAA, 0x98); | |
1191 cfi_hi = FLASH_READ_HALFWORD(FLASH2_BASE_ADDR + 0x86); | |
1192 cfi_lo = FLASH_READ_HALFWORD(FLASH2_BASE_ADDR + 0x88); | |
1193 cfi_ver = (cfi_hi << 8) | (cfi_lo & 0xFF); | |
1194 | |
1195 /* return to read array mode */ | |
1196 FLASH_WRITE_HALFWORD(FLASH2_BASE_ADDR + 0xAAA, 0xF0); | |
1197 | |
1198 if (cfi_ver >= 0x3134) | |
1199 return 1; | |
1200 else | |
1201 return 0; | |
1202 } | |
1203 #endif | |
1204 | |
1205 #else // (TARGET == 0) | |
1206 | |
1207 void ffsdrv_device_id_read(uint16 *manufact, uint16 *device) {} | |
1208 int ffsdrv_driver_copy_to_ram(int type) { return 0; } | |
1209 | |
1210 #endif // (TARGET == 1) | |
1211 | |
1212 | |
1213 /****************************************************************************** | |
1214 * Initialization | |
1215 ******************************************************************************/ | |
1216 | |
1217 const struct ffsdrv_s ffsdrv_amd = { | |
1218 ffsdrv_null_init, | |
1219 ffsdrv_amd_erase, | |
1220 ffsdrv_amd_write_halfword, | |
1221 ffsdrv_amd_write, | |
1222 ffsdrv_amd_write_end, | |
1223 ffsdrv_amd_erase_suspend, | |
1224 ffsdrv_amd_erase_resume | |
1225 }; | |
1226 | |
1227 const struct ffsdrv_s ffsdrv_amd_sb = { | |
1228 ffsdrv_null_init, | |
1229 ffsdrv_ram_amd_sb_erase, | |
1230 ffsdrv_ram_amd_sb_write_halfword, | |
1231 ffsdrv_generic_write, | |
1232 ffsdrv_null_write_end, | |
1233 ffsdrv_null_erase_suspend, | |
1234 ffsdrv_null_erase_resume | |
1235 }; | |
1236 | |
1237 const struct ffsdrv_s ffsdrv_sst = { | |
1238 ffsdrv_null_init, | |
1239 ffsdrv_sst_erase, | |
1240 ffsdrv_amd_write_halfword, // Use AMD driver function | |
1241 ffsdrv_sst_write, | |
1242 ffsdrv_amd_write_end, // Use AMD driver function | |
1243 ffsdrv_sst_erase_suspend, | |
1244 ffsdrv_null_erase_resume | |
1245 }; | |
1246 | |
1247 const struct ffsdrv_s ffsdrv_sst_sb = { | |
1248 ffsdrv_null_init, | |
1249 ffsdrv_null_erase, | |
1250 ffsdrv_null_write_halfword, | |
1251 ffsdrv_null_write, | |
1252 ffsdrv_null_write_end, | |
1253 ffsdrv_null_erase_suspend, | |
1254 ffsdrv_null_erase_resume | |
1255 }; | |
1256 | |
1257 // We use the functions ffsdrv_ram_intel_sb_write_halfword and | |
1258 // ffsdrv_ram_intel_erase due to the bug in the intel wireless flash | |
1259 // device. See 28F640W30.pdf specification Errata 5. | |
1260 const struct ffsdrv_s ffsdrv_intel = { | |
1261 ffsdrv_null_init, | |
1262 ffsdrv_intel_erase, | |
1263 ffsdrv_intel_write_halfword, | |
1264 ffsdrv_generic_write, | |
1265 ffsdrv_intel_write_end, | |
1266 ffsdrv_intel_erase_suspend, | |
1267 ffsdrv_intel_erase_resume | |
1268 }; | |
1269 | |
1270 const struct ffsdrv_s ffsdrv_intel_sb = { | |
1271 ffsdrv_null_init, | |
1272 ffsdrv_ram_intel_sb_erase, | |
1273 ffsdrv_ram_intel_sb_write_halfword, | |
1274 ffsdrv_generic_write, | |
1275 ffsdrv_null_write_end, | |
1276 ffsdrv_null_erase_suspend, | |
1277 ffsdrv_null_erase_resume | |
1278 }; | |
1279 | |
1280 const struct ffsdrv_s ffsdrv_null = { | |
1281 ffsdrv_null_init, | |
1282 ffsdrv_null_erase, | |
1283 ffsdrv_null_write_halfword, | |
1284 ffsdrv_null_write, | |
1285 ffsdrv_null_write_end, | |
1286 ffsdrv_null_erase_suspend, | |
1287 ffsdrv_null_erase_resume | |
1288 }; | |
1289 | |
1290 const struct ffsdrv_s ffsdrv_amd_pseudo_sb = { | |
1291 ffsdrv_null_init, | |
1292 ffsdrv_amd_pseudo_sb_erase, | |
1293 ffsdrv_amd_pseudo_sb_write_halfword, | |
1294 ffsdrv_generic_write, | |
1295 ffsdrv_null_write_end, | |
1296 ffsdrv_null_erase_suspend, | |
1297 ffsdrv_null_erase_resume | |
1298 }; | |
1299 | |
1300 const struct ffsdrv_s ffsdrv_ram = { | |
1301 ffsdrv_null_init, | |
1302 ffsdrv_ram_erase, | |
1303 ffsdrv_ram_write_halfword, | |
1304 ffsdrv_ram_write, | |
1305 ffsdrv_null_write_end, | |
1306 ffsdrv_null_erase_suspend, | |
1307 ffsdrv_null_erase_resume | |
1308 }; | |
1309 | |
1310 #if (TARGET == 0) | |
1311 const struct ffsdrv_s ffsdrv_test = { | |
1312 ffsdrv_null_init, | |
1313 ffsdrv_test_erase, | |
1314 ffsdrv_test_write_halfword, | |
1315 ffsdrv_test_write, | |
1316 ffsdrv_null_write_end, | |
1317 ffsdrv_null_erase_suspend, | |
1318 ffsdrv_null_erase_resume | |
1319 }; | |
1320 #endif | |
1321 | |
1322 // Note: This function is designed for little-endian memory addressing! | |
1323 void ffsdrv_write_byte(void *dst, uint8 value) | |
1324 { | |
1325 uint16 halfword; | |
1326 | |
1327 tw(tr(TR_FUNC, TrDrvWrite, "ffsdrv_write_byte(0x%05x, 0x%x)\n", | |
1328 (int) (addr2offset(dst)), value)); | |
1329 ttw(str(TTrDrvWrite, "wb" NL)); | |
1330 | |
1331 if ((int) dst & 1) | |
1332 halfword = (value << 8) | *((uint8 *) dst - 1); | |
1333 else | |
1334 halfword = (*((uint8 *) dst + 1) << 8) | (value); | |
1335 | |
1336 ffsdrv.write_halfword((uint16 *) ((int) dst & ~1), halfword); | |
1337 } | |
1338 | |
1339 | |
1340 extern uint16 ffs_flash_manufact; | |
1341 extern uint16 ffs_flash_device; | |
1342 | |
1343 effs_t ffsdrv_init(void) | |
1344 { | |
1345 const struct ffsdrv_s *p; | |
1346 const struct flash_info_s *flash = &flash_info[0]; | |
1347 int error; | |
1348 | |
1349 tw(tr(TR_BEGIN, TrDrvInit, "drv_init() {\n")); | |
1350 ttw(str(TTrDrvOther, "ffsdrv_init() {" NL)); | |
1351 | |
1352 dev.state = DEV_READ; | |
1353 dev.binfo = 0; | |
1354 dev.base = 0; | |
1355 dev.numblocks = 0; | |
1356 | |
1357 // If ffs_flash_device is zero, detect device automatically by copying | |
1358 // the detect function into RAM and execute it from there... | |
1359 if (ffs_flash_manufact == 0 && ffs_flash_device == 0) | |
1360 { | |
1361 #if (TARGET == 1) | |
1362 char detect_code[0x80]; | |
1363 typedef (*pf_t)(uint16 *, uint16 *); | |
1364 pf_t myfp; | |
1365 uint16 device_id[3]; | |
1366 | |
1367 ffsdrv_device_id_read_copy_to_ram((uint16 *) detect_code, | |
1368 sizeof(detect_code)); | |
1369 // Combine bit 0 of the thumb mode function pointer with the address | |
1370 // of the code in RAM. Then call the detect function in RAM. | |
1371 #ifdef __GNUC__ | |
1372 /* gcc fails to do the needed trick, so force Thumb */ | |
1373 myfp = (pf_t) (((int) detect_code) | 1); | |
1374 #else | |
1375 myfp = (pf_t) (((int) &ffsdrv_device_id_read & 1) | (int) detect_code); | |
1376 #endif | |
1377 (*myfp)(&dev.manufact, device_id); | |
1378 | |
1379 if ((dev.manufact == MANUFACT_AMD || dev.manufact == MANUFACT_FUJITSU) && | |
1380 device_id[0] == 0x227E) { | |
1381 // This is a multi-id device | |
1382 dev.device = (device_id[1] << 8) | (device_id[2] & 0xFF); | |
1383 #if defined(CONFIG_TARGET_PIRELLI) || defined(CONFIG_TARGET_FCFAM) | |
1384 if (device_id[1] == 0x2221 && device_id[2] == 0x2200) | |
1385 dev.device += ffsdrv_is_new_spansion_flash(); | |
1386 #endif | |
1387 } | |
1388 else if (dev.manufact == MANUFACT_SAMSUNG && device_id[0] == 0x257E) { | |
1389 /* Samsung's version of extended ID */ | |
1390 dev.device = (device_id[1] << 8) | (device_id[2] & 0xFF); | |
1391 } | |
1392 else | |
1393 dev.device = device_id[0]; | |
1394 #endif | |
1395 } | |
1396 else { | |
1397 dev.manufact = ffs_flash_manufact; | |
1398 dev.device = ffs_flash_device; | |
1399 } | |
1400 | |
1401 tw(tr(TR_FUNC, TrDrvInit, "TARGET = %d\n", TARGET)); | |
1402 tw(tr(TR_FUNC, TrDrvInit, "Looking up device (0x%2x,0x%4x): ", | |
1403 dev.manufact, dev.device)); | |
1404 while (flash->manufact) { | |
1405 tw(tr(TR_NULL, TrDrvInit, "(0x%02x,0x%04x) ", | |
1406 flash->manufact, flash->device)); | |
1407 if (dev.manufact == flash->manufact && dev.device == flash->device) { | |
1408 tw(tr(TR_NULL, TrDrvInit, "FOUND ")); | |
1409 break; | |
1410 } | |
1411 flash++; | |
1412 } | |
1413 tw(tr(TR_NULL, TrDrvInit, "\n")); | |
1414 | |
1415 if (flash->manufact == 0) { | |
1416 tw(tr(TR_END, TrDrvInit, "} (%d)\n", EFFS_NODEVICE)); | |
1417 return EFFS_NODEVICE; | |
1418 } | |
1419 | |
1420 dev.binfo = (struct block_info_s *) flash->binfo; | |
1421 | |
1422 if (flash->driver == FFS_DRIVER_RAM && flash->base == 0) { | |
1423 if (ffs_ram_image_address <= 0) { | |
1424 tw(tr(TR_END, TrDrvInit, "} (%d)\n", EFFS_DRIVER)); | |
1425 return EFFS_DRIVER; | |
1426 } | |
1427 dev.base = (char *) ffs_ram_image_address; | |
1428 } | |
1429 else | |
1430 dev.base = (char *) flash->base; | |
1431 | |
1432 dev.numblocks = flash->numblocks; | |
1433 dev.driver = flash->driver; | |
1434 | |
1435 // We assume that ALL blocks are of equal size | |
1436 dev.blocksize_ld = dev.binfo[0].size_ld; | |
1437 dev.blocksize = (1 << dev.blocksize_ld); | |
1438 | |
1439 dev.atomlog2 = FFS_ATOM_LOG2; | |
1440 dev.atomsize = 1 << dev.atomlog2; | |
1441 dev.atomnotmask = dev.atomsize - 1; | |
1442 | |
1443 #if (TARGET == 0) | |
1444 if (dev.manufact == MANUFACT_TEST) | |
1445 dev.base = ffsdrv_test_create(); | |
1446 | |
1447 p = &ffsdrv_test; | |
1448 | |
1449 #else // (TARGET == 1) | |
1450 | |
1451 // Initialize hardware independent driver functions array | |
1452 switch (dev.driver) { | |
1453 case FFS_DRIVER_AMD: p = &ffsdrv_amd; break; | |
1454 case FFS_DRIVER_AMD_SB: p = &ffsdrv_amd_sb; break; | |
1455 case FFS_DRIVER_SST: p = &ffsdrv_sst; break; | |
1456 case FFS_DRIVER_SST_SB: p = &ffsdrv_sst_sb; break; | |
1457 case FFS_DRIVER_INTEL: p = &ffsdrv_intel; break; | |
1458 case FFS_DRIVER_INTEL_SB: p = &ffsdrv_intel_sb; break; | |
1459 case FFS_DRIVER_AMD_PSEUDO_SB: p = &ffsdrv_amd_pseudo_sb; break; | |
1460 case FFS_DRIVER_RAM: p = &ffsdrv_ram; break; | |
1461 default: p = &ffsdrv_null; break; | |
1462 } | |
1463 | |
1464 #endif // (TARGET == 0) | |
1465 | |
1466 // Bind the driver functions | |
1467 ffsdrv.init = p->init; | |
1468 ffsdrv.erase = p->erase; | |
1469 ffsdrv.write_halfword = p->write_halfword; | |
1470 ffsdrv.write = p->write; | |
1471 ffsdrv.write_end = p->write_end; | |
1472 ffsdrv.erase_suspend = p->erase_suspend; | |
1473 ffsdrv.erase_resume = p->erase_resume; | |
1474 | |
1475 // Copy single bank driver code to RAM (and possibly re-bind some of the | |
1476 // driver functions) | |
1477 error = ffsdrv_driver_copy_to_ram(dev.driver); | |
1478 | |
1479 if (error >= 0) | |
1480 error = ffsdrv.init(); | |
1481 | |
1482 tw(tr(TR_FUNC, TrDrvInit, "dev.binfo = 0x%x\n", (unsigned int) dev.binfo)); | |
1483 tw(tr(TR_FUNC, TrDrvInit, "dev.base = 0x%x\n", (unsigned int) dev.base)); | |
1484 tw(tr(TR_FUNC, TrDrvInit, "dev.numblocks = %d\n", dev.numblocks)); | |
1485 tw(tr(TR_FUNC, TrDrvInit, "dev.blocksize = %d\n", dev.blocksize)); | |
1486 tw(tr(TR_FUNC, TrDrvInit, "dev.atomlog2/atomsize/atomnotmask = %d/%d/%x\n", | |
1487 dev.atomlog2, dev.atomsize, dev.atomnotmask)); | |
1488 tw(tr(TR_END, TrDrvInit, "} %d\n", error)); | |
1489 ttw(ttr(TTrDrvOther, "} %d" NL, error)); | |
1490 | |
1491 return error; | |
1492 } | |
1493 | |
1494 | |
1495 /****************************************************************************** | |
1496 * Interrupt Enable/Disable | |
1497 ******************************************************************************/ | |
1498 | |
1499 // IMPORTANT NOTE! Apparently, locating this ARM assembly code at the top of | |
1500 // this file will make the compiler trash the A1 register between the calls | |
1501 // of arm_int_disable and arm_int_enable() thus crashing the whole system. | |
1502 // If the code is placed AFTER the usage of the functions, the compiler | |
1503 // saves the A1 register. Strange but true. | |
1504 | |
1505 // IMPORTANT NOTE! Apparently, another strange thing is that if the | |
1506 // functions are declared static, they don't work! | |
1507 | |
1508 // Executing code from RAM is NOT trivial when we need to jump between ROM | |
1509 // (flash) and RAM memory. The ARM only supports 26-bit relative branch | |
1510 // offsets. This is the reason why we have a local copy of the | |
1511 // arm_int_disable/enable() functions in this file plus each of the | |
1512 // single-bank drivers. | |
1513 | |
1514 #if (TARGET == 1) | |
1515 // Note that we use our own interrupt disable/enable function because | |
1516 // Nucleus allegedly should have a bug in its implementation for this. | |
1517 | |
1518 #ifdef __GNUC__ | |
1519 #define NOINLINE __attribute__ ((noinline)) | |
1520 #else | |
1521 #define NOINLINE | |
1522 #endif | |
1523 | |
1524 uint32 NOINLINE int_disable(void) | |
1525 { | |
1526 #ifdef __GNUC__ | |
1527 asm(" .code 16"); | |
1528 #else | |
1529 asm(" .state16"); | |
1530 #endif | |
1531 asm(" mov A1, #0xC0"); | |
1532 asm(" ldr A2, tct_disable"); | |
1533 asm(" bx A2 "); | |
1534 | |
1535 #ifdef __GNUC__ | |
1536 asm(".balign 4"); | |
1537 asm("tct_disable:"); | |
1538 asm(" .word TCT_Control_Interrupts"); | |
1539 #else | |
1540 asm("tct_disable .field _TCT_Control_Interrupts+0,32"); | |
1541 asm(" .global _TCT_Control_Interrupts"); | |
1542 #endif | |
1543 } | |
1544 | |
1545 void NOINLINE int_enable(uint32 cpsr) | |
1546 { | |
1547 #ifdef __GNUC__ | |
1548 asm(" .code 16"); | |
1549 #else | |
1550 asm(" .state16"); | |
1551 #endif | |
1552 asm(" ldr A2, tct_enable"); | |
1553 asm(" bx A2 "); | |
1554 | |
1555 #ifdef __GNUC__ | |
1556 asm(".balign 4"); | |
1557 asm("tct_enable:"); | |
1558 asm(" .word TCT_Control_Interrupts"); | |
1559 #else | |
1560 asm("tct_enable .field _TCT_Control_Interrupts+0,32"); | |
1561 asm(" .global _TCT_Control_Interrupts"); | |
1562 #endif | |
1563 } | |
1564 | |
1565 #else | |
1566 | |
1567 uint32 int_disable(void) { return 0; } | |
1568 void int_enable(uint32 tmp) {} | |
1569 | |
1570 #endif // (TARGET == 1) | |
1571 | |
1572 |