diff options
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c')
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c new file mode 100755 index 0000000..cf38104 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c @@ -0,0 +1,629 @@ +/*************************************************************************** + * Broadcom Corp. Confidential + * Copyright 2001 Broadcom Corp. All Rights Reserved. + * + * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED + * SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. + * YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT + * SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. + * + *************************************************************************** + * File Name : bcm63xx_flash.c + * + * Description: This file contains the flash device driver for bcm63xx board. Very similar to + * board.c in linux development. + * + * Created on : 4/18/2002 seanl + * + ***************************************************************************/ + + +/* Includes. */ +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "bcm_map.h" +#include "bcm_hwdefs.h" +#include "dev_bcm63xx_flash.h" +#include "flash_api.h" +#include "boardparms.h" +#include "boardparms_voice.h" +#include "bcm63xx_util.h" + +//#define DEBUG_FLASH + +/* This driver determines the NVRAM and persistent storage flash address and + * length. + */ +/* Foxconn start jenny add for timeout */ +extern int NMRPKeepAlive(void); +extern int NMRPTFTPWaiting(void); +extern int g_nmrp_keepalive; +extern int nmrp_server_detected; +/* Foxconn end jenny add for timeout*/ + +static FLASH_ADDR_INFO fInfo; + +//************************************************************************************** +// Flash read/write and image downloading.. +//************************************************************************************** + +void kerSysFlashInit( void ) +{ + NVRAM_DATA nvramData; + + flash_init(); + + while ((readNvramData(&nvramData) != 0) || (BpSetBoardId(nvramData.szBoardId) != BP_SUCCESS)) + { + printf("\n*** Board is not initialized properly ***\n\n"); + //setBoardParam(); /* Bob removed to set default board parameters, 11/01/2010 */ + setDefaultBoardParam(); /* Bob added to set default board parameters, 11/01/2010 */ + } + + fInfo.flash_rootfs_start_offset = flash_get_sector_size(0); + if( fInfo.flash_rootfs_start_offset < FLASH_LENGTH_BOOT_ROM ) + fInfo.flash_rootfs_start_offset = FLASH_LENGTH_BOOT_ROM; + + flash_init_info(&nvramData, &fInfo); + +#if (INC_NAND_FLASH_DRIVER==1) + validateNandPartTbl(&nvramData); + + /* Check if spare area data contains non 0xff values after JFFS2 clean + * marker. Early version of this CFE driver filled bytes 8 - 11 with + * 0 which Linux does not like. + */ + { + extern int read_spare_data(int blk, unsigned char *buf, int bufsize); + + int blk_size = flash_get_sector_size(0) / 1024; + int blk_start = nvramData.ulNandPartOfsKb[NP_DATA] / blk_size; + unsigned char spare[64]; + + memset(spare, 0xff, sizeof(spare)); + if( read_spare_data(blk_start, spare, sizeof(spare)) == FLASH_API_OK ) + { + const int spare_len = 8; /* Linux JFFS2 spare area is 8 bytes */ + int i; + + for( i = spare_len; i < sizeof(spare); i++ ) + { + if( spare[i] != 0xff ) + { + printf("Data spare area is not correct, erasing psi\n"); + printf("%8.8lx %8.8lx %8.8lx %8.8lx\n", + *(unsigned long *) &spare[0],*(unsigned long *)&spare[4], + *(unsigned long *) &spare[8],*(unsigned long *)&spare[12]); + kerSysErasePsi(); + break; + } + } + } + } +#endif +} + +#if (INC_NAND_FLASH_DRIVER==1) || (INC_SPI_PROG_NAND==1) +/*********************************************************************** + * Function Name: validateNandPartTbl + * Description : Checks the NAND partition table fields in NVRAM data. + * If nay of the fields are not valid, new values are set. + * Returns : None. + ***********************************************************************/ +void validateNandPartTbl(PNVRAM_DATA pNvramData) +{ + unsigned long ulBlockSizeKb = (unsigned long)flash_get_sector_size(0)/1024; + unsigned long ulTotalSizeKb = (unsigned long)flash_get_total_size() / 1024; + +#if (INC_SPI_PROG_NAND==1) + if( flash_get_flash_type() != FLASH_IFC_NAND ) + return; +#endif + if( pNvramData->ulNandPartSizeKb[NP_BOOT] != ulBlockSizeKb || + pNvramData->ulNandPartSizeKb[NP_DATA] != NAND_DATA_SIZE_KB || + (pNvramData->ulNandPartSizeKb[NP_BBT] != NAND_BBT_SMALL_SIZE_KB && + pNvramData->ulNandPartSizeKb[NP_BBT] != NAND_BBT_BIG_SIZE_KB) ) + { + /* Initialize NAND flash partition table. */ + unsigned long ulRootfsSizeKb; + unsigned long ulBbtSizeKb = (ulTotalSizeKb > NAND_BBT_THRESHOLD_KB) + ? NAND_BBT_BIG_SIZE_KB : NAND_BBT_SMALL_SIZE_KB; + + /* The Boot partition is first and is one block in size. */ + pNvramData->ulNandPartOfsKb[NP_BOOT] = 0; + pNvramData->ulNandPartSizeKb[NP_BOOT] = ulBlockSizeKb; + + /* The Bad Block Table partition is last and is a constant size. */ + pNvramData->ulNandPartOfsKb[NP_BBT] = ulTotalSizeKb - ulBbtSizeKb; + pNvramData->ulNandPartSizeKb[NP_BBT] = ulBbtSizeKb; + + /* The Data partition is before the BBT and is a constant size. */ + pNvramData->ulNandPartOfsKb[NP_DATA] = + pNvramData->ulNandPartOfsKb[NP_BBT] - NAND_DATA_SIZE_KB; + pNvramData->ulNandPartSizeKb[NP_DATA] = NAND_DATA_SIZE_KB; + + /* The first rootfs partition starts at the second sector. */ + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1] = ulBlockSizeKb; + + /* The size of the two root file system partitions is whatever is left + * after the Boot, Data and BBT paritions divided by 2 and evenly + * divisible by the NAND flash block size. + */ + ulRootfsSizeKb = ((pNvramData->ulNandPartOfsKb[NP_DATA] - + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1]) / 2); + ulRootfsSizeKb = (ulRootfsSizeKb / ulBlockSizeKb) * ulBlockSizeKb; + +#if 1 /* support two file system partitions */ + pNvramData->ulNandPartSizeKb[NP_ROOTFS_1] = ulRootfsSizeKb; + + pNvramData->ulNandPartOfsKb[NP_ROOTFS_2] = + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1] + ulRootfsSizeKb; + pNvramData->ulNandPartSizeKb[NP_ROOTFS_2] = ulRootfsSizeKb; +#else /* support one file system partition */ + pNvramData->ulNandPartSizeKb[NP_ROOTFS_1] = ulRootfsSizeKb * 2; + + pNvramData->ulNandPartOfsKb[NP_ROOTFS_2] = ulTotalSizeKb; + pNvramData->ulNandPartSizeKb[NP_ROOTFS_2] = 0; +#endif + + writeNvramData(pNvramData); + +#if defined(DEBUG_FLASH) + printf("boot offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_BOOT], + pNvramData->ulNandPartSizeKb[NP_BOOT]); + printf("rootfs1 offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_ROOTFS_1], + pNvramData->ulNandPartSizeKb[NP_ROOTFS_1]); + printf("rootfs2 offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_ROOTFS_2], + pNvramData->ulNandPartSizeKb[NP_ROOTFS_2]); + printf("data offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_DATA], + pNvramData->ulNandPartSizeKb[NP_DATA]); + printf("bbt offset=0x%8.8lx, size=0x%8.8lx\n", + pNvramData->ulNandPartOfsKb[NP_BBT], + pNvramData->ulNandPartSizeKb[NP_BBT]); +#endif + } +} +#else +void validateNandPartTbl(PNVRAM_DATA pNvramData) +{ +} +#endif + + +/*********************************************************************** + * Function Name: kerSysFlashAddrInfoGet + * Description : Fills in a structure with information about the NVRAM + * and persistent storage sections of flash memory. + * Returns : None. + ***********************************************************************/ +void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info) +{ + memcpy(pflash_addr_info, &fInfo, sizeof(FLASH_ADDR_INFO)); +} + +// get shared blks into *** pTempBuf *** which has to be released bye the caller! +// return: if pTempBuf != NULL, poits to the data with the dataSize of the buffer +// !NULL -- ok +// NULL -- fail +static unsigned char *getSharedBlks(int start_blk, int num_blks) +{ + int i = 0; + int usedBlkSize = 0; + int sect_size = 0; + unsigned char *pTempBuf = NULL; + unsigned char *pBuf = NULL; + + for (i = start_blk; i < (start_blk + num_blks); i++) + usedBlkSize += flash_get_sector_size((unsigned short) i); + + if ((pTempBuf = (unsigned char *) KMALLOC(usedBlkSize, sizeof(long))) == NULL) + { + printf("failed to allocate memory with size: %d\n", usedBlkSize); + return pTempBuf; + } + + pBuf = pTempBuf; + for (i = start_blk; i < (start_blk + num_blks); i++) + { + sect_size = flash_get_sector_size((unsigned short) i); +#if defined(DEBUG_FLASH) + printf("getShareBlks: blk=%d, sect_size=%d\n", i, sect_size); +#endif + flash_read_buf((unsigned short)i, 0, pBuf, sect_size); + pBuf += sect_size; + } + + return pTempBuf; +} + + + +// Set the pTempBuf to flash from start_blk for num_blks +// return: +// 0 -- ok +// -1 -- fail +static int setSharedBlks(int start_blk, int num_blks, unsigned char *pTempBuf) +{ + int i = 0; + int sect_size = 0; + int sts = 0; + unsigned char *pBuf = pTempBuf; + + for (i = start_blk; i < (start_blk + num_blks); i++) + { + sect_size = flash_get_sector_size((unsigned short) i); + flash_sector_erase_int(i); + if (flash_write_buf(i, 0, pBuf, sect_size) != sect_size) + { + printf("Error writing flash sector %d.", i); + sts = -1; + break; + } + +#if defined(DEBUG_FLASH) + printf("setShareBlks: blk=%d, sect_size=%d\n", i, sect_size); +#endif + + pBuf += sect_size; + } + + return sts; +} + + + +/******************************************************************************* + * NVRAM functions + *******************************************************************************/ + +// get nvram data +// return: +// 0 - ok +// -1 - fail +int kerSysNvRamGet(unsigned char *string, int strLen, int offset) +{ + unsigned char *pBuf = NULL; + + if ((pBuf = getSharedBlks(NVRAM_SECTOR, 1)) == NULL) + return -1; + + // get string off the memory buffer + memcpy(string, (pBuf + NVRAM_DATA_OFFSET + offset), strLen); + + KFREE(pBuf); + + return 0; +} + + +// set nvram +// return: +// 0 - ok +// -1 - fail +int kerSysNvRamSet(unsigned char *string, int strLen, int offset) +{ + int sts = 0; + unsigned char *pBuf = NULL; + + if ((pBuf = getSharedBlks(NVRAM_SECTOR, 1)) == NULL) + return -1; + + // set string to the memory buffer + memcpy((pBuf + NVRAM_DATA_OFFSET + offset), string, strLen); + + if (setSharedBlks(NVRAM_SECTOR, 1, pBuf) != 0) + sts = -1; + + KFREE(pBuf); + + return sts; +} + +/*********************************************************************** + * Function Name: kerSysEraseNvRam + * Description : Erase the NVRAM storage section of flash memory. + * Returns : 1 -- ok, 0 -- fail + ***********************************************************************/ +int kerSysEraseNvRam(void) +{ + int sts = 1; + unsigned char *tempStorage = KMALLOC(NVRAM_LENGTH, sizeof(long)); + + // just write the whole buf with '0xff' to the flash + if (!tempStorage) + sts = 0; + else + { + memset(tempStorage, 0xff, NVRAM_LENGTH); + if (kerSysNvRamSet(tempStorage, NVRAM_LENGTH, 0) != 0) + sts = 0; + KFREE(tempStorage); + } + + return sts; +} + + +/******************************************************************************* + * PSI functions + *******************************************************************************/ + +#if (INC_NAND_FLASH_DRIVER!=1) +/** set psi while preserving any other data that might be sharing sectors with + * the psi, e.g. scratch pad. + * + * @param string (IN) buffer that holds the data to be written. + * @param strLen (IN) length of buffer. + * + * @return 0 if OK, -1 on failure. + */ +static int kerSysPsiSet(const unsigned char *string, int strLen) +{ + int sts = 0; + unsigned char *pBuf = NULL; + + if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk, + fInfo.flash_persistent_number_blk)) == NULL) + return -1; + + // set string to the memory buffer + memcpy((pBuf + fInfo.flash_persistent_blk_offset), string, strLen); + + if (setSharedBlks(fInfo.flash_persistent_start_blk, + fInfo.flash_persistent_number_blk, pBuf) != 0) + sts = -1; + + KFREE(pBuf); + + return sts; +} + +/** set backup psi + * + * Backup PSI does not share its sectors with anything else, so this + * function does not need to read first and write. Just write. + * This function expects the length of the buffer to be exactly the + * length of the entire PSI. + * + * @param string (IN) buffer that holds the data to be written. + * + * @return 0 if OK, -1 on failure. + */ +static int kerSysBackupPsiSet(const unsigned char *string) +{ + int sts = 0; + + if (setSharedBlks(fInfo.flash_backup_psi_start_blk, + fInfo.flash_backup_psi_number_blk, + (unsigned char *) string) != 0) + sts = -1; + + return sts; +} + +/*********************************************************************** + * Function Name: kerSysErasePsi + * Description : Erase the Psi storage section of flash memory. + * Returns : 1 -- ok, 0 -- fail + ***********************************************************************/ +int kerSysErasePsi(void) +{ + int sts = 1; + unsigned char *tempStorage; + + if (fInfo.flash_persistent_start_blk == 0) { + sts = 0; + } + else { + tempStorage = KMALLOC(fInfo.flash_persistent_length, sizeof(long)); + // just write the whole buf with '0xff' to the flash + if (!tempStorage) + sts = 0; + else + { + memset(tempStorage, 0xff, fInfo.flash_persistent_length); + if (kerSysPsiSet(tempStorage, fInfo.flash_persistent_length) != 0) + sts = 0; + + // Also erase backup psi if it is there + if (fInfo.flash_backup_psi_number_blk > 0) + { + if (kerSysBackupPsiSet(tempStorage) != 0) + sts = 0; + } + + KFREE(tempStorage); + } + } + return sts; +} +#else +int kerSysErasePsi(void) +{ + int sts = 1; + NVRAM_DATA nvramData; + + if( readNvramData(&nvramData) == 0 ) + { + int blk_size = flash_get_sector_size(0) / 1024; + int blk_start = nvramData.ulNandPartOfsKb[NP_DATA] / blk_size; + int total_blks = + blk_start + (nvramData.ulNandPartSizeKb[NP_DATA]) / blk_size; + + while( blk_start < total_blks ) + { + flash_sector_erase_int(blk_start); + blk_start++; + } + sts = 0; + } + + return(sts); +} +#endif + +// flash bcm image +// return: +// 0 - ok +// !0 - the sector number fail to be flashed (should not be 0) +int kerSysBcmImageSet( int flash_start_addr, unsigned char *string, int size, int fWholeImage) +{ + int sts; + int sect_size; + int blk_start; + // int savedSize = size; + int total_blks = flash_get_numsectors(); + + /* Foxconn add by Cliff Wang, 03/23/2010 */ + unsigned char *pTempBuf = NULL; + int savedBlkStart; + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + if( flash_get_flash_type() == FLASH_IFC_NAND ) + { + if( flash_start_addr == FLASH_BASE ) + total_blks = 1; + else + { + NVRAM_DATA nvramData; + + if( readNvramData(&nvramData) == 0 ) + { + sect_size = flash_get_sector_size(0); + int rootfs = + ((flash_start_addr - FLASH_BASE) / 1024 == + nvramData.ulNandPartOfsKb[NP_ROOTFS_2]) + ? NP_ROOTFS_2 : NP_ROOTFS_1; + + total_blks = (nvramData.ulNandPartOfsKb[rootfs] + + nvramData.ulNandPartSizeKb[rootfs]) / (sect_size/ 1024); + } + } + } + +#if defined(DEBUG_FLASH) + printf("kerSysBcmImageSet: flash_start_addr=0x%x string=%p len=%d wholeImage=%d\n", + flash_start_addr, string, size, fWholeImage); +#endif + + blk_start = flash_get_blk(flash_start_addr); + /* Foxconn add start by Cliff Wang, 03/23/2010 */ + savedBlkStart = blk_start; + if( blk_start < 0 ) + return( -1 ); + /* Foxconn add end by Cliff Wang, 03/23/2010 */ + + /* write image to flash memory */ + do + { + g_nmrp_keepalive = 1; /* Foxconn add by Cliff Wang, 03/23/2010 */ + + sect_size = flash_get_sector_size(blk_start); + +#if defined(DEBUG_FLASH) + printf("Image flashing on block: %d\n", blk_start); +#endif + + // share the blk with psi only when fWholeImage == 0 + // Foxconn modified by Silver Shih for burn board Id + if ((!fWholeImage && blk_start == fInfo.flash_persistent_start_blk) || (fWholeImage == 5)) + { + +#if 0 + if (size > (sect_size - fInfo.flash_persistent_length)) + { + printf("Image is too big\n"); + break; // image is too big. Can not overwrite to psi + } +#endif + + if ((pTempBuf = (unsigned char *) KMALLOC(sect_size, sizeof(long))) == NULL) + { + printf("Failed to allocate memory with size: %d\n", sect_size); + break; + } + flash_read_buf((unsigned short)blk_start, 0, pTempBuf, sect_size); + memcpy(pTempBuf, string, size); + flash_sector_erase_int(blk_start); // erase blk before flash + + + if (flash_write_buf(blk_start, 0, pTempBuf, sect_size) == sect_size) + size = 0; // break out and say all is ok + break; + } + + flash_sector_erase_int(blk_start); // erase blk before flash + + if (sect_size > size) + { + if (size & 1) + size++; + sect_size = size; + } + if (flash_write_buf(blk_start, 0, string, sect_size) != sect_size) { + if( flash_get_flash_type() != FLASH_IFC_NAND ) + break; + blk_start++; + } + else { + printf("."); + blk_start++; + string += sect_size; + size -= sect_size; + + /* Foxconn added start by jenny @NMRP */ + if(nmrp_server_detected==1) // in NMRP mode + { + if(blk_start - savedBlkStart == 30) + { + savedBlkStart = blk_start; + printf("\n"); + NMRPKeepAlive(); + } + } + /* Foxconn added end by jenny @NMRP */ + } + } while (size > 0); + g_nmrp_keepalive = 0; /* Foxconn added by jenny add for timeout */ + +#if 0 /* Foxconn removed by EricHuang */ + if (size == 0 && fWholeImage && savedSize > FLASH_LENGTH_BOOT_ROM) + { + // If flashing a whole image, erase to end of flash. + while( blk_start < total_blks ) + { + flash_sector_erase_int(blk_start); + printf("."); + blk_start++; + } + } +#endif + + printf("\n\n"); + + if( size == 0 ) + sts = 0; // ok + else + sts = blk_start; // failed to flash this sector + + g_nmrp_keepalive = 0; /* Foxconn jenny add for timeout */ + return sts; +} + +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); +} + |