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 flash_info.pf = pf; // Do this before calling into the driver
91 if (flash_info.init) return FLASH_ERR_OK;
93 if ((err = flash_hwr_init()) != FLASH_ERR_OK) {
96 flash_info.block_mask = ~(flash_info.block_size-1);
101 // Use this function to make function pointers anonymous - forcing the
102 // compiler to use jumps instead of branches when calling driver
104 static void *__anonymizer(void *p)
109 // FIXME: Want to change all drivers to use this function. But it may
110 // make sense to wait till device structure pointer arguments get
113 flash_dev_query(void *data)
115 typedef void code_fun(void *);
116 code_fun *_flash_query;
117 int d_cache, i_cache;
119 _flash_query = (code_fun*)__anonymizer(&flash_query);
121 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
122 (*_flash_query)(data);
123 HAL_FLASH_CACHES_ON(d_cache, i_cache);
127 flash_verify_addr(void *target)
129 if (!flash_info.init) {
130 return FLASH_ERR_NOT_INIT;
132 if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) &&
133 ((CYG_ADDRESS)target <= ((CYG_ADDRESS)flash_info.end - 1))) {
136 return FLASH_ERR_INVALID;
141 flash_get_limits(void *target, void **start, void **end)
143 if (!flash_info.init) {
144 return FLASH_ERR_NOT_INIT;
146 *start = flash_info.start;
147 *end = flash_info.end;
152 flash_get_block_info(int *block_size, int *blocks)
154 if (!flash_info.init) {
155 return FLASH_ERR_NOT_INIT;
157 *block_size = flash_info.block_size;
158 *blocks = flash_info.blocks;
163 flash_erase(void *addr, int len, void **err_addr)
165 unsigned short *block, *end_addr;
167 typedef int code_fun(unsigned short *, unsigned int);
168 code_fun *_flash_erase_block;
169 int d_cache, i_cache;
171 if (!flash_info.init) {
172 return FLASH_ERR_NOT_INIT;
175 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
176 if (plf_flash_query_soft_wp(addr,len))
177 return FLASH_ERR_PROTECT;
180 _flash_erase_block = (code_fun*)__anonymizer(&flash_erase_block);
182 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
183 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
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);
190 #ifdef CYGSEM_IO_FLASH_CHATTER
191 flash_info.pf("... Erase from %p-%p: ", block, end_addr);
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)
204 dp = (unsigned char *)block;
205 for (i = 0; i < flash_info.block_size; i++) {
216 stat = (*_flash_erase_block)(block, flash_info.block_size);
217 stat = flash_hwr_map_error(stat);
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
232 #ifdef CYGSEM_IO_FLASH_CHATTER
236 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask), end_addr);
237 HAL_FLASH_CACHES_ON(d_cache, i_cache);
238 #ifdef CYGSEM_IO_FLASH_CHATTER
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 = _addr;
252 unsigned char *data = _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: ", data,
269 (void *)((CYG_ADDRESS)data + len), addr);
272 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
273 FLASH_Enable(addr, addr + len);
276 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
277 if (flash_info.start != 0)
279 if (size > flash_info.block_size) size = flash_info.block_size;
281 tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
283 tmp = flash_info.block_size - tmp;
284 if (size > tmp) size = tmp;
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) {
294 #ifdef CYGSEM_IO_FLASH_CHATTER
303 #ifdef CYGSEM_IO_FLASH_CHATTER
307 addr += size/sizeof(*addr);
308 data += size/sizeof(*data);
310 FLASH_Disable(_addr, addr);
311 HAL_FLASH_CACHES_ON(d_cache, i_cache);
312 #ifdef CYGSEM_IO_FLASH_CHATTER
319 flash_read(void *_addr, void *_data, int len, void **err_addr)
321 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
324 typedef int code_fun(void *, void *, int, unsigned long, int);
325 code_fun *_flash_read_buf;
326 unsigned char *addr = _addr;
327 unsigned char *data = _data;
329 int d_cache, i_cache;
331 if (!flash_info.init) {
332 return FLASH_ERR_NOT_INIT;
335 _flash_read_buf = (code_fun*)__anonymizer(&flash_read_buf);
337 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
338 flash_info.pf("... Read from %p-%p at %p: ", data,
339 (void *)((CYG_ADDRESS)data + len), addr);
342 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
343 FLASH_Enable(addr, addr + len);
346 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
347 if (flash_info.start !=0)
349 if (size > flash_info.block_size) size = flash_info.block_size;
351 tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
353 tmp = flash_info.block_size - tmp;
354 if (size>tmp) size = tmp;
358 stat = (*_flash_read_buf)(addr, data, size,
359 flash_info.block_mask, flash_info.buffer_size);
360 stat = flash_hwr_map_error(stat);
361 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
362 if (0 == stat) // Claims to be OK
363 if (memcmp(addr, data, size) != 0) {
365 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
374 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
378 addr += size / sizeof(*addr);
379 data += size / sizeof(*data);
381 FLASH_Disable(_addr, addr);
382 HAL_FLASH_CACHES_ON(d_cache, i_cache);
383 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
387 #else // CYGSEM_IO_FLASH_READ_INDIRECT
388 // Direct access to FLASH memory is possible - just move the requested bytes
389 if (!flash_info.init) {
390 return FLASH_ERR_NOT_INIT;
392 memcpy(_data, _addr, len);
397 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
400 flash_lock(void *addr, int len, void **err_addr)
402 unsigned short *block, *end_addr;
404 typedef int code_fun(unsigned short *);
405 code_fun *_flash_lock_block;
406 int d_cache, i_cache;
408 if (!flash_info.init) {
409 return FLASH_ERR_NOT_INIT;
412 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
413 if (plf_flash_query_soft_wp(addr,len))
414 return FLASH_ERR_PROTECT;
417 _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
419 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
420 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
422 /* Check to see if end_addr overflowed */
423 if ((end_addr < block) && (len > 0)) {
424 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
427 #ifdef CYGSEM_IO_FLASH_CHATTER
428 flash_info.pf("... Lock from %p-%p: ", block, end_addr);
431 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
432 FLASH_Enable(block, end_addr);
433 while (block < end_addr) {
434 unsigned short *tmp_block;
435 stat = (*_flash_lock_block)(block);
436 stat = flash_hwr_map_error(stat);
442 // Check to see if block will overflow
443 tmp_block = block + flash_info.block_size / sizeof(*block);
444 if (tmp_block < block) {
445 // If block address overflows, set block value to end on this loop
450 #ifdef CYGSEM_IO_FLASH_CHATTER
454 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
456 HAL_FLASH_CACHES_ON(d_cache, i_cache);
457 #ifdef CYGSEM_IO_FLASH_CHATTER
464 flash_unlock(void *addr, int len, void **err_addr)
466 unsigned short *block, *end_addr;
468 typedef int code_fun(unsigned short *, int, int);
469 code_fun *_flash_unlock_block;
470 int d_cache, i_cache;
472 if (!flash_info.init) {
473 return FLASH_ERR_NOT_INIT;
476 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
477 if (plf_flash_query_soft_wp(addr,len))
478 return FLASH_ERR_PROTECT;
481 _flash_unlock_block = (code_fun*)__anonymizer(&flash_unlock_block);
483 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
484 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
486 /* Check to see if end_addr overflowed */
487 if ((end_addr < block) && (len > 0)) {
488 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
491 #ifdef CYGSEM_IO_FLASH_CHATTER
492 flash_info.pf("... Unlock from %p-%p: ", block, end_addr);
495 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
496 FLASH_Enable(block, end_addr);
497 while (block < end_addr) {
498 unsigned short *tmp_block;
499 stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
500 stat = flash_hwr_map_error(stat);
506 tmp_block = block + flash_info.block_size / sizeof(*block);
507 if (tmp_block < block) {
508 // If block address overflows, set block value to end on this loop
513 #ifdef CYGSEM_IO_FLASH_CHATTER
517 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
519 HAL_FLASH_CACHES_ON(d_cache, i_cache);
520 #ifdef CYGSEM_IO_FLASH_CHATTER
528 flash_errmsg(int err)
532 return "No error - operation complete";
533 case FLASH_ERR_ERASE_SUSPEND:
534 return "Device is in erase suspend state";
535 case FLASH_ERR_PROGRAM_SUSPEND:
536 return "Device is in program suspend state";
537 case FLASH_ERR_INVALID:
538 return "Invalid FLASH address";
539 case FLASH_ERR_ERASE:
540 return "Error trying to erase";
542 return "Error trying to lock/unlock";
543 case FLASH_ERR_PROGRAM:
544 return "Error trying to program";
545 case FLASH_ERR_PROTOCOL:
546 return "Generic error";
547 case FLASH_ERR_PROTECT:
548 return "Device/region is write-protected";
549 case FLASH_ERR_NOT_INIT:
550 return "FLASH sub-system not initialized";
551 case FLASH_ERR_DRV_VERIFY:
552 return "Data verify failed after operation";
553 case FLASH_ERR_DRV_TIMEOUT:
554 return "Driver timed out waiting for device";
555 case FLASH_ERR_DRV_WRONG_PART:
556 return "Driver does not support device";
557 case FLASH_ERR_LOW_VOLTAGE:
558 return "Device reports low voltage";
560 return "Unknown error";
564 // EOF io/flash/..../flash.c