Index: flash.c =================================================================== RCS file: /cvs/ecos/ecos/packages/redboot/current/src/flash.c,v retrieving revision 1.64 diff -u -r1.64 flash.c --- flash.c 24 Feb 2004 14:15:15 -0000 1.64 +++ flash.c 27 Feb 2004 11:33:21 -0000 @@ -54,9 +54,11 @@ //========================================================================== #include +#define _FLASH_PRIVATE_ #include #include #include +#include #ifdef CYGSEM_REDBOOT_FLASH_COMBINED_FIS_AND_CONFIG // Note horrid intertwining of functions, to save precious FLASH @@ -160,6 +162,22 @@ do_fis, __FIS_cmds_TAB__, &__FIS_cmds_TAB_END__ ); +#define FL_UP 1 +#if FL_UP +// 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; +} +static cmd_fun do_update; +RedBoot_cmd("update", + "Update RedBoot in flash", + "-b [ -l ]", + do_update + ); +#endif // Local data used by these routines void *flash_start, *flash_end; @@ -1156,6 +1174,91 @@ } } } + +#if FL_UP +typedef int erase_fun(unsigned short, unsigned int); +typedef int program_fun(void *, void *, int, unsigned long, int); +typedef int update_fun(unsigned char *, int, erase_fun, program_fun); + +static void __flash_update(unsigned char *, int , erase_fun *, program_fun * ) __attribute__ ((section (".2ram.redboot_update"))); + +void +__flash_update(unsigned char *ram_addr, int len, erase_fun *_flash_erase_block, program_fun *_flash_program_buf) +{ + int stat = 0,size; + unsigned short *block, *end_addr; + int d_cache,i_cache; + unsigned int block_mask = flash_info.block_mask; + unsigned int block_size = flash_info.block_size; + unsigned int buffer_size = flash_info.buffer_size; + unsigned char * addr = (CYG_ADDRESS)flash_start + CYGBLD_REDBOOT_FLASH_BOOT_OFFSET+0x20000; + block = (unsigned short *)((CYG_ADDRESS)addr & flash_info.block_mask); + end_addr = (unsigned short *)((CYG_ADDRESS)addr+len); + + HAL_FLASH_CACHES_OFF(d_cache, i_cache); + FLASH_Enable(block, end_addr); + while (block < end_addr) { + + stat = (*_flash_erase_block)(block, block_size); + //diag_printf("Erasing at %X size %X\n", block, block_size); + + block += block_size / sizeof(*block); + } + + while (len > 0) { + size = len; + if (size > block_size) { + size = block_size; + } + + stat = (*_flash_program_buf)(addr, ram_addr, size, + block_mask, buffer_size); + //diag_printf("Programming at %X form RAM %X size %X\n", addr, ram_addr, size); + + + len -= size; + addr += size/sizeof(*addr); + ram_addr += size/sizeof(*ram_addr); + } + FLASH_Disable(block, end_addr); + HAL_FLASH_CACHES_ON(d_cache, i_cache); + while(1); +} + +static void +do_update(int argc, char *argv[]) +{ + bool mem_addr_set = false; + bool length_set = false; + unsigned int mem_addr; + long length; + struct option_info opts[2]; + + externC erase_fun flash_erase_block; + externC program_fun flash_program_buf; + update_fun * update = (update_fun *)__anonymizer(&__flash_update); + + init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, + (void *)&mem_addr, (bool *)&mem_addr_set, "memory base address"); + init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, + (void *)&length, (bool *)&length_set, "image length"); + + if (!scan_opts(argc, argv, 1, opts, 2, 0, 0, "")) + return; + + if (!length_set) { + length = CYGBLD_REDBOOT_MIN_IMAGE_SIZE; + } + + if (!mem_addr_set) + { + diag_printf("Specify RAM address of image\n"); + return; + } + + (*update)(mem_addr, length, (erase_fun*)__anonymizer(&flash_erase_block), (program_fun*)__anonymizer(&flash_program_buf)); +} +#endif static void fis_erase(int argc, char *argv[])