/******************************************************************************* Copyright (C) Marvell International Ltd. and its affiliates ******************************************************************************** Marvell GPL License Option If you received this File from Marvell, you may opt to use, redistribute and/or modify this File in accordance with the terms and conditions of the General Public License Version 2, June 1991 (the "GPL License"), a copy of which is available along with the File in the license.txt file or by writing to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. The GPL License provides additional details about this warranty disclaimer. *******************************************************************************/ #include #include #include #if (CONFIG_COMMANDS & CFG_CMD_FLASH) #include #include "norflash/mvFlash.h" #include "device/mvDeviceRegs.h" #include "mvBoardEnvSpec.h" #include "mvOs.h" #include "mvCtrlEnvLib.h" #include "mvSysHwConfig.h" #include "mvCpuIf.h" #if defined (MV_INCLUDE_INTEG_MFLASH) #include "mvMFlash.h" #include "mvMFlashSpec.h" #include "mvSMFlash.h" #include "mvPMFlash.h" #endif #if defined (MV_INC_BOARD_SPI_FLASH) #include "sflash/mvSFlash.h" #endif /* #define MV_DEBUG */ #ifdef MV_DEBUG #define DB(x) x #else #define DB(x) #endif #define FLASH_ROM 0xFFFD /* unknown flash type */ #define FLASH_RAM 0xFFFE /* unknown flash type */ #define FLASH_MAN_UNKNOWN 0xFFFF0000 #define NL_HASHES_PER_LINE 65 #define CFI_CMDSET_INTEL_EXTENDED 1 #define CFI_CMDSET_AMD_STANDARD 2 #define CFI_CMDSET_INTEL_STANDARD 3 #define CFI_CMDSET_AMD_EXTENDED 4 void flashInfoCopy(flash_info_t *flash_info, MV_FLASH_INFO *pFlash); MV_U32 getMvFlashInfoNum(flash_info_t *flash_info); MV_FLASH_INFO* getMvFlashInfo(int index); int mv_flash_real_protect(flash_info_t *info, long sector, int prot); int mv_flash_real_protect_bank(flash_info_t *info, int prot); #if defined (MV_INCLUDE_INTEG_MFLASH) void mflash_print_info (MV_MFLASH_INFO * pInfo); unsigned long mflash_init (MV_MFLASH_INFO * mflInfo); #endif #if defined (MV_INC_BOARD_SPI_FLASH) void sflash_print_info (MV_SFLASH_INFO * pInfo); unsigned long sflash_init (MV_SFLASH_INFO * sflInfo); #endif /* use CFG_MAX_FLASH_BANKS_DETECT if defined */ #ifdef CFG_MAX_FLASH_BANKS_DETECT static MV_FLASH_INFO mvFlashInfo[CFG_MAX_FLASH_BANKS_DETECT]; extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS_DETECT]; /* FLASH chips info */ extern int mv_board_num_flash_banks; #else static MV_FLASH_INFO mvFlashInfo[CFG_MAX_FLASH_BANKS]; extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ #endif /* Static Variables */ #if defined (MV_INCLUDE_INTEG_MFLASH) static MV_MFLASH_INFO mflash; #endif #if defined (MV_INC_BOARD_SPI_FLASH) static MV_SFLASH_INFO sflash = {0x0, 0, 0, 0, 0, 0, MV_INVALID_DEVICE_NUMBER}; #endif static unsigned long norFlashBanksNum = 0; static unsigned long mFlashBanksNum = 0; static unsigned long sFlashBanksNum = 0; typedef enum { MV_UNKNOWN_FLASH = 0, MV_NOR_FLASH, MV_MARVELL_FLASH, MV_SPI_FLASH } MV_FLASH_TYPE; /* return NULL in case didn't find a matching mvFlashInfo */ MV_FLASH_INFO* getMvFlashInfo(int index) { if (CFG_MAX_FLASH_BANKS < index) return NULL; return &mvFlashInfo[index]; } /* based on index get the type of flash */ static MV_FLASH_TYPE mvFlashTypeFromIndexGet(MV_U32 indx) { if ((indx >= 0) && (indx < norFlashBanksNum)) return MV_NOR_FLASH; else if ((indx >= norFlashBanksNum) && \ (indx < (norFlashBanksNum + mFlashBanksNum))) return MV_MARVELL_FLASH; else if ((indx >= (norFlashBanksNum + mFlashBanksNum)) && (indx < (norFlashBanksNum + mFlashBanksNum + sFlashBanksNum))) return MV_SPI_FLASH; return MV_UNKNOWN_FLASH; } /* return 0xFFFFFFFF in case didn't find a matching mvFlashInfo */ MV_U32 getMvFlashInfoNum(flash_info_t * pFlash_info) { MV_U32 i; DB(mvOsPrintf("%s\n", __FUNCTION__)); if( pFlash_info->flash_id == FLASH_UNKNOWN ) { DB(printf("%s : ERROR didn't find mvFlashInfo matching to flash_info_t.\n", __FUNCTION__)); return 0xFFFFFFFF; } for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { if (&flash_info[i] == pFlash_info) { DB(printf("getMvFlashInfoNum found mvFlashInfo %d \n",i)); return i; } DB(mvOsPrintf(" %x %x \n",mvFlashBaseAddrGet(&mvFlashInfo[i]), mvFlashVenIdGet(&mvFlashInfo[i]))); } DB(mvOsPrintf("%s(%d): ERROR didn't find mvFlashInfo matching to flash_info_t.\n", __FUNCTION__)); return 0xFFFFFFFF; } /* make sure that #define CFG_FLASH_PROTECTION present in MV64xx.h */ int mv_flash_real_protect(flash_info_t *info, long sector, int prot) { MV_U32 s; s = getMvFlashInfoNum(info); if(s >= CFG_MAX_FLASH_BANKS) { DB(printf("mv_flash_real_protect illegal mvFlashInfo \n")); return 1; } switch(mvFlashTypeFromIndexGet(s)) { #if defined (MV_INC_BOARD_NOR_FLASH) case MV_NOR_FLASH: if( mvFlashSecLockSet(&mvFlashInfo[s],sector,prot) != MV_OK) return 1; /* Write was not completed */ info->protect[sector] = prot; break; #endif #if defined (MV_INCLUDE_INTEG_MFLASH) case MV_MARVELL_FLASH: /* printf("MFlash WP modification per sector is not supported by this command!!\n"); */ if(mv_flash_real_protect_bank(info, prot) != MV_OK) return 1; break; #endif #if defined (MV_INC_BOARD_SPI_FLASH) case MV_SPI_FLASH: /* printf("SPI Flash WP modification per sector is not supported by this command!!\n"); */ if(mv_flash_real_protect_bank(info, prot) != MV_OK) return 1; break; #endif default: return 1; } return 0; /* write completed succefully */ } int mv_flash_real_protect_bank(flash_info_t *info, int prot) { MV_U32 s; MV_U32 i; s = getMvFlashInfoNum(info); if(s >= CFG_MAX_FLASH_BANKS) { DB(printf("mv_flash_real_protect_bank illegal mvFlashInfo \n")); return 1; } switch(mvFlashTypeFromIndexGet(s)) { #if defined (MV_INC_BOARD_NOR_FLASH) case MV_NOR_FLASH: for (i=0; isector_count; ++i) { if( mvFlashSecLockSet(&mvFlashInfo[s],i,prot) != MV_OK) return 1; /* Write was not completed */ info->protect[i] = prot; putc ('.'); } break; #endif #if defined (MV_INCLUDE_INTEG_MFLASH) case MV_MARVELL_FLASH: if (mvMFlashWriteProtectSet(&mflash, prot) != MV_OK) return 1; for (i=0; isector_count; ++i) { info->protect[i] = prot; /* putc ('.'); if (((i+1)%64) == 0) printf("\n"); */ } break; #endif #if defined (MV_INC_BOARD_SPI_FLASH) case MV_SPI_FLASH: if (prot) { if (mvSFlashWpRegionSet(&sflash, MV_WP_ALL) != MV_OK) return 1; } else { if (mvSFlashWpRegionSet(&sflash, MV_WP_NONE) != MV_OK) return 1; } for (i=0; isector_count; ++i) { info->protect[i] = prot; putc ('.'); if (((i+1)%64) == 0) printf("\n"); } break; #endif default: return 1; } return 0; /* write completed succefully */ } /******************************************************************** * Copy global CFI info into Marvell FLash info ********************************************************************/ void flashMvInfoCopy(flash_info_t *flash_info, MV_FLASH_INFO *pFlash) { MV_U32 i; /* Check if flash_info containe CFI data */ if(mvFlashVenIdGet(pFlash) != FLASH_UNKNOWN) { return; } if(flash_info->flash_id == FLASH_UNKNOWN) { pFlash->flashSpec.flashVen = FLASH_UNKNOWN; return; } /* convert to MV_FLASH_INFO manufactor Id */ switch (flash_info->vendor) { case CFI_CMDSET_INTEL_STANDARD: case CFI_CMDSET_INTEL_EXTENDED: pFlash->flashSpec.flashVen = INTEL_MANUF; break; case CFI_CMDSET_AMD_STANDARD: case CFI_CMDSET_AMD_EXTENDED: pFlash->flashSpec.flashVen = AMD_MANUF; break; default: pFlash->flashSpec.flashVen = 0; break; } /* convert to MV_FLASH_INFO flash Id */ pFlash->flashSpec.flashId = (flash_info->flash_id & FLASH_TYPEMASK); /* other flash info parameters */ pFlash->flashSpec.size = (flash_info->size / (flash_info->portwidth / flash_info->chipwidth)); pFlash->flashSpec.sectorNum = flash_info->sector_count; pFlash->busWidth = flash_info->portwidth; pFlash->devWidth = flash_info->chipwidth; /* sectors parameters */ for(i = 0; i < flash_info->sector_count; i++) { pFlash->sector[i].baseOffs = flash_info->start[i] - flash_info->start[0]; pFlash->sector[i].protect = flash_info->protect[i]; if (i + 1 < flash_info->sector_count) pFlash->sector[i].size = flash_info->start[i+1] - flash_info->start[i]; else pFlash->sector[i].size = (flash_info->start[0] + flash_info->size) - flash_info->start[i]; } pFlash->baseAddr = flash_info->start[0]; return; } void flashInfoCopy(flash_info_t *flash_info, MV_FLASH_INFO *pFlash) { MV_U32 i; /* Check if flash_info containe CFI data */ if(flash_info->flash_id != FLASH_UNKNOWN) { return; } if(mvFlashVenIdGet(pFlash) == FLASH_UNKNOWN) { flash_info->flash_id = FLASH_UNKNOWN; return; } /* convert to U-Boot manufactor Id */ flash_info->flash_id = ((mvFlashVenIdGet(pFlash) << 16) & FLASH_VENDMASK); /* convert to U-Boot flash Id */ flash_info->flash_id |= (mvFlashDevIdGet(pFlash) & FLASH_TYPEMASK); /* other flash info parameters */ flash_info->size = mvFlashSizeGet(pFlash); flash_info->sector_count = mvFlashNumOfSecsGet(pFlash); flash_info->portwidth = mvFlashBusWidthGet(pFlash); flash_info->chipwidth = mvFlashDevWidthGet(pFlash); /* sectors parameters */ for(i = 0; i < mvFlashNumOfSecsGet(pFlash); i++) { flash_info->start[i] = mvFlashSecOffsGet(pFlash,i) + mvFlashBaseAddrGet(pFlash); flash_info->protect[i] = mvFlashSecLockGet(pFlash,i); } return; } #if defined (MV_INCLUDE_INTEG_MFLASH) void mflashInfoCopy(flash_info_t *flash_info, MV_MFLASH_INFO *pFlash) { MV_U32 i; MV_U32 mfId; MV_U16 devId; MV_BOOL wp; /* Check if the Model was detected during the init stage and read the WP status */ if ((pFlash->flashModel == MV_MFLASH_MODEL_UNKNOWN) || (mvMFlashIdGet(pFlash, &mfId, &devId) != MV_OK) || (mvMFlashWriteProtectGet(pFlash, &wp) != MV_OK)) { flash_info->flash_id = FLASH_UNKNOWN; return; } /* Discard the manufacturer ID and use the device ID alnoe because we lack 16 bits */ flash_info->flash_id = devId; /* other flash info parameters */ flash_info->size = (pFlash->sectorSize * pFlash->sectorNumber); flash_info->sector_count = pFlash->sectorNumber; flash_info->portwidth = 1; /* Assuming 8bit although that this parameter is not used */ flash_info->chipwidth = 1; /* Assuming 8bit although that this parameter is not used */ /* sectors parameters */ for(i = 0; i < pFlash->sectorNumber; i++) { flash_info->start[i] = (pFlash->baseAddr + (i * pFlash->sectorSize)); flash_info->protect[i] = wp; } return; } #endif /* #if defined (MV_INCLUDE_INTEG_MFLASH) */ #if defined (MV_INC_BOARD_SPI_FLASH) void sflashInfoCopy(flash_info_t *flash_info, MV_SFLASH_INFO *pFlash) { MV_U32 i; MV_SFLASH_WP_REGION wp; MV_BOOL wpVal; /* Check if the Model was detected during the init stage and read thw WP status */ if ((pFlash->manufacturerId == 0) || (mvSFlashWpRegionGet(pFlash, &wp) != MV_OK)) { flash_info->flash_id = FLASH_UNKNOWN; return; } /* Discard the manufacturer ID and use the device ID alnoe because we lack 16 bits */ flash_info->flash_id = ((pFlash->manufacturerId << 16) | pFlash->deviceId); /* other flash info parameters */ flash_info->size = (pFlash->sectorSize * pFlash->sectorNumber); flash_info->sector_count = pFlash->sectorNumber; flash_info->portwidth = 0; /* Serial interface */ flash_info->chipwidth = 0; /* Serial interface */ if (wp == MV_WP_ALL) wpVal = MV_TRUE; else wpVal = MV_FALSE; /* sectors parameters */ for(i = 0; i < pFlash->sectorNumber; i++) { flash_info->start[i] = (pFlash->baseAddr + (i * pFlash->sectorSize)); flash_info->protect[i] = wpVal; } return; } #endif unsigned long mvFlash_init (void) { MV_U32 i; unsigned long current_bank_size=0; unsigned long flash_size=0; #if defined (MV_INC_BOARD_SPI_FLASH) || defined (MV_INCLUDE_INTEG_MFLASH) MV_U32 bankIndx; #endif /* defined (MV_INC_BOARD_SPI_FLASH) || defined (MV_INCLUDE_INTEG_MFLASH) */ /* Init: no FLASHes known */ for (i=0; i CFG_MAX_FLASH_BANKS) { printf("%s ERROR: Number of flash devices exceeds the CFG_MAX_FLASH_BANKS=0x%x\n", __FUNCTION__,CFG_MAX_FLASH_BANKS); return 0; } for (i=0; i < norFlashBanksNum; ++i) { /* CFI driver detected the device */ if (flash_info[i].flash_id != FLASH_UNKNOWN) { printf("[%ldkB@%x] ", flash_info[i].size/1024, flash_info[i].start[0]); continue; } mvFlashInfo[i].baseAddr = mvBoardGetDeviceBaseAddr(i, BOARD_DEV_NOR_FLASH); DB(printf("mvFlashInfo[%d].baseAddr %x\n",i,mvFlashInfo[i].baseAddr);) mvFlashInfo[i].busWidth = mvBoardGetDeviceBusWidth(i, BOARD_DEV_NOR_FLASH)/8; DB(printf("mvFlashInfo[%d].busWidth %x\n",i,mvFlashInfo[i].busWidth);) mvFlashInfo[i].devWidth = mvBoardGetDeviceWidth(i, BOARD_DEV_NOR_FLASH)/8; DB(printf("mvFlashInfo[%d].devWidth %x\n",i,mvFlashInfo[i].devWidth);) if (mvFlashInfo[i].baseAddr == 0xffffffff) continue; current_bank_size = mvFlashInit(&mvFlashInfo[i]); flashInfoCopy(&flash_info[i], &mvFlashInfo[i]); printf("[%ldkB@%x] ", flash_info[i].size/1024, flash_info[i].start[0]); if (flash_info[i].flash_id == FLASH_UNKNOWN) { printf ("## Unknown FLASH at %08x: Size = 0x%08lx = %ld MB\n", mvFlashInfo[i].baseAddr, current_bank_size, current_bank_size<<20); } flash_size += current_bank_size; } /* Copy from CFI to MV_FLASH_INFO the CFI data */ for (i=0; i < norFlashBanksNum; ++i) flashMvInfoCopy(&flash_info[i], &mvFlashInfo[i]); #endif /* #if defined (MV_INC_BOARD_NOR_FLASH) */ #if defined (MV_INCLUDE_INTEG_MFLASH) #ifdef MV_INCLUDE_INTEG_MFLASH_SPI if (mvCtrlSpiBusModeSet(MV_SPI_CONN_TO_MFLASH) != MV_OK) { printf("Failed to set the SPI bus to the MFlash mode\n"); } #endif mflash.ifMode = MV_SPI_CONN_UNKNOWN; /* to be detected from H/W */ mflash.baseAddr = mvCpuIfTargetWinBaseLowGet(MFLASH_CS); mflash.flashModel = MV_MFLASH_MODEL_UNKNOWN; /* will be detected in init */ mflash.sectorSize = 0; /* will be detected in init */ mflash.sectorNumber = 0; /* will be detected in init */ mflash.infoSize = 0; /* will be detected in init */ /* Try to initialize the Marvell Flash - returns the size of flash detected */ if (mflash_init(&mflash) != 0) { /* update the number of Marvell flashes detected to be used in index calculation */ mFlashBanksNum = 1; DB(printf("Number of Marvell flashes on board %d\n", mFlashBanksNum);) /* check that we did not exceed the MAX flash banks supported */ if ((norFlashBanksNum + mFlashBanksNum) > CFG_MAX_FLASH_BANKS) { printf("%s ERROR: Number of flash devices exceeds the CFG_MAX_FLASH_BANKS\n", __FUNCTION__); return 0; } /* Set the default sector size to small - needed for saveenv in the UBoot */ if (mvMFlashSectorSizeSet(&mflash, MV_MFLASH_SECTOR_SIZE_SMALL) != MV_OK) { printf("%s ERROR: Failed to set MFlash sector size to SMALL\n", __FUNCTION__); return 0; } current_bank_size = (mflash.sectorSize * mflash.sectorNumber); bankIndx = norFlashBanksNum; mflashInfoCopy(&flash_info[bankIndx], &mflash); printf("[%ldkB@%x] ", current_bank_size/1024, mflash.baseAddr); if (mflash.flashModel == MV_MFLASH_MODEL_UNKNOWN) { printf ("## Unknown MFLASH at %08x: Size = 0x%08lx = %ld MB\n", mflash.baseAddr, current_bank_size, current_bank_size<<20); } flash_size += current_bank_size; } else { DB(printf("Failed to initialize the Marvell Flash!\n");) } #endif /* #if defined (MV_INCLUDE_INTEG_MFLASH) */ #if defined (MV_INC_BOARD_SPI_FLASH) sflash.baseAddr = mvCpuIfTargetWinBaseLowGet(SPI_CS); sflash.manufacturerId = 0; /* will be detected in init */ sflash.deviceId = 0; /* will be detected in init */ sflash.sectorSize = 0; /* will be detected in init */ sflash.sectorNumber = 0; /* will be detected in init */ sflash.pageSize = 0; /* will be detected in init */ sflash.index = MV_INVALID_DEVICE_NUMBER; /* will be detected in init */ /* Try to initialize an external SPI flash and retreive the size in case of success */ if ((current_bank_size = sflash_init(&sflash)) != 0) { /* update the number of SPI flashes detected to be used in index calculation */ sFlashBanksNum = 1; DB(printf("Number of SPI flashes on board %d\n", sFlashBanksNum);) /* check that we did not exceed the MAX flash banks supported */ if ((norFlashBanksNum + mFlashBanksNum + sFlashBanksNum) > CFG_MAX_FLASH_BANKS) { printf("%s ERROR: Number of flash devices exceeds the CFG_MAX_FLASH_BANKS\n", __FUNCTION__); return 0; } /* convert the SFlash structure into the Uboot structre */ bankIndx = (norFlashBanksNum + mFlashBanksNum); sflashInfoCopy(&flash_info[bankIndx], &sflash); printf("[%ldkB@%x] ", current_bank_size/1024, sflash.baseAddr); /* verify that the manufacturer Id was detected */ if (sflash.manufacturerId == 0) { printf ("## Unknown SFLASH at %08x: Size = 0x%08lx = %ld MB\n", sflash.baseAddr, current_bank_size, current_bank_size<<20); } flash_size += current_bank_size; } else { DB(printf("Failed to initialize the SPI Flash!\n");) } #endif /* #if defined (MV_INC_BOARD_SPI_FLASH) */ /* Set the write protection */ if (norFlashBanksNum >= 1) { flash_protect (FLAG_PROTECT_SET, CFG_MONITOR_BASE, CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1, &flash_info[0]); flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR,CFG_ENV_ADDR + CFG_ENV_SECT_SIZE, &flash_info[0]); } //modfiy by QNAP: protect off all SPI flash #if defined (MV_INC_BOARD_SPI_FLASH) if (mvSFlashWpRegionSet(&sflash, MV_WP_NONE) != 0) printf("\nIn mvFlash_init:Failed to set the write protection to NONE.\n"); #endif /////////// return flash_size; } /*----------------------------------------------------------------------- */ void mv_flash_print_info (flash_info_t *info) { MV_U32 s; s = getMvFlashInfoNum(info); if(s >= CFG_MAX_FLASH_BANKS) { printf("missing or unknown FLASH type\n"); return; } switch(mvFlashTypeFromIndexGet(s)) { #if defined (MV_INC_BOARD_NOR_FLASH) case MV_NOR_FLASH: flashPrint(&mvFlashInfo[s]); break; #endif #if defined (MV_INCLUDE_INTEG_MFLASH) case MV_MARVELL_FLASH: mflash_print_info(&mflash); break; #endif #if defined (MV_INC_BOARD_SPI_FLASH) case MV_SPI_FLASH: sflash_print_info(&sflash); break; #endif default: printf("Unknown flash type on selected bank!\n"); } return; } /*----------------------------------------------------------------------- */ int mv_flash_erase (flash_info_t *info, int s_first, int s_last) { MV_U32 i,s; MV_STATUS ret; #if defined (MV_INCLUDE_INTEG_MFLASH) MV_BOOL mvMFstatus; #endif #if defined (MV_INC_BOARD_SPI_FLASH) MV_SFLASH_WP_REGION mvSFstatus; #endif DB(printf("%s: sectors %d - %d \n", __FUNCTION__, s_first, s_last)); s = getMvFlashInfoNum(info); if(s >= CFG_MAX_FLASH_BANKS) { DB(printf("%s: illegal mvFlashInfo \n", __FUNCTION__)); return 1; } printf("\n"); for(i = s_first; i <= s_last; i++) { switch(mvFlashTypeFromIndexGet(s)) { #if defined (MV_INC_BOARD_NOR_FLASH) case MV_NOR_FLASH: DB(printf("%s: calling mvFlashSecErase sector %d, base=%x, sec=%x\n", __FUNCTION__, i,mvFlashInfo[s].baseAddr, mvFlashInfo[s].sector[i].baseOffs)); ret = mvFlashSecErase(&mvFlashInfo[s],i); break; #endif #if defined (MV_INCLUDE_INTEG_MFLASH) case MV_MARVELL_FLASH: DB(printf("%s: calling mvMFlashSecErase sector %d, base=%x, sec=%x\n", __FUNCTION__, i,mvFlashInfo[s].baseAddr, mvFlashInfo[s].sector[i].baseOffs)); /* Check protect on/off */ mvMFlashWriteProtectGet(&mflash,&mvMFstatus); if (mvMFstatus == MV_TRUE) { ret = MV_FAIL; break; } ret = mvMFlashSecErase(&mflash, i); break; #endif #if defined (MV_INC_BOARD_SPI_FLASH) case MV_SPI_FLASH: DB(printf("%s: calling mvSFlashSectorErase sector %d, base=%x, sec=%x\n", __FUNCTION__, i,mvFlashInfo[s].baseAddr, mvFlashInfo[s].sector[i].baseOffs)); /* Check protect on/off */ mvSFlashWpRegionGet (&sflash, &mvSFstatus); if (mvSFstatus == MV_WP_ALL) { ret = MV_FAIL; break; } ret = mvSFlashSectorErase(&sflash, i); break; #endif default: mv_flash_print_info(info); return 1; } if(ret != MV_OK) { printf("Erase fail!\n"); mv_flash_print_info(info); return 1; } putc ('.'); if (((i+1) % (NL_HASHES_PER_LINE)) == 0) { puts ("\n"); } } puts("\n"); return 0; } /*----------------------------------------------------------------------- * Copy memory to flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */ int mv_write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) { unsigned int s = 0; s = getMvFlashInfoNum(info); if(s >= CFG_MAX_FLASH_BANKS) { DB(printf("mv_write_buff illegal mvFlashInfo \n")); return 1; } switch(mvFlashTypeFromIndexGet(s)) { #if defined (MV_INC_BOARD_NOR_FLASH) char *env; case MV_NOR_FLASH: env = getenv("enaFlashBuf"); if(( (strcmp(env,"yes") == 0) || (strcmp(env,"Yes") == 0) )) { if( mvFlashBlockWr(&mvFlashInfo[s],addr - mvFlashBaseAddrGet(&mvFlashInfo[s]) ,cnt,src) != cnt) return 1; /* Write was not completed */ } else { if( mvFlashBlockUnbufWr(&mvFlashInfo[s],addr - mvFlashBaseAddrGet(&mvFlashInfo[s]) ,cnt,src) != cnt) return 1; /* Write was not completed */ } break; #endif #if defined (MV_INCLUDE_INTEG_MFLASH) case MV_MARVELL_FLASH: if (mvMFlashBlockWr(&mflash, (addr - mflash.baseAddr), cnt, src, MV_FALSE /* no compare */) != MV_OK) return 1; /* Write was not completed */ break; #endif #if defined (MV_INC_BOARD_SPI_FLASH) case MV_SPI_FLASH: if (mvSFlashBlockWr(&sflash, (addr - sflash.baseAddr), src, cnt) != MV_OK) return 1; /* Write was not completed */ break; #endif default: return 1; } return 0; /* write completed succefully */ } #if (defined (MV_INCLUDE_INTEG_MFLASH)|| defined (MV_INC_BOARD_SPI_FLASH)) /******************************************************************************* * rangeStrDecode - Decode a range string into 2 integers * * DESCRIPTION: * Decode a string indicating a range like M-N into 2 integers M and N. * ********************************************************************************/ static int rangeStrDecode (char * str, int * first, int * last, unsigned int sectNum) { char * sl, * ep; if ((sl = strchr (str, '-')) == NULL) /* a single sector */ { /* only a single bank is specified */ *first = simple_strtoul (str, &ep, 10); if ((ep == str) || (*ep != '\0') || (*first >= sectNum) || (*first < 0)) return -1; *last = *first; return 0; } else /* we have a complete range M-N */ { *sl++ = '\0'; *first = simple_strtoul (str, &ep, 10); if ((ep == str) || (*ep != '\0') || (*first >= sectNum) || (*first < 0)) return -1; *last = simple_strtoul (sl, &ep, 10); if ((ep == str) || (*ep != '\0') || (*last >= sectNum) || (*last < 0)) return -1; } if (*first > *last) return -1; return 0; } #endif /* (defined (MV_INCLUDE_INTEG_MFLASH)|| defined (MV_INC_BOARD_SPI_FLASH)) */ /*#############################################################################*/ /*#############################################################################*/ /*###################### MFLASH COMMANDS #############################*/ /*#############################################################################*/ /*#############################################################################*/ #if defined (MV_INCLUDE_INTEG_MFLASH) /******************************************************************************* * mflash_init - Detect and Initialize the Integrated Marvell Flash * * DESCRIPTION: * Try to detect the Marvell Flash integrated in the SOC. Based on the * model detected, determine the flash size * * INPUT: * None. * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ unsigned long mflash_init (MV_MFLASH_INFO * mflInfo) { /* based on the SPI mode try to detect the Mflash device interface type */ if (mvCtrlSpiBusModeDetect() == MV_SPI_CONN_TO_MFLASH) mflInfo->ifMode = MV_MFLASH_SPI; else mflInfo->ifMode = MV_MFLASH_PARALLEL; /* Try to detect the flash and initialize it over the IF deteced */ if (mvMFlashInit(mflInfo) != MV_OK) { printf("%s ERROR: MFlash init failed\n", __FUNCTION__); return 0; } return (mflInfo->sectorSize * mflInfo->sectorNumber); } /******************************************************************************* * mflash_print_info - Print the Marvell flash info * * DESCRIPTION: * Print the flash information of the specified instance * * INPUT: * pInfo: pointer to the instance flash information structure. * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ void mflash_print_info (MV_MFLASH_INFO * pInfo) { MV_U32 manf = 0; MV_U16 dev = 0; MV_BOOL wp; printf("\nFlash Base Address : 0x%08x",pInfo->baseAddr); if (pInfo->ifMode == MV_MFLASH_SPI) printf("\nFlash Mode : SPI"); else if (pInfo->ifMode == MV_MFLASH_PARALLEL) printf("\nFlash Mode : Parallel"); else printf("\nFlash Mode : Unknown"); if (pInfo->flashModel != 0) printf("\nFlash Model : SUNOL %d",(MV_U32)pInfo->flashModel); else printf("\nFlash Model : Unknown"); printf("\nSector Size : %dK", (pInfo->sectorSize / 1024)); printf("\nNumber of sectors : %d", pInfo->sectorNumber); /* Get the Flash ID from the chip */ if (mvMFlashIdGet(pInfo, &manf, &dev) != MV_OK) { printf("\n\nFailed to get the Manufacturer and Device IDs!\n"); return; } /* Get the WP status from the chip */ if (mvMFlashWriteProtectGet(pInfo, &wp) != MV_OK) { printf("\n\nFailed to get the WP status!\n"); return; } printf("\nManufacturer ID : %08x", manf); printf("\nDevice ID : %03x", (dev >> 4)); printf("\nDevice Revision : %01x", (dev & 0xF)); if (wp) printf("\nWrite Protection : Enabled"); else printf("\nWrite Protection : Disabled"); printf("\n\n"); } /******************************************************************************* * mflash_erase - Erase a set of sectors * * DESCRIPTION: * Erase a set of sectors in the main flash region. * * INPUT: * pInfo: pointer to the instance flash information structure. * s_first: first sector to erase. * s_last: last sector to erase. * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ int mflash_erase (MV_MFLASH_INFO *pInfo, MV_U32 s_first, MV_U32 s_last) { MV_U32 i; for (i=s_first; i<=s_last; i++) { /* perform the erase in serial mode */ if (mvMFlashSecErase(pInfo, i) != MV_OK) return 1; } return 0; } /******************************************************************************* * mflash_cmd - mflash command implimentation * * DESCRIPTION: * parse and decode the mflash command * * INPUT: * cmdtp: command table pointer * flag: flags * argc: command argument count * argv: command argument vector * * OUTPUT: * None. * * RETURN: * Success or Error code. * *******************************************************************************/ int mflash_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int first, last; MV_U32 source, offset, size, dest; MV_BOOL verify; char * cp; if (mFlashBanksNum < 1) { printf ("No Marvell Flash detected!\n"); return 1; } if (argc < 2) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (strcmp(argv[1], "info") == 0) { /* check that we have the correct number of parameters */ if (argc != 2) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } mflash_print_info(&mflash); } else if (strcmp(argv[1], "protect") == 0) { /* check that we have the correct number of parameters */ if (argc != 3) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (strcmp(argv[2], "on") == 0) /* the whole chip */ { if (mvMFlashWriteProtectSet(&mflash, MV_TRUE) != 0) printf("\nFailed to enable write protection!\n"); } else if (strcmp(argv[2], "off") == 0) /* the whole chip */ { if (mvMFlashWriteProtectSet(&mflash, MV_FALSE) != 0) printf("\nFailed to disable write protection!\n"); } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } } else if (strcmp(argv[1], "sector") == 0) { MV_U32 i,j; /* check that we have the correct number of parameters */ if (argc != 3) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (strcmp(argv[2], "small") == 0) /* the whole chip */ { if (mvMFlashSectorSizeSet(&mflash, 0x1000) != 0) { printf("\nFailed to enable write protection!\n"); return 1; } } else if (strcmp(argv[2], "large") == 0) /* the whole chip */ { if (mvMFlashSectorSizeSet(&mflash, 0x8000) != 0) { printf("\nFailed to disable write protection!\n"); return 1; } } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } /* Find the Mflash entry and update the sector count and protection status */ for (i=0; iusage); return 1; } if (strcmp(argv[2], "chip") == 0) /* the whole chip */ { if (mvMFlashChipErase(&mflash) != 0) printf("\nFailed to erase the whole MFlash chip.\n", first, last); } else if (strcmp(argv[2], "main") == 0) /* only the main region */ { if (mvMFlashMainErase(&mflash) != 0) printf("\nFailed to erase the main region.\n", first, last); } else if (strcmp(argv[2], "info") == 0) /* ony the information region */ { if (mvMFlashInfErase(&mflash) != 0) printf("\nFailed to erase the information region\n", first, last); } else /* check if a range of sectors is specified */ { if (rangeStrDecode(argv[2], &first, &last, mflash.sectorNumber) == 0) { if (mflash_erase(&mflash, first, last) != 0) printf("\nFailed to erase sectors %d-%d\n", first, last); } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } } } else if (strcmp(argv[1], "read") == 0) { /* check that we have the correct number of parameters */ if (argc != 6) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } offset = simple_strtoul (argv[3], &cp, 16); if ((cp == argv[3]) || (*cp != '\0') || (offset < 0)) { printf ("Invalid offset."); return 1; } dest = simple_strtoul (argv[4], &cp, 16); if ((cp == argv[4]) || (*cp != '\0') || (size < 0)) { printf ("Invalid dest."); return 1; } size = simple_strtoul (argv[5], &cp, 16); if ((cp == argv[5]) || (*cp != '\0') || (size < 0)) { printf ("Invalid size."); return 1; } if (strcmp(argv[2], "main") == 0) /* ony the information region */ { if (mvMFlashBlockRd(&mflash, offset, size, (MV_U8*) dest) != MV_OK) printf ("Failed to read from the MFlash main region!\n"); } else if (strcmp(argv[2], "info") == 0) /* ony the information region */ { if (mvMFlashBlockInfRd(&mflash, offset, size, (MV_U8*) dest) != MV_OK) printf ("Failed to read from the MFlash information region!\n"); } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } } else if (strcmp(argv[1], "write") == 0) { /* check that we have the correct number of parameters */ if ((argc != 6) && (argc != 7)) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } source = simple_strtoul (argv[3], &cp, 16); if ((cp == argv[3]) || (*cp != '\0') || (source < 0)) { printf ("Invalid size!\n"); return 1; } offset = simple_strtoul (argv[4], &cp, 16); if ((cp == argv[4]) || (*cp != '\0') || (offset < 0)) { printf ("Invalid offset!\n"); return 1; } size = simple_strtoul (argv[5], &cp, 16); if ((cp == argv[5]) || (*cp != '\0') || (size < 0)) { printf ("Invalid size!\n"); return 1; } /* check if the verify flag was used */ if (argc == 7) { if (strcmp(argv[6], "verify") != 0) { printf("Invalid verify flag!\n"); return 1; } verify = MV_TRUE; } else verify = MV_FALSE; if (strcmp(argv[2], "main") == 0) /* ony the information region */ { if (mvMFlashBlockWr(&mflash,offset, size, (MV_U8*) source, verify) != MV_OK) { printf ("Failed to write to the MFlash main region!\n"); return 1; } } else if (strcmp(argv[2], "info") == 0) /* ony the information region */ { if (mvMFlashInfBlockWr(&mflash,offset, size, (MV_U8*) source, verify) != MV_OK) { printf ("Failed to write to the MFlash information region!\n"); return 1; } } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } return 1; } /*U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)*/ U_BOOT_CMD( mflash, 8, 1, mflash_cmd, "mflash\t- read, write or erase the Marvell Flash.\n", "info\n - Retreive the Marvell flash infomation.\n" "mflash protect \n - Enable or disable write protect over the whole MFlash chip.\n" "mflash sector \n - Set the sector size to small (4K).\n" "mflash erase \n - Erase the whole chip, main or information region.\n" "mflash erase SF[-SL]\n - Erase (set back to 0xFF) sectors SF-SL in main region.\n" "mflash read
offset dest size\n - Read data from the main or info region into the destination address.\n" "mflash write
source offset size [verify]\n - Write a buffer into the main or information region.\n" ); #endif /* #if defined (MV_INCLUDE_INTEG_MFLASH) */ /*#############################################################################*/ /*#############################################################################*/ /*###################### SFLASH COMMANDS #############################*/ /*#############################################################################*/ /*#############################################################################*/ #if defined (MV_INC_BOARD_SPI_FLASH) /******************************************************************************* * sflash_init - Detect and Initialize an external SPI flash device * * DESCRIPTION: * Try to detect the SPI Flash. Based on the model detected, determine * the flash size. * * INPUT: * None. * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ unsigned long sflash_init (MV_SFLASH_INFO * sflInfo) { #if (defined (MV_INCLUDE_SPI) && defined (MV_INCLUDE_INTEG_MFLASH)) /* First check that SIP mode is configured */ if (mvCtrlSpiBusModeDetect() != MV_SPI_CONN_TO_EXT_FLASH) { mvOsPrintf("%s ERROR: SPI interface is not routed to external SPI flash!\n", __FUNCTION__); return 0; } #endif /* Try to detect the flash and initialize it over SPI */ if (mvSFlashInit(sflInfo) != MV_OK) { mvOsPrintf("%s ERROR: SFlash init falied!\n", __FUNCTION__); return 0; } /* return the size of the detected SFLash */ return (mvSFlashSizeGet(sflInfo)); } /******************************************************************************* * sflash_print_info - Print the SPI flash info * * DESCRIPTION: * Print the flash information of the specified instance * * INPUT: * pInfo: pointer to the instance flash information structure. * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ void sflash_print_info (MV_SFLASH_INFO * pInfo) { MV_SFLASH_WP_REGION wp; printf("\nFlash Base Address : 0x%08x", pInfo->baseAddr); printf("\nFlash Model : %s", mvSFlashModelGet(pInfo)); printf("\nManufacturer ID : 0x%02x", pInfo->manufacturerId); printf("\nDevice Id : 0x%04x", pInfo->deviceId); printf("\nSector Size : %dK", (pInfo->sectorSize / 1024)); printf("\nNumber of sectors : %d", pInfo->sectorNumber); printf("\nPage Size : %d", pInfo->pageSize); if (mvSFlashWpRegionGet(pInfo, &wp) != MV_OK) { DB(mvOsPrintf("%s WARNING: Failed to get write protect mode!\n", __FUNCTION__);) printf("\nWrite Protection : UNKNOWN"); } else { switch (wp) { case MV_WP_NONE: printf("\nWrite Protection : Off"); break; case MV_WP_UPR_1OF64: printf("\nWrite Protection : Upper 1 of 64"); break; case MV_WP_UPR_1OF32: printf("\nWrite Protection : Upper 1 of 32"); break; case MV_WP_UPR_1OF16: printf("\nWrite Protection : Upper 1 of 16"); break; case MV_WP_UPR_1OF8: printf("\nWrite Protection : Upper 1 of 8"); break; case MV_WP_UPR_1OF4: printf("\nWrite Protection : Upper 1 of 4"); break; case MV_WP_UPR_1OF2: printf("\nWrite Protection : Upper 1 of 2"); break; case MV_WP_ALL: printf("\nWrite Protection : All"); break; default: DB(mvOsPrintf("%s WARNING: Invalid Write protect mode!\n", __FUNCTION__);) printf("\nWrite Protection : UNKNOWN"); break; } } printf("\n\n"); } /******************************************************************************* * sflash_erase - Erase a set of sectors * * DESCRIPTION: * Erase a set of sectors in the SPI flash * * INPUT: * pInfo: pointer to the instance flash information structure. * s_first: first sector to erase. * s_last: last sector to erase. * * OUTPUT: * None. * * RETURN: * Success or Error code. * * *******************************************************************************/ int sflash_erase (MV_SFLASH_INFO *pInfo, MV_U32 s_first, MV_U32 s_last) { MV_U32 i; for (i=s_first; i<=s_last; i++) { /* perform the erase in serial mode */ if (mvSFlashSectorErase(pInfo, i) != MV_OK) { DB(mvOsPrintf("%s WARNING: Failed to erase sector %d in SFlash %s!\n", \ __FUNCTION__, i, mvSFlashModelGet(pInfo));) return 1; } mvOsDelay(10); // add for fix "Error: sflash_erase - mvSFlashSectorErase on sector 199" from Tom's advice, wait 10 ms } return 0; } /***********************************************************************/ /************************ U-Boot Commands ******************************/ /***********************************************************************/ /******************************************************************************* * sflash_cmd - sflash command implimentation * * DESCRIPTION: * parse and decode the sflash command * * INPUT: * cmdtp: command table pointer * flag: flags * argc: command argument count * argv: command argument vector * * OUTPUT: * None. * * RETURN: * Success or Error code. * *******************************************************************************/ int sflash_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int first, last; MV_U32 source, offset, size, dest; char * cp; if (sFlashBanksNum < 1) { printf ("No SPI Flash detected!\n"); return 1; } if (argc < 2) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (strcmp(argv[1], "info") == 0) { /* check that we have the correct number of parameters */ if (argc != 2) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } sflash_print_info(&sflash); } else if (strcmp(argv[1], "protect") == 0) { /* check that we have the correct number of parameters */ if (argc != 3) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (strcmp(argv[2], "off") == 0) { if (mvSFlashWpRegionSet(&sflash, MV_WP_NONE) != 0) printf("\nFailed to set the write protection to NONE.\n", first, last); } else if (strcmp(argv[2], "on") == 0) { if (mvSFlashWpRegionSet(&sflash, MV_WP_ALL) != 0) printf("\nFailed to set the write protection to ALL.\n", first, last); } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } } else if (strcmp(argv[1], "erase") == 0) /* erase command */ { /* check that we have the correct number of parameters */ if (argc != 3) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (strcmp(argv[2], "all") == 0) /* the whole chip */ { if (mvSFlashChipErase(&sflash) != 0) printf("\nFailed to erase the whole SPI flash chip.\n", first, last); } else /* check if a range of sectors is specified */ { if (rangeStrDecode(argv[2], &first, &last, sflash.sectorNumber) == 0) { if (sflash_erase(&sflash, first, last) != 0) printf("\nFailed to erase sectors %d-%d\n", first, last); } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } } } else if (strcmp(argv[1], "read") == 0) { /* check that we have the correct number of parameters */ if (argc != 5) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } offset = simple_strtoul (argv[2], &cp, 16); if ((cp == argv[2]) || (*cp != '\0') || (offset < 0)) { printf ("Invalid offset."); return 1; } dest = simple_strtoul (argv[3], &cp, 16); if ((cp == argv[3]) || (*cp != '\0') || (size < 0)) { printf ("Invalid size."); return 1; } size = simple_strtoul (argv[4], &cp, 16); if ((cp == argv[4]) || (*cp != '\0') || (size < 0)) { printf ("Invalid size."); return 1; } if (mvSFlashBlockRd(&sflash, offset, (MV_U8*)dest, size) != MV_OK) { printf ("Failed to read from the SPI flash!\n"); return 1; } } else if (strcmp(argv[1], "write") == 0) { /* check that we have the correct number of parameters */ if (argc != 5) { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } source = simple_strtoul (argv[2], &cp, 16); if ((cp == argv[2]) || (*cp != '\0') || (source < 0)) { printf ("Invalid size."); return 1; } offset = simple_strtoul (argv[3], &cp, 16); if ((cp == argv[3]) || (*cp != '\0') || (offset < 0)) { printf ("Invalid offset."); return 1; } size = simple_strtoul (argv[4], &cp, 16); if ((cp == argv[4]) || (*cp != '\0') || (size < 0)) { printf ("Invalid size!\n"); return 1; } if (mvSFlashBlockWr(&sflash, offset, (MV_U8*) source, size) != MV_OK) { printf ("Failed to write to the SPI flash!\n"); return 1; } } else { printf ("Usage:\n%s\n", cmdtp->usage); return 1; } return 1; } /*U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)*/ U_BOOT_CMD( sflash, 6, 1, sflash_cmd, "sflash\t- read, write or erase the external SPI Flash.\n", "info\n - Retreive the SPI flash infomation.\n" "sflash protect \n - Enable or diasble write protection over the whole SPI flash.\n" "sflash erase all \n - Erase (set back to 0xFF) the whole chip.\n" "sflash erase SF[-SL]\n - Erase (set back to 0xFF) sectors SF-SL.\n" "sflash read offset dest size\n - Read data from the flash into the destination address.\n" "sflash write source offset size\n - Program a buffer from the source address into the flash offset (size in bytes).\n" ); #endif #endif /* #if (CONFIG_COMMANDS & CFG_CMD_FLASH) */