]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/flash/amd/am29xxxxx/v2_0/include/flash_am29xxxxx.inl
Initial revision
[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 #if (_16AS8 == 0)
101 # define FLASH_Setup_Addr1              (0x555)
102 # define FLASH_Setup_Addr2              (0x2AA)
103 # define FLASH_VendorID_Addr            (0)
104 # define FLASH_DeviceID_Addr            (1)
105 # define FLASH_DeviceID_Addr2           (0x0e)
106 # define FLASH_DeviceID_Addr3           (0x0f)
107 # define FLASH_WP_Addr                  (2)
108 #else
109 # define FLASH_Setup_Addr1              (0xAAA)
110 # define FLASH_Setup_Addr2              (0x555)
111 # define FLASH_VendorID_Addr            (0)
112 # define FLASH_DeviceID_Addr            (2)
113 # define FLASH_DeviceID_Addr2           (0x1c)
114 # define FLASH_DeviceID_Addr3           (0x1e)
115 # define FLASH_WP_Addr                  (4)
116 #endif
117 #define FLASH_Setup_Code1               FLASHWORD( 0xAA )
118 #define FLASH_Setup_Code2               FLASHWORD( 0x55 )
119 #define FLASH_Setup_Erase               FLASHWORD( 0x80 )
120
121 // Platform code must define the below
122 // #define CYGNUM_FLASH_INTERLEAVE      : Number of interleaved devices (in parallel)
123 // #define CYGNUM_FLASH_SERIES          : Number of devices in series
124 // #define CYGNUM_FLASH_WIDTH           : Width of devices on platform
125 // #define CYGNUM_FLASH_BASE            : Address of first device
126
127 // Platform code may define some or all of the below, to provide
128 // timeouts appropriate to the target hardware. The timeout
129 // values depend partly on the flash part being used, partly
130 // on the target (including bus and cpu speeds).
131 #ifndef CYGNUM_FLASH_TIMEOUT_QUERY
132 # define CYGNUM_FLASH_TIMEOUT_QUERY               500000
133 #endif
134 #ifndef CYGNUM_FLASH_TIMEOUT_ERASE_TIMER
135 # define CYGNUM_FLASH_TIMEOUT_ERASE_TIMER       10000000
136 #endif
137 #ifndef CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE
138 # define CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE    10000000
139 #endif
140 #ifndef CYGNUM_FLASH_TIMEOUT_PROGRAM
141 # define CYGNUM_FLASH_TIMEOUT_PROGRAM           10000000
142 #endif
143
144 #define CYGNUM_FLASH_BLANK              (1)
145
146 #ifndef FLASH_P2V
147 # define FLASH_P2V( _a_ ) ((volatile flash_data_t *)((CYG_ADDRWORD)(_a_)))
148 #endif
149 #ifndef CYGHWR_FLASH_AM29XXXXX_PLF_INIT
150 # define CYGHWR_FLASH_AM29XXXXX_PLF_INIT()
151 #endif
152
153 //----------------------------------------------------------------------------
154 // Now that device properties are defined, include magic for defining
155 // accessor type and constants.
156 #include <cyg/io/flash_dev.h>
157
158 //----------------------------------------------------------------------------
159 // Information about supported devices
160 typedef struct flash_dev_info {
161     cyg_bool     long_device_id;
162     flash_data_t device_id;
163     flash_data_t device_id2;
164     flash_data_t device_id3;
165     cyg_uint32   block_size;
166     cyg_int32    block_count;
167     cyg_uint32   base_mask;
168     cyg_uint32   device_size;
169     cyg_bool     bootblock;
170     cyg_uint32   bootblocks[64];         // 0 is bootblock offset, 1-11 sub-sector sizes (or 0)
171     cyg_bool     banked;
172     cyg_uint32   banks[16];               // bank offsets, highest to lowest (lowest should be 0)
173                                          // (only one entry for now, increase to support devices
174                                          // with more banks).
175     cyg_uint32   bufsiz;                 // write buffer size in units of flash_data_t
176 } flash_dev_info_t;
177
178 static const flash_dev_info_t* flash_dev_info;
179 static const flash_dev_info_t supported_devices[] = {
180 #include <cyg/io/flash_am29xxxxx_parts.inl>
181 };
182 #define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
183
184 //----------------------------------------------------------------------------
185 // Functions that put the flash device into non-read mode must reside
186 // in RAM.
187 #ifndef MXCFLASH_SELECT_MULTI
188 void flash_query(void* data) __attribute__ ((section (".2ram.flash_query")));
189 int  flash_erase_block(void* block, unsigned int size) 
190     __attribute__ ((section (".2ram.flash_erase_block")));
191 int  flash_program_buf(void* addr, void* data, int len)
192     __attribute__ ((section (".2ram.flash_program_buf")));
193
194 //----------------------------------------------------------------------------
195 // Auxiliary functions
196 static volatile flash_data_t * find_bank(volatile flash_data_t * base, void * addr, CYG_ADDRWORD * bo)
197     __attribute__ ((section (".2ram.find_bank")));
198 static flash_data_t * find_sector(volatile flash_data_t * addr, unsigned long *remain_size)
199     __attribute__ ((section (".2ram.find_sector")));
200
201 #else
202 void norflash_query(void* data);
203 int  norflash_erase_block(void* block, unsigned int size);
204 int  norflash_program_buf(void* addr, void* data, int len);
205
206 //----------------------------------------------------------------------------
207 // Auxiliary functions
208 static volatile flash_data_t * find_bank(volatile flash_data_t * base, void * addr, CYG_ADDRWORD * bo);
209 static flash_data_t * find_sector(volatile flash_data_t * addr, unsigned long *remain_size);
210 #endif //MXCFLASH_SELECT_MULTI
211
212 //----------------------------------------------------------------------------
213 // Flash Query
214 //
215 // Only reads the manufacturer and part number codes for the first
216 // device(s) in series. It is assumed that any devices in series
217 // will be of the same type.
218
219 void
220 #ifndef MXCFLASH_SELECT_MULTI
221 flash_query(void* data)
222 #else
223 norflash_query(void* data)
224 #endif
225 {
226     volatile flash_data_t *ROM;
227     volatile flash_data_t *f_s1, *f_s2;
228     flash_data_t* id = (flash_data_t*) data;
229     flash_data_t w;
230     long timeout = CYGNUM_FLASH_TIMEOUT_QUERY;
231
232     ROM = (flash_data_t*) CYGNUM_FLASH_BASE;
233     f_s1 = FLASH_P2V(ROM+FLASH_Setup_Addr1);
234     f_s2 = FLASH_P2V(ROM+FLASH_Setup_Addr2);
235
236     *f_s1 = FLASH_Reset;
237     w = *(FLASH_P2V(ROM));
238
239     *f_s1 = FLASH_Setup_Code1;
240     *f_s2 = FLASH_Setup_Code2;
241     *f_s1 = FLASH_Read_ID;
242
243     id[0] = -1;
244     id[1] = -1;
245
246     // Manufacturers' code
247     id[0] = *(FLASH_P2V(ROM+FLASH_VendorID_Addr));
248     // Part number
249     id[1] = *(FLASH_P2V(ROM+FLASH_DeviceID_Addr));
250     id[2] = *(FLASH_P2V(ROM+FLASH_DeviceID_Addr2));
251     id[3] = *(FLASH_P2V(ROM+FLASH_DeviceID_Addr3));
252
253
254     *(FLASH_P2V(ROM)) = FLASH_Reset;
255
256     // Stall, waiting for flash to return to read mode.
257     while ((--timeout != 0) && (w != *(FLASH_P2V(ROM)))) ;
258 }
259
260
261 //----------------------------------------------------------------------------
262 // Initialize driver details
263 int
264 #ifndef MXCFLASH_SELECT_MULTI
265 flash_hwr_init(void)
266 #else
267 norflash_hwr_init(void)
268 #endif
269 {
270     flash_data_t id[4];
271     int i;
272
273     CYGHWR_FLASH_AM29XXXXX_PLF_INIT();
274
275     flash_dev_query(id);
276
277     // Look through table for device data
278     flash_dev_info = supported_devices;
279     for (i = 0; i < NUM_DEVICES; i++) {
280         if (!flash_dev_info->long_device_id && flash_dev_info->device_id == id[1])
281             break;
282         else if ( flash_dev_info->long_device_id && flash_dev_info->device_id == id[1] 
283                   && flash_dev_info->device_id2 == id[2] 
284                   && flash_dev_info->device_id3 == id[3] )
285             break;
286         flash_dev_info++;
287     }
288
289     // Did we find the device? If not, return error.
290     if (NUM_DEVICES == i)
291         return FLASH_ERR_DRV_WRONG_PART;
292
293     // Hard wired for now
294     flash_info.block_size = flash_dev_info->block_size;
295     flash_info.blocks = flash_dev_info->block_count * CYGNUM_FLASH_SERIES;
296     flash_info.start = (void *)CYGNUM_FLASH_BASE;
297     flash_info.end = (void *)(CYGNUM_FLASH_BASE+ (flash_dev_info->device_size * CYGNUM_FLASH_SERIES));
298     return FLASH_ERR_OK;
299 }
300
301 //----------------------------------------------------------------------------
302 // Map a hardware status to a package error
303 int
304 #ifndef MXCFLASH_SELECT_MULTI
305 flash_hwr_map_error(int e)
306 #else
307 norflash_hwr_map_error(int e)
308 #endif
309 {
310     return e;
311 }
312
313
314 //----------------------------------------------------------------------------
315 // See if a range of FLASH addresses overlaps currently running code
316 bool
317 #ifndef MXCFLASH_SELECT_MULTI
318 flash_code_overlaps(void *start, void *end)
319 #else
320 norflash_code_overlaps(void *start, void *end)
321 #endif
322 {
323     extern unsigned char _stext[], _etext[];
324
325     return ((((unsigned long)&_stext >= (unsigned long)start) &&
326              ((unsigned long)&_stext < (unsigned long)end)) ||
327             (((unsigned long)&_etext >= (unsigned long)start) &&
328              ((unsigned long)&_etext < (unsigned long)end)));
329 }
330
331 //----------------------------------------------------------------------------
332 // Erase Block
333
334 int
335 #ifndef MXCFLASH_SELECT_MULTI
336 flash_erase_block(void* block, unsigned int size)
337 #else
338 norflash_erase_block(void* block, unsigned int size)
339 #endif
340 {
341     volatile flash_data_t* ROM, *BANK;
342     volatile flash_data_t* b_p = (flash_data_t*) block;
343     volatile flash_data_t *b_v;
344     volatile flash_data_t *f_s0, *f_s1, *f_s2;
345     int timeout = CYGNUM_FLASH_TIMEOUT_QUERY;
346     int len = 0;
347     int res = FLASH_ERR_OK;
348     flash_data_t state;
349     cyg_bool bootblock = false;
350     cyg_uint32 *bootblocks = (cyg_uint32 *)0;
351     CYG_ADDRWORD bank_offset;
352     ROM = (volatile flash_data_t*)((unsigned long)block & flash_dev_info->base_mask);
353     BANK = find_bank(ROM, block, &bank_offset);
354
355     f_s0 = FLASH_P2V(BANK);
356     f_s1 = FLASH_P2V(BANK + FLASH_Setup_Addr1);
357     f_s2 = FLASH_P2V(BANK + FLASH_Setup_Addr2);
358
359     // Assume not "boot" sector, full size
360     bootblock = false;
361     len = flash_dev_info->block_size;
362
363     // Is this in a "boot" sector?
364     if (flash_dev_info->bootblock) {
365         bootblocks = (cyg_uint32 *)&flash_dev_info->bootblocks[0];
366         while (*bootblocks != _LAST_BOOTBLOCK) {
367             if (*bootblocks++ == ((unsigned long)block - (unsigned long)ROM)) {
368                 len = *bootblocks++;  // Size of first sub-block
369                 bootblock = true;
370                 break;
371             } else {
372                 int ls = flash_dev_info->block_size;
373                 // Skip over segment
374                 while ((ls -= *bootblocks++) > 0) ;
375             }
376         }
377     }
378
379 #define CYGHWR_FLASH_AM29XXXXX_NO_WRITE_PROTECT
380
381     while (size > 0) {
382 #ifndef CYGHWR_FLASH_AM29XXXXX_NO_WRITE_PROTECT
383         // First check whether the block is protected
384         *f_s1 = FLASH_Setup_Code1;
385         *f_s2 = FLASH_Setup_Code2;
386         *f_s1 = FLASH_WP_State;
387         state = *FLASH_P2V(b_p+FLASH_WP_Addr);
388         *f_s0 = FLASH_Reset;
389
390         if (FLASH_unlocked != state)
391             return FLASH_ERR_PROTECT;
392 #endif
393
394         b_v = FLASH_P2V(b_p);
395     
396         // Send erase block command - six step sequence
397         *f_s1 = FLASH_Setup_Code1;
398         *f_s2 = FLASH_Setup_Code2;
399         *f_s1 = FLASH_Setup_Erase;
400         *f_s1 = FLASH_Setup_Code1;
401         *f_s2 = FLASH_Setup_Code2;
402         *b_v = FLASH_Block_Erase;
403
404         // Now poll for the completion of the sector erase timer (50us)
405         timeout = CYGNUM_FLASH_TIMEOUT_ERASE_TIMER;              // how many retries?
406         while (true) {
407             state = *b_v;
408             if ((state & FLASH_Sector_Erase_Timer)
409                                 == FLASH_Sector_Erase_Timer) break;
410
411             if (--timeout == 0) {
412                 res = FLASH_ERR_DRV_TIMEOUT;
413                 break;
414             }
415         }
416
417         // Then wait for erase completion.
418         if (FLASH_ERR_OK == res) {
419             timeout = CYGNUM_FLASH_TIMEOUT_ERASE_COMPLETE;
420             while (true) {
421                 state = *b_v;
422                 if (FLASH_BlankValue == state) {
423                     break;
424                 }
425
426                 // Don't check for FLASH_Err here since it will fail
427                 // with devices in parallel because these may finish
428                 // at different times.
429
430                 if (--timeout == 0) {
431                     res = FLASH_ERR_DRV_TIMEOUT;
432                     break;
433                 }
434             }
435         }
436
437         if (FLASH_ERR_OK != res)
438             *FLASH_P2V(ROM) = FLASH_Reset;
439
440         size -= len;  // This much has been erased
441
442         // Verify erase operation
443         while (len > 0) {
444             b_v = FLASH_P2V(b_p++);
445             if (*b_v != FLASH_BlankValue) {
446                 // Only update return value if erase operation was OK
447                 if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
448                 return res;
449             }
450             len -= sizeof(*b_p);
451         }
452
453         if (bootblock) {
454             len = *bootblocks++;
455         }
456     }
457     return res;
458 }
459
460
461 //----------------------------------------------------------------------------
462 // Program Buffer
463 int
464 #ifndef MXCFLASH_SELECT_MULTI
465 flash_program_buf(void* addr, void* data, int len)
466 #else
467 norflash_program_buf(void* addr, void* data, int len)
468 #endif
469 {
470     volatile flash_data_t* ROM;
471     volatile flash_data_t* BANK;
472     volatile flash_data_t* SECT=NULL;
473     volatile flash_data_t* data_ptr = (volatile flash_data_t*) data;
474     volatile flash_data_t* addr_p = (flash_data_t*) addr;
475     volatile flash_data_t* addr_v = FLASH_P2V(addr_p);
476     volatile flash_data_t *f_s1, *f_s2;
477     CYG_ADDRWORD bank_offset;
478     int timeout;
479     int res = FLASH_ERR_OK;
480     const CYG_ADDRWORD mask  =
481         flash_dev_info->bufsiz * sizeof (flash_data_t) - 1;
482     unsigned long rem_sect_size;
483
484     // check the address is suitably aligned
485     if ((unsigned long)addr & (CYGNUM_FLASH_INTERLEAVE * CYGNUM_FLASH_WIDTH / 8 - 1))
486         return FLASH_ERR_INVALID;
487
488     // Base address of device(s) being programmed.
489     ROM = (volatile flash_data_t*)((unsigned long)addr_p & flash_dev_info->base_mask);
490     BANK = find_bank(ROM, addr, &bank_offset);
491
492     f_s1 = FLASH_P2V(BANK + FLASH_Setup_Addr1);
493     f_s2 = FLASH_P2V(BANK + FLASH_Setup_Addr2);
494     rem_sect_size = 0;
495     len /= sizeof (flash_data_t);
496
497     while (len > 0) {
498         flash_data_t state;
499         unsigned int nwords;
500
501         addr_v = FLASH_P2V(addr_p);
502
503         if (flash_dev_info->bufsiz > 1) {
504             // Assume buffer size is power of two
505             unsigned int i;
506             
507             if (rem_sect_size == 0) {
508                 SECT = find_sector(addr_v, &rem_sect_size);
509                 rem_sect_size /= sizeof (flash_data_t);
510             }
511
512             // Compute word count to write                
513             nwords = flash_dev_info->bufsiz
514                 - (((CYG_ADDRWORD) addr_v & mask) / sizeof (flash_data_t));
515             if (nwords > len)
516                 nwords = len;
517
518             // Initiate buffered write
519             *f_s1 = FLASH_Setup_Code1;
520             *f_s2 = FLASH_Setup_Code2;
521             *SECT = FLASH_Load_Buffer;
522             *SECT = FLASHWORD(nwords - 1);  // All devices need to see this
523
524             // Load data into write buffer, flush buffer
525             for(i = 0; i < nwords; i++)
526                 *addr_v++ = *data_ptr++;
527             --addr_v; --data_ptr;
528             *SECT = FLASH_Flush_Buffer;
529             rem_sect_size -= nwords;
530         } else {
531             // Program data [byte] - 4 step sequence
532             *f_s1 = FLASH_Setup_Code1;
533             *f_s2 = FLASH_Setup_Code2;
534             *f_s1 = FLASH_Program;
535             *addr_v = *data_ptr;
536             
537             nwords = 1;
538         }
539
540         addr_p += nwords;
541         timeout = CYGNUM_FLASH_TIMEOUT_PROGRAM;
542         while (true) {
543             state = *addr_v;
544             if (*data_ptr == state) {
545                 break;
546             }
547
548             // Can't check for FLASH_Err since it'll fail in parallel
549             // configurations.
550
551             if (--timeout == 0) {
552                 res = FLASH_ERR_DRV_TIMEOUT;
553                 break;
554             }
555         }
556
557         if (FLASH_ERR_OK != res)
558             *FLASH_P2V(ROM) = FLASH_Reset;
559
560         if (*addr_v != *data_ptr++) {
561             // Only update return value if erase operation was OK
562             if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
563             break;
564         }
565         len -= nwords;
566     }
567
568     // Ideally, we'd want to return not only the failure code, but also
569     // the address/device that reported the error.
570     return res;
571 }
572
573 static volatile flash_data_t *
574 find_bank(volatile flash_data_t * base, void * addr, CYG_ADDRWORD * bo)
575 {
576     volatile flash_data_t * res = base;
577
578     if (flash_dev_info->banked) {
579         int b = 0;
580         *bo = (unsigned long)addr & ~(flash_dev_info->block_size-1);
581         *bo -= (unsigned long) base;
582         for(;;) {
583             if (*bo >= flash_dev_info->banks[b]) {
584                 res = (volatile flash_data_t*) ((unsigned long)base + flash_dev_info->banks[b]);
585                 break;
586             }
587             b++;
588         }
589     }
590     
591     return res;
592 }
593
594 static flash_data_t *
595 find_sector(volatile flash_data_t * addr, unsigned long *remain_size)
596 {
597     const CYG_ADDRESS mask = flash_dev_info->block_size - 1;
598     const CYG_ADDRESS a = (CYG_ADDRESS) addr;
599     const CYG_ADDRESS base = a & flash_dev_info->base_mask;
600     CYG_ADDRESS res = a & ~mask;
601     
602     *remain_size = flash_dev_info->block_size - (a & mask);
603
604     if (flash_dev_info->bootblock) {
605         cyg_uint32 * bootblocks = flash_dev_info->bootblocks;
606         while (*bootblocks != _LAST_BOOTBLOCK) {
607             int ls = flash_dev_info->block_size;
608
609             if (*bootblocks++ == (res - base)) {
610                 while (res + *bootblocks < a) {
611                     res += *bootblocks++;
612                 }
613             } else {
614                 // Skip over segment
615                 while ((ls -= *bootblocks++) > 0) ;
616             }
617         }
618
619         if (*bootblocks != _LAST_BOOTBLOCK)   
620             *remain_size = *bootblocks - (a - res);
621     }
622     
623     return (flash_data_t *) res;
624 }
625
626 #endif // CYGONCE_DEVS_FLASH_AMD_AM29XXXXX_INL