]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/io/flash/v2_0/src/flash.c
4276a6053693f292f2402bebaef2e7b902997d53
[karo-tx-redboot.git] / packages / io / flash / v2_0 / src / flash.c
1 //==========================================================================
2 //
3 //      flash.c
4 //
5 //      Flash programming
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-26
47 // Purpose:      
48 // Description:  
49 //              
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54 #include <pkgconf/system.h>
55 #include <pkgconf/io_flash.h>
56
57 #include <cyg/hal/hal_arch.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/hal/hal_cache.h>
60 #include <string.h>
61
62 #define  _FLASH_PRIVATE_
63 #include <cyg/io/flash.h>
64
65 // When this flag is set, do not actually jump to the relocated code.
66 // This can be used for running the function in place (RAM startup only),
67 // allowing calls to diag_printf() and similar.
68 #undef RAM_FLASH_DEV_DEBUG
69 #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
70 # warning "Can only enable the flash debugging when configured for RAM startup"
71 #endif
72
73 struct flash_info flash_info;
74
75 // These are the functions in the HW specific driver we need to call.
76 typedef void code_fun(void*);
77
78 externC code_fun flash_query;
79 externC code_fun flash_erase_block;
80 externC code_fun flash_program_buf;
81 externC code_fun flash_read_buf;
82 externC code_fun flash_lock_block;
83 externC code_fun flash_unlock_block;
84
85 int
86 flash_init(_printf *pf)
87 {
88     int err;
89
90     if (flash_info.init) return FLASH_ERR_OK;
91     flash_info.pf = pf; // Do this before calling into the driver
92     if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
93         return err;
94     }
95     flash_info.block_mask = ~(flash_info.block_size-1);
96     flash_info.init = 1;
97     return FLASH_ERR_OK;
98 }
99
100 // Use this function to make function pointers anonymous - forcing the
101 // compiler to use jumps instead of branches when calling driver
102 // services.
103 static void* __anonymizer(void* p)
104 {
105   return p;
106 }
107
108 // FIXME: Want to change all drivers to use this function. But it may
109 // make sense to wait till device structure pointer arguments get
110 // added as well.
111 void
112 flash_dev_query(void* data)
113 {
114     typedef void code_fun(void*);
115     code_fun *_flash_query;
116     int d_cache, i_cache;
117
118     _flash_query = (code_fun*) __anonymizer(&flash_query);
119
120     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
121     (*_flash_query)(data);
122     HAL_FLASH_CACHES_ON(d_cache, i_cache);
123 }
124
125 int
126 flash_verify_addr(void *target)
127 {
128     if (!flash_info.init) {
129         return FLASH_ERR_NOT_INIT;
130     }
131     if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
132         ((CYG_ADDRESS)target <= ( ((CYG_ADDRESS)flash_info.end) - 1) )) {
133         return FLASH_ERR_OK;
134     } else {
135         return FLASH_ERR_INVALID;
136     }
137 }
138
139 int
140 flash_get_limits(void *target, void **start, void **end)
141 {
142     if (!flash_info.init) {
143         return FLASH_ERR_NOT_INIT;
144     }
145     *start = flash_info.start;
146     *end = flash_info.end;
147     return FLASH_ERR_OK;
148 }
149
150 int
151 flash_get_block_info(int *block_size, int *blocks)
152 {
153     if (!flash_info.init) {
154         return FLASH_ERR_NOT_INIT;
155     }
156     *block_size = flash_info.block_size;
157     *blocks = flash_info.blocks;
158     return FLASH_ERR_OK;
159 }
160
161 int
162 flash_erase(void *addr, int len, void **err_addr)
163 {
164     unsigned short *block, *end_addr;
165     int stat = 0;
166     typedef int code_fun(unsigned short *, unsigned int);
167     code_fun *_flash_erase_block;
168     int d_cache, i_cache;
169
170     if (!flash_info.init) {
171         return FLASH_ERR_NOT_INIT;
172     }
173
174 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
175     if (plf_flash_query_soft_wp(addr,len))
176         return FLASH_ERR_PROTECT;
177 #endif
178
179      _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block);
180
181     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
182     end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
183
184     /* Check to see if end_addr overflowed */
185     if( (end_addr < block) && (len > 0) ){
186         end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
187     }
188
189 #ifdef CYGSEM_IO_FLASH_CHATTER
190     (*flash_info.pf)("... Erase from %p-%p: ", (void*)block, (void*)end_addr);
191 #endif
192
193     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
194     FLASH_Enable(block, end_addr);
195     while (block < end_addr) {
196         // Supply the blocksize for a gross check for erase success
197         unsigned short *tmp_block;
198 #if !defined(CYGSEM_IO_FLASH_READ_INDIRECT)
199         int i;
200         unsigned char *dp;
201         bool erased = true;
202
203         dp = (unsigned char *)block;
204         for (i = 0;  i < flash_info.block_size;  i++) {
205             if (*dp++ != (unsigned char)0xFF) {
206                 erased = false;
207                 break;
208             }
209         }
210 #else
211         bool erased = false;
212 #endif
213
214         if (!erased) {
215             stat = (*_flash_erase_block)(block, flash_info.block_size);
216             stat = flash_hwr_map_error(stat);
217         }
218         if (stat) {
219             *err_addr = (void *)block;
220             break;
221         }
222
223         // Check to see if block will overflow
224         tmp_block = block + flash_info.block_size / sizeof(*block);
225         if(tmp_block < block){
226             // If block address overflows, set block value to end on this loop
227             block = end_addr;
228         }
229         else{
230             block = tmp_block;
231         }
232 #ifdef CYGSEM_IO_FLASH_CHATTER
233         (*flash_info.pf)(".");
234 #endif
235     }
236     FLASH_Disable(block, end_addr);
237     HAL_FLASH_CACHES_ON(d_cache, i_cache);
238 #ifdef CYGSEM_IO_FLASH_CHATTER
239     (*flash_info.pf)("\n");
240 #endif
241     return (stat);
242 }
243
244 int
245 flash_program(void *_addr, void *_data, int len, void **err_addr)
246 {
247     int stat = 0;
248     int size;
249     typedef int code_fun(void *, void *, int, unsigned long, int);
250     code_fun *_flash_program_buf;
251     unsigned char *addr = (unsigned char *)_addr;
252     unsigned char *data = (unsigned char *)_data;
253     CYG_ADDRESS tmp;
254     int d_cache, i_cache;
255
256     if (!flash_info.init) {
257         return FLASH_ERR_NOT_INIT;
258     }
259
260 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
261     if (plf_flash_query_soft_wp(addr,len))
262         return FLASH_ERR_PROTECT;
263 #endif
264
265     _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf);
266
267 #ifdef CYGSEM_IO_FLASH_CHATTER
268     (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data, 
269                      (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
270 #endif
271
272     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
273     FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
274     while (len > 0) {
275         size = len;
276         if (size > flash_info.block_size) size = flash_info.block_size;
277
278         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
279         if (tmp) {
280                 tmp = flash_info.block_size - tmp;
281                 if (size>tmp) size = tmp;
282
283         }
284
285         stat = (*_flash_program_buf)(addr, data, size, 
286                                      flash_info.block_mask, flash_info.buffer_size);
287         stat = flash_hwr_map_error(stat);
288 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
289         if (0 == stat) // Claims to be OK
290             if (memcmp(addr, data, size) != 0) {                
291                 stat = 0x0BAD;
292 #ifdef CYGSEM_IO_FLASH_CHATTER
293                 (*flash_info.pf)("V");
294 #endif
295             }
296 #endif
297         if (stat) {
298             *err_addr = (void *)addr;
299             break;
300         }
301 #ifdef CYGSEM_IO_FLASH_CHATTER
302         (*flash_info.pf)(".");
303 #endif
304         len -= size;
305         addr += size/sizeof(*addr);
306         data += size/sizeof(*data);
307     }
308     FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
309     HAL_FLASH_CACHES_ON(d_cache, i_cache);
310 #ifdef CYGSEM_IO_FLASH_CHATTER
311     (*flash_info.pf)("\n");
312 #endif
313     return (stat);
314 }
315
316 int
317 flash_read(void *_addr, void *_data, int len, void **err_addr)
318 {
319 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
320     int stat = 0;
321     int size;
322     typedef int code_fun(void *, void *, int, unsigned long, int);
323     code_fun *_flash_read_buf;
324     unsigned char *addr = (unsigned char *)_addr;
325     unsigned char *data = (unsigned char *)_data;
326     CYG_ADDRESS tmp;
327     int d_cache, i_cache;
328
329     if (!flash_info.init) {
330         return FLASH_ERR_NOT_INIT;
331     }
332
333     _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf);
334
335 #ifdef CYGSEM_IO_FLASH_CHATTER
336     (*flash_info.pf)("... Read from %p-%p at %p: ", (void*)data, 
337                      (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
338 #endif
339
340     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
341     FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
342     while (len > 0) {
343         size = len;
344         if (size > flash_info.block_size) size = flash_info.block_size;
345
346         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
347         if (tmp) {
348                 tmp = flash_info.block_size - tmp;
349                 if (size>tmp) size = tmp;
350
351         }
352
353         stat = (*_flash_read_buf)(addr, data, size, 
354                                      flash_info.block_mask, flash_info.buffer_size);
355         stat = flash_hwr_map_error(stat);
356 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM_
357         if (0 == stat) // Claims to be OK
358             if (memcmp(addr, data, size) != 0) {                
359                 stat = 0x0BAD;
360 #ifdef CYGSEM_IO_FLASH_CHATTER
361                 (*flash_info.pf)("V");
362 #endif
363             }
364 #endif
365         if (stat) {
366             *err_addr = (void *)addr;
367             break;
368         }
369 #ifdef CYGSEM_IO_FLASH_CHATTER
370         (*flash_info.pf)(".");
371 #endif
372         len -= size;
373         addr += size/sizeof(*addr);
374         data += size/sizeof(*data);
375     }
376     FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
377     HAL_FLASH_CACHES_ON(d_cache, i_cache);
378 #ifdef CYGSEM_IO_FLASH_CHATTER
379     (*flash_info.pf)("\n");
380 #endif
381     return (stat);
382 #else // CYGSEM_IO_FLASH_READ_INDIRECT
383     // Direct access to FLASH memory is possible - just move the requested bytes
384     if (!flash_info.init) {
385         return FLASH_ERR_NOT_INIT;
386     }
387     memcpy(_data, _addr, len);
388     return FLASH_ERR_OK;
389 #endif
390 }
391
392 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
393
394 int
395 flash_lock(void *addr, int len, void **err_addr)
396 {
397     unsigned short *block, *end_addr;
398     int stat = 0;
399     typedef int code_fun(unsigned short *);
400     code_fun *_flash_lock_block;
401     int d_cache, i_cache;
402
403     if (!flash_info.init) {
404         return FLASH_ERR_NOT_INIT;
405     }
406
407 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
408     if (plf_flash_query_soft_wp(addr,len))
409         return FLASH_ERR_PROTECT;
410 #endif
411
412     _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block);
413
414     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
415     end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
416
417     /* Check to see if end_addr overflowed */
418     if( (end_addr < block) && (len > 0) ){
419         end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
420     }
421
422 #ifdef CYGSEM_IO_FLASH_CHATTER
423     (*flash_info.pf)("... Lock from %p-%p: ", block, end_addr);
424 #endif
425
426     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
427     FLASH_Enable(block, end_addr);
428     while (block < end_addr) {
429         unsigned short *tmp_block;
430         stat = (*_flash_lock_block)(block);
431         stat = flash_hwr_map_error(stat);
432         if (stat) {
433             *err_addr = (void *)block;
434             break;
435         }
436
437         // Check to see if block will overflow
438         tmp_block = block + flash_info.block_size / sizeof(*block);
439         if(tmp_block < block){
440             // If block address overflows, set block value to end on this loop
441             block = end_addr;
442         }
443         else{
444             block = tmp_block;
445         }
446 #ifdef CYGSEM_IO_FLASH_CHATTER
447         (*flash_info.pf)(".");
448 #endif
449     }
450     FLASH_Disable(block, end_addr);
451     HAL_FLASH_CACHES_ON(d_cache, i_cache);
452 #ifdef CYGSEM_IO_FLASH_CHATTER
453     (*flash_info.pf)("\n");
454 #endif
455     return (stat);
456 }
457
458 int
459 flash_unlock(void *addr, int len, void **err_addr)
460 {
461     unsigned short *block, *end_addr;
462     int stat = 0;
463     typedef int code_fun(unsigned short *, int, int);
464     code_fun *_flash_unlock_block;
465     int d_cache, i_cache;
466
467     if (!flash_info.init) {
468         return FLASH_ERR_NOT_INIT;
469     }
470
471 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
472     if (plf_flash_query_soft_wp(addr,len))
473         return FLASH_ERR_PROTECT;
474 #endif
475
476     _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block);
477
478     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
479     end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
480
481     /* Check to see if end_addr overflowed */
482     if( (end_addr < block) && (len > 0) ){
483         end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
484     }
485
486 #ifdef CYGSEM_IO_FLASH_CHATTER
487     (*flash_info.pf)("... Unlock from %p-%p: ", block, end_addr);
488 #endif
489
490     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
491     FLASH_Enable(block, end_addr);
492     while (block < end_addr) {
493         unsigned short *tmp_block;
494         stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
495         stat = flash_hwr_map_error(stat);
496         if (stat) {
497             *err_addr = (void *)block;
498             break;
499         }
500
501         tmp_block = block + flash_info.block_size / sizeof(*block);
502         if(tmp_block < block){
503             // If block address overflows, set block value to end on this loop
504             block = end_addr;
505         }
506         else{
507             block = tmp_block;
508         }
509 #ifdef CYGSEM_IO_FLASH_CHATTER
510         (*flash_info.pf)(".");
511 #endif
512     }
513     FLASH_Disable(block, end_addr);
514     HAL_FLASH_CACHES_ON(d_cache, i_cache);
515 #ifdef CYGSEM_IO_FLASH_CHATTER
516     (*flash_info.pf)("\n");
517 #endif
518     return (stat);
519 }
520 #endif
521
522 char *
523 flash_errmsg(int err)
524 {
525     switch (err) {
526     case FLASH_ERR_OK:
527         return "No error - operation complete";
528     case FLASH_ERR_ERASE_SUSPEND:
529         return "Device is in erase suspend state";
530     case FLASH_ERR_PROGRAM_SUSPEND:
531         return "Device is in program suspend state";
532     case FLASH_ERR_INVALID:
533         return "Invalid FLASH address";
534     case FLASH_ERR_ERASE:
535         return "Error trying to erase";
536     case FLASH_ERR_LOCK:
537         return "Error trying to lock/unlock";
538     case FLASH_ERR_PROGRAM:
539         return "Error trying to program";
540     case FLASH_ERR_PROTOCOL:
541         return "Generic error";
542     case FLASH_ERR_PROTECT:
543         return "Device/region is write-protected";
544     case FLASH_ERR_NOT_INIT:
545         return "FLASH sub-system not initialized";
546     case FLASH_ERR_DRV_VERIFY:
547         return "Data verify failed after operation";
548     case FLASH_ERR_DRV_TIMEOUT:
549         return "Driver timed out waiting for device";
550     case FLASH_ERR_DRV_WRONG_PART:
551         return "Driver does not support device";
552     case FLASH_ERR_LOW_VOLTAGE:
553         return "Device reports low voltage";
554     default:
555         return "Unknown error";
556     }
557 }
558
559 // EOF io/flash/..../flash.c