From: Erik M. <er...@us...> - 2001-10-15 21:52:12
|
Update of /cvsroot/blob/blob/src/blob In directory usw-pr-cvs1:/tmp/cvs-serv19896/src/blob Modified Files: flash.c Log Message: First cleanup of the flash code Index: flash.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/flash.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- flash.c 2001/10/14 20:24:32 1.3 +++ flash.c 2001/10/15 21:52:09 1.4 @@ -43,107 +43,185 @@ #include <blob/serial.h> #include <blob/flash.h> -/* define for advanced flash functionality (not that it works) -- Erik */ -/* #define ADVANCED_FLASH 1 */ +#include <blob/init.h> +#include <blob/command.h> +/* this is enough for a 16MB flash with 128kB blocks */ +#define NEW_NUM_FLASH_BLOCKS (128) -/* Static function defs */ -static u32 EraseOne(const char *whichOne); -#ifdef ADVANCED_FLASH -static void GetBlockOrder(tBlkInfo *blocksInfo, u8 which, - u8 blockOrder[NUM_FLASH_BLOCKS]); -#endif +typedef struct { + u32 start; + u32 size; + int lockable; +} flash_block_t; + +static flash_block_t flash_blocks[NEW_NUM_FLASH_BLOCKS]; +static int num_flash_blocks; -#ifdef ADVANCED_FLASH -void ScanFlash(tBlkInfo *blocksInfo) +/* initialise the flash blocks table */ +static void init_flash(void) { -/* Scans the flash for headers in the main blocks. Maybe in the future we will - put the headers in one of the parameter blocks. */ - int i,j; + int i = 0; + int j; + u32 start = 0; - j = 0; - for(i = 0; i < NUM_FLASH_BLOCKS; i++) { - MyMemCpy((u32 *) &(blocksInfo->headers[i]), - FLASH_BLOCK_BASE + i * FLASH_BLOCK_SIZE, - sizeof(tBlkHdr) / 4); - /* Is this a 'first' block ? */ - if(BLOCK_IN_USE(blocksInfo->headers[i]) - && (blocksInfo->headers[i].seqNum == 0)) - blocksInfo->firstBlockIndex[j++] = i; + num_flash_blocks = 0; + + while(flash_descriptors[i].size != 0) { +#ifdef BLOB_DEBUG + SerialOutputDec(flash_descriptors[i].num); + SerialOutputString("x 0x"); + SerialOutputHex(flash_descriptors[i].size); + SerialOutputString(", "); + + if(!flash_descriptors[i].lockable) + SerialOutputString("not "); + + SerialOutputString("lockable\n"); +#endif + + for(j = 0; j < flash_descriptors[i].num; j++) { + flash_blocks[num_flash_blocks].start = start; + flash_blocks[num_flash_blocks].size = + flash_descriptors[i].size; + flash_blocks[num_flash_blocks].lockable = + flash_descriptors[i].lockable; + + start += flash_descriptors[i].size; + + num_flash_blocks++; + + if(num_flash_blocks >= NEW_NUM_FLASH_BLOCKS) { + printerrprefix(); + SerialOutputString("not enough flash_blocks\n"); + break; + } + } + + i++; } - - for(; j < NUM_FLASH_BLOCKS; j++) - blocksInfo->firstBlockIndex[j] = NO_BLOCK; -} /* ScanFlash */ -#endif +#ifdef BLOB_DEBUG + SerialOutputString("Flash map:\n"); + for(i = 0; i < num_flash_blocks; i++) { + SerialOutputString(" 0x"); + SerialOutputHex(flash_blocks[i].size); + SerialOutputString(" @ 0x"); + SerialOutputHex(flash_blocks[i].start); + SerialOutputString(" ("); + SerialOutputDec(flash_blocks[i].size / 1024); + SerialOutputString(" kB), "); + if(!flash_blocks[i].lockable) + SerialOutputString("not "); + + SerialOutputString("lockable\n"); + } +#endif +} -#ifdef ADVANCED_FLASH -void LoadBlocksToMem(tBlkInfo *blocksInfo, u8 which, u32 *baseAddr) +__initlist(init_flash, INIT_LEVEL_OTHER_STUFF); + + +int flash_erase_region(u32 *start, u32 nwords) { -/* Load a series of blocks to memory */ - u8 blockOrder[NUM_FLASH_BLOCKS]; - int numBlocks = blocksInfo->headers[which].totSeq; - int i; - u32 *srcAddr, *dstAddr = baseAddr; - - /* If the block isn't in use, fail silently. */ - if(!BLOCK_IN_USE(blocksInfo->headers[which])) - return; - - GetBlockOrder(blocksInfo, which, blockOrder); - - for(i = 0; i < numBlocks; i++) { - srcAddr = FLASH_BLOCK_BASE + - blockOrder[i] * FLASH_BLOCK_SIZE + sizeof(tBlkHdr); - MyMemCpy(dstAddr, srcAddr, blocksInfo->headers[i].bytesInBlock / 4); - dstAddr += blocksInfo->headers[i].bytesInBlock / 4; + u32 *cur; + u32 *end; + int rv; + + cur = start; + end = start + nwords; + + while(cur < end) { + if(*cur != 0xffffffff) { + +#ifdef BLOB_DEBUG + SerialOutputString(__FUNCTION__ "(): erasing dirty block at 0x"); + SerialOutputHex((u32)cur); + SerialOutputByte('\n'); +#endif + /* dirty block */ + rv = erase_flash(cur); + + if(rv < 0) { + printerrprefix(); + SerialOutputString("flash erase error at 0x"); + SerialOutputHex((u32)cur); + SerialOutputByte('\n'); + return rv; + } + + continue; + } + cur ++; } -} /* LoadBlocksToMem */ + + return 0; +} + + + +int flash_write_region(u32 *dst, const u32 *src, u32 nwords) +{ + u32 *cur; + u32 *end; + int rv; + + cur = dst; + end = dst + nwords; + +#ifdef BLOB_DEBUG + SerialOutputString(__FUNCTION__ "(): flashing 0x"); + SerialOutputHex(nwords); + SerialOutputString(" words from 0x"); + SerialOutputHex((u32)src); + SerialOutputString(" to 0x"); + SerialOutputHex((u32)dst); + SerialOutputByte('\n'); #endif + while(cur < end) { + if((u32)cur % (16 * 1024) == 0) { + SerialOutputByte('.'); + led_toggle(); + } + rv = write_flash(cur, src); + if(rv < 0) { + printerrprefix(); + SerialOutputString("flash write error at 0x"); + SerialOutputHex((u32)cur); + SerialOutputByte('\n'); + return rv; + } -/* The spooky functions that write to the same flash that we're executing from */ + cur ++; + src ++; + } -u32 data_from_flash(u32 what); -u32 data_to_flash(u32 what); + return 0; +} -#if defined SHANNON || defined NESA -#define READ_ARRAY 0x00F000F0 -#define UNLOCK1 0x00AA00AA -#define UNLOCK2 0x00550055 -#define ERASE_SETUP 0x00800080 -#define ERASE_CONFIRM 0x00300030 -#define PGM_SETUP 0x00A000A0 -#define UNLOCK_BYPASS 0x00200020 -#define FLASH_ADDR1 (0x00000555 << 2) -#define FLASH_ADDR2 (0x000002AA << 2) -#define ERASE_DONE 0x00800080 -#define RDY_MASK 0x00800080 -#define STATUS_PGM_ERR 0x00200020 -#define STATUS_ERASE_ERR 0x00000001 -#else -#define READ_ARRAY 0x00FF00FF -#define ERASE_SETUP 0x00200020 -#define ERASE_CONFIRM 0x00D000D0 -#define PGM_SETUP 0x00400040 -#define STATUS_READ 0x00700070 -#define STATUS_CLEAR 0x00500050 -#define STATUS_BUSY 0x00800080 -#define STATUS_ERASE_ERR 0x00200020 -#define STATUS_PGM_ERR 0x00100010 -#endif + +/* -------- OLD ---------------------------------------------------- */ + + + + +/* Static function defs */ +static u32 EraseOne(const char *whichOne); + + + void EraseBlocks(tBlockType which) { @@ -181,7 +259,7 @@ for(i = 0; i < numBlocks; i++, thisBlock += MAIN_BLOCK_SIZE) { SerialOutputByte('.'); led_toggle(); - if((EraseOne(thisBlock) & STATUS_ERASE_ERR) != 0) { + if(EraseOne(thisBlock) != 0) { printerrprefix(); SerialOutputString("erase error at address 0x"); SerialOutputHex((u32)thisBlock); @@ -196,14 +274,8 @@ void WriteBlocksFromMem(tBlockType type, const u32 *source, int length) { - volatile u32 *flashBase; - u32 result; - int maxLength, i; -#if defined SHANNON || defined NESA -#define READY 1 -#define ERR 2 - int chip1, chip2; -#endif + u32 *flashBase; + int maxLength; if((u32)source & 0x03) { printerror(EALIGN, NULL); @@ -247,169 +319,37 @@ /* this should not happen */ return; } - + + length = (length + 3) / 4; + maxLength /= 4; + if(length > maxLength) length = maxLength; #ifdef BLOB_DEBUG SerialOutputString(__FUNCTION__ "(): Flashing 0x"); SerialOutputHex((u32)length); - SerialOutputString(" bytes from 0x"); + SerialOutputString(" words from 0x"); SerialOutputHex((u32)source); SerialOutputString(" to 0x"); SerialOutputHex((u32)flashBase); SerialOutputByte('\n'); #endif - -#if defined SHANNON || defined NESA - *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1); - *(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2); - *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK_BYPASS); -#endif - - for(i = 0; i < length; i+= 4, flashBase++, source++) { - if((i % MAIN_BLOCK_SIZE) == 0) { - SerialOutputByte('.'); - led_toggle(); - } - - *flashBase = data_to_flash(PGM_SETUP); - *flashBase = *source; - -#if defined SHANNON || defined NESA - - /* This is a pretty similar situation to the erasing status below - * Bit 7 is ~(data bit 7) until the flash is complete. If bit 5 - * gets set before this happens, there is an error, but this could - * happen near the clock edge, and bit 5 could be the actual data - * before bit 7 changes, so we have to read again. - */ - chip1 = chip2 = 0; - do { - result = data_from_flash(*flashBase); - if (!chip1 && ((result & 0x80) == (*source & 0x80))) chip1 = READY; - if (!chip1 && ((result & 0xFFFF) & STATUS_PGM_ERR)) { - result = data_from_flash(*flashBase); - if ((result & 0x80) == (*source & 0x80)) chip1 = READY; - else chip1 = ERR; - } - if (!chip2 && ((result & (0x80 << 16)) == (*source & (0x80 << 16)))) chip2 = READY; - if (!chip2 && ((result >> 16) & STATUS_PGM_ERR)) { - result = data_from_flash(*flashBase); - if ((result & (0x80 << 16)) == (*source & (0x80 << 16))) chip2 = READY; - else chip2 = ERR; - } - - } while (!chip1 || !chip2); - - if (chip1 == ERR || chip2 == ERR || *flashBase != *source) { -#else - do { - *flashBase = data_to_flash(STATUS_READ); - result = data_from_flash(*flashBase); - } while((~result & STATUS_BUSY) != 0); - - *flashBase = data_to_flash(READ_ARRAY); - - if((result & STATUS_PGM_ERR) != 0 || *flashBase != *source) { -#endif - printerrprefix(); - SerialOutputString("Write error at address 0x"); - SerialOutputHex((u32)flashBase); - SerialOutputByte('\n'); - return; - } - } - -#if defined SHANNON || defined NESA - *(u32 *)FLASH_ADDR1 = data_to_flash(READ_ARRAY); -#endif + flash_write_region(flashBase, source, length); } /* WriteBlocksFromMem */ + static u32 EraseOne(const char *whichOne) { -/* Routine to erase one block of flash */ - - volatile u32 *writeMe = (u32 *)whichOne; - u32 result; - -#if defined SHANNON || defined NESA - int chip1, chip2; -#endif + int rv; -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ "(): erasing block at address 0x"); - SerialOutputHex((u32)whichOne); - SerialOutputByte('\n'); -#endif - -#if defined SHANNON || defined NESA - *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1); - *(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2); - *(u32 *)FLASH_ADDR1 = data_to_flash(ERASE_SETUP); - *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1); - *(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2); - *writeMe = data_to_flash(ERASE_CONFIRM); - - /* I just can't find clean ways of dealing with this flash... - * The error bit is a *set* bit, so if its read, and bit 7 is 0, - * but bit 5 is 1, its an error, however, after these status reads - * are done, erased flash goes to 0xff...sooo...each chip has to - * be caught where the bits are the status bits */ - chip1 = chip2 = 0; - do { - result = data_from_flash(*writeMe); - if (!chip1 && (result & 0xFFFF) & ERASE_DONE) chip1 = READY; - if (!chip1 && (result & 0xFFFF) & STATUS_PGM_ERR) chip1 = ERR; - if (!chip2 && (result >> 16) & ERASE_DONE) chip2 = READY; - if (!chip2 && (result >> 16) & STATUS_PGM_ERR) chip2 = ERR; - - } while(!chip1 || !chip2); - - *(u32 *)FLASH_ADDR1 = data_to_flash(READ_ARRAY); - - if (chip1 == ERR || chip2 == ERR) return 1; - return 0; -#else + rv = flash_erase_region((u32 *)whichOne, MAIN_BLOCK_SIZE / 4); - *writeMe = data_to_flash(ERASE_SETUP); - *writeMe = data_to_flash(ERASE_CONFIRM); - - do { - *writeMe = data_to_flash(STATUS_READ); - result = data_from_flash(*writeMe); - } while((~result & STATUS_BUSY) != 0); - - *writeMe = data_to_flash(READ_ARRAY); - return result; -#endif + if(rv < 0) + return 1; + else + return 0; } /* EraseOne */ - - - -#ifdef ADVANCED_FLASH -static void GetBlockOrder(tBlkInfo *blocksInfo, u8 which, - u8 blockOrder[NUM_FLASH_BLOCKS]) -{ - - tBlockType type = blocksInfo->headers[which].type; - char *name = blocksInfo->headers[which].name; - int i; - - /* If the block isn't in use, fail silently. */ - if(!BLOCK_IN_USE(blocksInfo->headers[which])) - return; - - for(i = 0; i < NUM_FLASH_BLOCKS; i++) { - if(BLOCK_IN_USE(blocksInfo->headers[i]) && - (blocksInfo->headers[i].type == type) && - !MyStrNCmp(blocksInfo->headers[i].name, name, BLOCK_NAME_LEN)) { - - blockOrder[blocksInfo->headers[i].seqNum] = i; - } - } -} /* GetBlockOrder */ -#endif |