root/ar5315_microredboot/microredboot/ecos/packages/io/flash/current/src/flash.c

Revision 12429, 16.2 kB (checked in by BrainSlayer, 5 months ago)

compressed ELF support is required for ubnt images

Line 
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 void diag_blink(void);
162 int
163 flash_erase(void *addr, int len, void **err_addr)
164 {
165     unsigned short *block, *end_addr;
166     int stat = 0;
167     typedef int code_fun(unsigned short *, unsigned int);
168     code_fun *_flash_erase_block;
169     int d_cache, i_cache;
170
171     if (!flash_info.init) {
172         return FLASH_ERR_NOT_INIT;
173     }
174
175 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
176     if (plf_flash_query_soft_wp(addr,len))
177         return FLASH_ERR_PROTECT;
178 #endif
179
180      _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block);
181
182     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
183     end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
184
185     /* Check to see if end_addr overflowed */
186     if( (end_addr < block) && (len > 0) ){
187         end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
188     }
189
190 #ifdef CYGSEM_IO_FLASH_CHATTER
191     (*flash_info.pf)("... Erase from %p-%p: ", (void*)block, (void*)end_addr);
192 #endif
193
194     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
195     FLASH_Enable(block, end_addr);
196     while (block < end_addr) {
197         // Supply the blocksize for a gross check for erase success
198         unsigned short *tmp_block;
199 #if !defined(CYGSEM_IO_FLASH_READ_INDIRECT)
200         int i;
201         unsigned char *dp;
202         bool erased = true;
203
204         dp = (unsigned char *)block;
205         for (i = 0;  i < flash_info.block_size;  i++) {
206             if (*dp++ != (unsigned char)0xFF) {
207                 erased = false;
208                 break;
209             }
210         }
211 #else
212         bool erased = false;
213 #endif
214
215         if (!erased) {
216             stat = (*_flash_erase_block)(block, flash_info.block_size);
217             stat = flash_hwr_map_error(stat);
218         }
219         if (stat) {
220             *err_addr = (void *)block;
221             break;
222         }
223
224         // Check to see if block will overflow
225         tmp_block = block + flash_info.block_size / sizeof(*block);
226         if(tmp_block < block){
227             // If block address overflows, set block value to end on this loop
228             block = end_addr;
229         }
230         else{
231             block = tmp_block;
232         }
233 #ifdef CYGSEM_IO_FLASH_CHATTER
234         (*flash_info.pf)(".");
235         diag_blink();
236 #endif
237     }
238     FLASH_Disable(block, end_addr);
239     HAL_FLASH_CACHES_ON(d_cache, i_cache);
240 #ifdef CYGSEM_IO_FLASH_CHATTER
241     (*flash_info.pf)("\n");
242 #endif
243     return (stat);
244 }
245
246 int
247 flash_program(void *_addr, void *_data, int len, void **err_addr)
248 {
249     int stat = 0;
250     int size;
251     typedef int code_fun(void *, void *, int, unsigned long, int);
252     code_fun *_flash_program_buf;
253     unsigned char *addr = (unsigned char *)_addr;
254     unsigned char *data = (unsigned char *)_data;
255     CYG_ADDRESS tmp;
256     int d_cache, i_cache;
257
258     if (!flash_info.init) {
259         return FLASH_ERR_NOT_INIT;
260     }
261
262 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
263     if (plf_flash_query_soft_wp(addr,len))
264         return FLASH_ERR_PROTECT;
265 #endif
266
267     _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf);
268
269 #ifdef CYGSEM_IO_FLASH_CHATTER
270     (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data,
271                      (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
272 #endif
273
274     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
275     FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
276     while (len > 0) {
277         size = len;
278         if (size > flash_info.block_size) size = flash_info.block_size;
279
280         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
281         if (tmp) {
282                 tmp = flash_info.block_size - tmp;
283                 if (size>tmp) size = tmp;
284
285         }
286
287         stat = (*_flash_program_buf)(addr, data, size,
288                                      flash_info.block_mask, flash_info.buffer_size);
289         stat = flash_hwr_map_error(stat);
290 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
291         if (0 == stat) // Claims to be OK
292             if (memcmp(addr, data, size) != 0) {               
293                 stat = 0x0BAD;
294 #ifdef CYGSEM_IO_FLASH_CHATTER
295                 (*flash_info.pf)("V");
296         diag_blink();
297 #endif
298             }
299 #endif
300         if (stat) {
301             *err_addr = (void *)addr;
302             break;
303         }
304 #ifdef CYGSEM_IO_FLASH_CHATTER
305         (*flash_info.pf)(".");
306         diag_blink();
307 #endif
308         len -= size;
309         addr += size/sizeof(*addr);
310         data += size/sizeof(*data);
311     }
312     FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
313     HAL_FLASH_CACHES_ON(d_cache, i_cache);
314 #ifdef CYGSEM_IO_FLASH_CHATTER
315     (*flash_info.pf)("\n");
316 #endif
317     return (stat);
318 }
319
320 int
321 flash_read(void *_addr, void *_data, int len, void **err_addr)
322 {
323 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
324     int stat = 0;
325     int size;
326     typedef int code_fun(void *, void *, int, unsigned long, int);
327     code_fun *_flash_read_buf;
328     unsigned char *addr = (unsigned char *)_addr;
329     unsigned char *data = (unsigned char *)_data;
330     CYG_ADDRESS tmp;
331     int d_cache, i_cache;
332
333     if (!flash_info.init) {
334         return FLASH_ERR_NOT_INIT;
335     }
336
337     _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf);
338
339 #ifdef CYGSEM_IO_FLASH_CHATTER
340     (*flash_info.pf)("... Read from %p-%p at %p: ", (void*)data,
341                      (void*)(((CYG_ADDRESS)data)+len), (void*)addr);
342 #endif
343
344     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
345     FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
346     while (len > 0) {
347         size = len;
348         if (size > flash_info.block_size) size = flash_info.block_size;
349
350         tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
351         if (tmp) {
352                 tmp = flash_info.block_size - tmp;
353                 if (size>tmp) size = tmp;
354
355         }
356
357         stat = (*_flash_read_buf)(addr, data, size,
358                                      flash_info.block_mask, flash_info.buffer_size);
359         stat = flash_hwr_map_error(stat);
360 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM_
361         if (0 == stat) // Claims to be OK
362             if (memcmp(addr, data, size) != 0) {               
363                 stat = 0x0BAD;
364 #ifdef CYGSEM_IO_FLASH_CHATTER
365                 (*flash_info.pf)("V");
366 #endif
367             }
368 #endif
369         if (stat) {
370             *err_addr = (void *)addr;
371             break;
372         }
373 #ifdef CYGSEM_IO_FLASH_CHATTER
374         (*flash_info.pf)(".");
375 #endif
376         len -= size;
377         addr += size/sizeof(*addr);
378         data += size/sizeof(*data);
379     }
380     FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len));
381     HAL_FLASH_CACHES_ON(d_cache, i_cache);
382 #ifdef CYGSEM_IO_FLASH_CHATTER
383     (*flash_info.pf)("\n");
384 #endif
385     return (stat);
386 #else // CYGSEM_IO_FLASH_READ_INDIRECT
387     // Direct access to FLASH memory is possible - just move the requested bytes
388     if (!flash_info.init) {
389         return FLASH_ERR_NOT_INIT;
390     }
391     memcpy(_data, _addr, len);
392     return FLASH_ERR_OK;
393 #endif
394 }
395
396 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
397
398 int
399 flash_lock(void *addr, int len, void **err_addr)
400 {
401     unsigned short *block, *end_addr;
402     int stat = 0;
403     typedef int code_fun(unsigned short *);
404     code_fun *_flash_lock_block;
405     int d_cache, i_cache;
406
407     if (!flash_info.init) {
408         return FLASH_ERR_NOT_INIT;
409     }
410
411 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
412     if (plf_flash_query_soft_wp(addr,len))
413         return FLASH_ERR_PROTECT;
414 #endif
415
416     _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block);
417
418     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
419     end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
420
421     /* Check to see if end_addr overflowed */
422     if( (end_addr < block) && (len > 0) ){
423         end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
424     }
425
426 #ifdef CYGSEM_IO_FLASH_CHATTER
427     (*flash_info.pf)("... Lock from %p-%p: ", block, end_addr);
428 #endif
429
430     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
431     FLASH_Enable(block, end_addr);
432     while (block < end_addr) {
433         unsigned short *tmp_block;
434         stat = (*_flash_lock_block)(block);
435         stat = flash_hwr_map_error(stat);
436         if (stat) {
437             *err_addr = (void *)block;
438             break;
439         }
440
441         // Check to see if block will overflow
442         tmp_block = block + flash_info.block_size / sizeof(*block);
443         if(tmp_block < block){
444             // If block address overflows, set block value to end on this loop
445             block = end_addr;
446         }
447         else{
448             block = tmp_block;
449         }
450 #ifdef CYGSEM_IO_FLASH_CHATTER
451         (*flash_info.pf)(".");
452 #endif
453     }
454     FLASH_Disable(block, end_addr);
455     HAL_FLASH_CACHES_ON(d_cache, i_cache);
456 #ifdef CYGSEM_IO_FLASH_CHATTER
457     (*flash_info.pf)("\n");
458 #endif
459     return (stat);
460 }
461
462 int
463 flash_unlock(void *addr, int len, void **err_addr)
464 {
465     unsigned short *block, *end_addr;
466     int stat = 0;
467     typedef int code_fun(unsigned short *, int, int);
468     code_fun *_flash_unlock_block;
469     int d_cache, i_cache;
470
471     if (!flash_info.init) {
472         return FLASH_ERR_NOT_INIT;
473     }
474
475 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
476     if (plf_flash_query_soft_wp(addr,len))
477         return FLASH_ERR_PROTECT;
478 #endif
479
480     _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block);
481
482     block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
483     end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
484
485     /* Check to see if end_addr overflowed */
486     if( (end_addr < block) && (len > 0) ){
487         end_addr = (unsigned short *) ((CYG_ADDRESS) flash_info.end - 1);
488     }
489
490 #ifdef CYGSEM_IO_FLASH_CHATTER
491     (*flash_info.pf)("... Unlock from %p-%p: ", block, end_addr);
492 #endif
493
494     HAL_FLASH_CACHES_OFF(d_cache, i_cache);
495     FLASH_Enable(block, end_addr);
496     while (block < end_addr) {
497         unsigned short *tmp_block;
498         stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
499         stat = flash_hwr_map_error(stat);
500         if (stat) {
501             *err_addr = (void *)block;
502             break;
503         }
504
505         tmp_block = block + flash_info.block_size / sizeof(*block);
506         if(tmp_block < block){
507             // If block address overflows, set block value to end on this loop
508             block = end_addr;
509         }
510         else{
511             block = tmp_block;
512         }
513 #ifdef CYGSEM_IO_FLASH_CHATTER
514         (*flash_info.pf)(".");
515 #endif
516     }
517     FLASH_Disable(block, end_addr);
518     HAL_FLASH_CACHES_ON(d_cache, i_cache);
519 #ifdef CYGSEM_IO_FLASH_CHATTER
520     (*flash_info.pf)("\n");
521 #endif
522     return (stat);
523 }
524 #endif
525
526 char *
527 flash_errmsg(int err)
528 {
529     switch (err) {
530     case FLASH_ERR_OK:
531         return "No error - operation complete";
532     case FLASH_ERR_ERASE_SUSPEND:
533         return "Device is in erase suspend state";
534     case FLASH_ERR_PROGRAM_SUSPEND:
535         return "Device is in program suspend state";
536     case FLASH_ERR_INVALID:
537         return "Invalid FLASH address";
538     case FLASH_ERR_ERASE:
539         return "Error trying to erase";
540     case FLASH_ERR_LOCK:
541         return "Error trying to lock/unlock";
542     case FLASH_ERR_PROGRAM:
543         return "Error trying to program";
544     case FLASH_ERR_PROTOCOL:
545         return "Generic error";
546     case FLASH_ERR_PROTECT:
547         return "Device/region is write-protected";
548     case FLASH_ERR_NOT_INIT:
549         return "FLASH sub-system not initialized";
550     case FLASH_ERR_DRV_VERIFY:
551         return "Data verify failed after operation";
552     case FLASH_ERR_DRV_TIMEOUT:
553         return "Driver timed out waiting for device";
554     case FLASH_ERR_DRV_WRONG_PART:
555         return "Driver does not support device";
556     case FLASH_ERR_LOW_VOLTAGE:
557         return "Device reports low voltage";
558     default:
559         return "Unknown error";
560     }
561 }
562
563 // EOF io/flash/..../flash.c
Note: See TracBrowser for help on using the browser.