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 //==========================================================================
53 #include <pkgconf/system.h>
54 #include <pkgconf/io_flash.h>
56 #include <cyg/hal/hal_arch.h>
57 #include <cyg/hal/hal_intr.h>
58 #include <cyg/hal/hal_cache.h>
61 #define _FLASH_PRIVATE_
62 #include <cyg/io/flash.h>
64 // When this flag is set, do not actually jump to the relocated code.
65 // This can be used for running the function in place (RAM startup only),
66 // allowing calls to diag_printf() and similar.
67 #undef RAM_FLASH_DEV_DEBUG
68 #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG)
69 # warning "Can only enable the flash debugging when configured for RAM startup"
72 struct flash_info flash_info;
74 // These are the functions in the HW specific driver we need to call.
75 typedef void code_fun(void *);
77 externC code_fun flash_query;
78 externC code_fun flash_erase_block;
79 externC code_fun flash_program_buf;
80 externC code_fun flash_read_buf;
81 externC code_fun flash_lock_block;
82 externC code_fun flash_unlock_block;
85 flash_init(_printf *pf)
89 flash_info.pf = pf; // Do this before calling into the driver
90 if (flash_info.init) return FLASH_ERR_OK;
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);
189 #ifdef CYGSEM_IO_FLASH_CHATTER
190 flash_info.pf("... Erase from %p-%p: ", block, 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++) {
215 stat = (*_flash_erase_block)(block, flash_info.block_size);
216 stat = flash_hwr_map_error(stat);
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
231 #ifdef CYGSEM_IO_FLASH_CHATTER
235 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
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 + len);
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;
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) {
364 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
373 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
377 addr += size / sizeof(*addr);
378 data += size / sizeof(*data);
380 FLASH_Disable(_addr, addr + len);
381 HAL_FLASH_CACHES_ON(d_cache, i_cache);
382 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
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;
391 memcpy(_data, _addr, len);
396 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
399 flash_lock(void *addr, int len, void **err_addr)
401 unsigned short *block, *end_addr;
403 typedef int code_fun(unsigned short *);
404 code_fun *_flash_lock_block;
405 int d_cache, i_cache;
407 if (!flash_info.init) {
408 return FLASH_ERR_NOT_INIT;
411 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
412 if (plf_flash_query_soft_wp(addr,len))
413 return FLASH_ERR_PROTECT;
416 _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
418 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
419 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
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);
426 #ifdef CYGSEM_IO_FLASH_CHATTER
427 flash_info.pf("... Lock from %p-%p: ", block, end_addr);
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);
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
449 #ifdef CYGSEM_IO_FLASH_CHATTER
453 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
455 HAL_FLASH_CACHES_ON(d_cache, i_cache);
456 #ifdef CYGSEM_IO_FLASH_CHATTER
463 flash_unlock(void *addr, int len, void **err_addr)
465 unsigned short *block, *end_addr;
467 typedef int code_fun(unsigned short *, int, int);
468 code_fun *_flash_unlock_block;
469 int d_cache, i_cache;
471 if (!flash_info.init) {
472 return FLASH_ERR_NOT_INIT;
475 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
476 if (plf_flash_query_soft_wp(addr,len))
477 return FLASH_ERR_PROTECT;
480 _flash_unlock_block = (code_fun*)__anonymizer(&flash_unlock_block);
482 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
483 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
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);
490 #ifdef CYGSEM_IO_FLASH_CHATTER
491 flash_info.pf("... Unlock from %p-%p: ", block, end_addr);
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);
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
512 #ifdef CYGSEM_IO_FLASH_CHATTER
516 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
518 HAL_FLASH_CACHES_ON(d_cache, i_cache);
519 #ifdef CYGSEM_IO_FLASH_CHATTER
527 flash_errmsg(int err)
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";
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";
559 return "Unknown error";
563 // EOF io/flash/..../flash.c