From: Christopher H. <ch...@us...> - 2002-01-15 01:32:50
|
Update of /cvsroot/blob/blob/src/blob In directory usw-pr-cvs1:/tmp/cvs-serv24809/src/blob Modified Files: intel16.c intel32.c Log Message: Cleaned up code, increased conformance with Intel's CFI documentation, improved status reporting, and added a timeout mechanism so that (hopefully) the code never hangs while talking to the flash. Index: intel16.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/intel16.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- intel16.c 2002/01/03 16:07:17 1.4 +++ intel16.c 2002/01/15 01:32:47 1.5 @@ -1,5 +1,5 @@ /* - * intel16.c: Intel 16 bit flash driver + * intel16: Intel 16 bit flash driver * * Copyright (C) 2001 Erik Mouw (J.A...@it...) * Copyright (C) 1999 Jan-Derk Bakker (J.D...@it...) @@ -30,7 +30,7 @@ #include <blob/flash.h> #include <blob/util.h> #include <blob/serial.h> - +#include <blob/time.h> /* flash commands for a single 16 bit intel flash chip */ #define READ_ARRAY 0x000000FF @@ -39,9 +39,14 @@ #define PGM_SETUP 0x00000040 #define STATUS_READ 0x00000070 #define STATUS_CLEAR 0x00000050 -#define STATUS_BUSY 0x00000080 + +#define STATUS_READY 0x00000080 +#define STATUS_ERASE_SUSP 0x00000040 #define STATUS_ERASE_ERR 0x00000020 #define STATUS_PGM_ERR 0x00000010 +#define STATUS_VPPLOW_ERR 0x00000008 +#define STATUS_PGM_SUSP 0x00000004 +#define STATUS_LOCKED_ERR 0x00000002 #define CONFIG_SETUP 0x00000060 #define LOCK_SECTOR 0x00000001 @@ -50,15 +55,86 @@ #define LOCK_STATUS_LOCKED 0x00000001 #define LOCK_STATUS_LOCKEDDOWN 0x00000002 +#define WRITE_ERROR_MASK \ + (STATUS_PGM_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define ERASE_ERROR_MASK \ + (STATUS_ERASE_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define LOCK_ERROR_MASK \ + (STATUS_PGM_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define CONFIG_ERROR_MASK \ + (STATUS_ERASE_ERR|STATUS_PGM_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define FLASH_TIMEOUT (20) +static void clear_status(u16 *addr) +{ + *addr = STATUS_CLEAR; + barrier(); +} +static int get_status(u16 *addr) +{ + u32 start, end; + + start = TimerGetTime(); + end = start + (FLASH_TIMEOUT * TICKS_PER_SECOND); + + for (;;) { + u16 status; + + status = *addr; + barrier(); + + if ((status & STATUS_READY) == STATUS_READY) + return status; + + if (TimerGetTime() >= end) + return -1; + } +} + +static void print_flash_error(const char *what, u16 *addr, int status) +{ + serial_write('\n'); + SerialOutputString(what); + SerialOutputString(" failed for address 0x"); + SerialOutputHex((u32) addr); + serial_write('\n'); + + SerialOutputString(" status = 0x"); + SerialOutputHex(status); + serial_write('\n'); + + if (status < 0) { + SerialOutputString(" { timeout fetching status }"); + } else { + SerialOutputString(" { "); + +#define PRINT(x) \ + if (status & x) SerialOutputString(#x " ") + + PRINT(STATUS_READY); + PRINT(STATUS_ERASE_SUSP); + PRINT(STATUS_ERASE_ERR); + PRINT(STATUS_PGM_ERR); + PRINT(STATUS_VPPLOW_ERR); + PRINT(STATUS_PGM_SUSP); + PRINT(STATUS_LOCKED_ERR); + +#undef PRINT + + serial_write('}'); + } + + SerialOutputString("\n\n"); +} + +/* erases a flash block at the given address */ static int do_erase(u16 *addr) { - u16 result; + int status; - *addr = STATUS_CLEAR; - barrier(); + clear_status(addr); /* prepare for erase */ *addr = ERASE_SETUP; @@ -68,41 +144,27 @@ *addr = ERASE_CONFIRM; barrier(); - /* status check */ - do { - *addr = STATUS_READ; - barrier(); - result = *addr; - barrier(); - } while((~result & STATUS_BUSY) != 0); + status = get_status(addr); /* put flash back into Read Array mode */ *addr = READ_ARRAY; barrier(); - if((result & STATUS_ERASE_ERR) != 0) { -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ " failed, result=0x"); - SerialOutputHex(result); - SerialOutputString(", addr=0x"); - SerialOutputHex((u32) addr); - serial_write('\n'); -#endif + if ((status < 0) || + ((status & ERASE_ERROR_MASK) != 0)) { + print_flash_error(__FUNCTION__, addr, status); return -EFLASHERASE; } return 0; } - - - +/* write a flash block at a given location */ static int do_write(u16 *dst, const u16* src) { - u16 result; + int status; - *dst = STATUS_CLEAR; - barrier(); + clear_status(dst); /* setup flash for writing */ *dst = PGM_SETUP; @@ -113,39 +175,27 @@ barrier(); /* status check */ - do { - *dst = STATUS_READ; - barrier(); - - result = *dst; - barrier(); - } while((~result & STATUS_BUSY) != 0); + status = get_status(dst); /* put flash back into Read Array mode */ *dst = READ_ARRAY; barrier(); - if(((result & STATUS_PGM_ERR) != 0) || (*dst != *src)) { -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ " failed, result=0x"); - SerialOutputHex(result); - SerialOutputString(", dst=0x"); - SerialOutputHex((u32) dst); - SerialOutputString(", *dst=0x"); - SerialOutputHex(*dst); - SerialOutputString(", *src=0x"); - SerialOutputHex(*src); - serial_write('\n'); + if ((status < 0) || + ((status & WRITE_ERROR_MASK) != 0) || + (*dst != *src)) { +#ifdef FLASH_DEBUG + /* this often fails because we need to erase, so + don't be noisy about it */ + print_flash_error(__FUNCTION__, dst, status); #endif return -EFLASHPGM; } - + return 0; } - - /* erases a flash block at the given address */ /* we have to break this up in two erases at 16 bit aligned addresses * (if necessary) @@ -172,8 +222,6 @@ } - - /* write a flash block at a given location */ /* this has to be broken up into two consectutive 16 bit writes */ static int flash_write_intel16(u32 *dst, const u32* src) @@ -196,89 +244,55 @@ return 0; } - - - static int flash_lock_block_intel16(u32 *blockStart) { u16 *p = (u16 *) blockStart; - u16 result; - - *p = STATUS_CLEAR; - barrier(); + int status; *p = CONFIG_SETUP; barrier(); *p = LOCK_SECTOR; barrier(); - /* status check */ - *p = STATUS_READ; - barrier(); - - result = *p; - barrier(); + status = get_status(p); *p = READ_ARRAY; barrier(); - if ((result & STATUS_PGM_ERR) != 0) { -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ " failed at 0x"); - SerialOutputHex((u32) blockStart); - SerialOutputString(", status=0x"); - SerialOutputHex((u32) result); - serial_write('\n'); -#endif - return -EFLASHPGM; + if ((status < 0) || + ((status & LOCK_ERROR_MASK) != 0)) { + print_flash_error(__FUNCTION__, p, status); + return status; } return 0; } - - - static int flash_unlock_block_intel16(u32 *blockStart) { u16 *p = (u16 *) blockStart; - u16 result; - - *p = STATUS_CLEAR; - barrier(); + int status; *p = CONFIG_SETUP; barrier(); *p = UNLOCK_SECTOR; barrier(); - /* status check */ - *p = STATUS_READ; - barrier(); - - result = *p; - barrier(); + status = get_status(p); *p = READ_ARRAY; barrier(); - if ((result & STATUS_PGM_ERR) != 0) { -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ " failed at 0x"); - SerialOutputHex((u32) blockStart); - SerialOutputString(", status=0x"); - SerialOutputHex((u32) result); - serial_write('\n'); -#endif - return -EFLASHPGM; + + if ((status < 0) || + ((status & CONFIG_ERROR_MASK) != 0)) { + print_flash_error(__FUNCTION__, p, status); + return status; } return 0; } - - - static int flash_query_block_lock_intel16(u32 *blockStart) { u16 *p = (u16 *) blockStart; @@ -292,16 +306,17 @@ *blockStart = READ_ARRAY; barrier(); -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ ": status of block starting at 0x"); +#ifdef FLASH_DEBUG + SerialOutputString(__FUNCTION__ ": lock status of block starting at 0x"); SerialOutputHex((u32) blockStart); SerialOutputString(": 0x"); SerialOutputHex((u32) result); - serial_write('\n'); + SerialOutputString("\n"); #endif - return result & (LOCK_STATUS_LOCKED | LOCK_STATUS_LOCKEDDOWN); + return ((result & (LOCK_STATUS_LOCKED|LOCK_STATUS_LOCKEDDOWN)) != 0); } + /* flash driver structure */ flash_driver_t intel16_flash_driver = { Index: intel32.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/intel32.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- intel32.c 2002/01/03 16:07:18 1.4 +++ intel32.c 2002/01/15 01:32:47 1.5 @@ -30,7 +30,7 @@ #include <blob/flash.h> #include <blob/util.h> #include <blob/serial.h> - +#include <blob/time.h> /* flash commands for two 16 bit intel flash chips */ #define READ_ARRAY 0x00FF00FF @@ -39,9 +39,14 @@ #define PGM_SETUP 0x00400040 #define STATUS_READ 0x00700070 #define STATUS_CLEAR 0x00500050 -#define STATUS_BUSY 0x00800080 + +#define STATUS_READY 0x00800080 +#define STATUS_ERASE_SUSP 0x00400040 #define STATUS_ERASE_ERR 0x00200020 #define STATUS_PGM_ERR 0x00100010 +#define STATUS_VPPLOW_ERR 0x00080008 +#define STATUS_PGM_SUSP 0x00040004 +#define STATUS_LOCKED_ERR 0x00020002 #define CONFIG_SETUP 0x00600060 #define LOCK_SECTOR 0x00010001 @@ -50,16 +55,86 @@ #define LOCK_STATUS_LOCKED 0x00010001 #define LOCK_STATUS_LOCKEDDOWN 0x00020002 +#define WRITE_ERROR_MASK \ + (STATUS_PGM_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define ERASE_ERROR_MASK \ + (STATUS_ERASE_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define LOCK_ERROR_MASK \ + (STATUS_PGM_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) +#define CONFIG_ERROR_MASK \ + (STATUS_ERASE_ERR|STATUS_PGM_ERR|STATUS_VPPLOW_ERR|STATUS_LOCKED_ERR) + +#define FLASH_TIMEOUT (20) + +static void clear_status(u32 *addr) +{ + *addr = data_to_flash(STATUS_CLEAR); + barrier(); +} + +static int get_status(u32 *addr) +{ + u32 start, end; + + start = TimerGetTime(); + end = start + (FLASH_TIMEOUT * TICKS_PER_SECOND); + + for (;;) { + u32 status; + + status = data_from_flash(*addr); + barrier(); + + if ((status & STATUS_READY) == STATUS_READY) + return status; + if (TimerGetTime() >= end) + return -1; + } +} +static void print_flash_error(const char *what, u32 *addr, int status) +{ + serial_write('\n'); + SerialOutputString(what); + SerialOutputString(" failed for address 0x"); + SerialOutputHex((u32) addr); + serial_write('\n'); + SerialOutputString(" status = 0x"); + SerialOutputHex(status); + serial_write('\n'); + + if (status < 0) { + SerialOutputString(" { timeout fetching status }"); + } else { + SerialOutputString(" { "); + +#define PRINT(x) \ + if (status & x) SerialOutputString(#x " ") + + PRINT(STATUS_READY); + PRINT(STATUS_ERASE_SUSP); + PRINT(STATUS_ERASE_ERR); + PRINT(STATUS_PGM_ERR); + PRINT(STATUS_VPPLOW_ERR); + PRINT(STATUS_PGM_SUSP); + PRINT(STATUS_LOCKED_ERR); + +#undef PRINT + + serial_write('}'); + } + + SerialOutputString("\n\n"); +} + /* erases a flash block at the given address */ static int flash_erase_intel32(u32 *addr) { - u32 result; + u32 status; - *addr = data_to_flash(STATUS_CLEAR); - barrier(); + clear_status(addr); /* prepare for erase */ *addr = data_to_flash(ERASE_SETUP); @@ -69,41 +144,27 @@ *addr = data_to_flash(ERASE_CONFIRM); barrier(); - /* status check */ - do { - *addr = data_to_flash(STATUS_READ); - barrier(); - result = data_from_flash(*addr); - barrier(); - } while((~result & STATUS_BUSY) != 0); + status = get_status(addr); /* put flash back into Read Array mode */ *addr = data_to_flash(READ_ARRAY); barrier(); - if((result & STATUS_ERASE_ERR) != 0) { -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ " failed, result=0x"); - SerialOutputHex(result); - SerialOutputString(", addr=0x"); - SerialOutputHex((u32) addr); - serial_write('\n'); -#endif + if ((status < 0) || + ((status & ERASE_ERROR_MASK) != 0)) { + print_flash_error(__FUNCTION__, addr, status); return -EFLASHERASE; } return 0; } - - /* write a flash block at a given location */ static int flash_write_intel32(u32 *dst, const u32* src) { - u32 result; + u32 status; - *dst = data_to_flash(STATUS_CLEAR); - barrier(); + clear_status(dst); /* setup flash for writing */ *dst = data_to_flash(PGM_SETUP); @@ -114,115 +175,72 @@ barrier(); /* status check */ - do { - *dst = data_to_flash(STATUS_READ); - barrier(); - - result = data_from_flash(*dst); - barrier(); - } while((~result & STATUS_BUSY) != 0); + status = get_status(dst); /* put flash back into Read Array mode */ *dst = data_to_flash(READ_ARRAY); barrier(); - if(((result & STATUS_PGM_ERR) != 0) || (*dst != *src)) { -#ifdef BLOB_DEBUG - SerialOutputString(__FUNCTION__ "failed, result=0x"); - SerialOutputHex(result); - SerialOutputString(", addr=0x"); - SerialOutputHex((u32) dst); - serial_write('\n'); + if ((status < 0) || + ((status & WRITE_ERROR_MASK) != 0) || + (*dst != *src)) { +#ifdef FLASH_DEBUG + /* this often fails because we need to erase, so + don't be noisy about it */ + print_flash_error(__FUNCTION__, dst, status); #endif return -EFLASHPGM; } - + return 0; } - - - static int flash_lock_block_intel32(u32 *blockStart) { - u32 result; - - *blockStart = data_to_flash(STATUS_CLEAR); - barrier(); + u32 status; *blockStart = data_to_flash(CONFIG_SETUP); barrier(); *blockStart = data_to_flash(LOCK_SECTOR); barrier(); - - *blockStart = data_to_flash(READ_ARRAY); - barrier(); - - /* status check */ - *blockStart = data_to_flash(STATUS_READ); - barrier(); - result = data_from_flash(*blockStart); - barrier(); + status = get_status(blockStart); *blockStart = data_to_flash(READ_ARRAY); barrier(); - if ((result & STATUS_PGM_ERR) != 0) { -#ifdef FLASH_DEBUG - SerialOutputString(__FUNCTION__ " failed at 0x"); - SerialOutputHex((u32) blockStart); - SerialOutputString(", status=0x"); - SerialOutputHex((u32) result); - SerialOutputByte('\n'); -#endif - return -EFLASHPGM; + if ((status < 0) || + ((status & LOCK_ERROR_MASK) != 0)) { + print_flash_error(__FUNCTION__, blockStart, status); + return status; } return 0; } - - - static int flash_unlock_block_intel32(u32 *blockStart) { - u32 result; - - *blockStart = data_to_flash(STATUS_CLEAR); - barrier(); + u32 status; *blockStart = data_to_flash(CONFIG_SETUP); barrier(); *blockStart = data_to_flash(UNLOCK_SECTOR); barrier(); - *blockStart = data_to_flash(STATUS_READ); - barrier(); - - result = data_from_flash(*blockStart); - barrier(); + status = get_status(blockStart); *blockStart = data_to_flash(READ_ARRAY); barrier(); - if ((result & STATUS_PGM_ERR) != 0) { -#ifdef FLASH_DEBUG - SerialOutputString(__FUNCTION__ " failed at 0x"); - SerialOutputHex((u32) blockStart); - SerialOutputString(", status=0x"); - SerialOutputHex((u32) result); - SerialOutputByte('\n'); -#endif - return -EFLASHPGM; + if ((status < 0) || + ((status & CONFIG_ERROR_MASK) != 0)) { + print_flash_error(__FUNCTION__, blockStart, status); + return status; } return 0; } - - - static int flash_query_block_lock_intel32(u32 *blockStart) { u32 result; @@ -236,16 +254,15 @@ barrier(); #ifdef FLASH_DEBUG - SerialOutputString(__FUNCTION__ ": status of block starting at 0x"); + SerialOutputString(__FUNCTION__ ": lock status of block starting at 0x"); SerialOutputHex((u32) blockStart); SerialOutputString(": 0x"); - SerialOutputHex((u32) result); - SerialOutputByte('\n'); + SerialOutputHex( result); + serial_write('\n'); #endif - return result & (LOCK_STATUS_LOCKED | LOCK_STATUS_LOCKEDDOWN); + return ((result & (LOCK_STATUS_LOCKED|LOCK_STATUS_LOCKEDDOWN)) != 0); } - |