www.pudn.com > drivers.rar > drv.c
/****************************************************************************** * Flash File System (ffs) * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com * * ffs low level flash driver * * $Id: drv.c 1.30.1.6.1.51.1.1.1.13.1.11 Tue, 06 Jan 2004 14:36:52 +0100 tsj $ * ******************************************************************************/ #ifndef TARGET #include "ffs.cfg" #endif #include "ffs/ffs.h" #include "ffs/board/drv.h" #include "ffstrace.h" #include "ffs/board/task.h" #if (TARGET == 0) #include "tffs.h" #include "core.h" /*Add by ZhangTing for PC simulator 2006-08-26*/ #define WIN32 /*End*/ #ifdef WIN32 #include "windows.h" #else // WIN32 #include "sys/mman.h" #include "unistd.h" #endif // WIN32 #include "stdio.h" #include#include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #endif // Note that all code notes and comments pertaining to single-bank flash // drivers are located in the AMD SB driver (amdsbdrv.c). Consider this as // the reference. /****************************************************************************** * Globals ******************************************************************************/ #define FLASH_STATUS_CHECK 1 #define FLASH_WRITE_CHECK 0 //#define FLASH_WRITE(addr, data) (*(volatile UINT16 *) (addr)) = data #define AMD_FLASH #if (TARGET == 1) // NOTE: This is the size in bytes of the single-bank driver code that is // copied to RAM. The only way to determine the amount of memory needed is // to look into the linker output file (.map) or the assembler output of // both amdsbdrv.obj and intelsbdrv.obj files. #define FFSDRV_CODE_SIZE (0x200) uint8 ffsdrv_code[FFSDRV_CODE_SIZE]; #endif #define INTEL_UNLOCK_SLOW 1 struct dev_s dev; struct ffsdrv_s ffsdrv; extern OS_MUTEX ffs_write_mutex; /****************************************************************************** * Function Prototypes ******************************************************************************/ uint32 int_disable(void); void int_enable(uint32 tmp); int ffsdrv_write_check(char *addr, int size); void ffsdrv_unlock_sectors(void); void ffsdrv_amd_fg_write_halfword_local(volatile uint16 *addr, uint16 value); void ffsdrv_amd_fg_write_halfword_unlock_bypass(volatile uint16 *addr, uint16 value); void ffsdrv_amd_mb_buffer_write(void *dst, const void *src, uint16 size); void ffsdrv_amd_mb_erase_sector(void *dst); void ffsdrv_amd_mb_buffer_write_new(volatile UINT16 *dst_addr, const UINT8 *src_addr, UINT16 size); /*Add by ZhangTing for PC simulator 2006-08-26*/ void ffsdrv_amd_fg_erase(uint8 block); void ffsdrv_null_write_buffer(volatile uint16 *addr, volatile uint16 *src, uint16 words2write); void ffsdrv_amd_fg_write(void *dst, const void *src, uint16 size); void ffsdrv_amd_fg_write_suspend(void); void ffsdrv_amd_fg_write_halfword(volatile uint16 *addr, uint16 value); void ffsdrv_amd_fg_erase_sector(void *dst); void ffsdrv_amd_fg_erase_sector_pseudo_sb(void *dst); void ffsdrv_amd_mb_erase(uint8 block); void ffsdrv_amd_mb_write_halfword(volatile uint16 *addr, uint16 value); /*End*/ /****************************************************************************** * Macros ******************************************************************************/ #define addr2offset(address) ( (int) (address) - (int) dev.base ) #define blockoffsetaddr(address) ((int)address&(int)(dev.blocksize-1)) //fangcj added #define FLASH_READ(addr) (*(volatile UINT16 *) (addr)) #define FLASH_WRITE(addr, data) (*(volatile UINT16 *) (addr)) = data /****************************************************************************** * Generic Driver Functions ******************************************************************************/ void ffsdrv_generic_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; if (size > 0) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv.write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } void ffsdrv_generic_buffer_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; uint16 bytes2write; tw(tr(TR_BEGIN, TrDrvWrite, "test_generic_buffer_write(0x%05x, 0x%05x, 0x%x)" "{\n", addr2offset(dst), src, size)); while (size > 0) { // If buffer is aligned set it to max else align to buffer boundary. bytes2write = dev.write_buffersize - ((int) mydst & (dev.write_buffersize - 1)); // Saturate to size if (bytes2write > size) bytes2write = size; if ((unsigned int) mydst & 1 || bytes2write == 1) { bytes2write = 1; ffsdrv_write_byte(mydst, *mysrc); } // The amount: '3 bytes2write' is a special case as if it not is // written by the write_halfword() the buffer_write() will write 2 // bytes and the write_byte() will write the last byte.. (less // efficient) else if (bytes2write == 2 || bytes2write == 3) { bytes2write = 2; ffsdrv.write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); } else { // TODO: make a loop around the below function (speed optimization) uint16 wbuf[FFS_WR_BUF_MAX_WORDS]; #if 0 uint16 currentBlkLeftSize = dev.blocksize-blockoffsetaddr(dst); if(currentBlkLeftSize< bytes2write ) // beyond block boundary, turncate! fangcj added bytes2write = currentBlkLeftSize; #endif // Truncate to an even number of bytes bytes2write = bytes2write & (uint16) ~1; // The write_buffer() function is not able to make a // flash-to-flash copy thus the source most be copied to RAM. It // is the operations: rename, inode and data reclaim that makes // a flash-to-flash copy. The write_buffer() function cannot // fill the 'flash write buffer' with data from the flash // because the flash is in 'read status' mode ad the time the // buffer is filled. Furthermore the write_buffer() function // presume that src is half word aligned memcpy(wbuf, mysrc, bytes2write); ffsdrv.write_buffer((uint16 *) mydst, (uint16 *) wbuf, bytes2write/2); } size -= bytes2write; mysrc += bytes2write; mydst += bytes2write; } tw(tr(TR_END, TrDrvWrite, "}\n")); } /****************************************************************************** * AMD Single Bank Driver Functions ******************************************************************************/ #if (TARGET == 1) // Forward declaration of functions in file amdsbdrv.c void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value); void ffsdrv_ram_amd_sb_erase(uint8 block); void ffsdrv_ram_amd_sb_erase_sector(void *dst); #else // (TARGET == 0) // On PC these functions are empty void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value) {} void ffsdrv_ram_amd_sb_erase(uint8 block) {} void ffsdrv_ram_amd_sb_erase_sector(void *dst) {} #endif // (TARGET == 1) /****************************************************************************** * AMD Pseudo Single Bank Driver Functions ******************************************************************************/ // This is a pseudo single-bank flash driver. It simulates a single-bank // flash device on a dual-bank device. #ifdef AMD_FLASH #if (TARGET == 1) void ffsdrv_amd_pseudo_sb_write_halfword(volatile uint16 *addr, uint16 value) { volatile char *flash = dev.base; uint32 cpsr, i, x; ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); if (~*addr & value) { ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); return; } cpsr = int_disable(); tlw(led_on(LED_WRITE)); flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 flash[0xAAAA] = 0xA0; *addr = value; while ((*dev.addr ^ dev.data) & 0x80) ; tlw(led_off(LED_WRITE)); int_enable(cpsr); } // This VERY simple way of erase suspending only works because we run under // a pre-emptive operating system, so whenever an interrupt occurs, another // task takes the CPU, and at the end of the interrupt, FFS gets the CPU // again. void ffsdrv_amd_pseudo_sb_erase(uint8 block) { char *addr = (char *)block2addr(block); ffsdrv.erase_sector(addr); } void ffsdrv_amd_pseudo_sb_erase_sector(void *dst) { volatile char *flash = dev.base; volatile char *addr = (char *)dst; uint32 cpsr; uint16 flashpoll; ttw(ttr(TTrDrvErase, "e(%d)" NL, dst)); cpsr = int_disable(); tlw(led_on(LED_ERASE)); flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 flash[0xAAAA] = 0x80; flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 *addr = 0x30; // AMD erase sector command // Wait for erase to finish. while ((*addr & 0x80) == 0) { tlw(led_toggle(LED_ERASE)); // Poll interrupts, taking interrupt mask into account. if (INT_REQUESTED) { // 1. suspend erase // 2. enable interrupts // .. now the interrupt code executes // 3. disable interrupts // 4. resume erase tlw(led_on(LED_ERASE_SUSPEND)); *addr = 0xB0; // wait for erase suspend to finish while ((*addr & 0x80) == 0) ; tlw(led_off(LED_ERASE_SUSPEND)); int_enable(cpsr); // Other interrupts and tasks run now... cpsr = int_disable(); tlw(led_on(LED_ERASE_SUSPEND)); // Before resuming erase we must? check if the erase is really // suspended or if it did finish flashpoll = *addr; *addr = 0x30; tlw(led_off(LED_ERASE_SUSPEND)); } } tlw(led_on(LED_ERASE)); tlw(led_off(LED_ERASE)); int_enable(cpsr); } #else // (TARGET == 0) void ffsdrv_amd_pseudo_sb_write_halfword(volatile uint16 *addr, uint16 value) {} void ffsdrv_amd_pseudo_sb_erase(uint8 block) {} void ffsdrv_amd_pseudo_sb_erase_sector(void *dst) {} #endif // (TARGET == 1) /****************************************************************************** * AMD Dual/Multi Bank Driver Functions ******************************************************************************/ // All erase and write operations are performed atomically (interrupts // disabled). Otherwise we cannot trust the value of dev.state and we cannot // determine exactly how many of the command words have already been // written. // in ffs_end() when we resume an erasure that was previously suspended, how // does that affect multiple tasks doing that simultaneously? void ffsdrv_amd_write_end(void); void ffsdrv_amd_erase_end(void); void ffsdrv_amd_write_halfword(volatile uint16 *addr, uint16 value) { volatile char *flash = dev.base; uint32 cpsr; volatile uint16 a; tlw(led_on(LED_WRITE)); ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); dev.addr = addr; dev.data = value; a=value; a=*addr; if (~*addr & value) { ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); return; } cpsr = int_disable(); tlw(led_toggle(LED_WRITE_SUSPEND)); dev.state = DEV_WRITE; flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 flash[0xAAAA] = 0xA0; *addr = value; int_enable(cpsr); tlw(led_toggle(LED_WRITE_SUSPEND)); ffsdrv_amd_write_end(); } void ffsdrv_amd_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; if (size > 0) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_amd_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } void ffsdrv_amd_write_end(void) { while ((*dev.addr ^ dev.data) & 0x80) tlw(led_toggle(LED_WRITE_SUSPEND)); dev.state = DEV_READ; tlw(led_off(LED_WRITE)); } void ffsdrv_amd_erase(uint8 block) { uint16 *addr = (uint16 *) block2addr(block); ffsdrv.erase_sector(addr); } void ffsdrv_amd_erase_sector(void *dst) { volatile char *flash = dev.base; uint32 cpsr; tlw(led_on(LED_ERASE)); ttw(ttr(TTrDrvErase, "e(%d)" NL, dst)); dev.addr = (uint16 *) dst; cpsr = int_disable(); dev.state = DEV_ERASE; flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 flash[0xAAAA] = 0x80; flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 *dev.addr = 0x30; // AMD erase sector command int_enable(cpsr); ffsdrv_amd_erase_end(); } void ffsdrv_amd_erase_end(void) { while ((*dev.addr & 0x80) == 0) ; dev.state = DEV_READ; tlw(led_off(LED_ERASE)); } void ffsdrv_amd_erase_suspend(void) { uint32 cpsr; tlw(led_on(LED_ERASE_SUSPEND)); ttw(str(TTrDrvErase, "es" NL)); // if erase has finished then all is ok if (*dev.addr & 0x80) { ffsdrv_amd_erase_end(); tlw(led_off(LED_ERASE_SUSPEND)); return; } // NOTEME: As there is no way to be absolutely certain that erase // doesn't finish between last poll and the following erase suspend // command, we assume that the erase suspend is safe even though the // erase IS actually already finished. cpsr = int_disable(); dev.state = DEV_ERASE_SUSPEND; *dev.addr = 0xB0; // Wait for erase suspend to finish while ((*dev.addr & 0x80) == 0) /* Enabling the interrupt should be after this while, */ /* because DQ7==1 on entering to erase suspend mode */ ; int_enable(cpsr); } void ffsdrv_amd_erase_resume(void) { uint32 cpsr; ttw(str(TTrDrvErase, "er" NL)); // NOTEME: See note in erase_suspend()... We assume that the erase // resume is safe even though the erase IS actually already finished. cpsr = int_disable(); dev.state = DEV_ERASE; *dev.addr = 0x30; int_enable(cpsr); tlw(led_off(LED_ERASE_SUSPEND)); } #endif /****************************************************************************** * SST Dual/Multi Bank Driver Functions ******************************************************************************/ // SST flashes use almost same command set as AMD flashes. Only the command // addresses (4 more bits) and erase command data (0x50 instead of 0x30) are // different. SST flashes have no erase suspend/resume commands because they // are so fast at erasing! void ffsdrv_sst_write_end(void); void ffsdrv_sst_erase_end(void); void ffsdrv_sst_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; if (size > 0) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_amd_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } // Note that SST flashes have smaller sectors than other flash families. // Fortunately they support erasure of several of these sectors in a logical // unit called a "block". void ffsdrv_sst_erase(uint8 block) { uint16 *addr = (uint16 *) block2addr(block); ffsdrv.erase_sector(addr); } void ffsdrv_sst_erase_sector(void *dst) { volatile char *flash = dev.base; uint32 cpsr; tlw(led_on(LED_ERASE)); ttw(ttr(TTrDrvErase, "e(%d)" NL, dst)); dev.addr = dst; cpsr = int_disable(); dev.state = DEV_ERASE; flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 flash[0xAAAA] = 0x80; flash[0xAAAA] = 0xAA; // unlock cycle 1 flash[0x5555] = 0x55; // unlock cycle 2 *dev.addr = 0x50; // SST erase block command int_enable(cpsr); ffsdrv_sst_erase_end(); } void ffsdrv_sst_erase_end(void) { // Wait for erase end while ((*dev.addr & 0x80) == 0) ; dev.state = DEV_READ; tlw(led_off(LED_ERASE)); } // Erase suspend/resume commands do not exist for SST flashes, so we just // poll for the end of the erase operation... void ffsdrv_sst_erase_suspend(void) { ttw(str(TTrDrvErase, "es" NL)); ffsdrv_sst_erase_end(); } /****************************************************************************** * Intel Single Bank Driver Functions ******************************************************************************/ #ifdef INTEL_FLASH #if (TARGET == 1) // Forward declaration of functions in file intelsbdrv.c int ffsdrv_ram_intel_sb_init(void); void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value); void ffsdrv_ram_intel_sb_erase(uint8 block); void ffsdrv_ram_intel_sb_erase_sector(void *dst); void ffsdrv_ram_intel_erase(uint8 block); void ffsdrv_ram_intel_erase_sector(void *dst); #else // (TARGET == 0) // On PC these functions are empty void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value) {} void ffsdrv_ram_intel_sb_erase(uint8 block) {} void ffsdrv_ram_intel_sb_erase_sector(void *dst) {} void ffsdrv_ram_intel_erase(uint8 block) {} void ffsdrv_ram_intel_erase_sector(void *dst); #endif // (TARGET == 1) /****************************************************************************** * Intel Dual/Multi Bank Driver Functions ******************************************************************************/ void ffsdrv_intel_write_end(void); void ffsdrv_intel_erase_end(void); void ffsdrv_intel_init(void) { volatile uint16 *flash = (volatile uint16*)dev.base; flash[0] = INTEL_READ_ARRAY;//reset intel flash status } // ffsdrv_intel_write_halfword and ffsdrv_intel_write_end is not used // because of the bug in the intel flash device. Instead is the functions // ffsdrv_ram_intel_sb_write_halfword and ffsdrv_ram_intel_erase used. void ffsdrv_intel_write_halfword(volatile uint16 *addr, uint16 value) { uint32 cpsr; tlw(led_on(LED_WRITE)); ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value)); dev.addr = addr; #if (FLASH_WRITE_CHECK == 1) if (~*addr & value) { ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value)); return; } #endif cpsr = int_disable(); dev.state = DEV_WRITE; #if (INTEL_UNLOCK_SLOW == 1) *addr = 0x60; // Intel Config setup *addr = 0xD0; // Intel Unlock block *addr = 0x50; // Intel Clear Status Register #endif *addr = 0x40; // Intel program byte/word *addr = value; int_enable(cpsr); ffsdrv_intel_write_end(); } // IMPORTANT: This function presupposes that the size not is above the flash // write buffer size and the src is half word aligned. void ffsdrv_intel_write_buffer_mode(volatile uint16 *addr, volatile uint16 *src, uint16 words2write) { uint32 cpsr; uint16 i, status; ttw(ttr(TTrDrvWrite, "wbuf(%x, %x, %x)" NL, addr, src, words2write)); #if (FLASH_WRITE_CHECK == 1) // Make sure we don't try to flip a '0' to '1'. for (i = 0; i < words2write; i++) { if (~(int) addr[i] & (int) src[i]) { ttw(ttr(TTrFatal, "wbuf(%x,%x->%x) fatal" NL, addr, addr[i], src[i])); return; } } #endif cpsr = int_disable(); // FIXME can we disable interrupt for all this time? dev.addr = addr; dev.state = DEV_WRITE; *dev.addr = INTEL_CLR_STATUS; *dev.addr = INTEL_LOCK_SETUP; *dev.addr = INTEL_UNLOCK_BLK; // Wait for buffer ready do { *dev.addr = INTEL_BUFFER_PRG; status = *dev.addr; } while (!(status & INTEL_STATE_MACHINE_DONE)); // Write the word count - 1 *dev.addr = words2write - 1; // Fill the write buffer while (words2write > 0) { *addr = *src; words2write--; addr++; src++; } // Start the write buffer process *dev.addr = INTEL_BUFFER_PRG_CONFIRM; *dev.addr = INTEL_READ_STATUS; int_enable(cpsr); ffsdrv_intel_write_end(); // NOTEME Verify the write? } void ffsdrv_intel_write_end(void) { uint32 cpsr; uint16 status; // We can be interrupted and reentered thus the state can have been changed. while (1) { if (dev.state == DEV_WRITE) { // write completed? if ((*dev.addr & INTEL_STATE_MACHINE_DONE) > 0) break; // write completed continue; } else if (dev.state == DEV_WRITE_SUSPEND) continue; // Wait until the write is resumed else if (dev.state == DEV_READ) break; // write completed in write_suspend() or a re-entered // write_end() ttw(ttr(TTrFatal, "FATAL: invalid dev.state %d" NL, dev.state)); return; } // The flash state and dev.state must be in sync thus the stat changes // must be protected from being interrupted cpsr = int_disable(); #if (FLASH_STATUS_CHECK == 1) *dev.addr = INTEL_READ_STATUS; status = *dev.addr; if (status != INTEL_STATE_MACHINE_DONE) ttw(ttr(TTrFatal, "FATAL write error 0x%x" NL, status)); #endif dev.state = DEV_READ; *dev.addr = INTEL_READ_ARRAY; int_enable(cpsr); tlw(led_off(LED_WRITE)); } void ffsdrv_intel_write_suspend(void) { uint32 cpsr; uint16 poll; ttw(str(TTrDrvWrite, "wrs" NL)); // The flash state and dev.state must be in sync thus the stat changes // must be protected from being interrupted cpsr = int_disable(); dev.state = DEV_WRITE_SUSPEND; *dev.addr = INTEL_SUSPEND; *dev.addr = INTEL_READ_STATUS; while (((poll = *dev.addr) & INTEL_STATE_MACHINE_DONE) == 0) ; if ((poll & INTEL_PROGRAM_SUSPEND) == 0) { // Write has completed dev.state = DEV_READ; } // The write is finíshed or suspended, prepare to read data from the flash *dev.addr = INTEL_READ_ARRAY; int_enable(cpsr); } void ffsdrv_intel_write_resume(void) { uint32 cpsr; ttw(str(TTrDrvWrite, "wrr" NL)); // The flash state and dev.state must be in sync thus the stat changes // must be protected from being interrupted cpsr = int_disable(); dev.state = DEV_WRITE; *dev.addr = INTEL_RESUME; // FFS always expect that the flash is in READ status mode while the // dev.state is DEV_WRITE *dev.addr = INTEL_READ_STATUS; int_enable(cpsr); } void ffsdrv_intel_erase(uint8 block) { uint16 *addr = (uint16 *) block2addr(block); ffsdrv.erase_sector(addr); } void ffsdrv_intel_erase_sector(void *dst) { uint32 cpsr; ttw(ttr(TTrDrvErase, "e(0x%x)" NL, dst)); tlw(led_on(LED_ERASE)); dev.addr = (uint16 *)dst; cpsr = int_disable(); dev.state = DEV_ERASE; #if (INTEL_UNLOCK_SLOW == 1) *dev.addr = INTEL_CLR_STATUS; // Intel clear status register (not really necessary) *dev.addr = INTEL_LOCK_SETUP; // Intel Config setup *dev.addr = INTEL_UNLOCK_BLK; // Intel Unlock block #endif *dev.addr = INTEL_BLOCK_ERASE_SETUP; // Intel erase setup *dev.addr = INTEL_ERASE_CONFIRM; // Intel erase confirm *dev.addr = INTEL_READ_STATUS;//fangcj added int_enable(cpsr); ffsdrv_intel_erase_end(); } void ffsdrv_intel_erase_end(void) { uint16 status; #if (BOARD == 46) while ((*dev.addr & 0x80) == 0 && dev.state == DEV_ERASE) ; #else while ((*dev.addr & 0x80) == 0 && (dev.state == DEV_ERASE || dev.state == DEV_ERASE_SUSPEND)) ; #endif #if (FLASH_STATUS_CHECK == 1) *dev.addr = INTEL_READ_STATUS; status = *dev.addr; if (status != INTEL_STATE_MACHINE_DONE) ttw(ttr(TTrFatal, "FATAL erase error 0x%x" NL, status)); #endif *dev.addr = INTEL_READ_ARRAY; // Intel read array dev.state = DEV_READ; tlw(led_off(LED_ERASE)); } void ffsdrv_intel_erase_suspend(void) { uint32 cpsr; uint16 poll; ttw(str(TTrDrvErase, "es" NL)); tlw(led_on(LED_ERASE_SUSPEND)); cpsr = int_disable(); dev.state = DEV_ERASE_SUSPEND; *dev.addr = 0xB0; // Intel Erase Suspend *dev.addr = 0x70; // Intel Read Status Register while (((poll = *dev.addr) & 0x80) == 0) ; if ((poll & 0x40) == 0) { // Block erase has completed tlw(led_off(LED_ERASE_SUSPEND)); dev.state = DEV_READ; tlw(led_off(LED_ERASE)); } *dev.addr = 0xFF; // Intel read array int_enable(cpsr); } void ffsdrv_intel_erase_resume(void) { uint32 cpsr; ttw(str(TTrDrvErase, "er" NL)); cpsr = int_disable(); dev.state = DEV_ERASE; *dev.addr = 0xD0; // Intel erase resume // The following "extra" Read Status command is required because Intel has // changed the specification of the W30 flash! (See "1.8 Volt Intel? // Wireless Flash Memory with 3 Volt I/O 28F6408W30, 28F640W30, 28F320W30 // Specification Update") *dev.addr = 0x70; // Intel Read Status Register int_enable(cpsr); tlw(led_off(LED_ERASE_SUSPEND)); } // NOTE this function has a little better performance than the // generic_write() because it use less function pointers void ffsdrv_intel_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; if (size > 0) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_intel_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } #endif /****************************************************************************** * RAM Family Functions ******************************************************************************/ void ffsdrv_ram_write_halfword(volatile uint16 *dst, uint16 value) { *dst = value; } void ffsdrv_ram_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; if (size == 0) return; else if (size == 1) ffsdrv_write_byte(mydst, *mysrc); else { if ((int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_ram_write_halfword((uint16 *) mydst, mysrc[0]|(mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } void ffsdrv_ram_erase(uint8 block) { int i; char *addr; addr = (char *)block2addr(block);; for (i = 0; i < 1 << dev.binfo[block].size_ld; i++) { *addr++ = 0xFF; } } void ffsdrv_ram_erase_sector(void *dst) { uint8 block; for(block=0; block last) { ttw(ttr(TTrAll, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)" NL, (int) addr, size)); return -1; } return EFFS_OK; } // FIXME update this to work in target void ffsdrv_write_error(uint16 old, uint16 new) {} #else static char *image_addr = 0; static int image_size = 0; #ifdef WIN32 HANDLE image_fd, map_fd; #else //WIN32 static int image_fd = 0; #endif //WIN32 /*Modified by ZhangTing for PC simulator 2006-08-26*/ #ifndef _LEGEND_EMULATOR_ extern int arg_removeimage; extern char *arg_imagename; #else int arg_removeimage; char *arg_imagename = "ffs.bin"; #endif /*End*/ extern void test_fatal_printf(char *format, ...); int ffsdrv_write_check(char *addr, int size) { offset_t offset, last; offset = addr2offset(addr); last = dev.binfo[dev.numblocks-1].offset + (1 << dev.binfo[dev.numblocks-1].size_ld); if (offset < 0 || (offset + size) > last) { fprintf(stderr, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)\n", (int) addr, size); fprintf(stdout, "ffsdrv_write_check() failed (addr = 0x%x, size = %d)\n", (int) addr, size); exit (1); } return 0; } void ffsdrv_write_error(uint16 old, uint16 new) { #ifndef _LEGEND_EMULATOR_ /*Modified by ZhangTing for PC simulator 2006-06-15*/ test_fatal_printf("FATAL: Attempt to rewrite 0 to 1 bit " "(old:0x%x/%c new:0x%x/%c)\n", old, (old < ' ' ? '?' : old), new, (new < ' ' ? '?' : new)); #endif } void ffsdrv_test_write_halfword(volatile uint16 *addr, uint16 value) { tw(tr(TR_FUNC, TrDrvWrite, "test_write_halfword(0x%05x, 0x%x)\n", addr2offset(addr), value)); if (POWERFAIL_ENABLED) POWERFAIL_WRITE(addr, value); ffsdrv_write_check((uint8 *) addr, 2); if (~*addr & value) ffsdrv_write_error(*addr, value); *addr = value; } void ffsdrv_test_write_buffer(volatile uint16 *addr, volatile uint16 *src, uint16 words2write) { int i , num_bytes = words2write * 2; uint8 *mysrc = (uint8 *) src; uint8 *mydst = (uint8 *) addr; tw(tr(TR_FUNC, TrDrvWrite, "test_write_buffer(0x%x, 0x%05x, 0x%x)\n", addr2offset(addr), src, words2write)); if (words2write <= 1 || words2write * 2 > dev.write_buffersize) tw(tr(TR_FUNC, TrAll, "ERROR wrong number of words (%d)\n", words2write)); ffsdrv_write_check((uint8 *) addr, words2write * 2); // NOTEME this can be made a lot more simpel as the last input arg have // changed from num_bytes to words2write for (i = 0; i < num_bytes; i++) { if (~*(mydst + i) & *(mysrc + i)) ffsdrv_write_error(*(mydst + i), *(mysrc + i)); // Trigger only the powerfail framework at halfword aligned addresses if (POWERFAIL_ENABLED && !((int) (mydst + i) & 1)) // Note POWERFAIL_WRITE() write halfwords! POWERFAIL_WRITE((uint16 *) mydst + i/2, *(mysrc + i/2) | *(mysrc + i/2 + 1) << 8); *(mydst + i) = *(mysrc + i); } } void ffsdrv_test_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; tw(tr(TR_FUNC, TrDrvWrite, "test_write(0x%05x, 0x%x, %d)\n", addr2offset(mydst), mysrc, size)); if (size > 0) { if ((int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_test_write_halfword((uint16 *) mydst, mysrc[0]|(mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } void ffsdrv_test_erase(uint8 block) { int i; uint8 *addr; if (POWERFAIL_ENABLED) POWERFAIL_ERASE(block); addr = (uint8 *)block2addr(block); tw(tr(TR_FUNC, TrDrvErase, "ffsdrv_test_erase(%d)\n", block)); for (i = 0; i < 1 << dev.binfo[block].size_ld; i++) { *addr++ = 0xFF; } } void ffsdrv_test_erase_sector(void *dst) { uint8 block; for(block=0; block 0) { tw(tr(TR_FUNC, TrDrvInit, "re-opening '%s' file of size %d\n", arg_imagename, image_size)); } else { tw(tr(TR_FUNC, TrDrvInit, "opening '%s' file of size %d\n", arg_imagename, image_size)); #ifdef WIN32 image_fd = OpenFile( arg_imagename, &lpReOpenBuff, OF_READWRITE); map_fd = CreateFileMapping (image_fd, &lpAttributes, PAGE_READWRITE, 0, 0, arg_imagename); #else //WIN32 image_fd = open(arg_imagename, O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO); #endif //WIN32 if (image_fd == -1) { perror("Failed to open flash image"); exit(1); } // memory map the file and update block addresses of binfo array #ifdef WIN32 image_addr = MapViewOfFile( map_fd, FILE_MAP_ALL_ACCESS, 0, 0, 0); #else //WIN32 image_addr = mmap(0, image_size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, image_fd, 0); #endif //WIN32 } tw(tr(TR_END, TrDrvInit, "}\n")); return image_addr; } #endif // (TARGET == 0) /****************************************************************************** * Device Detection and Copying of Driver to RAM ******************************************************************************/ #if (TARGET == 1) // Note that this function reads device code of any of the three known flash // families; Intel, AMD and SST. This works because Intel and AMD use // the same command data for entering READ_IDENTIFIER mode (0x90). // The function should be copied and executed from RAM! #if (CHIPSET != 15) void ffsdrv_device_id_read(uint32 base_addr, uint16 *manufact, uint16 *device) { int addr, i; // This silly looking code has one purpose; to set addr = 0xAAAA. It is // necessary in order to force the compiler NOT to produce code that // uses LDR opcode(s) with PC-relative addressing. The assember code // produced from this C code is completely relocatable! for (i = 0, addr = 0; i < 2; i++) addr |= addr << 8 | 0xAA; FLASH_WRITE_HALFWORD (base_addr + addr, 0xAA); FLASH_WRITE_HALFWORD (base_addr + (addr >> 1), 0x55); // Intel/AMD read id command FLASH_WRITE_HALFWORD (base_addr + addr, 0x90); *manufact = FLASH_READ_HALFWORD (base_addr); // flash a0 = 0 device[0] = FLASH_READ_HALFWORD (base_addr + 2); // flash a0 = 1 // Read extended id device[1] = FLASH_READ_HALFWORD (base_addr + (0xE << 1)); device[2] = FLASH_READ_HALFWORD (base_addr + (0xF << 1)); FLASH_WRITE_HALFWORD (base_addr, 0xFF); // Intel read-array command // AMD devices do not need the two unlock cycles but SST devices do, // even though the SST datasheets states otherwise ;-) FLASH_WRITE_HALFWORD (base_addr + addr, 0xAA); FLASH_WRITE_HALFWORD (base_addr + (addr >> 1), 0x55); // AMD read-array/reset command FLASH_WRITE_HALFWORD (base_addr + addr, 0xF0); } #else /* for CHIPSET == 15 */ // Convert a offset_t value to a block index void ffsdrv_device_id_read(uint32 base_addr, uint16 *manufact, uint16 *device) { #ifdef INTEL_FLASH /* unlock cycle */ FLASH_WRITE_HALFWORD (base_addr, 0x60); FLASH_WRITE_HALFWORD (base_addr, 0xD0); //Enter into auto select command FLASH_WRITE_HALFWORD (base_addr, 0x90); *manufact = FLASH_READ_HALFWORD (base_addr); device[0]=FLASH_READ_HALFWORD ((base_addr+0x02)); // Read extended id device[1]=FLASH_READ_HALFWORD ((base_addr+0x0A)); device[2]=0; //FLASH_READ_HALFWORD ((base_addr+0xF)); /* Exit from auto select --- reset */ FLASH_WRITE_HALFWORD (base_addr, 0xFF); #else int addr, i; // This silly looking code has one purpose; to set addr = 0x555. It is // necessary in order to force the compiler NOT to produce code that // uses LDR opcode(s) with PC-relative addressing. The assember code // produced from this C code is completely relocatable! for (i = 0, addr = 0; i < 2; i++) addr |= addr << 4 | 0xAA; /* unlock cycle */ FLASH_WRITE_HALFWORD ((base_addr+addr), 0xAA); FLASH_WRITE_HALFWORD ((base_addr+(addr>>1)), 0x55); //Enter into auto select command FLASH_WRITE_HALFWORD ((base_addr+addr), 0x90); *manufact = FLASH_READ_HALFWORD (base_addr); device[0]=FLASH_READ_HALFWORD ((base_addr+0x02)); // Read extended id device[1]=FLASH_READ_HALFWORD ((base_addr+(0x0E<<1))); device[2]=FLASH_READ_HALFWORD ((base_addr+(0xF<<1))); /* Exit from auto select --- reset */ FLASH_WRITE_HALFWORD (base_addr, 0xF0); #endif } #endif #define offset2block(offset) (((uint32) offset) >> dev.binfo[0].size_ld) #ifdef AMD_FLASH void ffsdrv_amd_fg_write_halfword(volatile uint16 *addr, uint16 value) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint8 * offset; uint32 unlockOffset; static int badFlashCount=0; offset = (uint8*)addr - (uint32)(dev.base); unlockOffset = (dev.binfo[offset2block(offset)].offset+ 0x80)>>1; /* device state is write state */ OS_LOCK_MUTEX(&ffs_write_mutex); dev.state=DEV_WRITE; /* Dissable the interrupts */ cpsr=int_disable(); /*LOCOSTO-Live Unlock Fix */ flash[0]=0x0f0; flash[0]= 0x0060; // sector unlock sequence flash[0]= 0x0060; // sector unlock sequence flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) redowrite: flash[0]=0x0f0; /* two unlock cycles */ flash[0x555]=0xAA; flash[0x2AA]=0x55; /* issue the program command now */ flash[0x555]=0xA0; dev.addr=addr; /* record the last write */ dev.data=value; *addr = value; /* this will be base+offset */ /* Enable the interrupts */ int_enable(cpsr); /* Wait for the write to complete */ while (1) { unsigned short temp= (*addr); badFlashCount++; if(!((temp ^ dev.data) & 0x80)) break; else if ((temp & 0x20)) { if((((*addr) ^ dev.data) & 0x80)) goto redowrite; break; } else continue; }/* Data polling */ /* change the state to default read mode */ dev.state=DEV_READ; OS_UNLOCK_MUTEX(&ffs_write_mutex); } void ffsdrv_amd_fg_write_halfword_local(volatile uint16 *addr, uint16 value) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint8 * offset; uint32 unlockOffset; static int badFlashCount=0; // offset = (uint8*)addr - (uint32)(dev.base); // unlockOffset = (dev.binfo[offset2block(offset)].offset+ 0x80)>>1; /* device state is write state */ OS_LOCK_MUTEX(&ffs_write_mutex); dev.state=DEV_WRITE; /* Dissable the interrupts */ cpsr=int_disable(); /*LOCOSTO-Live Unlock Fix */ // flash[0]=0x0f0; // flash[0]= 0x0060; // sector unlock sequence // flash[0]= 0x0060; // sector unlock sequence // flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) redowrite: flash[0]=0x0f0; /* two unlock cycles */ flash[0x555]=0xAA; flash[0x2AA]=0x55; /* issue the program command now */ flash[0x555]=0xA0; dev.addr=addr; /* record the last write */ dev.data=value; *addr = value; /* this will be base+offset */ /* Enable the interrupts */ int_enable(cpsr); /* Wait for the write to complete */ while (1) { unsigned short temp= (*addr); badFlashCount++; if(!((temp ^ dev.data) & 0x80)) break; else if ((temp & 0x20)) { if((((*addr) ^ dev.data) & 0x80)) goto redowrite; break; } else continue; }/* Data polling */ /* change the state to default read mode */ dev.state=DEV_READ; OS_UNLOCK_MUTEX(&ffs_write_mutex); } void ffsdrv_amd_fg_write_halfword_unlock_bypass(volatile uint16 *addr, uint16 value) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint8 * offset; uint32 unlockOffset; static int badFlashCount=0; // offset = (uint8*)addr - (uint32)(dev.base); // unlockOffset = (dev.binfo[offset2block(offset)].offset+ 0x80)>>1; /* device state is write state */ OS_LOCK_MUTEX(&ffs_write_mutex); dev.state=DEV_WRITE; /* Dissable the interrupts */ cpsr=int_disable(); /*LOCOSTO-Live Unlock Fix */ // flash[0]=0x0f0; // flash[0]= 0x0060; // sector unlock sequence // flash[0]= 0x0060; // sector unlock sequence // flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) redowrite: flash[0]=0x0f0; /* two unlock cycles */ // flash[0x555]=0xAA; // flash[0x2AA]=0x55; /* issue the program command now */ flash[0x555]=0xA0; dev.addr=addr; /* record the last write */ dev.data=value; *addr = value; /* this will be base+offset */ /* Enable the interrupts */ int_enable(cpsr); /* Wait for the write to complete */ while (1) { unsigned short temp= (*addr); badFlashCount++; if(!((temp ^ dev.data) & 0x80)) break; else if ((temp & 0x20)) { if((((*addr) ^ dev.data) & 0x80)) goto redowrite; break; } else continue; }/* Data polling */ /* change the state to default read mode */ dev.state=DEV_READ; OS_UNLOCK_MUTEX(&ffs_write_mutex); } void ffsdrv_amd_fg_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; volatile uint16 *flash = (volatile uint16*)dev.base; uint8 * offset; uint32 unlockOffset; uint32 unlock_bypass=0x0; uint32 cpsr; /*#ifdef WCP_PROF prf_LogFunctionEntry((unsigned long) ffsdrv_amd_fg_write); #endif */ if (size > 0) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } if (size >=2) { offset = (uint8 *)dst - (uint32)(dev.base); unlockOffset = (dev.binfo[offset2block(offset)].offset+ 0x80)>>1; cpsr=int_disable(); flash[0]=0x0f0; flash[0]= 0x0060; // sector unlock sequence flash[0]= 0x0060; // sector unlock sequence flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) int_enable(cpsr); cpsr=int_disable(); // two unlock cycles flash[0x555]=0xAA; flash[0x2AA]=0x55; // issue the program command now flash[0x555]=0x20; int_enable(cpsr); unlock_bypass=1; } // cpsr=int_disable(); while (size >= 2) { // ffsdrv_amd_fg_write_halfword_local((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); ffsdrv_amd_fg_write_halfword_unlock_bypass((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } // int_enable(cpsr); //#if 0 if(unlock_bypass==1) { offset = (uint8*)dev.addr - (uint32)(dev.base); cpsr=int_disable(); flash[dev.binfo[offset2block(offset)].offset] = 0x90; *(dev.addr) = 0x00; // flash[0]=0x0f0; int_enable(cpsr); } //#endif if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } /*#ifdef WCP_PROF prf_LogFunctionExit((unsigned long) ffsdrv_amd_fg_write); #endif */ } void ffsdrv_amd_fg_erase(uint8 block) { uint16 *addr = (uint16 *) block2addr(block); ffsdrv.erase_sector(addr); } void ffsdrv_amd_fg_erase_sector(void *dst) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint32 unlockOffset; dev.addr = (uint16 *) dst; unlockOffset = ((uint32)(dev.addr)-(uint32)(dev.base) + 0x80) >> 1; /* change the device status */ dev.state=DEV_ERASE; /* disable the interrupts */ cpsr=int_disable(); /*LOCOSTO-Live Unlock Fix */ flash[0]=0x0f0; flash[0]= 0x0060; // sector unlock sequence flash[0]= 0x0060; // sector unlock sequence flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) flash[0]=0x0f0; /* sector erase command -- 6 cycles */ flash[0x555] =0xAA; flash[0x2AA]=0x55; flash[0x555]=0x80; flash[0x555]= 0xAA; flash[0x2AA]=0x55; *((volatile uint16*)(dev.addr))=0x30; /* write the command to sector address */ /* Enable the interrupts */ int_enable(cpsr); /* Wait for the erase to complete */ while ((*dev.addr & 0x80) == 0); /* DQ7 will have 1 on completion of erase */ /* Data polling */ /* change the device state to default READ mode */ dev.state=DEV_READ; } //OMAPS62129 Create NEW pseudo SB erase function for AMD_NOR (Isample v1.x) //This version allows the 3Mb of Flash not used by 1Mb FFS in Block C to //be reused for other code/data. void ffsdrv_amd_fg_erase_sector_pseudo_sb(void *dst) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint32 unlockOffset; dev.addr = (uint16 *) dst; unlockOffset = ((uint32)(dev.addr)-(uint32)(dev.base) + 0x80) >> 1; /* change the device status */ dev.state=DEV_ERASE; ttw(ttr(TTrDrvErase, "e(%d){" NL, dst)); /* disable the interrupts */ cpsr=int_disable(); /*LOCOSTO-Live Unlock Fix */ flash[0]=0x0f0; flash[0]= 0x0060; // sector unlock sequence flash[0]= 0x0060; // sector unlock sequence flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) flash[0]=0x0f0; /* sector erase command -- 6 cycles */ flash[0x555] =0xAA; flash[0x2AA]=0x55; flash[0x555]=0x80; flash[0x555]= 0xAA; flash[0x2AA]=0x55; *((volatile uint16*)(dev.addr))=0x30; /* write the command to sector address */ /* Enable the interrupts */ //CQ62129 start - new while loop added // delay re-enabling until after sector erased or we have an int to service /* Wait for the erase to complete */ while ((*dev.addr & 0x80) == 0) /* DQ7 will have 1 on completion of erase */ /* Data polling */ // add option to suspend if a frame interrupt occurs, same as old AMD single bank driver { // Poll interrupts, taking interrupt mask into account and check if IRQ was actually enabled if ((INT_REQUESTED) && !(cpsr & ~0x80)) { // 1. suspend erase // 2. enable interrupts // .. now the interrupt code executes // 3. disable interrupts // 4. resume erase // Suspend erase *((volatile uint16*)(dev.addr)) = 0xB0; // wait for erase suspend to finish while ((*((volatile uint16*)(dev.addr)) & 0x80) == 0); dev.state = DEV_ERASE_SUSPEND; int_enable(cpsr); // Other interrupts and tasks run now... cpsr=int_disable(); // Before resuming erase we must? check if the erase is really // suspended or if it did finish *((volatile uint16*)(dev.addr)) = 0x30; dev.state = DEV_ERASE; } } int_enable(cpsr); //CQ62129 end ttw(ttr(TTrDrvErase, "}" NL)); /* change the device state to default READ mode */ dev.state=DEV_READ; } void ffsdrv_amd_fg_write_suspend(void) { OS_LOCK_MUTEX(&ffs_write_mutex); /* Got the Mutex Write Got over */ OS_UNLOCK_MUTEX(&ffs_write_mutex); } void ffsdrv_amd_mb_write_halfword(volatile uint16 *addr, uint16 value) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint8 * offset; uint32 unlockOffset; static int badFlashCount=0; unsigned short temp1; offset = (uint8*)addr - (uint32)(dev.base); unlockOffset = (dev.binfo[offset2block(offset)].offset+ 0x80)>>1; /* device state is write state */ OS_LOCK_MUTEX(&ffs_write_mutex); dev.state=DEV_WRITE; /* Dissable the interrupts */ cpsr=int_disable(); temp1 = (*addr); redowrite: flash[0]=0x0f0; /* two unlock cycles */ flash[0x555]=0xAA; flash[0x2AA]=0x55; /* issue the program command now */ flash[0x555]=0xA0; dev.addr=addr; /* record the last write */ dev.data=value; *addr = value; /* this will be base+offset */ /* Enable the interrupts */ int_enable(cpsr); /* Wait for the write to complete */ while (1) { unsigned short temp= (*addr); badFlashCount++; if(!((temp ^ dev.data) & 0x80)) break; else if ((temp & 0x20)) { if((((*addr) ^ dev.data) & 0x80)) goto redowrite; break; } else continue; }/* Data polling */ /* change the state to default read mode */ dev.state=DEV_READ; OS_UNLOCK_MUTEX(&ffs_write_mutex); } void ffsdrv_amd_mb_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; if (size > 0) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_amd_mb_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) ffsdrv_write_byte(mydst++, *mysrc++); } } void ffsdrv_amd_mb_erase(uint8 block) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 cpsr; uint32 unlockOffset; dev.addr = (uint16 *) block2addr(block); unlockOffset = ((uint32)(dev.addr)-(uint32)(dev.base) + 0x80) >> 1; /* change the device status */ dev.state=DEV_ERASE; /* disable the interrupts */ cpsr=int_disable(); /* sector erase command -- 6 cycles */ flash[0x555] =0xAA; flash[0x2AA]=0x55; flash[0x555]=0x80; flash[0x555]= 0xAA; flash[0x2AA]=0x55; *((volatile uint16*)(dev.addr))=0x30; /* write the command to (short) sector address */ /* Enable the interrupts */ //CQ72069 start - new while loop added // delay re-enabling until after sector erased or we have an int to service /* Wait for the erase to complete */ while ((*dev.addr & 0x80) == 0) /* DQ7 will have 1 on completion of erase */ /* Data polling */ // add option to suspend if a frame interrupt occurs, same as old AMD single bank driver { // Poll interrupts, taking interrupt mask into account and check if IRQ was actually enabled if ((INT_REQUESTED) && !(cpsr & ~0x80)) { // 1. suspend erase // 2. enable interrupts // .. now the interrupt code executes // 3. disable interrupts // 4. resume erase // Suspend erase *((volatile uint16*)(dev.addr)) = 0xB0; // wait for erase suspend to finish while ((*((volatile uint16*)(dev.addr)) & 0x80) == 0); dev.state = DEV_ERASE_SUSPEND; int_enable(cpsr); // Other interrupts and tasks run now... cpsr=int_disable(); // Before resuming erase we must? check if the erase is really // suspended or if it did finish *((volatile uint16*)(dev.addr)) = 0x30; dev.state = DEV_ERASE; } } int_enable(cpsr); //CQ72069 end ttw(ttr(TTrDrvErase, "}" NL)); /* change the device state to default READ mode */ dev.state=DEV_READ; } void ffsdrv_amd_mb_erase_sector(void *dst) { volatile uint16 *flash; uint32 cpsr; dev.addr = (uint16 *) dst; flash= dev.addr; /* change the device status */ dev.state=DEV_ERASE; OS_LOCK_MUTEX(&ffs_write_mutex); /* disable the interrupts */ cpsr=int_disable(); /* sector erase command -- 6 cycles */ flash[0x555] =0xAA; flash[0x2AA]=0x55; flash[0x555]=0x80; flash[0x555]= 0xAA; flash[0x2AA]=0x55; *((volatile uint16*)(dev.addr))=0x30; /* write the command to sector address */ /* Enable the interrupts */ int_enable(cpsr); /* Wait for the erase to complete */ while ((*dev.addr & 0x80) == 0); /* DQ7 will have 1 on completion of erase */ /* Data polling */ /* change the device state to default READ mode */ dev.state=DEV_READ; } void ffsdrv_amd_mb_write_erase_suspend(void) { uint32 cpsr; tlw(led_on(LED_ERASE_SUSPEND)); ttw(str(TTrDrvErase, "es" NL)); // if erase has finished then all is ok if (*dev.addr & 0x80) { ffsdrv_amd_erase_end(); tlw(led_off(LED_ERASE_SUSPEND)); return; } // NOTEME: As there is no way to be absolutely certain that erase // doesn't finish between last poll and the following erase suspend // command, we assume that the erase suspend is safe even though the // erase IS actually already finished. cpsr = int_disable(); dev.state = DEV_ERASE_SUSPEND; *dev.addr = 0xB0; // Wait for erase suspend to finish while ((*dev.addr & 0x80) == 0) /* Enabling the interrupt should be after this while, */ /* becose DQ7==1 on entering to erase suspend mode */ ; int_enable(cpsr); } void ffsdrv_amd_write_erase_resume(void) { uint32 cpsr; ttw(str(TTrDrvErase, "er" NL)); // NOTEME: See note in erase_suspend()... We assume that the erase // resume is safe even though the erase IS actually already finished. cpsr = int_disable(); dev.state = DEV_ERASE; *dev.addr = 0x30; int_enable(cpsr); tlw(led_off(LED_ERASE_SUSPEND)); } void ffsdrv_amd_mb_buffer_write(void *dst, const void *src, uint16 size) { uint8 *mydst = dst; const uint8 *mysrc = src; uint8 unalignedbytes = 0; uint16 sizeEven; // use halfword write for size less than 32 bytes if (size <= 32) { if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } while (size >= 2) { ffsdrv_amd_mb_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; } if (size == 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } } // If size is more than 32 bytes then go for write buffer feature else if (size > 32) { // if the destination addredd is odd, write first byte in that. if ((unsigned int) mydst & 1) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } // write unaligned bytes in the write buffer page, since write buffer feature does not allow // write across write buffer boundaries and write can not start in the midded of the write buffer page. unalignedbytes = (0x20 - (unsigned int) mydst & 0x0000001F); if(unalignedbytes > 0) { while (unalignedbytes > 0) { ffsdrv_amd_mb_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8)); size -= 2; mysrc += 2; mydst += 2; unalignedbytes -= 2; } } // Write data using buffer write function if (size >=2) { // Truncate to an even number of bytes sizeEven = size & (uint16) ~1; // write the data using write buffer feature ffsdrv_amd_mb_buffer_write_new((uint16 *) mydst, mysrc, sizeEven); size -=sizeEven; mysrc += sizeEven; mydst += sizeEven; } // Write Last byte if(size==1 ) { ffsdrv_write_byte(mydst++, *mysrc++); size--; } } } void ffsdrv_amd_mb_buffer_write_new(volatile UINT16 *dst_addr, const UINT8 *src_addr, UINT16 size) { volatile uint16 *flash = (volatile uint16*)dev.base; volatile UINT16 *dst_ptr; const UINT8 *src_ptr; volatile UINT16 *last_loaded_addr; UINT16 write_data; UINT32 word_count; UINT32 word_size = size >> 1; uint32 cpsr; static int badFlashCount=0; dst_ptr=dst_addr; src_ptr=src_addr; OS_LOCK_MUTEX(&ffs_write_mutex); dev.state=DEV_WRITE; cpsr=int_disable(); // two unlock cycles flash[0x555]=0xAA; flash[0x2AA]=0x55; // Unlock Bypass flash[0x555]=0x20; int_enable(cpsr); while (word_size >0) { cpsr=int_disable(); // maximum 16 words can be written using write buffer word_count = 16; if (word_count > word_size) { word_count = word_size; } word_size -= word_count; redowrite_buf: flash[0]=0x0f0; /* Write to Buffer Command */ FLASH_WRITE(dst_ptr, 0x25); dev.addr=dst_ptr; dev.data=src_ptr[0] | (src_ptr[1] << 8); /* Write number of locations to program */ FLASH_WRITE(dst_ptr, word_count - 1); /* Load data into buffer */ while (word_count > 0) { /* Store last loaded address and data value (for polling) */ last_loaded_addr = dst_ptr; write_data = src_ptr[0] | (src_ptr[1] << 8); /* Write Data */ *dst_ptr=write_data; dst_ptr++; src_ptr +=2; word_count--; } /* Program Buffer to Flash Command */ FLASH_WRITE(last_loaded_addr, 0x29); int_enable(cpsr); /* Poll for completion, then check result */ while (1) { unsigned short temp= (*last_loaded_addr); badFlashCount++; if(!((temp ^ write_data) & 0x80)) break; else if ((temp & 0x20)) { if((((*last_loaded_addr) ^ write_data) & 0x80)) goto redowrite_buf; break; } else continue; } } FLASH_WRITE(dst_ptr, 0x90); FLASH_WRITE(dst_ptr, 0x00); /* change the state to default read mode */ dev.state=DEV_READ; OS_UNLOCK_MUTEX(&ffs_write_mutex); } #endif void ffsdrv_query_cfi_data(uint32 base_addr, uint16 addr, uint16* data) { volatile char *flash = (char*) base_addr; flash[0xAA] = 0x98; // Set CFI query mode *data = *((volatile uint16 *) (base_addr + addr)); // Query data flash[0xAA] = 0xF0; // AMD read-array/reset command flash[0] = 0xFF; // Intel read-array/reset command } void ffsdrv_copy_code_to_ram(uint16 *dst, uint16 *src, int size) { // The ARM7TDMI compiler sets bit 0 for thumb mode function pointers, so // we need to clear this in order to copy *all* bytes. Otherwise we // exclude first byte and the resulting copy becomes garbage src = (uint16 *) (~1 & (int) src); size /= 2; while (size--) *dst++ = *src++; } // Copy ffsdrv_xxx_sb_erase() and ffsdrv_xxx_sb_write_halfword() functions // to RAM. The only known way to determine the size of the code is to look // either in the linker-generated map file or in the assember output file. int ffsdrv_driver_copy_to_ram(int type) { int size; uint16 *src, *dst; extern uint16 ffsdrv_ram_amd_begin[]; extern uint16 ffsdrv_ram_intel_begin[]; uint32 offset_of_init; uint32 offset_of_erase; uint32 offset_of_write_halfword; ttw(ttr(TTrDrvOther, "ffsdrv_driver_copy_to_ram() {" NL)); switch (type) { #ifdef AMD_FLASH case FFS_DRIVER_AMD: case FFS_DRIVER_AMD_SB: src = ffsdrv_ram_amd_begin; offset_of_erase = (uint32) ffsdrv_ram_amd_sb_erase_sector - (uint32) src; offset_of_write_halfword = (uint32) ffsdrv_ram_amd_sb_write_halfword - (uint32) src; break; #endif #ifdef INTEL_FLASH case FFS_DRIVER_INTEL: case FFS_DRIVER_INTEL_SB: case FFS_DRIVER_INTEL_BW: src = ffsdrv_ram_intel_begin; offset_of_init = (uint32) ffsdrv_ram_intel_sb_init - (uint32) src; offset_of_erase = (uint32) ffsdrv_ram_intel_sb_erase_sector - (uint32) src; offset_of_write_halfword = (uint32) ffsdrv_ram_intel_sb_write_halfword - (uint32) src; break; #endif default: ttw(ttr(TTrDrvOther, "}" NL)); return 0; } // Make sure we are handling a half-word aligned address (Thumb mode // function pointers have lsb set!) src = (uint16 *) (~1 & (int) src); // If we detect that the linker allocated the driver to RUN in RAM, the // user has obviously NOT removed those linker lines and we bail out! if (offset_of_erase > FFSDRV_CODE_SIZE) return EFFS_DRIVER; dst = (uint16 *) &ffsdrv_code; // Code size in halfwords size = FFSDRV_CODE_SIZE / 2; // Rebind the two changed driver functions if (type == FFS_DRIVER_AMD_SB || type == FFS_DRIVER_INTEL_SB) { ffsdrv.erase_sector = (void (*)(void *)) (offset_of_erase + (uint32) dst); ffsdrv.write_halfword = (void (*)(volatile uint16 *, uint16)) (offset_of_write_halfword + (uint32) dst); } if (type == FFS_DRIVER_INTEL_SB) { ffsdrv.init = (int (*)(void)) (offset_of_init + (uint32) dst); } ttw(ttr(TTrDrvOther, "ffsdrv_code, init, write, erase_sector = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL, dst, (uint32) ffsdrv.init, (uint32) ffsdrv.write_halfword, (uint32) ffsdrv.erase_sector)); #ifdef AMD_FLASH ttw(ttr(TTrDrvOther, "amd_begin, init, write, erase_sector = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL, ffsdrv_ram_amd_begin, ffsdrv_null_init, ffsdrv_ram_amd_sb_write_halfword, ffsdrv_ram_amd_sb_erase_sector)); #endif #if 0 //fangcj removed them #ifdef INTEL_FLASH ttw(ttr(TTrDrvOther, "intel_begin, init, write, erase_sector = 0x%07x, 0x%07x, 0x%07x, 0x%07x" NL, ffsdrv_ram_intel_begin, ffsdrv_ram_intel_sb_init, ffsdrv_ram_intel_sb_write_halfword, ffsdrv_ram_intel_sb_erase_sector)); #endif #endif // Copy the code to RAM while (size--) *dst++ = *src++; ttw(ttr(TTrDrvOther, "}" NL)); return 0; } #else // (TARGET == 0) void ffsdrv_device_id_read(volatile uint32 base_addr, uint16 *manufact, uint16 *device) {} /*Add by ZhangTing for PC simulator 2006-06-15*/ #ifdef AMD_FLASH void ffsdrv_amd_fg_write_halfword(volatile uint16 *addr, uint16 value){}; void ffsdrv_amd_fg_write_halfword_local(volatile uint16 *addr, uint16 value){}; void ffsdrv_amd_fg_write_halfword_unlock_bypass(volatile uint16 *addr, uint16 value){}; void ffsdrv_amd_fg_write(void *dst, const void *src, uint16 size){}; void ffsdrv_amd_fg_erase(uint8 block){}; void ffsdrv_amd_fg_erase_sector(void *dst){}; void ffsdrv_amd_fg_erase_sector_pseudo_sb(void *dst){}; void ffsdrv_amd_fg_write_suspend(void){}; void ffsdrv_amd_mb_write_halfword(volatile uint16 *addr, uint16 value){}; void ffsdrv_amd_mb_write(void *dst, const void *src, uint16 size){}; void ffsdrv_amd_mb_erase(uint8 block){}; void ffsdrv_amd_mb_erase_sector(void *dst){}; void ffsdrv_amd_mb_write_erase_suspend(void){}; void ffsdrv_amd_write_erase_resume(void){}; void ffsdrv_amd_mb_buffer_write(void *dst, const void *src, uint16 size){}; void ffsdrv_amd_mb_buffer_write_new(volatile UINT16 *dst_addr, UINT16 *src_addr, UINT16 size){}; #endif /*End*/ void ffsdrv_copy_code_to_ram(uint16 *dst, uint16 *src, int size) {} int ffsdrv_driver_copy_to_ram(int type) { return 0; } void ffsdrv_query_cfi_data(uint32 base_addr, uint16 addr, uint16* data) {} #endif // (TARGET == 1) /****************************************************************************** * Initialization ******************************************************************************/ #ifdef AMD_FLASH const struct ffsdrv_s ffsdrv_amd_nor = { ffsdrv_null_init, ffsdrv_amd_fg_erase, ffsdrv_null_write_buffer, ffsdrv_amd_fg_write_halfword, ffsdrv_amd_fg_write, ffsdrv_amd_fg_write_suspend, /* use amd_write_end */ ffsdrv_null_write_resume, ffsdrv_amd_erase_suspend, /* use amd_erase_suspend */ ffsdrv_amd_erase_resume, /* use amd_erase_resueme */ ffsdrv_amd_fg_erase_sector }; //OMAPS62129 This is pseudo single bank driver for AMD_NOR, 3Mb in bank C in Flash can be reused for // code/data and so there is no wasted space in flash const struct ffsdrv_s ffsdrv_amd_nor_pseudo_sb = { ffsdrv_null_init, ffsdrv_amd_fg_erase, ffsdrv_null_write_buffer, ffsdrv_amd_fg_write_halfword, ffsdrv_amd_fg_write, ffsdrv_amd_fg_write_suspend, /* This is a null function anyway */ ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, /* use null driver as code cannot execute and so require suspend when FFS is erasing */ ffsdrv_null_erase_resume, /* use amd_erase_resueme */ ffsdrv_amd_fg_erase_sector_pseudo_sb }; const struct ffsdrv_s ffsdrv_amd_mirror_bit = { ffsdrv_amd_mb_init, ffsdrv_amd_mb_erase, ffsdrv_null_write_buffer, ffsdrv_amd_mb_write_halfword, ffsdrv_amd_mb_buffer_write, // ffsdrv_amd_mb_write, ffsdrv_amd_fg_write_suspend, /* This is a null function anyway */ ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, /* use null driver as code cannot execute and so require suspend when FFS is erasing */ ffsdrv_null_erase_resume, /* use amd_erase_resueme */ ffsdrv_amd_mb_erase_sector }; const struct ffsdrv_s ffsdrv_amd = { ffsdrv_null_init, ffsdrv_amd_erase, ffsdrv_null_write_buffer, ffsdrv_amd_write_halfword, ffsdrv_amd_write, ffsdrv_amd_write_end, // Wait for write to finish instead of suspend it ffsdrv_null_write_resume, ffsdrv_amd_erase_suspend, ffsdrv_amd_erase_resume, ffsdrv_amd_erase_sector }; const struct ffsdrv_s ffsdrv_amd_sb = { ffsdrv_null_init, ffsdrv_ram_amd_sb_erase, ffsdrv_null_write_buffer, ffsdrv_ram_amd_sb_write_halfword, ffsdrv_generic_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_ram_amd_sb_erase_sector }; #endif const struct ffsdrv_s ffsdrv_sst = { ffsdrv_null_init, ffsdrv_sst_erase, ffsdrv_null_write_buffer, ffsdrv_amd_write_halfword, // Use AMD driver function ffsdrv_sst_write, ffsdrv_amd_write_end, // Use AMD driver function ffsdrv_null_write_resume, ffsdrv_sst_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_sst_erase_sector }; const struct ffsdrv_s ffsdrv_sst_sb = { ffsdrv_null_init, ffsdrv_null_erase, ffsdrv_null_write_buffer, ffsdrv_null_write_halfword, ffsdrv_null_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_null_erase_sector }; #ifdef INTEL_FLASH const struct ffsdrv_s ffsdrv_intel = { ffsdrv_null_init, ffsdrv_intel_erase, ffsdrv_null_write_buffer, ffsdrv_intel_write_halfword, // ffsdrv_generic_write, ffsdrv_intel_write, ffsdrv_intel_write_suspend, ffsdrv_intel_write_resume, ffsdrv_intel_erase_suspend, ffsdrv_intel_erase_resume, ffsdrv_intel_erase_sector }; const struct ffsdrv_s ffsdrv_intel_bw = { // ffsdrv_null_init,//fangcj revised 2006/06/28 ffsdrv_intel_init, ffsdrv_intel_erase, ffsdrv_intel_write_buffer_mode, ffsdrv_intel_write_halfword, ffsdrv_generic_buffer_write, ffsdrv_intel_write_suspend, ffsdrv_intel_write_resume, ffsdrv_intel_erase_suspend, ffsdrv_intel_erase_resume, ffsdrv_intel_erase_sector }; const struct ffsdrv_s ffsdrv_intel_sb = { ffsdrv_null_init, ffsdrv_ram_intel_sb_erase, ffsdrv_null_write_buffer, ffsdrv_ram_intel_sb_write_halfword, ffsdrv_generic_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_ram_intel_sb_erase_sector }; #endif const struct ffsdrv_s ffsdrv_null = { ffsdrv_null_init, ffsdrv_null_erase, ffsdrv_null_write_buffer, ffsdrv_null_write_halfword, ffsdrv_null_write, ffsdrv_null_write_suspend, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_null_erase_sector }; const struct ffsdrv_s ffsdrv_amd_pseudo_sb = { ffsdrv_null_init, ffsdrv_amd_pseudo_sb_erase, ffsdrv_null_write_buffer, ffsdrv_amd_pseudo_sb_write_halfword, ffsdrv_generic_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_amd_pseudo_sb_erase_sector }; const struct ffsdrv_s ffsdrv_ram = { ffsdrv_null_init, ffsdrv_ram_erase, ffsdrv_null_write_buffer, ffsdrv_ram_write_halfword, ffsdrv_ram_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_ram_erase_sector }; #if (TARGET == 0) const struct ffsdrv_s ffsdrv_test = { ffsdrv_null_init, ffsdrv_test_erase, ffsdrv_test_write_buffer, ffsdrv_test_write_halfword, ffsdrv_generic_write, // ffsdrv_generic_buffer_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_test_erase_sector }; const struct ffsdrv_s ffsdrv_test_bw = { ffsdrv_null_init, ffsdrv_test_erase, ffsdrv_test_write_buffer, ffsdrv_test_write_halfword, // ffsdrv_generic_write, ffsdrv_generic_buffer_write, ffsdrv_null_write_end, ffsdrv_null_write_resume, ffsdrv_null_erase_suspend, ffsdrv_null_erase_resume, ffsdrv_test_erase_sector }; #endif // Note: This function is designed for little-endian memory addressing! void ffsdrv_write_byte(void *dst, uint8 value) { uint16 halfword; tw(tr(TR_FUNC, TrDrvWrite, "ffsdrv_write_byte(0x%05x, 0x%x)\n", (int) (addr2offset(dst)), value)); ttw(str(TTrDrvWrite, "wbyte" NL)); if ((int) dst & 1) halfword = (value << 8) | *((uint8 *) dst - 1); else halfword = (*((uint8 *) dst + 1) << 8) | (value); ffsdrv.write_halfword((uint16 *) ((int) dst & ~1), halfword); } extern uint16 ffs_flash_manufact; extern uint16 ffs_flash_device; effs_t ffsdrv_init(void) { const struct ffsdrv_s *p; const struct flash_info_s *flash = &flash_info[0]; int error; tw(tr(TR_BEGIN, TrDrvInit, "drv_init() {\n")); ttw(str(TTrDrvOther, "ffsdrv_init() {" NL)); dev.state = DEV_READ; dev.binfo = 0; dev.base = 0; dev.numblocks = 0; // If ffs_flash_device is zero, detect device automatically by copying // the detect function into RAM and execute it from there... if (ffs_flash_manufact == 0 && ffs_flash_device == 0) { #if (TARGET == 1)/*Add by ZhangTing for PC simulator 2006-08-26*/ char detect_code[80]; typedef void (*pf_t)(uint32, uint16 *, uint16 *); pf_t myfp; uint16 device_id[3]; // Copy ffsdrv_device_id_read() function code to RAM. The only known // way to determine the size of the code is to look either in the // linker-generated map file or in the assember output file. ffsdrv_copy_code_to_ram((uint16 *) detect_code, (uint16 *) &ffsdrv_device_id_read, sizeof(detect_code)); // Combine bit 0 of the thumb mode function pointer with the address // of the code in RAM. Then call the detect function in RAM. myfp = (pf_t) (((int) &ffsdrv_device_id_read & 1) | (int) detect_code); (*myfp)(flash_base_addr, &dev.manufact, device_id); if ((dev.manufact == MANUFACT_AMD || dev.manufact == MANUFACT_FUJITSU) && (device_id[0] == 0x227E || device_id[0] == 0x2C7E|| device_id[0] == 0x2b7E)) { // This is a multi-id device dev.device = (device_id[1] << 8) | (device_id[2] & 0xFF); ttr(TTrAll, "*******dev.manufact = 0x%x, dev.device = 0x%x" NL, dev.manufact, dev.device); } else { dev.device = device_id[0]; ttr(TTrAll, "__________dev.manufact = 0x%x, dev.device = 0x%x" NL, dev.manufact, dev.device); } #endif/*End*/ } else { dev.manufact = ffs_flash_manufact; dev.device = ffs_flash_device; } tw(tr(TR_FUNC, TrDrvInit, "TARGET = %d\n", TARGET)); tw(tr(TR_FUNC, TrDrvInit, "Looking up device (0x%2x,0x%4x): ", dev.manufact, dev.device)); while (flash->manufact) { tw(tr(TR_NULL, TrDrvInit, "(0x%02x,0x%04x) ", flash->manufact, flash->device)); if (dev.manufact == flash->manufact && dev.device == flash->device) { tw(tr(TR_NULL, TrDrvInit, "FOUND ")); break; } flash++; } tw(tr(TR_NULL, TrDrvInit, "\n")); if (flash->manufact == 0) { tw(tr(TR_END, TrDrvInit, "} (%d)\n", EFFS_NODEVICE)); return EFFS_NODEVICE; } dev.binfo = (struct block_info_s *) flash->binfo; dev.base = (char *) flash->base; if (flash->driver == FFS_DRIVER_RAM) { // The ram image base addr can be set in 2 ways: In dev.c as a flash // base addr in the configuration or applied through the variable // ffs_ram_image_address. if (dev.base == 0) { if (ffs_ram_image_address == 0) { tw(tr(TR_END, TrDrvInit, "} (%d)\n", EFFS_DRIVER)); ttw(ttr(TTrDrvOther, "} (%d)" NL, EFFS_DRIVER)); return EFFS_DRIVER; } dev.base = (char *) ffs_ram_image_address; } } // Query flash write buffer size if ((flash->driver == FFS_DRIVER_INTEL_BW) || (flash->driver == FFS_DRIVER_AMD_MIRROR_BIT)) /*Need modifiy? ZhangTing 2006-08-26*/ { char cfi_code[80]; typedef void (*pf_t)(uint32, uint16, uint16 *); pf_t myfp; ffsdrv_copy_code_to_ram((uint16 *) cfi_code, (uint16 *)&ffsdrv_query_cfi_data, sizeof(cfi_code)); myfp = (pf_t) (((int) &ffsdrv_query_cfi_data & 1) | (int) cfi_code); (*myfp)(flash_base_addr, 0x2A<<1, &dev.write_buffersize); dev.write_buffersize = 1 << dev.write_buffersize; // Read as 2^n } else if (flash->driver == FFS_DRIVER_TEST)//FFS_DRIVER_TEST_BW /*Need modifiy? ZhangTing 2006-08-26*/ dev.write_buffersize = 64; // PC simulation else dev.write_buffersize = 2; // Default 2 bytes if (dev.write_buffersize / 2 > FFS_WR_BUF_MAX_WORDS) { tw(tr(TR_END, TrDrvInit, "} (%d)\n", EFFS_FWBUF2BIG)); ttw(ttr(TTrDrvOther, "} (%d)" NL, EFFS_FWBUF2BIG)); return EFFS_FWBUF2BIG; } ttw(ttr(TTrDrvOther, "Buffer size: 0x%x" NL, dev.write_buffersize)); dev.numblocks = flash->numblocks; dev.driver = flash->driver; // We assume that ALL blocks are of equal size dev.blocksize_ld = dev.binfo[0].size_ld; dev.blocksize = (1 << dev.blocksize_ld); dev.atomlog2 = FFS_ATOM_LOG2; dev.atomsize = 1 << dev.atomlog2; dev.atomnotmask = dev.atomsize - 1; #if (TARGET == 0) if (dev.manufact == MANUFACT_TEST) dev.base = ffsdrv_test_create(); if (dev.driver == FFS_DRIVER_TEST_BW) p = &ffsdrv_test_bw; else p = &ffsdrv_test; #else // (TARGET == 1) // Initialize hardware independent driver functions array switch (dev.driver) { #ifdef AMD_FLASH case FFS_DRIVER_AMD: p = &ffsdrv_amd; break; case FFS_DRIVER_AMD_SB: p = &ffsdrv_amd_sb; break; case FFS_DRIVER_AMD_NOR: p = &ffsdrv_amd_nor; break; //OMAPS62129 add new driver type case FFS_DRIVER_AMD_NOR_PSEUDO_SB: p = &ffsdrv_amd_nor_pseudo_sb; break; //OMAPS62129 end case FFS_DRIVER_AMD_MIRROR_BIT: ttr(TTrFatal, "ffsdrv_amd_mirror_bit is selected."); p=&ffsdrv_amd_mirror_bit; break; #endif case FFS_DRIVER_SST: p = &ffsdrv_sst; break; case FFS_DRIVER_SST_SB: p = &ffsdrv_sst_sb; break; #ifdef INTEL_FLASH case FFS_DRIVER_INTEL: p = &ffsdrv_intel; break; case FFS_DRIVER_INTEL_SB: p = &ffsdrv_intel_sb; break; case FFS_DRIVER_INTEL_BW: ttr(TTrFatal, "ffsdrv_intel_bw is selected."); p = &ffsdrv_intel_bw; break; #endif case FFS_DRIVER_AMD_PSEUDO_SB: p = &ffsdrv_amd_pseudo_sb; break; case FFS_DRIVER_RAM: p = &ffsdrv_ram; break; default: p = &ffsdrv_null; break; } #endif // (TARGET == 0) // Bind the driver functions ffsdrv.init = p->init; ffsdrv.erase = p->erase; ffsdrv.write_buffer = p->write_buffer; ffsdrv.write_halfword = p->write_halfword; ffsdrv.write = p->write; ffsdrv.write_suspend = p->write_suspend; ffsdrv.write_resume = p->write_resume; ffsdrv.erase_suspend = p->erase_suspend; ffsdrv.erase_resume = p->erase_resume; ffsdrv.erase_sector = p->erase_sector; switch (dev.driver) { #ifdef INTEL_FLASH case FFS_DRIVER_INTEL_BW: if (dev.write_buffersize <= 1) // If the device not support buffer write use ffsdrv_intel_write // instead ffsdrv.write = ffsdrv_intel_write; break; #endif default: break; } // Copy single bank driver code to RAM (and possibly re-bind some of the // driver functions) if (flash->driver != FFS_DRIVER_RAM) error = ffsdrv_driver_copy_to_ram(dev.driver); if (error >= 0) error = ffsdrv.init(); tw(tr(TR_FUNC, TrDrvInit, "dev.binfo = 0x%x\n", (unsigned int) dev.binfo)); tw(tr(TR_FUNC, TrDrvInit, "dev.base = 0x%x\n", (unsigned int) dev.base)); tw(tr(TR_FUNC, TrDrvInit, "dev.numblocks = %d\n", dev.numblocks)); tw(tr(TR_FUNC, TrDrvInit, "dev.blocksize = %d\n", dev.blocksize)); tw(tr(TR_FUNC, TrDrvInit, "dev.atomlog2/atomsize/atomnotmask = %d/%d/%x\n", dev.atomlog2, dev.atomsize, dev.atomnotmask)); tw(tr(TR_END, TrDrvInit, "} %d\n", error)); ttw(ttr(TTrDrvOther, "} %d" NL, error)); #ifdef INTEL_FLASH /* unlock all the blocks */ ffsdrv_unlock_sectors(); #endif return error; } void ffsdrv_unlock_sectors(void) { volatile uint16 *flash = (volatile uint16*)dev.base; uint32 unlockOffset; uint32 i; uint32 cpsr; /* device state is write state */ // OS_LOCK_MUTEX(&ffs_write_mutex); dev.state=DEV_WRITE; cpsr=int_disable(); for(i=0;i >1; /* Dissable the interrupts */ flash[0]=0x0f0; flash[0]= 0x0060; // sector unlock sequence flash[0]= 0x0060; // sector unlock sequence flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH) /*TI david-yan for fix http://xmyanfa/bugzilla/show_bug.cgi?id=4188 2006-8-21*/ if(i==(dev.numblocks-1))//we are unlocking the last blcok, so we should exit the unlock sequence { flash[0]=0x0f0;//david-yan 2006-8-21 } /*TI david-yan added end*/ #else flash[dev.binfo[i].offset>>1] = 0x60; // sector unlock sequence flash[dev.binfo[i].offset>>1] = 0xD0; // sector unlock sequence (address6 = VIH) flash[dev.binfo[i].offset>>1] = 0xff ; //read array #endif /* Enable the interrupts */ } #ifdef INTEL_FLASH // flash[0] = 0xFF; //read array #endif int_enable(cpsr); /* change the state to default read mode */ dev.state=DEV_READ; // OS_UNLOCK_MUTEX(&ffs_write_mutex); return; } /****************************************************************************** * Interrupt Enable/Disable ******************************************************************************/ // IMPORTANT NOTE! Apparently, locating this ARM assembly code at the top of // this file will make the compiler trash the A1 register between the calls // of arm_int_disable and arm_int_enable() thus crashing the whole system. // If the code is placed AFTER the usage of the functions, the compiler // saves the A1 register. Strange but true. // IMPORTANT NOTE! Apparently, another strange thing is that if the // functions are declared static, they don't work! // Executing code from RAM is NOT trivial when we need to jump between ROM // (flash) and RAM memory. The ARM only supports 26-bit relative branch // offsets. This is the reason why we have a local copy of the // arm_int_disable/enable() functions in this file plus each of the // single-bank drivers. #if (TARGET == 1) uint32 int_disable(void) { asm(" .state16"); asm(" mov A1, #0xC0"); asm(" ldr A2, tct_disable"); asm(" bx A2 "); asm(" .align"); // word align asm("tct_disable .field _TCT_Control_Interrupts+0,32"); asm(" .global _TCT_Control_Interrupts"); } void int_enable(uint32 cpsr) { asm(" .state16"); asm(" ldr A2, tct_enable"); asm(" bx A2 "); asm("tct_enable .field _TCT_Control_Interrupts+0,32"); asm(" .global _TCT_Control_Interrupts"); } #else uint32 int_disable(void) { return 0; } void int_enable(uint32 tmp) {} #endif // (TARGET == 1)