summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c')
-rwxr-xr-xcfe/cfe/arch/mips/board/bcm63xx_ram/src/dev_bcm63xx_flash.c629
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);
+}
+