ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/obm/Common/Flash/NAND/nand.c b/marvell/obm/Common/Flash/NAND/nand.c
new file mode 100644
index 0000000..be76604
--- /dev/null
+++ b/marvell/obm/Common/Flash/NAND/nand.c
@@ -0,0 +1,365 @@
+/******************************************************************************
+**
+** COPYRIGHT (C) 2002, 2003 Intel Corporation.
+**
+** This software as well as the software described in it is furnished under
+** license and may only be used or copied in accordance with the terms of the
+** license. The information in this file is furnished for informational use
+** only, is subject to change without notice, and should not be construed as
+** a commitment by Intel Corporation. Intel Corporation assumes no
+** responsibility or liability for any errors or inaccuracies that may appear
+** in this document or any software that may be provided in association with
+** this document.
+** Except as permitted by such license, no part of this document may be
+** reproduced, stored in a retrieval system, or transmitted in any form or by
+** any means without the express written consent of Intel Corporation.
+**
+** FILENAME: Flash.c
+**
+** PURPOSE: Contain template OEM boot code flash operations
+**
+******************************************************************************/
+
+#include "Flash.h"
+#include "nand.h"
+#include "general.h"
+#include "xllp_dfc.h"
+#include "FM.h"
+#include "ProtocolManager.h"
+#if COPYIMAGESTOFLASH
+#include "BootLoader.h"
+#endif
+#if USE_DMA
+#include "xllp_dmac.h"
+#endif
+#include "dma.h"
+#include "BBM.h"
+
+NAND_Properties_T NAND_Prop; // Only need one
+extern UINT_T NandID;
+extern UINT_T nand_data_dma, nand_cmd_dma;
+
+P_NAND_Properties_T GetNANDProperties(void)
+{
+ return &NAND_Prop;
+}
+
+UINT_T GetSpareAreaSize(FlashBootType_T fbt)
+{
+ return GetNANDProperties()->SpareAreaSize;
+}
+
+UINT_T GetBlockSize(FlashBootType_T fbt)
+{
+ return GetNANDProperties()->BlockSize;
+}
+
+UINT_T GetPageSize(FlashBootType_T fbt)
+{
+ return GetNANDProperties()->PageSize;
+}
+
+/*
+ * Function initializes NAND device and fills out Flash Properties Struct
+ */
+
+UINT_T InitializeNANDDevice(UINT8_T FlashNum, FlashBootType_T FlashBootType, UINT8_T* P_DefaultPartitionNum)
+{
+ UINT_T Retval = NoError;
+ P_NAND_Properties_T pNandP = GetNANDProperties();
+ P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
+ // Set Current FlashBootType so XllpDfcInit can determine why it is called.
+ SetCurrentFlashBootType(FlashBootType);
+
+ // Pick correct bus width and set the ECC type
+ switch (FlashNum)
+ {
+ case NAND_FLASH_X16_HM_P:
+ pNandP->FlashBusWidth = FlashBusWidth16;
+ pNandP->ECCMode = ECC_HAMMING;
+ break;
+ case NAND_FLASH_X16_BCH_P:
+ pNandP->FlashBusWidth = FlashBusWidth16;
+ pNandP->ECCMode = ECC_BCH;
+ break;
+ case NAND_FLASH_X8_HM_P:
+ pNandP->FlashBusWidth = FlashBusWidth8;
+ pNandP->ECCMode = ECC_HAMMING;
+ break;
+ case NAND_FLASH_X8_BCH_P:
+ pNandP->FlashBusWidth = FlashBusWidth8;
+ pNandP->ECCMode = ECC_BCH;
+ break;
+ default:
+ return DFCInitFailed;
+ }
+
+ PlatformNandClocksEnable();
+
+ Retval = XllpDfcInit(pNandP->FlashBusWidth, pNandP);
+
+ if (Retval != NoError)
+ //return DFCInitFailed;
+ return NANDNotFound;
+
+ //set ECC with the correct ECCMode
+ xdfc_enable_ecc( 1 );
+ //define functions
+ pFlashP->ReadFromFlash = &ReadNAND;
+ pFlashP->WriteToFlash = &WriteNAND;
+ pFlashP->EraseFlash = &EraseNAND;
+ pFlashP->ResetFlash = &ResetNAND;
+ pFlashP->BlockSize = pNandP->BlockSize;
+ pFlashP->PageSize = pNandP->PageSize;
+ pFlashP->NumBlocks = pNandP->NumOfBlocks;
+ pFlashP->FlashSettings.UseBBM = 1;
+ pFlashP->FlashSettings.UseSpareArea = 0;
+ pFlashP->FlashSettings.SASize = 0;
+ pFlashP->FlashSettings.UseHwEcc = 1; // default is HW ECC ON
+ pFlashP->FlashType = NAND_FLASH;
+ pFlashP->GenerateFBBT = GenerateFBBTNAND;
+ // init the TIM load address
+ //---------------------------------------
+ pFlashP->TimFlashAddress = TIMOffset_NAND;
+ pFlashP->StreamingFlash = FALSE;
+ *P_DefaultPartitionNum = NAND_DEFAULT_PART;
+ pFlashP->FinalizeFlash = NULL;
+
+ NandID = (pNandP->FlashID << 8) | pNandP->ManufacturerCode;
+
+ GetDMAReqNum(&nand_data_dma, &nand_cmd_dma);
+
+ return Retval;
+}
+
+UINT_T GetDMAReqNum(UINT_T *data, UINT_T *cmd)
+{
+ UINT_T NAND_DMA_DataReqNum = DMAC_NAND_DATA;
+ UINT_T NAND_DMA_CMDReqNum = DMAC_NAND_CMD;
+
+#if NZA3
+ switch (PlatformGetRevisionID())
+ {
+ case 0xF0:
+ case 0xF2:
+ NAND_DMA_DataReqNum = DMAC_NAND_DATA_Z2;
+ NAND_DMA_CMDReqNum = DMAC_NAND_CMD_Z2;
+ break;
+
+ case 0xF3:
+ default:
+ break;
+ }
+#endif
+
+ *data = NAND_DMA_DataReqNum;
+ *cmd = NAND_DMA_CMDReqNum;
+}
+
+/*
+ This routine will read in data from the DFC.
+*/
+ #if !SHRINK_BINARY_SIZE
+UINT_T ReadNAND_nonDMA(UINT_T Address, UINT_T Destination, UINT_T ReadAmount, FlashBootType_T FlashBootType)
+{
+ P_NAND_Properties_T pNAND_Prop;
+ pNAND_Prop = GetNANDProperties();
+
+ UINT_T temp_buffer[2]; // temp use, no data needed
+
+ // For monolithic operation call legacy read routine
+ if (pNAND_Prop->PageSize <= TWO_KB)
+ {
+ if (upload_nand_spare == TRUE)
+ {
+ return xdfc_read_nonDMA((UINT_T *)Destination, Address, ReadAmount, temp_buffer, pNAND_Prop);
+ }
+ else
+ {
+ return xdfc_read_nonDMA((UINT_T *)Destination, Address, ReadAmount, NULL, pNAND_Prop);
+ }
+ }
+ else{ // Call the new routine that reads page at a time.
+#if NAND_LP
+ return xdfc_read_LP((UINT_T *)Destination, Address, ReadAmount, NULL, pNAND_Prop);
+#else
+ return NoError;
+#endif
+ }
+}
+ #endif
+
+UINT_T ReadNAND (UINT_T Address, UINT_T Destination, UINT_T ReadAmount, FlashBootType_T FlashBootType)
+{
+ return xdfc_read(Destination, Address, ReadAmount, NULL, GetNANDProperties());
+}
+
+/*
+ WriteNAND - This function is a wrapper to work with DFC
+ */
+
+UINT_T WriteNAND (UINT_T flash_addr, UINT_T source, UINT_T WriteAmount, FlashBootType_T FlashBootType)
+{
+ UINT_T Retval = NoError;
+ P_NAND_Properties_T pNandP = GetNANDProperties();
+ P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
+ if (pNandP->PageSize <= TWO_KB)
+ {
+ Retval = xdfc_write((UINT_T *) source,
+ flash_addr,
+ WriteAmount,
+ pFlashP->FlashSettings.UseSpareArea,
+ pFlashP->FlashSettings.UseHwEcc,
+ pNandP);
+ }
+ else
+ {
+#if NAND_LP
+ Retval = xdfc_write_LP((UINT_T *) source,
+ flash_addr,
+ WriteAmount,
+ pFlashP->FlashSettings.UseSpareArea,
+ pNandP);
+#endif
+ }
+ return Retval; // Return value
+}
+
+/*
+ *
+ * Erases one block at a time
+ * note: if user inputs determine that a partial block should be erased,
+ * this function will erase that WHOLE block: no partial blocks allowed
+ *
+ */
+UINT_T EraseNAND (UINT_T flashoffset, UINT_T size, FlashBootType_T fbt)
+{
+ return xdfc_erase(flashoffset, GetNANDProperties());
+}
+
+//Wrapper to link the dfc reset routine to the flash API
+UINT_T ResetNAND(FlashBootType_T fbt)
+{
+ return xdfc_reset(GetNANDProperties());
+}
+
+static UINT8_T page_buffer[2048]; //temp buffer to read dummy
+UINT_T GenerateFBBTNAND(UINT16 *badblocklist)
+{
+ unsigned int Retval, SA, i, j, temp, max, zero = 0, badblocks = 0;
+ unsigned int PageSize, BlockSize, block_good;
+ unsigned int *pRB0, *pRB1;
+ P_NAND_Properties_T pNandP = GetNANDProperties();
+ P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
+ UINT_T bUseHwEcc = FALSE;
+ unsigned int *dumy_buf = page_buffer;
+ unsigned char *ptemp = 0;
+
+ PageSize = pNandP->PageSize;
+ BlockSize = pNandP->BlockSize;
+ max = (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100; //max number of relocation is 2% of device
+
+ ptemp = malloc(BlockSize);
+ if(ptemp == NULL)
+ return HeapExhaustedError;
+
+ //buffers used to capture the entire spare area for page 0 and 1, respectively
+ pRB0 = (unsigned int *) (((unsigned int)ptemp + 16) & 0xFFFFFFF0); //align to 16 byte aligned
+ pRB1 = (unsigned int *) (((unsigned int)pRB0 + pNandP->SpareAreaSize + 16) & 0xFFFFFFF0); //ditto
+
+ //AddMessageError(REPORT_NOTIFICATION, PlatformBusy);
+ bUseHwEcc = GetUseHwEcc(BOOT_FLASH );
+ SetUseSpareArea( 1, BOOT_FLASH );
+ SetUseHwEcc( FALSE , BOOT_FLASH); //Turn Off ECC
+
+ //Block 0 is for TIM, scan from block1
+ for (i = 1; i < pFlashProp->NumBlocks; i++)
+ {
+ // address of 1st page in each block
+ SA = i * BlockSize;
+ // Read first page(including spare area) and second page of the block.
+ Retval = xdfc_read(dumy_buf, SA , PageSize, pRB0, pNandP);
+ Retval |= xdfc_read(dumy_buf, SA + PageSize, PageSize, pRB1, pNandP);
+
+ if(Retval != NoError) break; //read failure? something wrong with driver. return
+
+ //finished reading Spare Area in both page 0 and 1
+ //now check it:
+ // if it is all FFFFs, page is good
+ // else if byte 0 or byte 6 are not FFs, factory marked bad
+ // else try a erase/write cycle to termine bad v. just needed an erase cycle
+ block_good = TRUE;
+ for(j = 0; (block_good == TRUE) && (j < xdfc_getSpareAreaSize(pNandP)); j++)
+ if( (pRB0[j] != 0xFFFFFFFF) || (pRB1[j] != 0xFFFFFFFF) )
+ block_good = FALSE; //check for non FFFFs in spare area
+
+ //is this block 'good'?
+ if(block_good == FALSE) //nope
+ { //check bytes 0 and 6 of both spare areas. if any byte != FF, block is factory bad
+ if( ((pRB0[0] & 0xFF) != 0xFF) || ((pRB0[1] & 0xFF0000) != 0xFF0000) ||
+ ((pRB1[0] & 0xFF) != 0xFF) || ((pRB1[1] & 0xFF0000) != 0xFF0000) )
+ badblocklist[badblocks++] = i;
+ else
+ { //try erase/program attempt
+ memcpy(pRB0, &zero, PageSize); //get a page worth of zeros
+ //erase the block
+ Retval = xdfc_erase(SA, pNandP);
+ //try writing all the pages to 0
+ for(j = 0; (j < BlockSize) && (Retval == NoError); j += PageSize)
+ Retval = WriteNAND (SA + j, (unsigned int) pRB0, PageSize, BOOT_FLASH);
+ //now erase the block again (to see if any bits get stuck at 0)
+ if(Retval == NoError)
+ Retval = xdfc_erase(SA, pNandP);
+ //any failure indicates a bad block
+ if(Retval != NoError)
+ badblocklist[badblocks++] = i;
+ }
+ }
+ //if we hit a critical number, return now and let the upper level handle it
+ if(badblocks >= max)
+ break;
+
+ }
+ SetUseHwEcc( bUseHwEcc , BOOT_FLASH); //Turn On ECC
+ //AddMessageError(REPORT_NOTIFICATION, PlatformReady);
+ SetUseSpareArea( 0 , BOOT_FLASH);
+ free(ptemp);
+ return badblocks;
+}
+
+UINT32 OBMI_FlashEntryAddr = 0;
+UINT32 OBMI_ImageSize = 0;
+static INT_T OBMBlock = -1;
+
+void DisableSpareAreaForOBM(UINT_T OBMSartAddr, UINT_T OBMSize)
+{
+ P_NAND_Properties_T pNandP = GetNANDProperties();
+ UINT_T BlockNum;
+ if(OBMSize > pNandP->BlockSize)
+ {
+ obm_printf("Error: OBM Size too big.\n\r");
+ }
+
+ if(OBMBlock == -1) {
+ OBMBlock = OBMSartAddr/pNandP->BlockSize;
+ }
+
+ if(OBMSize == 0){ //OBMSize == 0, means OBM block is relocating
+ BlockNum = OBMSartAddr/pNandP->BlockSize;
+ }else{
+ BlockNum = LocateBlock(OBMBlock, BOOT_FLASH);
+ }
+ OBMI_FlashEntryAddr = BlockNum * pNandP->BlockSize;
+
+ if(OBMSize != 0)
+ OBMI_ImageSize = OBMSize;
+}
+
+INT_T IsAccessOBMBlock(UINT32 Address)
+{
+ UINT32 BlockSize = GetNANDProperties()->BlockSize;
+ UINT32 BlockNum;
+ BlockNum = Address/BlockSize;
+
+ return (BlockNum == OBMBlock);
+}