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