Mercurial > nand-ecoscentric
view packages/io/flash/current/src/flash.c @ 177:4c750ce71ae3
Merge from eCos master repository on 2001-08-10-19:22:57-BST
| author | jlarmour |
|---|---|
| date | Fri, 10 Aug 2001 19:27:55 +0000 |
| parents | 38892b97b685 |
| children | 678094f34118 |
line wrap: on
line source
//========================================================================== // // flash.c // // Flash programming // //========================================================================== //####COPYRIGHTBEGIN#### // // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas // Date: 2000-07-26 // Purpose: // Description: // //####DESCRIPTIONEND#### // //========================================================================== #include <pkgconf/system.h> #include <pkgconf/io_flash.h> #include <cyg/hal/hal_arch.h> #include <cyg/hal/hal_intr.h> #include <cyg/hal/hal_cache.h> #define _FLASH_PRIVATE_ #include <cyg/io/flash.h> // When this flag is set, do not actually jump to the relocated code. // This can be used for running the function in place (RAM startup only), // allowing calls to diag_printf() and similar. #undef RAM_FLASH_DEV_DEBUG #if !defined(CYG_HAL_STARTUP_RAM) && defined(RAM_FLASH_DEV_DEBUG) # warning "Can only enable the flash debugging when configured for RAM startup" # undef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM #endif struct flash_info flash_info; int flash_init(void *work_space, int work_space_size, _printf *pf) { int err; if (flash_info.init) return FLASH_ERR_OK; flash_info.pf = pf; // Do this before calling into the driver flash_info.work_space = work_space; flash_info.work_space_size = work_space_size; if ((err = flash_hwr_init()) != FLASH_ERR_OK) { return err; } flash_info.block_mask = ~(flash_info.block_size-1); flash_info.init = 1; return FLASH_ERR_OK; } #ifndef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM // Use this function to make function pointers anonymous - forcing the // compiler to use jumps instead of branches when calling driver // services. static void* __anonymizer(void* p) { return p; } #endif // FIXME: Want to change all drivers to use this function. But it may // make sense to wait till device structure pointer arguments get // added as well. void flash_dev_query(void* data) { typedef void code_fun(void*); code_fun *_flash_query; int d_cache, i_cache; #ifdef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM { extern char flash_query[], flash_query_end[]; CYG_ADDRESS code_len; // Query the device driver - copy 'query' code to RAM for execution code_len = (CYG_ADDRESS)&flash_query_end - (CYG_ADDRESS)&flash_query; _flash_query = (code_fun *)flash_info.work_space; memcpy(_flash_query, &flash_query, code_len); } #else { externC code_fun flash_query; _flash_query = (code_fun*) __anonymizer(&flash_query); } #endif HAL_FLASH_CACHES_OFF(d_cache, i_cache); (*_flash_query)(data); HAL_FLASH_CACHES_ON(d_cache, i_cache); } int flash_verify_addr(void *target) { if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } if (((CYG_ADDRESS)target >= (CYG_ADDRESS)flash_info.start) && ((CYG_ADDRESS)target < (CYG_ADDRESS)flash_info.end)) { return FLASH_ERR_OK; } else { return FLASH_ERR_INVALID; } } int flash_get_limits(void *target, void **start, void **end) { if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } *start = flash_info.start; *end = flash_info.end; return FLASH_ERR_OK; } int flash_get_block_info(int *block_size, int *blocks) { if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } *block_size = flash_info.block_size; *blocks = flash_info.blocks; return FLASH_ERR_OK; } int flash_erase(void *addr, int len, void **err_addr) { unsigned short *block, *end_addr; int stat = 0; typedef int code_fun(unsigned short *, unsigned int); code_fun *_flash_erase_block; int d_cache, i_cache; if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT if (plf_flash_query_soft_wp(addr,len)) return FLASH_ERR_PROTECT; #endif #ifdef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM { extern char flash_erase_block[], flash_erase_block_end[]; CYG_ADDRESS code_len; // Copy 'erase' code to RAM for execution code_len = (CYG_ADDRESS)&flash_erase_block_end - (CYG_ADDRESS)&flash_erase_block; _flash_erase_block = (code_fun *)flash_info.work_space; memcpy(_flash_erase_block, &flash_erase_block, code_len); } #else { externC code_fun flash_erase_block; _flash_erase_block = (code_fun*) __anonymizer(&flash_erase_block); } #endif block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); (*flash_info.pf)("... Erase from %p-%p: ", (void*)block, (void*)end_addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(block, end_addr); while (block < end_addr) { // Supply the blocksize for a gross check for erase success stat = (*_flash_erase_block)(block, flash_info.block_size); stat = flash_hwr_map_error(stat); if (stat) { *err_addr = (void *)block; break; } block += flash_info.block_size / sizeof(*block); (*flash_info.pf)("."); } FLASH_Disable(block, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); (*flash_info.pf)("\n"); return (stat); } int flash_program(void *_addr, void *_data, int len, void **err_addr) { int stat = 0; int size; typedef int code_fun(void *, void *, int, unsigned long, int); code_fun *_flash_program_buf; unsigned char *addr = (unsigned char *)_addr; unsigned char *data = (unsigned char *)_data; CYG_ADDRESS tmp; int d_cache, i_cache; if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT if (plf_flash_query_soft_wp(addr,len)) return FLASH_ERR_PROTECT; #endif #ifdef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM { CYG_ADDRESS code_len; extern char flash_program_buf[], flash_program_buf_end[]; // Copy 'program' code to RAM for execution code_len = (CYG_ADDRESS)&flash_program_buf_end - (CYG_ADDRESS)&flash_program_buf; _flash_program_buf = (code_fun *)flash_info.work_space; memcpy(_flash_program_buf, &flash_program_buf, code_len); } #else { externC code_fun flash_program_buf; _flash_program_buf = (code_fun*) __anonymizer(&flash_program_buf); } #endif (*flash_info.pf)("... Program from %p-%p at %p: ", (void*)data, (void*)(((CYG_ADDRESS)data)+len), (void*)addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable((unsigned short*)addr, (unsigned short *)(addr+len)); while (len > 0) { size = len; if (size > flash_info.block_size) size = flash_info.block_size; tmp = (CYG_ADDRESS)addr & ~flash_info.block_mask; if (tmp) { tmp = flash_info.block_size - tmp; if (size>tmp) size = tmp; } stat = (*_flash_program_buf)(addr, data, size, flash_info.block_mask, flash_info.buffer_size); stat = flash_hwr_map_error(stat); #ifdef CYGSEM_IO_FLASH_VERIFY_PROGRAM if (0 == stat) // Claims to be OK if (memcmp(addr, data, size) != 0) { stat = 0x0BAD; (*flash_info.pf)("V"); } #endif if (stat) { *err_addr = (void *)addr; break; } (*flash_info.pf)("."); len -= size; addr += size/sizeof(*addr); data += size/sizeof(*data); } FLASH_Disable((unsigned short*)addr, (unsigned short *)(addr+len)); HAL_FLASH_CACHES_ON(d_cache, i_cache); (*flash_info.pf)("\n"); return (stat); } #ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING int flash_lock(void *addr, int len, void **err_addr) { unsigned short *block, *end_addr; int stat = 0; typedef int code_fun(unsigned short *); code_fun *_flash_lock_block; int d_cache, i_cache; if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT if (plf_flash_query_soft_wp(addr,len)) return FLASH_ERR_PROTECT; #endif #ifdef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM { extern char flash_lock_block[], flash_lock_block_end[]; CYG_ADDRESS code_len; // Copy 'lock' code to RAM for execution code_len = (CYG_ADDRESS)&flash_lock_block_end - (CYG_ADDRESS)&flash_lock_block; _flash_lock_block = (code_fun *)flash_info.work_space; memcpy(_flash_lock_block, &flash_lock_block, code_len); } #else { externC code_fun flash_lock_block; _flash_lock_block = (code_fun*) __anonymizer(&flash_lock_block); } #endif block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); (*flash_info.pf)("... Lock from %p-%p: ", block, end_addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(block, end_addr); while (block < end_addr) { stat = (*_flash_lock_block)(block); stat = flash_hwr_map_error(stat); if (stat) { *err_addr = (void *)block; break; } block += flash_info.block_size / sizeof(*block); (*flash_info.pf)("."); } FLASH_Disable(block, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); (*flash_info.pf)("\n"); return (stat); } int flash_unlock(void *addr, int len, void **err_addr) { unsigned short *block, *end_addr; int stat = 0; typedef int code_fun(unsigned short *, int, int); code_fun *_flash_unlock_block; int d_cache, i_cache; if (!flash_info.init) { return FLASH_ERR_NOT_INIT; } #ifdef CYGSEM_IO_FLASH_SOFT_WRITE_PROTECT if (plf_flash_query_soft_wp(addr,len)) return FLASH_ERR_PROTECT; #endif #ifdef CYGHWR_IO_FLASH_DEVICE_NOT_IN_RAM { extern char flash_unlock_block[], flash_unlock_block_end[]; CYG_ADDRESS code_len; // Copy 'lock' code to RAM for execution code_len = (CYG_ADDRESS)&flash_unlock_block_end - (CYG_ADDRESS)&flash_unlock_block; _flash_unlock_block = (code_fun *)flash_info.work_space; memcpy(_flash_unlock_block, &flash_unlock_block, code_len); } #else { externC code_fun flash_unlock_block; _flash_unlock_block = (code_fun*) __anonymizer(&flash_unlock_block); } #endif block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); (*flash_info.pf)("... Unlock from %p-%p: ", block, end_addr); HAL_FLASH_CACHES_OFF(d_cache, i_cache); FLASH_Enable(block, end_addr); while (block < end_addr) { stat = (*_flash_unlock_block)(block, flash_info.block_size, flash_info.blocks); stat = flash_hwr_map_error(stat); if (stat) { *err_addr = (void *)block; break; } block += flash_info.block_size / sizeof(*block); (*flash_info.pf)("."); } FLASH_Disable(block, end_addr); HAL_FLASH_CACHES_ON(d_cache, i_cache); (*flash_info.pf)("\n"); return (stat); } #endif char * flash_errmsg(int err) { switch (err) { case FLASH_ERR_OK: return "No error - operation complete"; case FLASH_ERR_ERASE_SUSPEND: return "Device is in erase suspend state"; case FLASH_ERR_PROGRAM_SUSPEND: return "Device is in program suspend state"; case FLASH_ERR_INVALID: return "Invalid FLASH address"; case FLASH_ERR_ERASE: return "Error trying to erase"; case FLASH_ERR_LOCK: return "Error trying to lock/unlock"; case FLASH_ERR_PROGRAM: return "Error trying to program"; case FLASH_ERR_PROTOCOL: return "Generic error"; case FLASH_ERR_PROTECT: return "Device/region is write-protected"; case FLASH_ERR_NOT_INIT: return "FLASH sub-system not initialized"; case FLASH_ERR_DRV_VERIFY: return "Data verify failed after operation"; case FLASH_ERR_DRV_TIMEOUT: return "Driver timed out waiting for device"; case FLASH_ERR_DRV_WRONG_PART: return "Driver does not support device"; case FLASH_ERR_LOW_VOLTAGE: return "Device reports low voltage"; default: return "Unknown error"; } } // EOF io/flash/..../flash.c
