]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/devs/flash/amd/am29xxxxx/v2_0/include/flash_am29xxxxx.inl
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / flash / amd / am29xxxxx / v2_0 / include / flash_am29xxxxx.inl
1 #ifndef CYGONCE_DEVS_FLASH_AMD_AM29XXXXX_INL
2 #define CYGONCE_DEVS_FLASH_AMD_AM29XXXXX_INL
3 //==========================================================================
4 //
5 //      am29xxxxx.inl
6 //
7 //      AMD AM29xxxxx series flash driver
8 //
9 //==========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 // Copyright (C) 2002, 2004 Gary Thomas
15 //
16 // eCos is free software; you can redistribute it and/or modify it under
17 // the terms of the GNU General Public License as published by the Free
18 // Software Foundation; either version 2 or (at your option) any later version.
19 //
20 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
21 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 // for more details.
24 //
25 // You should have received a copy of the GNU General Public License along
26 // with eCos; if not, write to the Free Software Foundation, Inc.,
27 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 //
29 // As a special exception, if other files instantiate templates or use macros
30 // or inline functions from this file, or you compile this file and link it
31 // with other works to produce a work based on this file, this file does not
32 // by itself cause the resulting work to be covered by the GNU General Public
33 // License. However the source code for this file must still be made available
34 // in accordance with section (3) of the GNU General Public License.
35 //
36 // This exception does not invalidate any other reasons why a work based on
37 // this file might be covered by the GNU General Public License.
38 //
39 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
40 // at http://sources.redhat.com/ecos/ecos-license/
41 // -------------------------------------------
42 //####ECOSGPLCOPYRIGHTEND####
43 //==========================================================================
44 //#####DESCRIPTIONBEGIN####
45 //
46 // Author(s):    gthomas
47 // Contributors: gthomas, jskov, Koichi Nagashima
48 // Date:         2001-02-21
49 // Purpose:      
50 // Description:  AMD AM29xxxxx series flash device driver
51 // Notes:        While the parts support sector locking, some only do so
52 //               via crufty magic and the use of programmer hardware
53 //               (specifically by applying 12V to one of the address
54 //               pins) so the driver does not support write protection.
55 //
56 // FIXME:        Should support SW locking on the newer devices.
57 //
58 // FIXME:        Figure out how to do proper error checking when there are
59 //               devices in parallel. Presently the driver will return
60 //               driver timeout error on device errors which is not very
61 //               helpful.
62 //
63 //####DESCRIPTIONEND####
64 //
65 //==========================================================================
66
67 #include <pkgconf/hal.h>
68 #include <pkgconf/devs_flash_amd_am29xxxxx.h>
69 #include <cyg/hal/hal_arch.h>
70 #include <cyg/hal/hal_cache.h>
71 #include <cyg/hal/hal_misc.h>
72 #include CYGHWR_MEMORY_LAYOUT_H
73
74 #define  _FLASH_PRIVATE_
75 #include <cyg/io/flash.h>
76
77 //----------------------------------------------------------------------------
78 // Common device details.
79 #define FLASH_Read_ID                   FLASHWORD( 0x90 )
80 #define FLASH_WP_State                  FLASHWORD( 0x90 )
81 #define FLASH_Reset                     FLASHWORD( 0xF0 )
82 #define FLASH_Program                   FLASHWORD( 0xA0 )
83 #define FLASH_Block_Erase               FLASHWORD( 0x30 )
84 #define FLASH_Load_Buffer               FLASHWORD( 0x25 )
85 #define FLASH_Flush_Buffer              FLASHWORD( 0x29 )
86
87 #define FLASH_Data                      FLASHWORD( 0x80 ) // Data complement
88 #define FLASH_Busy                      FLASHWORD( 0x40 ) // "Toggle" bit
89 #define FLASH_Err                       FLASHWORD( 0x20 )
90 #define FLASH_Sector_Erase_Timer        FLASHWORD( 0x08 )
91
92 #define FLASH_unlocked                  FLASHWORD( 0x00 )
93
94 #ifndef CYGNUM_FLASH_16AS8
95 #define _16AS8 0
96 #else
97 #define _16AS8 CYGNUM_FLASH_16AS8
98 #endif
99
100
101 # if (_16AS8 == 0)||CYGHWR_DEVS_FLASH_ST_M29W320D
102 # define FLASH_Setup_Addr1              (0x555)
103 # define FLASH_Setup_Addr2              (0x2AA)
104 # define FLASH_VendorID_Addr            (0)
105 # define FLASH_DeviceID_Addr            (1)
106 # define FLASH_DeviceID_Addr2           (0x0e)
107 # define FLASH_DeviceID_Addr3           (0x0f)
108 # define FLASH_WP_Addr                  (2)
109 #else
110 # define FLASH_Setup_Addr1              (0xAAA)
111 # define FLASH_Setup_Addr2              (0x555)
112 # define FLASH_VendorID_Addr            (0)
113 # define FLASH_DeviceID_Addr            (2)
114 # define FLASH_DeviceID_Addr2           (0x1c)
115 # define FLASH_DeviceID_Addr3           (0x1e)
116 # define FLASH_WP_Addr                  (4)
117 #endif
118
119 #define FLASH_Setup_Code1               FLASHWORD( 0xAA )
120 #define FLASH_Setup_Code2               FLASHWORD( 0x55 )
121 #define FLASH_Setup_Erase               FLASHWORD( 0x80 )
122
123 // Platform code must define the below
124 // #define CYGNUM_FLASH_INTERLEAVE      : Number of interleaved devices (in parallel)
125 // #define CYGNUM_FLASH_SERIES          : Number of devices in series
126 // #define CYGNUM_FLASH_WIDTH           : Width of devices on platform
127 // #define CYGNUM_FLASH_BASE            : Address of first device
128
129 // Platform code may define some or all of the below, to provide
130 // timeouts appropriate to the target hardware. The timeout
131 // values depend partly on the flash part being used, partly
132 // on the target (including bus and cpu speeds).
133 #ifndef CYGNUM_FLASH_TIMEOUT_QUERY
134 # define CYGNUM_FLASH_TIMEOUT_QUERY               500000
135 #endif
136 #ifndef CYGNUM_FLASH_TIMEOUT_ERASE_TIMER
137 # define CYGNUM_FLASH_TIMEOUT_ERASE_TIMER       10000000
138 #endif
139 #ifndef CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE
140 # define CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE    10000000
141 #endif
142 #ifndef CYGNUM_FLASH_TIMEOUT_PROGRAM
143 # define CYGNUM_FLASH_TIMEOUT_PROGRAM           10000000
144 #endif
145
146 #define CYGNUM_FLASH_BLANK              (1)
147
148 #ifndef FLASH_P2V
149 # define FLASH_P2V( _a_ ) ((volatile flash_data_t *)((CYG_ADDRWORD)(_a_)))
150 #endif
151 #ifndef CYGHWR_FLASH_AM29XXXXX_PLF_INIT
152 # define CYGHWR_FLASH_AM29XXXXX_PLF_INIT()
153 #endif
154
155 //----------------------------------------------------------------------------
156 // Now that device properties are defined, include magic for defining
157 // accessor type and constants.
158 #include <cyg/io/flash_dev.h>
159
160 //----------------------------------------------------------------------------
161 // Information about supported devices
162 typedef struct flash_dev_info {
163     cyg_bool     long_device_id;
164     flash_data_t device_id;
165     flash_data_t device_id2;
166     flash_data_t device_id3;
167     cyg_uint32   block_size;
168     cyg_int32    block_count;
169     cyg_uint32   base_mask;
170     cyg_uint32   device_size;
171     cyg_bool     bootblock;
172     cyg_uint32   bootblocks[64];         // 0 is bootblock offset, 1-11 sub-sector sizes (or 0)
173     cyg_bool     banked;
174     cyg_uint32   banks[16];               // bank offsets, highest to lowest (lowest should be 0)
175                                          // (only one entry for now, increase to support devices
176                                          // with more banks).
177     cyg_uint32   bufsiz;                 // write buffer size in units of flash_data_t
178 } flash_dev_info_t;
179
180 static const flash_dev_info_t* flash_dev_info;
181 static const flash_dev_info_t supported_devices[] = {
182 #include <cyg/io/flash_am29xxxxx_parts.inl>
183 };
184 #define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
185
186 //----------------------------------------------------------------------------
187 // Functions that put the flash device into non-read mode must reside
188 // in RAM.
189 #ifndef MXCFLASH_SELECT_MULTI
190 void flash_query(void* data) __attribute__ ((section (".2ram.flash_query")));
191 int  flash_erase_block(void* block, unsigned int size) 
192     __attribute__ ((section (".2ram.flash_erase_block")));
193 int  flash_program_buf(void* addr, void* data, int len)
194     __attribute__ ((section (".2ram.flash_program_buf")));
195
196 //----------------------------------------------------------------------------
197 // Auxiliary functions
198 static volatile flash_data_t * find_bank(volatile flash_data_t * base, void * addr, CYG_ADDRWORD * bo)
199     __attribute__ ((section (".2ram.find_bank")));
200 static flash_data_t * find_sector(volatile flash_data_t * addr, unsigned long *remain_size)
201     __attribute__ ((section (".2ram.find_sector")));
202
203 #else
204 void norflash_query(void* data);
205 int  norflash_erase_block(void* block, unsigned int size);
206 int  norflash_program_buf(void* addr, void* data, int len);
207
208 //----------------------------------------------------------------------------
209 // Auxiliary functions
210 static volatile flash_data_t * find_bank(volatile flash_data_t * base, void * addr, CYG_ADDRWORD * bo);
211 static flash_data_t * find_sector(volatile flash_data_t * addr, unsigned long *remain_size);
212 #endif //MXCFLASH_SELECT_MULTI
213
214 //----------------------------------------------------------------------------
215 // Flash Query
216 //
217 // Only reads the manufacturer and part number codes for the first
218 // device(s) in series. It is assumed that any devices in series
219 // will be of the same type.
220
221 void
222 #ifndef MXCFLASH_SELECT_MULTI
223 flash_query(void* data)
224 #else
225 norflash_query(void* data)
226 #endif
227 {
228     volatile flash_data_t *ROM;
229     volatile flash_data_t *f_s1, *f_s2;
230     flash_data_t* id = (flash_data_t*) data;
231     flash_data_t w;
232     long timeout = CYGNUM_FLASH_TIMEOUT_QUERY;
233
234     ROM = (flash_data_t*) CYGNUM_FLASH_BASE;
235     f_s1 = FLASH_P2V(ROM+FLASH_Setup_Addr1);
236     f_s2 = FLASH_P2V(ROM+FLASH_Setup_Addr2);
237
238     *f_s1 = FLASH_Reset;
239     w = *(FLASH_P2V(ROM));
240
241     *f_s1 = FLASH_Setup_Code1;
242     *f_s2 = FLASH_Setup_Code2;
243     *f_s1 = FLASH_Read_ID;
244
245     id[0] = -1;
246     id[1] = -1;
247
248     // Manufacturers' code
249     id[0] = *(FLASH_P2V(ROM+FLASH_VendorID_Addr));
250     // Part number
251     id[1] = *(FLASH_P2V(ROM+FLASH_DeviceID_Addr));
252     id[2] = *(FLASH_P2V(ROM+FLASH_DeviceID_Addr2));
253     id[3] = *(FLASH_P2V(ROM+FLASH_DeviceID_Addr3));
254
255
256     *(FLASH_P2V(ROM)) = FLASH_Reset;
257
258     // Stall, waiting for flash to return to read mode.
259     while ((--timeout != 0) && (w != *(FLASH_P2V(ROM)))) ;
260 }
261
262
263 //----------------------------------------------------------------------------
264 // Initialize driver details
265 int
266 #ifndef MXCFLASH_SELECT_MULTI
267 flash_hwr_init(void)
268 #else
269 norflash_hwr_init(void)
270 #endif
271 {
272     flash_data_t id[4];
273     int i;
274
275     CYGHWR_FLASH_AM29XXXXX_PLF_INIT();
276
277     flash_dev_query(id);
278
279     // Look through table for device data
280     flash_dev_info = supported_devices;
281     for (i = 0; i < NUM_DEVICES; i++) {
282         if (!flash_dev_info->long_device_id && flash_dev_info->device_id == id[1])
283             break;
284         else if ( flash_dev_info->long_device_id && flash_dev_info->device_id == id[1] 
285                   && flash_dev_info->device_id2 == id[2] 
286                   && flash_dev_info->device_id3 == id[3] )
287             break;
288         flash_dev_info++;
289     }
290
291     // Did we find the device? If not, return error.
292     if (NUM_DEVICES == i)
293         return FLASH_ERR_DRV_WRONG_PART;
294
295     // Hard wired for now
296     flash_info.block_size = flash_dev_info->block_size;
297     flash_info.blocks = flash_dev_info->block_count * CYGNUM_FLASH_SERIES;
298     flash_info.start = (void *)CYGNUM_FLASH_BASE;
299     flash_info.end = (void *)(CYGNUM_FLASH_BASE+ (flash_dev_info->device_size * CYGNUM_FLASH_SERIES));
300     return FLASH_ERR_OK;
301 }
302
303 //----------------------------------------------------------------------------
304 // Map a hardware status to a package error
305 int
306 #ifndef MXCFLASH_SELECT_MULTI
307 flash_hwr_map_error(int e)
308 #else
309 norflash_hwr_map_error(int e)
310 #endif
311 {
312     return e;
313 }
314
315
316 //----------------------------------------------------------------------------
317 // See if a range of FLASH addresses overlaps currently running code
318 bool
319 #ifndef MXCFLASH_SELECT_MULTI
320 flash_code_overlaps(void *start, void *end)
321 #else
322 norflash_code_overlaps(void *start, void *end)
323 #endif
324 {
325     extern unsigned char _stext[], _etext[];
326
327     return ((((unsigned long)&_stext >= (unsigned long)start) &&
328              ((unsigned long)&_stext < (unsigned long)end)) ||
329             (((unsigned long)&_etext >= (unsigned long)start) &&
330              ((unsigned long)&_etext < (unsigned long)end)));
331 }
332
333 //----------------------------------------------------------------------------
334 // Erase Block
335
336 int
337 #ifndef MXCFLASH_SELECT_MULTI
338 flash_erase_block(void* block, unsigned int size)
339 #else
340 norflash_erase_block(void* block, unsigned int size)
341 #endif
342 {
343     volatile flash_data_t* ROM, *BANK;
344     volatile flash_data_t* b_p = (flash_data_t*) block;
345     volatile flash_data_t *b_v;
346     volatile flash_data_t *f_s0, *f_s1, *f_s2;
347     int timeout = CYGNUM_FLASH_TIMEOUT_QUERY;
348     int len = 0;
349     int res = FLASH_ERR_OK;
350     flash_data_t state;
351     cyg_bool bootblock = false;
352     cyg_uint32 *bootblocks = (cyg_uint32 *)0;
353     CYG_ADDRWORD bank_offset;
354     ROM = (volatile flash_data_t*)((unsigned long)block & flash_dev_info->base_mask);
355     BANK = find_bank(ROM, block, &bank_offset);
356
357     f_s0 = FLASH_P2V(BANK);
358     f_s1 = FLASH_P2V(BANK + FLASH_Setup_Addr1);
359     f_s2 = FLASH_P2V(BANK + FLASH_Setup_Addr2);
360
361     // Assume not "boot" sector, full size
362     bootblock = false;
363     len = flash_dev_info->block_size;
364
365     // Is this in a "boot" sector?
366     if (flash_dev_info->bootblock) {
367         bootblocks = (cyg_uint32 *)&flash_dev_info->bootblocks[0];
368         while (*bootblocks != _LAST_BOOTBLOCK) {
369             if (*bootblocks++ == ((unsigned long)block - (unsigned long)ROM)) {
370                 len = *bootblocks++;  // Size of first sub-block
371                 bootblock = true;
372                 break;
373             } else {
374                 int ls = flash_dev_info->block_size;
375                 // Skip over segment
376                 while ((ls -= *bootblocks++) > 0) ;
377             }
378         }
379     }
380
381 #define CYGHWR_FLASH_AM29XXXXX_NO_WRITE_PROTECT
382
383     while (size > 0) {
384 #ifndef CYGHWR_FLASH_AM29XXXXX_NO_WRITE_PROTECT
385         // First check whether the block is protected
386         *f_s1 = FLASH_Setup_Code1;
387         *f_s2 = FLASH_Setup_Code2;
388         *f_s1 = FLASH_WP_State;
389         state = *FLASH_P2V(b_p+FLASH_WP_Addr);
390         *f_s0 = FLASH_Reset;
391
392         if (FLASH_unlocked != state)
393             return FLASH_ERR_PROTECT;
394 #endif
395
396         b_v = FLASH_P2V(b_p);
397     
398         // Send erase block command - six step sequence
399         *f_s1 = FLASH_Setup_Code1;
400         *f_s2 = FLASH_Setup_Code2;
401         *f_s1 = FLASH_Setup_Erase;
402         *f_s1 = FLASH_Setup_Code1;
403         *f_s2 = FLASH_Setup_Code2;
404         *b_v = FLASH_Block_Erase;
405
406         // Now poll for the completion of the sector erase timer (50us)
407         timeout = CYGNUM_FLASH_TIMEOUT_ERASE_TIMER;              // how many retries?
408         while (true) {
409             state = *b_v;
410             if ((state & FLASH_Sector_Erase_Timer)
411                                 == FLASH_Sector_Erase_Timer) break;
412
413             if (--timeout == 0) {
414                 res = FLASH_ERR_DRV_TIMEOUT;
415                 break;
416             }
417         }
418
419         // Then wait for erase completion.
420         if (FLASH_ERR_OK == res) {
421             timeout = CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE;
422             while (true) {
423                 state = *b_v;
424                 if (FLASH_BlankValue == state) {
425                     break;
426                 }
427
428                 // Don't check for FLASH_Err here since it will fail
429                 // with devices in parallel because these may finish
430                 // at different times.
431
432                 if (--timeout == 0) {
433                     res = FLASH_ERR_DRV_TIMEOUT;
434                     break;
435                 }
436             }
437         }
438
439         if (FLASH_ERR_OK != res)
440             *FLASH_P2V(ROM) = FLASH_Reset;
441
442         size -= len;  // This much has been erased
443
444         // Verify erase operation
445         while (len > 0) {
446             b_v = FLASH_P2V(b_p++);
447             if (*b_v != FLASH_BlankValue) {
448                 // Only update return value if erase operation was OK
449                 if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
450                 return res;
451             }
452             len -= sizeof(*b_p);
453         }
454
455         if (bootblock) {
456             len = *bootblocks++;
457         }
458     }
459     return res;
460 }
461
462
463 //----------------------------------------------------------------------------
464 // Program Buffer
465 int
466 #ifndef MXCFLASH_SELECT_MULTI
467 flash_program_buf(void* addr, void* data, int len)
468 #else
469 norflash_program_buf(void* addr, void* data, int len)
470 #endif
471 {
472     volatile flash_data_t* ROM;
473     volatile flash_data_t* BANK;
474     volatile flash_data_t* SECT=NULL;
475     volatile flash_data_t* data_ptr = (volatile flash_data_t*) data;
476     volatile flash_data_t* addr_p = (flash_data_t*) addr;
477     volatile flash_data_t* addr_v = FLASH_P2V(addr_p);
478     volatile flash_data_t *f_s1, *f_s2;
479     CYG_ADDRWORD bank_offset;
480     int timeout;
481     int res = FLASH_ERR_OK;
482     const CYG_ADDRWORD mask  =
483         flash_dev_info->bufsiz * sizeof (flash_data_t) - 1;
484     unsigned long rem_sect_size;
485     int remain;
486
487     // check the address is suitably aligned
488     if ((unsigned long)addr & (CYGNUM_FLASH_INTERLEAVE * CYGNUM_FLASH_WIDTH / 8 - 1))
489         return FLASH_ERR_INVALID;
490
491     // Base address of device(s) being programmed.
492     ROM = (volatile flash_data_t*)((unsigned long)addr_p & flash_dev_info->base_mask);
493     BANK = find_bank(ROM, addr, &bank_offset);
494
495     f_s1 = FLASH_P2V(BANK + FLASH_Setup_Addr1);
496     f_s2 = FLASH_P2V(BANK + FLASH_Setup_Addr2);
497     rem_sect_size = 0;
498     remain = len % sizeof (flash_data_t);
499     len /= sizeof (flash_data_t);
500
501     while (len > 0) {
502         flash_data_t state;
503         unsigned int nwords;
504
505         addr_v = FLASH_P2V(addr_p);
506
507         if (flash_dev_info->bufsiz > 1) {
508             // Assume buffer size is power of two
509             unsigned int i;
510             
511             if (rem_sect_size == 0) {
512                 SECT = find_sector(addr_v, &rem_sect_size);
513                 rem_sect_size /= sizeof (flash_data_t);
514             }
515
516             // Compute word count to write                
517             nwords = flash_dev_info->bufsiz
518                 - (((CYG_ADDRWORD) addr_v & mask) / sizeof (flash_data_t));
519             if (nwords > len)
520                 nwords = len;
521
522             // Initiate buffered write
523             *f_s1 = FLASH_Setup_Code1;
524             *f_s2 = FLASH_Setup_Code2;
525             *SECT = FLASH_Load_Buffer;
526             *SECT = FLASHWORD(nwords - 1);  // All devices need to see this
527
528             // Load data into write buffer, flush buffer
529             for(i = 0; i < nwords; i++)
530                 *addr_v++ = *data_ptr++;
531             --addr_v; --data_ptr;
532             *SECT = FLASH_Flush_Buffer;
533             rem_sect_size -= nwords;
534         } else {
535             // Program data [byte] - 4 step sequence
536             *f_s1 = FLASH_Setup_Code1;
537             *f_s2 = FLASH_Setup_Code2;
538             *f_s1 = FLASH_Program;
539             *addr_v = *data_ptr;
540             
541             nwords = 1;
542         }
543
544         addr_p += nwords;
545         timeout = CYGNUM_FLASH_TIMEOUT_PROGRAM;
546         while (true) {
547             state = *addr_v;
548             if (*data_ptr == state) {
549                 break;
550             }
551
552             // Can't check for FLASH_Err since it'll fail in parallel
553             // configurations.
554
555             if (--timeout == 0) {
556                 res = FLASH_ERR_DRV_TIMEOUT;
557                 break;
558             }
559         }
560
561         if (FLASH_ERR_OK != res)
562             *FLASH_P2V(ROM) = FLASH_Reset;
563
564         if (*addr_v != *data_ptr++) {
565             // Only update return value if erase operation was OK
566             if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
567             break;
568         }
569         len -= nwords;
570     }
571
572     // Program remaining bytes if len not a multiple of flash word size
573     if ((FLASH_ERR_OK == res) && remain)
574     {
575         // construct final word to be programmed with 0xff in the
576         // remaining bytes
577         flash_data_t final = (flash_data_t)-1;
578         unsigned char *src = (unsigned char *) data_ptr;
579         unsigned char *dst = (unsigned char *) &final;
580
581         while (remain--)
582             *dst++ = *src++;
583
584         addr_v = FLASH_P2V(addr_p);
585
586         // Program data [byte] - 4 step sequence
587         *f_s1 = FLASH_Setup_Code1;
588         *f_s2 = FLASH_Setup_Code2;
589         *f_s1 = FLASH_Program;
590         *addr_v = final;
591
592         timeout = CYGNUM_FLASH_TIMEOUT_PROGRAM;
593         while (true) {
594             flash_data_t state = *addr_v;
595             if (final == state) {
596                 break;
597             }
598
599             // Can't check for FLASH_Err since it'll fail in parallel
600             // configurations.
601
602             if (--timeout == 0) {
603                 res = FLASH_ERR_DRV_TIMEOUT;
604                 break;
605             }
606         }
607
608         if (FLASH_ERR_OK != res)
609             *FLASH_P2V(ROM) = FLASH_Reset;
610
611         if (*addr_v != final) {
612             // Only update return value if write operation was OK
613             if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
614         }
615     }
616
617     // Ideally, we'd want to return not only the failure code, but also
618     // the address/device that reported the error.
619     return res;
620 }
621
622 static volatile flash_data_t *
623 find_bank(volatile flash_data_t * base, void * addr, CYG_ADDRWORD * bo)
624 {
625     volatile flash_data_t * res = base;
626
627     if (flash_dev_info->banked) {
628         int b = 0;
629         *bo = (unsigned long)addr & ~(flash_dev_info->block_size-1);
630         *bo -= (unsigned long) base;
631         for(;;) {
632             if (*bo >= flash_dev_info->banks[b]) {
633                 res = (volatile flash_data_t*) ((unsigned long)base + flash_dev_info->banks[b]);
634                 break;
635             }
636             b++;
637         }
638     }
639     
640     return res;
641 }
642
643 static flash_data_t *
644 find_sector(volatile flash_data_t * addr, unsigned long *remain_size)
645 {
646     const CYG_ADDRESS mask = flash_dev_info->block_size - 1;
647     const CYG_ADDRESS a = (CYG_ADDRESS) addr;
648     const CYG_ADDRESS base = a & flash_dev_info->base_mask;
649     CYG_ADDRESS res = a & ~mask;
650     
651     *remain_size = flash_dev_info->block_size - (a & mask);
652
653     if (flash_dev_info->bootblock) {
654         cyg_uint32 * bootblocks = flash_dev_info->bootblocks;
655         while (*bootblocks != _LAST_BOOTBLOCK) {
656             if (*bootblocks++ == (res - base)) { /* Matching offset marker */
657                 while (res + *bootblocks <= a) {
658                     res += *bootblocks++;
659                 }
660                 *remain_size = *bootblocks - (a - res);
661                 break;
662             } else {
663                 int ls = flash_dev_info->block_size;
664                 // Skip over segment
665                 while ((ls -= *bootblocks++) > 0) ;
666             }
667         }
668     }
669     
670     return (flash_data_t *) res;
671 }
672
673 #endif // CYGONCE_DEVS_FLASH_AMD_AM29XXXXX_INL