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);
+}