1 //==========================================================================
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
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.
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
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.
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.
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.
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####
45 // Contributors: gthomas
50 //####DESCRIPTIONEND####
52 //==========================================================================
54 #include <pkgconf/system.h>
55 #include <pkgconf/io_flash.h>
57 #include <cyg/hal/hal_arch.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/hal/hal_cache.h>
62 #define _FLASH_PRIVATE_
63 #include <cyg/io/flash.h>
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"
73 struct flash_info flash_info;
75 // These are the functions in the HW specific driver we need to call.
76 typedef void code_fun(void*);
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;
86 flash_init(_printf *pf)
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) {
95 flash_info.block_mask = ~(flash_info.block_size-1);
100 // Use this function to make function pointers anonymous - forcing the
101 // compiler to use jumps instead of branches when calling driver
103 static void* __anonymizer(void* p)
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
112 flash_dev_query(void* data)
114 typedef void code_fun(void*);
115 code_fun *_flash_query;
116 int d_cache, i_cache;
118 _flash_query = (code_fun*) __anonymizer(&flash_query);
120 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
121 (*_flash_query)(data);
122 HAL_FLASH_CACHES_ON(d_cache, i_cache);
126 flash_verify_addr(void *target)
128 if (!flash_info.init) {
129 return FLASH_ERR_NOT_INIT;
131 if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
132 ((CYG_ADDRESS)target <= ( ((CYG_ADDRESS)flash_info.end) - 1) )) {
135 return FLASH_ERR_INVALID;
140 flash_get_limits(void *target, void **start, void **end)
142 if (!flash_info.init) {
143 return FLASH_ERR_NOT_INIT;
145 *start = flash_info.start;
146 *end = flash_info.end;
151 flash_get_block_info(int *block_size, int *blocks)
153 if (!flash_info.init) {
154 return FLASH_ERR_NOT_INIT;
156 *block_size = flash_info.block_size;
157 *blocks = flash_info.blocks;
162 flash_erase(void *addr, int len, void **err_addr)
164 unsigned short *block, *end_addr;
166 typedef int code_fun(unsigned short *, unsigned int);
167 code_fun *_flash_erase_block;
168 int d_cache, i_cache;
170 if (!flash_info.init) {
171 return FLASH_ERR_NOT_INIT;
174 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
175 if (plf_flash_query_soft_wp(addr,len))
176 return FLASH_ERR_PROTECT;
179 _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block);
181 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
182 end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
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);
189 #ifdef CYGSEM_IO_FLASH_CHATTER
190 (*flash_info.pf)("... Erase from %p-%p: ", (void*)block, (void*)end_addr);
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)
203 dp = (unsigned char *)block;
204 for (i = 0; i < flash_info.block_size; i++) {
205 if (*dp++ != (unsigned char)0xFF) {
215 stat = (*_flash_erase_block)(block, flash_info.block_size);
216 stat = flash_hwr_map_error(stat);
219 *err_addr = (void *)block;
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
232 #ifdef CYGSEM_IO_FLASH_CHATTER
233 (*flash_info.pf)(".");
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");
245 flash_program(void *_addr, void *_data, int len, void **err_addr)
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;
254 int d_cache, i_cache;
256 if (!flash_info.init) {
257 return FLASH_ERR_NOT_INIT;
260 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
261 if (plf_flash_query_soft_wp(addr,len))
262 return FLASH_ERR_PROTECT;
265 _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf);
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);
272 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
273 FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
276 if (size > flash_info.block_size) size = flash_info.block_size;
278 tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
280 tmp = flash_info.block_size - tmp;
281 if (size>tmp) size = tmp;
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) {
292 #ifdef CYGSEM_IO_FLASH_CHATTER
293 (*flash_info.pf)("V");
298 *err_addr = (void *)addr;
301 #ifdef CYGSEM_IO_FLASH_CHATTER
302 (*flash_info.pf)(".");
305 addr += size/sizeof(*addr);
306 data += size/sizeof(*data);
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");
317 flash_read(void *_addr, void *_data, int len, void **err_addr)
319 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
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;
327 int d_cache, i_cache;
329 if (!flash_info.init) {
330 return FLASH_ERR_NOT_INIT;
333 _flash_read_buf = (code_fun*) __anonymizer(&flash_read_buf);
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);
340 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
341 FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len));
344 if (size > flash_info.block_size) size = flash_info.block_size;
346 tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
348 tmp = flash_info.block_size - tmp;
349 if (size>tmp) size = tmp;
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) {
360 #ifdef CYGSEM_IO_FLASH_CHATTER
361 (*flash_info.pf)("V");
366 *err_addr = (void *)addr;
369 #ifdef CYGSEM_IO_FLASH_CHATTER
370 (*flash_info.pf)(".");
373 addr += size/sizeof(*addr);
374 data += size/sizeof(*data);
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");
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;
387 memcpy(_data, _addr, len);
392 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
395 flash_lock(void *addr, int len, void **err_addr)
397 unsigned short *block, *end_addr;
399 typedef int code_fun(unsigned short *);
400 code_fun *_flash_lock_block;
401 int d_cache, i_cache;
403 if (!flash_info.init) {
404 return FLASH_ERR_NOT_INIT;
407 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
408 if (plf_flash_query_soft_wp(addr,len))
409 return FLASH_ERR_PROTECT;
412 _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block);
414 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
415 end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
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);
422 #ifdef CYGSEM_IO_FLASH_CHATTER
423 (*flash_info.pf)("... Lock from %p-%p: ", block, end_addr);
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);
433 *err_addr = (void *)block;
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
446 #ifdef CYGSEM_IO_FLASH_CHATTER
447 (*flash_info.pf)(".");
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");
459 flash_unlock(void *addr, int len, void **err_addr)
461 unsigned short *block, *end_addr;
463 typedef int code_fun(unsigned short *, int, int);
464 code_fun *_flash_unlock_block;
465 int d_cache, i_cache;
467 if (!flash_info.init) {
468 return FLASH_ERR_NOT_INIT;
471 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
472 if (plf_flash_query_soft_wp(addr,len))
473 return FLASH_ERR_PROTECT;
476 _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block);
478 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
479 end_addr = (unsigned short *)((CYG_ADDRESS)addr+len);
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);
486 #ifdef CYGSEM_IO_FLASH_CHATTER
487 (*flash_info.pf)("... Unlock from %p-%p: ", block, end_addr);
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);
497 *err_addr = (void *)block;
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
509 #ifdef CYGSEM_IO_FLASH_CHATTER
510 (*flash_info.pf)(".");
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");
523 flash_errmsg(int err)
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";
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";
555 return "Unknown error";
559 // EOF io/flash/..../flash.c