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),
238 HAL_FLASH_CACHES_ON(d_cache, i_cache);
239 #ifdef CYGSEM_IO_FLASH_CHATTER
246 flash_program(void *_addr, void *_data, int len, void **err_addr)
250 typedef int code_fun(void *, void *, int, unsigned long, int);
251 code_fun *_flash_program_buf;
252 unsigned char *addr = _addr;
253 unsigned char *data = _data;
255 int d_cache, i_cache;
257 if (!flash_info.init) {
258 return FLASH_ERR_NOT_INIT;
261 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
262 if (plf_flash_query_soft_wp(addr,len))
263 return FLASH_ERR_PROTECT;
266 _flash_program_buf = (code_fun*)__anonymizer(&flash_program_buf);
268 #ifdef CYGSEM_IO_FLASH_CHATTER
269 flash_info.pf("... Program from %p-%p at %p: ", data,
270 (void *)((CYG_ADDRESS)data + len), addr);
273 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
274 FLASH_Enable(addr, addr + len);
277 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
278 if (flash_info.start != 0)
280 if (size > flash_info.block_size) size = flash_info.block_size;
282 tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
284 tmp = flash_info.block_size - tmp;
285 if (size > tmp) size = tmp;
288 stat = (*_flash_program_buf)(addr, data, size,
289 flash_info.block_mask, flash_info.buffer_size);
290 stat = flash_hwr_map_error(stat);
291 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
292 if (0 == stat) // Claims to be OK
293 if (memcmp(addr, data, size) != 0) {
295 #ifdef CYGSEM_IO_FLASH_CHATTER
304 #ifdef CYGSEM_IO_FLASH_CHATTER
308 addr += size / sizeof(*addr);
309 data += size / sizeof(*data);
311 FLASH_Disable(_addr, addr + len);
312 HAL_FLASH_CACHES_ON(d_cache, i_cache);
313 #ifdef CYGSEM_IO_FLASH_CHATTER
320 flash_read(void *_addr, void *_data, int len, void **err_addr)
322 #ifdef CYGSEM_IO_FLASH_READ_INDIRECT
325 typedef int code_fun(void *, void *, int, unsigned long, int);
326 code_fun *_flash_read_buf;
327 unsigned char *addr = _addr;
328 unsigned char *data = _data;
330 int d_cache, i_cache;
332 if (!flash_info.init) {
333 return FLASH_ERR_NOT_INIT;
336 _flash_read_buf = (code_fun*)__anonymizer(&flash_read_buf);
338 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
339 flash_info.pf("... Read from %p-%p at %p: ", data,
340 (void *)((CYG_ADDRESS)data + len), addr);
343 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
344 FLASH_Enable(addr, addr + len);
347 #if defined(MXCFLASH_SELECT_NAND) || defined(MXCFLASH_SELECT_MMC)
348 if (flash_info.start !=0)
350 if (size > flash_info.block_size) size = flash_info.block_size;
352 tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask;
354 tmp = flash_info.block_size - tmp;
355 if (size>tmp) size = tmp;
359 stat = (*_flash_read_buf)(addr, data, size,
360 flash_info.block_mask, flash_info.buffer_size);
361 stat = flash_hwr_map_error(stat);
362 #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM
363 if (0 == stat) // Claims to be OK
364 if (memcmp(addr, data, size) != 0) {
366 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
375 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
379 addr += size / sizeof(*addr);
380 data += size / sizeof(*data);
382 FLASH_Disable(_addr, addr + len);
383 HAL_FLASH_CACHES_ON(d_cache, i_cache);
384 #ifdef CYGSEM_IO_FLASH_CHATTER_VERBOSE
388 #else // CYGSEM_IO_FLASH_READ_INDIRECT
389 // Direct access to FLASH memory is possible - just move the requested bytes
390 if (!flash_info.init) {
391 return FLASH_ERR_NOT_INIT;
393 memcpy(_data, _addr, len);
398 #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
401 flash_lock(void *addr, int len, void **err_addr)
403 unsigned short *block, *end_addr;
405 typedef int code_fun(unsigned short *);
406 code_fun *_flash_lock_block;
407 int d_cache, i_cache;
409 if (!flash_info.init) {
410 return FLASH_ERR_NOT_INIT;
413 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
414 if (plf_flash_query_soft_wp(addr,len))
415 return FLASH_ERR_PROTECT;
418 _flash_lock_block = (code_fun*)__anonymizer(&flash_lock_block);
420 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
421 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
423 /* Check to see if end_addr overflowed */
424 if ((end_addr < block) && (len > 0)) {
425 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
428 #ifdef CYGSEM_IO_FLASH_CHATTER
429 flash_info.pf("... Lock from %p-%p: ", block, end_addr);
432 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
433 FLASH_Enable(block, end_addr);
434 while (block < end_addr) {
435 unsigned short *tmp_block;
436 stat = (*_flash_lock_block)(block);
437 stat = flash_hwr_map_error(stat);
443 // Check to see if block will overflow
444 tmp_block = block + flash_info.block_size / sizeof(*block);
445 if (tmp_block < block) {
446 // If block address overflows, set block value to end on this loop
451 #ifdef CYGSEM_IO_FLASH_CHATTER
455 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
457 HAL_FLASH_CACHES_ON(d_cache, i_cache);
458 #ifdef CYGSEM_IO_FLASH_CHATTER
465 flash_unlock(void *addr, int len, void **err_addr)
467 unsigned short *block, *end_addr;
469 typedef int code_fun(unsigned short *, int, int);
470 code_fun *_flash_unlock_block;
471 int d_cache, i_cache;
473 if (!flash_info.init) {
474 return FLASH_ERR_NOT_INIT;
477 #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT
478 if (plf_flash_query_soft_wp(addr,len))
479 return FLASH_ERR_PROTECT;
482 _flash_unlock_block = (code_fun*)__anonymizer(&flash_unlock_block);
484 block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask);
485 end_addr = (unsigned short *)((CYG_ADDRESS)addr + len);
487 /* Check to see if end_addr overflowed */
488 if ((end_addr < block) && (len > 0)) {
489 end_addr = (unsigned short *)((CYG_ADDRESS)flash_info.end - 1);
492 #ifdef CYGSEM_IO_FLASH_CHATTER
493 flash_info.pf("... Unlock from %p-%p: ", block, end_addr);
496 HAL_FLASH_CACHES_OFF(d_cache, i_cache);
497 FLASH_Enable(block, end_addr);
498 while (block < end_addr) {
499 unsigned short *tmp_block;
500 stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks);
501 stat = flash_hwr_map_error(stat);
507 tmp_block = block + flash_info.block_size / sizeof(*block);
508 if (tmp_block < block) {
509 // If block address overflows, set block value to end on this loop
514 #ifdef CYGSEM_IO_FLASH_CHATTER
518 FLASH_Disable((void *)((CYG_ADDRESS)addr & flash_info.block_mask),
520 HAL_FLASH_CACHES_ON(d_cache, i_cache);
521 #ifdef CYGSEM_IO_FLASH_CHATTER
529 flash_errmsg(int err)
533 return "No error - operation complete";
534 case FLASH_ERR_ERASE_SUSPEND:
535 return "Device is in erase suspend state";
536 case FLASH_ERR_PROGRAM_SUSPEND:
537 return "Device is in program suspend state";
538 case FLASH_ERR_INVALID:
539 return "Invalid FLASH address";
540 case FLASH_ERR_ERASE:
541 return "Error trying to erase";
543 return "Error trying to lock/unlock";
544 case FLASH_ERR_PROGRAM:
545 return "Error trying to program";
546 case FLASH_ERR_PROTOCOL:
547 return "Generic error";
548 case FLASH_ERR_PROTECT:
549 return "Device/region is write-protected";
550 case FLASH_ERR_NOT_INIT:
551 return "FLASH sub-system not initialized";
552 case FLASH_ERR_DRV_VERIFY:
553 return "Data verify failed after operation";
554 case FLASH_ERR_DRV_TIMEOUT:
555 return "Driver timed out waiting for device";
556 case FLASH_ERR_DRV_WRONG_PART:
557 return "Driver does not support device";
558 case FLASH_ERR_LOW_VOLTAGE:
559 return "Device reports low voltage";
561 return "Unknown error";
565 // EOF io/flash/..../flash.c