int flash_write_buf(WORD sector, int offset, byte *buffer, int numbytes) { int ret = -1; int i; unsigned char *p = flash_get_memptr(sector) + offset; /* After writing the flash block, compare the contents to the source * buffer. Try to write the sector successfully up to three times. */ //Pan.Liu //1. Erase flash //2. program flash //3. Verify for( i = 0; i < 3; i++ ) { ret = flash_write(sector, offset, buffer, numbytes); if( !memcmp( p, buffer, numbytes ) ) break; #ifdef DEBUGMSG //Pan.liu for debuging printk("****Erase flash and rewrite again!****\n"); printk("Error sector number:%d offset:%x ptr:%x\n",sector,offset,p); flash_sector_erase_int(sector); #endif ret = -1; } if( ret == -1 ) printk( "Flash write error. Verify failed\n" ); return( ret ); }
unsigned long kerSysReadFromFlash( void *toaddr, unsigned long fromaddr, unsigned long len ) { int sect = flash_get_blk((int) fromaddr); unsigned char *start = flash_get_memptr(sect); flash_read_buf( sect, (int) fromaddr - (int) start, toaddr, len ); return( len ); }
int flash_read_buf(WORD sector, int offset, byte *buffer, int numbytes) { byte *fwp; fwp = (byte *)flash_get_memptr(sector); while (numbytes) { *buffer++ = *(fwp + offset); numbytes--; fwp++; } return (1); }
static UINT16 flash_get_device_id() { volatile UINT16 *fwp; /* flash window */ UINT16 answer; fwp = (UINT16 *)flash_get_memptr(0); flash_command(FLASH_READ_ID, 0, 0, 0); answer = *(fwp + 1); if (answer == ID_AM29LV320M) { answer = *(fwp + 0xe); answer = *(fwp + 0xf); } flash_command(FLASH_RESET, 0, 0, 0); return( (UINT16) answer ); }
static int flash_get_cfi(struct cfi_query *query, UINT16 *cfi_struct, int flashFamily) { volatile UINT16 *fwp; /* flash window */ int i=0,temp=0; flash_command(FLASH_CFIQUERY, 0, 0, 0); if (cfi_struct == 0) fwp = (UINT16 *)flash_get_memptr(0); else fwp = cfi_struct; /* Initial house-cleaning */ for(i=0; i < 8; i++) { query->erase_block[i].sector_size = 0; query->erase_block[i].num_sectors = 0; } /* If not 'QRY', then we dont have a CFI enabled device in the socket */ if( fwp[0x10] != 'Q' && fwp[0x11] != 'R' && fwp[0x12] != 'Y') { flash_command(FLASH_RESET, 0, 0, 0); return(-1); } temp = fwp[0x27]; query->device_size = (int) (((int)1) << temp); query->num_erase_blocks = fwp[0x2C]; if(flashFamily == FLASH_SST) query->num_erase_blocks = 1; for(i=0; i < query->num_erase_blocks; i++) { query->erase_block[i].num_sectors = fwp[(0x2D+(4*i))] + (fwp[0x2E + (4*i)] << 8); query->erase_block[i].num_sectors++; query->erase_block[i].sector_size = 256 * (256 * fwp[(0x30+(4*i))] + fwp[(0x2F+(4*i))]); } flash_command(FLASH_RESET, 0, 0, 0); return(1); }
//MXIC flash only //for polling erase operation static int flash_wait_erase(WORD sector, int offset, UINT16 data) { volatile UINT16 *flashptr; /* flash window */ UINT16 d1; flashptr = (UINT16 *) flash_get_memptr(sector); do { while (!(*flashptr & 0x80)); // read DQ7 to see if it is one d1=*flashptr; d1 ^= *flashptr; if(d1==0) return STATUS_READY; }while(!(d1 & 0x20)); //time out DQ5 d1 = *flashptr; /* read data */ d1 ^= *flashptr; /* read it again and see what toggled */ if (d1 != 0) flash_command(FLASH_RESET, 0, 0, 0); return STATUS_TIMEOUT; }
void flash_init_info(const NVRAM_DATA *nvRam, FLASH_ADDR_INFO *fInfo) { int i = 0; int totalBlks = 0; int totalSize = 0; int auxFsSize = 0; int psiStartAddr = 0; int spStartAddr = 0; int usedBlkSize = 0; int needBytes = 0; int sBlk, eBlk; int blkSize, sectSize; /* Size of all blocks in a partition or 0 */ int totalPartSize; /* Size in bytes for a partition */ unsigned long offset; /* Offset calulations */ if (flash_get_flash_type() == FLASH_IFC_NAND) { /* When using NAND flash disable Bcm_flash */ totalSize = 0; } else { totalBlks = flash_get_numsectors(); totalSize = flash_get_total_size(); printk("Total Flash size: %dK with %d sectors\n", totalSize/1024, totalBlks); } if (totalSize <= FLASH_LENGTH_BOOT_ROM) { /* NAND flash settings. NAND flash does not use raw flash partitioins * to store psi, backup psi, scratch pad and syslog. These data items * are stored as files on a JFFS2 file system. */ if ((nvRam->ulPsiSize != -1) && (nvRam->ulPsiSize != 0)) fInfo->flash_persistent_length = nvRam->ulPsiSize * ONEK; else fInfo->flash_persistent_length = DEFAULT_PSI_SIZE * ONEK; fInfo->flash_persistent_start_blk = 0; fInfo->flash_rootfs_start_offset = 0; fInfo->flash_scratch_pad_length = SP_MAX_LEN; fInfo->flash_syslog_length = nvRam->ulSyslogSize * 1024; /* This is a boolean field for NAND flash. */ fInfo->flash_backup_psi_number_blk = nvRam->backupPsi; return; } /* * calculate mandatory primary PSI size and set its fInfo parameters. */ if ((nvRam->ulPsiSize != -1) && (nvRam->ulPsiSize != 0)) fInfo->flash_persistent_length = nvRam->ulPsiSize * ONEK; else fInfo->flash_persistent_length = DEFAULT_PSI_SIZE * ONEK; psiStartAddr = totalSize - fInfo->flash_persistent_length; fInfo->flash_persistent_start_blk = flash_get_blk(FLASH_BASE+psiStartAddr); fInfo->flash_persistent_number_blk = totalBlks - fInfo->flash_persistent_start_blk; usedBlkSize = 0; for (i = fInfo->flash_persistent_start_blk; i < (fInfo->flash_persistent_start_blk + fInfo->flash_persistent_number_blk); i++) { usedBlkSize += flash_get_sector_size((unsigned short) i); } fInfo->flash_persistent_blk_offset = usedBlkSize - fInfo->flash_persistent_length; fInfo->flash_meta_start_blk = fInfo->flash_persistent_start_blk; /* * Next is the optional scratch pad, which is on top of the primary PSI. * Old code allowed scratch pad to share a sector with primary PSI. * That is retained for backward compatibility. (Although depending on your * NOR flash sector sizes, they may still be in different sectors.) * If you have a new deployment, consider forcing separate sectors. */ if ((fInfo->flash_persistent_blk_offset > 0) && (fInfo->flash_persistent_blk_offset < SP_MAX_LEN)) { /* * there is some room left in the first persistent sector, but it is * not big enough for the scratch pad. (Use this line unconditionally * if you want to guarentee scratch pad and primary PSI are on different * sectors.) */ spStartAddr = psiStartAddr - fInfo->flash_persistent_blk_offset - SP_MAX_LEN; } else { /* either the primary PSI starts on a sector boundary, or there is * enough room at the top of the first sector for the scratch pad. */ spStartAddr = psiStartAddr - SP_MAX_LEN ; } fInfo->flash_scratch_pad_start_blk = flash_get_blk(FLASH_BASE+spStartAddr); fInfo->flash_scratch_pad_length = SP_MAX_LEN; if (fInfo->flash_persistent_start_blk == fInfo->flash_scratch_pad_start_blk) // share blk { #if 0 /* do not used scratch pad unless it's in its own sector */ printk("Scratch pad is not used for this flash part.\n"); fInfo->flash_scratch_pad_length = 0; // no sp #else /* allow scratch pad to share a sector with another section such as PSI */ fInfo->flash_scratch_pad_number_blk = 1; fInfo->flash_scratch_pad_blk_offset = fInfo->flash_persistent_blk_offset - fInfo->flash_scratch_pad_length; #endif } else // on different blk { fInfo->flash_scratch_pad_number_blk = fInfo->flash_persistent_start_blk - fInfo->flash_scratch_pad_start_blk; // find out the offset in the start_blk usedBlkSize = 0; for (i = fInfo->flash_scratch_pad_start_blk; i < (fInfo->flash_scratch_pad_start_blk + fInfo->flash_scratch_pad_number_blk); i++) usedBlkSize += flash_get_sector_size((unsigned short) i); fInfo->flash_scratch_pad_blk_offset = usedBlkSize - fInfo->flash_scratch_pad_length; } if (fInfo->flash_scratch_pad_length > 0) { fInfo->flash_meta_start_blk = fInfo->flash_scratch_pad_start_blk; } /* * Next is the optional backup PSI. */ if (nvRam->backupPsi == 0x01) { needBytes = fInfo->flash_persistent_length; i = fInfo->flash_meta_start_blk; while (needBytes > 0) { i--; needBytes -= flash_get_sector_size((unsigned short) i); } fInfo->flash_backup_psi_start_blk = i; /* calclate how many blocks we actually consumed */ needBytes = fInfo->flash_persistent_length; fInfo->flash_backup_psi_number_blk = 0; while (needBytes > 0) { needBytes -= flash_get_sector_size((unsigned short) i); i++; fInfo->flash_backup_psi_number_blk++; } fInfo->flash_meta_start_blk = fInfo->flash_backup_psi_start_blk; } else { fInfo->flash_backup_psi_number_blk = 0; } /* * Next is the optional persistent syslog. */ if (nvRam->ulSyslogSize != 0 && nvRam->ulSyslogSize != -1) { fInfo->flash_syslog_length = nvRam->ulSyslogSize * 1024; needBytes = fInfo->flash_syslog_length; i = fInfo->flash_meta_start_blk; while (needBytes > 0) { i--; needBytes -= flash_get_sector_size((unsigned short) i); } fInfo->flash_syslog_start_blk = i; /* calclate how many blocks we actually consumed */ needBytes = fInfo->flash_syslog_length; fInfo->flash_syslog_number_blk = 0; while (needBytes > 0) { needBytes -= flash_get_sector_size((unsigned short) i); i++; fInfo->flash_syslog_number_blk++; } fInfo->flash_meta_start_blk = fInfo->flash_syslog_start_blk; } else { fInfo->flash_syslog_length = 0; fInfo->flash_syslog_number_blk = 0; } #if 1 //for AUXFS if ( (nvRam->ucAuxFSPercent != 0) && (nvRam->ucAuxFSPercent <= MAX_AUXFS_PERCENT)) { /* Estimate the Auxillary File System size */ auxFsSize = (totalSize * (int)nvRam->ucAuxFSPercent)/100; /* JFFS_AUXFS offset */ offset = totalSize - auxFsSize - flash_get_reserved_bytes_at_end(fInfo); sBlk = flash_get_blk(offset+FLASH_BASE); eBlk = fInfo->flash_meta_start_blk; /* * Implementation Note: * Ensure that we have even number of blocks for * ROOTFS+KERNEL to support dual image booting */ if ( ( (sBlk+1) < eBlk) && ((((sBlk+1) - flash_get_blk(fInfo->flash_rootfs_start_offset + FLASH_BASE)) % 2) == 0)) { sBlk += 1; /* Round up */ } blkSize = flash_get_sector_size(sBlk); for ( i=sBlk+1, totalPartSize = blkSize; i<eBlk; i++) { sectSize = flash_get_sector_size(i); //if ( blkSize != sectSize ) blkSize = 0; if ( blkSize != sectSize ) break; totalPartSize += sectSize; } fAuxFsInfo.sect_size = blkSize; auxFsSize = totalPartSize; printk("Flash split %d : AuxFS[%d]\n", (int)nvRam->ucAuxFSPercent,auxFsSize ); } else { /* * Implementation Note: When there is no AuxFS Partition. * Total number of rootfs/kernel blocks will always be ODD. * Option: Increase RESERVED section ??? but this would * decrease the space available for a single kernel image */ sBlk = eBlk = 0; fAuxFsInfo.sect_size = 0; auxFsSize = 0; printk("Flash not used for Auxillary File System\n"); } /*------------*/ /* JFFS_AUXFS */ /*------------*/ sprintf(fAuxFsInfo.name, "JFFS_AUXFS"); fAuxFsInfo.start_blk = sBlk; fAuxFsInfo.number_blk = eBlk - sBlk; fAuxFsInfo.blk_offset = 0; fAuxFsInfo.total_len = auxFsSize; fAuxFsInfo.mem_base = (unsigned long) flash_get_memptr( sBlk ) + fAuxFsInfo.blk_offset; fAuxFsInfo.mem_length = auxFsSize; #endif #ifdef DEBUG_FLASH_TOO_MUCH /* dump sizes of all sectors in flash */ for (i=0; i<totalBlks; i++) printk("blk %03d: %d\n", i, flash_get_sector_size((unsigned short) i)); #endif #if defined(DEBUG_FLASH) printk("FLASH_BASE =0x%08x\n\n", (unsigned int)FLASH_BASE); printk("fInfo->flash_rootfs_start_offset =0x%08x\n\n", (unsigned int)fInfo->flash_rootfs_start_offset); printk("fInfo->flash_meta_start_blk = %d\n\n", fInfo->flash_meta_start_blk); printk("fInfo->flash_syslog_start_blk = %d\n", fInfo->flash_syslog_start_blk); printk("fInfo->flash_syslog_number_blk = %d\n", fInfo->flash_syslog_number_blk); printk("fInfo->flash_syslog_length=0x%x\n\n", (unsigned int)fInfo->flash_syslog_length); printk("fInfo->flash_backup_psi_start_blk = %d\n", fInfo->flash_backup_psi_start_blk); printk("fInfo->flash_backup_psi_number_blk = %d\n\n", fInfo->flash_backup_psi_number_blk); printk("sp startAddr = %x\n", (unsigned int) (FLASH_BASE+spStartAddr)); printk("fInfo->flash_scratch_pad_start_blk = %d\n", fInfo->flash_scratch_pad_start_blk); printk("fInfo->flash_scratch_pad_number_blk = %d\n", fInfo->flash_scratch_pad_number_blk); printk("fInfo->flash_scratch_pad_length = 0x%x\n", fInfo->flash_scratch_pad_length); printk("fInfo->flash_scratch_pad_blk_offset = 0x%x\n\n", (unsigned int)fInfo->flash_scratch_pad_blk_offset); printk("psi startAddr = %x\n", (unsigned int) (FLASH_BASE+psiStartAddr)); printk("fInfo->flash_persistent_start_blk = %d\n", fInfo->flash_persistent_start_blk); printk("fInfo->flash_persistent_number_blk = %d\n", fInfo->flash_persistent_number_blk); printk("fInfo->flash_persistent_length=0x%x\n", (unsigned int)fInfo->flash_persistent_length); printk("fInfo->flash_persistent_blk_offset = 0x%x\n\n", (unsigned int)fInfo->flash_persistent_blk_offset); printk("AuxFs.start_blk = %d\n",fAuxFsInfo.start_blk ); printk("AuxFs,number_blk = %d\n", fAuxFsInfo.number_blk); printk("AuxFs.total_len = 0x%x\n",fAuxFsInfo.total_len); printk("AuxFs.sect_size = 0x%x\n",fAuxFsInfo.sect_size); #endif }
static int flash_wait(WORD sector, int offset, UINT16 data) { volatile UINT16 *flashptr; /* flash window */ UINT16 d1,d2; UINT16 var=0x20; flashptr = (UINT16 *) flash_get_memptr(sector); if ( flashFamily == FLASH_SST) var=0x40; if (flashFamily == FLASH_AMD || flashFamily == FLASH_SST || flashFamily==FLASH_MXIC) { #if defined(_BCM96338_) || defined(CONFIG_BCM96338) /* If the word written does not yet compare, try for another 100ms. * This check is done for SST39VF800A. */ if(flashFamily == FLASH_SST){ /* If the word written does not yet compare, try for another 100ms. * This check is done for SST39VF800A. */ int i; for( i = 0; i < 10000; i++ ) { d1 = flashptr[offset/2]; if (d1 == data) return STATUS_READY; udelay(10);//CFI_USLEEP(10); } d1 = flashptr[offset/2]; if (d1 != data) { flash_command(FLASH_RESET, 0, 0, 0); return STATUS_TIMEOUT; } } else { do { d1 = flashptr[offset/2]; if (d1 == data) return STATUS_READY; } while (!(d1 & 0x20)); d1 = flashptr[offset/2]; } #else if(flashFamily == FLASH_SST) { // timeout error /* If the word written does not yet compare, try for another 100ms. * This check is done for SST39VF800A. */ DWORD i,cycles; if(flashPrg==0) cycles=357143; else cycles=143; for( i = 0; i < cycles; i++ ) { d1 = flashptr[offset/2]; if (d1 == data) { Delay_1_Micro_Seconds(); return STATUS_READY; } } d1 = flashptr[offset/2]; if (d1 != data) { flash_command(FLASH_RESET, 0, 0, 0); return STATUS_TIMEOUT; } } else if(flashFamily==FLASH_AMD) { do { d1 = *flashptr; /* read data */ d1 ^= *flashptr; /* read it again and see what toggled */ if (d1 == 0) /* no toggles, nothing's happening */ return STATUS_READY; } while (!(d1 & 0x20)); d1 = *flashptr; /* read data */ d1 ^= *flashptr; /* read it again and see what toggled */ if (d1 != 0) { flash_command(FLASH_RESET, 0, 0, 0); return STATUS_TIMEOUT; } } else if(flashFamily == FLASH_MXIC) { do { d2 = *flashptr; d2 ^= *flashptr; if(d2==0) // see what toggle { d1 = flashptr[offset/2]; //compare with input data if the same then output status ready signal if(d1==data) return STATUS_READY; } } while (!(*flashptr & 0x20)); d1 = flashptr[offset/2]; if (d1 != data) { flash_command(FLASH_RESET, 0, 0, 0); return STATUS_TIMEOUT; } } #endif } else if (flashFamily == FLASH_INTEL) { flashptr[0] = 0x70; /* Wait for completion */ while(!(*flashptr & 0x80)); if (*flashptr & 0x30) { flashptr[0] = 0x50; flash_command(FLASH_RESET, 0, 0, 0); return STATUS_TIMEOUT; } flashptr[0] = 0x50; flash_command(FLASH_RESET, 0, 0, 0); } return STATUS_READY; }
static void flash_command(int command, WORD sector, int offset, UINT16 data) { volatile UINT16 *flashptr; volatile UINT16 *flashbase; flashptr = (UINT16 *) flash_get_memptr(sector); flashbase = (UINT16 *) flash_get_memptr(0); switch (flashFamily) { case FLASH_UNDEFINED: /* These commands should work for AMD, Intel and SST flashes */ switch (command) { case FLASH_RESET: flashptr[0] = 0xF0; flashptr[0] = 0xFF; break; case FLASH_READ_ID: flashptr[0x5555] = 0xAA; /* unlock 1 */ flashptr[0x2AAA] = 0x55; /* unlock 2 */ flashptr[0x5555] = 0x90; break; case FLASH_CFIQUERY: flashbase[0x5555] = 0xAA; /* unlock 1 */ flashbase[0x2AAA] = 0x55; /* unlock 2 */ flashbase[0x5555] = 0x90; break; default: break; } break; case FLASH_AMD: //Pan.Liu AMD and MXIC share the same flash command case FLASH_MXIC: switch (command) { case FLASH_RESET: flashptr[0] = 0xF0; break; case FLASH_READ_ID: flashptr[0x555] = 0xAA; /* unlock 1 */ flashptr[0x2AA] = 0x55; /* unlock 2 */ flashptr[0x555] = 0x90; break; case FLASH_CFIQUERY: flashptr[0x55] = 0x98; break; case FLASH_UB: flashptr[0x555] = 0xAA; /* unlock 1 */ flashptr[0x2AA] = 0x55; /* unlock 2 */ flashptr[0x555] = 0x20; break; case FLASH_PROG: flashptr[0] = 0xA0; flashptr[offset/2] = data; break; case FLASH_UBRESET: flashptr[0] = 0x90; flashptr[0] = 0x00; break; case FLASH_SERASE: flashptr[0x555] = 0xAA; /* unlock 1 */ flashptr[0x2AA] = 0x55; /* unlock 2 */ flashptr[0x555] = 0x80; flashptr[0x555] = 0xAA; flashptr[0x2AA] = 0x55; flashptr[0] = 0x30; break; default: break; } break; case FLASH_INTEL: switch (command) { case FLASH_RESET: flashptr[0] = 0xFF; break; case FLASH_READ_ID: flashptr[0] = 0x90; break; case FLASH_CFIQUERY: flashptr[0] = 0x98; break; case FLASH_PROG: flashptr[0] = 0x40; flashptr[offset/2] = data; break; case FLASH_SERASE: flashptr[0] = 0x60; flashptr[0] = 0xD0; flashptr[0] = 0x20; flashptr[0] = 0xD0; break; default: break; } break; case FLASH_SST: switch (command) { case FLASH_RESET: flashbase[0x5555] = 0xAA; /* unlock 1 */ flashbase[0x2AAA] = 0x55; /* unlock 2 */ flashbase[0x5555] = 0xf0; break; case FLASH_READ_ID: flashbase[0x5555] = 0xAA; /* unlock 1 */ flashbase[0x2AAA] = 0x55; /* unlock 2 */ flashbase[0x5555] = 0x90; break; case FLASH_CFIQUERY: flashbase[0x5555] = 0xAA; /* unlock 1 */ flashbase[0x2AAA] = 0x55; /* unlock 2 */ flashbase[0x5555] = 0x98; break; case FLASH_UB: break; case FLASH_PROG: flashbase[0x5555] = 0xAA; /* unlock 1 */ flashbase[0x2AAA] = 0x55; /* unlock 2 */ flashbase[0x5555] = 0xa0; flashptr[offset/2] = data; flashPrg=1; break; case FLASH_UBRESET: break; case FLASH_SERASE: flashbase[0x5555] = 0xAA; /* unlock 1 */ flashbase[0x2AAA] = 0x55; /* unlock 2 */ flashbase[0x5555] = 0x80; flashbase[0x5555] = 0xAA; flashbase[0x2AAA] = 0x55; flashptr[0] = 0x30; flashPrg=0; break; default: break; } break; default: break; } }