]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/flash/intel/28fxxx/v2_0/include/flash_28fxxx_w18.inl
RedBoot TX53 Release 2012-02-15
[karo-tx-redboot.git] / packages / devs / flash / intel / 28fxxx / v2_0 / include / flash_28fxxx_w18.inl
1 #ifndef CYGONCE_DEVS_FLASH_INTEL_28FXXX_INL
2 #define CYGONCE_DEVS_FLASH_INTEL_28FXXX_INL
3 //==========================================================================
4 //
5 //      flash_28fxxx.inl
6 //
7 //      Intel 28Fxxx 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 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):    jskov
47 // Contributors: jskov
48 // Date:         2001-03-21
49 // Purpose:
50 // Description:
51 //
52 // Notes:        Device table could use unions of flags to save some space
53 //
54 //####DESCRIPTIONEND####
55 //
56 //==========================================================================
57
58 #include <pkgconf/hal.h>
59 #include <pkgconf/io_flash.h>
60 #include <pkgconf/devs_flash_intel_28fxxx.h>
61
62 #include <cyg/hal/hal_arch.h>
63 #include <cyg/hal/hal_cache.h>
64 #include CYGHWR_MEMORY_LAYOUT_H
65
66 #include <cyg/hal/hal_io.h>
67
68 #define  _FLASH_PRIVATE_
69 #include <cyg/io/flash.h>
70
71 #define nDEBUG
72
73 #ifdef DEBUG
74 typedef void (*call_t)(char* str, ...);
75 extern void diag_printf(char* str, ...);
76 call_t d_print = &diag_printf;
77 #endif
78
79
80
81
82
83
84 //----------------------------------------------------------------------------
85 // Common device details.
86 #define FLASH_Read_ID                   FLASHWORD( 0x90 )
87 #define FLASH_Reset                     FLASHWORD( 0xFF )
88 #define FLASH_Program                   FLASHWORD( 0x40 )
89 #define FLASH_Write_Buffer              FLASHWORD( 0xe8 )
90 #define FLASH_Block_Erase               FLASHWORD( 0x20 )
91 #define FLASH_Confirm                   FLASHWORD( 0xD0 )
92 #define FLASH_Resume                    FLASHWORD( 0xD0 )
93
94 #define FLASH_Set_Lock                  FLASHWORD( 0x60 )
95 #define FLASH_Set_Lock_Confirm          FLASHWORD( 0x01 )
96 #define FLASH_Clear_Lock                FLASHWORD( 0x60 )
97 #define FLASH_Clear_Lock_Confirm        FLASHWORD( 0xd0 )
98 #define FLASH_Lock_State_Mask                   FLASHWORD( 0x03 )
99 #define FLASH_Status_Locked                             FLASHWORD( 0x01 )
100
101 #define FLASH_Read_Status               FLASHWORD( 0x70 )
102 #define FLASH_Clear_Status              FLASHWORD( 0x50 )
103 #define FLASH_Status_Ready              FLASHWORD( 0x80 )
104
105 // Status that we read back:
106 #define FLASH_ErrorMask                 FLASHWORD( 0x7E )
107 #define FLASH_ErrorProgram              FLASHWORD( 0x10 )
108 #define FLASH_ErrorErase                FLASHWORD( 0x20 )
109 #define FLASH_ErrorLock                 FLASHWORD( 0x30 )
110 #define FLASH_ErrorLowVoltage           FLASHWORD( 0x08 )
111 #define FLASH_ErrorLocked               FLASHWORD( 0x02 )
112
113 // Platform code must define the below
114 // #define CYGNUM_FLASH_INTERLEAVE      : Number of interleaved devices (in parallel)
115 // #define CYGNUM_FLASH_SERIES          : Number of devices in series
116 // #define CYGNUM_FLASH_WIDTH           : Width of devices on platform
117 // #define CYGNUM_FLASH_BASE            : Address of first device
118
119 #define CYGNUM_FLASH_BLANK              (1)
120 #define CYGNUM_FLASH_DEVICES            (CYGNUM_FLASH_INTERLEAVE*CYGNUM_FLASH_SERIES)
121
122
123 #ifndef FLASH_P2V
124 # define FLASH_P2V( _a_ ) ((volatile flash_data_t *)((CYG_ADDRWORD)(_a_)))
125 #endif
126 #ifndef CYGHWR_FLASH_28FXXX_PLF_INIT
127 # define CYGHWR_FLASH_28FXXX_PLF_INIT()
128 #endif
129 #ifndef CYGHWR_FLASH_WRITE_ENABLE
130 #define CYGHWR_FLASH_WRITE_ENABLE()
131 #endif
132 #ifndef CYGHWR_FLASH_WRITE_DISABLE
133 #define CYGHWR_FLASH_WRITE_DISABLE()
134 #endif
135
136 //----------------------------------------------------------------------------
137 // Now that device properties are defined, include magic for defining
138 // accessor type and constants.
139 #include <cyg/io/flash_dev.h>
140
141 //----------------------------------------------------------------------------
142 // Information about supported devices
143 typedef struct flash_dev_info {
144     flash_data_t device_id;
145     cyg_uint32   block_size;
146     cyg_int32    block_count;
147     cyg_uint32   base_mask;
148     cyg_uint32   device_size;
149     cyg_bool     locking;               // supports locking
150     cyg_bool     buffered_w;            // supports buffered writes
151     cyg_bool     bootblock;
152     cyg_uint32   bootblocks[12];         // 0 is bootblock offset, 1-11 sub-sector sizes (or 0)
153     cyg_bool     banked;
154     cyg_uint32   banks[2];               // bank offets, highest to lowest (lowest should be 0)
155                                          // (only one entry for now, increase to support devices
156                                          // with more banks).
157 } flash_dev_info_t;
158
159 static const flash_dev_info_t* flash_dev_info;
160 static const flash_dev_info_t supported_devices[] = {
161         #include <cyg/io/flash_28fxxx_parts.inl>
162 };
163
164
165
166 #define NUM_DEVICES (sizeof(supported_devices)/sizeof(flash_dev_info_t))
167
168
169
170 #if 1
171 //----------------------------------------------------------------------------
172 // Functions that put the flash device into non-read mode must reside
173 // in RAM.
174
175
176 void print_string(unsigned char *sp)
177     __attribute__ ((section (".2ram.print_string")));
178
179 void flash_query(void* data) __attribute__ ((section (".2ram.flash_query")));
180
181 int  flash_erase_block(void* block, unsigned int size)
182     __attribute__ ((section (".2ram.flash_erase_block")));
183 int  flash_program_buf(void* addr, void* data, int len,
184                        unsigned long block_mask, int buffer_size)
185     __attribute__ ((section (".2ram.flash_program_buf")));
186 int  flash_lock_block(void* addr)
187     __attribute__ ((section (".2ram.flash_lock_block")));
188 int flash_unlock_block(void* block, int block_size, int blocks, void *)
189     __attribute__ ((section (".2ram.flash_unlock_block")));
190
191
192
193
194 //----------------------------------------------------------------------------
195 #endif
196
197 #if 0
198                 while(1) {
199                         *((unsigned long *)0x40E0002C) = 0x04000000;    // clear GPIO90
200                         *((unsigned long *)0x40E00020) = 0x04000000;    // set GPIO90
201                 }
202 #endif
203
204 void print_string(unsigned char *sp) {
205
206         unsigned char   *cp;
207
208         unsigned long value;
209
210         cp = sp;
211
212
213
214
215
216         while((*cp) != 0x00) {
217                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
218                 *((volatile unsigned long *)0x40E00020) = 0x04000000;   // set GPIO90
219
220                 value = *((volatile unsigned long *)0x40100014);                //FFLSR
221
222
223                 while(!(value&0x40)){
224                         value = *((volatile unsigned long *)0x40100014);                //FFLSR
225                 }
226                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
227                 *((volatile unsigned long *)0x40E00020) = 0x04000000;   // set GPIO90
228
229                 *((volatile unsigned long *)0x40100000) = (unsigned long)*cp;                           //FFTHR
230
231                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
232                 *((volatile unsigned long *)0x40E00020) = 0x04000000;   // set GPIO90
233
234
235                 cp++;
236                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
237                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
238                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
239                 *((volatile unsigned long *)0x40E0002C) = 0x04000000;   // clear GPIO90
240                 *((volatile unsigned long *)0x40E00020) = 0x04000000;   // set GPIO90
241
242
243         }
244
245
246 }
247
248
249
250
251
252
253
254
255
256
257 // Initialize driver details
258 int
259 flash_hwr_init(void)
260 {
261         int i;
262         flash_data_t id[2];
263
264         CYGHWR_FLASH_28FXXX_PLF_INIT();
265
266         flash_dev_query(id);
267
268         // Look through table for device data
269         flash_dev_info = supported_devices;
270         for (i = 0; i < NUM_DEVICES; i++) {
271
272                 if (flash_dev_info->device_id == id[1])
273                         break;
274                 flash_dev_info++;
275         }
276
277         // Did we find the device? If not, return error.
278         if (NUM_DEVICES == i){
279                 return FLASH_ERR_DRV_WRONG_PART;
280         }
281
282         // Hard wired for now
283         flash_info.block_size = flash_dev_info->block_size;
284         flash_info.blocks = flash_dev_info->block_count * CYGNUM_FLASH_SERIES;
285         flash_info.start = (void *)CYGNUM_FLASH_BASE;
286         flash_info.end = (void *)(CYGNUM_FLASH_BASE + (flash_dev_info->device_size * CYGNUM_FLASH_SERIES));
287
288         return FLASH_ERR_OK;
289 }
290
291 //----------------------------------------------------------------------------
292 // Map a hardware status to a package error
293 int
294 flash_hwr_map_error(int e)
295 {
296         return e;
297 }
298
299
300 //----------------------------------------------------------------------------
301 // See if a range of FLASH addresses overlaps currently running code
302 bool
303 flash_code_overlaps(void *start, void *end)
304 {
305         extern unsigned char _stext[], _etext[];
306
307         return ((((unsigned long)&_stext >= (unsigned long)start) &&
308                  ((unsigned long)&_stext < (unsigned long)end)) ||
309                 (((unsigned long)&_etext >= (unsigned long)start) &&
310                  ((unsigned long)&_etext < (unsigned long)end)));
311 }
312
313 //----------------------------------------------------------------------------
314 // Flash Query
315 //
316 // Only reads the manufacturer and part number codes for the first
317 // device(s) in series. It is assumed that any devices in series
318 // will be of the same type.
319
320 void
321 flash_query(void* data)
322 {
323         volatile flash_data_t *ROM;
324         flash_data_t* id = (flash_data_t*) data;
325         flash_data_t w;
326
327         ROM = FLASH_P2V(CYGNUM_FLASH_BASE);
328         w = ROM[0];
329
330         CYGHWR_FLASH_WRITE_ENABLE();
331
332         ROM[0] = FLASH_Read_ID;
333
334         // Manufacturers' code
335         id[0] = ROM[0];
336         // Part number
337         id[1] = ROM[1];
338
339         ROM[0] = FLASH_Reset;
340
341         CYGHWR_FLASH_WRITE_DISABLE();
342
343         // Stall, waiting for flash to return to read mode.
344         while (w != ROM[0]);
345 }
346
347 //----------------------------------------------------------------------------
348 // Erase Block
349 int
350 flash_erase_block(void* block, unsigned int block_size)
351 {
352         int res = FLASH_ERR_OK;
353         int timeout;
354         unsigned long len;
355         int len_ix = 1;
356         flash_data_t stat;
357         volatile flash_data_t *ROM;
358         volatile flash_data_t *b_p = (flash_data_t*) block;
359         volatile flash_data_t *b_v;
360         cyg_bool bootblock;
361
362         ROM = FLASH_P2V((unsigned long)block & flash_dev_info->base_mask);
363
364         // Is this the boot sector?
365         bootblock = (flash_dev_info->bootblock &&
366                      (flash_dev_info->bootblocks[0] == ((unsigned long)block - (unsigned long)ROM)));
367         if (bootblock) {
368                 len = flash_dev_info->bootblocks[len_ix++];
369         } else {
370                 len = flash_dev_info->block_size;
371         }
372
373         CYGHWR_FLASH_WRITE_ENABLE();
374
375         while (len > 0) {
376                 b_v = FLASH_P2V(b_p);
377
378                 // Clear any error conditions
379                 *b_v = FLASH_Clear_Status;
380
381                 // Erase block
382                 *b_v = FLASH_Block_Erase;
383                 *b_v = FLASH_Confirm;
384
385                 timeout = 5000000;
386                 while(((stat = *b_v) & FLASH_Status_Ready) != FLASH_Status_Ready) {
387                         if (--timeout == 0) break;
388                 }
389
390                 // Restore ROM to "normal" mode
391                 *b_v = FLASH_Reset;
392
393
394
395
396                 if (stat & FLASH_ErrorMask) {
397                         if (!(stat & FLASH_ErrorErase)) {
398                                 res = FLASH_ERR_HWR;    // Unknown error
399                         } else {
400                                 if (stat & FLASH_ErrorLowVoltage)
401                                         res = FLASH_ERR_LOW_VOLTAGE;
402                                 else if (stat & FLASH_ErrorLocked)
403                                         res = FLASH_ERR_PROTECT;
404                                 else
405                                         res = FLASH_ERR_ERASE;
406                         }
407                 }
408
409                 // Check if block got erased
410
411                 while (len > 0) {
412                         b_v = FLASH_P2V(b_p);
413                         b_p++;
414                         if (*b_v != FLASH_BlankValue ) {
415                                 // Only update return value if erase operation was OK
416                                 if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
417                                 return res;
418                         }
419                         len -= sizeof(*b_p);
420                 }
421
422                 if (bootblock)
423                         len = flash_dev_info->bootblocks[len_ix++];
424         }
425
426         CYGHWR_FLASH_WRITE_DISABLE();
427
428         return res;
429 }
430
431 //----------------------------------------------------------------------------
432 // Program Buffer
433 int
434 flash_program_buf(void* addr, void* data, int len,
435                   unsigned long block_mask, int buffer_size)
436 {
437     flash_data_t stat = 0;
438     int timeout;
439     volatile flash_data_t* ROM;
440     volatile flash_data_t* addr_v;
441     volatile flash_data_t* addr_p = (flash_data_t*) addr;
442     volatile flash_data_t* data_p = (flash_data_t*) data;
443
444     int res = FLASH_ERR_OK;
445
446     // Base address of device(s) being programmed.
447     ROM = FLASH_P2V((unsigned long)addr & flash_dev_info->base_mask);
448
449     CYGHWR_FLASH_WRITE_ENABLE();
450
451     // Clear any error conditions
452     ROM[0] = FLASH_Clear_Status;
453
454     while (len > 0) {
455         addr_v = FLASH_P2V(addr_p);
456         addr_p++;
457         *addr_v = FLASH_Program;
458         *addr_v = *data_p;
459         timeout = 5000000;
460         while(((stat = *addr_v) & FLASH_Status_Ready) != FLASH_Status_Ready) {
461
462             if (--timeout == 0) {
463                 #ifdef DEBUG
464                                         d_print("status is 0x%08X \n", stat);
465                                 #endif
466                 res = FLASH_ERR_DRV_TIMEOUT;
467                 goto bad;
468             }
469         }
470         if (stat & FLASH_ErrorMask) {
471             if (!(stat & FLASH_ErrorProgram))
472                 res = FLASH_ERR_HWR;    // Unknown error
473             else {
474                 if (stat & FLASH_ErrorLowVoltage)
475                     res = FLASH_ERR_LOW_VOLTAGE;
476                 else if (stat & FLASH_ErrorLocked)
477                     res = FLASH_ERR_PROTECT;
478                 else
479                     res = FLASH_ERR_PROGRAM;
480             }
481             break;
482         }
483         *addr_v = FLASH_Clear_Status;
484         *addr_v = FLASH_Reset;
485         if (*addr_v != *data_p++) {
486             res = FLASH_ERR_DRV_VERIFY;
487             break;
488         }
489         len -= sizeof( flash_data_t );
490     }
491
492     // Restore ROM to "normal" mode
493  bad:
494     ROM[0] = FLASH_Reset;
495
496     CYGHWR_FLASH_WRITE_DISABLE();
497
498     // Ideally, we'd want to return not only the failure code, but also
499     // the address/device that reported the error.
500     return res;
501 }
502
503
504
505
506
507
508 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
509 //----------------------------------------------------------------------------
510 // Lock block
511 int
512 flash_lock_block(void* block)
513 {
514         volatile flash_data_t *ROM;
515         int res = FLASH_ERR_OK;
516         flash_data_t state;
517         int timeout = 5000000;
518         volatile flash_data_t* b_p = (flash_data_t*) block;
519         volatile flash_data_t *b_v;
520         cyg_bool bootblock;
521         int len, len_ix = 1;
522 #if 0
523         register unsigned long PC asm("pc");
524
525         unsigned char   testbuffer[3];
526
527         testbuffer[0]='o';
528         testbuffer[1]='k';
529         testbuffer[2]='\0';
530
531         *((volatile unsigned long *)0xa1000000) = PC;
532         *((volatile unsigned long *)0xa1000004) = testbuffer;
533
534         return res;
535
536         print_string(testbuffer);
537
538
539         testbuffer[0]='n';
540         testbuffer[1]='a';
541         testbuffer[2]='\0';
542
543         print_string(testbuffer);
544         return res;
545 #endif
546         if (!flash_dev_info->locking) {
547                 return res;
548         }
549 #ifdef DEBUG
550         d_print("flash_lock_block %08x\n", block);
551 #endif
552         //ROM = (volatile flash_data_t*)((unsigned long)block & flash_dev_info->base_mask);
553         ROM = FLASH_P2V((unsigned long)block & flash_dev_info->base_mask);
554
555         // Is this the boot sector?
556         bootblock = (flash_dev_info->bootblock &&
557                      (flash_dev_info->bootblocks[0] == ((unsigned long)block - (unsigned long)ROM)));
558         if (bootblock) {
559                 len = flash_dev_info->bootblocks[len_ix++];
560         } else {
561                 len = flash_dev_info->block_size;
562         }
563
564         CYGHWR_FLASH_WRITE_ENABLE();
565         while (len > 0) {
566                 b_v = FLASH_P2V(b_p);
567
568                 // Clear any error conditions
569                 *b_v = FLASH_Clear_Status;
570
571                 // Set lock bit
572                 *b_v = FLASH_Set_Lock;
573                 *b_v = FLASH_Set_Lock_Confirm;  // Confirmation
574                 *(b_v+2) = FLASH_Read_ID ;
575                 while(((state = *(b_v+2)) & FLASH_Lock_State_Mask) != FLASH_Status_Locked) {
576                         if (--timeout == 0) {
577                                 res = FLASH_ERR_DRV_TIMEOUT;
578                                 break;
579                         }
580                 }
581
582                 // Restore ROM to "normal" mode
583                 *b_v = FLASH_Reset;
584
585                 // Go to next block
586                 b_p += len / sizeof( flash_data_t );
587                 len = 0;
588
589                 if (FLASH_ErrorLock == (state & FLASH_ErrorLock))
590                         res = FLASH_ERR_LOCK;
591
592                 if (res != FLASH_ERR_OK)
593                         break;
594
595                 if (bootblock)
596                         len = flash_dev_info->bootblocks[len_ix++];
597         }
598
599         CYGHWR_FLASH_WRITE_DISABLE();
600
601         return res;
602 }
603 //----------------------------------------------------------------------------
604 // Unlock block
605
606 int
607 flash_unlock_block(void* block, int block_size, int blocks, void *myprint)
608 {
609         volatile flash_data_t *ROM;
610         int res = FLASH_ERR_OK;
611         flash_data_t state;
612         int timeout = 5000000;
613         volatile flash_data_t* b_p = (flash_data_t*) block;
614         volatile flash_data_t *b_v;
615         cyg_bool bootblock;
616         int len, len_ix = 1;
617         //void (*func_ptr)(void) = myprint;
618 #if 0
619         unsigned char   testbuffer[16];
620
621         testbuffer[0]='o';
622         testbuffer[1]='k';
623         testbuffer[2]='1';
624         testbuffer[3]='\r';
625         testbuffer[4]='\n';
626         testbuffer[5]='\0';
627 #endif
628
629         //*((unsigned long *)0xA0100000) = func_ptr;
630         //(*func_ptr)(testbuffer);
631         //(*func_ptr)("flash_unlock_block function entered now ....\n");
632         //return FLASH_ERR_OK;
633 #ifdef DEBUG
634         d_print("flash_unlock_block function entered ....\n");
635 #endif
636         if (!flash_dev_info->locking) {
637                 return res;
638         }
639         //ROM = (volatile flash_data_t*)((unsigned long)block & flash_dev_info->base_mask);
640         ROM = FLASH_P2V((unsigned long)block & flash_dev_info->base_mask);
641 #ifdef DEBUG
642         d_print("flash_unlock_block dev %08x block %08x size %08x count %08x\n", ROM, block, block_size, blocks);
643 #endif
644         // Is this the boot sector?
645         bootblock = (flash_dev_info->bootblock &&
646                      (flash_dev_info->bootblocks[0] == ((unsigned long)block - (unsigned long)ROM)));
647         if (bootblock) {
648                 len = flash_dev_info->bootblocks[len_ix++];
649         } else {
650                 len = flash_dev_info->block_size;
651         }
652
653         CYGHWR_FLASH_WRITE_ENABLE();
654
655         while (len > 0) {
656                 b_v = FLASH_P2V(b_p);
657                 // Clear any error conditions
658                 *b_v = FLASH_Clear_Status;
659
660                 // Clear lock bit
661                 *b_v = FLASH_Clear_Lock;
662                 *b_v = FLASH_Clear_Lock_Confirm;  // Confirmation
663
664                 *(b_v+2) = FLASH_Read_ID;
665
666                 while((state = *(b_v+2)) & FLASH_Lock_State_Mask)  {
667                         if (--timeout == 0) {
668                                 res = FLASH_ERR_DRV_TIMEOUT;
669                                 break;
670                         }
671                 }
672                 // Restore ROM to "normal" mode
673                 *b_v = FLASH_Reset;
674
675                 // Go to next block
676                 b_p += len / sizeof( flash_data_t );
677                 len = 0;
678                 if (FLASH_ErrorLock == (state & FLASH_ErrorLock)) {
679                         res = FLASH_ERR_LOCK;
680                 }
681                 if (res != FLASH_ERR_OK) {
682                         break;
683                 }
684                 if (bootblock) {
685                         len = flash_dev_info->bootblocks[len_ix++];
686                 }
687         }
688         CYGHWR_FLASH_WRITE_DISABLE();
689         // (*func_ptr)("leaving flash_unlock_block function now\n");
690
691         return res;
692
693         // FIXME: Unlocking need to support some other parts in the future
694         // as well which take a little more diddling.
695 }
696 #endif // CYGHWR_IO_FLASH_BLOCK_LOCKING
697 #endif // CYGONCE_DEVS_FLASH_INTEL_28FXXX_INL